[call-v3] Begin adding benchmarks (#36946)

Closes #36946

COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/36946 from ctiller:transport-refs-10 16f50573e7
PiperOrigin-RevId: 645243962
pull/37002/head
Craig Tiller 5 months ago committed by Copybara-Service
parent ff54357fe6
commit 23adb994cf
  1. 206
      CMakeLists.txt
  2. 85
      build_autogenerated.yaml
  3. 1
      src/core/client_channel/client_channel.cc
  4. 5
      src/core/lib/channel/channel_args.h
  5. 2
      src/core/lib/promise/activity.h
  6. 34
      src/core/lib/promise/poll.h
  7. 16
      src/core/lib/promise/status_flag.h
  8. 74
      src/core/lib/transport/call_filters.cc
  9. 9
      src/core/lib/transport/call_filters.h
  10. 2
      src/core/lib/transport/call_spine.h
  11. 5
      src/core/lib/transport/metadata_batch.h
  12. 18
      test/core/call/BUILD
  13. 192
      test/core/call/bm_client_call.cc
  14. 19
      test/core/client_channel/BUILD
  15. 200
      test/core/client_channel/bm_client_channel.cc
  16. 15
      test/core/filters/BUILD
  17. 86
      test/core/filters/bm_http_client_filter.cc
  18. 19
      test/core/promise/BUILD
  19. 110
      test/core/promise/bm_party.cc
  20. 6
      test/core/security/ssl_server_fuzzer.cc
  21. 38
      test/core/transport/BUILD
  22. 121
      test/core/transport/bm_call_spine.cc
  23. 2
      test/core/transport/call_filters_test.cc
  24. 367
      test/core/transport/call_spine_benchmarks.h
  25. 24
      test/core/transport/chttp2/ping_configuration_test.cc
  26. 3
      tools/distrib/fix_build_deps.py
  27. 114
      tools/run_tests/generated/tests.json
  28. 1
      tools/run_tests/sanity/check_absl_mutex.sh

206
CMakeLists.txt generated

@ -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)

@ -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

