mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-03-05 14:06:27 -05:00
util: optimizes HexStr
In my benchmark, this rewrite improves runtime 27% (g++) to 46% (clang++) for the benchmark `HexStrBench`: g++ 11.2.0 | ns/byte | byte/s | err% | ins/byte | cyc/byte | IPC | bra/byte | miss% | total | benchmark |--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:---------- | 0.94 | 1,061,381,310.36 | 0.7% | 12.00 | 3.01 | 3.990 | 1.00 | 0.0% | 0.01 | `HexStrBench` master | 0.68 | 1,465,366,544.25 | 1.7% | 6.00 | 2.16 | 2.778 | 1.00 | 0.0% | 0.01 | `HexStrBench` branch clang++ 13.0.1 | ns/byte | byte/s | err% | ins/byte | cyc/byte | IPC | bra/byte | miss% | total | benchmark |--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:---------- | 0.80 | 1,244,713,415.92 | 0.9% | 10.00 | 2.56 | 3.913 | 0.50 | 0.0% | 0.01 | `HexStrBench` master | 0.43 | 2,324,188,940.72 | 0.2% | 4.00 | 1.37 | 2.914 | 0.25 | 0.0% | 0.01 | `HexStrBench` branch Note that the idea for this change comes from denis2342 in PR 23364. This is a rewrite so no unaligned accesses occur. Also, the lookup table is now calculated at compile time, which hopefully makes the code a bit easier to review.
This commit is contained in:
parent
4e2b99f72a
commit
5e61532e72
1 changed files with 27 additions and 6 deletions
|
@ -9,6 +9,7 @@
|
|||
#include <tinyformat.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
|
@ -508,17 +509,37 @@ std::string Capitalize(std::string str)
|
|||
return str;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
using ByteAsHex = std::array<char, 2>;
|
||||
|
||||
constexpr std::array<ByteAsHex, 256> CreateByteToHexMap()
|
||||
{
|
||||
constexpr char hexmap[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
|
||||
std::array<ByteAsHex, 256> byte_to_hex{};
|
||||
for (size_t i = 0; i < byte_to_hex.size(); ++i) {
|
||||
byte_to_hex[i][0] = hexmap[i >> 4];
|
||||
byte_to_hex[i][1] = hexmap[i & 15];
|
||||
}
|
||||
return byte_to_hex;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::string HexStr(const Span<const uint8_t> s)
|
||||
{
|
||||
std::string rv(s.size() * 2, '\0');
|
||||
static constexpr char hexmap[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
|
||||
auto it = rv.begin();
|
||||
static constexpr auto byte_to_hex = CreateByteToHexMap();
|
||||
static_assert(sizeof(byte_to_hex) == 512);
|
||||
|
||||
char* it = rv.data();
|
||||
for (uint8_t v : s) {
|
||||
*it++ = hexmap[v >> 4];
|
||||
*it++ = hexmap[v & 15];
|
||||
std::memcpy(it, byte_to_hex[v].data(), 2);
|
||||
it += 2;
|
||||
}
|
||||
assert(it == rv.end());
|
||||
|
||||
assert(it == rv.data() + rv.size());
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue