mirror of https://github.com/grpc/grpc.git
Remove competetion benchmark (#28316)
parent
88a2e16586
commit
4283b7d644
4 changed files with 0 additions and 753 deletions
@ -1,51 +0,0 @@ |
||||
# 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_cc_test", "grpc_package") |
||||
load("//test/cpp/microbenchmarks:grpc_benchmark_config.bzl", "grpc_benchmark_args") |
||||
|
||||
licenses(["notice"]) |
||||
|
||||
grpc_package(name = "test/core/promise/benchmark") |
||||
|
||||
grpc_cc_test( |
||||
name = "competition", |
||||
srcs = [ |
||||
"competition.cc", |
||||
"filter_stack.cc", |
||||
"filter_stack.h", |
||||
], |
||||
args = grpc_benchmark_args(), |
||||
external_deps = [ |
||||
"benchmark", |
||||
"absl/synchronization", |
||||
], |
||||
tags = [ |
||||
"no_mac", |
||||
"no_windows", |
||||
], |
||||
uses_polling = False, |
||||
deps = [ |
||||
"//:activity", |
||||
"//:for_each", |
||||
"//:join", |
||||
"//:latch", |
||||
"//:pipe", |
||||
"//:seq", |
||||
"//:try_join", |
||||
"//:try_seq", |
||||
"//test/core/promise:test_wakeup_schedulers", |
||||
"//test/core/util:grpc_suppressions", |
||||
], |
||||
) |
@ -1,492 +0,0 @@ |
||||
// 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.
|
||||
|
||||
/* This benchmark exists to ensure that immediately-firing alarms are fast */ |
||||
|
||||
#include <benchmark/benchmark.h> |
||||
|
||||
#include "absl/synchronization/mutex.h" |
||||
|
||||
#include "src/core/lib/promise/activity.h" |
||||
#include "src/core/lib/promise/context.h" |
||||
#include "src/core/lib/promise/for_each.h" |
||||
#include "src/core/lib/promise/join.h" |
||||
#include "src/core/lib/promise/latch.h" |
||||
#include "src/core/lib/promise/pipe.h" |
||||
#include "src/core/lib/promise/seq.h" |
||||
#include "src/core/lib/promise/try_join.h" |
||||
#include "src/core/lib/promise/try_seq.h" |
||||
#include "test/core/promise/benchmark/filter_stack.h" |
||||
#include "test/core/promise/test_wakeup_schedulers.h" |
||||
|
||||
namespace filter_stack { |
||||
|
||||
Filter passthrough_filter = { |
||||
CallNextOp, NoCallData, NoCallData, NoChannelData, NoChannelData, 0, 0, |
||||
}; |
||||
|
||||
struct Interject { |
||||
Closure c; |
||||
Closure* next; |
||||
|
||||
static void Callback(void* p, absl::Status status) { |
||||
auto* i = static_cast<Interject*>(p); |
||||
i->next->Run(std::move(status)); |
||||
} |
||||
|
||||
static void Init(CallElem* elem) { |
||||
auto* i = static_cast<Interject*>(elem->call_data); |
||||
i->c.f = Callback; |
||||
i->c.p = i; |
||||
} |
||||
|
||||
static void Destroy(CallElem*) {} |
||||
|
||||
static void StartOp(CallElem* elem, Op* op) { |
||||
auto* i = static_cast<Interject*>(elem->call_data); |
||||
if (op->recv_initial_metadata) { |
||||
i->next = op->on_complete; |
||||
op->on_complete = &i->c; |
||||
} |
||||
CallNextOp(elem, op); |
||||
} |
||||
}; |
||||
|
||||
Filter interject_filter = { |
||||
Interject::StartOp, |
||||
Interject::Init, |
||||
Interject::Destroy, |
||||
NoChannelData, |
||||
NoChannelData, |
||||
sizeof(Interject), |
||||
0, |
||||
}; |
||||
|
||||
struct InterjectPipe { |
||||
Closure c_init_metadata; |
||||
Closure* next_init_metadata; |
||||
Closure c_payload; |
||||
Closure* next_payload; |
||||
Closure c_trailing_metadata; |
||||
Closure* next_trailing_metadata; |
||||
|
||||
static void CallbackInitMetadata(void* p, absl::Status status) { |
||||
auto* i = static_cast<InterjectPipe*>(p); |
||||
i->next_init_metadata->Run(std::move(status)); |
||||
} |
||||
|
||||
static void CallbackPayload(void* p, absl::Status status) { |
||||
auto* i = static_cast<InterjectPipe*>(p); |
||||
i->next_payload->Run(std::move(status)); |
||||
} |
||||
|
||||
static void CallbackTrailingMetadata(void* p, absl::Status status) { |
||||
auto* i = static_cast<InterjectPipe*>(p); |
||||
i->next_trailing_metadata->Run(std::move(status)); |
||||
} |
||||
|
||||
static void Init(CallElem* elem) { |
||||
auto* i = static_cast<InterjectPipe*>(elem->call_data); |
||||
i->c_init_metadata.f = CallbackInitMetadata; |
||||
i->c_init_metadata.p = i; |
||||
i->c_payload.f = CallbackPayload; |
||||
i->c_payload.p = i; |
||||
i->c_trailing_metadata.f = CallbackTrailingMetadata; |
||||
i->c_trailing_metadata.p = i; |
||||
} |
||||
|
||||
static void Destroy(CallElem*) {} |
||||
|
||||
static void StartOp(CallElem* elem, Op* op) { |
||||
auto* i = static_cast<InterjectPipe*>(elem->call_data); |
||||
if (op->recv_trailing_metadata) { |
||||
i->next_trailing_metadata = op->on_complete; |
||||
op->on_complete = &i->c_trailing_metadata; |
||||
} |
||||
if (op->recv_message) { |
||||
i->next_payload = op->on_complete; |
||||
op->on_complete = &i->c_payload; |
||||
} |
||||
if (op->recv_initial_metadata) { |
||||
i->next_init_metadata = op->on_complete; |
||||
op->on_complete = &i->c_init_metadata; |
||||
} |
||||
CallNextOp(elem, op); |
||||
} |
||||
}; |
||||
|
||||
Filter interject_pipe = { |
||||
InterjectPipe::StartOp, |
||||
InterjectPipe::Init, |
||||
InterjectPipe::Destroy, |
||||
NoChannelData, |
||||
NoChannelData, |
||||
sizeof(InterjectPipe), |
||||
0, |
||||
}; |
||||
|
||||
void EndOp(CallElem*, Op* op) { op->on_complete->Run(absl::OkStatus()); } |
||||
|
||||
Filter end_filter = {EndOp, NoCallData, NoCallData, NoChannelData, |
||||
NoChannelData, 0, 0}; |
||||
|
||||
static void unary(benchmark::State& state, |
||||
std::initializer_list<Filter*> filters) { |
||||
auto* channel = |
||||
MakeChannel(const_cast<Filter**>(&*filters.begin()), filters.size()); |
||||
for (auto _ : state) { |
||||
auto* call = MakeCall(channel); |
||||
Op op; |
||||
Op::Payload payload; |
||||
op.recv_initial_metadata = true; |
||||
op.recv_message = true; |
||||
op.recv_trailing_metadata = true; |
||||
op.payload = &payload; |
||||
Closure done = {call, +[](void* p, absl::Status status) { |
||||
if (!status.ok()) abort(); |
||||
FreeCall(static_cast<CallStack*>(p)); |
||||
}}; |
||||
op.on_complete = &done; |
||||
RunOp(call, &op); |
||||
} |
||||
FreeChannel(channel); |
||||
} |
||||
|
||||
static void BM_FilterStack_Passthrough3_Unary(benchmark::State& state) { |
||||
unary(state, {&passthrough_filter, &passthrough_filter, &passthrough_filter, |
||||
&end_filter}); |
||||
} |
||||
BENCHMARK(BM_FilterStack_Passthrough3_Unary); |
||||
|
||||
static void BM_FilterStack_Passthrough10_Unary(benchmark::State& state) { |
||||
unary(state, {&passthrough_filter, &passthrough_filter, &passthrough_filter, |
||||
&passthrough_filter, &passthrough_filter, &passthrough_filter, |
||||
&passthrough_filter, &passthrough_filter, &passthrough_filter, |
||||
&passthrough_filter, &end_filter}); |
||||
} |
||||
BENCHMARK(BM_FilterStack_Passthrough10_Unary); |
||||
|
||||
static void BM_FilterStack_Interject3_Unary(benchmark::State& state) { |
||||
unary(state, |
||||
{&interject_filter, &interject_filter, &interject_filter, &end_filter}); |
||||
} |
||||
BENCHMARK(BM_FilterStack_Interject3_Unary); |
||||
|
||||
static void BM_FilterStack_Interject10_Unary(benchmark::State& state) { |
||||
unary(state, {&interject_filter, &interject_filter, &interject_filter, |
||||
&interject_filter, &interject_filter, &interject_filter, |
||||
&interject_filter, &interject_filter, &interject_filter, |
||||
&interject_filter, &end_filter}); |
||||
} |
||||
BENCHMARK(BM_FilterStack_Interject10_Unary); |
||||
|
||||
static void BM_FilterStack_Interject30_Unary(benchmark::State& state) { |
||||
unary(state, {&interject_filter, &interject_filter, &interject_filter, |
||||
&interject_filter, &interject_filter, &interject_filter, |
||||
&interject_filter, &interject_filter, &interject_filter, |
||||
&interject_filter, &interject_filter, &interject_filter, |
||||
&interject_filter, &interject_filter, &interject_filter, |
||||
&interject_filter, &interject_filter, &interject_filter, |
||||
&interject_filter, &interject_filter, &interject_filter, |
||||
&interject_filter, &interject_filter, &interject_filter, |
||||
&interject_filter, &interject_filter, &interject_filter, |
||||
&interject_filter, &interject_filter, &interject_filter, |
||||
&end_filter}); |
||||
} |
||||
BENCHMARK(BM_FilterStack_Interject30_Unary); |
||||
|
||||
static void BM_FilterStack_Interject3Pipe_Unary(benchmark::State& state) { |
||||
unary(state, |
||||
{&interject_pipe, &interject_pipe, &interject_pipe, &end_filter}); |
||||
} |
||||
BENCHMARK(BM_FilterStack_Interject3Pipe_Unary); |
||||
|
||||
static void BM_FilterStack_Interject10Pipe_Unary(benchmark::State& state) { |
||||
unary(state, |
||||
{&interject_pipe, &interject_pipe, &interject_pipe, &interject_pipe, |
||||
&interject_pipe, &interject_pipe, &interject_pipe, &interject_pipe, |
||||
&interject_pipe, &interject_pipe, &end_filter}); |
||||
} |
||||
BENCHMARK(BM_FilterStack_Interject10Pipe_Unary); |
||||
|
||||
static void BM_FilterStack_Interject30Pipe_Unary(benchmark::State& state) { |
||||
unary(state, |
||||
{&interject_pipe, &interject_pipe, &interject_pipe, &interject_pipe, |
||||
&interject_pipe, &interject_pipe, &interject_pipe, &interject_pipe, |
||||
&interject_pipe, &interject_pipe, &interject_pipe, &interject_pipe, |
||||
&interject_pipe, &interject_pipe, &interject_pipe, &interject_pipe, |
||||
&interject_pipe, &interject_pipe, &interject_pipe, &interject_pipe, |
||||
&interject_pipe, &interject_pipe, &interject_pipe, &interject_pipe, |
||||
&interject_pipe, &interject_pipe, &interject_pipe, &interject_pipe, |
||||
&interject_pipe, &interject_pipe, &end_filter}); |
||||
} |
||||
BENCHMARK(BM_FilterStack_Interject30Pipe_Unary); |
||||
|
||||
} // namespace filter_stack
|
||||
|
||||
namespace grpc_core { |
||||
|
||||
namespace activity_stack { |
||||
struct RPCIO { |
||||
Latch<int> recv_initial_metadata; |
||||
}; |
||||
|
||||
struct RPCP { |
||||
Pipe<int> pipe; |
||||
}; |
||||
} // namespace activity_stack
|
||||
|
||||
template <> |
||||
struct ContextType<activity_stack::RPCIO> {}; |
||||
|
||||
template <> |
||||
struct ContextType<activity_stack::RPCP> {}; |
||||
|
||||
namespace activity_stack { |
||||
|
||||
template <typename MakeCall> |
||||
static void unary(benchmark::State& state, MakeCall make_call) { |
||||
printf("activity stack size: %d\n", static_cast<int>(make_call()->Size())); |
||||
for (auto _ : state) { |
||||
make_call(); |
||||
} |
||||
} |
||||
|
||||
static void BM_ActivityStack_Passthrough3_Unary(benchmark::State& state) { |
||||
unary(state, []() { |
||||
return MakeActivity( |
||||
[]() { |
||||
auto one = []() { return absl::OkStatus(); }; |
||||
return TrySeq(one, one, one); |
||||
}, |
||||
NoWakeupScheduler(), |
||||
[](absl::Status status) { |
||||
if (!status.ok()) abort(); |
||||
}); |
||||
}); |
||||
} |
||||
BENCHMARK(BM_ActivityStack_Passthrough3_Unary); |
||||
|
||||
static void BM_ActivityStack_Passthrough10_Unary(benchmark::State& state) { |
||||
unary(state, []() { |
||||
return MakeActivity( |
||||
[]() { |
||||
auto one = []() { return absl::OkStatus(); }; |
||||
return TrySeq(one, one, one, one, one, one, one, one, one, one); |
||||
}, |
||||
NoWakeupScheduler(), |
||||
[](absl::Status status) { |
||||
if (!status.ok()) abort(); |
||||
}); |
||||
}); |
||||
} |
||||
BENCHMARK(BM_ActivityStack_Passthrough10_Unary); |
||||
|
||||
static void BM_ActivityStack_Interject3Latches_Unary(benchmark::State& state) { |
||||
unary(state, []() { |
||||
RPCIO rpcio; |
||||
return MakeActivity( |
||||
[]() { |
||||
auto one = []() { |
||||
return GetContext<RPCIO>()->recv_initial_metadata.Wait(); |
||||
}; |
||||
return Seq(Join(one(), one(), one(), |
||||
[]() { |
||||
GetContext<RPCIO>()->recv_initial_metadata.Set(42); |
||||
return true; |
||||
}), |
||||
[]() { return absl::OkStatus(); }); |
||||
}, |
||||
NoWakeupScheduler(), |
||||
[](absl::Status status) { |
||||
if (!status.ok()) abort(); |
||||
}, |
||||
std::move(rpcio)); |
||||
}); |
||||
} |
||||
BENCHMARK(BM_ActivityStack_Interject3Latches_Unary); |
||||
|
||||
static void BM_ActivityStack_Interject10Latches_Unary(benchmark::State& state) { |
||||
unary(state, []() { |
||||
RPCIO rpcio; |
||||
return MakeActivity( |
||||
[]() { |
||||
auto one = []() { |
||||
return GetContext<RPCIO>()->recv_initial_metadata.Wait(); |
||||
}; |
||||
return Seq(Join(one(), one(), one(), one(), one(), one(), one(), |
||||
one(), one(), one(), |
||||
[]() { |
||||
GetContext<RPCIO>()->recv_initial_metadata.Set(42); |
||||
return true; |
||||
}), |
||||
[]() { return absl::OkStatus(); }); |
||||
}, |
||||
NoWakeupScheduler(), |
||||
[](absl::Status status) { |
||||
if (!status.ok()) abort(); |
||||
}, |
||||
std::move(rpcio)); |
||||
}); |
||||
} |
||||
BENCHMARK(BM_ActivityStack_Interject10Latches_Unary); |
||||
|
||||
static void BM_ActivityStack_Interject30Latches_Unary(benchmark::State& state) { |
||||
unary(state, []() { |
||||
RPCIO rpcio; |
||||
return MakeActivity( |
||||
[]() { |
||||
auto one = []() { |
||||
return GetContext<RPCIO>()->recv_initial_metadata.Wait(); |
||||
}; |
||||
return Seq( |
||||
Join(one(), one(), one(), one(), one(), one(), one(), one(), |
||||
one(), one(), one(), one(), one(), one(), one(), one(), |
||||
one(), one(), one(), one(), one(), one(), one(), one(), |
||||
one(), one(), one(), one(), one(), one(), |
||||
[]() { |
||||
GetContext<RPCIO>()->recv_initial_metadata.Set(42); |
||||
return true; |
||||
}), |
||||
[]() { return absl::OkStatus(); }); |
||||
}, |
||||
NoWakeupScheduler(), |
||||
[](absl::Status status) { |
||||
if (!status.ok()) abort(); |
||||
}, |
||||
std::move(rpcio)); |
||||
}); |
||||
} |
||||
BENCHMARK(BM_ActivityStack_Interject30Latches_Unary); |
||||
|
||||
static void BM_ActivityStack_Interject3Filters_Unary(benchmark::State& state) { |
||||
unary(state, []() { |
||||
RPCP rpcio; |
||||
return MakeActivity( |
||||
[]() { |
||||
auto one = []() { |
||||
return GetContext<RPCP>()->pipe.sender.Filter( |
||||
[](int i) { return absl::StatusOr<int>(i); }); |
||||
}; |
||||
return TryJoin( |
||||
one(), one(), one(), |
||||
Seq( |
||||
GetContext<RPCP>()->pipe.sender.Push(42), |
||||
[]() { return GetContext<RPCP>()->pipe.sender.Push(43); }, |
||||
[]() { return GetContext<RPCP>()->pipe.sender.Push(44); }, |
||||
[]() { |
||||
auto x = std::move(GetContext<RPCP>()->pipe.sender); |
||||
return absl::OkStatus(); |
||||
}), |
||||
Seq( |
||||
GetContext<RPCP>()->pipe.receiver.Next(), |
||||
[]() { return GetContext<RPCP>()->pipe.receiver.Next(); }, |
||||
[]() { return GetContext<RPCP>()->pipe.receiver.Next(); }, |
||||
[]() { return absl::OkStatus(); })); |
||||
}, |
||||
NoWakeupScheduler(), |
||||
[](absl::Status status) { |
||||
if (!status.ok()) abort(); |
||||
}, |
||||
std::move(rpcio)); |
||||
}); |
||||
} |
||||
BENCHMARK(BM_ActivityStack_Interject3Filters_Unary); |
||||
|
||||
static void BM_ActivityStack_Interject10Filters_Unary(benchmark::State& state) { |
||||
unary(state, []() { |
||||
RPCP rpcio; |
||||
return MakeActivity( |
||||
[]() { |
||||
auto one = []() { |
||||
return GetContext<RPCP>()->pipe.sender.Filter( |
||||
[](int i) { return absl::StatusOr<int>(i); }); |
||||
}; |
||||
return TryJoin( |
||||
one(), one(), one(), one(), one(), one(), one(), one(), one(), |
||||
one(), |
||||
Seq( |
||||
GetContext<RPCP>()->pipe.sender.Push(42), |
||||
[]() { return GetContext<RPCP>()->pipe.sender.Push(43); }, |
||||
[]() { return GetContext<RPCP>()->pipe.sender.Push(44); }, |
||||
[]() { |
||||
auto x = std::move(GetContext<RPCP>()->pipe.sender); |
||||
return absl::OkStatus(); |
||||
}), |
||||
Seq( |
||||
GetContext<RPCP>()->pipe.receiver.Next(), |
||||
[]() { return GetContext<RPCP>()->pipe.receiver.Next(); }, |
||||
[]() { return GetContext<RPCP>()->pipe.receiver.Next(); }, |
||||
[]() { return absl::OkStatus(); })); |
||||
}, |
||||
NoWakeupScheduler(), |
||||
[](absl::Status status) { |
||||
if (!status.ok()) abort(); |
||||
}, |
||||
std::move(rpcio)); |
||||
}); |
||||
} |
||||
BENCHMARK(BM_ActivityStack_Interject10Filters_Unary); |
||||
|
||||
static void BM_ActivityStack_Interject30Filters_Unary(benchmark::State& state) { |
||||
unary(state, []() { |
||||
RPCP rpcio; |
||||
return MakeActivity( |
||||
[]() { |
||||
auto one = []() { |
||||
return GetContext<RPCP>()->pipe.sender.Filter( |
||||
[](int i) { return absl::StatusOr<int>(i); }); |
||||
}; |
||||
return TryJoin( |
||||
one(), one(), one(), one(), one(), one(), one(), one(), one(), |
||||
one(), one(), one(), one(), one(), one(), one(), one(), one(), |
||||
one(), one(), one(), one(), one(), one(), one(), one(), one(), |
||||
one(), one(), one(), |
||||
Seq( |
||||
GetContext<RPCP>()->pipe.sender.Push(42), |
||||
[]() { return GetContext<RPCP>()->pipe.sender.Push(43); }, |
||||
[]() { return GetContext<RPCP>()->pipe.sender.Push(44); }, |
||||
[]() { |
||||
auto x = std::move(GetContext<RPCP>()->pipe.sender); |
||||
return absl::OkStatus(); |
||||
}), |
||||
Seq( |
||||
GetContext<RPCP>()->pipe.receiver.Next(), |
||||
[]() { return GetContext<RPCP>()->pipe.receiver.Next(); }, |
||||
[]() { return GetContext<RPCP>()->pipe.receiver.Next(); }, |
||||
[]() { return absl::OkStatus(); })); |
||||
}, |
||||
NoWakeupScheduler(), |
||||
[](absl::Status status) { |
||||
if (!status.ok()) abort(); |
||||
}, |
||||
std::move(rpcio)); |
||||
}); |
||||
} |
||||
BENCHMARK(BM_ActivityStack_Interject30Filters_Unary); |
||||
|
||||
} // namespace activity_stack
|
||||
} // 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); |
||||
benchmark::RunTheBenchmarksNamespaced(); |
||||
return 0; |
||||
} |
@ -1,102 +0,0 @@ |
||||
// 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.
|
||||
|
||||
#include "test/core/promise/benchmark/filter_stack.h" |
||||
|
||||
namespace filter_stack { |
||||
|
||||
ChannelStack* MakeChannel(Filter** filters, size_t num_filters) { |
||||
size_t size = sizeof(ChannelStack) + num_filters * sizeof(ChannelElem); |
||||
size_t call_size = sizeof(CallStack) + num_filters * sizeof(CallElem); |
||||
for (size_t i = 0; i < num_filters; i++) { |
||||
size += filters[i]->sizeof_channel_data; |
||||
call_size += filters[i]->sizeof_call_data; |
||||
} |
||||
char* data = new char[size]; |
||||
ChannelStack* stk = reinterpret_cast<ChannelStack*>(data); |
||||
new (data) ChannelStack{0, num_filters, call_size}; |
||||
data += sizeof(ChannelStack); |
||||
char* user_data = data + num_filters * sizeof(ChannelElem); |
||||
for (size_t i = 0; i < num_filters; i++) { |
||||
new (data) ChannelElem{filters[i], user_data}; |
||||
filters[i]->init_channel_data(reinterpret_cast<ChannelElem*>(data)); |
||||
data += sizeof(ChannelElem); |
||||
user_data += filters[i]->sizeof_channel_data; |
||||
} |
||||
printf("CALL STACK SIZE: %d\n", static_cast<int>(call_size)); |
||||
return stk; |
||||
} |
||||
|
||||
void FreeChannel(ChannelStack* stk) { |
||||
ChannelElem* elems = reinterpret_cast<ChannelElem*>(stk + 1); |
||||
for (size_t i = 0; i < stk->num_elems; i++) { |
||||
elems[i].filter->destroy_channel_data(&elems[i]); |
||||
} |
||||
stk->~ChannelStack(); |
||||
delete[] reinterpret_cast<char*>(stk); |
||||
} |
||||
|
||||
CallStack* MakeCall(ChannelStack* stk) { |
||||
char* data = new char[stk->call_stack_size]; |
||||
CallStack* call = reinterpret_cast<CallStack*>(data); |
||||
new (data) CallStack{{1}, stk->num_elems, {}}; |
||||
data += sizeof(CallStack); |
||||
ChannelElem* channel_elems = reinterpret_cast<ChannelElem*>(stk + 1); |
||||
char* user_data = data + stk->num_elems * sizeof(CallElem); |
||||
for (size_t i = 0; i < stk->num_elems; i++) { |
||||
new (data) CallElem{channel_elems[i].filter, channel_elems[i].channel_data, |
||||
user_data}; |
||||
channel_elems[i].filter->init_call_data(reinterpret_cast<CallElem*>(data)); |
||||
data += sizeof(CallElem); |
||||
user_data += channel_elems[i].filter->sizeof_call_data; |
||||
} |
||||
return call; |
||||
} |
||||
|
||||
static void RefCall(CallStack* stk) { |
||||
stk->refcount.fetch_add(1, std::memory_order_relaxed); |
||||
} |
||||
|
||||
static void UnrefCall(CallStack* stk) { |
||||
if (stk->refcount.fetch_sub(1, std::memory_order_acq_rel) == 1) { |
||||
CallElem* elems = reinterpret_cast<CallElem*>(stk + 1); |
||||
for (size_t i = 0; i < stk->num_elems; i++) { |
||||
elems[i].filter->destroy_call_data(&elems[i]); |
||||
} |
||||
stk->~CallStack(); |
||||
delete[] reinterpret_cast<char*>(stk); |
||||
} |
||||
} |
||||
|
||||
void FreeCall(CallStack* stk) { UnrefCall(stk); } |
||||
|
||||
void NoChannelData(ChannelElem*) {} |
||||
void NoCallData(CallElem*) {} |
||||
|
||||
static void StartOp(CallElem* elem, Op* op) { |
||||
elem->filter->start_transport_stream_op_batch(elem, op); |
||||
} |
||||
|
||||
void CallNextOp(CallElem* elem, Op* op) { StartOp(elem + 1, op); } |
||||
|
||||
void RunOp(CallStack* stk, Op* op) { |
||||
RefCall(stk); |
||||
{ |
||||
absl::MutexLock lock(&stk->mutex); |
||||
StartOp(reinterpret_cast<CallElem*>(stk + 1), op); |
||||
} |
||||
UnrefCall(stk); |
||||
} |
||||
|
||||
} // namespace filter_stack
|
@ -1,108 +0,0 @@ |
||||
// 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.
|
||||
|
||||
#ifndef FILTER_STACK_H |
||||
#define FILTER_STACK_H |
||||
|
||||
#include "absl/status/status.h" |
||||
#include "absl/synchronization/mutex.h" |
||||
|
||||
namespace filter_stack { |
||||
|
||||
struct Filter; |
||||
|
||||
struct ChannelStack { |
||||
uint64_t refcount; |
||||
size_t num_elems; |
||||
size_t call_stack_size; |
||||
}; |
||||
|
||||
struct CallStack { |
||||
std::atomic<size_t> refcount; |
||||
size_t num_elems; |
||||
absl::Mutex mutex; |
||||
}; |
||||
|
||||
struct ChannelElem { |
||||
Filter* filter; |
||||
void* channel_data; |
||||
}; |
||||
|
||||
struct CallElem { |
||||
Filter* filter; |
||||
void* channel_data; |
||||
void* call_data; |
||||
}; |
||||
|
||||
struct Closure { |
||||
void* p; |
||||
void (*f)(void* p, absl::Status); |
||||
void Run(absl::Status status) { f(p, std::move(status)); } |
||||
}; |
||||
|
||||
struct Op { |
||||
struct Payload {}; |
||||
|
||||
Op() |
||||
: send_initial_metadata(false), |
||||
send_trailing_metadata(false), |
||||
send_message(false), |
||||
recv_initial_metadata(false), |
||||
recv_message(false), |
||||
recv_trailing_metadata(false), |
||||
cancel_stream(false), |
||||
is_traced(false) {} |
||||
|
||||
Op(const Op&) = delete; |
||||
Op& operator=(const Op&) = delete; |
||||
|
||||
Payload* payload = nullptr; |
||||
|
||||
Closure* on_complete = nullptr; |
||||
|
||||
bool send_initial_metadata : 1; |
||||
bool send_trailing_metadata : 1; |
||||
bool send_message : 1; |
||||
bool recv_initial_metadata : 1; |
||||
bool recv_message : 1; |
||||
bool recv_trailing_metadata : 1; |
||||
bool cancel_stream : 1; |
||||
bool is_traced : 1; |
||||
}; |
||||
|
||||
struct Filter { |
||||
void (*start_transport_stream_op_batch)(CallElem* elem, Op* op); |
||||
void (*init_call_data)(CallElem* elem); |
||||
void (*destroy_call_data)(CallElem* elem); |
||||
void (*init_channel_data)(ChannelElem* elem); |
||||
void (*destroy_channel_data)(ChannelElem* elem); |
||||
size_t sizeof_call_data; |
||||
size_t sizeof_channel_data; |
||||
}; |
||||
|
||||
ChannelStack* MakeChannel(Filter** filters, size_t num_filters); |
||||
void FreeChannel(ChannelStack* stk); |
||||
CallStack* MakeCall(ChannelStack* stk); |
||||
void FreeCall(CallStack* stk); |
||||
|
||||
void NoChannelData(ChannelElem*); |
||||
void NoCallData(CallElem*); |
||||
|
||||
void CallNextOp(CallElem* elem, Op* op); |
||||
|
||||
void RunOp(CallStack* stk, Op* op); |
||||
|
||||
} // namespace filter_stack
|
||||
|
||||
#endif |
Loading…
Reference in new issue