Skip to content

Commit d757bff

Browse files
curtisblacklgritz
andauthored
perf(TS): Remove redundant instructions from tile hash (#3898)
Optimises the code in the tile hash function. During a render this function is called billions of times so this small improvement adds up, in some test scenes it reduces total render time by an average of about 2%. See https://godbolt.org/z/jMzz4PTce for the exact details. A summary would be: - Reduced instruction count from 75 to 61, this is due to the redundant add and shift operations that can be implicitely handled by taking advantage of the member layout in the class. - Halves the number of memory fetch instructions because all accesses are now 64-bit. - Removes branching instructions and extra memory indirection inside `ustring::hash()`. There is a slight change in behaviour, which is that the hash is now computed from the `m_file` pointer rather than from `m_file->filename().hash()`, so runtime reproducibility is lost. However the performance gain seems worth it. Signed-off-by: Curtis Black <[email protected]> Signed-off-by: Larry Gritz <[email protected]> Co-authored-by: Larry Gritz <[email protected]>
1 parent 9fd9fbf commit d757bff

File tree

2 files changed

+17
-7
lines changed

2 files changed

+17
-7
lines changed

src/include/OpenImageIO/hash.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,12 @@ inline uint64_t fasthash64(const void *buf, size_t len, uint64_t seed=1771)
8080
uint64_t v;
8181

8282
while (pos != end) {
83+
// This appears to be a false positive which only affects GCC.
84+
// https://godbolt.org/z/5q7Y7ndfb
85+
OIIO_PRAGMA_WARNING_PUSH
86+
OIIO_GCC_ONLY_PRAGMA(GCC diagnostic ignored "-Wmaybe-uninitialized")
8387
v = *pos++;
88+
OIIO_PRAGMA_WARNING_PUSH
8489
h ^= mix(v);
8590
h *= m;
8691
}

src/libtexture/imagecache_pvt.h

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -560,13 +560,17 @@ struct TileID {
560560
/// Digest the TileID into a size_t to use as a hash key.
561561
size_t hash() const
562562
{
563-
const uint64_t a = (uint64_t(m_x) << 32) + uint64_t(m_y);
564-
const uint64_t b = (uint64_t(m_z) << 32) + uint64_t(m_subimage);
565-
const uint64_t c = (uint64_t(m_miplevel) << 32)
566-
+ (uint64_t(m_chbegin) << 16) + uint64_t(m_chend);
567-
const uint64_t d = m_file->filename().hash()
568-
+ uint64_t(m_colortransformid);
569-
return fasthash::fasthash64({ a, b, c, d });
563+
static constexpr size_t member_size
564+
= sizeof(m_x) + sizeof(m_y) + sizeof(m_z) + sizeof(m_subimage)
565+
+ sizeof(m_miplevel) + sizeof(m_chbegin) + sizeof(m_chend)
566+
+ sizeof(m_colortransformid) + sizeof(m_padding) + sizeof(m_file);
567+
static_assert(
568+
sizeof(*this) == member_size,
569+
"All TileID members must be accounted for so we can hash the entire class.");
570+
static_assert(
571+
sizeof(*this) % sizeof(uint64_t) == 0,
572+
"FastHash uses the fewest instructions when data size is a multiple of 8 bytes.");
573+
return fasthash::fasthash64(this, sizeof(*this));
570574
}
571575

572576
/// Functor that hashes a TileID
@@ -590,6 +594,7 @@ struct TileID {
590594
int m_miplevel; ///< MIP-map level
591595
short m_chbegin, m_chend; ///< Channel range
592596
int m_colortransformid; ///< Colorspace id (0 == default)
597+
int m_padding = 0; ///< Unused
593598
ImageCacheFile* m_file; ///< Which ImageCacheFile we refer to
594599
};
595600

0 commit comments

Comments
 (0)