[call-v3][transport] Add benchmarks for promise based transports (#37054)

Add benchmarks for inproc & chaotic good transports.

Initial inproc results:
```
-----------------------------------------------------------------------------------------------------
Benchmark                                                           Time             CPU   Iterations
-----------------------------------------------------------------------------------------------------
BM_UnaryWithSpawnPerEnd<TransportFixture<InprocTraits>>          2017 ns         2017 ns      6999359
BM_UnaryWithSpawnPerOp<TransportFixture<InprocTraits>>           2201 ns         2201 ns      6343162
BM_ClientToServerStreaming<TransportFixture<InprocTraits>>        388 ns          388 ns     36472157
```

Initial chaotic good results:
```
----------------------------------------------------------------------------------------------------------
Benchmark                                                                Time             CPU   Iterations
----------------------------------------------------------------------------------------------------------
BM_UnaryWithSpawnPerEnd<TransportFixture<ChaoticGoodTraits>>         87201 ns        36978 ns       392538
BM_UnaryWithSpawnPerOp<TransportFixture<ChaoticGoodTraits>>          86533 ns        36676 ns       369698
BM_ClientToServerStreaming<TransportFixture<ChaoticGoodTraits>>      20843 ns        10253 ns      1000000
```

(chaotic good is jumping threads all over the place here... we'll want to address that as future work)

Closes #37054

COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/37054 from ctiller:moar-transporty 27511cd483
PiperOrigin-RevId: 647319669
pull/37073/head
Craig Tiller 8 months ago committed by Copybara-Service
parent da14ff3ebd
commit c4aa89d60d
  1. 96
      CMakeLists.txt
  2. 74
      build_autogenerated.yaml
  3. 1
      src/core/ext/transport/chaotic_good/client_transport.cc
  4. 4
      src/core/ext/transport/chaotic_good/server_transport.cc
  5. 12
      test/core/test_util/BUILD
  6. 131
      test/core/test_util/passthrough_endpoint.cc
  7. 95
      test/core/test_util/passthrough_endpoint.h
  8. 48
      test/core/transport/benchmarks/BUILD
  9. 93
      test/core/transport/benchmarks/bm_chaotic_good.cc
  10. 83
      test/core/transport/benchmarks/bm_inproc.cc
  11. 83
      test/core/transport/call_spine_benchmarks.h
  12. 44
      tools/run_tests/generated/tests.json

96
CMakeLists.txt generated

@ -889,6 +889,9 @@ if(gRPC_BUILD_TESTS)
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_chaotic_good)
endif()
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_c bm_client_call)
endif()
@ -901,6 +904,9 @@ if(gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_c bm_http_client_filter)
endif()
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_c bm_inproc)
endif()
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_c bm_party)
endif()
@ -5869,6 +5875,51 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX)
)
endif()
endif()
if(gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX)
add_executable(bm_chaotic_good
src/core/ext/transport/chaotic_good/client_transport.cc
src/core/ext/transport/chaotic_good/frame.cc
src/core/ext/transport/chaotic_good/frame_header.cc
src/core/ext/transport/chaotic_good/server_transport.cc
src/core/lib/transport/promise_endpoint.cc
test/core/test_util/passthrough_endpoint.cc
test/core/transport/benchmarks/bm_chaotic_good.cc
)
if(WIN32 AND MSVC)
if(BUILD_SHARED_LIBS)
target_compile_definitions(bm_chaotic_good
PRIVATE
"GPR_DLL_IMPORTS"
"GRPC_DLL_IMPORTS"
)
endif()
endif()
target_compile_features(bm_chaotic_good PUBLIC cxx_std_14)
target_include_directories(bm_chaotic_good
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_chaotic_good
${_gRPC_ALLTARGETS_LIBRARIES}
${_gRPC_BENCHMARK_LIBRARIES}
grpc
)
endif()
endif()
if(gRPC_BUILD_TESTS)
@ -6025,6 +6076,51 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX)
)
endif()
endif()
if(gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX)
add_executable(bm_inproc
src/core/ext/transport/chaotic_good/client_transport.cc
src/core/ext/transport/chaotic_good/frame.cc
src/core/ext/transport/chaotic_good/frame_header.cc
src/core/ext/transport/chaotic_good/server_transport.cc
src/core/lib/transport/promise_endpoint.cc
test/core/test_util/passthrough_endpoint.cc
test/core/transport/benchmarks/bm_inproc.cc
)
if(WIN32 AND MSVC)
if(BUILD_SHARED_LIBS)
target_compile_definitions(bm_inproc
PRIVATE
"GPR_DLL_IMPORTS"
"GRPC_DLL_IMPORTS"
)
endif()
endif()
target_compile_features(bm_inproc PUBLIC cxx_std_14)
target_include_directories(bm_inproc
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_inproc
${_gRPC_ALLTARGETS_LIBRARIES}
${_gRPC_BENCHMARK_LIBRARIES}
grpc
)
endif()
endif()
if(gRPC_BUILD_TESTS)

