← Documentation
ADS-IDAC Engine 5.0.0
ConfigFingerprint.h
Go to the documentation of this file.
1#pragma once
22
23#include <algorithm>
24#include <cstdint>
25#include <filesystem>
26#include <fstream>
27#include <string>
28#include <vector>
29
30namespace adsidac {
31
34inline void fingerprint_feed(uint64_t& h, const char* data, size_t n) {
35 for (size_t i = 0; i < n; ++i) {
36 h ^= static_cast<unsigned char>(data[i]);
37 h *= 1099511628211ULL;
38 }
39}
40
43inline void fingerprint_feed_file(uint64_t& h, const std::filesystem::path& p) {
44 std::ifstream in(p, std::ios::binary);
45 char buf[1 << 16];
46 while (in.read(buf, sizeof buf) || in.gcount() > 0)
47 fingerprint_feed(h, buf, static_cast<size_t>(in.gcount()));
48}
49
65inline uint64_t compute_config_fingerprint(const std::string& project_dir,
66 const std::string& deck_path) {
67 namespace fs = std::filesystem;
68 uint64_t h = 1469598103934665603ULL; // FNV-1a 64 offset basis
69
70 std::vector<fs::path> files;
71 std::error_code ec;
72 if (!deck_path.empty() && fs::is_regular_file(deck_path, ec))
73 files.emplace_back(deck_path);
74 fs::path ctrl = fs::path(project_dir) / "ZCtrlPar.txt";
75 if (fs::is_regular_file(ctrl, ec))
76 files.push_back(ctrl);
77 fs::path input_dir = fs::path(project_dir) / "Input";
78 if (fs::is_directory(input_dir, ec))
79 for (auto& e : fs::recursive_directory_iterator(input_dir, ec))
80 if (e.is_regular_file(ec))
81 files.push_back(e.path());
82
83 // Sort by project-relative path so directory iteration order, absolute
84 // prefixes, and machine differences cannot change the digest. Keys are
85 // derived LEXICALLY and once per file: fs::relative canonicalizes both
86 // paths with per-component syscalls, which is costly inside a sort
87 // comparator when many ranks stat the same directory at MPI startup.
88 const fs::path base = fs::path(project_dir).lexically_normal();
89 auto rel_key = [&](const fs::path& p) {
90 fs::path r = p.lexically_normal().lexically_relative(base);
91 return (r.empty() || *r.begin() == "..") ? p.filename().generic_string()
92 : r.generic_string();
93 };
94 std::vector<std::pair<std::string, fs::path>> keyed;
95 keyed.reserve(files.size());
96 for (auto& p : files)
97 keyed.emplace_back(rel_key(p), p);
98 std::sort(keyed.begin(), keyed.end(),
99 [](const auto& a, const auto& b) { return a.first < b.first; });
100
101 for (const auto& [key, p] : keyed) {
102 fingerprint_feed(h, key.data(), key.size());
104 }
105 return h;
106}
107
108} // namespace adsidac
document e
uint64_t compute_config_fingerprint(const std::string &project_dir, const std::string &deck_path)
Digest the configuration inputs of a project.
void fingerprint_feed_file(uint64_t &h, const std::filesystem::path &p)
Fold the contents of file p into h, read in 64 KiB blocks. A file that cannot be opened contributes n...
void fingerprint_feed(uint64_t &h, const char *data, size_t n)
Fold n bytes at data into the running 64-bit FNV-1a hash h (xor the byte, then multiply by the FNV pr...