diff --git a/BUILD b/BUILD
index 7121bc0b7c4..b8e53145408 100644
--- a/BUILD
+++ b/BUILD
@@ -402,6 +402,17 @@ grpc_cc_library(
deps = ["gpr_platform"],
)
+grpc_cc_library(
+ name = "experiments",
+ srcs = ["src/core/lib/experiments/experiments.cc"],
+ hdrs = ["src/core/lib/experiments/experiments.h"],
+ language = "c++",
+ deps = [
+ "gpr",
+ "gpr_platform",
+ ],
+)
+
grpc_cc_library(
name = "grpc_unsecure",
srcs = [
@@ -3185,6 +3196,7 @@ grpc_cc_library(
"error",
"event_engine_common",
"exec_ctx",
+ "experiments",
"gpr",
"gpr_tls",
"grpc_public_hdrs",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 00ad1a5ab08..d541b06ff44 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2124,6 +2124,7 @@ add_library(grpc
src/core/lib/event_engine/windows/iocp.cc
src/core/lib/event_engine/windows/win_socket.cc
src/core/lib/event_engine/windows/windows_engine.cc
+ src/core/lib/experiments/experiments.cc
src/core/lib/gprpp/status_helper.cc
src/core/lib/gprpp/time.cc
src/core/lib/gprpp/time_averaged_stats.cc
@@ -2758,6 +2759,7 @@ add_library(grpc_unsecure
src/core/lib/event_engine/windows/iocp.cc
src/core/lib/event_engine/windows/win_socket.cc
src/core/lib/event_engine/windows/windows_engine.cc
+ src/core/lib/experiments/experiments.cc
src/core/lib/gprpp/status_helper.cc
src/core/lib/gprpp/time.cc
src/core/lib/gprpp/time_averaged_stats.cc
diff --git a/Makefile b/Makefile
index 802119b0d03..77b17125ace 100644
--- a/Makefile
+++ b/Makefile
@@ -1440,6 +1440,7 @@ LIBGRPC_SRC = \
src/core/lib/event_engine/windows/iocp.cc \
src/core/lib/event_engine/windows/win_socket.cc \
src/core/lib/event_engine/windows/windows_engine.cc \
+ src/core/lib/experiments/experiments.cc \
src/core/lib/gprpp/status_helper.cc \
src/core/lib/gprpp/time.cc \
src/core/lib/gprpp/time_averaged_stats.cc \
@@ -1938,6 +1939,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/lib/event_engine/windows/iocp.cc \
src/core/lib/event_engine/windows/win_socket.cc \
src/core/lib/event_engine/windows/windows_engine.cc \
+ src/core/lib/experiments/experiments.cc \
src/core/lib/gprpp/status_helper.cc \
src/core/lib/gprpp/time.cc \
src/core/lib/gprpp/time_averaged_stats.cc \
diff --git a/bazel/experiments.bzl b/bazel/experiments.bzl
new file mode 100644
index 00000000000..e77ee6a1aad
--- /dev/null
+++ b/bazel/experiments.bzl
@@ -0,0 +1,18 @@
+# Copyright 2022 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Automatically generated by tools/codegen/core/gen_experiments.py
+
+"""Dictionary of tags to experiments so we know when to test different experiments."""
+EXPERIMENTS = {"endpoint_test": ["tcp_frame_size_tuning"], "core_end2end_test": ["tcp_frame_size_tuning"]}
diff --git a/bazel/grpc_build_system.bzl b/bazel/grpc_build_system.bzl
index 760ece9232d..4c59d5aa4f1 100644
--- a/bazel/grpc_build_system.bzl
+++ b/bazel/grpc_build_system.bzl
@@ -29,6 +29,7 @@ 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("@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")
@@ -259,8 +260,8 @@ def ios_cc_test(
deps = ios_test_deps,
)
-def expand_tests_for_each_poller_and_engine(name, srcs, deps, tags, args, exclude_pollers, uses_event_engine):
- """Common logic used to parameterize tests for every poller and EventEngine.
+def expand_tests(name, srcs, deps, tags, args, exclude_pollers, uses_event_engine):
+ """Common logic used to parameterize tests for every poller and EventEngine and experiment.
Args:
name: base name of the test
@@ -326,7 +327,37 @@ def expand_tests_for_each_poller_and_engine(name, srcs, deps, tags, args, exclud
"tags": test_tags,
"args": test_args,
})
- return poller_config
+
+ experiments = {}
+ for tag in tags:
+ if tag not in EXPERIMENTS:
+ continue
+ for experiment in EXPERIMENTS[tag]:
+ experiments[experiment] = 1
+ experiments = list(experiments.keys())
+
+ experiment_config = list(poller_config)
+ for experiment in experiments:
+ for config in poller_config:
+ config = dict(config)
+ config["name"] = config["name"] + "@experiment=" + experiment
+ config["args"] = config["args"] + ["--experiment=" + experiment]
+ tags = config["tags"]
+ must_have_tags = [
+ # We don't run experiments on cmake builds
+ "bazel_only",
+ # Nor on windows
+ "no_windows",
+ # Nor on mac
+ "no_mac",
+ ]
+ for tag in must_have_tags:
+ if tag not in tags:
+ tags = tags + [tag]
+ config["tags"] = tags
+ experiment_config.append(config)
+
+ return experiment_config
def grpc_cc_test(name, srcs = [], deps = [], external_deps = [], args = [], data = [], uses_polling = True, language = "C++", size = "medium", timeout = None, tags = [], exec_compatible_with = [], exec_properties = {}, shard_count = None, flaky = None, copts = [], linkstatic = None, exclude_pollers = [], uses_event_engine = True):
"""A cc_test target for use in the gRPC repo.
@@ -395,7 +426,7 @@ def grpc_cc_test(name, srcs = [], deps = [], external_deps = [], args = [], data
)
return
- for poller_config in expand_tests_for_each_poller_and_engine(name, srcs, core_deps, tags, args, exclude_pollers, uses_event_engine):
+ for poller_config in expand_tests(name, srcs, core_deps, tags, args, exclude_pollers, uses_event_engine):
native.cc_test(
name = poller_config["name"],
srcs = poller_config["srcs"],
@@ -497,7 +528,7 @@ def grpc_sh_test(name, srcs = [], args = [], data = [], uses_polling = True, siz
)
return
- for poller_config in expand_tests_for_each_poller_and_engine(name, srcs, [], tags, args, exclude_pollers, uses_event_engine):
+ for poller_config in expand_tests(name, srcs, [], tags, args, exclude_pollers, uses_event_engine):
native.sh_test(
name = poller_config["name"],
srcs = poller_config["srcs"],
diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml
index e242db4f9bf..dd38fab1698 100644
--- a/build_autogenerated.yaml
+++ b/build_autogenerated.yaml
@@ -795,6 +795,7 @@ libs:
- src/core/lib/event_engine/windows/iocp.h
- src/core/lib/event_engine/windows/win_socket.h
- src/core/lib/event_engine/windows/windows_engine.h
+ - src/core/lib/experiments/experiments.h
- src/core/lib/gprpp/atomic_utils.h
- src/core/lib/gprpp/bitset.h
- src/core/lib/gprpp/chunked_vector.h
@@ -1496,6 +1497,7 @@ libs:
- src/core/lib/event_engine/windows/iocp.cc
- src/core/lib/event_engine/windows/win_socket.cc
- src/core/lib/event_engine/windows/windows_engine.cc
+ - src/core/lib/experiments/experiments.cc
- src/core/lib/gprpp/status_helper.cc
- src/core/lib/gprpp/time.cc
- src/core/lib/gprpp/time_averaged_stats.cc
@@ -2010,6 +2012,7 @@ libs:
- src/core/lib/event_engine/windows/iocp.h
- src/core/lib/event_engine/windows/win_socket.h
- src/core/lib/event_engine/windows/windows_engine.h
+ - src/core/lib/experiments/experiments.h
- src/core/lib/gprpp/atomic_utils.h
- src/core/lib/gprpp/bitset.h
- src/core/lib/gprpp/chunked_vector.h
@@ -2351,6 +2354,7 @@ libs:
- src/core/lib/event_engine/windows/iocp.cc
- src/core/lib/event_engine/windows/win_socket.cc
- src/core/lib/event_engine/windows/windows_engine.cc
+ - src/core/lib/experiments/experiments.cc
- src/core/lib/gprpp/status_helper.cc
- src/core/lib/gprpp/time.cc
- src/core/lib/gprpp/time_averaged_stats.cc
diff --git a/config.m4 b/config.m4
index 13bc9665481..3994fb80f4b 100644
--- a/config.m4
+++ b/config.m4
@@ -488,6 +488,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/event_engine/windows/iocp.cc \
src/core/lib/event_engine/windows/win_socket.cc \
src/core/lib/event_engine/windows/windows_engine.cc \
+ src/core/lib/experiments/experiments.cc \
src/core/lib/gpr/alloc.cc \
src/core/lib/gpr/atm.cc \
src/core/lib/gpr/cpu_iphone.cc \
@@ -1331,6 +1332,7 @@ if test "$PHP_GRPC" != "no"; then
PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/event_engine/executor)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/event_engine/posix_engine)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/event_engine/windows)
+ PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/experiments)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/gpr)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/gprpp)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/http)
diff --git a/config.w32 b/config.w32
index 9b4ae930689..32847fe0417 100644
--- a/config.w32
+++ b/config.w32
@@ -454,6 +454,7 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\event_engine\\windows\\iocp.cc " +
"src\\core\\lib\\event_engine\\windows\\win_socket.cc " +
"src\\core\\lib\\event_engine\\windows\\windows_engine.cc " +
+ "src\\core\\lib\\experiments\\experiments.cc " +
"src\\core\\lib\\gpr\\alloc.cc " +
"src\\core\\lib\\gpr\\atm.cc " +
"src\\core\\lib\\gpr\\cpu_iphone.cc " +
@@ -1453,6 +1454,7 @@ if (PHP_GRPC != "no") {
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\event_engine\\executor");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\event_engine\\posix_engine");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\event_engine\\windows");
+ FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\experiments");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\gpr");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\gprpp");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\http");
diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec
index fb683eabd54..1cade5b9012 100644
--- a/gRPC-C++.podspec
+++ b/gRPC-C++.podspec
@@ -700,6 +700,7 @@ Pod::Spec.new do |s|
'src/core/lib/event_engine/windows/iocp.h',
'src/core/lib/event_engine/windows/win_socket.h',
'src/core/lib/event_engine/windows/windows_engine.h',
+ 'src/core/lib/experiments/experiments.h',
'src/core/lib/gpr/alloc.h',
'src/core/lib/gpr/env.h',
'src/core/lib/gpr/murmur_hash.h',
@@ -1557,6 +1558,7 @@ Pod::Spec.new do |s|
'src/core/lib/event_engine/windows/iocp.h',
'src/core/lib/event_engine/windows/win_socket.h',
'src/core/lib/event_engine/windows/windows_engine.h',
+ 'src/core/lib/experiments/experiments.h',
'src/core/lib/gpr/alloc.h',
'src/core/lib/gpr/env.h',
'src/core/lib/gpr/murmur_hash.h',
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index 060736e0482..10c883785ca 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -1086,6 +1086,8 @@ Pod::Spec.new do |s|
'src/core/lib/event_engine/windows/win_socket.h',
'src/core/lib/event_engine/windows/windows_engine.cc',
'src/core/lib/event_engine/windows/windows_engine.h',
+ 'src/core/lib/experiments/experiments.cc',
+ 'src/core/lib/experiments/experiments.h',
'src/core/lib/gpr/alloc.cc',
'src/core/lib/gpr/alloc.h',
'src/core/lib/gpr/atm.cc',
@@ -2179,6 +2181,7 @@ Pod::Spec.new do |s|
'src/core/lib/event_engine/windows/iocp.h',
'src/core/lib/event_engine/windows/win_socket.h',
'src/core/lib/event_engine/windows/windows_engine.h',
+ 'src/core/lib/experiments/experiments.h',
'src/core/lib/gpr/alloc.h',
'src/core/lib/gpr/env.h',
'src/core/lib/gpr/murmur_hash.h',
diff --git a/grpc.gemspec b/grpc.gemspec
index d30e2621ec1..22583fd3288 100644
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -999,6 +999,8 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/event_engine/windows/win_socket.h )
s.files += %w( src/core/lib/event_engine/windows/windows_engine.cc )
s.files += %w( src/core/lib/event_engine/windows/windows_engine.h )
+ s.files += %w( src/core/lib/experiments/experiments.cc )
+ s.files += %w( src/core/lib/experiments/experiments.h )
s.files += %w( src/core/lib/gpr/alloc.cc )
s.files += %w( src/core/lib/gpr/alloc.h )
s.files += %w( src/core/lib/gpr/atm.cc )
diff --git a/grpc.gyp b/grpc.gyp
index be5f96a09e6..a173a35b0bd 100644
--- a/grpc.gyp
+++ b/grpc.gyp
@@ -819,6 +819,7 @@
'src/core/lib/event_engine/windows/iocp.cc',
'src/core/lib/event_engine/windows/win_socket.cc',
'src/core/lib/event_engine/windows/windows_engine.cc',
+ 'src/core/lib/experiments/experiments.cc',
'src/core/lib/gprpp/status_helper.cc',
'src/core/lib/gprpp/time.cc',
'src/core/lib/gprpp/time_averaged_stats.cc',
@@ -1262,6 +1263,7 @@
'src/core/lib/event_engine/windows/iocp.cc',
'src/core/lib/event_engine/windows/win_socket.cc',
'src/core/lib/event_engine/windows/windows_engine.cc',
+ 'src/core/lib/experiments/experiments.cc',
'src/core/lib/gprpp/status_helper.cc',
'src/core/lib/gprpp/time.cc',
'src/core/lib/gprpp/time_averaged_stats.cc',
diff --git a/package.xml b/package.xml
index e2ffa036c0b..4c04a727a28 100644
--- a/package.xml
+++ b/package.xml
@@ -981,6 +981,8 @@
+
+
diff --git a/src/core/lib/experiments/experiments.cc b/src/core/lib/experiments/experiments.cc
new file mode 100644
index 00000000000..34eb7a2ff42
--- /dev/null
+++ b/src/core/lib/experiments/experiments.cc
@@ -0,0 +1,47 @@
+// Copyright 2022 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Automatically generated by tools/codegen/core/gen_experiments.py
+
+#include
+
+#include "src/core/lib/experiments/experiments.h"
+
+#include "src/core/lib/gprpp/global_config.h"
+
+namespace {
+const char* const description_tcp_frame_size_tuning =
+ "If set, enables TCP to use RPC size estimation made by higher layers. TCP "
+ "would not indicate completion of a read operation until a specified "
+ "number of bytes have been read over the socket. Buffers are also "
+ "allocated according to estimated RPC sizes.";
+}
+
+GPR_GLOBAL_CONFIG_DEFINE_BOOL(grpc_experimental_enable_tcp_frame_size_tuning,
+ false, description_tcp_frame_size_tuning);
+
+namespace grpc_core {
+
+bool IsTcpFrameSizeTuningEnabled() {
+ static const bool enabled =
+ GPR_GLOBAL_CONFIG_GET(grpc_experimental_enable_tcp_frame_size_tuning);
+ return enabled;
+}
+
+const ExperimentMetadata g_experiment_metadata[] = {
+ {"tcp_frame_size_tuning", description_tcp_frame_size_tuning, false,
+ IsTcpFrameSizeTuningEnabled},
+};
+
+} // namespace grpc_core
diff --git a/src/core/lib/experiments/experiments.h b/src/core/lib/experiments/experiments.h
new file mode 100644
index 00000000000..c955ea63f34
--- /dev/null
+++ b/src/core/lib/experiments/experiments.h
@@ -0,0 +1,40 @@
+// Copyright 2022 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Automatically generated by tools/codegen/core/gen_experiments.py
+
+#ifndef GRPC_CORE_LIB_EXPERIMENTS_EXPERIMENTS_H
+#define GRPC_CORE_LIB_EXPERIMENTS_EXPERIMENTS_H
+
+#include
+
+#include
+
+namespace grpc_core {
+
+bool IsTcpFrameSizeTuningEnabled();
+
+struct ExperimentMetadata {
+ const char* name;
+ const char* description;
+ bool default_value;
+ bool (*is_enabled)();
+};
+
+constexpr const size_t kNumExperiments = 1;
+extern const ExperimentMetadata g_experiment_metadata[kNumExperiments];
+
+} // namespace grpc_core
+
+#endif // GRPC_CORE_LIB_EXPERIMENTS_EXPERIMENTS_H
diff --git a/src/core/lib/experiments/experiments.yaml b/src/core/lib/experiments/experiments.yaml
new file mode 100644
index 00000000000..7c5ec44d1c1
--- /dev/null
+++ b/src/core/lib/experiments/experiments.yaml
@@ -0,0 +1,37 @@
+# Copyright 2022 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Format of each entry:
+# name: name of the experiment
+# description: description of the experiment
+# default: boolean - does this experiment default on
+# expiry: when is the next time this experiment *must* be updated
+# (date, YYYY/MM/DD)
+# test_tags: a set of bazel tags, that if a test declares them signals
+# that that test should be run with this experiment enabled in CI
+#
+# Well known test tags:
+# core_end2end_tests: all tests, fixtures in the core end2end suite
+# endpoint_test: endpoint related iomgr tests
+
+- name: tcp_frame_size_tuning
+ description:
+ If set, enables TCP to use RPC size estimation made by higher layers.
+ TCP would not indicate completion of a read operation until a specified
+ number of bytes have been read over the socket.
+ Buffers are also allocated according to estimated RPC sizes.
+ default: false
+ expiry: 2022/09/01
+ owner: ctiller@google.com
+ test_tags: ["endpoint_test", "core_end2end_test"]
diff --git a/src/core/lib/iomgr/iomgr.cc b/src/core/lib/iomgr/iomgr.cc
index 777c03c319a..8a9eadd18af 100644
--- a/src/core/lib/iomgr/iomgr.cc
+++ b/src/core/lib/iomgr/iomgr.cc
@@ -45,13 +45,6 @@ GPR_GLOBAL_CONFIG_DEFINE_BOOL(grpc_abort_on_leaks, false,
"A debugging aid to cause a call to abort() when "
"gRPC objects are leaked past grpc_shutdown()");
-GPR_GLOBAL_CONFIG_DEFINE_BOOL(
- grpc_experimental_enable_tcp_frame_size_tuning, false,
- "If set, enables TCP to use RPC size estimation made by higher layers. TCP "
- "would not indicate completion of a read operation until a specified "
- "number of bytes have been read over the socket. Buffers are also "
- "allocated according to estimated RPC sizes.");
-
static gpr_mu g_mu;
static gpr_cv g_rcv;
static int g_shutdown;
diff --git a/src/core/lib/iomgr/tcp_posix.cc b/src/core/lib/iomgr/tcp_posix.cc
index 09c23d9b193..de8bb36b020 100644
--- a/src/core/lib/iomgr/tcp_posix.cc
+++ b/src/core/lib/iomgr/tcp_posix.cc
@@ -50,6 +50,7 @@
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/debug/stats.h"
#include "src/core/lib/debug/trace.h"
+#include "src/core/lib/experiments/experiments.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/sync.h"
@@ -96,8 +97,6 @@ typedef size_t msg_iovlen_type;
extern grpc_core::TraceFlag grpc_tcp_trace;
-GPR_GLOBAL_CONFIG_DECLARE_BOOL(grpc_experimental_enable_tcp_frame_size_tuning);
-
namespace grpc_core {
class TcpZerocopySendRecord {
@@ -465,12 +464,6 @@ using grpc_core::TcpZerocopySendRecord;
namespace {
-bool ExperimentalTcpFrameSizeTuningEnabled() {
- static const bool kEnableTcpFrameSizeTuning =
- GPR_GLOBAL_CONFIG_GET(grpc_experimental_enable_tcp_frame_size_tuning);
- return kEnableTcpFrameSizeTuning;
-}
-
struct grpc_tcp {
grpc_tcp(int max_sends, size_t send_bytes_threshold)
: tcp_zerocopy_send_ctx(max_sends, send_bytes_threshold) {}
@@ -1956,7 +1949,7 @@ grpc_endpoint* grpc_tcp_create(grpc_fd* em_fd,
tcp->socket_ts_enabled = false;
tcp->ts_capable = true;
tcp->outgoing_buffer_arg = nullptr;
- tcp->frame_size_tuning_enabled = ExperimentalTcpFrameSizeTuningEnabled();
+ tcp->frame_size_tuning_enabled = grpc_core::IsTcpFrameSizeTuningEnabled();
tcp->min_progress_size = 1;
if (tcp_tx_zerocopy_enabled && !tcp->tcp_zerocopy_send_ctx.memory_limited()) {
#ifdef GRPC_LINUX_ERRQUEUE
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index 63a873bf72c..8162829ff14 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -463,6 +463,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/event_engine/windows/iocp.cc',
'src/core/lib/event_engine/windows/win_socket.cc',
'src/core/lib/event_engine/windows/windows_engine.cc',
+ 'src/core/lib/experiments/experiments.cc',
'src/core/lib/gpr/alloc.cc',
'src/core/lib/gpr/atm.cc',
'src/core/lib/gpr/cpu_iphone.cc',
diff --git a/test/core/end2end/generate_tests.bzl b/test/core/end2end/generate_tests.bzl
index 5b491e6f86e..249e98b1859 100755
--- a/test/core/end2end/generate_tests.bzl
+++ b/test/core/end2end/generate_tests.bzl
@@ -473,6 +473,7 @@ def grpc_end2end_tests():
args = ["$(location %s)" % bin_name, t],
tags = _platform_support_tags(fopt) + fopt.tags + [
"no_test_ios",
+ "core_end2end_test",
],
flaky = name in FLAKY_TESTS,
exclude_pollers = topt.exclude_pollers,
diff --git a/test/core/iomgr/BUILD b/test/core/iomgr/BUILD
index 05a9dedb43a..7bc51281b09 100644
--- a/test/core/iomgr/BUILD
+++ b/test/core/iomgr/BUILD
@@ -60,6 +60,7 @@ grpc_cc_test(
srcs = ["endpoint_pair_test.cc"],
external_deps = ["gtest"],
language = "C++",
+ tags = ["endpoint_test"],
deps = [
":endpoint_tests",
"//:gpr",
@@ -241,7 +242,10 @@ grpc_cc_test(
srcs = ["tcp_client_posix_test.cc"],
external_deps = ["gtest"],
language = "C++",
- tags = ["no_windows"],
+ tags = [
+ "endpoint_test",
+ "no_windows",
+ ],
deps = [
"//:gpr",
"//:grpc",
@@ -255,6 +259,7 @@ grpc_cc_test(
srcs = ["tcp_posix_test.cc"],
language = "C++",
tags = [
+ "endpoint_test",
"no_mac", # TODO(jtattermusch): Reenable once https://github.com/grpc/grpc/issues/21282 is fixed.
"no_windows",
],
diff --git a/test/core/util/test_config.cc b/test/core/util/test_config.cc
index 997c5f3b932..f6a5e09b679 100644
--- a/test/core/util/test_config.cc
+++ b/test/core/util/test_config.cc
@@ -20,13 +20,13 @@
#include
#include
-#include
#include
#include "absl/debugging/failure_signal_handler.h"
#include "absl/status/status.h"
#include "absl/strings/match.h"
+#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include
@@ -94,8 +94,9 @@ gpr_timespec grpc_timeout_milliseconds_to_deadline(int64_t time_ms) {
namespace {
void RmArg(int i, int* argc, char** argv) {
--(*argc);
- if (i < *argc) {
- memmove(argv + i, argv + i + 1, *argc - i);
+ while (i < *argc) {
+ argv[i] = argv[i + 1];
+ ++i;
}
}
@@ -104,6 +105,7 @@ void ParseTestArgs(int* argc, char** argv) {
// flags to look for and consume
const absl::string_view poller_flag{"--poller="};
const absl::string_view engine_flag{"--engine="};
+ const absl::string_view experiment_flag{"--experiment="};
int i = 1;
while (i < *argc) {
if (absl::StartsWith(argv[i], poller_flag)) {
@@ -124,6 +126,15 @@ void ParseTestArgs(int* argc, char** argv) {
RmArg(i, argc, argv);
continue;
}
+ if (absl::StartsWith(argv[i], experiment_flag)) {
+ gpr_setenv(
+ absl::StrCat("GRPC_EXPERIMENT_", argv[i] + experiment_flag.length())
+ .c_str(),
+ "true");
+ // remove the spent argv
+ RmArg(i, argc, argv);
+ continue;
+ }
++i;
}
}
diff --git a/tools/codegen/core/gen_experiments.py b/tools/codegen/core/gen_experiments.py
new file mode 100755
index 00000000000..e2edb4c6316
--- /dev/null
+++ b/tools/codegen/core/gen_experiments.py
@@ -0,0 +1,218 @@
+#!/usr/bin/env python3
+
+# Copyright 2022 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""
+Generate experiment related code artifacts.
+
+Invoke as: tools/codegen/core/gen_experiments.py
+Experiment definitions are in src/core/lib/experiments/experiments.yaml
+"""
+
+from __future__ import print_function
+
+import collections
+import ctypes
+import datetime
+import json
+import math
+import os
+import re
+import sys
+
+import yaml
+
+with open('src/core/lib/experiments/experiments.yaml') as f:
+ attrs = yaml.load(f.read(), Loader=yaml.FullLoader)
+
+error = False
+today = datetime.date.today()
+two_quarters_from_now = today + datetime.timedelta(days=180)
+for attr in attrs:
+ if 'name' not in attr:
+ print("experiment with no name: %r" % attr)
+ error = True
+ continue # can't run other diagnostics because we don't know a name
+ if 'description' not in attr:
+ print("no description for experiment %s" % attr['name'])
+ error = True
+ if 'default' not in attr:
+ print("no default for experiment %s" % attr['name'])
+ error = True
+ if 'expiry' not in attr:
+ print("no expiry for experiment %s" % attr['name'])
+ error = True
+ if 'owner' not in attr:
+ print("no owner for experiment %s" % attr['name'])
+ error = True
+ expiry = datetime.datetime.strptime(attr['expiry'], '%Y/%m/%d').date()
+ if expiry < today:
+ print("experiment %s expired on %s" % (attr['name'], attr['expiry']))
+ error = True
+ if expiry > two_quarters_from_now:
+ print("experiment %s expires far in the future on %s" %
+ (attr['name'], attr['expiry']))
+ print("expiry should be no more than two quarters from now")
+ error = True
+
+if error:
+ sys.exit(1)
+
+
+def c_str(s, encoding='ascii'):
+ if isinstance(s, str):
+ s = s.encode(encoding)
+ result = ''
+ for c in s:
+ c = chr(c) if isinstance(c, int) else c
+ if not (32 <= ord(c) < 127) or c in ('\\', '"'):
+ result += '\\%03o' % ord(c)
+ else:
+ result += c
+ return '"' + result + '"'
+
+
+def snake_to_pascal(s):
+ return ''.join(x.capitalize() for x in s.split('_'))
+
+
+# utility: print a big comment block into a set of files
+def put_banner(files, banner, prefix):
+ for f in files:
+ for line in banner:
+ print('%s %s' % (prefix, line), file=f)
+ print(file=f)
+
+
+def put_copyright(file, prefix):
+ # copy-paste copyright notice from this file
+ with open(sys.argv[0]) as my_source:
+ copyright = []
+ for line in my_source:
+ if line[0] != '#':
+ break
+ for line in my_source:
+ if line[0] == '#':
+ copyright.append(line)
+ break
+ for line in my_source:
+ if line[0] != '#':
+ break
+ copyright.append(line)
+ put_banner([file], [line[2:].rstrip() for line in copyright], prefix)
+
+
+EXPERIMENT_METADATA = """struct ExperimentMetadata {
+ const char* name;
+ const char* description;
+ bool default_value;
+ bool (*is_enabled)();
+};"""
+
+with open('src/core/lib/experiments/experiments.h', 'w') as H:
+ put_copyright(H, "//")
+
+ put_banner(
+ [H],
+ ["Automatically generated by tools/codegen/core/gen_experiments.py"],
+ "//")
+
+ print("#ifndef GRPC_CORE_LIB_EXPERIMENTS_EXPERIMENTS_H", file=H)
+ print("#define GRPC_CORE_LIB_EXPERIMENTS_EXPERIMENTS_H", file=H)
+ print(file=H)
+ print("#include ", file=H)
+ print(file=H)
+ print("#include ", file=H)
+ print(file=H)
+ print("namespace grpc_core {", file=H)
+ print(file=H)
+ for attr in attrs:
+ print("bool Is%sEnabled();" % snake_to_pascal(attr['name']), file=H)
+ print(file=H)
+ print(EXPERIMENT_METADATA, file=H)
+ print(file=H)
+ print("constexpr const size_t kNumExperiments = %d;" % len(attrs), file=H)
+ print(
+ "extern const ExperimentMetadata g_experiment_metadata[kNumExperiments];",
+ file=H)
+ print(file=H)
+ print("} // namespace grpc_core", file=H)
+ print(file=H)
+ print("#endif // GRPC_CORE_LIB_EXPERIMENTS_EXPERIMENTS_H", file=H)
+
+with open('src/core/lib/experiments/experiments.cc', 'w') as C:
+ put_copyright(C, "//")
+
+ put_banner(
+ [C],
+ ["Automatically generated by tools/codegen/core/gen_experiments.py"],
+ "//")
+
+ print("#include ", file=C)
+ print("#include \"src/core/lib/experiments/experiments.h\"", file=C)
+ print("#include \"src/core/lib/gprpp/global_config.h\"", file=C)
+ print(file=C)
+ print("namespace {", file=C)
+ for attr in attrs:
+ print("const char* const description_%s = %s;" %
+ (attr['name'], c_str(attr['description'])),
+ file=C)
+ print("}", file=C)
+ print(file=C)
+ for attr in attrs:
+ print(
+ "GPR_GLOBAL_CONFIG_DEFINE_BOOL(grpc_experimental_enable_%s, %s, description_%s);"
+ % (attr['name'], 'true' if attr['default'] else 'false',
+ attr['name']),
+ file=C)
+ print(file=C)
+ print("namespace grpc_core {", file=C)
+ print(file=C)
+ for attr in attrs:
+ print("bool Is%sEnabled() {" % snake_to_pascal(attr['name']), file=C)
+ print(
+ " static const bool enabled = GPR_GLOBAL_CONFIG_GET(grpc_experimental_enable_%s);"
+ % attr['name'],
+ file=C)
+ print(" return enabled;", file=C)
+ print("}", file=C)
+ print(file=C)
+ print("const ExperimentMetadata g_experiment_metadata[] = {", file=C)
+ for attr in attrs:
+ print(" {%s, description_%s, %s, Is%sEnabled}," %
+ (c_str(attr['name']), attr['name'], 'true'
+ if attr['default'] else 'false', snake_to_pascal(attr['name'])),
+ file=C)
+ print("};", file=C)
+ print(file=C)
+ print("} // namespace grpc_core", file=C)
+
+tags_to_experiments = collections.defaultdict(list)
+for attr in attrs:
+ for tag in attr['test_tags']:
+ tags_to_experiments[tag].append(attr['name'])
+
+with open('bazel/experiments.bzl', 'w') as B:
+ put_copyright(B, "#")
+
+ put_banner(
+ [B],
+ ["Automatically generated by tools/codegen/core/gen_experiments.py"],
+ "#")
+
+ print(
+ "\"\"\"Dictionary of tags to experiments so we know when to test different experiments.\"\"\"",
+ file=B)
+
+ print("EXPERIMENTS=%r" % dict(tags_to_experiments), file=B)
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index 142f00f13da..cdc7f4551f6 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -1982,6 +1982,8 @@ src/core/lib/event_engine/windows/win_socket.cc \
src/core/lib/event_engine/windows/win_socket.h \
src/core/lib/event_engine/windows/windows_engine.cc \
src/core/lib/event_engine/windows/windows_engine.h \
+src/core/lib/experiments/experiments.cc \
+src/core/lib/experiments/experiments.h \
src/core/lib/gpr/alloc.cc \
src/core/lib/gpr/alloc.h \
src/core/lib/gpr/atm.cc \
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index 4afc526927d..cb15c9afefd 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -1772,6 +1772,8 @@ src/core/lib/event_engine/windows/win_socket.cc \
src/core/lib/event_engine/windows/win_socket.h \
src/core/lib/event_engine/windows/windows_engine.cc \
src/core/lib/event_engine/windows/windows_engine.h \
+src/core/lib/experiments/experiments.cc \
+src/core/lib/experiments/experiments.h \
src/core/lib/gpr/README.md \
src/core/lib/gpr/alloc.cc \
src/core/lib/gpr/alloc.h \
diff --git a/tools/internal_ci/linux/grpc_bazel_rbe.sh b/tools/internal_ci/linux/grpc_bazel_rbe.sh
index c7c7f3bac8e..f8f031fa5e0 100755
--- a/tools/internal_ci/linux/grpc_bazel_rbe.sh
+++ b/tools/internal_ci/linux/grpc_bazel_rbe.sh
@@ -33,4 +33,4 @@ bazel_rbe/bazel_wrapper \
test \
$BAZEL_FLAGS \
"$@" \
- -- //test/...
+ -- ${BAZEL_TESTS:-//test/...}