summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/experiments/field_trials.py
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /third_party/libwebrtc/experiments/field_trials.py
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/libwebrtc/experiments/field_trials.py')
-rwxr-xr-xthird_party/libwebrtc/experiments/field_trials.py1087
1 files changed, 1087 insertions, 0 deletions
diff --git a/third_party/libwebrtc/experiments/field_trials.py b/third_party/libwebrtc/experiments/field_trials.py
new file mode 100755
index 0000000000..e39b53eb47
--- /dev/null
+++ b/third_party/libwebrtc/experiments/field_trials.py
@@ -0,0 +1,1087 @@
+#!/usr/bin/env vpython3
+
+# Copyright (c) 2022 The WebRTC Project Authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS. All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+
+import datetime
+from datetime import date
+import sys
+from typing import FrozenSet, List, Set
+
+import argparse
+import dataclasses
+
+
+@dataclasses.dataclass(frozen=True)
+class FieldTrial:
+ """Representation of all attributes associated with a field trial.
+
+ Attributes:
+ key: Field trial key.
+ bug: Associated open bug containing more context.
+ end_date: Date when the field trial expires and must be deleted.
+ """
+ key: str
+ bug: str
+ end_date: date
+
+
+# As per the policy in `g3doc/field-trials.md`, all field trials should be
+# registered in the container below.
+ACTIVE_FIELD_TRIALS: FrozenSet[FieldTrial] = frozenset([
+ # keep-sorted start
+ FieldTrial('WebRTC-Aec3DelayEstimatorDetectPreEcho',
+ 'webrtc:14205',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3PenalyzeHighDelaysInitialPhase',
+ 'webrtc:14919',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3PreEchoConfiguration',
+ 'webrtc:14205',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Audio-GainController2',
+ 'webrtc:7494',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Audio-OpusSetSignalVoiceWithDtx',
+ 'webrtc:4559',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Av1-GetEncoderInfoOverride',
+ 'webrtc:14931',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-BurstyPacer',
+ 'chromium:1354491',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Bwe-SubtractAdditionalBackoffTerm',
+ 'webrtc:13402',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-DisableRtxRateLimiter',
+ 'webrtc:15184',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-EncoderDataDumpDirectory',
+ 'b/296242528',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-IPv6NetworkResolutionFixes',
+ 'webrtc:14334',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-IncomingTimestampOnMarkerBitOnly',
+ 'webrtc:14526',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-IncreaseIceCandidatePriorityHostSrflx',
+ 'webrtc:15020',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-JitterEstimatorConfig',
+ 'webrtc:14151',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-LibaomAv1Encoder-DisableFrameDropping',
+ 'webrtc:15225',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Pacer-FastRetransmissions',
+ 'chromium:1354491',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Pacer-KeyframeFlushing',
+ 'webrtc:11340',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-PaddingMode-RecentLargePacket',
+ 'webrtc:15201',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-PermuteTlsClientHello',
+ 'webrtc:15467',
+ date(2024, 7, 1)),
+ FieldTrial('WebRTC-PreventSsrcGroupsWithUnexpectedSize',
+ 'chromium:1459124',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-RtcEventLogEncodeDependencyDescriptor',
+ 'webrtc:14975',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-RtcEventLogEncodeNetEqSetMinimumDelayKillSwitch',
+ 'webrtc:14763',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-SCM-Timestamp',
+ 'webrtc:5773',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-SendPacketsOnWorkerThread',
+ 'webrtc:14502',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Stats-RtxReceiveStats',
+ 'webrtc:15096',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-TaskQueue-ReplaceLibeventWithStdlib',
+ 'webrtc:14389',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Video-EnableRetransmitAllLayers',
+ 'webrtc:14959',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Video-EncoderFallbackSettings',
+ 'webrtc:6634',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Video-RequestedResolutionOverrideOutputFormatRequest',
+ 'webrtc:14451',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-VideoEncoderSettings',
+ 'chromium:1406331',
+ date(2024, 4, 1)),
+ # keep-sorted end
+]) # yapf: disable
+
+INDEFINITE = date(datetime.MAXYEAR, 1, 1)
+
+# These field trials precedes the policy in `g3doc/field-trials.md` and are
+# therefore not required to follow it. Do not add any new field trials here.
+POLICY_EXEMPT_FIELD_TRIALS: FrozenSet[FieldTrial] = frozenset([
+ # keep-sorted start
+ FieldTrial('UseTwccPlrForAna',
+ 'webrtc:7058',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-AddNetworkCostToVpn',
+ 'webrtc:13097',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-AddPacingToCongestionWindowPushback',
+ 'webrtc:10171',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-AdjustOpusBandwidth',
+ 'webrtc:8522',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3AecStateFullResetKillSwitch',
+ 'webrtc:11475',
+ INDEFINITE),
+ FieldTrial('WebRTC-Aec3AecStateSubtractorAnalyzerResetKillSwitch',
+ 'webrtc:11475',
+ INDEFINITE),
+ FieldTrial('WebRTC-Aec3AntiHowlingMinimizationKillSwitch',
+ 'b/150764764',
+ INDEFINITE),
+ FieldTrial('WebRTC-Aec3ClampInstQualityToOneKillSwitch',
+ 'webrtc:10913',
+ INDEFINITE),
+ FieldTrial('WebRTC-Aec3ClampInstQualityToZeroKillSwitch',
+ 'webrtc:10913',
+ INDEFINITE),
+ FieldTrial('WebRTC-Aec3CoarseFilterResetHangoverKillSwitch',
+ 'webrtc:12265',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3ConservativeTailFreqResponse',
+ 'webrtc:13173',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3DeactivateInitialStateResetKillSwitch',
+ 'webrtc:11475',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3DelayEstimateSmoothingDelayFoundOverride',
+ 'webrtc:12775',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3DelayEstimateSmoothingOverride',
+ 'webrtc:12775',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3EchoSaturationDetectionKillSwitch',
+ 'webrtc:11475',
+ INDEFINITE),
+ FieldTrial('WebRTC-Aec3EnforceCaptureDelayEstimationDownmixing',
+ 'webrtc:11153',
+ INDEFINITE),
+ FieldTrial(
+ 'WebRTC-Aec3EnforceCaptureDelayEstimationLeftRightPrioritization',
+ 'webrtc:11153',
+ INDEFINITE),
+ FieldTrial('WebRTC-Aec3EnforceConservativeHfSuppression',
+ 'webrtc:11985',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3EnforceLowActiveRenderLimit',
+ 'webrtc:11475',
+ INDEFINITE),
+ FieldTrial('WebRTC-Aec3EnforceMoreTransparentNearendSuppressorHfTuning',
+ 'webrtc:11487',
+ INDEFINITE),
+ FieldTrial('WebRTC-Aec3EnforceMoreTransparentNearendSuppressorTuning',
+ 'webrtc:11475',
+ INDEFINITE),
+ FieldTrial('WebRTC-Aec3EnforceMoreTransparentNormalSuppressorHfTuning',
+ 'webrtc:11487',
+ INDEFINITE),
+ FieldTrial('WebRTC-Aec3EnforceMoreTransparentNormalSuppressorTuning',
+ 'webrtc:11475',
+ INDEFINITE),
+ FieldTrial('WebRTC-Aec3EnforceRapidlyAdjustingNearendSuppressorTunings',
+ 'webrtc:11475',
+ INDEFINITE),
+ FieldTrial('WebRTC-Aec3EnforceRapidlyAdjustingNormalSuppressorTunings',
+ 'webrtc:11475',
+ INDEFINITE),
+ FieldTrial('WebRTC-Aec3EnforceRenderDelayEstimationDownmixing',
+ 'webrtc:11153',
+ INDEFINITE),
+ FieldTrial('WebRTC-Aec3EnforceSlowlyAdjustingNearendSuppressorTunings',
+ 'webrtc:11475',
+ INDEFINITE),
+ FieldTrial('WebRTC-Aec3EnforceSlowlyAdjustingNormalSuppressorTunings',
+ 'webrtc:11475',
+ INDEFINITE),
+ FieldTrial('WebRTC-Aec3EnforceStationarityProperties',
+ 'webrtc:11475',
+ INDEFINITE),
+ FieldTrial('WebRTC-Aec3EnforceStationarityPropertiesAtInit',
+ 'webrtc:11475',
+ INDEFINITE),
+ FieldTrial('WebRTC-Aec3EnforceVeryLowActiveRenderLimit',
+ 'webrtc:11475',
+ INDEFINITE),
+ FieldTrial('WebRTC-Aec3HighPassFilterEchoReference',
+ 'webrtc:12265',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3MinErleDuringOnsetsKillSwitch',
+ 'webrtc:10341',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3NonlinearModeReverbKillSwitch',
+ 'webrtc:11985',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3OnsetDetectionKillSwitch',
+ 'webrtc:11475',
+ INDEFINITE),
+ FieldTrial(
+ 'WebRTC-Aec3RenderDelayEstimationLeftRightPrioritizationKillSwitch',
+ 'webrtc:11153',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3SensitiveDominantNearendActivation',
+ 'webrtc:11475',
+ INDEFINITE),
+ FieldTrial('WebRTC-Aec3SetupSpecificDefaultConfigDefaultsKillSwitch',
+ 'webrtc:11151',
+ INDEFINITE),
+ FieldTrial('WebRTC-Aec3ShortHeadroomKillSwitch',
+ 'webrtc:10341',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3StereoContentDetectionKillSwitch',
+ 'webrtc:14900',
+ INDEFINITE),
+ FieldTrial('WebRTC-Aec3SuppressorAntiHowlingGainOverride',
+ 'webrtc:11487',
+ INDEFINITE),
+ FieldTrial('WebRTC-Aec3SuppressorDominantNearendEnrExitThresholdOverride',
+ 'webrtc:11487',
+ INDEFINITE),
+ FieldTrial('WebRTC-Aec3SuppressorDominantNearendEnrThresholdOverride',
+ 'webrtc:11487',
+ INDEFINITE),
+ FieldTrial('WebRTC-Aec3SuppressorDominantNearendHoldDurationOverride',
+ 'webrtc:11487',
+ INDEFINITE),
+ FieldTrial('WebRTC-Aec3SuppressorDominantNearendSnrThresholdOverride',
+ 'webrtc:11487',
+ INDEFINITE),
+ FieldTrial('WebRTC-Aec3SuppressorDominantNearendTriggerThresholdOverride',
+ 'webrtc:11487',
+ INDEFINITE),
+ FieldTrial('WebRTC-Aec3SuppressorNearendHfMaskSuppressOverride',
+ 'webrtc:11487',
+ INDEFINITE),
+ FieldTrial('WebRTC-Aec3SuppressorNearendHfMaskTransparentOverride',
+ 'webrtc:11487',
+ INDEFINITE),
+ FieldTrial('WebRTC-Aec3SuppressorNearendLfMaskSuppressOverride',
+ 'webrtc:11487',
+ INDEFINITE),
+ FieldTrial('WebRTC-Aec3SuppressorNearendLfMaskTransparentOverride',
+ 'webrtc:11487',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3SuppressorNearendMaxDecFactorLfOverride',
+ 'webrtc:11487',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3SuppressorNearendMaxIncFactorOverride',
+ 'webrtc:11487',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3SuppressorNormalHfMaskSuppressOverride',
+ 'webrtc:11487',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3SuppressorNormalHfMaskTransparentOverride',
+ 'webrtc:11487',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3SuppressorNormalLfMaskSuppressOverride',
+ 'webrtc:11487',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3SuppressorNormalLfMaskTransparentOverride',
+ 'webrtc:11487',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3SuppressorNormalMaxDecFactorLfOverride',
+ 'webrtc:11487',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3SuppressorNormalMaxIncFactorOverride',
+ 'webrtc:11487',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3SuppressorTuningOverride',
+ 'webrtc:11487',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3TransparentAntiHowlingGain',
+ 'webrtc:11475',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3TransparentModeHmm',
+ 'webrtc:12265',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3TransparentModeKillSwitch',
+ 'webrtc:9256',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3Use1Dot2SecondsInitialStateDuration',
+ 'webrtc:11475',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3Use1Dot6SecondsInitialStateDuration',
+ 'webrtc:11475',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3Use2Dot0SecondsInitialStateDuration',
+ 'webrtc:11475',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3UseDot1SecondsInitialStateDuration',
+ 'webrtc:11475',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3UseDot2SecondsInitialStateDuration',
+ 'webrtc:11475',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3UseDot3SecondsInitialStateDuration',
+ 'webrtc:11475',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3UseDot6SecondsInitialStateDuration',
+ 'webrtc:11475',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3UseDot9SecondsInitialStateDuration',
+ 'webrtc:11475',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3UseErleOnsetCompensationInDominantNearend',
+ 'webrtc:12686',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3UseLowEarlyReflectionsDefaultGain',
+ 'webrtc:11475',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3UseLowLateReflectionsDefaultGain',
+ 'webrtc:11475',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3UseNearendReverbLen',
+ 'webrtc:13143',
+ INDEFINITE),
+ FieldTrial('WebRTC-Aec3UseShortConfigChangeDuration',
+ 'webrtc:11475',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3UseZeroInitialStateDuration',
+ 'webrtc:11475',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Aec3VerySensitiveDominantNearendActivation',
+ 'webrtc:11475',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Agc2SimdAvx2KillSwitch',
+ 'webrtc:7494',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Agc2SimdNeonKillSwitch',
+ 'webrtc:7494',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Agc2SimdSse2KillSwitch',
+ 'webrtc:7494',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-AllowMACBasedIPv6',
+ 'webrtc:12268',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-AlrDetectorParameters',
+ 'webrtc:10542',
+ INDEFINITE),
+ FieldTrial('WebRTC-AndroidNetworkMonitor-IsAdapterAvailable',
+ 'webrtc:13741',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-ApmExperimentalMultiChannelCaptureKillSwitch',
+ 'webrtc:14901',
+ INDEFINITE),
+ FieldTrial('WebRTC-ApmExperimentalMultiChannelRenderKillSwitch',
+ 'webrtc:14902',
+ INDEFINITE),
+ FieldTrial('WebRTC-Audio-2ndAgcMinMicLevelExperiment',
+ 'chromium:1275566',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Audio-ABWENoTWCC',
+ 'webrtc:8243',
+ INDEFINITE),
+ FieldTrial('WebRTC-Audio-AdaptivePtime',
+ 'chromium:1086942',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Audio-Allocation',
+ 'webrtc:10286',
+ INDEFINITE),
+ FieldTrial('WebRTC-Audio-AlrProbing',
+ 'webrtc:10200',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Audio-FecAdaptation',
+ 'webrtc:8127',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Audio-LegacyOverhead',
+ 'webrtc:11001',
+ INDEFINITE),
+ FieldTrial('WebRTC-Audio-MinimizeResamplingOnMobile',
+ 'webrtc:6181',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Audio-NetEqDecisionLogicConfig',
+ 'webrtc:13322',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Audio-NetEqDelayManagerConfig',
+ 'webrtc:10333',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Audio-NetEqNackTrackerConfig',
+ 'webrtc:10178',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Audio-NetEqSmartFlushing',
+ 'webrtc:12201',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Audio-OpusAvoidNoisePumpingDuringDtx',
+ 'webrtc:12380',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Audio-OpusBitrateMultipliers',
+ 'webrtc:11055',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Audio-OpusPlcUsePrevDecodedSamples',
+ 'b/143582588',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Audio-Red-For-Opus',
+ 'webrtc:11640',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Audio-StableTargetAdaptation',
+ 'webrtc:10981',
+ INDEFINITE),
+ FieldTrial('WebRTC-Audio-iOS-Holding',
+ 'webrtc:8126',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-AudioDevicePlayoutBufferSizeFactor',
+ 'webrtc:10928',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-AutomaticAnimationDetectionScreenshare',
+ 'webrtc:11058',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Avx2SupportKillSwitch',
+ 'webrtc:11663',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-BindUsingInterfaceName',
+ 'webrtc:10707',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-BoostedScreenshareQp',
+ 'webrtc:9659',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Bwe-AllocationProbing',
+ 'webrtc:10394',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Bwe-AlrProbing',
+ 'webrtc:10394',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Bwe-EstimateBoundedIncrease',
+ 'webrtc:10498',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Bwe-ExponentialProbing',
+ 'webrtc:10394',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Bwe-IgnoreProbesLowerThanNetworkStateEstimate',
+ 'webrtc:10498',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Bwe-InitialProbing',
+ 'webrtc:10394',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Bwe-InjectedCongestionController',
+ 'webrtc:8415',
+ INDEFINITE),
+ FieldTrial('WebRTC-Bwe-LimitProbesLowerThanThroughputEstimate',
+ 'webrtc:11498',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Bwe-LinkCapacity',
+ 'webrtc:9718',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Bwe-LossBasedBweV2',
+ 'webrtc:12707',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Bwe-LossBasedControl',
+ '',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Bwe-MaxRttLimit',
+ 'webrtc:9718',
+ INDEFINITE),
+ FieldTrial('WebRTC-Bwe-MinAllocAsLowerBound',
+ '',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Bwe-NetworkRouteConstraints',
+ 'webrtc:11434',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Bwe-NoFeedbackReset',
+ 'webrtc:9718',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Bwe-PaceAtMaxOfBweAndLowerLinkCapacity',
+ '',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Bwe-ProbingBehavior',
+ 'webrtc:10394',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Bwe-ProbingConfiguration',
+ 'webrtc:10394',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Bwe-ReceiveTimeFix',
+ 'webrtc:9054',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Bwe-ReceiverLimitCapsOnly',
+ 'webrtc:12306',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Bwe-RobustThroughputEstimatorSettings',
+ 'webrtc:10274',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Bwe-SafeResetOnRouteChange',
+ 'webrtc:9718',
+ INDEFINITE),
+ FieldTrial('WebRTC-Bwe-SeparateAudioPackets',
+ 'webrtc:10932',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Bwe-TrendlineEstimatorSettings',
+ 'webrtc:10932',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-BweBackOffFactor',
+ 'webrtc:8212',
+ INDEFINITE),
+ FieldTrial('WebRTC-BweLossExperiment',
+ 'webrtc:5839',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-BweRapidRecoveryExperiment',
+ 'webrtc:8015',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-BweThroughputWindowConfig',
+ 'webrtc:10274',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-BweWindowSizeInPackets',
+ 'webrtc:8212',
+ INDEFINITE),
+ FieldTrial('WebRTC-CongestionWindow',
+ 'webrtc:14898',
+ INDEFINITE),
+ FieldTrial('WebRTC-CpuLoadEstimator',
+ 'webrtc:8504',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Debugging-RtpDump',
+ 'webrtc:10675',
+ INDEFINITE),
+ FieldTrial('WebRTC-DecoderDataDumpDirectory',
+ 'webrtc:14236',
+ INDEFINITE),
+ FieldTrial('WebRTC-DefaultBitrateLimitsKillSwitch',
+ '',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-DependencyDescriptorAdvertised',
+ 'webrtc:10342',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-DisablePacerEmergencyStop',
+ '',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-DisableUlpFecExperiment',
+ '',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-DontIncreaseDelayBasedBweInAlr',
+ 'webrtc:10542',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-DscpFieldTrial',
+ 'webrtc:13622',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-ExtraICEPing',
+ 'webrtc:10273',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-FakeNetworkReceiveConfig',
+ 'webrtc:14238',
+ INDEFINITE),
+ FieldTrial('WebRTC-FakeNetworkSendConfig',
+ 'webrtc:14238',
+ INDEFINITE),
+ FieldTrial('WebRTC-FilterAbsSendTimeExtension',
+ 'webrtc:10234',
+ INDEFINITE),
+ FieldTrial('WebRTC-FindNetworkHandleWithoutIpv6TemporaryPart',
+ 'webrtc:11067',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-FlexFEC-03',
+ 'webrtc:5654',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-FlexFEC-03-Advertised',
+ 'webrtc:5654',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-ForcePlayoutDelay',
+ 'webrtc:11896',
+ INDEFINITE),
+ FieldTrial('WebRTC-ForceSendPlayoutDelay',
+ 'webrtc:11896',
+ INDEFINITE),
+ FieldTrial('WebRTC-ForceSimulatedOveruseIntervalMs',
+ 'webrtc:14239',
+ INDEFINITE),
+ FieldTrial('WebRTC-FrameDropper',
+ 'webrtc:9711',
+ INDEFINITE),
+ FieldTrial('WebRTC-FullBandHpfKillSwitch',
+ 'webrtc:11193',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-GenericCodecDependencyDescriptor',
+ 'webrtc:14969',
+ INDEFINITE),
+ FieldTrial('WebRTC-GenericDescriptorAdvertised',
+ 'webrtc:9361',
+ INDEFINITE),
+ FieldTrial('WebRTC-GenericDescriptorAuth',
+ 'webrtc:10103',
+ INDEFINITE),
+ FieldTrial('WebRTC-GenericPictureId',
+ 'webrtc:9361',
+ INDEFINITE),
+ FieldTrial('WebRTC-GetEncoderInfoOverride',
+ '',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-H264HighProfile',
+ 'webrtc:6337',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-IPv6Default',
+ 'chromium:413437',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-IceControllerFieldTrials',
+ 'chromium:1024965',
+ INDEFINITE),
+ FieldTrial('WebRTC-IceFieldTrials',
+ 'webrtc:11021',
+ INDEFINITE),
+ FieldTrial('WebRTC-KeyframeInterval',
+ 'webrtc:10427',
+ INDEFINITE),
+ FieldTrial('WebRTC-LegacyFrameIdJumpBehavior',
+ 'webrtc:13343',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-LegacySimulcastLayerLimit',
+ 'webrtc:8785',
+ INDEFINITE),
+ FieldTrial('WebRTC-LegacyTlsProtocols',
+ 'webrtc:10261',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-LowresSimulcastBitrateInterpolation',
+ 'webrtc:12415',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-MutedStateKillSwitch',
+ 'b/177830919',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Network-UseNWPathMonitor',
+ 'webrtc:10966',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-NetworkMonitorAutoDetect',
+ 'webrtc:13741',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-NormalizeSimulcastResolution',
+ '',
+ INDEFINITE),
+ FieldTrial('WebRTC-Pacer-BlockAudio',
+ 'webrtc:8415',
+ INDEFINITE),
+ FieldTrial('WebRTC-Pacer-DrainQueue',
+ 'webrtc:8415',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Pacer-IgnoreTransportOverhead',
+ 'webrtc:9883',
+ INDEFINITE),
+ FieldTrial('WebRTC-Pacer-PadInSilence',
+ 'webrtc:8415',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-PacketBufferMaxSize',
+ 'webrtc:9851',
+ INDEFINITE),
+ FieldTrial('WebRTC-PcFactoryDefaultBitrates',
+ 'webrtc:10865',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-PiggybackIceCheckAcknowledgement',
+ '',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-PixelLimitResource',
+ 'webrtc:12261',
+ INDEFINITE),
+ FieldTrial('WebRTC-ProbingScreenshareBwe',
+ 'webrtc:7694',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-ProtectionOverheadRateThreshold',
+ 'webrtc:14899',
+ INDEFINITE),
+ FieldTrial('WebRTC-QpParsingKillSwitch',
+ 'webrtc:12542',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-RtcEventLogKillSwitch',
+ 'webrtc:12084',
+ INDEFINITE),
+ FieldTrial('WebRTC-RtcEventLogNewFormat',
+ 'webrtc:8111',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-RtcpLossNotification',
+ 'webrtc:10336',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-RttMult',
+ 'webrtc:9670',
+ INDEFINITE),
+ FieldTrial('WebRTC-SendBufferSizeBytes',
+ 'webrtc:11905',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-ReceiveBufferSize',
+ 'webrtc:15585',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-SendNackDelayMs',
+ 'webrtc:9953',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-SetSocketReceiveBuffer',
+ 'webrtc:13753',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-SignalNetworkPreferenceChange',
+ 'webrtc:11825',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-SimulcastEncoderAdapter-GetEncoderInfoOverride',
+ '',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-SimulcastLayerLimitRoundUp',
+ '',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-SpsPpsIdrIsH264Keyframe',
+ 'webrtc:8423',
+ INDEFINITE),
+ FieldTrial('WebRTC-StableTargetRate',
+ 'webrtc:10126',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-StrictPacingAndProbing',
+ 'webrtc:8072',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-StunInterPacketDelay',
+ '',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-SurfaceCellularTypes',
+ 'webrtc:11473',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-SwitchEncoderOnInitializationFailures',
+ 'webrtc:13572',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Target-Bitrate-Rtcp',
+ 'webrtc:9969',
+ INDEFINITE),
+ FieldTrial('WebRTC-TransientSuppressorForcedOff',
+ 'chromium:1186705',
+ INDEFINITE),
+ FieldTrial('WebRTC-UseBaseHeavyVP8TL3RateAllocation',
+ 'webrtc:9477',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-UseDifferentiatedCellularCosts',
+ 'webrtc:11473',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-UseShortVP8TL2Pattern',
+ 'webrtc:9477',
+ INDEFINITE),
+ FieldTrial('WebRTC-UseShortVP8TL3Pattern',
+ 'webrtc:8162',
+ INDEFINITE),
+ FieldTrial('WebRTC-UseStandardBytesStats',
+ 'webrtc:10525',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-UseTurnServerAsStunServer',
+ 'webrtc:11059',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-VP8-CpuSpeed-Arm',
+ '',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-VP8-ForcePartitionResilience',
+ 'webrtc:11832',
+ INDEFINITE),
+ FieldTrial('WebRTC-VP8-Forced-Fallback-Encoder-v2',
+ 'webrtc:6634',
+ INDEFINITE),
+ FieldTrial('WebRTC-VP8-GetEncoderInfoOverride',
+ 'webrtc:11832',
+ INDEFINITE),
+ FieldTrial('WebRTC-VP8-MaxFrameInterval',
+ 'webrtc:15530',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-VP8-Postproc-Config',
+ 'webrtc:11551',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-VP8-Postproc-Config-Arm',
+ 'webrtc:6634',
+ INDEFINITE),
+ FieldTrial('WebRTC-VP8ConferenceTemporalLayers',
+ 'webrtc:9260',
+ INDEFINITE),
+ FieldTrial('WebRTC-VP8IosMaxNumberOfThread',
+ 'webrtc:10005',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-VP8VariableFramerateScreenshare',
+ 'webrtc:10310',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-VP9-GetEncoderInfoOverride',
+ '',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-VP9-LowTierOptimizations',
+ 'webrtc:13888',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-VP9-PerformanceFlags',
+ 'webrtc:11551',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-VP9QualityScaler',
+ 'webrtc:11319',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-VP9VariableFramerateScreenshare',
+ 'webrtc:10310',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Video-BalancedDegradation',
+ 'webrtc:7607',
+ INDEFINITE),
+ FieldTrial('WebRTC-Video-BalancedDegradationSettings',
+ '',
+ INDEFINITE),
+ FieldTrial('WebRTC-Video-BandwidthQualityScalerSettings',
+ 'webrtc:12942',
+ INDEFINITE),
+ FieldTrial('WebRTC-Video-DisableAutomaticResize',
+ 'webrtc:11812',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Video-DiscardPacketsWithUnknownSsrc',
+ 'webrtc:9871',
+ INDEFINITE),
+ FieldTrial('WebRTC-Video-ForcedSwDecoderFallback',
+ '',
+ INDEFINITE),
+ FieldTrial('WebRTC-Video-InitialDecoderResolution',
+ 'webrtc:11898',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Video-MinVideoBitrate',
+ 'webrtc:10915',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Video-Pacing',
+ 'webrtc:10038',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Video-PreferTemporalSupportOnBaseLayer',
+ 'webrtc:11324',
+ INDEFINITE),
+ FieldTrial('WebRTC-Video-QualityRampupSettings',
+ '',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Video-QualityScalerSettings',
+ '',
+ INDEFINITE),
+ FieldTrial('WebRTC-Video-QualityScaling',
+ 'webrtc:9169',
+ INDEFINITE),
+ FieldTrial('WebRTC-Video-UseFrameRateForOverhead',
+ 'b/166341943',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Video-VariableStartScaleFactor',
+ '',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-VideoFrameTrackingIdAdvertised',
+ 'webrtc:12594',
+ INDEFINITE),
+ FieldTrial('WebRTC-VideoLayersAllocationAdvertised',
+ 'webrtc:1200',
+ INDEFINITE),
+ FieldTrial('WebRTC-VideoRateControl',
+ 'webrtc:10223',
+ INDEFINITE),
+ FieldTrial('WebRTC-VoIPChannelRemixingAdjustmentKillSwitch',
+ 'chromium:1027117',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Vp9ExternalRefCtrl',
+ 'webrtc:9585',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-Vp9InterLayerPred',
+ 'chromium:949536',
+ INDEFINITE),
+ FieldTrial('WebRTC-Vp9IssueKeyFrameOnLayerDeactivation',
+ 'chromium:889017',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-ZeroHertzScreenshare',
+ 'chromium:1255737',
+ date(2024, 4, 1)),
+ FieldTrial('WebRTC-ZeroPlayoutDelay',
+ 'chromium:1335323',
+ date(2024, 4, 1)),
+ # keep-sorted end
+]) # yapf: disable
+
+REGISTERED_FIELD_TRIALS: FrozenSet[FieldTrial] = ACTIVE_FIELD_TRIALS.union(
+ POLICY_EXEMPT_FIELD_TRIALS)
+
+
+def todays_date() -> date:
+ now = datetime.datetime.now(datetime.timezone.utc)
+ return date(now.year, now.month, now.day)
+
+
+def registry_header(
+ field_trials: FrozenSet[FieldTrial] = REGISTERED_FIELD_TRIALS) -> str:
+ """Generates a C++ header with all field trial keys.
+
+ Args:
+ field_trials: Field trials to include in the header.
+
+ Returns:
+ String representation of a C++ header file containing all field trial
+ keys.
+
+ >>> trials = {
+ ... FieldTrial('B', '', date(1, 1, 1)),
+ ... FieldTrial('A', '', date(1, 1, 1)),
+ ... FieldTrial('B', '', date(2, 2, 2)),
+ ... }
+ >>> print(registry_header(trials))
+ // This file was automatically generated. Do not edit.
+ <BLANKLINE>
+ #ifndef GEN_REGISTERED_FIELD_TRIALS_H_
+ #define GEN_REGISTERED_FIELD_TRIALS_H_
+ <BLANKLINE>
+ #include "absl/strings/string_view.h"
+ <BLANKLINE>
+ namespace webrtc {
+ <BLANKLINE>
+ inline constexpr absl::string_view kRegisteredFieldTrials[] = {
+ "A",
+ "B",
+ };
+ <BLANKLINE>
+ } // namespace webrtc
+ <BLANKLINE>
+ #endif // GEN_REGISTERED_FIELD_TRIALS_H_
+ <BLANKLINE>
+ """
+ registered_keys = {f.key for f in field_trials}
+ keys = '\n'.join(f' "{k}",' for k in sorted(registered_keys))
+ return ('// This file was automatically generated. Do not edit.\n'
+ '\n'
+ '#ifndef GEN_REGISTERED_FIELD_TRIALS_H_\n'
+ '#define GEN_REGISTERED_FIELD_TRIALS_H_\n'
+ '\n'
+ '#include "absl/strings/string_view.h"\n'
+ '\n'
+ 'namespace webrtc {\n'
+ '\n'
+ 'inline constexpr absl::string_view kRegisteredFieldTrials[] = {\n'
+ f'{keys}\n'
+ '};\n'
+ '\n'
+ '} // namespace webrtc\n'
+ '\n'
+ '#endif // GEN_REGISTERED_FIELD_TRIALS_H_\n')
+
+
+def expired_field_trials(
+ threshold: date,
+ field_trials: FrozenSet[FieldTrial] = REGISTERED_FIELD_TRIALS
+) -> Set[FieldTrial]:
+ """Obtains expired field trials.
+
+ Args:
+ threshold: Date from which to check end date.
+ field_trials: Field trials to validate.
+
+ Returns:
+ All expired field trials.
+
+ >>> trials = {
+ ... FieldTrial('Expired', '', date(1, 1, 1)),
+ ... FieldTrial('Not-Expired', '', date(1, 1, 2)),
+ ... }
+ >>> expired_field_trials(date(1, 1, 1), trials)
+ {FieldTrial(key='Expired', bug='', end_date=datetime.date(1, 1, 1))}
+ """
+ return {f for f in field_trials if f.end_date <= threshold}
+
+
+def validate_field_trials(
+ field_trials: FrozenSet[FieldTrial] = ACTIVE_FIELD_TRIALS
+) -> List[str]:
+ """Validate that field trials conforms to the policy.
+
+ Args:
+ field_trials: Field trials to validate.
+
+ Returns:
+ A list of explanations for invalid field trials.
+ """
+ invalid = []
+ for trial in field_trials:
+ if not trial.key.startswith('WebRTC-'):
+ invalid.append(f'{trial.key} does not start with "WebRTC-".')
+ if len(trial.bug) <= 0:
+ invalid.append(f'{trial.key} must have an associated bug.')
+ if trial.end_date >= INDEFINITE:
+ invalid.append(f'{trial.key} must have an end date.')
+ return invalid
+
+
+def cmd_header(args: argparse.Namespace) -> None:
+ args.output.write(registry_header())
+
+
+def cmd_expired(args: argparse.Namespace) -> None:
+ today = todays_date()
+ diff = datetime.timedelta(days=args.in_days)
+ expired = expired_field_trials(today + diff)
+
+ if len(expired) <= 0:
+ return
+
+ expired_by_date = sorted([(f.end_date, f.key) for f in expired])
+ print('\n'.join(
+ f'{key} {"expired" if date <= today else "expires"} on {date}'
+ for date, key in expired_by_date))
+ if any(date <= today for date, _ in expired_by_date):
+ sys.exit(1)
+
+
+def cmd_validate(args: argparse.Namespace) -> None:
+ del args
+ invalid = validate_field_trials()
+
+ if len(invalid) <= 0:
+ return
+
+ print('\n'.join(sorted(invalid)))
+ sys.exit(1)
+
+
+def main() -> None:
+ parser = argparse.ArgumentParser()
+ subcommand = parser.add_subparsers(dest='cmd')
+
+ parser_header = subcommand.add_parser(
+ 'header',
+ help='generate C++ header file containing registered field trial keys')
+ parser_header.add_argument('--output',
+ default=sys.stdout,
+ type=argparse.FileType('w'),
+ required=False,
+ help='output file')
+ parser_header.set_defaults(cmd=cmd_header)
+
+ parser_expired = subcommand.add_parser(
+ 'expired',
+ help='lists all expired field trials',
+ description='''
+ Lists all expired field trials. Exits with a non-zero exit status if
+ any field trials has expired, ignoring the --in-days argument.
+ ''')
+ parser_expired.add_argument(
+ '--in-days',
+ default=0,
+ type=int,
+ required=False,
+ help='number of days relative to today to check')
+ parser_expired.set_defaults(cmd=cmd_expired)
+
+ parser_validate = subcommand.add_parser(
+ 'validate',
+ help='validates that all field trials conforms to the policy.',
+ description='''
+ Validates that all field trials conforms to the policy. Exits with a
+ non-zero exit status if any field trials does not.
+ ''')
+ parser_validate.set_defaults(cmd=cmd_validate)
+
+ args = parser.parse_args()
+
+ if not args.cmd:
+ parser.print_help(sys.stderr)
+ sys.exit(1)
+
+ args.cmd(args)
+
+
+if __name__ == '__main__':
+ main()