diff --git a/bazel/experiments.bzl b/bazel/experiments.bzl index 1656f5aef83..08083d21f8d 100644 --- a/bazel/experiments.bzl +++ b/bazel/experiments.bzl @@ -58,6 +58,12 @@ EXPERIMENT_ENABLES = { "wrr_delegate_to_pick_first": "wrr_delegate_to_pick_first", } +EXPERIMENT_POLLERS = [ + "event_engine_client", + "event_engine_dns", + "event_engine_listener", +] + EXPERIMENTS = { "windows": { "dbg": { diff --git a/bazel/grpc_build_system.bzl b/bazel/grpc_build_system.bzl index f151740a234..aa1b6645f7c 100644 --- a/bazel/grpc_build_system.bzl +++ b/bazel/grpc_build_system.bzl @@ -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", "EXPERIMENT_ENABLES") -load("//bazel:test_experiments.bzl", "TEST_EXPERIMENTS", "TEST_EXPERIMENT_ENABLES") +load("//bazel:experiments.bzl", "EXPERIMENTS", "EXPERIMENT_ENABLES", "EXPERIMENT_POLLERS") +load("//bazel:test_experiments.bzl", "TEST_EXPERIMENTS", "TEST_EXPERIMENT_ENABLES", "TEST_EXPERIMENT_POLLERS") 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") load("@com_google_protobuf//bazel:upb_proto_library.bzl", "upb_proto_library", "upb_proto_reflection_library") @@ -279,8 +279,10 @@ def ios_cc_test( deps = ios_test_deps, ) -def expand_tests(name, srcs, deps, tags, args, exclude_pollers, uses_polling, uses_event_engine, flaky): - """Common logic used to parameterize tests for every poller and EventEngine and experiment. +def expand_poller_config(name, srcs, deps, tags, args, exclude_pollers, uses_polling, uses_event_engine, flaky): + """Common logic used to parameterize tests for every poller and EventEngine. + + Used by expand_tests (repeatedly) to form base lists of pollers for each experiment. Args: name: base name of the test @@ -297,6 +299,7 @@ def expand_tests(name, srcs, deps, tags, args, exclude_pollers, uses_polling, us Returns: A list of dictionaries containing modified values of name, srcs, deps, tags, and args. """ + poller_config = [] # See work_stealing_thread_pool.cc for details. @@ -373,6 +376,27 @@ def expand_tests(name, srcs, deps, tags, args, exclude_pollers, uses_polling, us "flaky": flaky, }) + return poller_config + +def expand_tests(name, srcs, deps, tags, args, exclude_pollers, uses_polling, uses_event_engine, flaky): + """Common logic used to parameterize tests for every poller and EventEngine and experiment. + + Args: + name: base name of the test + srcs: source files + deps: base deps + tags: base tags + args: base args + flaky: base flaky + exclude_pollers: list of poller names to exclude for this set of tests. + uses_polling: set to False if the test is not sensitive to polling methodology. + uses_event_engine: set to False if the test is not sensitive to + EventEngine implementation differences + + Returns: + A list of dictionaries containing modified values of name, srcs, deps, tags, and args. + """ + experiments = {} # buildifier: disable=uninitialized @@ -421,13 +445,28 @@ def expand_tests(name, srcs, deps, tags, args, exclude_pollers, uses_polling, us tags.append("no_test_ios") return tags - experiment_config = list(poller_config) + base_params = { + "name": name, + "srcs": srcs, + "deps": deps, + "tags": tags, + "args": args, + "exclude_pollers": exclude_pollers, + "uses_polling": uses_polling, + "uses_event_engine": uses_event_engine, + "flaky": flaky, + } + + experiment_config = expand_poller_config(**base_params) experiment_enables = {k: v for k, v in EXPERIMENT_ENABLES.items() + TEST_EXPERIMENT_ENABLES.items()} + experiment_pollers = EXPERIMENT_POLLERS + TEST_EXPERIMENT_POLLERS for mode, config in mode_config.items(): enabled_tags, disabled_tags = config if enabled_tags != None: for experiment in experiments[mode].keys(): - for config in poller_config: + experiment_params = dict(base_params) + experiment_params["uses_polling"] = uses_polling and (experiment in experiment_pollers) + for config in expand_poller_config(**experiment_params): config = dict(config) config["name"] = config["name"] + "@experiment=" + experiment env = dict(config["env"]) @@ -443,7 +482,9 @@ def expand_tests(name, srcs, deps, tags, args, exclude_pollers, uses_polling, us experiment_config.append(config) if disabled_tags != None: for experiment in experiments[mode].keys(): - for config in poller_config: + experiment_params = dict(base_params) + experiment_params["uses_polling"] = uses_polling and (experiment in experiment_pollers) + for config in expand_poller_config(**experiment_params): config = dict(config) config["name"] = config["name"] + "@experiment=no_" + experiment env = dict(config["env"]) diff --git a/bazel/test_experiments.bzl b/bazel/test_experiments.bzl index 593d2dc4683..7d4e037b2dc 100644 --- a/bazel/test_experiments.bzl +++ b/bazel/test_experiments.bzl @@ -23,6 +23,9 @@ TEST_EXPERIMENT_ENABLES = { "test_experiment_4": "test_experiment_4", } +TEST_EXPERIMENT_POLLERS = [ +] + TEST_EXPERIMENTS = { "windows": { "dbg": { diff --git a/src/core/lib/experiments/experiments.yaml b/src/core/lib/experiments/experiments.yaml index d3a4ef55120..4988ce499c1 100644 --- a/src/core/lib/experiments/experiments.yaml +++ b/src/core/lib/experiments/experiments.yaml @@ -26,6 +26,9 @@ # 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. +# uses_polling: optional boolean (false if not specified) that indicates that +# this experiment should be tested with all different polling +# engines. # # Well known test tags: # core_end2end_test: all tests, fixtures in the core end2end suite @@ -68,6 +71,7 @@ expiry: 2024/04/01 owner: hork@google.com test_tags: ["core_end2end_test", "event_engine_client_test"] + uses_polling: true - name: event_engine_dns description: If set, use EventEngine DNSResolver for client channel resolution @@ -75,11 +79,13 @@ owner: yijiem@google.com test_tags: ["cancel_ares_query_test", "resolver_component_tests_runner_invoker"] allow_in_fuzzing_config: false + uses_polling: true - name: event_engine_listener description: Use EventEngine listeners instead of iomgr's grpc_tcp_server expiry: 2024/04/01 owner: vigneshbabu@google.com test_tags: ["core_end2end_test", "event_engine_listener_test"] + uses_polling: true - name: free_large_allocator description: If set, return all free bytes from a "big" allocator expiry: 2024/04/01 diff --git a/tools/codegen/core/experiments_compiler.py b/tools/codegen/core/experiments_compiler.py index 8812a8c301e..c86f8433006 100644 --- a/tools/codegen/core/experiments_compiler.py +++ b/tools/codegen/core/experiments_compiler.py @@ -192,6 +192,7 @@ class ExperimentDefinition(object): print("Failed to create experiment definition") return self._allow_in_fuzzing_config = True + self._uses_polling = False self._name = attributes["name"] self._description = attributes["description"] self._expiry = attributes["expiry"] @@ -200,6 +201,9 @@ class ExperimentDefinition(object): self._test_tags = [] self._requires = set() + if "uses_polling" in attributes: + self._uses_polling = attributes["uses_polling"] + if "allow_in_fuzzing_config" in attributes: self._allow_in_fuzzing_config = attributes[ "allow_in_fuzzing_config" @@ -683,6 +687,17 @@ class ExperimentsCompiler(object): ) print("}", file=B) + # Generate a list of experiments that use polling. + print(file=B) + if mode == "test": + print("TEST_EXPERIMENT_POLLERS = [", file=B) + else: + print("EXPERIMENT_POLLERS = [", file=B) + for name, exp in self._experiment_definitions.items(): + if exp._uses_polling: + print(f' "{name}",', file=B) + print("]", file=B) + print(file=B) if mode == "test": print("TEST_EXPERIMENTS = {", file=B)