Skip to content

Commit 472365f

Browse files
goldvitalycopybara-github
authored andcommitted
Remove the salt parameter from low level hash and use a global constant. That may potentially remove some loads.
Also remove `LowLevelHashImpl` since it is adding an indirection to save the passing Seed() argument that is likely already in the register. ``` name old CYCLES/op new CYCLES/op delta BM_latency_AbslHash_Int32 16.1 ± 2% 16.0 ± 3% ~ (p=0.249 n=49+55) BM_latency_AbslHash_Int64 16.5 ± 3% 16.5 ± 3% ~ (p=0.862 n=51+50) BM_latency_AbslHash_String3 22.6 ± 0% 22.6 ± 1% +0.11% (p=0.012 n=54+55) BM_latency_AbslHash_String5 22.9 ±10% 22.9 ± 8% ~ (p=0.566 n=57+56) BM_latency_AbslHash_String9 22.9 ±14% 23.2 ±13% ~ (p=0.640 n=56+57) BM_latency_AbslHash_String17 21.9 ±10% 21.9 ± 7% ~ (p=0.409 n=52+55) BM_latency_AbslHash_String33 23.6 ± 4% 23.4 ± 5% ~ (p=0.098 n=53+55) BM_latency_AbslHash_String65 34.0 ±11% 32.5 ± 8% -4.41% (p=0.000 n=56+56) BM_latency_AbslHash_String257 53.0 ± 7% 52.3 ± 8% -1.31% (p=0.037 n=53+50) ``` PiperOrigin-RevId: 758656004 Change-Id: I9e828cde7d181da813aa8228b73d208ba7dc9042
1 parent bf98162 commit 472365f

File tree

5 files changed

+67
-76
lines changed

5 files changed

+67
-76
lines changed

absl/hash/internal/hash.cc

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
#include "absl/base/attributes.h"
2222
#include "absl/base/config.h"
23-
#include "absl/hash/internal/low_level_hash.h"
23+
#include "absl/hash/internal/city.h"
2424

2525
namespace absl {
2626
ABSL_NAMESPACE_BEGIN
@@ -55,11 +55,6 @@ uint64_t MixingHashState::CombineLargeContiguousImpl64(
5555

5656
ABSL_CONST_INIT const void* const MixingHashState::kSeed = &kSeed;
5757

58-
uint64_t MixingHashState::LowLevelHashImpl(const unsigned char* data,
59-
size_t len) {
60-
return LowLevelHashLenGt32(data, len, Seed(), &kStaticRandomData[0]);
61-
}
62-
6358
} // namespace hash_internal
6459
ABSL_NAMESPACE_END
6560
} // namespace absl