@ -5157,6 +5157,43 @@ targets:
- linux
- posix
uses_polling: false
- name: bm_chaotic_good
build: test
language: c
headers:
- src/core/ext/transport/chaotic_good/chaotic_good_transport.h
- src/core/ext/transport/chaotic_good/client_transport.h
- src/core/ext/transport/chaotic_good/frame.h
- src/core/ext/transport/chaotic_good/frame_header.h
- src/core/ext/transport/chaotic_good/server_transport.h
- src/core/lib/promise/event_engine_wakeup_scheduler.h
- src/core/lib/promise/inter_activity_latch.h
- src/core/lib/promise/inter_activity_pipe.h
- src/core/lib/promise/mpsc.h
- src/core/lib/promise/switch.h
- src/core/lib/promise/wait_set.h
- src/core/lib/transport/promise_endpoint.h
- test/core/test_util/passthrough_endpoint.h
- test/core/transport/call_spine_benchmarks.h
src:
- src/core/ext/transport/chaotic_good/client_transport.cc
- src/core/ext/transport/chaotic_good/frame.cc
- src/core/ext/transport/chaotic_good/frame_header.cc
- src/core/ext/transport/chaotic_good/server_transport.cc
- src/core/lib/transport/promise_endpoint.cc
- test/core/test_util/passthrough_endpoint.cc
- test/core/transport/benchmarks/bm_chaotic_good.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
@ -5227,6 +5264,43 @@ targets:
- linux
- posix
uses_polling: false
- name: bm_inproc
build: test
language: c
headers:
- src/core/ext/transport/chaotic_good/chaotic_good_transport.h
- src/core/ext/transport/chaotic_good/client_transport.h
- src/core/ext/transport/chaotic_good/frame.h
- src/core/ext/transport/chaotic_good/frame_header.h
- src/core/ext/transport/chaotic_good/server_transport.h
- src/core/lib/promise/event_engine_wakeup_scheduler.h
- src/core/lib/promise/inter_activity_latch.h
- src/core/lib/promise/inter_activity_pipe.h
- src/core/lib/promise/mpsc.h
- src/core/lib/promise/switch.h
- src/core/lib/promise/wait_set.h
- src/core/lib/transport/promise_endpoint.h
- test/core/test_util/passthrough_endpoint.h
- test/core/transport/call_spine_benchmarks.h
src:
- src/core/ext/transport/chaotic_good/client_transport.cc
- src/core/ext/transport/chaotic_good/frame.cc
- src/core/ext/transport/chaotic_good/frame_header.cc
- src/core/ext/transport/chaotic_good/server_transport.cc
- src/core/lib/transport/promise_endpoint.cc
- test/core/test_util/passthrough_endpoint.cc
- test/core/transport/benchmarks/bm_inproc.cc
deps:
- benchmark
- grpc
args:
- --benchmark_min_time=0.001s
benchmark: true
defaults: benchmark
platforms:
- linux
- posix
uses_polling: false
- name: bm_party
build: test
language: c

