diff --git a/CMakeLists.txt b/CMakeLists.txt index d9360e09e50..838ae79c140 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -886,7 +886,20 @@ protobuf_generate_grpc_cpp_with_import_path_correction( if(gRPC_BUILD_TESTS) add_custom_target(buildtests_c) + if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX) + add_dependencies(buildtests_c bm_call_spine) + endif() + if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX) + add_dependencies(buildtests_c bm_client_call) + endif() + if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX) + add_dependencies(buildtests_c bm_client_channel) + endif() add_dependencies(buildtests_c bm_experiments) + add_dependencies(buildtests_c bm_http_client_filter) + if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX) + add_dependencies(buildtests_c bm_party) + endif() if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) add_dependencies(buildtests_c fd_conservation_posix_test) endif() @@ -5809,6 +5822,123 @@ endif() endif() +if(gRPC_BUILD_TESTS) +if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX) + + add_executable(bm_call_spine + test/core/transport/bm_call_spine.cc + ) + if(WIN32 AND MSVC) + if(BUILD_SHARED_LIBS) + target_compile_definitions(bm_call_spine + PRIVATE + "GPR_DLL_IMPORTS" + "GRPC_DLL_IMPORTS" + ) + endif() + endif() + target_compile_features(bm_call_spine PUBLIC cxx_std_14) + target_include_directories(bm_call_spine + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR} + ${_gRPC_RE2_INCLUDE_DIR} + ${_gRPC_SSL_INCLUDE_DIR} + ${_gRPC_UPB_GENERATED_DIR} + ${_gRPC_UPB_GRPC_GENERATED_DIR} + ${_gRPC_UPB_INCLUDE_DIR} + ${_gRPC_XXHASH_INCLUDE_DIR} + ${_gRPC_ZLIB_INCLUDE_DIR} + ) + + target_link_libraries(bm_call_spine + ${_gRPC_ALLTARGETS_LIBRARIES} + ${_gRPC_BENCHMARK_LIBRARIES} + grpc + ) + + +endif() +endif() +if(gRPC_BUILD_TESTS) +if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX) + + add_executable(bm_client_call + test/core/call/bm_client_call.cc + ) + if(WIN32 AND MSVC) + if(BUILD_SHARED_LIBS) + target_compile_definitions(bm_client_call + PRIVATE + "GPR_DLL_IMPORTS" + "GRPC_DLL_IMPORTS" + ) + endif() + endif() + target_compile_features(bm_client_call PUBLIC cxx_std_14) + target_include_directories(bm_client_call + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR} + ${_gRPC_RE2_INCLUDE_DIR} + ${_gRPC_SSL_INCLUDE_DIR} + ${_gRPC_UPB_GENERATED_DIR} + ${_gRPC_UPB_GRPC_GENERATED_DIR} + ${_gRPC_UPB_INCLUDE_DIR} + ${_gRPC_XXHASH_INCLUDE_DIR} + ${_gRPC_ZLIB_INCLUDE_DIR} + ) + + target_link_libraries(bm_client_call + ${_gRPC_ALLTARGETS_LIBRARIES} + ${_gRPC_BENCHMARK_LIBRARIES} + grpc + ) + + +endif() +endif() +if(gRPC_BUILD_TESTS) +if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX) + + add_executable(bm_client_channel + test/core/client_channel/bm_client_channel.cc + ) + if(WIN32 AND MSVC) + if(BUILD_SHARED_LIBS) + target_compile_definitions(bm_client_channel + PRIVATE + "GPR_DLL_IMPORTS" + "GRPC_DLL_IMPORTS" + ) + endif() + endif() + target_compile_features(bm_client_channel PUBLIC cxx_std_14) + target_include_directories(bm_client_channel + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR} + ${_gRPC_RE2_INCLUDE_DIR} + ${_gRPC_SSL_INCLUDE_DIR} + ${_gRPC_UPB_GENERATED_DIR} + ${_gRPC_UPB_GRPC_GENERATED_DIR} + ${_gRPC_UPB_INCLUDE_DIR} + ${_gRPC_XXHASH_INCLUDE_DIR} + ${_gRPC_ZLIB_INCLUDE_DIR} + ) + + target_link_libraries(bm_client_channel + ${_gRPC_ALLTARGETS_LIBRARIES} + ${_gRPC_BENCHMARK_LIBRARIES} + grpc + ) + + +endif() +endif() if(gRPC_BUILD_TESTS) add_executable(bm_experiments @@ -5848,6 +5978,82 @@ target_link_libraries(bm_experiments ) +endif() +if(gRPC_BUILD_TESTS) + +add_executable(bm_http_client_filter + test/core/filters/bm_http_client_filter.cc +) +if(WIN32 AND MSVC) + if(BUILD_SHARED_LIBS) + target_compile_definitions(bm_http_client_filter + PRIVATE + "GPR_DLL_IMPORTS" + "GRPC_DLL_IMPORTS" + ) + endif() +endif() +target_compile_features(bm_http_client_filter PUBLIC cxx_std_14) +target_include_directories(bm_http_client_filter + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR} + ${_gRPC_RE2_INCLUDE_DIR} + ${_gRPC_SSL_INCLUDE_DIR} + ${_gRPC_UPB_GENERATED_DIR} + ${_gRPC_UPB_GRPC_GENERATED_DIR} + ${_gRPC_UPB_INCLUDE_DIR} + ${_gRPC_XXHASH_INCLUDE_DIR} + ${_gRPC_ZLIB_INCLUDE_DIR} +) + +target_link_libraries(bm_http_client_filter + ${_gRPC_ALLTARGETS_LIBRARIES} + ${_gRPC_BENCHMARK_LIBRARIES} + grpc +) + + +endif() +if(gRPC_BUILD_TESTS) +if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX) + + add_executable(bm_party + test/core/promise/bm_party.cc + ) + if(WIN32 AND MSVC) + if(BUILD_SHARED_LIBS) + target_compile_definitions(bm_party + PRIVATE + "GPR_DLL_IMPORTS" + "GRPC_DLL_IMPORTS" + ) + endif() + endif() + target_compile_features(bm_party PUBLIC cxx_std_14) + target_include_directories(bm_party + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR} + ${_gRPC_RE2_INCLUDE_DIR} + ${_gRPC_SSL_INCLUDE_DIR} + ${_gRPC_UPB_GENERATED_DIR} + ${_gRPC_UPB_GRPC_GENERATED_DIR} + ${_gRPC_UPB_INCLUDE_DIR} + ${_gRPC_XXHASH_INCLUDE_DIR} + ${_gRPC_ZLIB_INCLUDE_DIR} + ) + + target_link_libraries(bm_party + ${_gRPC_ALLTARGETS_LIBRARIES} + ${_gRPC_BENCHMARK_LIBRARIES} + grpc + ) + + +endif() endif() if(gRPC_BUILD_TESTS) if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml index e937a527def..3f93c7d8199 100644 --- a/build_autogenerated.yaml +++ b/build_autogenerated.yaml @@ -5128,6 +5128,59 @@ libs: - grpc++ - opentelemetry-cpp::api targets: +- name: bm_call_spine + build: test + language: c + headers: + - test/core/transport/call_spine_benchmarks.h + src: + - test/core/transport/bm_call_spine.cc + deps: + - benchmark + - grpc + args: + - --benchmark_min_time=0.001s + benchmark: true + defaults: benchmark + platforms: + - linux + - posix + uses_polling: false +- name: bm_client_call + build: test + language: c + headers: [] + src: + - test/core/call/bm_client_call.cc + deps: + - benchmark + - grpc + args: + - --benchmark_min_time=0.001s + benchmark: true + defaults: benchmark + platforms: + - linux + - posix + uses_polling: false +- name: bm_client_channel + build: test + language: c + headers: + - test/core/transport/call_spine_benchmarks.h + src: + - test/core/client_channel/bm_client_channel.cc + deps: + - benchmark + - grpc + args: + - --benchmark_min_time=0.001s + benchmark: true + defaults: benchmark + platforms: + - linux + - posix + uses_polling: false - name: bm_experiments build: test language: c @@ -5141,6 +5194,38 @@ targets: - grpc_test_util benchmark: true defaults: benchmark +- name: bm_http_client_filter + build: test + language: c + headers: + - test/core/transport/call_spine_benchmarks.h + src: + - test/core/filters/bm_http_client_filter.cc + deps: + - benchmark + - grpc + args: + - --benchmark_min_time=0.001s + benchmark: true + defaults: benchmark + uses_polling: false +- name: bm_party + build: test + language: c + headers: [] + src: + - test/core/promise/bm_party.cc + deps: + - benchmark + - grpc + args: + - --benchmark_min_time=0.001s + benchmark: true + defaults: benchmark + platforms: + - linux + - posix + uses_polling: false - name: fd_conservation_posix_test build: test language: c diff --git a/src/core/client_channel/client_channel.cc b/src/core/client_channel/client_channel.cc index ce5ae3f6a66..eb03d841fd1 100644 --- a/src/core/client_channel/client_channel.cc +++ b/src/core/client_channel/client_channel.cc @@ -625,6 +625,7 @@ ClientChannel::ClientChannel( work_serializer_(std::make_shared(event_engine_)), state_tracker_("client_channel", GRPC_CHANNEL_IDLE), subchannel_pool_(GetSubchannelPool(channel_args_)) { + CHECK(event_engine_.get() != nullptr); GRPC_TRACE_LOG(client_channel, INFO) << "client_channel=" << this << ": creating client_channel"; // Set initial keepalive time. diff --git a/src/core/lib/channel/channel_args.h b/src/core/lib/channel/channel_args.h index 55cb2785abc..301c0c287c5 100644 --- a/src/core/lib/channel/channel_args.h +++ b/src/core/lib/channel/channel_args.h @@ -558,6 +558,11 @@ class ChannelArgs { bool WantMinimalStack() const; std::string ToString() const; + template + friend void AbslStringify(Sink& sink, const ChannelArgs& args) { + sink.Append(args.ToString()); + } + private: explicit ChannelArgs(AVL args); diff --git a/src/core/lib/promise/activity.h b/src/core/lib/promise/activity.h index 5c2a6ebfeac..7bd44a39084 100644 --- a/src/core/lib/promise/activity.h +++ b/src/core/lib/promise/activity.h @@ -673,8 +673,6 @@ inline Pending IntraActivityWaiter::pending() { } inline void IntraActivityWaiter::Wake() { - GRPC_TRACE_LOG(promise_primitives, INFO) - << "IntraActivityWaiter::Wake: " << GRPC_DUMP_ARGS(this, wakeups_); if (wakeups_ == 0) return; GetContext()->ForceImmediateRepoll(std::exchange(wakeups_, 0)); } diff --git a/src/core/lib/promise/poll.h b/src/core/lib/promise/poll.h index df31cccc85c..ed1725303c2 100644 --- a/src/core/lib/promise/poll.h +++ b/src/core/lib/promise/poll.h @@ -44,6 +44,10 @@ GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline bool operator==(const Empty&, const Empty&) { return true; } +template +void AbslStringify(Sink& sink, Empty) { + sink.Append("{}"); +} // The result of polling a Promise once. // @@ -283,6 +287,36 @@ void AbslStringify(Sink& sink, const Poll& poll) { absl::Format(&sink, "%v", poll.value()); } +template +void AbslStringify(Sink& sink, const Poll>& poll) { + if (poll.pending()) { + absl::Format(&sink, "<>"); + return; + } + const auto& value = poll.value(); + if (value.has_value()) { + absl::Format(&sink, "%v", value); + } else { + sink.append("nullopt"); + } +} + +// Hack to get metadata printing +template +void AbslStringify(Sink& sink, const Poll>>& poll) { + if (poll.pending()) { + absl::Format(&sink, "<>"); + return; + } + const auto& value = poll.value(); + if (value.has_value()) { + absl::Format(&sink, "%v", *value); + } else { + sink.Append("nullopt"); + } +} + + } // namespace grpc_core #endif // GRPC_SRC_CORE_LIB_PROMISE_POLL_H diff --git a/src/core/lib/promise/status_flag.h b/src/core/lib/promise/status_flag.h index cd7e4a430a4..14de24cbcc3 100644 --- a/src/core/lib/promise/status_flag.h +++ b/src/core/lib/promise/status_flag.h @@ -172,6 +172,11 @@ struct StatusCastImpl { } }; +template <> +struct StatusCastImpl { + static StatusFlag Cast(Success) { return StatusFlag(true); } +}; + template struct FailureStatusCastImpl, StatusFlag> { GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static absl::StatusOr Cast( @@ -253,6 +258,17 @@ class ValueOrFailure { return value_ != other; } + template + friend void AbslStringify(Sink& sink, const ValueOrFailure& value) { + if (value.ok()) { + sink.Append("Success("); + sink.Append(absl::StrCat(value)); + sink.Append(")"); + } else { + sink.Append("Failure"); + } + } + private: absl::optional value_; }; @@ -315,4 +331,4 @@ struct StatusCastImpl, StatusFlag> { } // namespace grpc_core -#endif // GRPC_SRC_CORE_LIB_PROMISE_STATUS_FLAG_H \ No newline at end of file +#endif // GRPC_SRC_CORE_LIB_PROMISE_STATUS_FLAG_H diff --git a/src/core/lib/transport/call_filters.cc b/src/core/lib/transport/call_filters.cc index 627ebd6303a..1df79c85c26 100644 --- a/src/core/lib/transport/call_filters.cc +++ b/src/core/lib/transport/call_filters.cc @@ -311,8 +311,14 @@ void CallState::Start() { server_to_client_pull_state_ = ServerToClientPullState::kStarted; server_to_client_pull_waiter_.Wake(); break; + case ServerToClientPullState::kUnstartedReading: + server_to_client_pull_state_ = ServerToClientPullState::kStartedReading; + server_to_client_pull_waiter_.Wake(); + break; case ServerToClientPullState::kStarted: + case ServerToClientPullState::kStartedReading: case ServerToClientPullState::kProcessingServerInitialMetadata: + case ServerToClientPullState::kProcessingServerInitialMetadataReading: case ServerToClientPullState::kIdle: case ServerToClientPullState::kReading: case ServerToClientPullState::kProcessingServerToClientMessage: @@ -633,8 +639,10 @@ Poll CallState::PollPullServerInitialMetadataAvailable() { << "[call_state] PollPullServerInitialMetadataAvailable: " << GRPC_DUMP_ARGS(this, server_to_client_pull_state_, server_to_client_push_state_); + bool reading; switch (server_to_client_pull_state_) { case ServerToClientPullState::kUnstarted: + case ServerToClientPullState::kUnstartedReading: if (server_to_client_push_state_ == ServerToClientPushState::kTrailersOnly) { server_to_client_pull_state_ = ServerToClientPullState::kTerminated; @@ -642,9 +650,14 @@ Poll CallState::PollPullServerInitialMetadataAvailable() { } server_to_client_push_waiter_.pending(); return server_to_client_pull_waiter_.pending(); + case ServerToClientPullState::kStartedReading: + reading = true; + break; case ServerToClientPullState::kStarted: + reading = false; break; case ServerToClientPullState::kProcessingServerInitialMetadata: + case ServerToClientPullState::kProcessingServerInitialMetadataReading: case ServerToClientPullState::kIdle: case ServerToClientPullState::kReading: case ServerToClientPullState::kProcessingServerToClientMessage: @@ -653,14 +666,19 @@ Poll CallState::PollPullServerInitialMetadataAvailable() { case ServerToClientPullState::kTerminated: return false; } - DCHECK_EQ(server_to_client_pull_state_, ServerToClientPullState::kStarted); + DCHECK(server_to_client_pull_state_ == ServerToClientPullState::kStarted || + server_to_client_pull_state_ == + ServerToClientPullState::kStartedReading) + << server_to_client_pull_state_; switch (server_to_client_push_state_) { case ServerToClientPushState::kStart: return server_to_client_push_waiter_.pending(); case ServerToClientPushState::kPushedServerInitialMetadata: case ServerToClientPushState::kPushedServerInitialMetadataAndPushedMessage: server_to_client_pull_state_ = - ServerToClientPullState::kProcessingServerInitialMetadata; + reading + ? ServerToClientPullState::kProcessingServerInitialMetadataReading + : ServerToClientPullState::kProcessingServerInitialMetadata; server_to_client_pull_waiter_.Wake(); return true; case ServerToClientPushState::kIdle: @@ -683,8 +701,10 @@ void CallState::FinishPullServerInitialMetadata() { << GRPC_DUMP_ARGS(this, server_to_client_pull_state_); switch (server_to_client_pull_state_) { case ServerToClientPullState::kUnstarted: + case ServerToClientPullState::kUnstartedReading: LOG(FATAL) << "FinishPullServerInitialMetadata called before Start"; case ServerToClientPullState::kStarted: + case ServerToClientPullState::kStartedReading: CHECK_EQ(server_to_client_push_state_, ServerToClientPushState::kTrailersOnly); return; @@ -692,6 +712,10 @@ void CallState::FinishPullServerInitialMetadata() { server_to_client_pull_state_ = ServerToClientPullState::kIdle; server_to_client_pull_waiter_.Wake(); break; + case ServerToClientPullState::kProcessingServerInitialMetadataReading: + server_to_client_pull_state_ = ServerToClientPullState::kReading; + server_to_client_pull_waiter_.Wake(); + break; case ServerToClientPullState::kIdle: case ServerToClientPullState::kReading: case ServerToClientPullState::kProcessingServerToClientMessage: @@ -700,7 +724,9 @@ void CallState::FinishPullServerInitialMetadata() { case ServerToClientPullState::kTerminated: return; } - DCHECK_EQ(server_to_client_pull_state_, ServerToClientPullState::kIdle); + DCHECK(server_to_client_pull_state_ == ServerToClientPullState::kIdle || + server_to_client_pull_state_ == ServerToClientPullState::kReading) + << server_to_client_pull_state_; switch (server_to_client_push_state_) { case ServerToClientPushState::kStart: LOG(FATAL) << "FinishPullServerInitialMetadata called before initial " @@ -711,7 +737,7 @@ void CallState::FinishPullServerInitialMetadata() { break; case ServerToClientPushState::kPushedServerInitialMetadataAndPushedMessage: server_to_client_push_state_ = ServerToClientPushState::kPushedMessage; - server_to_client_pull_waiter_.Wake(); + server_to_client_push_waiter_.Wake(); break; case ServerToClientPushState::kIdle: case ServerToClientPushState::kPushedMessage: @@ -729,9 +755,19 @@ Poll> CallState::PollPullServerToClientMessageAvailable() { server_trailing_metadata_state_); switch (server_to_client_pull_state_) { case ServerToClientPullState::kUnstarted: + server_to_client_pull_state_ = ServerToClientPullState::kUnstartedReading; + return server_to_client_pull_waiter_.pending(); case ServerToClientPullState::kProcessingServerInitialMetadata: + server_to_client_pull_state_ = + ServerToClientPullState::kProcessingServerInitialMetadataReading; + return server_to_client_pull_waiter_.pending(); + case ServerToClientPullState::kUnstartedReading: + case ServerToClientPullState::kProcessingServerInitialMetadataReading: return server_to_client_pull_waiter_.pending(); case ServerToClientPullState::kStarted: + server_to_client_pull_state_ = ServerToClientPullState::kStartedReading; + ABSL_FALLTHROUGH_INTENDED; + case ServerToClientPullState::kStartedReading: if (server_to_client_push_state_ == ServerToClientPushState::kTrailersOnly) { return false; @@ -788,8 +824,11 @@ void CallState::FinishPullServerToClientMessage() { server_to_client_push_state_); switch (server_to_client_pull_state_) { case ServerToClientPullState::kUnstarted: + case ServerToClientPullState::kUnstartedReading: case ServerToClientPullState::kStarted: + case ServerToClientPullState::kStartedReading: case ServerToClientPullState::kProcessingServerInitialMetadata: + case ServerToClientPullState::kProcessingServerInitialMetadataReading: LOG(FATAL) << "FinishPullServerToClientMessage called before metadata available"; case ServerToClientPullState::kIdle: @@ -831,16 +870,41 @@ Poll CallState::PollServerTrailingMetadataAvailable() { GRPC_TRACE_LOG(call, INFO) << "[call_state] PollServerTrailingMetadataAvailable: " << GRPC_DUMP_ARGS(this, server_to_client_pull_state_, + server_to_client_push_state_, server_trailing_metadata_state_, server_trailing_metadata_waiter_.DebugString()); switch (server_to_client_pull_state_) { case ServerToClientPullState::kProcessingServerInitialMetadata: case ServerToClientPullState::kProcessingServerToClientMessage: + case ServerToClientPullState::kProcessingServerInitialMetadataReading: + case ServerToClientPullState::kUnstartedReading: return server_to_client_pull_waiter_.pending(); + case ServerToClientPullState::kStartedReading: + case ServerToClientPullState::kReading: + switch (server_to_client_push_state_) { + case ServerToClientPushState::kTrailersOnly: + case ServerToClientPushState::kIdle: + case ServerToClientPushState::kStart: + case ServerToClientPushState::kFinished: + if (server_trailing_metadata_state_ != + ServerTrailingMetadataState::kNotPushed) { + server_to_client_pull_state_ = + ServerToClientPullState::kProcessingServerTrailingMetadata; + server_to_client_pull_waiter_.Wake(); + return Empty{}; + } + ABSL_FALLTHROUGH_INTENDED; + case ServerToClientPushState::kPushedServerInitialMetadata: + case ServerToClientPushState:: + kPushedServerInitialMetadataAndPushedMessage: + case ServerToClientPushState::kPushedMessage: + server_to_client_push_waiter_.pending(); + return server_to_client_pull_waiter_.pending(); + } + break; case ServerToClientPullState::kStarted: case ServerToClientPullState::kUnstarted: case ServerToClientPullState::kIdle: - case ServerToClientPullState::kReading: if (server_trailing_metadata_state_ != ServerTrailingMetadataState::kNotPushed) { server_to_client_pull_state_ = diff --git a/src/core/lib/transport/call_filters.h b/src/core/lib/transport/call_filters.h index d48ae8932d3..8128d45d08c 100644 --- a/src/core/lib/transport/call_filters.h +++ b/src/core/lib/transport/call_filters.h @@ -1299,9 +1299,12 @@ class CallState { enum class ServerToClientPullState : uint16_t { // Not yet started: cannot read kUnstarted, + kUnstartedReading, kStarted, + kStartedReading, // Processing server initial metadata kProcessingServerInitialMetadata, + kProcessingServerInitialMetadataReading, // Main call loop: not reading kIdle, // Main call loop: reading but no message available @@ -1317,10 +1320,16 @@ class CallState { switch (state) { case ServerToClientPullState::kUnstarted: return "Unstarted"; + case ServerToClientPullState::kUnstartedReading: + return "UnstartedReading"; case ServerToClientPullState::kStarted: return "Started"; + case ServerToClientPullState::kStartedReading: + return "StartedReading"; case ServerToClientPullState::kProcessingServerInitialMetadata: return "ProcessingServerInitialMetadata"; + case ServerToClientPullState::kProcessingServerInitialMetadataReading: + return "ProcessingServerInitialMetadataReading"; case ServerToClientPullState::kIdle: return "Idle"; case ServerToClientPullState::kReading: diff --git a/src/core/lib/transport/call_spine.h b/src/core/lib/transport/call_spine.h index 81f3e6a53c8..9126372edb5 100644 --- a/src/core/lib/transport/call_spine.h +++ b/src/core/lib/transport/call_spine.h @@ -290,6 +290,7 @@ class CallInitiator { } Arena* arena() { return spine_->arena(); } + Party* party() { return spine_.get(); } grpc_event_engine::experimental::EventEngine* event_engine() const { return spine_->event_engine(); @@ -354,6 +355,7 @@ class CallHandler { } Arena* arena() { return spine_->arena(); } + Party* party() { return spine_.get(); } grpc_event_engine::experimental::EventEngine* event_engine() const { return spine_->event_engine(); diff --git a/src/core/lib/transport/metadata_batch.h b/src/core/lib/transport/metadata_batch.h index a5a934803ee..3d7779113ab 100644 --- a/src/core/lib/transport/metadata_batch.h +++ b/src/core/lib/transport/metadata_batch.h @@ -1322,6 +1322,11 @@ class MetadataMap { return builder.TakeOutput(); } + template + friend void AbslStringify(Sink& sink, const MetadataMap& map) { + sink.Append(map.DebugString()); + } + // Get the pointer to the value of some known metadata. // Returns nullptr if the metadata is not present. // Causes a compilation error if Which is not an element of Traits. diff --git a/test/core/call/BUILD b/test/core/call/BUILD index 6ca668d0251..41f3409b64c 100644 --- a/test/core/call/BUILD +++ b/test/core/call/BUILD @@ -14,6 +14,7 @@ load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_package") load("//test/core/call/yodel:grpc_yodel_test.bzl", "grpc_yodel_simple_test") +load("//test/cpp/microbenchmarks:grpc_benchmark_config.bzl", "grpc_benchmark_args") grpc_package(name = "test/core/call") @@ -77,3 +78,20 @@ grpc_cc_library( "//test/core/end2end:cq_verifier", ], ) + +grpc_cc_test( + name = "bm_client_call", + size = "small", + srcs = ["bm_client_call.cc"], + args = grpc_benchmark_args(), + external_deps = ["benchmark"], + tags = [ + "no_mac", + "no_windows", + ], + uses_polling = False, + deps = [ + "//:grpc", + "//src/core:default_event_engine", + ], +) diff --git a/test/core/call/bm_client_call.cc b/test/core/call/bm_client_call.cc new file mode 100644 index 00000000000..aefe7a6c8b5 --- /dev/null +++ b/test/core/call/bm_client_call.cc @@ -0,0 +1,192 @@ +// Copyright 2024 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. + +#include + +#include + +#include "src/core/lib/event_engine/default_event_engine.h" +#include "src/core/lib/promise/all_ok.h" +#include "src/core/lib/promise/map.h" +#include "src/core/lib/resource_quota/arena.h" +#include "src/core/lib/resource_quota/resource_quota.h" +#include "src/core/lib/slice/slice.h" +#include "src/core/lib/surface/client_call.h" +#include "src/core/lib/transport/call_arena_allocator.h" + +namespace grpc_core { +namespace { + +class TestCallDestination : public UnstartedCallDestination { + public: + void StartCall(UnstartedCallHandler handler) override { + handler_ = std::move(handler); + } + + UnstartedCallHandler TakeHandler() { + CHECK(handler_.has_value()); + auto handler = std::move(*handler_); + handler_.reset(); + return handler; + } + + void Orphaned() override { handler_.reset(); } + + private: + absl::optional handler_; +}; + +class Helper { + public: + ~Helper() { + grpc_completion_queue_shutdown(cq_); + auto ev = grpc_completion_queue_next( + cq_, gpr_inf_future(GPR_CLOCK_REALTIME), nullptr); + CHECK_EQ(ev.type, GRPC_QUEUE_SHUTDOWN); + grpc_completion_queue_destroy(cq_); + } + + auto MakeCall() { + return std::unique_ptr( + MakeClientCall(nullptr, 0, cq_, path_.Copy(), absl::nullopt, true, + Timestamp::InfFuture(), compression_options_, + event_engine_.get(), arena_allocator_->MakeArena(), + destination_), + grpc_call_unref); + } + + UnstartedCallHandler TakeHandler() { return destination_->TakeHandler(); } + + grpc_completion_queue* cq() { return cq_; } + + private: + grpc_completion_queue* cq_ = grpc_completion_queue_create_for_next(nullptr); + Slice path_ = Slice::FromStaticString("/foo/bar"); + const grpc_compression_options compression_options_ = { + 1, + {0, GRPC_COMPRESS_LEVEL_NONE}, + {0, GRPC_COMPRESS_NONE}, + }; + std::shared_ptr event_engine_ = + grpc_event_engine::experimental::GetDefaultEventEngine(); + RefCountedPtr arena_allocator_ = + MakeRefCounted( + ResourceQuota::Default()->memory_quota()->CreateMemoryAllocator( + "test-allocator"), + 1024); + RefCountedPtr destination_ = + MakeRefCounted(); +}; + +void BM_CreateDestroy(benchmark::State& state) { + Helper helper; + for (auto _ : state) { + helper.MakeCall(); + } +} +BENCHMARK(BM_CreateDestroy); + +void BM_Unary(benchmark::State& state) { + Helper helper; + grpc_slice request_payload_slice = grpc_slice_from_static_string("hello"); + grpc_byte_buffer* request_payload = + grpc_raw_byte_buffer_create(&request_payload_slice, 1); + grpc_status_code status; + grpc_slice status_details; + grpc_metadata_array initial_metadata_recv; + grpc_metadata_array trailing_metadata_recv; + Slice response_payload = Slice::FromStaticString("world"); + grpc_byte_buffer* recv_response_payload = nullptr; + for (auto _ : state) { + auto call = helper.MakeCall(); + // Create ops the old school way to avoid any overheads + grpc_op ops[6]; + memset(ops, 0, sizeof(ops)); + grpc_metadata_array_init(&initial_metadata_recv); + grpc_metadata_array_init(&trailing_metadata_recv); + ops[0].op = GRPC_OP_SEND_INITIAL_METADATA; + ops[0].data.send_initial_metadata.count = 0; + ops[1].op = GRPC_OP_SEND_MESSAGE; + ops[1].data.send_message.send_message = request_payload; + ops[2].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT; + ops[3].op = GRPC_OP_RECV_INITIAL_METADATA; + ops[3].data.recv_initial_metadata.recv_initial_metadata = + &initial_metadata_recv; + ops[4].op = GRPC_OP_RECV_MESSAGE; + ops[4].data.recv_message.recv_message = &recv_response_payload; + ops[5].op = GRPC_OP_RECV_STATUS_ON_CLIENT; + ops[5].data.recv_status_on_client.status = &status; + ops[5].data.recv_status_on_client.status_details = &status_details; + ops[5].data.recv_status_on_client.trailing_metadata = + &trailing_metadata_recv; + grpc_call_start_batch(call.get(), ops, 6, reinterpret_cast(1), + nullptr); + // Now fetch the handler at the other side, retrieve the request, and poke + // back a response. + auto unstarted_handler = helper.TakeHandler(); + unstarted_handler.SpawnInfallible("run_handler", [&]() mutable { + auto handler = unstarted_handler.StartWithEmptyFilterStack(); + handler.PushServerInitialMetadata(Arena::MakePooled()); + auto response = + Arena::MakePooled(SliceBuffer(response_payload.Copy()), 0); + return Map( + AllOk( + Map(handler.PullClientInitialMetadata(), + [](ValueOrFailure status) { + return status.status(); + }), + Map(handler.PullMessage(), + [](ValueOrFailure> message) { + return message.status(); + }), + handler.PushMessage(std::move(response))), + [handler](StatusFlag status) mutable { + CHECK(status.ok()); + auto trailing_metadata = Arena::MakePooled(); + trailing_metadata->Set(GrpcStatusMetadata(), GRPC_STATUS_OK); + handler.PushServerTrailingMetadata(std::move(trailing_metadata)); + return Empty{}; + }); + }); + auto ev = grpc_completion_queue_next( + helper.cq(), gpr_inf_future(GPR_CLOCK_REALTIME), nullptr); + CHECK_EQ(ev.type, GRPC_OP_COMPLETE); + call.reset(); + grpc_byte_buffer_destroy(recv_response_payload); + grpc_metadata_array_destroy(&initial_metadata_recv); + grpc_metadata_array_destroy(&trailing_metadata_recv); + } + grpc_byte_buffer_destroy(request_payload); +} +BENCHMARK(BM_Unary); + +} // namespace +} // namespace grpc_core + +// Some distros have RunSpecifiedBenchmarks under the benchmark namespace, +// and others do not. This allows us to support both modes. +namespace benchmark { +void RunTheBenchmarksNamespaced() { RunSpecifiedBenchmarks(); } +} // namespace benchmark + +int main(int argc, char** argv) { + ::benchmark::Initialize(&argc, argv); + grpc_init(); + { + auto ee = grpc_event_engine::experimental::GetDefaultEventEngine(); + benchmark::RunTheBenchmarksNamespaced(); + } + grpc_shutdown(); + return 0; +} diff --git a/test/core/client_channel/BUILD b/test/core/client_channel/BUILD index fab2857ce6c..a41e9a3d45d 100644 --- a/test/core/client_channel/BUILD +++ b/test/core/client_channel/BUILD @@ -14,6 +14,7 @@ load("//bazel:grpc_build_system.bzl", "grpc_cc_test", "grpc_package") load("//test/core/call/yodel:grpc_yodel_test.bzl", "grpc_yodel_simple_test") +load("//test/cpp/microbenchmarks:grpc_benchmark_config.bzl", "grpc_benchmark_args") grpc_package(name = "test/core/client_channel") @@ -116,3 +117,21 @@ grpc_cc_test( "//test/core/test_util:grpc_test_util", ], ) + +grpc_cc_test( + name = "bm_client_channel", + size = "small", + srcs = ["bm_client_channel.cc"], + args = grpc_benchmark_args(), + external_deps = ["benchmark"], + tags = [ + "no_mac", + "no_windows", + ], + uses_polling = False, + deps = [ + "//:grpc", + "//src/core:default_event_engine", + "//test/core/transport:call_spine_benchmarks", + ], +) diff --git a/test/core/client_channel/bm_client_channel.cc b/test/core/client_channel/bm_client_channel.cc new file mode 100644 index 00000000000..f3d56b6ea8e --- /dev/null +++ b/test/core/client_channel/bm_client_channel.cc @@ -0,0 +1,200 @@ +// Copyright 2024 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. + +#include + +#include "absl/memory/memory.h" +#include "absl/strings/string_view.h" + +#include + +#include "src/core/client_channel/client_channel.h" +#include "src/core/lib/address_utils/parse_address.h" +#include "test/core/transport/call_spine_benchmarks.h" + +namespace grpc_core { + +namespace { +const Slice kTestPath = Slice::FromExternalString("/foo/bar"); +} + +class ClientChannelTraits { + public: + RefCountedPtr CreateCallDestination( + RefCountedPtr final_destination) { + call_destination_factory_ = std::make_unique( + std::move(final_destination)); + auto channel = ClientChannel::Create( + "test:///target", + ChannelArgs() + .SetObject(&client_channel_factory_) + .SetObject(call_destination_factory_.get()) + .SetObject(ResourceQuota::Default()) + .SetObject(grpc_event_engine::experimental::GetDefaultEventEngine()) + .Set(GRPC_ARG_USE_LOCAL_SUBCHANNEL_POOL, true) + // TODO(ctiller): remove once v3 supports retries + .Set(GRPC_ARG_ENABLE_RETRIES, 0)); + CHECK_OK(channel); + return std::move(*channel); + } + + ClientMetadataHandle MakeClientInitialMetadata() { + auto md = Arena::MakePooled(); + md->Set(HttpPathMetadata(), kTestPath.Copy()); + return md; + } + + ServerMetadataHandle MakeServerInitialMetadata() { + return Arena::MakePooled(); + } + + MessageHandle MakePayload() { return Arena::MakePooled(); } + + ServerMetadataHandle MakeServerTrailingMetadata() { + auto md = Arena::MakePooled(); + return md; + } + + private: + class TestConnector final : public SubchannelConnector { + public: + void Connect(const Args&, Result*, grpc_closure* notify) override { + CHECK_EQ(notify_, nullptr); + notify_ = notify; + } + + void Shutdown(grpc_error_handle error) override { + if (notify_ != nullptr) ExecCtx::Run(DEBUG_LOCATION, notify_, error); + } + + private: + grpc_closure* notify_ = nullptr; + }; + + class TestClientChannelFactory final : public ClientChannelFactory { + public: + RefCountedPtr CreateSubchannel( + const grpc_resolved_address& address, + const ChannelArgs& args) override { + return Subchannel::Create(MakeOrphanable(), address, args); + } + }; + + class TestCallDestinationFactory final + : public ClientChannel::CallDestinationFactory { + public: + explicit TestCallDestinationFactory( + RefCountedPtr call_destination) + : call_destination_(std::move(call_destination)) {} + + RefCountedPtr CreateCallDestination( + ClientChannel::PickerObservable picker) override { + return call_destination_; + } + + private: + RefCountedPtr call_destination_; + }; + + std::unique_ptr call_destination_factory_; + TestClientChannelFactory client_channel_factory_; +}; +GRPC_CALL_SPINE_BENCHMARK(UnstartedCallDestinationFixture); + +namespace { +class TestResolver final : public Resolver { + public: + explicit TestResolver(ChannelArgs args, + std::unique_ptr result_handler, + std::shared_ptr work_serializer) + : args_(std::move(args)), + result_handler_(std::move(result_handler)), + work_serializer_(std::move(work_serializer)) {} + + void StartLocked() override { + work_serializer_->Run( + [self = RefAsSubclass()] { + self->result_handler_->ReportResult( + self->MakeSuccessfulResolutionResult("ipv4:127.0.0.1:1234")); + }, + DEBUG_LOCATION); + } + void ShutdownLocked() override {} + + private: + Resolver::Result MakeSuccessfulResolutionResult( + absl::string_view endpoint_address) { + Resolver::Result result; + result.args = args_; + grpc_resolved_address address; + CHECK(grpc_parse_uri(URI::Parse(endpoint_address).value(), &address)); + result.addresses = EndpointAddressesList({EndpointAddresses{address, {}}}); + return result; + } + + const ChannelArgs args_; + const std::unique_ptr result_handler_; + const std::shared_ptr work_serializer_; +}; + +class TestResolverFactory final : public ResolverFactory { + public: + OrphanablePtr CreateResolver(ResolverArgs args) const override { + return MakeOrphanable(std::move(args.args), + std::move(args.result_handler), + std::move(args.work_serializer)); + } + + absl::string_view scheme() const override { return "test"; } + bool IsValidUri(const URI&) const override { return true; } +}; + +void BM_CreateClientChannel(benchmark::State& state) { + class FinalDestination : public UnstartedCallDestination { + public: + void StartCall(UnstartedCallHandler) override {} + void Orphaned() override {} + }; + ClientChannelTraits traits; + auto final_destination = MakeRefCounted(); + for (auto _ : state) { + traits.CreateCallDestination(final_destination); + } +} +BENCHMARK(BM_CreateClientChannel); + +} // namespace +} // namespace grpc_core + +// Some distros have RunSpecifiedBenchmarks under the benchmark namespace, +// and others do not. This allows us to support both modes. +namespace benchmark { +void RunTheBenchmarksNamespaced() { RunSpecifiedBenchmarks(); } +} // namespace benchmark + +int main(int argc, char** argv) { + ::benchmark::Initialize(&argc, argv); + grpc_core::CoreConfiguration::RegisterBuilder( + [](grpc_core::CoreConfiguration::Builder* builder) { + builder->resolver_registry()->RegisterResolverFactory( + std::make_unique()); + }); + grpc_init(); + { + auto ee = grpc_event_engine::experimental::GetDefaultEventEngine(); + benchmark::RunTheBenchmarksNamespaced(); + } + grpc_shutdown(); + return 0; +} diff --git a/test/core/filters/BUILD b/test/core/filters/BUILD index a3f47f166a5..5774972ad72 100644 --- a/test/core/filters/BUILD +++ b/test/core/filters/BUILD @@ -13,6 +13,7 @@ # limitations under the License. load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_package") +load("//test/cpp/microbenchmarks:grpc_benchmark_config.bzl", "grpc_benchmark_args") licenses(["notice"]) @@ -118,3 +119,17 @@ grpc_cc_test( "//src/core:grpc_client_authority_filter", ], ) + +grpc_cc_test( + name = "bm_http_client_filter", + size = "small", + srcs = ["bm_http_client_filter.cc"], + args = grpc_benchmark_args(), + external_deps = ["benchmark"], + uses_polling = False, + deps = [ + "//:grpc", + "//src/core:default_event_engine", + "//test/core/transport:call_spine_benchmarks", + ], +) diff --git a/test/core/filters/bm_http_client_filter.cc b/test/core/filters/bm_http_client_filter.cc new file mode 100644 index 00000000000..77a075e36c5 --- /dev/null +++ b/test/core/filters/bm_http_client_filter.cc @@ -0,0 +1,86 @@ +// Copyright 2024 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. + +#include + +#include "absl/strings/string_view.h" + +#include + +#include "src/core/ext/filters/http/client/http_client_filter.h" +#include "src/core/lib/event_engine/default_event_engine.h" +#include "src/core/lib/transport/connectivity_state.h" +#include "src/core/lib/transport/metadata.h" +#include "src/core/lib/transport/transport.h" +#include "test/core/transport/call_spine_benchmarks.h" + +namespace grpc_core { + +class HttpClientFilterTraits { + public: + using Filter = HttpClientFilter; + + ChannelArgs MakeChannelArgs() { return ChannelArgs().SetObject(&transport_); } + + ClientMetadataHandle MakeClientInitialMetadata() { + return Arena::MakePooled(); + } + + ServerMetadataHandle MakeServerInitialMetadata() { + return Arena::MakePooled(); + } + + MessageHandle MakePayload() { return Arena::MakePooled(); } + + ServerMetadataHandle MakeServerTrailingMetadata() { + auto md = Arena::MakePooled(); + md->Set(HttpStatusMetadata(), 200); + return md; + } + + private: + class FakeTransport final : public Transport { + public: + FilterStackTransport* filter_stack_transport() override { return nullptr; } + ClientTransport* client_transport() override { return nullptr; } + ServerTransport* server_transport() override { return nullptr; } + absl::string_view GetTransportName() const override { return "fake-http"; } + void SetPollset(grpc_stream*, grpc_pollset*) override {} + void SetPollsetSet(grpc_stream*, grpc_pollset_set*) override {} + void PerformOp(grpc_transport_op*) override {} + void Orphan() override {} + }; + + FakeTransport transport_; +}; +GRPC_CALL_SPINE_BENCHMARK(FilterFixture); + +} // namespace grpc_core + +// Some distros have RunSpecifiedBenchmarks under the benchmark namespace, +// and others do not. This allows us to support both modes. +namespace benchmark { +void RunTheBenchmarksNamespaced() { RunSpecifiedBenchmarks(); } +} // namespace benchmark + +int main(int argc, char** argv) { + ::benchmark::Initialize(&argc, argv); + grpc_init(); + { + auto ee = grpc_event_engine::experimental::GetDefaultEventEngine(); + benchmark::RunTheBenchmarksNamespaced(); + } + grpc_shutdown(); + return 0; +} diff --git a/test/core/promise/BUILD b/test/core/promise/BUILD index aca4b5b3631..6c8c1cd0832 100644 --- a/test/core/promise/BUILD +++ b/test/core/promise/BUILD @@ -14,6 +14,7 @@ load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_package") load("//test/core/test_util:grpc_fuzzer.bzl", "grpc_proto_fuzzer") +load("//test/cpp/microbenchmarks:grpc_benchmark_config.bzl", "grpc_benchmark_args") licenses(["notice"]) @@ -684,3 +685,21 @@ grpc_cc_test( "//src/core:time", ], ) + +grpc_cc_test( + name = "bm_party", + size = "small", + srcs = ["bm_party.cc"], + args = grpc_benchmark_args(), + external_deps = ["benchmark"], + tags = [ + "no_mac", + "no_windows", + ], + uses_polling = False, + deps = [ + "//:grpc", + "//src/core:1999", + "//src/core:default_event_engine", + ], +) diff --git a/test/core/promise/bm_party.cc b/test/core/promise/bm_party.cc new file mode 100644 index 00000000000..ed179f4e934 --- /dev/null +++ b/test/core/promise/bm_party.cc @@ -0,0 +1,110 @@ +// Copyright 2024 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. + +#include + +#include + +#include "src/core/lib/event_engine/default_event_engine.h" +#include "src/core/lib/promise/party.h" + +namespace grpc_core { +namespace { + +class TestParty final : public Party { + public: + TestParty() : Party(1) {} + ~TestParty() override {} + std::string DebugTag() const override { return "TestParty"; } + + using Party::IncrementRefCount; + using Party::Unref; + + bool RunParty() override { + promise_detail::Context + ee_ctx(ee_.get()); + return Party::RunParty(); + } + + void PartyOver() override { + { + promise_detail::Context + ee_ctx(ee_.get()); + CancelRemainingParticipants(); + } + delete this; + } + + private: + grpc_event_engine::experimental::EventEngine* event_engine() const final { + return ee_.get(); + } + + std::shared_ptr ee_ = + grpc_event_engine::experimental::GetDefaultEventEngine(); +}; + +void BM_PartyCreate(benchmark::State& state) { + for (auto _ : state) { + auto* party = new TestParty(); + party->Unref(); + } +} +BENCHMARK(BM_PartyCreate); + +void BM_AddParticipant(benchmark::State& state) { + auto* party = new TestParty(); + for (auto _ : state) { + party->Spawn( + "participant", []() { return Success{}; }, [](StatusFlag) {}); + } + party->Unref(); +} +BENCHMARK(BM_AddParticipant); + +void BM_WakeupParticipant(benchmark::State& state) { + auto* party = new TestParty(); + party->Spawn( + "driver", + [&state, w = IntraActivityWaiter()]() mutable -> Poll { + w.pending(); + if (state.KeepRunning()) { + w.Wake(); + return Pending{}; + } + return Success{}; + }, + [party](StatusFlag) { party->Unref(); }); +} +BENCHMARK(BM_WakeupParticipant); + +} // namespace +} // namespace grpc_core + +// Some distros have RunSpecifiedBenchmarks under the benchmark namespace, +// and others do not. This allows us to support both modes. +namespace benchmark { +void RunTheBenchmarksNamespaced() { RunSpecifiedBenchmarks(); } +} // namespace benchmark + +int main(int argc, char** argv) { + ::benchmark::Initialize(&argc, argv); + grpc_init(); + { + auto ee = grpc_event_engine::experimental::GetDefaultEventEngine(); + benchmark::RunTheBenchmarksNamespaced(); + } + grpc_shutdown(); + return 0; +} diff --git a/test/core/security/ssl_server_fuzzer.cc b/test/core/security/ssl_server_fuzzer.cc index 67ffb76228b..d4310ebfa8c 100644 --- a/test/core/security/ssl_server_fuzzer.cc +++ b/test/core/security/ssl_server_fuzzer.cc @@ -97,9 +97,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { auto channel_args = grpc_core::ChannelArgs().SetObject(std::move(engine)); sc->add_handshakers(channel_args, nullptr, handshake_mgr.get()); - handshake_mgr->DoHandshake( - mock_endpoint_controller->TakeCEndpoint(), channel_args, deadline, - nullptr /* acceptor */, on_handshake_done, &state); + handshake_mgr->DoHandshake(mock_endpoint_controller->TakeCEndpoint(), + channel_args, deadline, nullptr /* acceptor */, + on_handshake_done, &state); grpc_core::ExecCtx::Get()->Flush(); // If the given string happens to be part of the correct client hello, the diff --git a/test/core/transport/BUILD b/test/core/transport/BUILD index 2e3c9e671ed..8097556471b 100644 --- a/test/core/transport/BUILD +++ b/test/core/transport/BUILD @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("//bazel:grpc_build_system.bzl", "grpc_cc_test", "grpc_package") +load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_package") load("//test/core/call/yodel:grpc_yodel_test.bzl", "grpc_yodel_simple_test") +load("//test/cpp/microbenchmarks:grpc_benchmark_config.bzl", "grpc_benchmark_args") licenses(["notice"]) @@ -207,3 +208,38 @@ grpc_yodel_simple_test( "//test/core/call/yodel:yodel_test", ], ) + +grpc_cc_library( + name = "call_spine_benchmarks", + testonly = 1, + hdrs = ["call_spine_benchmarks.h"], + external_deps = ["benchmark"], + visibility = ["//test/core:__subpackages__"], + deps = [ + "//:exec_ctx", + "//src/core:all_ok", + "//src/core:call_spine", + "//src/core:default_event_engine", + "//src/core:map", + "//src/core:notification", + "//src/core:resource_quota", + ], +) + +grpc_cc_test( + name = "bm_call_spine", + size = "small", + srcs = ["bm_call_spine.cc"], + args = grpc_benchmark_args(), + external_deps = ["benchmark"], + tags = [ + "no_mac", + "no_windows", + ], + uses_polling = False, + deps = [ + ":call_spine_benchmarks", + "//:grpc", + "//src/core:default_event_engine", + ], +) diff --git a/test/core/transport/bm_call_spine.cc b/test/core/transport/bm_call_spine.cc new file mode 100644 index 00000000000..8a6bacdc427 --- /dev/null +++ b/test/core/transport/bm_call_spine.cc @@ -0,0 +1,121 @@ +// Copyright 2024 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. + +#include + +#include + +#include "src/core/lib/event_engine/default_event_engine.h" +#include "src/core/lib/resource_quota/resource_quota.h" +#include "test/core/transport/call_spine_benchmarks.h" + +namespace grpc_core { + +class CallSpineFixture { + public: + BenchmarkCall MakeCall() { + auto p = MakeCallPair(Arena::MakePooled(), + event_engine_.get(), arena_allocator_->MakeArena()); + return {std::move(p.initiator), p.handler.StartCall(stack_)}; + } + + ServerMetadataHandle MakeServerInitialMetadata() { + return Arena::MakePooled(); + } + + MessageHandle MakePayload() { return Arena::MakePooled(); } + + ServerMetadataHandle MakeServerTrailingMetadata() { + return Arena::MakePooled(); + } + + private: + std::shared_ptr event_engine_ = + grpc_event_engine::experimental::GetDefaultEventEngine(); + RefCountedPtr arena_allocator_ = + MakeRefCounted( + ResourceQuota::Default()->memory_quota()->CreateMemoryAllocator( + "test-allocator"), + 1024); + RefCountedPtr stack_ = + CallFilters::StackBuilder().Build(); +}; +GRPC_CALL_SPINE_BENCHMARK(CallSpineFixture); + +class ForwardCallFixture { + public: + BenchmarkCall MakeCall() { + auto p1 = MakeCallPair(Arena::MakePooled(), + event_engine_.get(), arena_allocator_->MakeArena()); + auto p2 = MakeCallPair(Arena::MakePooled(), + event_engine_.get(), arena_allocator_->MakeArena()); + p1.handler.SpawnInfallible("initial_metadata", [&]() { + auto p1_handler = p1.handler.StartCall(stack_); + return Map( + p1_handler.PullClientInitialMetadata(), + [p1_handler, &p2](ValueOrFailure md) mutable { + CHECK(md.ok()); + ForwardCall(std::move(p1_handler), std::move(p2.initiator)); + return Empty{}; + }); + }); + absl::optional p2_handler; + p2.handler.SpawnInfallible("start", [&]() { + p2_handler = p2.handler.StartCall(stack_); + return Empty{}; + }); + return {std::move(p1.initiator), std::move(*p2_handler)}; + } + + ServerMetadataHandle MakeServerInitialMetadata() { + return Arena::MakePooled(); + } + + MessageHandle MakePayload() { return Arena::MakePooled(); } + + ServerMetadataHandle MakeServerTrailingMetadata() { + return Arena::MakePooled(); + } + + private: + std::shared_ptr event_engine_ = + grpc_event_engine::experimental::GetDefaultEventEngine(); + RefCountedPtr arena_allocator_ = + MakeRefCounted( + ResourceQuota::Default()->memory_quota()->CreateMemoryAllocator( + "test-allocator"), + 1024); + RefCountedPtr stack_ = + CallFilters::StackBuilder().Build(); +}; +GRPC_CALL_SPINE_BENCHMARK(ForwardCallFixture); + +} // namespace grpc_core + +// Some distros have RunSpecifiedBenchmarks under the benchmark namespace, +// and others do not. This allows us to support both modes. +namespace benchmark { +void RunTheBenchmarksNamespaced() { RunSpecifiedBenchmarks(); } +} // namespace benchmark + +int main(int argc, char** argv) { + ::benchmark::Initialize(&argc, argv); + grpc_init(); + { + auto ee = grpc_event_engine::experimental::GetDefaultEventEngine(); + benchmark::RunTheBenchmarksNamespaced(); + } + grpc_shutdown(); + return 0; +} diff --git a/test/core/transport/call_filters_test.cc b/test/core/transport/call_filters_test.cc index 625b5b45dd3..351e26867ac 100644 --- a/test/core/transport/call_filters_test.cc +++ b/test/core/transport/call_filters_test.cc @@ -59,9 +59,9 @@ class MockActivity : public Activity, public Wakeable { std::unique_ptr scoped_activity_; }; -#define EXPECT_WAKEUP(activity, statement) \ - EXPECT_CALL((activity), WakeupRequested()); \ - statement; \ +#define EXPECT_WAKEUP(activity, statement) \ + EXPECT_CALL((activity), WakeupRequested()).Times(::testing::AtLeast(1)); \ + statement; \ Mock::VerifyAndClearExpectations(&(activity)); } // namespace diff --git a/test/core/transport/call_spine_benchmarks.h b/test/core/transport/call_spine_benchmarks.h new file mode 100644 index 00000000000..96d84f88c46 --- /dev/null +++ b/test/core/transport/call_spine_benchmarks.h @@ -0,0 +1,367 @@ +// Copyright 2024 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. + +#ifndef GRPC_TEST_CORE_TRANSPORT_CALL_SPINE_BENCHMARKS_H +#define GRPC_TEST_CORE_TRANSPORT_CALL_SPINE_BENCHMARKS_H + +#include + +#include "benchmark/benchmark.h" + +#include "src/core/lib/event_engine/default_event_engine.h" +#include "src/core/lib/gprpp/notification.h" +#include "src/core/lib/iomgr/exec_ctx.h" +#include "src/core/lib/promise/all_ok.h" +#include "src/core/lib/promise/map.h" +#include "src/core/lib/resource_quota/resource_quota.h" +#include "src/core/lib/transport/call_spine.h" + +namespace grpc_core { + +struct BenchmarkCall { + CallInitiator initiator; + CallHandler handler; +}; + +// Unary call with one spawn on each end of the spine. +template +void BM_UnaryWithSpawnPerEnd(benchmark::State& state) { + Fixture fixture; + for (auto _ : state) { + Notification handler_done; + Notification initiator_done; + { + ExecCtx exec_ctx; + BenchmarkCall call = fixture.MakeCall(); + call.handler.SpawnInfallible("handler", [handler = call.handler, &fixture, + &handler_done]() mutable { + handler.PushServerInitialMetadata(fixture.MakeServerInitialMetadata()); + return Map( + AllOk( + Map(handler.PullClientInitialMetadata(), + [](ValueOrFailure md) { + return md.status(); + }), + Map(handler.PullMessage(), + [](ValueOrFailure> msg) { + return msg.status(); + }), + handler.PushMessage(fixture.MakePayload())), + [&handler_done, &fixture, handler](StatusFlag status) mutable { + CHECK(status.ok()); + handler.PushServerTrailingMetadata( + fixture.MakeServerTrailingMetadata()); + handler_done.Notify(); + return Empty{}; + }); + }); + call.initiator.SpawnInfallible( + "initiator", + [initiator = call.initiator, &fixture, &initiator_done]() mutable { + return Map( + AllOk( + Map(initiator.PushMessage(fixture.MakePayload()), + [](StatusFlag) { return Success{}; }), + Map(initiator.PullServerInitialMetadata(), + [](absl::optional md) { + return Success{}; + }), + Map(initiator.PullMessage(), + [](ValueOrFailure> msg) { + return msg.status(); + }), + Map(initiator.PullServerTrailingMetadata(), + [](ServerMetadataHandle) { return Success(); })), + [&initiator_done](StatusFlag result) { + CHECK(result.ok()); + initiator_done.Notify(); + return Empty{}; + }); + }); + } + handler_done.WaitForNotification(); + initiator_done.WaitForNotification(); + } +} + +// Unary call with one promise spawned per operation on the spine. +// It's a little unclear what the optimum should be between the above variant +// and this: whilst a spawn per end minimizes the number of spawns we need to +// do, a spawn per operation can conceivably (but not at the time of writing) +// minimize the number of internal wakeups in the parties. +// For now we track both. +template +void BM_UnaryWithSpawnPerOp(benchmark::State& state) { + Fixture fixture; + for (auto _ : state) { + BenchmarkCall call = fixture.MakeCall(); + Notification handler_done; + Notification initiator_done; + { + ExecCtx exec_ctx; + Party::BulkSpawner handler_spawner(call.handler.party()); + Party::BulkSpawner initiator_spawner(call.initiator.party()); + handler_spawner.Spawn( + "HANDLER:PushServerInitialMetadata", + [&]() { + call.handler.PushServerInitialMetadata( + fixture.MakeServerInitialMetadata()); + return Empty{}; + }, + [](Empty) {}); + handler_spawner.Spawn( + "HANDLER:PullClientInitialMetadata", + [&]() { return call.handler.PullClientInitialMetadata(); }, + [](ValueOrFailure md) { CHECK(md.ok()); }); + handler_spawner.Spawn( + "HANDLER:PullMessage", [&]() { return call.handler.PullMessage(); }, + [&](ValueOrFailure> msg) { + CHECK(msg.ok()); + call.handler.SpawnInfallible( + "HANDLER:PushServerTrailingMetadata", [&]() { + call.handler.PushServerTrailingMetadata( + fixture.MakeServerTrailingMetadata()); + handler_done.Notify(); + return Empty{}; + }); + }); + handler_spawner.Spawn( + "HANDLER:PushMessage", + [&]() { return call.handler.PushMessage(fixture.MakePayload()); }, + [](StatusFlag) {}); + + initiator_spawner.Spawn( + "INITIATOR:PushMessage", + [&]() { return call.initiator.PushMessage(fixture.MakePayload()); }, + [](StatusFlag) {}); + initiator_spawner.Spawn( + "INITIATOR:PullServerInitialMetadata", + [&]() { return call.initiator.PullServerInitialMetadata(); }, + [](absl::optional md) { + CHECK(md.has_value()); + }); + initiator_spawner.Spawn( + "INITIATOR:PullMessage", + [&]() { return call.initiator.PullMessage(); }, + [](ValueOrFailure> msg) { + CHECK(msg.ok()); + }); + initiator_spawner.Spawn( + "INITIATOR:PullServerTrailingMetadata", + [&]() { return call.initiator.PullServerTrailingMetadata(); }, + [&](ServerMetadataHandle md) { + initiator_done.Notify(); + return Empty{}; + }); + } + handler_done.WaitForNotification(); + initiator_done.WaitForNotification(); + } +} + +template +void BM_ClientToServerStreaming(benchmark::State& state) { + Fixture fixture; + BenchmarkCall call = fixture.MakeCall(); + Notification handler_metadata_done; + Notification initiator_metadata_done; + call.handler.SpawnInfallible("handler-initial-metadata", [&]() { + return Map(call.handler.PullClientInitialMetadata(), + [&](ValueOrFailure md) { + CHECK(md.ok()); + call.handler.PushServerInitialMetadata( + fixture.MakeServerInitialMetadata()); + handler_metadata_done.Notify(); + return Empty{}; + }); + }); + call.initiator.SpawnInfallible("initiator-initial-metadata", [&]() { + return Map(call.initiator.PullServerInitialMetadata(), + [&](absl::optional md) { + CHECK(md.has_value()); + initiator_metadata_done.Notify(); + return Empty{}; + }); + }); + handler_metadata_done.WaitForNotification(); + initiator_metadata_done.WaitForNotification(); + for (auto _ : state) { + Notification handler_done; + Notification initiator_done; + call.handler.SpawnInfallible("handler", [&]() { + return Map(call.handler.PullMessage(), + [&](ValueOrFailure> msg) { + CHECK(msg.ok()); + handler_done.Notify(); + return Empty{}; + }); + }); + call.initiator.SpawnInfallible("initiator", [&]() { + return Map(call.initiator.PushMessage(fixture.MakePayload()), + [&](StatusFlag result) { + CHECK(result.ok()); + initiator_done.Notify(); + return Empty{}; + }); + }); + handler_done.WaitForNotification(); + initiator_done.WaitForNotification(); + } + call.initiator.SpawnInfallible("done", [&]() { + call.initiator.Cancel(); + return Empty{}; + }); + call.handler.SpawnInfallible("done", [&]() { + call.handler.PushServerTrailingMetadata( + CancelledServerMetadataFromStatus(absl::CancelledError())); + return Empty{}; + }); +} + +// Base class for fixtures that wrap a single filter. +// Traits should have MakeClientInitialMetadata, MakeServerInitialMetadata, +// MakePayload, MakeServerTrailingMetadata, MakeChannelArgs and a type named +// Filter. +template +class FilterFixture { + public: + BenchmarkCall MakeCall() { + auto p = MakeCallPair(traits_.MakeClientInitialMetadata(), + event_engine_.get(), arena_allocator_->MakeArena()); + return {std::move(p.initiator), p.handler.StartCall(stack_)}; + } + + ServerMetadataHandle MakeServerInitialMetadata() { + return traits_.MakeServerInitialMetadata(); + } + + MessageHandle MakePayload() { return traits_.MakePayload(); } + + ServerMetadataHandle MakeServerTrailingMetadata() { + return traits_.MakeServerTrailingMetadata(); + } + + private: + Traits traits_; + std::shared_ptr event_engine_ = + grpc_event_engine::experimental::GetDefaultEventEngine(); + RefCountedPtr arena_allocator_ = + MakeRefCounted( + ResourceQuota::Default()->memory_quota()->CreateMemoryAllocator( + "test-allocator"), + 1024); + const RefCountedPtr stack_ = [this]() { + auto filter = Traits::Filter::Create(traits_.MakeChannelArgs(), + typename Traits::Filter::Args{}); + CHECK(filter.ok()); + CallFilters::StackBuilder builder; + builder.Add(filter->get()); + builder.AddOwnedObject(std::move(*filter)); + return builder.Build(); + }(); +}; + +// Base class for fixtures that wrap an UnstartedCallDestination. +template +class UnstartedCallDestinationFixture { + public: + BenchmarkCall MakeCall() { + auto p = MakeCallPair(traits_->MakeClientInitialMetadata(), + event_engine_.get(), arena_allocator_->MakeArena()); + top_destination_->StartCall(std::move(p.handler)); + auto handler = bottom_destination_->TakeHandler(); + absl::optional started_handler; + Notification started; + handler.SpawnInfallible("handler_setup", [&]() { + started_handler = handler.StartCall(stack_); + started.Notify(); + return Empty{}; + }); + started.WaitForNotification(); + CHECK(started_handler.has_value()); + return {std::move(p.initiator), std::move(*started_handler)}; + } + + ~UnstartedCallDestinationFixture() { + // TODO(ctiller): entire destructor can be deleted once ExecCtx is gone. + ExecCtx exec_ctx; + stack_.reset(); + top_destination_.reset(); + bottom_destination_.reset(); + arena_allocator_.reset(); + event_engine_.reset(); + traits_.reset(); + } + + ServerMetadataHandle MakeServerInitialMetadata() { + return traits_->MakeServerInitialMetadata(); + } + + MessageHandle MakePayload() { return traits_->MakePayload(); } + + ServerMetadataHandle MakeServerTrailingMetadata() { + return traits_->MakeServerTrailingMetadata(); + } + + private: + class SinkDestination : public UnstartedCallDestination { + public: + void StartCall(UnstartedCallHandler handler) override { + MutexLock lock(&mu_); + handler_ = std::move(handler); + } + void Orphaned() override {} + + UnstartedCallHandler TakeHandler() { + mu_.LockWhen(absl::Condition( + +[](SinkDestination* dest) ABSL_EXCLUSIVE_LOCKS_REQUIRED(dest->mu_) { + return dest->handler_.has_value(); + }, + this)); + auto h = std::move(*handler_); + handler_.reset(); + mu_.Unlock(); + return h; + } + + private: + absl::Mutex mu_; + absl::optional handler_ ABSL_GUARDED_BY(mu_); + }; + + // TODO(ctiller): no need for unique_ptr once ExecCtx is gone + std::unique_ptr traits_ = std::make_unique(); + std::shared_ptr event_engine_ = + grpc_event_engine::experimental::GetDefaultEventEngine(); + RefCountedPtr arena_allocator_ = + MakeRefCounted( + ResourceQuota::Default()->memory_quota()->CreateMemoryAllocator( + "test-allocator"), + 1024); + RefCountedPtr bottom_destination_ = + MakeRefCounted(); + RefCountedPtr top_destination_ = + traits_->CreateCallDestination(bottom_destination_); + RefCountedPtr stack_ = + CallFilters::StackBuilder().Build(); +}; + +} // namespace grpc_core + +#define GRPC_CALL_SPINE_BENCHMARK(Fixture) \ + BENCHMARK(grpc_core::BM_UnaryWithSpawnPerEnd); \ + BENCHMARK(grpc_core::BM_UnaryWithSpawnPerOp); \ + BENCHMARK(grpc_core::BM_ClientToServerStreaming) + +#endif // GRPC_TEST_CORE_TRANSPORT_CALL_SPINE_BENCHMARKS_H diff --git a/test/core/transport/chttp2/ping_configuration_test.cc b/test/core/transport/chttp2/ping_configuration_test.cc index 8c007454de5..4b91a3019c1 100644 --- a/test/core/transport/chttp2/ping_configuration_test.cc +++ b/test/core/transport/chttp2/ping_configuration_test.cc @@ -55,8 +55,8 @@ class ConfigurationTest : public ::testing::Test { TEST_F(ConfigurationTest, ClientKeepaliveDefaults) { ExecCtx exec_ctx; - grpc_chttp2_transport* t = reinterpret_cast( - grpc_create_chttp2_transport( + grpc_chttp2_transport* t = + reinterpret_cast(grpc_create_chttp2_transport( args_, mock_endpoint_controller_->TakeCEndpoint(), /*is_client=*/true)); EXPECT_EQ(t->keepalive_time, Duration::Infinity()); @@ -72,8 +72,8 @@ TEST_F(ConfigurationTest, ClientKeepaliveExplicitArgs) { args_ = args_.Set(GRPC_ARG_KEEPALIVE_TIMEOUT_MS, 10000); args_ = args_.Set(GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS, true); args_ = args_.Set(GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA, 3); - grpc_chttp2_transport* t = reinterpret_cast( - grpc_create_chttp2_transport( + grpc_chttp2_transport* t = + reinterpret_cast(grpc_create_chttp2_transport( args_, mock_endpoint_controller_->TakeCEndpoint(), /*is_client=*/true)); EXPECT_EQ(t->keepalive_time, Duration::Seconds(20)); @@ -85,8 +85,8 @@ TEST_F(ConfigurationTest, ClientKeepaliveExplicitArgs) { TEST_F(ConfigurationTest, ServerKeepaliveDefaults) { ExecCtx exec_ctx; - grpc_chttp2_transport* t = reinterpret_cast( - grpc_create_chttp2_transport( + grpc_chttp2_transport* t = + reinterpret_cast(grpc_create_chttp2_transport( args_, mock_endpoint_controller_->TakeCEndpoint(), /*is_client=*/false)); EXPECT_EQ(t->keepalive_time, Duration::Hours(2)); @@ -109,8 +109,8 @@ TEST_F(ConfigurationTest, ServerKeepaliveExplicitArgs) { args_ = args_.Set(GRPC_ARG_HTTP2_MIN_RECV_PING_INTERVAL_WITHOUT_DATA_MS, 20000); args_ = args_.Set(GRPC_ARG_HTTP2_MAX_PING_STRIKES, 0); - grpc_chttp2_transport* t = reinterpret_cast( - grpc_create_chttp2_transport( + grpc_chttp2_transport* t = + reinterpret_cast(grpc_create_chttp2_transport( args_, mock_endpoint_controller_->TakeCEndpoint(), /*is_client=*/false)); EXPECT_EQ(t->keepalive_time, Duration::Seconds(20)); @@ -138,8 +138,8 @@ TEST_F(ConfigurationTest, ModifyClientDefaults) { grpc_chttp2_config_default_keepalive_args(args, /*is_client=*/true); // Note that we are using the original args_ object for creating the transport // which does not override the defaults. - grpc_chttp2_transport* t = reinterpret_cast( - grpc_create_chttp2_transport( + grpc_chttp2_transport* t = + reinterpret_cast(grpc_create_chttp2_transport( args_, mock_endpoint_controller_->TakeCEndpoint(), /*is_client=*/true)); EXPECT_EQ(t->keepalive_time, Duration::Seconds(20)); @@ -165,8 +165,8 @@ TEST_F(ConfigurationTest, ModifyServerDefaults) { grpc_chttp2_config_default_keepalive_args(args, /*is_client=*/false); // Note that we are using the original args_ object for creating the transport // which does not override the defaults. - grpc_chttp2_transport* t = reinterpret_cast( - grpc_create_chttp2_transport( + grpc_chttp2_transport* t = + reinterpret_cast(grpc_create_chttp2_transport( args_, mock_endpoint_controller_->TakeCEndpoint(), /*is_client=*/false)); EXPECT_EQ(t->keepalive_time, Duration::Seconds(20)); diff --git a/tools/distrib/fix_build_deps.py b/tools/distrib/fix_build_deps.py index 9bbf9627773..5b6e7492755 100755 --- a/tools/distrib/fix_build_deps.py +++ b/tools/distrib/fix_build_deps.py @@ -97,6 +97,7 @@ EXTERNAL_DEPS = { "absl/types/span.h": "absl/types:span", "absl/types/variant.h": "absl/types:variant", "absl/utility/utility.h": "absl/utility", + "benchmark/benchmark.h": "benchmark", "address_sorting/address_sorting.h": "address_sorting", "google/cloud/opentelemetry/resource_detector.h": "google_cloud_cpp:opentelemetry", "opentelemetry/common/attribute_value.h": "otel/api", @@ -412,6 +413,7 @@ for dirname in [ "test/core/resource_quota", "test/core/transport/chaotic_good", "test/core/transport/test_suite", + "test/core/transport", "fuzztest", "fuzztest/core/channel", "fuzztest/core/transport/chttp2", @@ -452,6 +454,7 @@ for dirname in [ "sh_library": lambda name, **kwargs: None, "platform": lambda name, **kwargs: None, "grpc_clang_cl_settings": lambda **kwargs: None, + "grpc_benchmark_args": lambda **kwargs: [], }, {}, ) diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json index 224566e60d2..5937f778a88 100644 --- a/tools/run_tests/generated/tests.json +++ b/tools/run_tests/generated/tests.json @@ -1,6 +1,72 @@ [ + { + "args": [ + "--benchmark_min_time=0.001s" + ], + "benchmark": true, + "ci_platforms": [ + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "gtest": false, + "language": "c", + "name": "bm_call_spine", + "platforms": [ + "linux", + "posix" + ], + "uses_polling": false + }, + { + "args": [ + "--benchmark_min_time=0.001s" + ], + "benchmark": true, + "ci_platforms": [ + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "gtest": false, + "language": "c", + "name": "bm_client_call", + "platforms": [ + "linux", + "posix" + ], + "uses_polling": false + }, + { + "args": [ + "--benchmark_min_time=0.001s" + ], + "benchmark": true, + "ci_platforms": [ + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "gtest": false, + "language": "c", + "name": "bm_client_channel", + "platforms": [ + "linux", + "posix" + ], + "uses_polling": false + }, { "args": [], "benchmark": true, @@ -25,6 +91,54 @@ ], "uses_polling": true }, + { + "args": [ + "--benchmark_min_time=0.001s" + ], + "benchmark": true, + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "gtest": false, + "language": "c", + "name": "bm_http_client_filter", + "platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "uses_polling": false + }, + { + "args": [ + "--benchmark_min_time=0.001s" + ], + "benchmark": true, + "ci_platforms": [ + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "gtest": false, + "language": "c", + "name": "bm_party", + "platforms": [ + "linux", + "posix" + ], + "uses_polling": false + }, { "args": [], "benchmark": false, diff --git a/tools/run_tests/sanity/check_absl_mutex.sh b/tools/run_tests/sanity/check_absl_mutex.sh index e4b5cb27d9d..7243f9e471a 100755 --- a/tools/run_tests/sanity/check_absl_mutex.sh +++ b/tools/run_tests/sanity/check_absl_mutex.sh @@ -30,6 +30,7 @@ find . \( \( -name "*.cc" \) -or \( -name "*.h" \) \) \ -a -not -wholename "./include/grpcpp/impl/sync.h" \ -a -not -wholename "./src/core/lib/gprpp/sync.h" \ -a -not -wholename "./src/core/util/sync_abseil.cc" \ + -a -not -wholename "./test/core/transport/call_spine_benchmarks.h" \ -print0 |\ xargs -0 grep -n "absl::Mutex" | \ diff - /dev/null