[experiments] Explicit requirement check (#34880)

Add a config to experiments & rollouts to allow dependent experiments to
be flagged.

We're getting past the point where it's possible to reason about which
experiments need to be turned off if we disable some other experiment,
and so this provides some additional rollout safety.

Can be specified in both experiments and rollouts: experiments.yaml
makes the most sense and we should default to it, but rollouts.yaml lets
us put dependencies between internal & external dependencies internally
and that's gonna be a little useful.

---------

Co-authored-by: ctiller <ctiller@users.noreply.github.com>
pull/34905/head
Craig Tiller 1 year ago committed by GitHub
parent 1e15d00ec4
commit 88011e05f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 51
      bazel/experiments.bzl
  2. 7
      bazel/grpc_build_system.bzl
  3. 7
      bazel/test_experiments.bzl
  4. 13
      src/core/lib/experiments/config.cc
  5. 3
      src/core/lib/experiments/config.h
  6. 449
      src/core/lib/experiments/experiments.cc
  7. 66
      src/core/lib/experiments/experiments.h
  8. 8
      src/core/lib/experiments/experiments.yaml
  9. 4
      src/core/lib/experiments/rollouts.yaml
  10. 29
      test/core/experiments/fixtures/experiments.cc
  11. 72
      tools/codegen/core/experiments_compiler.py

@ -16,6 +16,57 @@
"""Dictionary of tags to experiments so we know when to test different experiments."""
EXPERIMENT_ENABLES = {
"block_excessive_requests_before_settings_ack": "block_excessive_requests_before_settings_ack",
"call_status_override_on_cancellation": "call_status_override_on_cancellation",
"canary_client_privacy": "canary_client_privacy",
"client_idleness": "client_idleness",
"client_privacy": "client_privacy",
"combiner_offload_to_event_engine": "combiner_offload_to_event_engine",
"chttp2_batch_requests": "chttp2_batch_requests,combiner_offload_to_event_engine",
"chttp2_offload_on_rst_stream": "chttp2_offload_on_rst_stream,combiner_offload_to_event_engine",
"event_engine_client": "event_engine_client",
"event_engine_dns": "event_engine_dns",
"event_engine_listener": "event_engine_listener",
"free_large_allocator": "free_large_allocator",
"http2_stats_fix": "http2_stats_fix",
"keepalive_fix": "keepalive_fix",
"keepalive_server_fix": "keepalive_server_fix",
"lazier_stream_updates": "lazier_stream_updates",
"memory_pressure_controller": "memory_pressure_controller",
"monitoring_experiment": "monitoring_experiment",
"multiping": "multiping",
"overload_protection": "overload_protection",
"peer_state_based_framing": "peer_state_based_framing",
"pending_queue_cap": "pending_queue_cap",
"pick_first_happy_eyeballs": "pick_first_happy_eyeballs",
"ping_on_rst_stream": "ping_on_rst_stream",
"promise_based_client_call": "promise_based_client_call",
"promise_based_inproc_transport": "promise_based_inproc_transport",
"promise_based_server_call": "lazier_stream_updates,promise_based_server_call",
"red_max_concurrent_streams": "red_max_concurrent_streams",
"registered_method_lookup_in_transport": "registered_method_lookup_in_transport",
"registered_methods_map": "registered_methods_map",
"rfc_max_concurrent_streams": "rfc_max_concurrent_streams",
"round_robin_delegate_to_pick_first": "round_robin_delegate_to_pick_first",
"rstpit": "rstpit",
"schedule_cancellation_over_write": "schedule_cancellation_over_write",
"separate_ping_from_keepalive": "separate_ping_from_keepalive",
"server_privacy": "server_privacy",
"settings_timeout": "settings_timeout",
"tarpit": "tarpit",
"tcp_frame_size_tuning": "tcp_frame_size_tuning",
"tcp_rcv_lowat": "tcp_rcv_lowat",
"trace_record_callops": "trace_record_callops",
"unconstrained_max_quota_buffer_size": "unconstrained_max_quota_buffer_size",
"uniquely_unowned": "uniquely_unowned",
"work_serializer_clears_time_cache": "work_serializer_clears_time_cache",
"work_serializer_dispatch": "work_serializer_dispatch",
"write_size_policy": "write_size_policy",
"write_size_cap": "write_size_cap,write_size_policy",
"wrr_delegate_to_pick_first": "wrr_delegate_to_pick_first",
}
EXPERIMENTS = {
"windows": {
"dbg": {

@ -29,8 +29,8 @@ Contains macros used throughout the repo.
load("//bazel:cc_grpc_library.bzl", "cc_grpc_library")
load("//bazel:copts.bzl", "GRPC_DEFAULT_COPTS")
load("//bazel:experiments.bzl", "EXPERIMENTS")
load("//bazel:test_experiments.bzl", "TEST_EXPERIMENTS")
load("//bazel:experiments.bzl", "EXPERIMENTS", "EXPERIMENT_ENABLES")
load("//bazel:test_experiments.bzl", "TEST_EXPERIMENTS", "TEST_EXPERIMENT_ENABLES")
load("@upb//bazel:upb_proto_library.bzl", "upb_proto_library", "upb_proto_reflection_library")
load("@build_bazel_rules_apple//apple:ios.bzl", "ios_unit_test")
load("@build_bazel_rules_apple//apple/testing/default_runner:ios_test_runner.bzl", "ios_test_runner")
@ -418,6 +418,7 @@ def expand_tests(name, srcs, deps, tags, args, exclude_pollers, uses_polling, us
return tags
experiment_config = list(poller_config)
experiment_enables = {k: v for k, v in EXPERIMENT_ENABLES.items() + TEST_EXPERIMENT_ENABLES.items()}
for mode, config in mode_config.items():
enabled_tags, disabled_tags = config
if enabled_tags != None:
@ -426,7 +427,7 @@ def expand_tests(name, srcs, deps, tags, args, exclude_pollers, uses_polling, us
config = dict(config)
config["name"] = config["name"] + "@experiment=" + experiment
env = dict(config["env"])
env["GRPC_EXPERIMENTS"] = experiment
env["GRPC_EXPERIMENTS"] = experiment_enables[experiment]
env["GRPC_CI_EXPERIMENTS"] = "1"
config["env"] = env
tags = config["tags"] + ["experiment_variation"]

@ -16,6 +16,13 @@
"""Dictionary of tags to experiments so we know when to test different experiments."""
TEST_EXPERIMENT_ENABLES = {
"test_experiment_1": "test_experiment_1",
"test_experiment_2": "test_experiment_2",
"test_experiment_3": "test_experiment_3",
"test_experiment_4": "test_experiment_4",
}
TEST_EXPERIMENTS = {
"windows": {
"dbg": {

@ -135,6 +135,19 @@ GPR_ATTRIBUTE_NOINLINE Experiments LoadExperimentsFromConfigVariable() {
std::string(experiment).c_str());
}
}
for (size_t i = 0; i < kNumExperiments; i++) {
// If required experiments are not enabled, disable this one too.
for (size_t j = 0; j < g_experiment_metadata[i].num_required_experiments;
j++) {
// Require that we can check dependent requirements with a linear sweep
// (implies the experiments generator must DAG sort the experiments)
GPR_ASSERT(g_experiment_metadata[i].required_experiments[j] < i);
if (!experiments
.enabled[g_experiment_metadata[i].required_experiments[j]]) {
experiments.enabled[i] = false;
}
}
}
return experiments;
}

@ -18,6 +18,7 @@
#include <grpc/support/port_platform.h>
#include <stddef.h>
#include <stdint.h>
#include "absl/functional/any_invocable.h"
#include "absl/strings/string_view.h"
@ -30,6 +31,8 @@ struct ExperimentMetadata {
const char* name;
const char* description;
const char* additional_constaints;
const uint8_t* required_experiments;
uint8_t num_required_experiments;
bool default_value;
bool allow_in_fuzzing_config;
};

@ -18,6 +18,8 @@
#include "src/core/lib/experiments/experiments.h"
#include <stdint.h>
#ifndef GRPC_EXPERIMENTS_ARE_FINAL
#if defined(GRPC_CFSTREAM)
@ -34,13 +36,6 @@ const char* const additional_constraints_call_status_override_on_cancellation =
const char* const description_canary_client_privacy =
"If set, canary client privacy";
const char* const additional_constraints_canary_client_privacy = "{}";
const char* const description_chttp2_batch_requests =
"Cap the number of requests received by one transport read prior to "
"offload.";
const char* const additional_constraints_chttp2_batch_requests = "{}";
const char* const description_chttp2_offload_on_rst_stream =
"Offload work on RST_STREAM.";
const char* const additional_constraints_chttp2_offload_on_rst_stream = "{}";
const char* const description_client_idleness =
"If enabled, client channel idleness is enabled by default.";
const char* const additional_constraints_client_idleness = "{}";
@ -50,6 +45,17 @@ const char* const description_combiner_offload_to_event_engine =
"Offload Combiner work onto the EventEngine instead of the Executor.";
const char* const additional_constraints_combiner_offload_to_event_engine =
"{}";
const char* const description_chttp2_batch_requests =
"Cap the number of requests received by one transport read prior to "
"offload.";
const char* const additional_constraints_chttp2_batch_requests = "{}";
const uint8_t required_experiments_chttp2_batch_requests[] = {
static_cast<uint8_t>(grpc_core::kExperimentIdCombinerOffloadToEventEngine)};
const char* const description_chttp2_offload_on_rst_stream =
"Offload work on RST_STREAM.";
const char* const additional_constraints_chttp2_offload_on_rst_stream = "{}";
const uint8_t required_experiments_chttp2_offload_on_rst_stream[] = {
static_cast<uint8_t>(grpc_core::kExperimentIdCombinerOffloadToEventEngine)};
const char* const description_event_engine_client =
"Use EventEngine clients instead of iomgr's grpc_tcp_client";
const char* const additional_constraints_event_engine_client = "{}";
@ -121,6 +127,8 @@ const char* const description_promise_based_server_call =
"If set, use the new gRPC promise based call code when it's appropriate "
"(ie when all filters in a stack are promise based)";
const char* const additional_constraints_promise_based_server_call = "{}";
const uint8_t required_experiments_promise_based_server_call[] = {
static_cast<uint8_t>(grpc_core::kExperimentIdLazierStreamUpdates)};
const char* const description_red_max_concurrent_streams =
"Perform random early rejection of requests that would exceed a newly "
"reduced MAX_CONCURRENT_STREAMS but are allowed by the current.";
@ -193,12 +201,14 @@ const char* const description_work_serializer_dispatch =
"callback, instead of running things inline in the first thread that "
"successfully enqueues work.";
const char* const additional_constraints_work_serializer_dispatch = "{}";
const char* const description_write_size_cap =
"Limit outgoing writes proportional to the target write size";
const char* const additional_constraints_write_size_cap = "{}";
const char* const description_write_size_policy =
"Try to size writes such that they don't create too large of a backlog";
const char* const additional_constraints_write_size_policy = "{}";
const char* const description_write_size_cap =
"Limit outgoing writes proportional to the target write size";
const char* const additional_constraints_write_size_cap = "{}";
const uint8_t required_experiments_write_size_cap[] = {
static_cast<uint8_t>(grpc_core::kExperimentIdWriteSizePolicy)};
const char* const description_wrr_delegate_to_pick_first =
"Change WRR code to delegate to pick_first as per dualstack backend "
"design.";
@ -215,109 +225,126 @@ namespace grpc_core {
const ExperimentMetadata g_experiment_metadata[] = {
{"block_excessive_requests_before_settings_ack",
description_block_excessive_requests_before_settings_ack,
additional_constraints_block_excessive_requests_before_settings_ack, true,
true},
additional_constraints_block_excessive_requests_before_settings_ack,
nullptr, 0, true, true},
{"call_status_override_on_cancellation",
description_call_status_override_on_cancellation,
additional_constraints_call_status_override_on_cancellation,
additional_constraints_call_status_override_on_cancellation, nullptr, 0,
kDefaultForDebugOnly, true},
{"canary_client_privacy", description_canary_client_privacy,
additional_constraints_canary_client_privacy, false, false},
{"chttp2_batch_requests", description_chttp2_batch_requests,
additional_constraints_chttp2_batch_requests, true, true},
{"chttp2_offload_on_rst_stream", description_chttp2_offload_on_rst_stream,
additional_constraints_chttp2_offload_on_rst_stream, true, true},
additional_constraints_canary_client_privacy, nullptr, 0, false, false},
{"client_idleness", description_client_idleness,
additional_constraints_client_idleness, true, true},
additional_constraints_client_idleness, nullptr, 0, true, true},
{"client_privacy", description_client_privacy,
additional_constraints_client_privacy, false, false},
additional_constraints_client_privacy, nullptr, 0, false, false},
{"combiner_offload_to_event_engine",
description_combiner_offload_to_event_engine,
additional_constraints_combiner_offload_to_event_engine, true, true},
additional_constraints_combiner_offload_to_event_engine, nullptr, 0, true,
true},
{"chttp2_batch_requests", description_chttp2_batch_requests,
additional_constraints_chttp2_batch_requests,
required_experiments_chttp2_batch_requests, 1, true, true},
{"chttp2_offload_on_rst_stream", description_chttp2_offload_on_rst_stream,
additional_constraints_chttp2_offload_on_rst_stream,
required_experiments_chttp2_offload_on_rst_stream, 1, true, true},
{"event_engine_client", description_event_engine_client,
additional_constraints_event_engine_client, false, true},
additional_constraints_event_engine_client, nullptr, 0, false, true},
{"event_engine_dns", description_event_engine_dns,
additional_constraints_event_engine_dns, false, false},
additional_constraints_event_engine_dns, nullptr, 0, false, false},
{"event_engine_listener", description_event_engine_listener,
additional_constraints_event_engine_listener, false, true},
additional_constraints_event_engine_listener, nullptr, 0, false, true},
{"free_large_allocator", description_free_large_allocator,
additional_constraints_free_large_allocator, false, true},
additional_constraints_free_large_allocator, nullptr, 0, false, true},
{"http2_stats_fix", description_http2_stats_fix,
additional_constraints_http2_stats_fix, true, true},
additional_constraints_http2_stats_fix, nullptr, 0, true, true},
{"keepalive_fix", description_keepalive_fix,
additional_constraints_keepalive_fix, false, false},
additional_constraints_keepalive_fix, nullptr, 0, false, false},
{"keepalive_server_fix", description_keepalive_server_fix,
additional_constraints_keepalive_server_fix, false, false},
additional_constraints_keepalive_server_fix, nullptr, 0, false, false},
{"lazier_stream_updates", description_lazier_stream_updates,
additional_constraints_lazier_stream_updates, true, true},
additional_constraints_lazier_stream_updates, nullptr, 0, true, true},
{"memory_pressure_controller", description_memory_pressure_controller,
additional_constraints_memory_pressure_controller, false, true},
additional_constraints_memory_pressure_controller, nullptr, 0, false,
true},
{"monitoring_experiment", description_monitoring_experiment,
additional_constraints_monitoring_experiment, true, true},
additional_constraints_monitoring_experiment, nullptr, 0, true, true},
{"multiping", description_multiping, additional_constraints_multiping,
false, true},
nullptr, 0, false, true},
{"overload_protection", description_overload_protection,
additional_constraints_overload_protection, true, true},
additional_constraints_overload_protection, nullptr, 0, true, true},
{"peer_state_based_framing", description_peer_state_based_framing,
additional_constraints_peer_state_based_framing, false, true},
additional_constraints_peer_state_based_framing, nullptr, 0, false, true},
{"pending_queue_cap", description_pending_queue_cap,
additional_constraints_pending_queue_cap, true, true},
additional_constraints_pending_queue_cap, nullptr, 0, true, true},
{"pick_first_happy_eyeballs", description_pick_first_happy_eyeballs,
additional_constraints_pick_first_happy_eyeballs, true, true},
additional_constraints_pick_first_happy_eyeballs, nullptr, 0, true, true},
{"ping_on_rst_stream", description_ping_on_rst_stream,
additional_constraints_ping_on_rst_stream, true, true},
additional_constraints_ping_on_rst_stream, nullptr, 0, true, true},
{"promise_based_client_call", description_promise_based_client_call,
additional_constraints_promise_based_client_call, false, true},
additional_constraints_promise_based_client_call, nullptr, 0, false, true},
{"promise_based_inproc_transport",
description_promise_based_inproc_transport,
additional_constraints_promise_based_inproc_transport, false, false},
additional_constraints_promise_based_inproc_transport, nullptr, 0, false,
false},
{"promise_based_server_call", description_promise_based_server_call,
additional_constraints_promise_based_server_call, false, true},
additional_constraints_promise_based_server_call,
required_experiments_promise_based_server_call, 1, false, true},
{"red_max_concurrent_streams", description_red_max_concurrent_streams,
additional_constraints_red_max_concurrent_streams, false, true},
additional_constraints_red_max_concurrent_streams, nullptr, 0, false,
true},
{"registered_method_lookup_in_transport",
description_registered_method_lookup_in_transport,
additional_constraints_registered_method_lookup_in_transport, true, true},
additional_constraints_registered_method_lookup_in_transport, nullptr, 0,
true, true},
{"registered_methods_map", description_registered_methods_map,
additional_constraints_registered_methods_map, false, true},
additional_constraints_registered_methods_map, nullptr, 0, false, true},
{"rfc_max_concurrent_streams", description_rfc_max_concurrent_streams,
additional_constraints_rfc_max_concurrent_streams, false, true},
additional_constraints_rfc_max_concurrent_streams, nullptr, 0, false,
true},
{"round_robin_delegate_to_pick_first",
description_round_robin_delegate_to_pick_first,
additional_constraints_round_robin_delegate_to_pick_first, true, true},
{"rstpit", description_rstpit, additional_constraints_rstpit, false, true},
additional_constraints_round_robin_delegate_to_pick_first, nullptr, 0,
true, true},
{"rstpit", description_rstpit, additional_constraints_rstpit, nullptr, 0,
false, true},
{"schedule_cancellation_over_write",
description_schedule_cancellation_over_write,
additional_constraints_schedule_cancellation_over_write, false, true},
additional_constraints_schedule_cancellation_over_write, nullptr, 0, false,
true},
{"separate_ping_from_keepalive", description_separate_ping_from_keepalive,
additional_constraints_separate_ping_from_keepalive, true, true},
additional_constraints_separate_ping_from_keepalive, nullptr, 0, true,
true},
{"server_privacy", description_server_privacy,
additional_constraints_server_privacy, false, false},
additional_constraints_server_privacy, nullptr, 0, false, false},
{"settings_timeout", description_settings_timeout,
additional_constraints_settings_timeout, true, true},
{"tarpit", description_tarpit, additional_constraints_tarpit, true, true},
additional_constraints_settings_timeout, nullptr, 0, true, true},
{"tarpit", description_tarpit, additional_constraints_tarpit, nullptr, 0,
true, true},
{"tcp_frame_size_tuning", description_tcp_frame_size_tuning,
additional_constraints_tcp_frame_size_tuning, false, true},
additional_constraints_tcp_frame_size_tuning, nullptr, 0, false, true},
{"tcp_rcv_lowat", description_tcp_rcv_lowat,
additional_constraints_tcp_rcv_lowat, false, true},
additional_constraints_tcp_rcv_lowat, nullptr, 0, false, true},
{"trace_record_callops", description_trace_record_callops,
additional_constraints_trace_record_callops, false, true},
additional_constraints_trace_record_callops, nullptr, 0, false, true},
{"unconstrained_max_quota_buffer_size",
description_unconstrained_max_quota_buffer_size,
additional_constraints_unconstrained_max_quota_buffer_size, false, true},
additional_constraints_unconstrained_max_quota_buffer_size, nullptr, 0,
false, true},
{"uniquely_unowned", description_uniquely_unowned,
additional_constraints_uniquely_unowned, true, true},
additional_constraints_uniquely_unowned, nullptr, 0, true, true},
{"work_serializer_clears_time_cache",
description_work_serializer_clears_time_cache,
additional_constraints_work_serializer_clears_time_cache, true, true},
additional_constraints_work_serializer_clears_time_cache, nullptr, 0, true,
true},
{"work_serializer_dispatch", description_work_serializer_dispatch,
additional_constraints_work_serializer_dispatch, false, true},
{"write_size_cap", description_write_size_cap,
additional_constraints_write_size_cap, true, true},
additional_constraints_work_serializer_dispatch, nullptr, 0, false, true},
{"write_size_policy", description_write_size_policy,
additional_constraints_write_size_policy, true, true},
additional_constraints_write_size_policy, nullptr, 0, true, true},
{"write_size_cap", description_write_size_cap,
additional_constraints_write_size_cap, required_experiments_write_size_cap,
1, true, true},
{"wrr_delegate_to_pick_first", description_wrr_delegate_to_pick_first,
additional_constraints_wrr_delegate_to_pick_first, true, true},
additional_constraints_wrr_delegate_to_pick_first, nullptr, 0, true, true},
};
} // namespace grpc_core
@ -336,13 +363,6 @@ const char* const additional_constraints_call_status_override_on_cancellation =
const char* const description_canary_client_privacy =
"If set, canary client privacy";
const char* const additional_constraints_canary_client_privacy = "{}";
const char* const description_chttp2_batch_requests =
"Cap the number of requests received by one transport read prior to "
"offload.";
const char* const additional_constraints_chttp2_batch_requests = "{}";
const char* const description_chttp2_offload_on_rst_stream =
"Offload work on RST_STREAM.";
const char* const additional_constraints_chttp2_offload_on_rst_stream = "{}";
const char* const description_client_idleness =
"If enabled, client channel idleness is enabled by default.";
const char* const additional_constraints_client_idleness = "{}";
@ -352,6 +372,17 @@ const char* const description_combiner_offload_to_event_engine =
"Offload Combiner work onto the EventEngine instead of the Executor.";
const char* const additional_constraints_combiner_offload_to_event_engine =
"{}";
const char* const description_chttp2_batch_requests =
"Cap the number of requests received by one transport read prior to "
"offload.";
const char* const additional_constraints_chttp2_batch_requests = "{}";
const uint8_t required_experiments_chttp2_batch_requests[] = {
static_cast<uint8_t>(grpc_core::kExperimentIdCombinerOffloadToEventEngine)};
const char* const description_chttp2_offload_on_rst_stream =
"Offload work on RST_STREAM.";
const char* const additional_constraints_chttp2_offload_on_rst_stream = "{}";
const uint8_t required_experiments_chttp2_offload_on_rst_stream[] = {
static_cast<uint8_t>(grpc_core::kExperimentIdCombinerOffloadToEventEngine)};
const char* const description_event_engine_client =
"Use EventEngine clients instead of iomgr's grpc_tcp_client";
const char* const additional_constraints_event_engine_client = "{}";
@ -423,6 +454,8 @@ const char* const description_promise_based_server_call =
"If set, use the new gRPC promise based call code when it's appropriate "
"(ie when all filters in a stack are promise based)";
const char* const additional_constraints_promise_based_server_call = "{}";
const uint8_t required_experiments_promise_based_server_call[] = {
static_cast<uint8_t>(grpc_core::kExperimentIdLazierStreamUpdates)};
const char* const description_red_max_concurrent_streams =
"Perform random early rejection of requests that would exceed a newly "
"reduced MAX_CONCURRENT_STREAMS but are allowed by the current.";
@ -495,12 +528,14 @@ const char* const description_work_serializer_dispatch =
"callback, instead of running things inline in the first thread that "
"successfully enqueues work.";
const char* const additional_constraints_work_serializer_dispatch = "{}";
const char* const description_write_size_cap =
"Limit outgoing writes proportional to the target write size";
const char* const additional_constraints_write_size_cap = "{}";
const char* const description_write_size_policy =
"Try to size writes such that they don't create too large of a backlog";
const char* const additional_constraints_write_size_policy = "{}";
const char* const description_write_size_cap =
"Limit outgoing writes proportional to the target write size";
const char* const additional_constraints_write_size_cap = "{}";
const uint8_t required_experiments_write_size_cap[] = {
static_cast<uint8_t>(grpc_core::kExperimentIdWriteSizePolicy)};
const char* const description_wrr_delegate_to_pick_first =
"Change WRR code to delegate to pick_first as per dualstack backend "
"design.";
@ -517,109 +552,126 @@ namespace grpc_core {
const ExperimentMetadata g_experiment_metadata[] = {
{"block_excessive_requests_before_settings_ack",
description_block_excessive_requests_before_settings_ack,
additional_constraints_block_excessive_requests_before_settings_ack, true,
true},
additional_constraints_block_excessive_requests_before_settings_ack,
nullptr, 0, true, true},
{"call_status_override_on_cancellation",
description_call_status_override_on_cancellation,
additional_constraints_call_status_override_on_cancellation,
additional_constraints_call_status_override_on_cancellation, nullptr, 0,
kDefaultForDebugOnly, true},
{"canary_client_privacy", description_canary_client_privacy,
additional_constraints_canary_client_privacy, false, false},
{"chttp2_batch_requests", description_chttp2_batch_requests,
additional_constraints_chttp2_batch_requests, true, true},
{"chttp2_offload_on_rst_stream", description_chttp2_offload_on_rst_stream,
additional_constraints_chttp2_offload_on_rst_stream, true, true},
additional_constraints_canary_client_privacy, nullptr, 0, false, false},
{"client_idleness", description_client_idleness,
additional_constraints_client_idleness, true, true},
additional_constraints_client_idleness, nullptr, 0, true, true},
{"client_privacy", description_client_privacy,
additional_constraints_client_privacy, false, false},
additional_constraints_client_privacy, nullptr, 0, false, false},
{"combiner_offload_to_event_engine",
description_combiner_offload_to_event_engine,
additional_constraints_combiner_offload_to_event_engine, true, true},
additional_constraints_combiner_offload_to_event_engine, nullptr, 0, true,
true},
{"chttp2_batch_requests", description_chttp2_batch_requests,
additional_constraints_chttp2_batch_requests,
required_experiments_chttp2_batch_requests, 1, true, true},
{"chttp2_offload_on_rst_stream", description_chttp2_offload_on_rst_stream,
additional_constraints_chttp2_offload_on_rst_stream,
required_experiments_chttp2_offload_on_rst_stream, 1, true, true},
{"event_engine_client", description_event_engine_client,
additional_constraints_event_engine_client, false, true},
additional_constraints_event_engine_client, nullptr, 0, false, true},
{"event_engine_dns", description_event_engine_dns,
additional_constraints_event_engine_dns, false, false},
additional_constraints_event_engine_dns, nullptr, 0, false, false},
{"event_engine_listener", description_event_engine_listener,
additional_constraints_event_engine_listener, true, true},
additional_constraints_event_engine_listener, nullptr, 0, true, true},
{"free_large_allocator", description_free_large_allocator,
additional_constraints_free_large_allocator, false, true},
additional_constraints_free_large_allocator, nullptr, 0, false, true},
{"http2_stats_fix", description_http2_stats_fix,
additional_constraints_http2_stats_fix, true, true},
additional_constraints_http2_stats_fix, nullptr, 0, true, true},
{"keepalive_fix", description_keepalive_fix,
additional_constraints_keepalive_fix, false, false},
additional_constraints_keepalive_fix, nullptr, 0, false, false},
{"keepalive_server_fix", description_keepalive_server_fix,
additional_constraints_keepalive_server_fix, false, false},
additional_constraints_keepalive_server_fix, nullptr, 0, false, false},
{"lazier_stream_updates", description_lazier_stream_updates,
additional_constraints_lazier_stream_updates, true, true},
additional_constraints_lazier_stream_updates, nullptr, 0, true, true},
{"memory_pressure_controller", description_memory_pressure_controller,
additional_constraints_memory_pressure_controller, false, true},
additional_constraints_memory_pressure_controller, nullptr, 0, false,
true},
{"monitoring_experiment", description_monitoring_experiment,
additional_constraints_monitoring_experiment, true, true},
additional_constraints_monitoring_experiment, nullptr, 0, true, true},
{"multiping", description_multiping, additional_constraints_multiping,
false, true},
nullptr, 0, false, true},
{"overload_protection", description_overload_protection,
additional_constraints_overload_protection, true, true},
additional_constraints_overload_protection, nullptr, 0, true, true},
{"peer_state_based_framing", description_peer_state_based_framing,
additional_constraints_peer_state_based_framing, false, true},
additional_constraints_peer_state_based_framing, nullptr, 0, false, true},
{"pending_queue_cap", description_pending_queue_cap,
additional_constraints_pending_queue_cap, true, true},
additional_constraints_pending_queue_cap, nullptr, 0, true, true},
{"pick_first_happy_eyeballs", description_pick_first_happy_eyeballs,
additional_constraints_pick_first_happy_eyeballs, true, true},
additional_constraints_pick_first_happy_eyeballs, nullptr, 0, true, true},
{"ping_on_rst_stream", description_ping_on_rst_stream,
additional_constraints_ping_on_rst_stream, true, true},
additional_constraints_ping_on_rst_stream, nullptr, 0, true, true},
{"promise_based_client_call", description_promise_based_client_call,
additional_constraints_promise_based_client_call, false, true},
additional_constraints_promise_based_client_call, nullptr, 0, false, true},
{"promise_based_inproc_transport",
description_promise_based_inproc_transport,
additional_constraints_promise_based_inproc_transport, false, false},
additional_constraints_promise_based_inproc_transport, nullptr, 0, false,
false},
{"promise_based_server_call", description_promise_based_server_call,
additional_constraints_promise_based_server_call, false, true},
additional_constraints_promise_based_server_call,
required_experiments_promise_based_server_call, 1, false, true},
{"red_max_concurrent_streams", description_red_max_concurrent_streams,
additional_constraints_red_max_concurrent_streams, false, true},
additional_constraints_red_max_concurrent_streams, nullptr, 0, false,
true},
{"registered_method_lookup_in_transport",
description_registered_method_lookup_in_transport,
additional_constraints_registered_method_lookup_in_transport, true, true},
additional_constraints_registered_method_lookup_in_transport, nullptr, 0,
true, true},
{"registered_methods_map", description_registered_methods_map,
additional_constraints_registered_methods_map, false, true},
additional_constraints_registered_methods_map, nullptr, 0, false, true},
{"rfc_max_concurrent_streams", description_rfc_max_concurrent_streams,
additional_constraints_rfc_max_concurrent_streams, false, true},
additional_constraints_rfc_max_concurrent_streams, nullptr, 0, false,
true},
{"round_robin_delegate_to_pick_first",
description_round_robin_delegate_to_pick_first,
additional_constraints_round_robin_delegate_to_pick_first, true, true},
{"rstpit", description_rstpit, additional_constraints_rstpit, false, true},
additional_constraints_round_robin_delegate_to_pick_first, nullptr, 0,
true, true},
{"rstpit", description_rstpit, additional_constraints_rstpit, nullptr, 0,
false, true},
{"schedule_cancellation_over_write",
description_schedule_cancellation_over_write,
additional_constraints_schedule_cancellation_over_write, false, true},
additional_constraints_schedule_cancellation_over_write, nullptr, 0, false,
true},
{"separate_ping_from_keepalive", description_separate_ping_from_keepalive,
additional_constraints_separate_ping_from_keepalive, true, true},
additional_constraints_separate_ping_from_keepalive, nullptr, 0, true,
true},
{"server_privacy", description_server_privacy,
additional_constraints_server_privacy, false, false},
additional_constraints_server_privacy, nullptr, 0, false, false},
{"settings_timeout", description_settings_timeout,
additional_constraints_settings_timeout, true, true},
{"tarpit", description_tarpit, additional_constraints_tarpit, true, true},
additional_constraints_settings_timeout, nullptr, 0, true, true},
{"tarpit", description_tarpit, additional_constraints_tarpit, nullptr, 0,
true, true},
{"tcp_frame_size_tuning", description_tcp_frame_size_tuning,
additional_constraints_tcp_frame_size_tuning, false, true},
additional_constraints_tcp_frame_size_tuning, nullptr, 0, false, true},
{"tcp_rcv_lowat", description_tcp_rcv_lowat,
additional_constraints_tcp_rcv_lowat, false, true},
additional_constraints_tcp_rcv_lowat, nullptr, 0, false, true},
{"trace_record_callops", description_trace_record_callops,
additional_constraints_trace_record_callops, false, true},
additional_constraints_trace_record_callops, nullptr, 0, false, true},
{"unconstrained_max_quota_buffer_size",
description_unconstrained_max_quota_buffer_size,
additional_constraints_unconstrained_max_quota_buffer_size, false, true},
additional_constraints_unconstrained_max_quota_buffer_size, nullptr, 0,
false, true},
{"uniquely_unowned", description_uniquely_unowned,
additional_constraints_uniquely_unowned, true, true},
additional_constraints_uniquely_unowned, nullptr, 0, true, true},
{"work_serializer_clears_time_cache",
description_work_serializer_clears_time_cache,
additional_constraints_work_serializer_clears_time_cache, true, true},
additional_constraints_work_serializer_clears_time_cache, nullptr, 0, true,
true},
{"work_serializer_dispatch", description_work_serializer_dispatch,
additional_constraints_work_serializer_dispatch, false, true},
{"write_size_cap", description_write_size_cap,
additional_constraints_write_size_cap, true, true},
additional_constraints_work_serializer_dispatch, nullptr, 0, false, true},
{"write_size_policy", description_write_size_policy,
additional_constraints_write_size_policy, true, true},
additional_constraints_write_size_policy, nullptr, 0, true, true},
{"write_size_cap", description_write_size_cap,
additional_constraints_write_size_cap, required_experiments_write_size_cap,
1, true, true},
{"wrr_delegate_to_pick_first", description_wrr_delegate_to_pick_first,
additional_constraints_wrr_delegate_to_pick_first, true, true},
additional_constraints_wrr_delegate_to_pick_first, nullptr, 0, true, true},
};
} // namespace grpc_core
@ -638,13 +690,6 @@ const char* const additional_constraints_call_status_override_on_cancellation =
const char* const description_canary_client_privacy =
"If set, canary client privacy";
const char* const additional_constraints_canary_client_privacy = "{}";
const char* const description_chttp2_batch_requests =
"Cap the number of requests received by one transport read prior to "
"offload.";
const char* const additional_constraints_chttp2_batch_requests = "{}";
const char* const description_chttp2_offload_on_rst_stream =
"Offload work on RST_STREAM.";
const char* const additional_constraints_chttp2_offload_on_rst_stream = "{}";
const char* const description_client_idleness =
"If enabled, client channel idleness is enabled by default.";
const char* const additional_constraints_client_idleness = "{}";
@ -654,6 +699,17 @@ const char* const description_combiner_offload_to_event_engine =
"Offload Combiner work onto the EventEngine instead of the Executor.";
const char* const additional_constraints_combiner_offload_to_event_engine =
"{}";
const char* const description_chttp2_batch_requests =
"Cap the number of requests received by one transport read prior to "
"offload.";
const char* const additional_constraints_chttp2_batch_requests = "{}";
const uint8_t required_experiments_chttp2_batch_requests[] = {
static_cast<uint8_t>(grpc_core::kExperimentIdCombinerOffloadToEventEngine)};
const char* const description_chttp2_offload_on_rst_stream =
"Offload work on RST_STREAM.";
const char* const additional_constraints_chttp2_offload_on_rst_stream = "{}";
const uint8_t required_experiments_chttp2_offload_on_rst_stream[] = {
static_cast<uint8_t>(grpc_core::kExperimentIdCombinerOffloadToEventEngine)};
const char* const description_event_engine_client =
"Use EventEngine clients instead of iomgr's grpc_tcp_client";
const char* const additional_constraints_event_engine_client = "{}";
@ -725,6 +781,8 @@ const char* const description_promise_based_server_call =
"If set, use the new gRPC promise based call code when it's appropriate "
"(ie when all filters in a stack are promise based)";
const char* const additional_constraints_promise_based_server_call = "{}";
const uint8_t required_experiments_promise_based_server_call[] = {
static_cast<uint8_t>(grpc_core::kExperimentIdLazierStreamUpdates)};
const char* const description_red_max_concurrent_streams =
"Perform random early rejection of requests that would exceed a newly "
"reduced MAX_CONCURRENT_STREAMS but are allowed by the current.";
@ -797,12 +855,14 @@ const char* const description_work_serializer_dispatch =
"callback, instead of running things inline in the first thread that "
"successfully enqueues work.";
const char* const additional_constraints_work_serializer_dispatch = "{}";
const char* const description_write_size_cap =
"Limit outgoing writes proportional to the target write size";
const char* const additional_constraints_write_size_cap = "{}";
const char* const description_write_size_policy =
"Try to size writes such that they don't create too large of a backlog";
const char* const additional_constraints_write_size_policy = "{}";
const char* const description_write_size_cap =
"Limit outgoing writes proportional to the target write size";
const char* const additional_constraints_write_size_cap = "{}";
const uint8_t required_experiments_write_size_cap[] = {
static_cast<uint8_t>(grpc_core::kExperimentIdWriteSizePolicy)};
const char* const description_wrr_delegate_to_pick_first =
"Change WRR code to delegate to pick_first as per dualstack backend "
"design.";
@ -819,109 +879,126 @@ namespace grpc_core {
const ExperimentMetadata g_experiment_metadata[] = {
{"block_excessive_requests_before_settings_ack",
description_block_excessive_requests_before_settings_ack,
additional_constraints_block_excessive_requests_before_settings_ack, true,
true},
additional_constraints_block_excessive_requests_before_settings_ack,
nullptr, 0, true, true},
{"call_status_override_on_cancellation",
description_call_status_override_on_cancellation,
additional_constraints_call_status_override_on_cancellation,
additional_constraints_call_status_override_on_cancellation, nullptr, 0,
kDefaultForDebugOnly, true},
{"canary_client_privacy", description_canary_client_privacy,
additional_constraints_canary_client_privacy, false, false},
{"chttp2_batch_requests", description_chttp2_batch_requests,
additional_constraints_chttp2_batch_requests, true, true},
{"chttp2_offload_on_rst_stream", description_chttp2_offload_on_rst_stream,
additional_constraints_chttp2_offload_on_rst_stream, true, true},
additional_constraints_canary_client_privacy, nullptr, 0, false, false},
{"client_idleness", description_client_idleness,
additional_constraints_client_idleness, true, true},
additional_constraints_client_idleness, nullptr, 0, true, true},
{"client_privacy", description_client_privacy,
additional_constraints_client_privacy, false, false},
additional_constraints_client_privacy, nullptr, 0, false, false},
{"combiner_offload_to_event_engine",
description_combiner_offload_to_event_engine,
additional_constraints_combiner_offload_to_event_engine, true, true},
additional_constraints_combiner_offload_to_event_engine, nullptr, 0, true,
true},
{"chttp2_batch_requests", description_chttp2_batch_requests,
additional_constraints_chttp2_batch_requests,
required_experiments_chttp2_batch_requests, 1, true, true},
{"chttp2_offload_on_rst_stream", description_chttp2_offload_on_rst_stream,
additional_constraints_chttp2_offload_on_rst_stream,
required_experiments_chttp2_offload_on_rst_stream, 1, true, true},
{"event_engine_client", description_event_engine_client,
additional_constraints_event_engine_client, false, true},
additional_constraints_event_engine_client, nullptr, 0, false, true},
{"event_engine_dns", description_event_engine_dns,
additional_constraints_event_engine_dns, false, false},
additional_constraints_event_engine_dns, nullptr, 0, false, false},
{"event_engine_listener", description_event_engine_listener,
additional_constraints_event_engine_listener, true, true},
additional_constraints_event_engine_listener, nullptr, 0, true, true},
{"free_large_allocator", description_free_large_allocator,
additional_constraints_free_large_allocator, false, true},
additional_constraints_free_large_allocator, nullptr, 0, false, true},
{"http2_stats_fix", description_http2_stats_fix,
additional_constraints_http2_stats_fix, true, true},
additional_constraints_http2_stats_fix, nullptr, 0, true, true},
{"keepalive_fix", description_keepalive_fix,
additional_constraints_keepalive_fix, false, false},
additional_constraints_keepalive_fix, nullptr, 0, false, false},
{"keepalive_server_fix", description_keepalive_server_fix,
additional_constraints_keepalive_server_fix, false, false},
additional_constraints_keepalive_server_fix, nullptr, 0, false, false},
{"lazier_stream_updates", description_lazier_stream_updates,
additional_constraints_lazier_stream_updates, true, true},
additional_constraints_lazier_stream_updates, nullptr, 0, true, true},
{"memory_pressure_controller", description_memory_pressure_controller,
additional_constraints_memory_pressure_controller, false, true},
additional_constraints_memory_pressure_controller, nullptr, 0, false,
true},
{"monitoring_experiment", description_monitoring_experiment,
additional_constraints_monitoring_experiment, true, true},
additional_constraints_monitoring_experiment, nullptr, 0, true, true},
{"multiping", description_multiping, additional_constraints_multiping,
false, true},
nullptr, 0, false, true},
{"overload_protection", description_overload_protection,
additional_constraints_overload_protection, true, true},
additional_constraints_overload_protection, nullptr, 0, true, true},
{"peer_state_based_framing", description_peer_state_based_framing,
additional_constraints_peer_state_based_framing, false, true},
additional_constraints_peer_state_based_framing, nullptr, 0, false, true},
{"pending_queue_cap", description_pending_queue_cap,
additional_constraints_pending_queue_cap, true, true},
additional_constraints_pending_queue_cap, nullptr, 0, true, true},
{"pick_first_happy_eyeballs", description_pick_first_happy_eyeballs,
additional_constraints_pick_first_happy_eyeballs, true, true},
additional_constraints_pick_first_happy_eyeballs, nullptr, 0, true, true},
{"ping_on_rst_stream", description_ping_on_rst_stream,
additional_constraints_ping_on_rst_stream, true, true},
additional_constraints_ping_on_rst_stream, nullptr, 0, true, true},
{"promise_based_client_call", description_promise_based_client_call,
additional_constraints_promise_based_client_call, false, true},
additional_constraints_promise_based_client_call, nullptr, 0, false, true},
{"promise_based_inproc_transport",
description_promise_based_inproc_transport,
additional_constraints_promise_based_inproc_transport, false, false},
additional_constraints_promise_based_inproc_transport, nullptr, 0, false,
false},
{"promise_based_server_call", description_promise_based_server_call,
additional_constraints_promise_based_server_call, false, true},
additional_constraints_promise_based_server_call,
required_experiments_promise_based_server_call, 1, false, true},
{"red_max_concurrent_streams", description_red_max_concurrent_streams,
additional_constraints_red_max_concurrent_streams, false, true},
additional_constraints_red_max_concurrent_streams, nullptr, 0, false,
true},
{"registered_method_lookup_in_transport",
description_registered_method_lookup_in_transport,
additional_constraints_registered_method_lookup_in_transport, true, true},
additional_constraints_registered_method_lookup_in_transport, nullptr, 0,
true, true},
{"registered_methods_map", description_registered_methods_map,
additional_constraints_registered_methods_map, false, true},
additional_constraints_registered_methods_map, nullptr, 0, false, true},
{"rfc_max_concurrent_streams", description_rfc_max_concurrent_streams,
additional_constraints_rfc_max_concurrent_streams, false, true},
additional_constraints_rfc_max_concurrent_streams, nullptr, 0, false,
true},
{"round_robin_delegate_to_pick_first",
description_round_robin_delegate_to_pick_first,
additional_constraints_round_robin_delegate_to_pick_first, true, true},
{"rstpit", description_rstpit, additional_constraints_rstpit, false, true},
additional_constraints_round_robin_delegate_to_pick_first, nullptr, 0,
true, true},
{"rstpit", description_rstpit, additional_constraints_rstpit, nullptr, 0,
false, true},
{"schedule_cancellation_over_write",
description_schedule_cancellation_over_write,
additional_constraints_schedule_cancellation_over_write, false, true},
additional_constraints_schedule_cancellation_over_write, nullptr, 0, false,
true},
{"separate_ping_from_keepalive", description_separate_ping_from_keepalive,
additional_constraints_separate_ping_from_keepalive, true, true},
additional_constraints_separate_ping_from_keepalive, nullptr, 0, true,
true},
{"server_privacy", description_server_privacy,
additional_constraints_server_privacy, false, false},
additional_constraints_server_privacy, nullptr, 0, false, false},
{"settings_timeout", description_settings_timeout,
additional_constraints_settings_timeout, true, true},
{"tarpit", description_tarpit, additional_constraints_tarpit, true, true},
additional_constraints_settings_timeout, nullptr, 0, true, true},
{"tarpit", description_tarpit, additional_constraints_tarpit, nullptr, 0,
true, true},
{"tcp_frame_size_tuning", description_tcp_frame_size_tuning,
additional_constraints_tcp_frame_size_tuning, false, true},
additional_constraints_tcp_frame_size_tuning, nullptr, 0, false, true},
{"tcp_rcv_lowat", description_tcp_rcv_lowat,
additional_constraints_tcp_rcv_lowat, false, true},
additional_constraints_tcp_rcv_lowat, nullptr, 0, false, true},
{"trace_record_callops", description_trace_record_callops,
additional_constraints_trace_record_callops, false, true},
additional_constraints_trace_record_callops, nullptr, 0, false, true},
{"unconstrained_max_quota_buffer_size",
description_unconstrained_max_quota_buffer_size,
additional_constraints_unconstrained_max_quota_buffer_size, false, true},
additional_constraints_unconstrained_max_quota_buffer_size, nullptr, 0,
false, true},
{"uniquely_unowned", description_uniquely_unowned,
additional_constraints_uniquely_unowned, true, true},
additional_constraints_uniquely_unowned, nullptr, 0, true, true},
{"work_serializer_clears_time_cache",
description_work_serializer_clears_time_cache,
additional_constraints_work_serializer_clears_time_cache, true, true},
additional_constraints_work_serializer_clears_time_cache, nullptr, 0, true,
true},
{"work_serializer_dispatch", description_work_serializer_dispatch,
additional_constraints_work_serializer_dispatch, false, true},
{"write_size_cap", description_write_size_cap,
additional_constraints_write_size_cap, true, true},
additional_constraints_work_serializer_dispatch, nullptr, 0, false, true},
{"write_size_policy", description_write_size_policy,
additional_constraints_write_size_policy, true, true},
additional_constraints_write_size_policy, nullptr, 0, true, true},
{"write_size_cap", description_write_size_cap,
additional_constraints_write_size_cap, required_experiments_write_size_cap,
1, true, true},
{"wrr_delegate_to_pick_first", description_wrr_delegate_to_pick_first,
additional_constraints_wrr_delegate_to_pick_first, true, true},
additional_constraints_wrr_delegate_to_pick_first, nullptr, 0, true, true},
};
} // namespace grpc_core