@ -58,7 +58,6 @@ namespace grpc_core {
namespace chaotic_good {
void ChaoticGoodClientTransport::Orphan() {
LOG(INFO) << "ChaoticGoodClientTransport::Orphan";
AbortWithError();
ActivityPtr writer;
ActivityPtr reader;

@ -323,9 +323,7 @@ auto ChaoticGoodServerTransport::ReadOneFrame(ChaoticGoodTransport& transport) {
return absl::OkStatus();
});
},
[]() -> absl::Status {
return absl::InternalError("Unexpected cancel frame");
});
[]() -> absl::Status { return absl::OkStatus(); });
}),
Default([frame_header]() {
return absl::InternalError(

@ -535,3 +535,15 @@ grpc_cc_library(
"//src/core:metrics",
],
)
grpc_cc_library(
name = "passthrough_endpoint",
testonly = True,
srcs = ["passthrough_endpoint.cc"],
hdrs = ["passthrough_endpoint.h"],
external_deps = [
],
deps = [
"//:grpc",
],
)

@ -0,0 +1,131 @@
// 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 "test/core/test_util/passthrough_endpoint.h"
namespace grpc_event_engine {
namespace experimental {
class PassthroughEndpoint::CallbackHelper {
public:
CallbackHelper(EventEngine* event_engine, bool allow_inline_callbacks)
: event_engine_(allow_inline_callbacks ? nullptr : event_engine) {}
template <typename F>
void AddCallback(F&& callback) {
if (event_engine_ != nullptr) {
event_engine_->Run(std::forward<F>(callback));
} else {
callbacks_.emplace_back(std::forward<F>(callback));
}
}
~CallbackHelper() {
for (auto& callback : callbacks_) {
callback();
}
}
private:
EventEngine* event_engine_;
absl::InlinedVector<absl::AnyInvocable<void()>, 4> callbacks_;
};
PassthroughEndpoint::PassthroughEndpointPair
PassthroughEndpoint::MakePassthroughEndpoint(int client_port, int server_port,
bool allow_inline_callbacks) {
auto send_middle =
grpc_core::MakeRefCounted<PassthroughEndpoint::Middle>(client_port);
auto recv_middle =
grpc_core::MakeRefCounted<PassthroughEndpoint::Middle>(server_port);
auto client = std::unique_ptr<PassthroughEndpoint>(new PassthroughEndpoint(
send_middle, recv_middle, allow_inline_callbacks));
auto server = std::unique_ptr<PassthroughEndpoint>(new PassthroughEndpoint(
recv_middle, send_middle, allow_inline_callbacks));
return {std::move(client), std::move(server)};
}
PassthroughEndpoint::~PassthroughEndpoint() {
CallbackHelper callback_helper(event_engine_.get(), allow_inline_callbacks_);
send_middle_->Close(callback_helper);
recv_middle_->Close(callback_helper);
}
bool PassthroughEndpoint::Read(absl::AnyInvocable<void(absl::Status)> on_read,
SliceBuffer* buffer, const ReadArgs*) {
CallbackHelper callback_helper(event_engine_.get(), allow_inline_callbacks_);
grpc_core::MutexLock lock(&recv_middle_->mu);
if (recv_middle_->closed) {
callback_helper.AddCallback([on_read = std::move(on_read)]() mutable {
on_read(absl::CancelledError());
});
return false;
}
if (recv_middle_->on_write != nullptr) {
*buffer = std::move(*recv_middle_->write_buffer);
callback_helper.AddCallback(
[on_write = std::move(recv_middle_->on_write)]() mutable {
on_write(absl::OkStatus());
});
recv_middle_->on_write = nullptr;
return true;
}
recv_middle_->read_buffer = buffer;
recv_middle_->on_read = std::move(on_read);
return false;
}
bool PassthroughEndpoint::Write(absl::AnyInvocable<void(absl::Status)> on_write,
SliceBuffer* buffer, const WriteArgs*) {
CallbackHelper callback_helper(event_engine_.get(), allow_inline_callbacks_);
grpc_core::MutexLock lock(&send_middle_->mu);
if (send_middle_->closed) {
callback_helper.AddCallback([on_write = std::move(on_write)]() mutable {
on_write(absl::CancelledError());
});
return false;
}
if (send_middle_->on_read != nullptr) {
*send_middle_->read_buffer = std::move(*buffer);
callback_helper.AddCallback(
[on_read = std::move(send_middle_->on_read)]() mutable {
on_read(absl::OkStatus());
});
send_middle_->on_read = nullptr;
return true;
}
send_middle_->write_buffer = buffer;
send_middle_->on_write = std::move(on_write);
return false;
}
void PassthroughEndpoint::Middle::Close(CallbackHelper& callback_helper) {
grpc_core::MutexLock lock(&mu);
closed = true;
if (on_read != nullptr) {
callback_helper.AddCallback([on_read = std::move(on_read)]() mutable {
on_read(absl::CancelledError());
});
on_read = nullptr;
}
if (on_write != nullptr) {
callback_helper.AddCallback([on_write = std::move(on_write)]() mutable {
on_write(absl::CancelledError());
});
on_write = nullptr;
}
}
} // namespace experimental
} // namespace grpc_event_engine

@ -0,0 +1,95 @@
// 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_TEST_UTIL_PASSTHROUGH_ENDPOINT_H
#define GRPC_TEST_CORE_TEST_UTIL_PASSTHROUGH_ENDPOINT_H
#include <memory>
#include <grpc/event_engine/event_engine.h>
#include "src/core/lib/event_engine/default_event_engine.h"
#include "src/core/lib/event_engine/tcp_socket_utils.h"
#include "src/core/lib/gprpp/ref_counted.h"
namespace grpc_event_engine {
namespace experimental {
class PassthroughEndpoint final : public EventEngine::Endpoint {
public:
struct PassthroughEndpointPair {
std::unique_ptr<PassthroughEndpoint> client;
std::unique_ptr<PassthroughEndpoint> server;
};
// client_port, server_port are markers that are baked into the peer/local
// addresses for debug information.
// allow_inline_callbacks is a flag that allows the endpoint to call the
// on_read/on_write callbacks inline (but outside any PassthroughEndpoint
// locks)
static PassthroughEndpointPair MakePassthroughEndpoint(
int client_port, int server_port, bool allow_inline_callbacks);
~PassthroughEndpoint() override;
bool Read(absl::AnyInvocable<void(absl::Status)> on_read, SliceBuffer* buffer,
const ReadArgs* args) override;
bool Write(absl::AnyInvocable<void(absl::Status)> on_write,
SliceBuffer* buffer, const WriteArgs* args) override;
const EventEngine::ResolvedAddress& GetPeerAddress() const override {
return recv_middle_->address;
}
const EventEngine::ResolvedAddress& GetLocalAddress() const override {
return send_middle_->address;
}
private:
class CallbackHelper;
struct Middle : public grpc_core::RefCounted<Middle> {
explicit Middle(int port)
: address(URIToResolvedAddress(absl::StrCat("ipv4:127.0.0.1:", port))
.value()) {}
void Close(CallbackHelper& callback_helper);
grpc_core::Mutex mu;
bool closed ABSL_GUARDED_BY(mu) = false;
SliceBuffer* read_buffer ABSL_GUARDED_BY(mu) = nullptr;
absl::AnyInvocable<void(absl::Status)> on_read ABSL_GUARDED_BY(mu) =
nullptr;
SliceBuffer* write_buffer ABSL_GUARDED_BY(mu) = nullptr;
absl::AnyInvocable<void(absl::Status)> on_write ABSL_GUARDED_BY(mu) =
nullptr;
EventEngine::ResolvedAddress address;
};
PassthroughEndpoint(grpc_core::RefCountedPtr<Middle> send_middle,
grpc_core::RefCountedPtr<Middle> recv_middle,
bool allow_inline_callbacks)
: send_middle_(std::move(send_middle)),
recv_middle_(std::move(recv_middle)),
allow_inline_callbacks_(allow_inline_callbacks) {}
grpc_core::RefCountedPtr<Middle> send_middle_;
grpc_core::RefCountedPtr<Middle> recv_middle_;
std::shared_ptr<EventEngine> event_engine_ = GetDefaultEventEngine();
bool allow_inline_callbacks_;
};
} // namespace experimental
} // namespace grpc_event_engine
#endif // GRPC_TEST_CORE_TEST_UTIL_PASSTHROUGH_ENDPOINT_H

@ -0,0 +1,48 @@
# Copyright 2021 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.
load("//bazel:grpc_build_system.bzl", "grpc_package")
load("//test/cpp/microbenchmarks:grpc_benchmark_config.bzl", "grpc_cc_benchmark")
licenses(["notice"])
grpc_package(
name = "test/core/transport/benchmarks",
)
grpc_cc_benchmark(
name = "bm_chaotic_good",
srcs = ["bm_chaotic_good.cc"],
deps = [
"//:grpc",
"//src/core:chaotic_good_client_transport",
"//src/core:chaotic_good_server_transport",
"//src/core:default_event_engine",
"//test/core/test_util:passthrough_endpoint",
"//test/core/transport:call_spine_benchmarks",
],
)
grpc_cc_benchmark(
name = "bm_inproc",
srcs = ["bm_inproc.cc"],
deps = [
"//:grpc",
"//src/core:chaotic_good_client_transport",
"//src/core:chaotic_good_server_transport",
"//src/core:default_event_engine",
"//test/core/test_util:passthrough_endpoint",
"//test/core/transport:call_spine_benchmarks",
],
)

@ -0,0 +1,93 @@
// 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/ext/transport/chaotic_good/client_transport.h"
#include "src/core/ext/transport/chaotic_good/server_transport.h"
#include "src/core/lib/address_utils/parse_address.h"
#include "test/core/test_util/passthrough_endpoint.h"
#include "test/core/transport/call_spine_benchmarks.h"
namespace grpc_core {
namespace {
const Slice kTestPath = Slice::FromExternalString("/foo/bar");
class ChaoticGoodTraits {
public:
BenchmarkTransport MakeTransport() {
auto channel_args = CoreConfiguration::Get()
.channel_args_preconditioning()
.PreconditionChannelArgs(nullptr);
auto control = grpc_event_engine::experimental::PassthroughEndpoint::
MakePassthroughEndpoint(1, 2, true);
auto data = grpc_event_engine::experimental::PassthroughEndpoint::
MakePassthroughEndpoint(3, 4, true);
auto client = MakeOrphanable<chaotic_good::ChaoticGoodClientTransport>(
PromiseEndpoint(std::move(control.client), SliceBuffer()),
PromiseEndpoint(std::move(data.client), SliceBuffer()), channel_args,
grpc_event_engine::experimental::GetDefaultEventEngine(), HPackParser(),
HPackCompressor());
auto server = MakeOrphanable<chaotic_good::ChaoticGoodServerTransport>(
channel_args, PromiseEndpoint(std::move(control.server), SliceBuffer()),
PromiseEndpoint(std::move(data.server), SliceBuffer()),
grpc_event_engine::experimental::GetDefaultEventEngine(), HPackParser(),
HPackCompressor());
return {std::move(client), std::move(server)};
}
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;
}
};
GRPC_CALL_SPINE_BENCHMARK(TransportFixture<ChaoticGoodTraits>);
} // 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;
}

@ -0,0 +1,83 @@
// 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 <memory>
#include <benchmark/benchmark.h>
#include "absl/memory/memory.h"
#include "absl/strings/string_view.h"
#include <grpc/grpc.h>
#include "src/core/ext/transport/inproc/inproc_transport.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 InprocTraits {
public:
BenchmarkTransport MakeTransport() {
auto channel_args = CoreConfiguration::Get()
.channel_args_preconditioning()
.PreconditionChannelArgs(nullptr);
auto t = MakeInProcessTransportPair(channel_args);
return {OrphanablePtr<ClientTransport>(
DownCast<ClientTransport*>(t.first.release())),
OrphanablePtr<ServerTransport>(
DownCast<ServerTransport*>(t.second.release()))};
}
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;
}
};
GRPC_CALL_SPINE_BENCHMARK(TransportFixture<InprocTraits>);
} // 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;
}