absl/hash/internal/hash.h

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
#include "absl/base/port.h"
8181
#include "absl/container/fixed_array.h"
8282
#include "absl/hash/internal/city.h"
83+
#include "absl/hash/internal/low_level_hash.h"
8384
#include "absl/hash/internal/weakly_mixed_integer.h"
8485
#include "absl/meta/type_traits.h"
8586
#include "absl/numeric/bits.h"
@@ -1074,13 +1075,6 @@ class ABSL_DLL MixingHashState : public HashStateBase<MixingHashState> {
10741075
using uint128 = absl::uint128;
10751076
#endif // ABSL_HAVE_INTRINSIC_INT128
10761077

1077-
// Random data taken from the hexadecimal digits of Pi's fractional component.
1078-
// https://en.wikipedia.org/wiki/Nothing-up-my-sleeve_number
1079-
ABSL_CACHELINE_ALIGNED static constexpr uint64_t kStaticRandomData[] = {
1080-
0x243f'6a88'85a3'08d3, 0x1319'8a2e'0370'7344, 0xa409'3822'299f'31d0,
1081-
0x082e'fa98'ec4e'6c89, 0x4528'21e6'38d0'1377,
1082-
};
1083-
10841078
static constexpr uint64_t kMul =
10851079
uint64_t{0xdcb22ca68cb134ed};
10861080

@@ -1329,16 +1323,13 @@ class ABSL_DLL MixingHashState : public HashStateBase<MixingHashState> {
13291323
return absl::gbswap_64(n * kMul);
13301324
}
13311325

1332-
// An extern to avoid bloat on a direct call to LowLevelHash() with fixed
1333-
// values for both the seed and salt parameters.
1334-
static uint64_t LowLevelHashImpl(const unsigned char* data, size_t len);
1335-
13361326
ABSL_ATTRIBUTE_ALWAYS_INLINE static uint64_t Hash64(const unsigned char* data,
13371327
size_t len) {
13381328
#ifdef ABSL_HAVE_INTRINSIC_INT128
1339-
return LowLevelHashImpl(data, len);
1329+
return LowLevelHashLenGt32(data, len, Seed());
13401330
#else
1341-
return hash_internal::CityHash64(reinterpret_cast<const char*>(data), len);
1331+
return hash_internal::CityHash64WithSeed(
1332+
reinterpret_cast<const char*>(data), len, Seed());
13421333
#endif
13431334
}
13441335

@@ -1378,12 +1369,13 @@ class ABSL_DLL MixingHashState : public HashStateBase<MixingHashState> {
13781369
inline uint64_t MixingHashState::CombineContiguousImpl(
13791370
uint64_t state, const unsigned char* first, size_t len,
13801371
std::integral_constant<int, 4> /* sizeof_size_t */) {
1381-
// For large values we use CityHash, for small ones we just use a
1382-
// multiplicative hash.
1372+
// For large values we use CityHash, for small ones we use custom low latency
1373+
// hash.
13831374
if (len <= 8) {
13841375
return CombineSmallContiguousImpl(state, first, len);
13851376
}
13861377
if (ABSL_PREDICT_TRUE(len <= PiecewiseChunkSize())) {
1378+
// TODO(b/417141985): expose and use CityHash32WithSeed.
13871379
return Mix(state ^ hash_internal::CityHash32(
13881380
reinterpret_cast<const char*>(first), len),
13891381
kMul);
@@ -1396,7 +1388,7 @@ inline uint64_t MixingHashState::CombineContiguousImpl(
13961388
uint64_t state, const unsigned char* first, size_t len,
13971389
std::integral_constant<int, 8> /* sizeof_size_t */) {
13981390
// For large values we use LowLevelHash or CityHash depending on the platform,
1399-
// for small ones we just use a multiplicative hash.
1391+
// for small ones we use custom low latency hash.
14001392
if (len <= 8) {
14011393
return CombineSmallContiguousImpl(state, first, len);
14021394
}

absl/hash/internal/low_level_hash.cc

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,29 +28,30 @@ namespace absl {
2828
ABSL_NAMESPACE_BEGIN
2929
namespace hash_internal {
3030
namespace {
31+
3132
uint64_t Mix(uint64_t v0, uint64_t v1) {
3233
absl::uint128 p = v0;
3334
p *= v1;
3435
return absl::Uint128Low64(p) ^ absl::Uint128High64(p);
3536
}
36-
uint64_t Mix32Bytes(const uint8_t* ptr, uint64_t current_state,
37-
const uint64_t salt[5]) {
37+
38+
uint64_t Mix32Bytes(const uint8_t* ptr, uint64_t current_state) {
3839
uint64_t a = absl::base_internal::UnalignedLoad64(ptr);
3940
uint64_t b = absl::base_internal::UnalignedLoad64(ptr + 8);
4041
uint64_t c = absl::base_internal::UnalignedLoad64(ptr + 16);
4142
uint64_t d = absl::base_internal::UnalignedLoad64(ptr + 24);
4243

43-
uint64_t cs0 = Mix(a ^ salt[1], b ^ current_state);
44-
uint64_t cs1 = Mix(c ^ salt[2], d ^ current_state);
44+
uint64_t cs0 = Mix(a ^ kStaticRandomData[1], b ^ current_state);
45+
uint64_t cs1 = Mix(c ^ kStaticRandomData[2], d ^ current_state);
4546
return cs0 ^ cs1;
4647
}
48+
4749
} // namespace
4850

49-
uint64_t LowLevelHashLenGt32(const void* data, size_t len, uint64_t seed,
50-
const uint64_t salt[5]) {
51+
uint64_t LowLevelHashLenGt32(const void* data, size_t len, uint64_t seed) {
5152
assert(len > 32);
5253
const uint8_t* ptr = static_cast<const uint8_t*>(data);
53-
uint64_t current_state = seed ^ salt[0] ^ len;
54+
uint64_t current_state = seed ^ kStaticRandomData[0] ^ len;
5455
const uint8_t* last_32_ptr = ptr + len - 32;
5556

5657
if (len > 64) {
@@ -74,11 +75,11 @@ uint64_t LowLevelHashLenGt32(const void* data, size_t len, uint64_t seed,
7475
uint64_t g = absl::base_internal::UnalignedLoad64(ptr + 48);
7576
uint64_t h = absl::base_internal::UnalignedLoad64(ptr + 56);
7677

77-
current_state = Mix(a ^ salt[1], b ^ current_state);
78-
duplicated_state0 = Mix(c ^ salt[2], d ^ duplicated_state0);
78+
current_state = Mix(a ^ kStaticRandomData[1], b ^ current_state);
79+
duplicated_state0 = Mix(c ^ kStaticRandomData[2], d ^ duplicated_state0);
7980

80-
duplicated_state1 = Mix(e ^ salt[3], f ^ duplicated_state1);
81-
duplicated_state2 = Mix(g ^ salt[4], h ^ duplicated_state2);
81+
duplicated_state1 = Mix(e ^ kStaticRandomData[3], f ^ duplicated_state1);
82+
duplicated_state2 = Mix(g ^ kStaticRandomData[4], h ^ duplicated_state2);
8283

8384
ptr += 64;
8485
len -= 64;
@@ -91,13 +92,13 @@ uint64_t LowLevelHashLenGt32(const void* data, size_t len, uint64_t seed,
9192
// We now have a data `ptr` with at most 64 bytes and the current state
9293
// of the hashing state machine stored in current_state.
9394
if (len > 32) {
94-
current_state = Mix32Bytes(ptr, current_state, salt);
95+
current_state = Mix32Bytes(ptr, current_state);
9596
}
9697

9798
// We now have a data `ptr` with at most 32 bytes and the current state
9899
// of the hashing state machine stored in current_state. But we can
99100
// safely read from `ptr + len - 32`.
100-
return Mix32Bytes(last_32_ptr, current_state, salt);
101+
return Mix32Bytes(last_32_ptr, current_state);
101102
}
102103

103104
} // namespace hash_internal

absl/hash/internal/low_level_hash.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,19 +29,26 @@
2929
#include <stdlib.h>
3030

3131
#include "absl/base/config.h"
32+
#include "absl/base/optimization.h"
3233

3334
namespace absl {
3435
ABSL_NAMESPACE_BEGIN
3536
namespace hash_internal {
3637

38+
// Random data taken from the hexadecimal digits of Pi's fractional component.
39+
// https://en.wikipedia.org/wiki/Nothing-up-my-sleeve_number
40+
ABSL_CACHELINE_ALIGNED static constexpr uint64_t kStaticRandomData[] = {
41+
0x243f'6a88'85a3'08d3, 0x1319'8a2e'0370'7344, 0xa409'3822'299f'31d0,
42+
0x082e'fa98'ec4e'6c89, 0x4528'21e6'38d0'1377,
43+
};
44+
3745
// Hash function for a byte array. A 64-bit seed and a set of five 64-bit
3846
// integers are hashed into the result. The length must be greater than 32.
3947
//
4048
// To allow all hashable types (including string_view and Span) to depend on
4149
// this algorithm, we keep the API low-level, with as few dependencies as
4250
// possible.
43-
uint64_t LowLevelHashLenGt32(const void* data, size_t len, uint64_t seed,
44-
const uint64_t salt[5]);
51+
uint64_t LowLevelHashLenGt32(const void* data, size_t len, uint64_t seed);
4552

4653
} // namespace hash_internal
4754
ABSL_NAMESPACE_END

absl/hash/internal/low_level_hash_test.cc

Lines changed: 35 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
#include "absl/hash/internal/low_level_hash.h"
1616

17-
#include <cinttypes>
17+
#include <cstddef>
1818
#include <cstdint>
1919

2020
#include "gmock/gmock.h"
@@ -25,10 +25,6 @@
2525

2626
namespace {
2727

28-
static const uint64_t kSalt[5] = {0xa0761d6478bd642f, 0xe7037ed1a0b428dbl,
29-
0x8ebc6af09c88c6e3, 0x589965cc75374cc3l,
30-
0x1d8e4e27c47d124f};
31-
3228
TEST(LowLevelHashTest, VerifyGolden) {
3329
constexpr size_t kNumGoldenOutputs = 94;
3430
static struct {
@@ -366,38 +362,38 @@ TEST(LowLevelHashTest, VerifyGolden) {
366362
GTEST_SKIP() << "We only maintain golden data for little endian systems.";
367363
#else
368364
constexpr uint64_t kGolden[kNumGoldenOutputs] = {
369-
0x59b1542b0ff6b7b8, 0x3fb979d297096db9, 0xb391802c536343a9,
370-
0x94e0f7e4331081c4, 0x234d95e49e3ce30e, 0xca6351a3e568ed17,
371-
0xa62fcf7fa334293d, 0xb03111035f546067, 0x97b8c861e013d558,
372-
0xb6683803d9387949, 0xce5d907e0b3cb6a1, 0xab7466fae53ed201,
373-
0x8f13ca3f1cac3edd, 0xa2684a99cd909a2a, 0x03194f86b9440843,
374-
0xab3a745d96f75a66, 0xef2448606760ec3d, 0xd999e03247d5d5c5,
375-
0x4a25ab345d53f926, 0xa511b829ce9fc919, 0x4b76517f8e806cbf,
376-
0x006efd7ee09ff8d4, 0x790a4978bd0170a1, 0xc14f6e4b2dff057e,
377-
0xe0d2f4ae7c836d09, 0x4e2038a491ed939d, 0x23fd6f408e9598e0,
378-
0xa91cf8f1d92bcb08, 0x555cdec06df49d58, 0xe7d3e14bd6a8f3bd,
379-
0x4fdd25c1e75c009a, 0x3dffb8acf1ffbd17, 0x56946f33ed73a705,
380-
0x154c633d7690f3b0, 0x3e96f8e9a58a04e0, 0xb0279b244d3ccf9c,
381-
0x8571e87c882b2142, 0x9d9ada45132e7b41, 0xd5667655533f1dec,
382-
0x70607ace4ec36463, 0x691418d2eb63116c, 0xa70179d8e7142980,
383-
0xf8388d756bea25a7, 0xe5127c736d9826de, 0x7f1c95f9b6b656b6,
384-
0x66ab835b7bf4c7b3, 0xc03423b9a6db9728, 0xe88415a2b416b76d,
385-
0x8afd8c14d0b56c36, 0xe9a252b3ba217dad, 0x710150f5cd87a9ff,
386-
0xd66b147837fad9ae, 0x1af5f8ffbaa717a7, 0xe01f88d7a9a8ac17,
387-
0xd67870a7251fde72, 0xf32b837f845a676b, 0x0827717b1ffe59f7,
388-
0x80307212ca7645fb, 0xf0d22af71ea57c80, 0x459373765f2c114b,
389-
0x54d26109fab9cbaf, 0xc603da4e257b93db, 0x57fa334b5689d7d5,
390-
0x41cd1b2a8a91f620, 0xe1d6e7cd0fb015af, 0x8608e9035eb9d795,
391-
0x45c7b9fae739fee1, 0x9f5ae4f7a6b597ee, 0xfb771b6e0017757d,
392-
0x8dac6d29cfd8d027, 0x3c9ba4fb62ce6508, 0xa971fad8243844a7,
393-
0xd2126f49b2ea3b64, 0x5dd78fe7ac436861, 0xfe4004a6bb3494a8,
394-
0xe7c01cc63d770d7c, 0xa117075b8c801d37, 0xdf1dfe75f0e73069,
395-
0x7285b39700cefb98, 0x5e97ea1aa9a670eb, 0xe21872db2b9137a3,
396-
0x12630b02c6ca405e, 0xfe1f2d802151f97a, 0xb53b0ed3dea4fb02,
397-
0xc6d5ed56d1dbf9fd, 0xe5b92b558a5c70cb, 0xccd6eedf97277d08,
398-
0x08582fff2e1494ed, 0xa41f2b3d17f1c4c7, 0x29ec07e5ef950f3d,
399-
0x96aba32565a97084, 0xf26870eca10cebcd, 0xbe1432feb4d33361,
400-
0x21993a779845e6eb,
365+
0x669da02f8d009e0f, 0xceb19bf2255445cd, 0x0e746992d6d43a7c,
366+
0x41ed623b9dcc5fde, 0x187a5a30d7c72edc, 0x949ae2a9c1eb925a,
367+
0x7e9c76a7b7c35e68, 0x4f96bf15b8309ff6, 0x26c0c1fde233732e,
368+
0xb0453f72aa151615, 0xf24b621a9ce9fece, 0x99ed798408687b5f,
369+
0x3b13ec1221423b66, 0xc67cf148a28afe59, 0x22f7e0173f92e3fa,
370+
0x14186c5fda6683a0, 0x97d608caa2603b2c, 0xfde3b0bbba24ffa9,
371+
0xb7068eb48c472c77, 0x9e34d72866b9fda0, 0xbbb99c884cdef88e,
372+
0x81d3e01f472a8a1a, 0xf84f506b3b60366d, 0xfe3f42f01300db37,
373+
0xe385712a51c1f836, 0x41dfd5e394245c79, 0x60855dbedadb900a,
374+
0xbdb4c0aa38567476, 0x9748802e8eec02cc, 0x5ced256d257f88de,
375+
0x55acccdf9a80f155, 0xa64b55b071afbbea, 0xa205bfe6c724ce4d,
376+
0x69dd26ca8ac21744, 0xef80e2ff2f6a9bc0, 0xde266c0baa202c20,
377+
0xfa3463080ac74c50, 0x379d968a40125c2b, 0x4cbbd0a7b3c7d648,
378+
0xc92afd93f4c665d2, 0x6e28f5adb7ae38dc, 0x7c689c9c237be35e,
379+
0xaea41b29bd9d0f73, 0x832cef631d77e59f, 0x70cac8e87bc37dd3,
380+
0x8e8c98bbde68e764, 0xd6117aeb3ddedded, 0xd796ab808e766240,
381+
0x8953d0ea1a7d9814, 0xa212eba4281b391c, 0x21a555a8939ce597,
382+
0x809d31660f6d81a8, 0x2356524b20ab400f, 0x5bc611e1e49d0478,
383+
0xba9c065e2f385ce2, 0xb0a0fd12f4e83899, 0x14d076a35b1ff2ca,
384+
0x8acd0bb8cf9a93c0, 0xe62e8ec094039ee4, 0x38a536a7072bdc61,
385+
0xca256297602524f8, 0xfc62ebfb3530caeb, 0x8d8b0c05520569f6,
386+
0xbbaca65cf154c59d, 0x3739b5ada7e338d3, 0xdb9ea31f47365340,
387+
0x410b5c9c1da56755, 0x7e0abc03dbd10283, 0x136f87be70ed442e,
388+
0x6b727d4feddbe1e9, 0x074ebb21183b01df, 0x3fe92185b1985484,
389+
0xc5d8efd3c68305ca, 0xd9bada21b17e272e, 0x64d73133e1360f83,
390+
0xeb8563aa993e21f9, 0xe5e8da50cceab28f, 0x7a6f92eb3223d2f3,
391+
0xbdaf98370ea9b31b, 0x1682a84457f077bc, 0x4abd2d33b6e3be37,
392+
0xb35bc81a7c9d4c04, 0x3e5bde3fb7cfe63d, 0xff3abe6e2ffec974,
393+
0xb8116dd26cf6feec, 0x7a77a6e4ed0cf081, 0xb71eec2d5a184316,
394+
0x6fa932f77b4da817, 0x795f79b33909b2c4, 0x1b8755ef6b5eb34e,
395+
0x2255b72d7d6b2d79, 0xf2bdafafa90bd50a, 0x442a578f02cb1fc8,
396+
0xc25aefe55ecf83db,
401397
};
402398
#endif
403399

@@ -408,7 +404,7 @@ TEST(LowLevelHashTest, VerifyGolden) {
408404
ASSERT_TRUE(absl::Base64Unescape(cases[i].base64_data, &str));
409405
ASSERT_GT(str.size(), 32);
410406
uint64_t h = absl::hash_internal::LowLevelHashLenGt32(
411-
str.data(), str.size(), cases[i].seed, kSalt);
407+
str.data(), str.size(), cases[i].seed);
412408
printf("0x%016" PRIx64 ", ", h);
413409
if (i % 3 == 2) {
414410
printf("\n");
@@ -424,7 +420,7 @@ TEST(LowLevelHashTest, VerifyGolden) {
424420
ASSERT_TRUE(absl::Base64Unescape(cases[i].base64_data, &str));
425421
ASSERT_GT(str.size(), 32);
426422
EXPECT_EQ(absl::hash_internal::LowLevelHashLenGt32(str.data(), str.size(),
427-
cases[i].seed, kSalt),
423+
cases[i].seed),
428424
kGolden[i]);
429425
}
430426
#endif

0 commit comments

Comments
 (0)