@ -70,15 +70,15 @@ inline bool IsCallStatusOverrideOnCancellationEnabled() {
#endif
}
inline bool IsCanaryClientPrivacyEnabled() { return false; }
#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_BATCH_REQUESTS
inline bool IsChttp2BatchRequestsEnabled() { return true; }
#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_OFFLOAD_ON_RST_STREAM
inline bool IsChttp2OffloadOnRstStreamEnabled() { return true; }
#define GRPC_EXPERIMENT_IS_INCLUDED_CLIENT_IDLENESS
inline bool IsClientIdlenessEnabled() { return true; }
inline bool IsClientPrivacyEnabled() { return false; }
#define GRPC_EXPERIMENT_IS_INCLUDED_COMBINER_OFFLOAD_TO_EVENT_ENGINE
inline bool IsCombinerOffloadToEventEngineEnabled() { return true; }
#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_BATCH_REQUESTS
inline bool IsChttp2BatchRequestsEnabled() { return true; }
#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_OFFLOAD_ON_RST_STREAM
inline bool IsChttp2OffloadOnRstStreamEnabled() { return true; }
inline bool IsEventEngineClientEnabled() { return false; }
inline bool IsEventEngineDnsEnabled() { return false; }
inline bool IsEventEngineListenerEnabled() { return false; }
@ -130,10 +130,10 @@ inline bool IsUniquelyUnownedEnabled() { return true; }
#define GRPC_EXPERIMENT_IS_INCLUDED_WORK_SERIALIZER_CLEARS_TIME_CACHE
inline bool IsWorkSerializerClearsTimeCacheEnabled() { return true; }
inline bool IsWorkSerializerDispatchEnabled() { return false; }
#define GRPC_EXPERIMENT_IS_INCLUDED_WRITE_SIZE_CAP
inline bool IsWriteSizeCapEnabled() { return true; }
#define GRPC_EXPERIMENT_IS_INCLUDED_WRITE_SIZE_POLICY
inline bool IsWriteSizePolicyEnabled() { return true; }
#define GRPC_EXPERIMENT_IS_INCLUDED_WRITE_SIZE_CAP
inline bool IsWriteSizeCapEnabled() { return true; }
#define GRPC_EXPERIMENT_IS_INCLUDED_WRR_DELEGATE_TO_PICK_FIRST
inline bool IsWrrDelegateToPickFirstEnabled() { return true; }
@ -151,15 +151,15 @@ inline bool IsCallStatusOverrideOnCancellationEnabled() {
#endif
}
inline bool IsCanaryClientPrivacyEnabled() { return false; }
#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_BATCH_REQUESTS
inline bool IsChttp2BatchRequestsEnabled() { return true; }
#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_OFFLOAD_ON_RST_STREAM
inline bool IsChttp2OffloadOnRstStreamEnabled() { return true; }
#define GRPC_EXPERIMENT_IS_INCLUDED_CLIENT_IDLENESS
inline bool IsClientIdlenessEnabled() { return true; }
inline bool IsClientPrivacyEnabled() { return false; }
#define GRPC_EXPERIMENT_IS_INCLUDED_COMBINER_OFFLOAD_TO_EVENT_ENGINE
inline bool IsCombinerOffloadToEventEngineEnabled() { return true; }
#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_BATCH_REQUESTS
inline bool IsChttp2BatchRequestsEnabled() { return true; }
#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_OFFLOAD_ON_RST_STREAM
inline bool IsChttp2OffloadOnRstStreamEnabled() { return true; }
inline bool IsEventEngineClientEnabled() { return false; }
inline bool IsEventEngineDnsEnabled() { return false; }
#define GRPC_EXPERIMENT_IS_INCLUDED_EVENT_ENGINE_LISTENER
@ -212,10 +212,10 @@ inline bool IsUniquelyUnownedEnabled() { return true; }
#define GRPC_EXPERIMENT_IS_INCLUDED_WORK_SERIALIZER_CLEARS_TIME_CACHE
inline bool IsWorkSerializerClearsTimeCacheEnabled() { return true; }
inline bool IsWorkSerializerDispatchEnabled() { return false; }
#define GRPC_EXPERIMENT_IS_INCLUDED_WRITE_SIZE_CAP
inline bool IsWriteSizeCapEnabled() { return true; }
#define GRPC_EXPERIMENT_IS_INCLUDED_WRITE_SIZE_POLICY
inline bool IsWriteSizePolicyEnabled() { return true; }
#define GRPC_EXPERIMENT_IS_INCLUDED_WRITE_SIZE_CAP
inline bool IsWriteSizeCapEnabled() { return true; }
#define GRPC_EXPERIMENT_IS_INCLUDED_WRR_DELEGATE_TO_PICK_FIRST
inline bool IsWrrDelegateToPickFirstEnabled() { return true; }
@ -233,15 +233,15 @@ inline bool IsCallStatusOverrideOnCancellationEnabled() {
#endif
}
inline bool IsCanaryClientPrivacyEnabled() { return false; }
#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_BATCH_REQUESTS
inline bool IsChttp2BatchRequestsEnabled() { return true; }
#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_OFFLOAD_ON_RST_STREAM
inline bool IsChttp2OffloadOnRstStreamEnabled() { return true; }
#define GRPC_EXPERIMENT_IS_INCLUDED_CLIENT_IDLENESS
inline bool IsClientIdlenessEnabled() { return true; }
inline bool IsClientPrivacyEnabled() { return false; }
#define GRPC_EXPERIMENT_IS_INCLUDED_COMBINER_OFFLOAD_TO_EVENT_ENGINE
inline bool IsCombinerOffloadToEventEngineEnabled() { return true; }
#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_BATCH_REQUESTS
inline bool IsChttp2BatchRequestsEnabled() { return true; }
#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_OFFLOAD_ON_RST_STREAM
inline bool IsChttp2OffloadOnRstStreamEnabled() { return true; }
inline bool IsEventEngineClientEnabled() { return false; }
inline bool IsEventEngineDnsEnabled() { return false; }
#define GRPC_EXPERIMENT_IS_INCLUDED_EVENT_ENGINE_LISTENER
@ -294,10 +294,10 @@ inline bool IsUniquelyUnownedEnabled() { return true; }
#define GRPC_EXPERIMENT_IS_INCLUDED_WORK_SERIALIZER_CLEARS_TIME_CACHE
inline bool IsWorkSerializerClearsTimeCacheEnabled() { return true; }
inline bool IsWorkSerializerDispatchEnabled() { return false; }
#define GRPC_EXPERIMENT_IS_INCLUDED_WRITE_SIZE_CAP
inline bool IsWriteSizeCapEnabled() { return true; }
#define GRPC_EXPERIMENT_IS_INCLUDED_WRITE_SIZE_POLICY
inline bool IsWriteSizePolicyEnabled() { return true; }
#define GRPC_EXPERIMENT_IS_INCLUDED_WRITE_SIZE_CAP
inline bool IsWriteSizeCapEnabled() { return true; }
#define GRPC_EXPERIMENT_IS_INCLUDED_WRR_DELEGATE_TO_PICK_FIRST
inline bool IsWrrDelegateToPickFirstEnabled() { return true; }
#endif
@ -307,11 +307,11 @@ enum ExperimentIds {
kExperimentIdBlockExcessiveRequestsBeforeSettingsAck,
kExperimentIdCallStatusOverrideOnCancellation,
kExperimentIdCanaryClientPrivacy,
kExperimentIdChttp2BatchRequests,
kExperimentIdChttp2OffloadOnRstStream,
kExperimentIdClientIdleness,
kExperimentIdClientPrivacy,
kExperimentIdCombinerOffloadToEventEngine,
kExperimentIdChttp2BatchRequests,
kExperimentIdChttp2OffloadOnRstStream,
kExperimentIdEventEngineClient,
kExperimentIdEventEngineDns,
kExperimentIdEventEngineListener,
@ -349,8 +349,8 @@ enum ExperimentIds {
kExperimentIdUniquelyUnowned,
kExperimentIdWorkSerializerClearsTimeCache,
kExperimentIdWorkSerializerDispatch,
kExperimentIdWriteSizeCap,
kExperimentIdWriteSizePolicy,
kExperimentIdWriteSizeCap,
kExperimentIdWrrDelegateToPickFirst,
kNumExperiments
};
@ -367,14 +367,6 @@ inline bool IsCallStatusOverrideOnCancellationEnabled() {
inline bool IsCanaryClientPrivacyEnabled() {
return IsExperimentEnabled(kExperimentIdCanaryClientPrivacy);
}
#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_BATCH_REQUESTS
inline bool IsChttp2BatchRequestsEnabled() {
return IsExperimentEnabled(kExperimentIdChttp2BatchRequests);
}
#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_OFFLOAD_ON_RST_STREAM
inline bool IsChttp2OffloadOnRstStreamEnabled() {
return IsExperimentEnabled(kExperimentIdChttp2OffloadOnRstStream);
}
#define GRPC_EXPERIMENT_IS_INCLUDED_CLIENT_IDLENESS
inline bool IsClientIdlenessEnabled() {
return IsExperimentEnabled(kExperimentIdClientIdleness);
@ -387,6 +379,14 @@ inline bool IsClientPrivacyEnabled() {
inline bool IsCombinerOffloadToEventEngineEnabled() {
return IsExperimentEnabled(kExperimentIdCombinerOffloadToEventEngine);
}
#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_BATCH_REQUESTS
inline bool IsChttp2BatchRequestsEnabled() {
return IsExperimentEnabled(kExperimentIdChttp2BatchRequests);
}
#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_OFFLOAD_ON_RST_STREAM
inline bool IsChttp2OffloadOnRstStreamEnabled() {
return IsExperimentEnabled(kExperimentIdChttp2OffloadOnRstStream);
}
#define GRPC_EXPERIMENT_IS_INCLUDED_EVENT_ENGINE_CLIENT
inline bool IsEventEngineClientEnabled() {
return IsExperimentEnabled(kExperimentIdEventEngineClient);
@ -535,14 +535,14 @@ inline bool IsWorkSerializerClearsTimeCacheEnabled() {
inline bool IsWorkSerializerDispatchEnabled() {
return IsExperimentEnabled(kExperimentIdWorkSerializerDispatch);
}
#define GRPC_EXPERIMENT_IS_INCLUDED_WRITE_SIZE_CAP
inline bool IsWriteSizeCapEnabled() {
return IsExperimentEnabled(kExperimentIdWriteSizeCap);
}
#define GRPC_EXPERIMENT_IS_INCLUDED_WRITE_SIZE_POLICY
inline bool IsWriteSizePolicyEnabled() {
return IsExperimentEnabled(kExperimentIdWriteSizePolicy);
}
#define GRPC_EXPERIMENT_IS_INCLUDED_WRITE_SIZE_CAP
inline bool IsWriteSizeCapEnabled() {
return IsExperimentEnabled(kExperimentIdWriteSizeCap);
}
#define GRPC_EXPERIMENT_IS_INCLUDED_WRR_DELEGATE_TO_PICK_FIRST
inline bool IsWrrDelegateToPickFirstEnabled() {
return IsExperimentEnabled(kExperimentIdWrrDelegateToPickFirst);

@ -22,6 +22,10 @@
# allow_in_fuzzing_config: optional boolean (true if not specified)
# if false, this experiment will not be included in fuzzers that
# explore the config space
# requires: A list of names of experiments that this experiment depends on.
# Defaults to the empty list.
# If any of the experiments in the required list is determined to
# be disabled at runtime, this experiment is disabled at runtime.
#
# Well known test tags:
# core_end2end_test: all tests, fixtures in the core end2end suite
@ -59,12 +63,14 @@
expiry: 2024/03/03
owner: ctiller@google.com
test_tags: ["cpp_end2end_test", "flow_control_test"]
requires: [combiner_offload_to_event_engine]
- name: chttp2_offload_on_rst_stream
description:
Offload work on RST_STREAM.
expiry: 2024/03/03
owner: ctiller@google.com
test_tags: ["cpp_end2end_test", "flow_control_test"]
requires: [combiner_offload_to_event_engine]
- name: client_idleness
description: If enabled, client channel idleness is enabled by default.
expiry: 2023/12/15
@ -210,6 +216,7 @@
expiry: 2024/06/14
owner: ctiller@google.com
test_tags: ["core_end2end_test", "cpp_end2end_test", "xds_end2end_test", "logging_test"]
requires: [lazier_stream_updates]
- name: red_max_concurrent_streams
description:
Perform random early rejection of requests that would exceed a newly reduced
@ -331,6 +338,7 @@
expiry: 2024/03/03
owner: ctiller@google.com
test_tags: [flow_control_test]
requires: [write_size_policy]
- name: write_size_policy
description:
Try to size writes such that they don't create too large of a backlog

@ -22,6 +22,10 @@
# - debug - the experiment defaults to on in debug builds,
# off in release builds in all platforms.
# - true - the experiment defaults to on in all platforms.
# requires: A list of names of experiments that this experiment depends on.
# Defaults to the empty list.
# If any of the experiments in the required list is determined to
# be disabled at runtime, this experiment is disabled at runtime.
#
# [OR] the default can be platform specific:
# -----------------------------------------

@ -41,13 +41,14 @@ namespace grpc_core {
const ExperimentMetadata g_test_experiment_metadata[] = {
{"test_experiment_1", description_test_experiment_1,
additional_constraints_test_experiment_1, false, true},
additional_constraints_test_experiment_1, nullptr, 0, false, true},
{"test_experiment_2", description_test_experiment_2,
additional_constraints_test_experiment_2, true, true},
additional_constraints_test_experiment_2, nullptr, 0, true, true},
{"test_experiment_3", description_test_experiment_3,
additional_constraints_test_experiment_3, kDefaultForDebugOnly, true},
additional_constraints_test_experiment_3, nullptr, 0, kDefaultForDebugOnly,
true},
{"test_experiment_4", description_test_experiment_4,
additional_constraints_test_experiment_4, true, true},
additional_constraints_test_experiment_4, nullptr, 0, true, true},
};
} // namespace grpc_core
@ -73,13 +74,14 @@ namespace grpc_core {
const ExperimentMetadata g_test_experiment_metadata[] = {
{"test_experiment_1", description_test_experiment_1,
additional_constraints_test_experiment_1, false, true},
additional_constraints_test_experiment_1, nullptr, 0, false, true},
{"test_experiment_2", description_test_experiment_2,
additional_constraints_test_experiment_2, false, true},
additional_constraints_test_experiment_2, nullptr, 0, false, true},
{"test_experiment_3", description_test_experiment_3,
additional_constraints_test_experiment_3, kDefaultForDebugOnly, true},
additional_constraints_test_experiment_3, nullptr, 0, kDefaultForDebugOnly,
true},
{"test_experiment_4", description_test_experiment_4,
additional_constraints_test_experiment_4, true, true},
additional_constraints_test_experiment_4, nullptr, 0, true, true},
};
} // namespace grpc_core
@ -105,13 +107,16 @@ namespace grpc_core {
const ExperimentMetadata g_test_experiment_metadata[] = {
{"test_experiment_1", description_test_experiment_1,
additional_constraints_test_experiment_1, kDefaultForDebugOnly, true},
additional_constraints_test_experiment_1, nullptr, 0, kDefaultForDebugOnly,
true},
{"test_experiment_2", description_test_experiment_2,
additional_constraints_test_experiment_2, kDefaultForDebugOnly, true},
additional_constraints_test_experiment_2, nullptr, 0, kDefaultForDebugOnly,
true},
{"test_experiment_3", description_test_experiment_3,
additional_constraints_test_experiment_3, kDefaultForDebugOnly, true},
additional_constraints_test_experiment_3, nullptr, 0, kDefaultForDebugOnly,
true},
{"test_experiment_4", description_test_experiment_4,
additional_constraints_test_experiment_4, false, true},
additional_constraints_test_experiment_4, nullptr, 0, false, true},
};
} // namespace grpc_core