@ -625,6 +625,7 @@ ClientChannel::ClientChannel(
work_serializer_(std::make_shared<WorkSerializer>(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.

@ -558,6 +558,11 @@ class ChannelArgs {
bool WantMinimalStack() const;
std::string ToString() const;
template <typename Sink>
friend void AbslStringify(Sink& sink, const ChannelArgs& args) {
sink.Append(args.ToString());
}
private:
explicit ChannelArgs(AVL<RefCountedStringValue, Value> args);

@ -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<Activity>()->ForceImmediateRepoll(std::exchange(wakeups_, 0));
}

@ -44,6 +44,10 @@ GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline bool operator==(const Empty&,
const Empty&) {
return true;
}
template <typename Sink>
void AbslStringify(Sink& sink, Empty) {
sink.Append("{}");
}
// The result of polling a Promise once.
//
@ -283,6 +287,36 @@ void AbslStringify(Sink& sink, const Poll<T>& poll) {
absl::Format(&sink, "%v", poll.value());
}
template <typename Sink, typename T>
void AbslStringify(Sink& sink, const Poll<absl::optional<T>>& poll) {
if (poll.pending()) {
absl::Format(&sink, "<<pending>>");
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 <typename Sink, typename T, typename Deleter>
void AbslStringify(Sink& sink, const Poll<absl::optional<std::unique_ptr<T, Deleter>>>& poll) {
if (poll.pending()) {
absl::Format(&sink, "<<pending>>");
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

@ -172,6 +172,11 @@ struct StatusCastImpl<absl::Status, const StatusFlag&> {
}
};
template <>
struct StatusCastImpl<StatusFlag, Success> {
static StatusFlag Cast(Success) { return StatusFlag(true); }
};
template <typename T>
struct FailureStatusCastImpl<absl::StatusOr<T>, StatusFlag> {
GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static absl::StatusOr<T> Cast(
@ -253,6 +258,17 @@ class ValueOrFailure {
return value_ != other;
}
template <typename Sink>
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<T> value_;
};

@ -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<bool> 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<bool> 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<bool> 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<ValueOrFailure<bool>> 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<Empty> 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_ =

@ -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:

@ -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();

@ -1322,6 +1322,11 @@ class MetadataMap {
return builder.TakeOutput();
}
template <typename Sink>
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.

@ -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",
],
)

@ -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 <benchmark/benchmark.h>
#include <grpc/grpc.h>
#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<UnstartedCallHandler> 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<grpc_call, void (*)(grpc_call*)>(
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<grpc_event_engine::experimental::EventEngine> event_engine_ =
grpc_event_engine::experimental::GetDefaultEventEngine();
RefCountedPtr<CallArenaAllocator> arena_allocator_ =
MakeRefCounted<CallArenaAllocator>(
ResourceQuota::Default()->memory_quota()->CreateMemoryAllocator(
"test-allocator"),
1024);
RefCountedPtr<TestCallDestination> destination_ =
MakeRefCounted<TestCallDestination>();
};
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<void*>(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<ServerMetadata>());
auto response =
Arena::MakePooled<Message>(SliceBuffer(response_payload.Copy()), 0);
return Map(
AllOk<StatusFlag>(
Map(handler.PullClientInitialMetadata(),
[](ValueOrFailure<ClientMetadataHandle> status) {
return status.status();
}),
Map(handler.PullMessage(),
[](ValueOrFailure<absl::optional<MessageHandle>> message) {
return message.status();
}),
handler.PushMessage(std::move(response))),
[handler](StatusFlag status) mutable {
CHECK(status.ok());
auto trailing_metadata = Arena::MakePooled<ServerMetadata>();
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;
}

@ -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",
],
)

@ -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 <benchmark/benchmark.h>
#include "absl/memory/memory.h"
#include "absl/strings/string_view.h"
#include <grpc/grpc.h>
#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<UnstartedCallDestination> CreateCallDestination(
RefCountedPtr<UnstartedCallDestination> final_destination) {
call_destination_factory_ = std::make_unique<TestCallDestinationFactory>(
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<ClientMetadata>();
md->Set(HttpPathMetadata(), kTestPath.Copy());
return md;
}
ServerMetadataHandle MakeServerInitialMetadata() {
return Arena::MakePooled<ServerMetadata>();
}
MessageHandle MakePayload() { return Arena::MakePooled<Message>(); }
ServerMetadataHandle MakeServerTrailingMetadata() {
auto md = Arena::MakePooled<ServerMetadata>();
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<Subchannel> CreateSubchannel(
const grpc_resolved_address& address,
const ChannelArgs& args) override {
return Subchannel::Create(MakeOrphanable<TestConnector>(), address, args);
}
};
class TestCallDestinationFactory final
: public ClientChannel::CallDestinationFactory {
public:
explicit TestCallDestinationFactory(
RefCountedPtr<UnstartedCallDestination> call_destination)
: call_destination_(std::move(call_destination)) {}
RefCountedPtr<UnstartedCallDestination> CreateCallDestination(
ClientChannel::PickerObservable picker) override {
return call_destination_;
}
private:
RefCountedPtr<UnstartedCallDestination> call_destination_;
};
std::unique_ptr<TestCallDestinationFactory> call_destination_factory_;
TestClientChannelFactory client_channel_factory_;
};
GRPC_CALL_SPINE_BENCHMARK(UnstartedCallDestinationFixture<ClientChannelTraits>);
namespace {
class TestResolver final : public Resolver {
public:
explicit TestResolver(ChannelArgs args,
std::unique_ptr<Resolver::ResultHandler> result_handler,
std::shared_ptr<WorkSerializer> 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<TestResolver>()] {
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<Resolver::ResultHandler> result_handler_;
const std::shared_ptr<WorkSerializer> work_serializer_;
};
class TestResolverFactory final : public ResolverFactory {
public:
OrphanablePtr<Resolver> CreateResolver(ResolverArgs args) const override {
return MakeOrphanable<TestResolver>(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<FinalDestination>();
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_core::TestResolverFactory>());
});
grpc_init();
{
auto ee = grpc_event_engine::experimental::GetDefaultEventEngine();
benchmark::RunTheBenchmarksNamespaced();
}
grpc_shutdown();
return 0;
}

@ -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",
],
)

@ -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 <benchmark/benchmark.h>
#include "absl/strings/string_view.h"
#include <grpc/grpc.h>
#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<ClientMetadata>();
}
ServerMetadataHandle MakeServerInitialMetadata() {
return Arena::MakePooled<ServerMetadata>();
}
MessageHandle MakePayload() { return Arena::MakePooled<Message>(); }
ServerMetadataHandle MakeServerTrailingMetadata() {
auto md = Arena::MakePooled<ServerMetadata>();
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<HttpClientFilterTraits>);
} // 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;
}

