[libc++] Optimize internal function in <system_error>
In the event the internal function __init is called with an empty string the code will take unnecessary extra steps, in addition, the code generated might be overall greater because, to my understanding, when initializing a string with an empty `const char*` "" (like in this case), the compiler might be unable to deduce the string is indeed empty at compile time and more code is generated. The goal of this patch is to make a new internal function that will accept just an error code skipping the empty string argument. It should skip the unnecessary steps and in the event `if (ec)` is `false`, it will return an empty string using the correct ctor, avoiding any extra code generation issues. After the conversation about this patch matured in the libcxx channel on the LLVM Discord server, the patch was analyzed quickly with "Compiler Explorer" and other tools and it was discovered that it does indeed reduce the amount of code generated when using the latest stable clang version (16) which in turn produces faster code. This patch targets LLVM 18 as it will break the ABI by addressing https://github.com/llvm/llvm-project/issues/63985 Benchmark tests run on other machines as well show in the best case, that the new version without the extra string as an argument performs 10 times faster. On the buildkite CI run it shows the new code takes less CPU time as well. In conclusion, the new code should also just appear cleaner because there are fewer checks to do when there is no message. Reviewed By: #libc, philnik Spies: emaste, nemanjai, philnik, libcxx-commits Differential Revision: https://reviews.llvm.org/D155820
This commit is contained in:
parent
e789bcbb96
commit
66bb6b4fda
@ -192,6 +192,7 @@ set(BENCHMARK_TESTS
|
||||
std_format_spec_string_unicode.bench.cpp
|
||||
string.bench.cpp
|
||||
stringstream.bench.cpp
|
||||
system_error.bench.cpp
|
||||
to_chars.bench.cpp
|
||||
unordered_set_operations.bench.cpp
|
||||
util_smartptr.bench.cpp
|
||||
|
30
libcxx/benchmarks/system_error.bench.cpp
Normal file
30
libcxx/benchmarks/system_error.bench.cpp
Normal file
@ -0,0 +1,30 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
|
||||
#include "benchmark/benchmark.h"
|
||||
|
||||
static void BM_SystemErrorWithMessage(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
std::error_code ec{};
|
||||
benchmark::DoNotOptimize(std::system_error{ec, ""});
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_SystemErrorWithMessage);
|
||||
|
||||
static void BM_SystemErrorWithoutMessage(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
std::error_code ec{};
|
||||
benchmark::DoNotOptimize(std::system_error{ec});
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_SystemErrorWithoutMessage);
|
||||
|
||||
BENCHMARK_MAIN();
|
@ -74,6 +74,8 @@ LLVM 18
|
||||
ABI Affecting Changes
|
||||
---------------------
|
||||
|
||||
- The symbol of a non-visible function part of ``std::system_error`` was removed.
|
||||
This is not a breaking change as the private function ``__init`` was never referenced internally outside of the dylib
|
||||
|
||||
Build System Changes
|
||||
--------------------
|
||||
|
@ -36,9 +36,6 @@ public:
|
||||
~system_error() _NOEXCEPT override;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI const error_code& code() const _NOEXCEPT { return __ec_; }
|
||||
|
||||
private:
|
||||
static string __init(const error_code&, string);
|
||||
};
|
||||
|
||||
_LIBCPP_NORETURN _LIBCPP_EXPORTED_FROM_ABI void __throw_system_error(int __ev, const char* __what_arg);
|
||||
|
@ -12,6 +12,25 @@ To generate a summary, re-generate the new ABI list using the
|
||||
|
||||
New entries should be added directly below the "Version" header.
|
||||
|
||||
------------
|
||||
Version 18.0
|
||||
------------
|
||||
|
||||
* [libc++] Remove symbol for std::system_error from the dylib
|
||||
|
||||
This patch removes a symbol defined in the library for std::system_error.
|
||||
The symbol '__init' was defined as a private static function as part of the
|
||||
system_error class and was never visible. The addition of this symbol to the ABI was most likely accidental.
|
||||
The function '__init' is replaced by another equivalent function which is placed in the
|
||||
anonymous namespace of the std::system_error source code file.
|
||||
There are no internal references to this symbol which seems to support the reasoning that
|
||||
this was never used outside of the dylib.
|
||||
The deletion of the symbol should not be a breaking change.
|
||||
|
||||
All platforms
|
||||
-------------
|
||||
Symbol removed: _ZNSt3__112system_error6__initERKNS_10error_codeENS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE
|
||||
|
||||
------------
|
||||
Version 17.0
|
||||
------------
|
||||
|
@ -1062,7 +1062,6 @@
|
||||
{'is_defined': True, 'name': '__ZNSt3__112strstreambufD0Ev', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '__ZNSt3__112strstreambufD1Ev', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '__ZNSt3__112strstreambufD2Ev', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '__ZNSt3__112system_error6__initERKNS_10error_codeENS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '__ZNSt3__112system_errorC1ENS_10error_codeE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '__ZNSt3__112system_errorC1ENS_10error_codeEPKc', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '__ZNSt3__112system_errorC1ENS_10error_codeERKNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE', 'type': 'FUNC'}
|
||||
|
@ -393,7 +393,6 @@
|
||||
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__112strstreambufD0Ev', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
|
||||
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__112strstreambufD1Ev', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
|
||||
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__112strstreambufD2Ev', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
|
||||
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__112system_error6__initERKNS_10error_codeENS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
|
||||
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__112system_errorC1ENS_10error_codeE', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
|
||||
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__112system_errorC1ENS_10error_codeEPKc', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
|
||||
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__112system_errorC1ENS_10error_codeERKNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
|
||||
|
@ -393,7 +393,6 @@
|
||||
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__112strstreambufD0Ev', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
|
||||
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__112strstreambufD1Ev', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
|
||||
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__112strstreambufD2Ev', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
|
||||
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__112system_error6__initERKNS_10error_codeENS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
|
||||
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__112system_errorC1ENS_10error_codeE', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
|
||||
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__112system_errorC1ENS_10error_codeEPKc', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
|
||||
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__112system_errorC1ENS_10error_codeERKNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
|
||||
|
@ -1062,7 +1062,6 @@
|
||||
{'is_defined': True, 'name': '__ZNSt3__112strstreambufD0Ev', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '__ZNSt3__112strstreambufD1Ev', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '__ZNSt3__112strstreambufD2Ev', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '__ZNSt3__112system_error6__initERKNS_10error_codeENS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '__ZNSt3__112system_errorC1ENS_10error_codeE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '__ZNSt3__112system_errorC1ENS_10error_codeEPKc', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '__ZNSt3__112system_errorC1ENS_10error_codeERKNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE', 'type': 'FUNC'}
|
||||
|
@ -757,7 +757,6 @@
|
||||
{'is_defined': True, 'name': '_ZNSt3__112strstreambufD0Ev', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__112strstreambufD1Ev', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__112strstreambufD2Ev', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__112system_error6__initERKNS_10error_codeENS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__112system_errorC1ENS_10error_codeE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__112system_errorC1ENS_10error_codeEPKc', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__112system_errorC1ENS_10error_codeERKNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE', 'type': 'FUNC'}
|
||||
|
@ -755,7 +755,6 @@
|
||||
{'is_defined': True, 'name': '_ZNSt3__112strstreambufD0Ev', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__112strstreambufD1Ev', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__112strstreambufD2Ev', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__112system_error6__initERKNS_10error_codeENS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__112system_errorC1ENS_10error_codeE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__112system_errorC1ENS_10error_codeEPKc', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__112system_errorC1ENS_10error_codeERKNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE', 'type': 'FUNC'}
|
||||
|
@ -727,7 +727,6 @@
|
||||
{'is_defined': True, 'name': '_ZNSt3__112strstreambufD0Ev', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__112strstreambufD1Ev', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__112strstreambufD2Ev', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__112system_error6__initERKNS_10error_codeENS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__112system_errorC1ENS_10error_codeE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__112system_errorC1ENS_10error_codeEPKc', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__112system_errorC1ENS_10error_codeERKNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE', 'type': 'FUNC'}
|
||||
|
@ -59,8 +59,8 @@ error_category::equivalent(const error_code& code, int condition) const noexcept
|
||||
return *this == code.category() && code.value() == condition;
|
||||
}
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_THREADS)
|
||||
namespace {
|
||||
#if !defined(_LIBCPP_HAS_NO_THREADS)
|
||||
|
||||
// GLIBC also uses 1024 as the maximum buffer size internally.
|
||||
constexpr size_t strerror_buff_size = 1024;
|
||||
@ -128,8 +128,26 @@ string do_strerror_r(int ev) {
|
||||
return string(error_message);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // !defined(_LIBCPP_HAS_NO_THREADS)
|
||||
|
||||
string make_error_str(const error_code& ec, string what_arg) {
|
||||
if (ec) {
|
||||
if (!what_arg.empty()) {
|
||||
what_arg += ": ";
|
||||
}
|
||||
what_arg += ec.message();
|
||||
}
|
||||
return what_arg;
|
||||
}
|
||||
|
||||
string make_error_str(const error_code& ec) {
|
||||
if (ec) {
|
||||
return ec.message();
|
||||
}
|
||||
return string();
|
||||
}
|
||||
} // end namespace
|
||||
#endif
|
||||
|
||||
string
|
||||
__do_message::message(int ev) const
|
||||
@ -232,50 +250,38 @@ error_code::message() const
|
||||
|
||||
// system_error
|
||||
|
||||
string
|
||||
system_error::__init(const error_code& ec, string what_arg)
|
||||
{
|
||||
if (ec)
|
||||
{
|
||||
if (!what_arg.empty())
|
||||
what_arg += ": ";
|
||||
what_arg += ec.message();
|
||||
}
|
||||
return what_arg;
|
||||
}
|
||||
|
||||
system_error::system_error(error_code ec, const string& what_arg)
|
||||
: runtime_error(__init(ec, what_arg)),
|
||||
: runtime_error(make_error_str(ec, what_arg)),
|
||||
__ec_(ec)
|
||||
{
|
||||
}
|
||||
|
||||
system_error::system_error(error_code ec, const char* what_arg)
|
||||
: runtime_error(__init(ec, what_arg)),
|
||||
: runtime_error(make_error_str(ec, what_arg)),
|
||||
__ec_(ec)
|
||||
{
|
||||
}
|
||||
|
||||
system_error::system_error(error_code ec)
|
||||
: runtime_error(__init(ec, "")),
|
||||
: runtime_error(make_error_str(ec)),
|
||||
__ec_(ec)
|
||||
{
|
||||
}
|
||||
|
||||
system_error::system_error(int ev, const error_category& ecat, const string& what_arg)
|
||||
: runtime_error(__init(error_code(ev, ecat), what_arg)),
|
||||
: runtime_error(make_error_str(error_code(ev, ecat), what_arg)),
|
||||
__ec_(error_code(ev, ecat))
|
||||
{
|
||||
}
|
||||
|
||||
system_error::system_error(int ev, const error_category& ecat, const char* what_arg)
|
||||
: runtime_error(__init(error_code(ev, ecat), what_arg)),
|
||||
: runtime_error(make_error_str(error_code(ev, ecat), what_arg)),
|
||||
__ec_(error_code(ev, ecat))
|
||||
{
|
||||
}
|
||||
|
||||
system_error::system_error(int ev, const error_category& ecat)
|
||||
: runtime_error(__init(error_code(ev, ecat), "")),
|
||||
: runtime_error(make_error_str(error_code(ev, ecat))),
|
||||
__ec_(error_code(ev, ecat))
|
||||
{
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user