mirror of
https://github.com/official-stockfish/Stockfish.git
synced 2026-07-22 12:47:08 +00:00
Make PGO builds deterministic again
some environment dependent execution (e.g. pid) were being std::hash'ed, and net filenames put in unordered maps. Also uses sprintf instead of std::to_string. Depending on precise content, this could lead to different PGO'ed binaries. This is mitigated by using a basic hash function. This also fixes a potential issue in net filename generation, in cases where std::hash would use invocation dependent salt, which is not the cases today for typical std libraries. Closes https://github.com/official-stockfish/Stockfish/pull/6562 No functional change
This commit is contained in:
committed by
Joost VandeVondele
parent
f61d4317a3
commit
c0f245303b
+28
-13
@@ -34,6 +34,7 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#define stringify2(x) #x
|
||||
@@ -305,24 +306,38 @@ inline uint64_t mul_hi64(uint64_t a, uint64_t b) {
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
inline void hash_combine(std::size_t& seed, const T& v) {
|
||||
std::hash<T> hasher;
|
||||
seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void hash_combine(std::size_t& seed, const std::size_t& v) {
|
||||
seed ^= v + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||
inline std::uint64_t hash_bytes(const char* data, std::size_t size) {
|
||||
// FNV-1a 64-bit
|
||||
const char* p = data;
|
||||
std::uint64_t h = 14695981039346656037ull;
|
||||
for (std::size_t i = 0; i < size; ++i)
|
||||
h = (h ^ p[i]) * 1099511628211ull;
|
||||
return h;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline std::size_t get_raw_data_hash(const T& value) {
|
||||
return std::hash<std::string_view>{}(
|
||||
std::string_view(reinterpret_cast<const char*>(&value), sizeof(value)));
|
||||
// We must have no padding bytes because we're reinterpreting as char
|
||||
static_assert(std::has_unique_object_representations<T>());
|
||||
|
||||
return static_cast<std::size_t>(
|
||||
hash_bytes(reinterpret_cast<const char*>(&value), sizeof(value)));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void hash_combine(std::size_t& seed, const T& v) {
|
||||
std::size_t x;
|
||||
// For primitive types we avoid using the default hasher, which may be
|
||||
// nondeterministic across program invocations
|
||||
if constexpr (std::is_integral<T>())
|
||||
x = v;
|
||||
else
|
||||
x = std::hash<T>{}(v);
|
||||
seed ^= x + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||
}
|
||||
|
||||
inline std::uint64_t hash_string(const std::string& sv) { return hash_bytes(sv.data(), sv.size()); }
|
||||
|
||||
template<std::size_t Capacity>
|
||||
class FixedString {
|
||||
public:
|
||||
@@ -450,7 +465,7 @@ void move_to_front(std::vector<T>& vec, Predicate pred) {
|
||||
template<std::size_t N>
|
||||
struct std::hash<Stockfish::FixedString<N>> {
|
||||
std::size_t operator()(const Stockfish::FixedString<N>& fstr) const noexcept {
|
||||
return std::hash<std::string_view>{}((std::string_view) fstr);
|
||||
return Stockfish::hash_bytes(fstr.data(), fstr.size());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user