Skip to content

Commit 4d46183

Browse files
committed
Optimize the layout of MetadataCacheEntryBase to pack fields more effectively.
1 parent d93e0df commit 4d46183

File tree

2 files changed

+49
-60
lines changed

2 files changed

+49
-60
lines changed

stdlib/public/runtime/Metadata.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3377,7 +3377,7 @@ void swift::resumeMetadataCompletion(
33773377
// This array comes from the metadata, so
33783378
// we can just "unslice" it to get the
33793379
// non-key arguments.
3380-
key.KeyData.begin());
3380+
key.begin());
33813381
}
33823382

33833383
void forOtherMetadata(const Metadata *metadata) && {

stdlib/public/runtime/MetadataCache.h

Lines changed: 48 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -291,26 +291,19 @@ class SimpleLockingCacheEntryBase {
291291
}
292292
};
293293

294-
// A wrapper around a pointer to a metadata cache entry that provides
295-
// DenseMap semantics that compare values in the key vector for the metadata
296-
// instance.
297-
//
298-
// This is stored as a pointer to the arguments buffer, so that we can save
299-
// an offset while looking for the matching argument given a key.
300-
class KeyDataRef {
301-
const void * const *Args;
302-
unsigned Length;
303-
304-
KeyDataRef(const void * const *args, unsigned length)
305-
: Args(args), Length(length) {}
294+
/// A key value as provided to the concurrent map.
295+
class MetadataCacheKey {
296+
const void * const *Data;
297+
uint32_t Length;
298+
uint32_t Hash;
306299

307300
public:
308-
static KeyDataRef forArguments(const void * const *args,
309-
unsigned numArguments) {
310-
return KeyDataRef(args, numArguments);
311-
}
301+
MetadataCacheKey(const void * const *data, size_t size)
302+
: Data(data), Length(size), Hash(computeHash()) {}
303+
MetadataCacheKey(const void * const *data, size_t size, uint32_t hash)
304+
: Data(data), Length(size), Hash(hash) {}
312305

313-
bool operator==(KeyDataRef rhs) const {
306+
bool operator==(MetadataCacheKey rhs) const {
314307
// Compare the sizes.
315308
unsigned asize = size(), bsize = rhs.size();
316309
if (asize != bsize) return false;
@@ -322,46 +315,49 @@ class KeyDataRef {
322315
return true;
323316
}
324317

325-
int compare(KeyDataRef rhs) const {
318+
int compare(const MetadataCacheKey &rhs) const {
319+
// Compare the hashes.
320+
if (auto hashComparison = compareIntegers(Hash, rhs.Hash)) {
321+
return hashComparison;
322+
}
323+
326324
// Compare the sizes.
327-
unsigned asize = size(), bsize = rhs.size();
328-
if (asize != bsize) {
329-
return (asize < bsize ? -1 : 1);
325+
if (auto sizeComparison = compareIntegers(size(), rhs.size())) {
326+
return sizeComparison;
330327
}
331328

332329
// Compare the content.
333-
auto abegin = begin(), bbegin = rhs.begin();
334-
for (unsigned i = 0; i < asize; ++i) {
335-
if (abegin[i] != bbegin[i])
336-
return (uintptr_t(abegin[i]) < uintptr_t(bbegin[i]) ? -1 : 1);
330+
auto lbegin = begin(), rbegin = rhs.begin();
331+
for (unsigned i = 0, e = size(); i != e; ++i) {
332+
if (auto ptrComparison = comparePointers(lbegin[i], rbegin[i]))
333+
return ptrComparison;
337334
}
338335

336+
// Equal.
339337
return 0;
340338
}
341339

342-
size_t hash() {
343-
size_t H = 0x56ba80d1 * Length ;
344-
for (unsigned i = 0; i < Length; i++) {
345-
H = (H >> 10) | (H << ((sizeof(size_t) * 8) - 10));
346-
H ^= ((size_t)Args[i]) ^ ((size_t)Args[i] >> 19);
347-
}
348-
H *= 0x27d4eb2d;
349-
return (H >> 10) | (H << ((sizeof(size_t) * 8) - 10));
340+
uint32_t hash() const {
341+
return Hash;
350342
}
351343

352-
const void * const *begin() const { return Args; }
353-
const void * const *end() const { return Args + Length; }
344+
const void * const *begin() const { return Data; }
345+
const void * const *end() const { return Data + Length; }
354346
unsigned size() const { return Length; }
355-
};
356347

357-
/// A key value as provided to the concurrent map.
358-
struct MetadataCacheKey {
359-
size_t Hash;
360-
KeyDataRef KeyData;
348+
private:
349+
uint32_t computeHash() const {
350+
size_t H = 0x56ba80d1 * Length;
351+
for (unsigned i = 0; i < Length; i++) {
352+
H = (H >> 10) | (H << ((sizeof(size_t) * 8) - 10));
353+
H ^= (reinterpret_cast<size_t>(Data[i])
354+
^ (reinterpret_cast<size_t>(Data[i]) >> 19));
355+
}
356+
H *= 0x27d4eb2d;
361357

362-
MetadataCacheKey(KeyDataRef data) : Hash(data.hash()), KeyData(data) {}
363-
MetadataCacheKey(const void *const *data, size_t size)
364-
: MetadataCacheKey(KeyDataRef::forArguments(data, size)) {}
358+
// Rotate right by 10 and then truncate to 32 bits.
359+
return uint32_t((H >> 10) | (H << ((sizeof(size_t) * 8) - 10)));
360+
}
365361
};
366362

367363
/// A helper class for ConcurrentMap entry types which allows trailing objects
@@ -622,14 +618,14 @@ class MetadataCacheEntryBase
622618
static size_t numTrailingObjects(OverloadToken<const void *>,
623619
const MetadataCacheKey &key,
624620
Args &&...extraArgs) {
625-
return key.KeyData.size();
621+
return key.size();
626622
}
627623

628624
using super::asImpl;
629625

630626
private:
631627
/// These are set during construction and never changed.
632-
const size_t Hash;
628+
const uint32_t Hash;
633629
const uint16_t KeyLength;
634630

635631
/// What kind of data is stored in the LockedStorage field below?
@@ -665,13 +661,12 @@ class MetadataCacheEntryBase
665661

666662
public:
667663
MetadataCacheEntryBase(const MetadataCacheKey &key)
668-
: Hash(key.Hash), KeyLength(key.KeyData.size()),
664+
: Hash(key.hash()), KeyLength(key.size()),
669665
TrackingInfo(PrivateMetadataTrackingInfo::initial().getRawValue()) {
670666
LockedStorageKind = LSK::AllocatingThread;
671667
LockedStorage.AllocatingThread = std::this_thread::get_id();
672-
memcpy(this->template getTrailingObjects<const void*>(),
673-
key.KeyData.begin(),
674-
KeyLength * sizeof(void*));
668+
memcpy(this->template getTrailingObjects<const void *>(),
669+
key.begin(), key.size() * sizeof(const void *));
675670
}
676671

677672
~MetadataCacheEntryBase() {
@@ -684,23 +679,17 @@ class MetadataCacheEntryBase
684679
LockedStorage.AllocatingThread == std::this_thread::get_id();
685680
}
686681

687-
KeyDataRef getKeyData() const {
688-
return KeyDataRef::forArguments(
689-
this->template getTrailingObjects<const void*>(),
690-
KeyLength);
682+
MetadataCacheKey getKey() const {
683+
return MetadataCacheKey(this->template getTrailingObjects<const void*>(),
684+
KeyLength, Hash);
691685
}
692686

693687
intptr_t getKeyIntValueForDump() const {
694688
return Hash;
695689
}
696690

697691
int compareWithKey(const MetadataCacheKey &key) const {
698-
// Order by hash first, then by the actual key data.
699-
if (auto comparison = compareIntegers(key.Hash, Hash)) {
700-
return comparison;
701-
} else {
702-
return key.KeyData.compare(getKeyData());
703-
}
692+
return key.compare(getKey());
704693
}
705694

706695
/// Given that this thread doesn't own the right to initialize the

0 commit comments

Comments
 (0)