@ -198,6 +198,7 @@ class ExperimentDefinition(object):
self._default = {}
self._additional_constraints = {}
self._test_tags = []
self._requires = set()
if "allow_in_fuzzing_config" in attributes:
self._allow_in_fuzzing_config = attributes[
@ -207,6 +208,9 @@ class ExperimentDefinition(object):
if "test_tags" in attributes:
self._test_tags = attributes["test_tags"]
for requirement in attributes.get("requires", []):
self._requires.add(requirement)
def IsValid(self, check_expiry=False):
if self._error:
return False
@ -244,6 +248,8 @@ class ExperimentDefinition(object):
" experiment: %s" % self._name
)
return False
for requirement in rollout_attributes.get("requires", []):
self._requires.add(requirement)
if "default" not in rollout_attributes:
print(
"ERROR: no default for experiment %s"
@ -310,7 +316,7 @@ class ExperimentsCompiler(object):
self._final_define = final_define
self._platforms_define = platforms_define
self._bzl_list_for_defaults = bzl_list_for_defaults
self._experiment_definitions = {}
self._experiment_definitions = collections.OrderedDict()
self._experiment_rollouts = {}
def AddExperimentDefinition(self, experiment_definition):
@ -344,6 +350,27 @@ class ExperimentsCompiler(object):
self._defaults, self._platforms_define, rollout_attributes
)
def _FinalizeExperiments(self):
queue = collections.OrderedDict()
for name, exp in self._experiment_definitions.items():
queue[name] = exp._requires
done = set()
final = collections.OrderedDict()
while queue:
take = None
for name, requires in queue.items():
if requires.issubset(done):
take = name
break
if take is None:
print("ERROR: circular dependency in experiments")
return False
done.add(take)
final[take] = self._experiment_definitions[take]
del queue[take]
self._experiment_definitions = final
return True
def _GenerateExperimentsHdrForPlatform(self, platform, file_desc):
for _, exp in self._experiment_definitions.items():
define_fmt = self._final_define[exp.default(platform)]
@ -363,6 +390,7 @@ class ExperimentsCompiler(object):
)
def GenerateExperimentsHdr(self, output_file, mode):
assert self._FinalizeExperiments()
with open(output_file, "w") as H:
PutCopyright(H, "//")
PutBanner(
@ -463,6 +491,18 @@ class ExperimentsCompiler(object):
file=file_desc,
)
have_defaults.add(self._defaults[exp.default(platform)])
if exp._requires:
print(
"const uint8_t required_experiments_%s[] = {%s};"
% (
exp.name,
",".join(
f"static_cast<uint8_t>(grpc_core::kExperimentId{SnakeToPascal(name)})"
for name in sorted(exp._requires)
),
),
file=file_desc,
)
if "kDefaultForDebugOnly" in have_defaults:
print("#ifdef NDEBUG", file=file_desc)
if "kDefaultForDebugOnly" in have_defaults:
@ -487,11 +527,15 @@ class ExperimentsCompiler(object):
)
for _, exp in self._experiment_definitions.items():
print(
" {%s, description_%s, additional_constraints_%s, %s, %s},"
" {%s, description_%s, additional_constraints_%s, %s, %d, %s, %s},"
% (
ToCStr(exp.name),
exp.name,
exp.name,
f"required_experiments_{exp.name}"
if exp._requires
else "nullptr",
len(exp._requires),
self._defaults[exp.default(platform)],
"true" if exp.allow_in_fuzzing_config else "false",
),
@ -502,6 +546,7 @@ class ExperimentsCompiler(object):
print("} // namespace grpc_core", file=file_desc)
def GenerateExperimentsSrc(self, output_file, header_file_path, mode):
assert self._FinalizeExperiments()
with open(output_file, "w") as C:
PutCopyright(C, "//")
PutBanner(
@ -510,7 +555,15 @@ class ExperimentsCompiler(object):
"//",
)
any_requires = False
for _, exp in self._experiment_definitions.items():
if exp._requires:
any_requires = True
break
print("#include <grpc/support/port_platform.h>", file=C)
if any_requires:
print("#include <stdint.h>", file=C)
print(f'#include "{header_file_path}"', file=C)
print(file=C)
print("#ifndef GRPC_EXPERIMENTS_ARE_FINAL", file=C)
@ -540,6 +593,7 @@ class ExperimentsCompiler(object):
return defs
def GenTest(self, output_file):
assert self._FinalizeExperiments()
with open(output_file, "w") as C:
PutCopyright(C, "//")
PutBanner(
@ -567,6 +621,7 @@ class ExperimentsCompiler(object):
print(_EXPERIMENTS_TEST_SKELETON(defs, test_body), file=C)
def GenExperimentsBzl(self, mode, output_file):
assert self._FinalizeExperiments()
if self._bzl_list_for_defaults is None:
return
@ -610,6 +665,19 @@ class ExperimentsCompiler(object):
file=B,
)
print(file=B)
if mode == "test":
print("TEST_EXPERIMENT_ENABLES = {", file=B)
else:
print("EXPERIMENT_ENABLES = {", file=B)
for name, exp in self._experiment_definitions.items():
enables = exp._requires.copy()
enables.add(name)
print(
f" \"{name}\": \"{','.join(sorted(enables))}\",", file=B
)
print("}", file=B)
print(file=B)
if mode == "test":
print("TEST_EXPERIMENTS = {", file=B)

Loading…
Cancel
Save