@ -27,6 +27,7 @@
#include "src/core/lib/promise/map.h"
#include "src/core/lib/resource_quota/resource_quota.h"
#include "src/core/lib/transport/call_spine.h"
#include "src/core/lib/transport/transport.h"
namespace grpc_core {
@ -361,6 +362,88 @@ class UnstartedCallDestinationFixture {
traits_->CreateCallDestination(bottom_destination_);
};
// Base class for transports
// Traits should have MakeClientInitialMetadata, MakeServerInitialMetadata,
// MakePayload, MakeServerTrailingMetadata.
// They should also have a MakeTransport returning a BenchmarkTransport.
struct BenchmarkTransport {
OrphanablePtr<ClientTransport> client;
OrphanablePtr<ServerTransport> server;
};
template <class Traits>
class TransportFixture {
public:
TransportFixture() { transport_.server->SetCallDestination(acceptor_); };
BenchmarkCall MakeCall() {
auto arena = arena_allocator_->MakeArena();
arena->SetContext<grpc_event_engine::experimental::EventEngine>(
event_engine_.get());
auto p =
MakeCallPair(traits_.MakeClientInitialMetadata(), std::move(arena));
transport_.client->StartCall(p.handler.StartCall());
auto handler = acceptor_->TakeHandler();
absl::optional<CallHandler> started_handler;
Notification started;
handler.SpawnInfallible("handler_setup", [&]() {
started_handler = handler.StartCall();
started.Notify();
return Empty{};
});
started.WaitForNotification();
CHECK(started_handler.has_value());
return {std::move(p.initiator), std::move(*started_handler)};
}
ServerMetadataHandle MakeServerInitialMetadata() {
return traits_.MakeServerInitialMetadata();
}
MessageHandle MakePayload() { return traits_.MakePayload(); }
ServerMetadataHandle MakeServerTrailingMetadata() {
return traits_.MakeServerTrailingMetadata();
}
private:
class Acceptor : public UnstartedCallDestination {
public:
void StartCall(UnstartedCallHandler handler) override {
MutexLock lock(&mu_);
handler_ = std::move(handler);
}
void Orphaned() override {}
UnstartedCallHandler TakeHandler() {
mu_.LockWhen(absl::Condition(
+[](Acceptor* dest) ABSL_EXCLUSIVE_LOCKS_REQUIRED(dest->mu_) {
return dest->handler_.has_value();
},
this));
auto h = std::move(*handler_);
handler_.reset();
mu_.Unlock();
return h;
}
absl::Mutex mu_;
absl::optional<UnstartedCallHandler> handler_ ABSL_GUARDED_BY(mu_);
};
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);
RefCountedPtr<Acceptor> acceptor_ = MakeRefCounted<Acceptor>();
BenchmarkTransport transport_ = traits_.MakeTransport();
};
} // namespace grpc_core
// Declare all relevant benchmarks for a given fixture

@ -23,6 +23,28 @@
],
"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_chaotic_good",
"platforms": [
"linux",
"posix"
],
"uses_polling": false
},
{
"args": [
"--benchmark_min_time=0.001s"
@ -111,6 +133,28 @@
],
"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_inproc",
"platforms": [
"linux",
"posix"
],
"uses_polling": false
},
{
"args": [
"--benchmark_min_time=0.001s"

Loading…
Cancel
Save