/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* 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 <folly/lang/Exception.h>
#include <stdexcept>
#include <folly/Benchmark.h>
#include <folly/lang/Keep.h>
extern "C" FOLLY_KEEP int check_std_uncaught_exceptions() {
return std::uncaught_exceptions();
}
extern "C" FOLLY_KEEP int check_folly_uncaught_exceptions() {
return folly::uncaught_exceptions();
}
extern "C" FOLLY_KEEP void check_std_current_exception() {
auto eptr = std::current_exception();
folly::detail::keep_sink_nx();
}
extern "C" FOLLY_KEEP void check_folly_current_exception() {
auto eptr = folly::current_exception();
folly::detail::keep_sink_nx();
}
namespace {
template <int I>
struct Virt {
virtual ~Virt() {}
int value = I;
operator int() const { return value; }
};
using A0 = Virt<0>;
using A1 = Virt<1>;
using A2 = Virt<2>;
struct B0 : virtual A1, virtual A2 {};
struct B1 : virtual A2, virtual A0 {};
struct B2 : virtual A0, virtual A1 {};
struct C : B0, B1, B2 {};
struct D : B0, B1, B2 {};
} // namespace
extern "C" FOLLY_KEEP std::exception*
check_folly_exception_ptr_try_get_object_exact_fast(
std::exception_ptr const& ptr) {
return folly::exception_ptr_try_get_object_exact_fast<std::exception>(
ptr, folly::tag<std::logic_error, std::range_error, std::bad_cast>);
}
extern "C" FOLLY_KEEP std::exception* //
check_folly_exception_ptr_get_object_hint( //
std::exception_ptr const& ptr) {
return folly::exception_ptr_get_object_hint<std::exception>(
ptr, folly::tag<std::logic_error, std::range_error, std::bad_cast>);
}
extern "C" FOLLY_KEEP A0* //
check_folly_exception_ptr_try_get_object_exact_fast_vmi(
std::exception_ptr const& ptr) {
return folly::exception_ptr_try_get_object_exact_fast<A0>(
ptr, folly::tag<B1, C, B2>);
}
extern "C" FOLLY_KEEP A0* //
check_folly_exception_ptr_get_object_hint_vmi( //
std::exception_ptr const& ptr) {
return folly::exception_ptr_get_object_hint<A0>(ptr, folly::tag<B1, C, B2>);
}
BENCHMARK(std_uncaught_exceptions, iters) {
int s = 0;
while (iters--) {
int u = std::uncaught_exceptions();
folly::compiler_must_not_predict(u);
s ^= u;
}
folly::compiler_must_not_elide(s);
}
BENCHMARK(folly_uncaught_exceptions, iters) {
int s = 0;
while (iters--) {
int u = folly::uncaught_exceptions();
folly::compiler_must_not_predict(u);
s ^= u;
}
folly::compiler_must_not_elide(s);
}
BENCHMARK(std_current_exception_empty, iters) {
while (iters--) {
auto eptr = std::current_exception();
folly::compiler_must_not_elide(eptr);
}
}
BENCHMARK(std_current_exception_primary, iters) {
folly::BenchmarkSuspender braces;
try {
throw std::exception();
} catch (...) {
braces.dismissing([&] {
while (iters--) {
auto eptr = std::current_exception();
folly::compiler_must_not_elide(eptr);
}
});
}
}
BENCHMARK(std_current_exception_dependent, iters) {
folly::BenchmarkSuspender braces;
try {
throw std::exception();
} catch (...) {
try {
throw;
} catch (...) {
braces.dismissing([&] {
while (iters--) {
auto eptr = std::current_exception();
folly::compiler_must_not_elide(eptr);
}
});
}
}
}
BENCHMARK(folly_current_exception_empty, iters) {
while (iters--) {
auto eptr = folly::current_exception();
folly::compiler_must_not_elide(eptr);
}
}
BENCHMARK(folly_current_exception_primary, iters) {
folly::BenchmarkSuspender braces;
try {
throw std::exception();
} catch (...) {
braces.dismissing([&] {
while (iters--) {
auto eptr = folly::current_exception();
folly::compiler_must_not_elide(eptr);
}
});
}
}
BENCHMARK(folly_current_exception_dependent, iters) {
folly::BenchmarkSuspender braces;
try {
throw std::exception();
} catch (...) {
try {
throw;
} catch (...) {
braces.dismissing([&] {
while (iters--) {
auto eptr = folly::current_exception();
folly::compiler_must_not_elide(eptr);
}
});
}
}
}
BENCHMARK(get_object_fail, iters) {
folly::BenchmarkSuspender braces;
bool result = false;
auto const ptr = std::make_exception_ptr(std::range_error("foo"));
braces.dismissing([&] {
while (iters--) {
auto const match = folly::exception_ptr_get_object<std::bad_cast>(ptr);
folly::compiler_must_not_predict(match);
result = result || match;
}
});
folly::compiler_must_not_elide(result);
}
BENCHMARK(get_object_pass_0, iters) {
folly::BenchmarkSuspender braces;
bool result = false;
auto const ptr = std::make_exception_ptr(std::range_error("foo"));
braces.dismissing([&] {
while (iters--) {
auto const match = folly::exception_ptr_get_object<std::range_error>(ptr);
folly::compiler_must_not_predict(match);
result = result || match;
}
});
folly::compiler_must_not_elide(result);
}
BENCHMARK(get_object_pass_1, iters) {
folly::BenchmarkSuspender braces;
bool result = false;
auto const ptr = std::make_exception_ptr(std::range_error("foo"));
braces.dismissing([&] {
while (iters--) {
auto const match =
folly::exception_ptr_get_object<std::runtime_error>(ptr);
folly::compiler_must_not_predict(match);
result = result || match;
}
});
folly::compiler_must_not_elide(result);
}
BENCHMARK(get_object_pass_2, iters) {
folly::BenchmarkSuspender braces;
bool result = false;
auto const ptr = std::make_exception_ptr(std::range_error("foo"));
braces.dismissing([&] {
while (iters--) {
auto const match = folly::exception_ptr_get_object<std::exception>(ptr);
folly::compiler_must_not_predict(match);
result = result || match;
}
});
folly::compiler_must_not_elide(result);
}
BENCHMARK(get_object_vmi_fail, iters) {
folly::BenchmarkSuspender braces;
bool result = false;
auto const ptr = std::make_exception_ptr(C());
braces.dismissing([&] {
while (iters--) {
auto const match = folly::exception_ptr_get_object<D>(ptr);
folly::compiler_must_not_predict(match);
result = result || match;
}
});
folly::compiler_must_not_elide(result);
}
BENCHMARK(get_object_vmi_pass_0, iters) {
folly::BenchmarkSuspender braces;
bool result = false;
auto const ptr = std::make_exception_ptr(C());
braces.dismissing([&] {
while (iters--) {
auto const match = folly::exception_ptr_get_object<C>(ptr);
folly::compiler_must_not_predict(match);
result = result || match;
}
});
folly::compiler_must_not_elide(result);
}
BENCHMARK(get_object_vmi_pass_1, iters) {
folly::BenchmarkSuspender braces;
bool result = false;
auto const ptr = std::make_exception_ptr(C());
braces.dismissing([&] {
while (iters--) {
auto const match = folly::exception_ptr_get_object<B0>(ptr);
folly::compiler_must_not_predict(match);
result = result || match;
}
});
folly::compiler_must_not_elide(result);
}
BENCHMARK(get_object_vmi_pass_2, iters) {
folly::BenchmarkSuspender braces;
bool result = false;
auto const ptr = std::make_exception_ptr(C());
braces.dismissing([&] {
while (iters--) {
auto const match = folly::exception_ptr_get_object<A0>(ptr);
folly::compiler_must_not_predict(match);
result = result || match;
}
});
folly::compiler_must_not_elide(result);
}
BENCHMARK(get_object_hint_fail, iters) {
folly::BenchmarkSuspender braces;
bool result = false;
auto const ptr = std::make_exception_ptr(std::range_error("foo"));
braces.dismissing([&] {
while (iters--) {
auto const match = folly::exception_ptr_get_object_hint<std::exception>(
ptr, folly::tag<std::logic_error, std::bad_cast>);
folly::compiler_must_not_predict(match);
result = result || match;
}
});
folly::compiler_must_not_elide(result);
}
BENCHMARK(get_object_hint_pass, iters) {
folly::BenchmarkSuspender braces;
bool result = false;
auto const ptr = std::make_exception_ptr(std::range_error("foo"));
braces.dismissing([&] {
while (iters--) {
auto const match = folly::exception_ptr_get_object_hint<std::exception>(
ptr, folly::tag<std::logic_error, std::range_error, std::bad_cast>);
folly::compiler_must_not_predict(match);
result = result || match;
}
});
folly::compiler_must_not_elide(result);
}
BENCHMARK(get_object_hint_vmi_fail, iters) {
folly::BenchmarkSuspender braces;
bool result = false;
auto const ptr = std::make_exception_ptr(C());
braces.dismissing([&] {
while (iters--) {
auto const match =
folly::exception_ptr_get_object_hint<A0>(ptr, folly::tag<B1, B2>);
folly::compiler_must_not_predict(match);
result = result || match;
}
});
folly::compiler_must_not_elide(result);
}
BENCHMARK(get_object_hint_vmi_pass, iters) {
folly::BenchmarkSuspender braces;
bool result = false;
auto const ptr = std::make_exception_ptr(C());
braces.dismissing([&] {
while (iters--) {
auto const match =
folly::exception_ptr_get_object_hint<A0>(ptr, folly::tag<B1, C, B2>);
folly::compiler_must_not_predict(match);
result = result || match;
}
});
folly::compiler_must_not_elide(result);
}
BENCHMARK(try_get_object_exact_fast_fail, iters) {
folly::BenchmarkSuspender braces;
bool result = false;
auto const ptr = std::make_exception_ptr(std::range_error("foo"));
braces.dismissing([&] {
while (iters--) {
auto const match =
folly::exception_ptr_try_get_object_exact_fast<std::exception>(
ptr, folly::tag<std::logic_error, std::bad_cast>);
folly::compiler_must_not_predict(match);
result = result || match;
}
});
folly::compiler_must_not_elide(result);
}
BENCHMARK(try_get_object_exact_fast_pass, iters) {
folly::BenchmarkSuspender braces;
bool result = false;
auto const ptr = std::make_exception_ptr(std::range_error("foo"));
braces.dismissing([&] {
while (iters--) {
auto const match =
folly::exception_ptr_try_get_object_exact_fast<std::exception>(
ptr,
folly::tag<std::logic_error, std::range_error, std::bad_cast>);
folly::compiler_must_not_predict(match);
result = result || match;
}
});
folly::compiler_must_not_elide(result);
}
BENCHMARK(try_get_object_exact_fast_vmi_fail, iters) {
folly::BenchmarkSuspender braces;
bool result = false;
auto const ptr = std::make_exception_ptr(C());
braces.dismissing([&] {
while (iters--) {
auto const match = folly::exception_ptr_try_get_object_exact_fast<A0>(
ptr, folly::tag<B1, B2>);
folly::compiler_must_not_predict(match);
result = result || match;
}
});
folly::compiler_must_not_elide(result);
}
BENCHMARK(try_get_object_exact_fast_vmi_pass, iters) {
folly::BenchmarkSuspender braces;
bool result = false;
auto const ptr = std::make_exception_ptr(C());
braces.dismissing([&] {
while (iters--) {
auto const match = folly::exception_ptr_try_get_object_exact_fast<A0>(
ptr, folly::tag<B1, C, B2>);
folly::compiler_must_not_predict(match);
result = result || match;
}
});
folly::compiler_must_not_elide(result);
}
int main(int argc, char** argv) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
folly::runBenchmarks();
return 0;
}