Merge pull request #9851 from matt-kwong/internal-ci-adjustments
Reduce running time of internally run fuzzers
diff --git a/.pylintrc b/.pylintrc
index 1682488..da2081b 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -30,6 +30,5 @@
#TODO: Enable too-many-nested-blocks
#TODO: Enable super-init-not-called
#TODO: Enable no-self-use
-#TODO: Enable no-member
-disable=missing-docstring,too-few-public-methods,too-many-arguments,no-init,duplicate-code,invalid-name,suppressed-message,locally-disabled,protected-access,no-name-in-module,unused-argument,fixme,wrong-import-order,no-value-for-parameter,cyclic-import,unused-variable,redefined-outer-name,unused-import,too-many-instance-attributes,broad-except,too-many-locals,too-many-lines,redefined-variable-type,next-method-called,import-error,useless-else-on-loop,too-many-return-statements,too-many-nested-blocks,super-init-not-called,no-self-use,no-member
+disable=missing-docstring,too-few-public-methods,too-many-arguments,no-init,duplicate-code,invalid-name,suppressed-message,locally-disabled,protected-access,no-name-in-module,unused-argument,fixme,wrong-import-order,no-value-for-parameter,cyclic-import,unused-variable,redefined-outer-name,unused-import,too-many-instance-attributes,broad-except,too-many-locals,too-many-lines,redefined-variable-type,next-method-called,import-error,useless-else-on-loop,too-many-return-statements,too-many-nested-blocks,super-init-not-called,no-self-use
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ca0a668..f2a2380 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -576,6 +576,9 @@
add_dependencies(buildtests_cxx bm_cq)
endif()
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
+add_dependencies(buildtests_cxx bm_error)
+endif()
+if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_cxx bm_fullstack)
endif()
add_dependencies(buildtests_cxx channel_arguments_test)
@@ -7475,6 +7478,44 @@
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
+add_executable(bm_error
+ test/cpp/microbenchmarks/bm_error.cc
+ third_party/googletest/src/gtest-all.cc
+)
+
+
+target_include_directories(bm_error
+ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+ PRIVATE ${BORINGSSL_ROOT_DIR}/include
+ PRIVATE ${PROTOBUF_ROOT_DIR}/src
+ PRIVATE ${BENCHMARK_ROOT_DIR}/include
+ PRIVATE ${ZLIB_ROOT_DIR}
+ PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
+ PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
+ PRIVATE third_party/googletest/include
+ PRIVATE third_party/googletest
+ PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(bm_error
+ ${_gRPC_PROTOBUF_LIBRARIES}
+ ${_gRPC_ALLTARGETS_LIBRARIES}
+ benchmark
+ grpc++_test_util
+ grpc_test_util
+ grpc++
+ grpc
+ gpr_test_util
+ gpr
+ ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+endif()
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
+
add_executable(bm_fullstack
test/cpp/microbenchmarks/bm_fullstack.cc
third_party/googletest/src/gtest-all.cc
diff --git a/Makefile b/Makefile
index 93486bd..0d8b960 100644
--- a/Makefile
+++ b/Makefile
@@ -1043,6 +1043,7 @@
bm_call_create: $(BINDIR)/$(CONFIG)/bm_call_create
bm_closure: $(BINDIR)/$(CONFIG)/bm_closure
bm_cq: $(BINDIR)/$(CONFIG)/bm_cq
+bm_error: $(BINDIR)/$(CONFIG)/bm_error
bm_fullstack: $(BINDIR)/$(CONFIG)/bm_fullstack
channel_arguments_test: $(BINDIR)/$(CONFIG)/channel_arguments_test
channel_filter_test: $(BINDIR)/$(CONFIG)/channel_filter_test
@@ -1450,6 +1451,7 @@
$(BINDIR)/$(CONFIG)/bm_call_create \
$(BINDIR)/$(CONFIG)/bm_closure \
$(BINDIR)/$(CONFIG)/bm_cq \
+ $(BINDIR)/$(CONFIG)/bm_error \
$(BINDIR)/$(CONFIG)/bm_fullstack \
$(BINDIR)/$(CONFIG)/channel_arguments_test \
$(BINDIR)/$(CONFIG)/channel_filter_test \
@@ -1558,6 +1560,7 @@
$(BINDIR)/$(CONFIG)/bm_call_create \
$(BINDIR)/$(CONFIG)/bm_closure \
$(BINDIR)/$(CONFIG)/bm_cq \
+ $(BINDIR)/$(CONFIG)/bm_error \
$(BINDIR)/$(CONFIG)/bm_fullstack \
$(BINDIR)/$(CONFIG)/channel_arguments_test \
$(BINDIR)/$(CONFIG)/channel_filter_test \
@@ -1880,6 +1883,8 @@
$(Q) $(BINDIR)/$(CONFIG)/bm_closure || ( echo test bm_closure failed ; exit 1 )
$(E) "[RUN] Testing bm_cq"
$(Q) $(BINDIR)/$(CONFIG)/bm_cq || ( echo test bm_cq failed ; exit 1 )
+ $(E) "[RUN] Testing bm_error"
+ $(Q) $(BINDIR)/$(CONFIG)/bm_error || ( echo test bm_error failed ; exit 1 )
$(E) "[RUN] Testing bm_fullstack"
$(Q) $(BINDIR)/$(CONFIG)/bm_fullstack || ( echo test bm_fullstack failed ; exit 1 )
$(E) "[RUN] Testing channel_arguments_test"
@@ -12426,6 +12431,49 @@
endif
+BM_ERROR_SRC = \
+ test/cpp/microbenchmarks/bm_error.cc \
+
+BM_ERROR_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(BM_ERROR_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/bm_error: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/bm_error: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/bm_error: $(PROTOBUF_DEP) $(BM_ERROR_OBJS) $(LIBDIR)/$(CONFIG)/libbenchmark.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+ $(E) "[LD] Linking $@"
+ $(Q) mkdir -p `dirname $@`
+ $(Q) $(LDXX) $(LDFLAGS) $(BM_ERROR_OBJS) $(LIBDIR)/$(CONFIG)/libbenchmark.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/bm_error
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/cpp/microbenchmarks/bm_error.o: $(LIBDIR)/$(CONFIG)/libbenchmark.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_bm_error: $(BM_ERROR_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(BM_ERROR_OBJS:.o=.dep)
+endif
+endif
+
+
BM_FULLSTACK_SRC = \
test/cpp/microbenchmarks/bm_fullstack.cc \
diff --git a/build.yaml b/build.yaml
index 55f0111..33cd692 100644
--- a/build.yaml
+++ b/build.yaml
@@ -3016,6 +3016,25 @@
- mac
- linux
- posix
+- name: bm_error
+ build: test
+ language: c++
+ src:
+ - test/cpp/microbenchmarks/bm_error.cc
+ deps:
+ - benchmark
+ - grpc++_test_util
+ - grpc_test_util
+ - grpc++
+ - grpc
+ - gpr_test_util
+ - gpr
+ args:
+ - --benchmark_min_time=0
+ platforms:
+ - mac
+ - linux
+ - posix
- name: bm_fullstack
build: test
language: c++
diff --git a/src/core/lib/surface/call.c b/src/core/lib/surface/call.c
index 0fae3ef..3c563bc 100644
--- a/src/core/lib/surface/call.c
+++ b/src/core/lib/surface/call.c
@@ -153,8 +153,6 @@
bool destroy_called;
/** flag indicating that cancellation is inherited */
bool cancellation_is_inherited;
- /** bitmask of live batches */
- uint8_t used_batches;
/** which ops are in-flight */
bool sent_initial_metadata;
bool sending_message;
@@ -1012,25 +1010,48 @@
return !(flags & invalid_positions);
}
-static batch_control *allocate_batch_control(grpc_call *call) {
- size_t i;
- for (i = 0; i < MAX_CONCURRENT_BATCHES; i++) {
- if ((call->used_batches & (1 << i)) == 0) {
- call->used_batches = (uint8_t)(call->used_batches | (uint8_t)(1 << i));
- return &call->active_batches[i];
- }
+static int batch_slot_for_op(grpc_op_type type) {
+ switch (type) {
+ case GRPC_OP_SEND_INITIAL_METADATA:
+ return 0;
+ case GRPC_OP_SEND_MESSAGE:
+ return 1;
+ case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
+ case GRPC_OP_SEND_STATUS_FROM_SERVER:
+ return 2;
+ case GRPC_OP_RECV_INITIAL_METADATA:
+ return 3;
+ case GRPC_OP_RECV_MESSAGE:
+ return 4;
+ case GRPC_OP_RECV_CLOSE_ON_SERVER:
+ case GRPC_OP_RECV_STATUS_ON_CLIENT:
+ return 5;
}
- return NULL;
+ GPR_UNREACHABLE_CODE(return 123456789);
+}
+
+static batch_control *allocate_batch_control(grpc_call *call,
+ const grpc_op *ops,
+ size_t num_ops) {
+ int slot = batch_slot_for_op(ops[0].op);
+ for (size_t i = 1; i < num_ops; i++) {
+ int op_slot = batch_slot_for_op(ops[i].op);
+ slot = GPR_MIN(slot, op_slot);
+ }
+ batch_control *bctl = &call->active_batches[slot];
+ if (bctl->call != NULL) {
+ return NULL;
+ }
+ memset(bctl, 0, sizeof(*bctl));
+ bctl->call = call;
+ return bctl;
}
static void finish_batch_completion(grpc_exec_ctx *exec_ctx, void *user_data,
grpc_cq_completion *storage) {
batch_control *bctl = user_data;
grpc_call *call = bctl->call;
- gpr_mu_lock(&call->mu);
- call->used_batches = (uint8_t)(
- call->used_batches & ~(uint8_t)(1 << (bctl - call->active_batches)));
- gpr_mu_unlock(&call->mu);
+ bctl->call = NULL;
GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, "completion");
}
@@ -1113,12 +1134,8 @@
if (bctl->is_notify_tag_closure) {
/* unrefs bctl->error */
+ bctl->call = NULL;
grpc_closure_run(exec_ctx, bctl->notify_tag, error);
- gpr_mu_lock(&call->mu);
- bctl->call->used_batches =
- (uint8_t)(bctl->call->used_batches &
- ~(uint8_t)(1 << (bctl - bctl->call->active_batches)));
- gpr_mu_unlock(&call->mu);
GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, "completion");
} else {
/* unrefs bctl->error */
@@ -1330,6 +1347,11 @@
finish_batch_step(exec_ctx, bctl);
}
+static void free_no_op_completion(grpc_exec_ctx *exec_ctx, void *p,
+ grpc_cq_completion *completion) {
+ gpr_free(completion);
+}
+
static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
grpc_call *call, const grpc_op *ops,
size_t nops, void *notify_tag,
@@ -1344,32 +1366,34 @@
grpc_metadata compression_md;
GPR_TIMER_BEGIN("grpc_call_start_batch", 0);
-
GRPC_CALL_LOG_BATCH(GPR_INFO, call, ops, nops, notify_tag);
- /* TODO(ctiller): this feels like it could be made lock-free */
- gpr_mu_lock(&call->mu);
- bctl = allocate_batch_control(call);
- memset(bctl, 0, sizeof(*bctl));
- bctl->call = call;
- bctl->notify_tag = notify_tag;
- bctl->is_notify_tag_closure = (uint8_t)(is_notify_tag_closure != 0);
-
- grpc_transport_stream_op *stream_op = &bctl->op;
- memset(stream_op, 0, sizeof(*stream_op));
- stream_op->covered_by_poller = true;
-
if (nops == 0) {
- GRPC_CALL_INTERNAL_REF(call, "completion");
if (!is_notify_tag_closure) {
grpc_cq_begin_op(call->cq, notify_tag);
+ grpc_cq_end_op(exec_ctx, call->cq, notify_tag, GRPC_ERROR_NONE,
+ free_no_op_completion, NULL,
+ gpr_malloc(sizeof(grpc_cq_completion)));
+ } else {
+ grpc_closure_sched(exec_ctx, notify_tag, GRPC_ERROR_NONE);
}
- gpr_mu_unlock(&call->mu);
- post_batch_completion(exec_ctx, bctl);
error = GRPC_CALL_OK;
goto done;
}
+ /* TODO(ctiller): this feels like it could be made lock-free */
+ bctl = allocate_batch_control(call, ops, nops);
+ if (bctl == NULL) {
+ return GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
+ }
+ bctl->notify_tag = notify_tag;
+ bctl->is_notify_tag_closure = (uint8_t)(is_notify_tag_closure != 0);
+
+ gpr_mu_lock(&call->mu);
+ grpc_transport_stream_op *stream_op = &bctl->op;
+ memset(stream_op, 0, sizeof(*stream_op));
+ stream_op->covered_by_poller = true;
+
/* rewrite batch ops into a transport op */
for (i = 0; i < nops; i++) {
op = &ops[i];
diff --git a/src/python/grpcio/grpc/_channel.py b/src/python/grpcio/grpc/_channel.py
index 26d93fa..e602f39 100644
--- a/src/python/grpcio/grpc/_channel.py
+++ b/src/python/grpcio/grpc/_channel.py
@@ -43,7 +43,6 @@
_EMPTY_FLAGS = 0
_INFINITE_FUTURE = cygrpc.Timespec(float('+inf'))
-_EMPTY_METADATA = cygrpc.Metadata(())
_UNARY_UNARY_INITIAL_DUE = (cygrpc.OperationType.send_initial_metadata,
cygrpc.OperationType.send_message,
@@ -138,8 +137,8 @@
state.code = code
state.details = details
if state.initial_metadata is None:
- state.initial_metadata = _EMPTY_METADATA
- state.trailing_metadata = _EMPTY_METADATA
+ state.initial_metadata = _common.EMPTY_METADATA
+ state.trailing_metadata = _common.EMPTY_METADATA
def _handle_event(event, state, response_deserializer):
@@ -435,7 +434,7 @@
deadline, deadline_timespec = _deadline(timeout)
serialized_request = _common.serialize(request, request_serializer)
if serialized_request is None:
- state = _RPCState((), _EMPTY_METADATA, _EMPTY_METADATA,
+ state = _RPCState((), _common.EMPTY_METADATA, _common.EMPTY_METADATA,
grpc.StatusCode.INTERNAL,
'Exception serializing request!')
rendezvous = _Rendezvous(state, None, None, deadline)
diff --git a/src/python/grpcio/grpc/_common.py b/src/python/grpcio/grpc/_common.py
index f9accd7..6879e17 100644
--- a/src/python/grpcio/grpc/_common.py
+++ b/src/python/grpcio/grpc/_common.py
@@ -37,7 +37,7 @@
import grpc
from grpc._cython import cygrpc
-_EMPTY_METADATA = cygrpc.Metadata(())
+EMPTY_METADATA = cygrpc.Metadata(())
CYGRPC_CONNECTIVITY_STATE_TO_CHANNEL_CONNECTIVITY = {
cygrpc.ConnectivityState.idle:
@@ -107,7 +107,7 @@
def cygrpc_metadata(application_metadata):
- return _EMPTY_METADATA if application_metadata is None else cygrpc.Metadata(
+ return EMPTY_METADATA if application_metadata is None else cygrpc.Metadata(
cygrpc.Metadatum(encode(key), encode(value))
for key, value in application_metadata)
diff --git a/src/python/grpcio/grpc/_server.py b/src/python/grpcio/grpc/_server.py
index bf2743c..b8e7ea1 100644
--- a/src/python/grpcio/grpc/_server.py
+++ b/src/python/grpcio/grpc/_server.py
@@ -57,7 +57,6 @@
_CANCELLED = 'cancelled'
_EMPTY_FLAGS = 0
-_EMPTY_METADATA = cygrpc.Metadata(())
_UNEXPECTED_EXIT_SERVER_GRACE = 1.0
@@ -143,7 +142,7 @@
effective_details = details if state.details is None else state.details
if state.initial_metadata_allowed:
operations = (cygrpc.operation_send_initial_metadata(
- _EMPTY_METADATA, _EMPTY_FLAGS),
+ _common.EMPTY_METADATA, _EMPTY_FLAGS),
cygrpc.operation_send_status_from_server(
_common.cygrpc_metadata(state.trailing_metadata),
effective_code, effective_details, _EMPTY_FLAGS),)
@@ -416,7 +415,7 @@
else:
if state.initial_metadata_allowed:
operations = (cygrpc.operation_send_initial_metadata(
- _EMPTY_METADATA, _EMPTY_FLAGS),
+ _common.EMPTY_METADATA, _EMPTY_FLAGS),
cygrpc.operation_send_message(serialized_response,
_EMPTY_FLAGS),)
state.initial_metadata_allowed = False
@@ -446,8 +445,8 @@
]
if state.initial_metadata_allowed:
operations.append(
- cygrpc.operation_send_initial_metadata(_EMPTY_METADATA,
- _EMPTY_FLAGS))
+ cygrpc.operation_send_initial_metadata(
+ _common.EMPTY_METADATA, _EMPTY_FLAGS))
if serialized_response is not None:
operations.append(
cygrpc.operation_send_message(serialized_response,
@@ -549,12 +548,12 @@
def _handle_unrecognized_method(rpc_event):
- operations = (
- cygrpc.operation_send_initial_metadata(_EMPTY_METADATA, _EMPTY_FLAGS),
- cygrpc.operation_receive_close_on_server(_EMPTY_FLAGS),
- cygrpc.operation_send_status_from_server(
- _EMPTY_METADATA, cygrpc.StatusCode.unimplemented,
- b'Method not found!', _EMPTY_FLAGS),)
+ operations = (cygrpc.operation_send_initial_metadata(_common.EMPTY_METADATA,
+ _EMPTY_FLAGS),
+ cygrpc.operation_receive_close_on_server(_EMPTY_FLAGS),
+ cygrpc.operation_send_status_from_server(
+ _common.EMPTY_METADATA, cygrpc.StatusCode.unimplemented,
+ b'Method not found!', _EMPTY_FLAGS),)
rpc_state = _RPCState()
rpc_event.operation_call.start_server_batch(
operations, lambda ignored_event: (rpc_state, (),))
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-5171071900712960 b/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-5171071900712960
new file mode 100644
index 0000000..70ca3a3
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-5171071900712960
Binary files differ
diff --git a/test/cpp/microbenchmarks/bm_error.cc b/test/cpp/microbenchmarks/bm_error.cc
new file mode 100644
index 0000000..8a4b86f
--- /dev/null
+++ b/test/cpp/microbenchmarks/bm_error.cc
@@ -0,0 +1,248 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* Test various operations on grpc_error */
+
+#include <memory>
+
+extern "C" {
+#include "src/core/lib/iomgr/error.h"
+#include "src/core/lib/transport/error_utils.h"
+}
+
+#include "third_party/benchmark/include/benchmark/benchmark.h"
+
+class ErrorDeleter {
+ public:
+ void operator()(grpc_error* error) { GRPC_ERROR_UNREF(error); }
+};
+typedef std::unique_ptr<grpc_error, ErrorDeleter> ErrorPtr;
+
+static void BM_ErrorCreate(benchmark::State& state) {
+ while (state.KeepRunning()) {
+ GRPC_ERROR_UNREF(GRPC_ERROR_CREATE("Error"));
+ }
+}
+BENCHMARK(BM_ErrorCreate);
+
+static void BM_ErrorCreateAndSetStatus(benchmark::State& state) {
+ while (state.KeepRunning()) {
+ GRPC_ERROR_UNREF(grpc_error_set_int(GRPC_ERROR_CREATE("Error"),
+ GRPC_ERROR_INT_GRPC_STATUS,
+ GRPC_STATUS_ABORTED));
+ }
+}
+BENCHMARK(BM_ErrorCreateAndSetStatus);
+
+static void BM_ErrorRefUnref(benchmark::State& state) {
+ grpc_error* error = GRPC_ERROR_CREATE("Error");
+ while (state.KeepRunning()) {
+ GRPC_ERROR_UNREF(GRPC_ERROR_REF(error));
+ }
+ GRPC_ERROR_UNREF(error);
+}
+BENCHMARK(BM_ErrorRefUnref);
+
+static void BM_ErrorUnrefNone(benchmark::State& state) {
+ while (state.KeepRunning()) {
+ GRPC_ERROR_UNREF(GRPC_ERROR_NONE);
+ }
+}
+BENCHMARK(BM_ErrorUnrefNone);
+
+static void BM_ErrorGetIntFromNoError(benchmark::State& state) {
+ while (state.KeepRunning()) {
+ intptr_t value;
+ grpc_error_get_int(GRPC_ERROR_NONE, GRPC_ERROR_INT_GRPC_STATUS, &value);
+ }
+}
+BENCHMARK(BM_ErrorGetIntFromNoError);
+
+static void BM_ErrorGetMissingInt(benchmark::State& state) {
+ ErrorPtr error(
+ grpc_error_set_int(GRPC_ERROR_CREATE("Error"), GRPC_ERROR_INT_INDEX, 1));
+ while (state.KeepRunning()) {
+ intptr_t value;
+ grpc_error_get_int(error.get(), GRPC_ERROR_INT_OFFSET, &value);
+ }
+}
+BENCHMARK(BM_ErrorGetMissingInt);
+
+static void BM_ErrorGetPresentInt(benchmark::State& state) {
+ ErrorPtr error(
+ grpc_error_set_int(GRPC_ERROR_CREATE("Error"), GRPC_ERROR_INT_OFFSET, 1));
+ while (state.KeepRunning()) {
+ intptr_t value;
+ grpc_error_get_int(error.get(), GRPC_ERROR_INT_OFFSET, &value);
+ }
+}
+BENCHMARK(BM_ErrorGetPresentInt);
+
+// Fixtures for tests: generate different kinds of errors
+class ErrorNone {
+ public:
+ gpr_timespec deadline() const { return deadline_; }
+ grpc_error* error() const { return GRPC_ERROR_NONE; }
+
+ private:
+ const gpr_timespec deadline_ = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+};
+
+class ErrorCancelled {
+ public:
+ gpr_timespec deadline() const { return deadline_; }
+ grpc_error* error() const { return GRPC_ERROR_CANCELLED; }
+
+ private:
+ const gpr_timespec deadline_ = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+};
+
+class SimpleError {
+ public:
+ gpr_timespec deadline() const { return deadline_; }
+ grpc_error* error() const { return error_.get(); }
+
+ private:
+ const gpr_timespec deadline_ = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+ ErrorPtr error_{GRPC_ERROR_CREATE("Error")};
+};
+
+class ErrorWithGrpcStatus {
+ public:
+ gpr_timespec deadline() const { return deadline_; }
+ grpc_error* error() const { return error_.get(); }
+
+ private:
+ const gpr_timespec deadline_ = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+ ErrorPtr error_{grpc_error_set_int(GRPC_ERROR_CREATE("Error"),
+ GRPC_ERROR_INT_GRPC_STATUS,
+ GRPC_STATUS_UNIMPLEMENTED)};
+};
+
+class ErrorWithHttpError {
+ public:
+ gpr_timespec deadline() const { return deadline_; }
+ grpc_error* error() const { return error_.get(); }
+
+ private:
+ const gpr_timespec deadline_ = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+ ErrorPtr error_{grpc_error_set_int(GRPC_ERROR_CREATE("Error"),
+ GRPC_ERROR_INT_HTTP2_ERROR,
+ GRPC_HTTP2_COMPRESSION_ERROR)};
+};
+
+class ErrorWithNestedGrpcStatus {
+ public:
+ gpr_timespec deadline() const { return deadline_; }
+ grpc_error* error() const { return error_.get(); }
+
+ private:
+ const gpr_timespec deadline_ = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+ ErrorPtr nested_error_{grpc_error_set_int(GRPC_ERROR_CREATE("Error"),
+ GRPC_ERROR_INT_GRPC_STATUS,
+ GRPC_STATUS_UNIMPLEMENTED)};
+ grpc_error* nested_errors_[1] = {nested_error_.get()};
+ ErrorPtr error_{GRPC_ERROR_CREATE_REFERENCING("Error", nested_errors_, 1)};
+};
+
+template <class Fixture>
+static void BM_ErrorStringOnNewError(benchmark::State& state) {
+ while (state.KeepRunning()) {
+ Fixture fixture;
+ grpc_error_string(fixture.error());
+ }
+}
+
+template <class Fixture>
+static void BM_ErrorStringRepeatedly(benchmark::State& state) {
+ Fixture fixture;
+ while (state.KeepRunning()) {
+ grpc_error_string(fixture.error());
+ }
+}
+
+template <class Fixture>
+static void BM_ErrorGetStatus(benchmark::State& state) {
+ Fixture fixture;
+ while (state.KeepRunning()) {
+ grpc_status_code status;
+ const char* msg;
+ grpc_error_get_status(fixture.error(), fixture.deadline(), &status, &msg,
+ NULL);
+ }
+}
+
+template <class Fixture>
+static void BM_ErrorGetStatusCode(benchmark::State& state) {
+ Fixture fixture;
+ while (state.KeepRunning()) {
+ grpc_status_code status;
+ grpc_error_get_status(fixture.error(), fixture.deadline(), &status, NULL,
+ NULL);
+ }
+}
+
+template <class Fixture>
+static void BM_ErrorHttpError(benchmark::State& state) {
+ Fixture fixture;
+ while (state.KeepRunning()) {
+ grpc_http2_error_code error;
+ grpc_error_get_status(fixture.error(), fixture.deadline(), NULL, NULL,
+ &error);
+ }
+}
+
+template <class Fixture>
+static void BM_HasClearGrpcStatus(benchmark::State& state) {
+ Fixture fixture;
+ while (state.KeepRunning()) {
+ grpc_error_has_clear_grpc_status(fixture.error());
+ }
+}
+
+#define BENCHMARK_SUITE(fixture) \
+ BENCHMARK_TEMPLATE(BM_ErrorStringOnNewError, fixture); \
+ BENCHMARK_TEMPLATE(BM_ErrorStringRepeatedly, fixture); \
+ BENCHMARK_TEMPLATE(BM_ErrorGetStatus, fixture); \
+ BENCHMARK_TEMPLATE(BM_ErrorGetStatusCode, fixture); \
+ BENCHMARK_TEMPLATE(BM_ErrorHttpError, fixture); \
+ BENCHMARK_TEMPLATE(BM_HasClearGrpcStatus, fixture)
+
+BENCHMARK_SUITE(ErrorNone);
+BENCHMARK_SUITE(ErrorCancelled);
+BENCHMARK_SUITE(SimpleError);
+BENCHMARK_SUITE(ErrorWithGrpcStatus);
+BENCHMARK_SUITE(ErrorWithHttpError);
+BENCHMARK_SUITE(ErrorWithNestedGrpcStatus);
+
+BENCHMARK_MAIN();
diff --git a/tools/profiling/microbenchmarks/bm2bq.py b/tools/profiling/microbenchmarks/bm2bq.py
index b65aebc..3aa7003 100755
--- a/tools/profiling/microbenchmarks/bm2bq.py
+++ b/tools/profiling/microbenchmarks/bm2bq.py
@@ -104,6 +104,30 @@
'tpl': [],
'dyn': ['request_size', 'bandwidth_kilobits'],
},
+ 'BM_ErrorStringOnNewError': {
+ 'tpl': ['fixture'],
+ 'dyn': [],
+ },
+ 'BM_ErrorStringRepeatedly': {
+ 'tpl': ['fixture'],
+ 'dyn': [],
+ },
+ 'BM_ErrorGetStatus': {
+ 'tpl': ['fixture'],
+ 'dyn': [],
+ },
+ 'BM_ErrorGetStatusCode': {
+ 'tpl': ['fixture'],
+ 'dyn': [],
+ },
+ 'BM_ErrorHttpError': {
+ 'tpl': ['fixture'],
+ 'dyn': [],
+ },
+ 'BM_HasClearGrpcStatus': {
+ 'tpl': ['fixture'],
+ 'dyn': [],
+ },
'BM_IsolatedFilter' : {
'tpl': ['fixture', 'client_mutator'],
'dyn': [],
diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json
index 462353c..b04e4bd 100644
--- a/tools/run_tests/generated/sources_and_headers.json
+++ b/tools/run_tests/generated/sources_and_headers.json
@@ -2383,6 +2383,26 @@
"headers": [],
"is_filegroup": false,
"language": "c++",
+ "name": "bm_error",
+ "src": [
+ "test/cpp/microbenchmarks/bm_error.cc"
+ ],
+ "third_party": false,
+ "type": "target"
+ },
+ {
+ "deps": [
+ "benchmark",
+ "gpr",
+ "gpr_test_util",
+ "grpc",
+ "grpc++",
+ "grpc++_test_util",
+ "grpc_test_util"
+ ],
+ "headers": [],
+ "is_filegroup": false,
+ "language": "c++",
"name": "bm_fullstack",
"src": [
"test/cpp/microbenchmarks/bm_fullstack.cc"
diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json
index facc1c36..103a379 100644
--- a/tools/run_tests/generated/tests.json
+++ b/tools/run_tests/generated/tests.json
@@ -2528,6 +2528,28 @@
"flaky": false,
"gtest": false,
"language": "c++",
+ "name": "bm_error",
+ "platforms": [
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
+ "--benchmark_min_time=0"
+ ],
+ "ci_platforms": [
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "gtest": false,
+ "language": "c++",
"name": "bm_fullstack",
"platforms": [
"linux",
@@ -79705,6 +79727,28 @@
},
{
"args": [
+ "test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-5171071900712960"
+ ],
+ "ci_platforms": [
+ "linux"
+ ],
+ "cpu_cost": 0.1,
+ "exclude_configs": [
+ "tsan"
+ ],
+ "exclude_iomgrs": [
+ "uv"
+ ],
+ "flaky": false,
+ "language": "c",
+ "name": "api_fuzzer_one_entry",
+ "platforms": [
+ "linux"
+ ],
+ "uses_polling": false
+ },
+ {
+ "args": [
"test/core/end2end/fuzzers/api_fuzzer_corpus/crash-0597bbdd657fa4ed14443994c9147a1a7bbc205f"
],
"ci_platforms": [
diff --git a/tools/run_tests/run_microbenchmark.py b/tools/run_tests/run_microbenchmark.py
index b090847..c524776 100755
--- a/tools/run_tests/run_microbenchmark.py
+++ b/tools/run_tests/run_microbenchmark.py
@@ -199,7 +199,7 @@
default=sorted(collectors.keys()),
help='Which collectors should be run against each benchmark')
argp.add_argument('-b', '--benchmarks',
- default=['bm_fullstack', 'bm_closure', 'bm_cq', 'bm_call_create'],
+ default=['bm_fullstack', 'bm_closure', 'bm_cq', 'bm_call_create', 'bm_error'],
nargs='+',
type=str,
help='Which microbenchmarks should be run')