mirror of
https://github.com/verilator/verilator.git
synced 2026-10-07 18:42:58 +02:00
Improve --skip-identical to skip on identical input file contents (#6109).
This commit is contained in:
+68
-39
@@ -60,6 +60,8 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
constexpr int INFILTER_IPC_BUFSIZ = (64 * 1024); // For debug, try this as a small number
|
||||
constexpr int INFILTER_CACHE_MAX = (64 * 1024); // Maximum bytes to cache if same file read twice
|
||||
|
||||
constexpr off_t FILE_HASH_SIZE_MAX = 1 * 1024 * 1024; // Maxium size file to hash
|
||||
|
||||
//######################################################################
|
||||
// V3File Internal state
|
||||
|
||||
@@ -71,6 +73,7 @@ class V3FileDependImp final {
|
||||
bool m_exists = true;
|
||||
const string m_filename; // Filename
|
||||
struct stat m_stat; // Stat information
|
||||
VHashSha256 m_hash; // SHA hash of file contents
|
||||
public:
|
||||
DependFile(const string& filename, bool target)
|
||||
: m_target{target}
|
||||
@@ -88,6 +91,11 @@ class V3FileDependImp final {
|
||||
time_t cnstime() const { return VL_STAT_CTIME_NSEC(m_stat); } // Nanoseconds
|
||||
time_t mstime() const { return m_stat.st_mtime; } // Seconds
|
||||
time_t mnstime() const { return VL_STAT_MTIME_NSEC(m_stat); } // Nanoseconds
|
||||
string hashDigestSymbol() {
|
||||
static VHashSha256 emptyHash;
|
||||
return m_hash.digestSymbol() != emptyHash.digestSymbol() ? m_hash.digestSymbol()
|
||||
: "unhashed";
|
||||
}
|
||||
void loadStats() {
|
||||
if (!m_stat.st_mtime) {
|
||||
const string fn = filename();
|
||||
@@ -98,6 +106,9 @@ class V3FileDependImp final {
|
||||
m_exists = false;
|
||||
// Not an error... This can occur due to `line directives in the .vpp files
|
||||
UINFO(1, "-Info: File not statable: " << filename());
|
||||
} else {
|
||||
// For speed, don't hash large files (e.g. verilator_bin)
|
||||
if (!target() && size() <= FILE_HASH_SIZE_MAX) m_hash.insertFile(filename());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -186,28 +197,28 @@ void V3FileDependImp::writeTimes(const string& filename, const string& cmdlineIn
|
||||
<< "IPTION: Verilator output: Timestamp data for --skip-identical. Delete at will.\n";
|
||||
*ofp << "C \"" << cmdline << "\"\n";
|
||||
|
||||
for (std::set<DependFile>::iterator iter = m_filenameList.begin();
|
||||
iter != m_filenameList.end(); ++iter) {
|
||||
for (auto& it : m_filenameList) {
|
||||
DependFile* const depfilep = const_cast<DependFile*>(&it);
|
||||
// Read stats of files we create after we're done making them
|
||||
// (except for this file, of course)
|
||||
DependFile* const dfp = const_cast<DependFile*>(&(*iter));
|
||||
V3Os::filesystemFlush(dfp->filename());
|
||||
dfp->loadStats();
|
||||
off_t showSize = iter->size();
|
||||
ino_t showIno = iter->ino();
|
||||
if (dfp->filename() == filename) {
|
||||
V3Os::filesystemFlush(depfilep->filename());
|
||||
depfilep->loadStats();
|
||||
off_t showSize = depfilep->size();
|
||||
ino_t showIno = depfilep->ino();
|
||||
if (depfilep->filename() == filename) {
|
||||
showSize = 0;
|
||||
showIno = 0; // We're writing it, so need to ignore it
|
||||
}
|
||||
|
||||
*ofp << (iter->target() ? "T" : "S") << " ";
|
||||
*ofp << (depfilep->target() ? "T" : "S") << " ";
|
||||
*ofp << " " << std::setw(8) << showSize;
|
||||
*ofp << " " << std::setw(8) << showIno;
|
||||
*ofp << " " << std::setw(11) << iter->cstime();
|
||||
*ofp << " " << std::setw(11) << iter->cnstime();
|
||||
*ofp << " " << std::setw(11) << iter->mstime();
|
||||
*ofp << " " << std::setw(11) << iter->mnstime();
|
||||
*ofp << " \"" << iter->filename() << "\"";
|
||||
*ofp << " " << std::setw(11) << depfilep->cstime();
|
||||
*ofp << " " << std::setw(11) << depfilep->cnstime();
|
||||
*ofp << " " << std::setw(11) << depfilep->mstime();
|
||||
*ofp << " " << std::setw(11) << depfilep->mnstime();
|
||||
*ofp << " \"" << depfilep->hashDigestSymbol() << "\"";
|
||||
*ofp << " \"" << depfilep->filename() << "\"";
|
||||
*ofp << '\n';
|
||||
}
|
||||
}
|
||||
@@ -236,6 +247,8 @@ bool V3FileDependImp::checkTimes(const string& filename, const string& cmdlineIn
|
||||
}
|
||||
}
|
||||
|
||||
const bool skipHashing = !V3Os::getenvStr("VERILATOR_DEBUG_SKIP_HASH", "").empty();
|
||||
|
||||
while (!ifp->eof()) {
|
||||
char chkDir;
|
||||
*ifp >> chkDir;
|
||||
@@ -254,39 +267,55 @@ bool V3FileDependImp::checkTimes(const string& filename, const string& cmdlineIn
|
||||
*ifp >> chkMnstime;
|
||||
char quote;
|
||||
*ifp >> quote;
|
||||
const string chkHash = V3Os::getline(*ifp, '"');
|
||||
*ifp >> quote;
|
||||
const string chkFilename = V3Os::getline(*ifp, '"');
|
||||
|
||||
V3Os::filesystemFlush(chkFilename);
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
|
||||
struct stat chkStat;
|
||||
const int err = stat(chkFilename.c_str(), &chkStat);
|
||||
struct stat curStat;
|
||||
const int err = stat(chkFilename.c_str(), &curStat);
|
||||
if (err != 0) {
|
||||
UINFO(2, " --check-times failed: missing " << chkFilename);
|
||||
return false;
|
||||
}
|
||||
// UINFO(9," got d="<<chkDir<<" s="<<chkSize<<" ct="<<chkCstime<<"."
|
||||
// <<chkCnstime<<" mt="<<chkMstime<<"."<<chkMnstime<<" fn = "<<chkFilename<<endl);
|
||||
// UINFO(9," nowSt s="<<chkStat.st_size<<" mt="<<chkStat.st_mtime<<"
|
||||
// ct="<<chkStat.st_ctime<<" fn = "<<chkFilename<<endl);
|
||||
if (filename != chkFilename) { // Other then the .dat file itself, as we were writing it
|
||||
// at the time...
|
||||
// We'd like this rule:
|
||||
// if (!(chkStat.st_size == chkSize
|
||||
// && chkStat.st_mtime == chkMstime) {
|
||||
// However NFS messes us up, as there might be some data outstanding when
|
||||
// we determined the original size. For safety, we know the creation time
|
||||
// must be within a few second window... call it 20 sec.
|
||||
if (!(chkStat.st_size >= chkSize && chkStat.st_ino == chkIno
|
||||
&& chkStat.st_ctime == chkCstime && VL_STAT_CTIME_NSEC(chkStat) == chkCnstime
|
||||
&& chkStat.st_mtime <= (chkMstime + 20)
|
||||
// Not comparing chkMnstime
|
||||
)) {
|
||||
UINFO(2, " --check-times failed: out-of-date "
|
||||
<< chkFilename << "; " << chkStat.st_size << "=?" << chkSize << " "
|
||||
<< chkStat.st_ctime << "." << VL_STAT_CTIME_NSEC(chkStat) << "=?"
|
||||
<< chkCstime << "." << chkCnstime << " " << chkStat.st_mtime << "."
|
||||
<< VL_STAT_MTIME_NSEC(chkStat) << "=?" << chkMstime << "."
|
||||
<< chkMnstime << endl);
|
||||
|
||||
// Skip the .dat file itself, as we were writing it at the time was being made
|
||||
if (filename == chkFilename) continue;
|
||||
|
||||
UINFO(9, " got d=" << chkDir << " s=" << chkSize << " ct=" << chkCstime << "."
|
||||
<< chkCnstime << " mt=" << chkMstime << "." << chkMnstime
|
||||
<< " h=" << chkHash << " fn= " << chkFilename);
|
||||
UINFO(9, " nowSt s=" << curStat.st_size << " mt=" << curStat.st_mtime
|
||||
<< " ct=" << curStat.st_ctime);
|
||||
|
||||
// We'd like this rule:
|
||||
// if (!(curStat.st_size == chkSize
|
||||
// && curStat.st_mtime == chkMstime) {
|
||||
// However NFS messes us up, as there might be some data outstanding when
|
||||
// we determined the original size. For safety, we know the creation time
|
||||
// must be within a few second window... call it 20 sec.
|
||||
if (!(curStat.st_size >= chkSize && curStat.st_ino == chkIno
|
||||
&& curStat.st_ctime == chkCstime && VL_STAT_CTIME_NSEC(curStat) == chkCnstime
|
||||
&& curStat.st_mtime <= (chkMstime + 20)
|
||||
// Not comparing chkMnstime
|
||||
)) {
|
||||
UINFO(2, " --check-times: out-of-date "
|
||||
<< chkFilename << "; " << curStat.st_size << "=?" << chkSize << " "
|
||||
<< curStat.st_ctime << "." << VL_STAT_CTIME_NSEC(curStat) << "=?"
|
||||
<< chkCstime << "." << chkCnstime << " " << curStat.st_mtime << "."
|
||||
<< VL_STAT_MTIME_NSEC(curStat) << "=?" << chkMstime << "." << chkMnstime
|
||||
<< endl);
|
||||
if (skipHashing) return false;
|
||||
// We didn't hash target output files, nor large files,
|
||||
// as unlikely to find a match and can be large
|
||||
if (chkHash == "unhashed") return false;
|
||||
|
||||
VHashSha256 curHash;
|
||||
curHash.insertFile(chkFilename);
|
||||
if (curHash.digestSymbol() != chkHash) {
|
||||
UINFO(2, " --check-times: hash differs "
|
||||
<< chkFilename << "; " << curHash.digestSymbol() << "=?" << chkHash);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user