The C based gRPC (C++, Python, Ruby, Objective-C, PHP, C#) https://grpc.io/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

330 lines
9.9 KiB

/*
*
* Copyright 2015 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.
*
*/
/* Test various operations on grpc_error */
#include <memory>
#include <benchmark/benchmark.h>
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/transport/error_utils.h"
#include "test/core/util/test_config.h"
#include "test/cpp/microbenchmarks/helpers.h"
#include "test/cpp/util/test_config.h"
class ErrorHandleHolder {
public:
explicit ErrorHandleHolder(grpc_error_handle error) : error_(error) {}
~ErrorHandleHolder() { GRPC_ERROR_UNREF(error_); }
const grpc_error_handle& get() const { return error_; }
private:
grpc_error_handle error_;
};
static void BM_ErrorCreateFromStatic(benchmark::State& state) {
TrackCounters track_counters;
for (auto _ : state) {
GRPC_ERROR_UNREF(GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error"));
}
track_counters.Finish(state);
}
BENCHMARK(BM_ErrorCreateFromStatic);
static void BM_ErrorCreateFromCopied(benchmark::State& state) {
TrackCounters track_counters;
for (auto _ : state) {
GRPC_ERROR_UNREF(GRPC_ERROR_CREATE_FROM_COPIED_STRING("Error not inline"));
}
track_counters.Finish(state);
}
BENCHMARK(BM_ErrorCreateFromCopied);
static void BM_ErrorCreateAndSetStatus(benchmark::State& state) {
TrackCounters track_counters;
for (auto _ : state) {
GRPC_ERROR_UNREF(
grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error"),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_ABORTED));
}
track_counters.Finish(state);
}
BENCHMARK(BM_ErrorCreateAndSetStatus);
static void BM_ErrorCreateAndSetIntAndStr(benchmark::State& state) {
TrackCounters track_counters;
for (auto _ : state) {
GRPC_ERROR_UNREF(grpc_error_set_str(
grpc_error_set_int(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("GOAWAY received"),
GRPC_ERROR_INT_HTTP2_ERROR, (intptr_t)0),
GRPC_ERROR_STR_RAW_BYTES, "raw bytes"));
}
track_counters.Finish(state);
}
BENCHMARK(BM_ErrorCreateAndSetIntAndStr);
static void BM_ErrorCreateAndSetIntLoop(benchmark::State& state) {
TrackCounters track_counters;
grpc_error_handle error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error");
int n = 0;
for (auto _ : state) {
error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS, n++);
}
GRPC_ERROR_UNREF(error);
track_counters.Finish(state);
}
BENCHMARK(BM_ErrorCreateAndSetIntLoop);
static void BM_ErrorCreateAndSetStrLoop(benchmark::State& state) {
TrackCounters track_counters;
grpc_error_handle error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error");
const char* str = "hello";
for (auto _ : state) {
error = grpc_error_set_str(error, GRPC_ERROR_STR_GRPC_MESSAGE, str);
}
GRPC_ERROR_UNREF(error);
track_counters.Finish(state);
}
BENCHMARK(BM_ErrorCreateAndSetStrLoop);
static void BM_ErrorRefUnref(benchmark::State& state) {
TrackCounters track_counters;
grpc_error_handle error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error");
for (auto _ : state) {
GRPC_ERROR_UNREF(GRPC_ERROR_REF(error));
}
GRPC_ERROR_UNREF(error);
track_counters.Finish(state);
}
BENCHMARK(BM_ErrorRefUnref);
static void BM_ErrorUnrefNone(benchmark::State& state) {
TrackCounters track_counters;
for (auto _ : state) {
GRPC_ERROR_UNREF(GRPC_ERROR_NONE);
}
}
BENCHMARK(BM_ErrorUnrefNone);
static void BM_ErrorGetIntFromNoError(benchmark::State& state) {
TrackCounters track_counters;
for (auto _ : state) {
intptr_t value;
grpc_error_get_int(GRPC_ERROR_NONE, GRPC_ERROR_INT_GRPC_STATUS, &value);
}
track_counters.Finish(state);
}
BENCHMARK(BM_ErrorGetIntFromNoError);
static void BM_ErrorGetMissingInt(benchmark::State& state) {
TrackCounters track_counters;
ErrorHandleHolder error(grpc_error_set_int(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error"), GRPC_ERROR_INT_INDEX, 1));
for (auto _ : state) {
intptr_t value;
grpc_error_get_int(error.get(), GRPC_ERROR_INT_OFFSET, &value);
}
track_counters.Finish(state);
}
BENCHMARK(BM_ErrorGetMissingInt);
static void BM_ErrorGetPresentInt(benchmark::State& state) {
TrackCounters track_counters;
ErrorHandleHolder error(grpc_error_set_int(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error"), GRPC_ERROR_INT_OFFSET, 1));
for (auto _ : state) {
intptr_t value;
grpc_error_get_int(error.get(), GRPC_ERROR_INT_OFFSET, &value);
}
track_counters.Finish(state);
}
BENCHMARK(BM_ErrorGetPresentInt);
// Fixtures for tests: generate different kinds of errors
class ErrorNone {
public:
grpc_millis deadline() const { return deadline_; }
grpc_error_handle error() const { return GRPC_ERROR_NONE; }
private:
const grpc_millis deadline_ = GRPC_MILLIS_INF_FUTURE;
};
class ErrorCancelled {
public:
grpc_millis deadline() const { return deadline_; }
grpc_error_handle error() const { return GRPC_ERROR_CANCELLED; }
private:
const grpc_millis deadline_ = GRPC_MILLIS_INF_FUTURE;
};
class SimpleError {
public:
grpc_millis deadline() const { return deadline_; }
grpc_error_handle error() const { return error_.get(); }
private:
const grpc_millis deadline_ = GRPC_MILLIS_INF_FUTURE;
ErrorHandleHolder error_{GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error")};
};
class ErrorWithGrpcStatus {
public:
grpc_millis deadline() const { return deadline_; }
grpc_error_handle error() const { return error_.get(); }
private:
const grpc_millis deadline_ = GRPC_MILLIS_INF_FUTURE;
ErrorHandleHolder error_{grpc_error_set_int(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error"), GRPC_ERROR_INT_GRPC_STATUS,
GRPC_STATUS_UNIMPLEMENTED)};
};
class ErrorWithHttpError {
public:
grpc_millis deadline() const { return deadline_; }
grpc_error_handle error() const { return error_.get(); }
private:
const grpc_millis deadline_ = GRPC_MILLIS_INF_FUTURE;
ErrorHandleHolder error_{grpc_error_set_int(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error"), GRPC_ERROR_INT_HTTP2_ERROR,
GRPC_HTTP2_COMPRESSION_ERROR)};
};
class ErrorWithNestedGrpcStatus {
public:
grpc_millis deadline() const { return deadline_; }
grpc_error_handle error() const { return error_.get(); }
private:
const grpc_millis deadline_ = GRPC_MILLIS_INF_FUTURE;
ErrorHandleHolder nested_error_{grpc_error_set_int(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error"), GRPC_ERROR_INT_GRPC_STATUS,
GRPC_STATUS_UNIMPLEMENTED)};
grpc_error_handle nested_errors_[1] = {nested_error_.get()};
ErrorHandleHolder error_{GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Error", nested_errors_, 1)};
};
template <class Fixture>
static void BM_ErrorStringOnNewError(benchmark::State& state) {
TrackCounters track_counters;
for (auto _ : state) {
Fixture fixture;
grpc_error_std_string(fixture.error());
}
track_counters.Finish(state);
}
template <class Fixture>
static void BM_ErrorStringRepeatedly(benchmark::State& state) {
TrackCounters track_counters;
Fixture fixture;
for (auto _ : state) {
grpc_error_std_string(fixture.error());
}
track_counters.Finish(state);
}
template <class Fixture>
static void BM_ErrorGetStatus(benchmark::State& state) {
TrackCounters track_counters;
Fixture fixture;
grpc_core::ExecCtx exec_ctx;
for (auto _ : state) {
grpc_status_code status;
std::string message;
grpc_error_get_status(fixture.error(), fixture.deadline(), &status,
&message, nullptr, nullptr);
}
track_counters.Finish(state);
}
template <class Fixture>
static void BM_ErrorGetStatusCode(benchmark::State& state) {
TrackCounters track_counters;
Fixture fixture;
grpc_core::ExecCtx exec_ctx;
for (auto _ : state) {
grpc_status_code status;
grpc_error_get_status(fixture.error(), fixture.deadline(), &status, nullptr,
nullptr, nullptr);
}
track_counters.Finish(state);
}
template <class Fixture>
static void BM_ErrorHttpError(benchmark::State& state) {
TrackCounters track_counters;
Fixture fixture;
grpc_core::ExecCtx exec_ctx;
for (auto _ : state) {
grpc_http2_error_code error;
grpc_error_get_status(fixture.error(), fixture.deadline(), nullptr, nullptr,
&error, nullptr);
}
track_counters.Finish(state);
}
template <class Fixture>
static void BM_HasClearGrpcStatus(benchmark::State& state) {
TrackCounters track_counters;
Fixture fixture;
for (auto _ : state) {
grpc_error_has_clear_grpc_status(fixture.error());
}
track_counters.Finish(state);
}
#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);
// 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) {
grpc::testing::TestEnvironment env(argc, argv);
LibraryInitializer libInit;
::benchmark::Initialize(&argc, argv);
::grpc::testing::InitTest(&argc, &argv, false);
benchmark::RunTheBenchmarksNamespaced();
return 0;
}