diff --git a/CMakeLists.txt b/CMakeLists.txt index ca0a668f580..f2a2380f2e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -576,6 +576,9 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) 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 @@ endif (gRPC_BUILD_TESTS) 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 93486bd2e4c..0d8b9608f2e 100644 --- a/Makefile +++ b/Makefile @@ -1043,6 +1043,7 @@ auth_property_iterator_test: $(BINDIR)/$(CONFIG)/auth_property_iterator_test 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 @@ buildtests_cxx: privatelibs_cxx \ $(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 @@ buildtests_cxx: privatelibs_cxx \ $(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 @@ test_cxx: buildtests_cxx $(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 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 55f011129a5..33cd692b455 100644 --- a/build.yaml +++ b/build.yaml @@ -3016,6 +3016,25 @@ targets: - 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/test/cpp/microbenchmarks/bm_error.cc b/test/cpp/microbenchmarks/bm_error.cc new file mode 100644 index 00000000000..8a4b86f281a --- /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 + +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 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 +static void BM_ErrorStringOnNewError(benchmark::State& state) { + while (state.KeepRunning()) { + Fixture fixture; + grpc_error_string(fixture.error()); + } +} + +template +static void BM_ErrorStringRepeatedly(benchmark::State& state) { + Fixture fixture; + while (state.KeepRunning()) { + grpc_error_string(fixture.error()); + } +} + +template +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 +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 +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 +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 b65aebc97ff..3aa700388e7 100755 --- a/tools/profiling/microbenchmarks/bm2bq.py +++ b/tools/profiling/microbenchmarks/bm2bq.py @@ -104,6 +104,30 @@ bm_specs = { '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 462353cb50a..b04e4bd06fa 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -2370,6 +2370,26 @@ "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_error", + "src": [ + "test/cpp/microbenchmarks/bm_error.cc" + ], + "third_party": false, + "type": "target" + }, { "deps": [ "benchmark", diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json index c8d0f040738..103a379c5c5 100644 --- a/tools/run_tests/generated/tests.json +++ b/tools/run_tests/generated/tests.json @@ -2513,6 +2513,28 @@ "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_error", + "platforms": [ + "linux", + "mac", + "posix" + ] + }, { "args": [ "--benchmark_min_time=0" diff --git a/tools/run_tests/run_microbenchmark.py b/tools/run_tests/run_microbenchmark.py index b090847820c..c5247761ef6 100755 --- a/tools/run_tests/run_microbenchmark.py +++ b/tools/run_tests/run_microbenchmark.py @@ -199,7 +199,7 @@ argp.add_argument('-c', '--collect', 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')