@ -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",
],
)

@ -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 <benchmark/benchmark.h>
#include <grpc/grpc.h>
#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<grpc_event_engine::experimental::EventEngine>
ee_ctx(ee_.get());
return Party::RunParty();
}
void PartyOver() override {
{
promise_detail::Context<grpc_event_engine::experimental::EventEngine>
ee_ctx(ee_.get());
CancelRemainingParticipants();
}
delete this;
}
private:
grpc_event_engine::experimental::EventEngine* event_engine() const final {
return ee_.get();
}
std::shared_ptr<grpc_event_engine::experimental::EventEngine> 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<StatusFlag> {
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;
}

@ -97,9 +97,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
auto channel_args =
grpc_core::ChannelArgs().SetObject<EventEngine>(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

@ -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",
],
)

@ -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 <benchmark/benchmark.h>
#include <grpc/grpc.h>
#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<ClientMetadata>(),
event_engine_.get(), arena_allocator_->MakeArena());
return {std::move(p.initiator), p.handler.StartCall(stack_)};
}
ServerMetadataHandle MakeServerInitialMetadata() {
return Arena::MakePooled<ServerMetadata>();
}
MessageHandle MakePayload() { return Arena::MakePooled<Message>(); }
ServerMetadataHandle MakeServerTrailingMetadata() {
return Arena::MakePooled<ServerMetadata>();
}
private:
std::shared_ptr<grpc_event_engine::experimental::EventEngine> event_engine_ =
grpc_event_engine::experimental::GetDefaultEventEngine();
RefCountedPtr<CallArenaAllocator> arena_allocator_ =
MakeRefCounted<CallArenaAllocator>(
ResourceQuota::Default()->memory_quota()->CreateMemoryAllocator(
"test-allocator"),
1024);
RefCountedPtr<CallFilters::Stack> stack_ =
CallFilters::StackBuilder().Build();
};
GRPC_CALL_SPINE_BENCHMARK(CallSpineFixture);
class ForwardCallFixture {
public:
BenchmarkCall MakeCall() {
auto p1 = MakeCallPair(Arena::MakePooled<ClientMetadata>(),
event_engine_.get(), arena_allocator_->MakeArena());
auto p2 = MakeCallPair(Arena::MakePooled<ClientMetadata>(),
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<ClientMetadataHandle> md) mutable {
CHECK(md.ok());
ForwardCall(std::move(p1_handler), std::move(p2.initiator));
return Empty{};
});
});
absl::optional<CallHandler> 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<ServerMetadata>();
}
MessageHandle MakePayload() { return Arena::MakePooled<Message>(); }
ServerMetadataHandle MakeServerTrailingMetadata() {
return Arena::MakePooled<ServerMetadata>();
}
private:
std::shared_ptr<grpc_event_engine::experimental::EventEngine> event_engine_ =
grpc_event_engine::experimental::GetDefaultEventEngine();
RefCountedPtr<CallArenaAllocator> arena_allocator_ =
MakeRefCounted<CallArenaAllocator>(
ResourceQuota::Default()->memory_quota()->CreateMemoryAllocator(
"test-allocator"),
1024);
RefCountedPtr<CallFilters::Stack> 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;
}

@ -60,7 +60,7 @@ class MockActivity : public Activity, public Wakeable {
};
#define EXPECT_WAKEUP(activity, statement) \
EXPECT_CALL((activity), WakeupRequested()); \
EXPECT_CALL((activity), WakeupRequested()).Times(::testing::AtLeast(1)); \
statement; \
Mock::VerifyAndClearExpectations(&(activity));

