Skip to content

Commit

Permalink
FastMod for EEHashTable (Faster virtual generics) (#65926)
Browse files Browse the repository at this point in the history
  • Loading branch information
EgorBo authored Mar 1, 2022
1 parent a5a7836 commit af71404
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 8 deletions.
20 changes: 14 additions & 6 deletions src/coreclr/vm/eehash.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,11 @@ class EEHashTableBase

struct BucketTable
{
DPTR(PTR_EEHashEntry_t) m_pBuckets; // Pointer to first entry for each bucket
DWORD m_dwNumBuckets;
DPTR(PTR_EEHashEntry_t) m_pBuckets; // Pointer to first entry for each bucket
DWORD m_dwNumBuckets;
#ifdef TARGET_64BIT
UINT64 m_dwNumBucketsMul; // "Fast Mod" multiplier for "X % m_dwNumBuckets"
#endif
} m_BucketTable[2];
typedef DPTR(BucketTable) PTR_BucketTable;

Expand Down Expand Up @@ -191,10 +194,15 @@ class EEHashTable : public EEHashTableBase<KeyType, Helper, bDefaultCopyIsDeep>
EEHashTable()
{
LIMITED_METHOD_CONTRACT;
this->m_BucketTable[0].m_pBuckets = NULL;
this->m_BucketTable[0].m_dwNumBuckets = 0;
this->m_BucketTable[1].m_pBuckets = NULL;
this->m_BucketTable[1].m_dwNumBuckets = 0;
this->m_BucketTable[0].m_pBuckets = NULL;
this->m_BucketTable[0].m_dwNumBuckets = 0;
this->m_BucketTable[1].m_pBuckets = NULL;
this->m_BucketTable[1].m_dwNumBuckets = 0;
#ifdef TARGET_64BIT
this->m_BucketTable[0].m_dwNumBucketsMul = 0;
this->m_BucketTable[1].m_dwNumBucketsMul = 0;
#endif

#ifndef DACCESS_COMPILE
this->m_pVolatileBucketTable = NULL;
#endif
Expand Down
18 changes: 16 additions & 2 deletions src/coreclr/vm/eehash.inl
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ void EEHashTableBase<KeyType, Helper, bDefaultCopyIsDeep>::ClearHashTable()
}

m_pVolatileBucketTable->m_dwNumBuckets = 0;
#ifdef TARGET_64BIT
m_pVolatileBucketTable->m_dwNumBucketsMul = 0;
#endif
m_dwNumEntries = 0;
}

Expand Down Expand Up @@ -193,8 +196,10 @@ BOOL EEHashTableBase<KeyType, Helper, bDefaultCopyIsDeep>::Init(DWORD dwNumBucke

// The first slot links to the next list.
m_pVolatileBucketTable->m_pBuckets++;

m_pVolatileBucketTable->m_dwNumBuckets = dwNumBuckets;
#ifdef TARGET_64BIT
m_pVolatileBucketTable->m_dwNumBucketsMul = GetFastModMultiplier(dwNumBuckets);
#endif

m_Heap = pHeap;

Expand Down Expand Up @@ -637,7 +642,13 @@ FORCEINLINE EEHashEntry_t *EEHashTableBase<KeyType, Helper, bDefaultCopyIsDeep>:

_ASSERTE(pBucketTable->m_dwNumBuckets != 0);

DWORD dwBucket = dwHash % pBucketTable->m_dwNumBuckets;
DWORD dwBucket;
#ifdef TARGET_64BIT
_ASSERTE(pBucketTable->m_dwNumBucketsMul != 0);
dwBucket = FastMod(dwHash, pBucketTable->m_dwNumBuckets, pBucketTable->m_dwNumBucketsMul);
#else
dwBucket = dwHash % pBucketTable->m_dwNumBuckets;
#endif
EEHashEntry_t * pSearch;

for (pSearch = pBucketTable->m_pBuckets[dwBucket]; pSearch; pSearch = pSearch->pNext)
Expand Down Expand Up @@ -774,6 +785,9 @@ BOOL EEHashTableBase<KeyType, Helper, bDefaultCopyIsDeep>::GrowHashTable()

pNewBucketTable->m_pBuckets = pNewBuckets;
pNewBucketTable->m_dwNumBuckets = dwNewNumBuckets;
#ifdef TARGET_64BIT
pNewBucketTable->m_dwNumBucketsMul = GetFastModMultiplier(dwNewNumBuckets);
#endif

// Add old table to the to free list. Note that the SyncClean thing will only
// delete the buckets at a safe point
Expand Down
15 changes: 15 additions & 0 deletions src/coreclr/vm/util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1006,4 +1006,19 @@ class NormalizedTimer
HRESULT GetFileVersion(LPCWSTR wszFilePath, ULARGE_INTEGER* pFileVersion);
#endif // !TARGET_UNIX

#ifdef TARGET_64BIT
// We use modified Daniel Lemire's fastmod algorithm (https://github.com/dotnet/runtime/pull/406),
// which allows to avoid the long multiplication if the divisor is less than 2**31.
// This is a copy of HashHelpers.cs, see that impl (or linked PR) for more details
inline UINT64 GetFastModMultiplier(UINT32 divisor)
{
return UINT64_MAX / divisor + 1;
}

inline UINT32 FastMod(UINT32 value, UINT32 divisor, UINT64 multiplier)
{
return (UINT32)(((((multiplier * value) >> 32) + 1) * divisor) >> 32);
}
#endif

#endif /* _H_UTIL */

0 comments on commit af71404

Please sign in to comment.