@ -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 <memory>
#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 <typename Fixture>
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<StatusFlag>(
Map(handler.PullClientInitialMetadata(),
[](ValueOrFailure<ClientMetadataHandle> md) {
return md.status();
}),
Map(handler.PullMessage(),
[](ValueOrFailure<absl::optional<MessageHandle>> 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<StatusFlag>(
Map(initiator.PushMessage(fixture.MakePayload()),
[](StatusFlag) { return Success{}; }),
Map(initiator.PullServerInitialMetadata(),
[](absl::optional<ServerMetadataHandle> md) {
return Success{};
}),
Map(initiator.PullMessage(),
[](ValueOrFailure<absl::optional<MessageHandle>> 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 <typename Fixture>
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<ClientMetadataHandle> md) { CHECK(md.ok()); });
handler_spawner.Spawn(
"HANDLER:PullMessage", [&]() { return call.handler.PullMessage(); },
[&](ValueOrFailure<absl::optional<MessageHandle>> 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<ServerMetadataHandle> md) {
CHECK(md.has_value());
});
initiator_spawner.Spawn(
"INITIATOR:PullMessage",
[&]() { return call.initiator.PullMessage(); },
[](ValueOrFailure<absl::optional<MessageHandle>> 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 <typename Fixture>
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<ClientMetadataHandle> 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<ServerMetadataHandle> 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<absl::optional<MessageHandle>> 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 Traits>
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<grpc_event_engine::experimental::EventEngine> event_engine_ =
grpc_event_engine::experimental::GetDefaultEventEngine();
RefCountedPtr<CallArenaAllocator> arena_allocator_ =
MakeRefCounted<CallArenaAllocator>(
ResourceQuota::Default()->memory_quota()->CreateMemoryAllocator(
"test-allocator"),
1024);
const RefCountedPtr<CallFilters::Stack> 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 Traits>
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<CallHandler> 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<UnstartedCallHandler> handler_ ABSL_GUARDED_BY(mu_);
};
// TODO(ctiller): no need for unique_ptr once ExecCtx is gone
std::unique_ptr<Traits> traits_ = std::make_unique<Traits>();
std::shared_ptr<grpc_event_engine::experimental::EventEngine> event_engine_ =
grpc_event_engine::experimental::GetDefaultEventEngine();
RefCountedPtr<CallArenaAllocator> arena_allocator_ =
MakeRefCounted<CallArenaAllocator>(
ResourceQuota::Default()->memory_quota()->CreateMemoryAllocator(
"test-allocator"),
1024);
RefCountedPtr<SinkDestination> bottom_destination_ =
MakeRefCounted<SinkDestination>();
RefCountedPtr<UnstartedCallDestination> top_destination_ =
traits_->CreateCallDestination(bottom_destination_);
RefCountedPtr<CallFilters::Stack> stack_ =
CallFilters::StackBuilder().Build();
};
} // namespace grpc_core
#define GRPC_CALL_SPINE_BENCHMARK(Fixture) \
BENCHMARK(grpc_core::BM_UnaryWithSpawnPerEnd<Fixture>); \
BENCHMARK(grpc_core::BM_UnaryWithSpawnPerOp<Fixture>); \
BENCHMARK(grpc_core::BM_ClientToServerStreaming<Fixture>)
#endif // GRPC_TEST_CORE_TRANSPORT_CALL_SPINE_BENCHMARKS_H

@ -55,8 +55,8 @@ class ConfigurationTest : public ::testing::Test {
TEST_F(ConfigurationTest, ClientKeepaliveDefaults) {
ExecCtx exec_ctx;
grpc_chttp2_transport* t = reinterpret_cast<grpc_chttp2_transport*>(
grpc_create_chttp2_transport(
grpc_chttp2_transport* t =
reinterpret_cast<grpc_chttp2_transport*>(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_chttp2_transport*>(
grpc_create_chttp2_transport(
grpc_chttp2_transport* t =
reinterpret_cast<grpc_chttp2_transport*>(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_chttp2_transport*>(
grpc_create_chttp2_transport(
grpc_chttp2_transport* t =
reinterpret_cast<grpc_chttp2_transport*>(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_chttp2_transport*>(
grpc_create_chttp2_transport(
grpc_chttp2_transport* t =
reinterpret_cast<grpc_chttp2_transport*>(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_chttp2_transport*>(
grpc_create_chttp2_transport(
grpc_chttp2_transport* t =
reinterpret_cast<grpc_chttp2_transport*>(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_chttp2_transport*>(
grpc_create_chttp2_transport(
grpc_chttp2_transport* t =
reinterpret_cast<grpc_chttp2_transport*>(grpc_create_chttp2_transport(
args_, mock_endpoint_controller_->TakeCEndpoint(),
/*is_client=*/false));
EXPECT_EQ(t->keepalive_time, Duration::Seconds(20));

@ -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: [],
},
{},
)

@ -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,

@ -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

Loading…
Cancel
Save