summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNico Weber <thakis@chromium.org>2014-05-25 04:17:35 (GMT)
committerNico Weber <thakis@chromium.org>2014-06-15 21:13:17 (GMT)
commit945a1080afc7f79d50e166428af754a3e5d5d91c (patch)
treec36bd3936b0f9e7576aaef7fec95af254f4f9b06
parent0ac72f01630bbca087cdb41a89ca4d80b659b536 (diff)
downloadNinja-945a1080afc7f79d50e166428af754a3e5d5d91c.zip
Ninja-945a1080afc7f79d50e166428af754a3e5d5d91c.tar.gz
Ninja-945a1080afc7f79d50e166428af754a3e5d5d91c.tar.bz2
Add a stat cache. Demo-quality, and disabled atm.
-rw-r--r--src/disk_interface.cc119
-rw-r--r--src/disk_interface.h9
-rw-r--r--src/ninja.cc6
3 files changed, 114 insertions, 20 deletions
diff --git a/src/disk_interface.cc b/src/disk_interface.cc
index 4dfae1a..2175051 100644
--- a/src/disk_interface.cc
+++ b/src/disk_interface.cc
@@ -55,6 +55,29 @@ int MakeDir(const string& path) {
#endif
}
+TimeStamp StatSingleFile(const string& path, bool quiet) {
+ WIN32_FILE_ATTRIBUTE_DATA attrs;
+ if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &attrs)) {
+ DWORD err = GetLastError();
+ if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND)
+ return 0;
+ if (!quiet) {
+ Error("GetFileAttributesEx(%s): %s", path.c_str(),
+ GetLastErrorString().c_str());
+ }
+ return -1;
+ }
+ const FILETIME& filetime = attrs.ftLastWriteTime;
+ // FILETIME is in 100-nanosecond increments since the Windows epoch.
+ // We don't much care about epoch correctness but we do want the
+ // resulting value to fit in an integer.
+ uint64_t mtime = ((uint64_t)filetime.dwHighDateTime << 32) |
+ ((uint64_t)filetime.dwLowDateTime);
+ mtime /= 1000000000LL / 100; // 100ns -> s.
+ mtime -= 12622770400LL; // 1600 epoch -> 2000 epoch (subtract 400 years).
+ return (TimeStamp)mtime;
+}
+
} // namespace
// DiskInterface ---------------------------------------------------------------
@@ -89,26 +112,84 @@ TimeStamp RealDiskInterface::Stat(const string& path) {
}
return -1;
}
- WIN32_FILE_ATTRIBUTE_DATA attrs;
- if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &attrs)) {
- DWORD err = GetLastError();
- if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND)
- return 0;
- if (!quiet_) {
- Error("GetFileAttributesEx(%s): %s", path.c_str(),
- GetLastErrorString().c_str());
- }
- return -1;
+ if (!use_cache_)
+ return StatSingleFile(path, quiet_);
+
+ string dir = DirName(path);
+ int offs = dir.size();
+ if (offs) ++offs; // skip \ too
+ string base(path.substr(offs));
+
+ std::transform(dir.begin(), dir.end(), dir.begin(), ::tolower);
+ std::transform(base.begin(), base.end(), base.begin(), ::tolower);
+
+ Cache::iterator ci = cache_.find(dir);
+ if (ci != cache_.end()) {
+ DirCache::iterator di = ci->second->find(base);
+ if (di != ci->second->end())
+ return di->second;
+ return 0;
}
- const FILETIME& filetime = attrs.ftLastWriteTime;
- // FILETIME is in 100-nanosecond increments since the Windows epoch.
- // We don't much care about epoch correctness but we do want the
- // resulting value to fit in an integer.
- uint64_t mtime = ((uint64_t)filetime.dwHighDateTime << 32) |
- ((uint64_t)filetime.dwLowDateTime);
- mtime /= 1000000000LL / 100; // 100ns -> s.
- mtime -= 12622770400LL; // 1600 epoch -> 2000 epoch (subtract 400 years).
- return (TimeStamp)mtime;
+
+ if (dir.empty())
+ dir = ".";
+ // XXX fill in dir using FFF / FNF
+ HANDLE hFind = INVALID_HANDLE_VALUE;
+ WIN32_FIND_DATAA ffd;
+
+#if 0
+ hFind = FindFirstFileA((dir + "\\*").c_str(), &ffd);
+#else
+ hFind = FindFirstFileExA((dir + "\\*").c_str(),
+ //FindExInfoStandard,
+ FindExInfoBasic, // 30% faster than FindExInfoStandard!
+ &ffd,
+ FindExSearchNameMatch,
+ NULL,
+ 0 ); // XXX: check FIND_FIRST_EX_LARGE_FETCH
+#endif
+
+ if (hFind == INVALID_HANDLE_VALUE) {
+ fprintf(stderr, "fail %s", dir.c_str());
+ exit(-1);
+ }
+ DirCache* dc = new DirCache;
+ do {
+ if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ continue;
+
+ string lowername = ffd.cFileName;
+ std::transform(lowername.begin(), lowername.end(),
+ lowername.begin(), ::tolower);
+
+//fprintf(stderr, "%s %s\n", dir.c_str(), lowername.c_str());
+
+ const FILETIME& filetime = ffd.ftLastWriteTime;
+ // FILETIME is in 100-nanosecond increments since the Windows epoch.
+ // We don't much care about epoch correctness but we do want the
+ // resulting value to fit in an integer.
+ uint64_t mtime = ((uint64_t)filetime.dwHighDateTime << 32) |
+ ((uint64_t)filetime.dwLowDateTime);
+ mtime /= 1000000000LL / 100; // 100ns -> s.
+//if(mtime == 0)
+//printf(" asdasdfadsfsadf\n");
+
+ mtime -= 12622770400LL; // 1600 epoch -> 2000 epoch (subtract 400 years).
+
+ (*dc).insert(make_pair(lowername, (TimeStamp)mtime));
+ } while (FindNextFileA(hFind, &ffd));
+ FindClose(hFind);
+
+ if (dir == ".")
+ cache_.insert(make_pair("", dc));
+ else
+ cache_.insert(make_pair(dir, dc));
+
+ DirCache::iterator di = dc->find(base);
+ if (di != dc->end())
+ return di->second;
+ return 0;
+
#else
struct stat st;
if (stat(path.c_str(), &st) < 0) {
diff --git a/src/disk_interface.h b/src/disk_interface.h
index ff1e21c..d368c38 100644
--- a/src/disk_interface.h
+++ b/src/disk_interface.h
@@ -15,6 +15,7 @@
#ifndef NINJA_DISK_INTERFACE_H_
#define NINJA_DISK_INTERFACE_H_
+#include <map>
#include <string>
using namespace std;
@@ -55,7 +56,7 @@ struct DiskInterface {
/// Implementation of DiskInterface that actually hits the disk.
struct RealDiskInterface : public DiskInterface {
- RealDiskInterface() : quiet_(false) {}
+ RealDiskInterface() : quiet_(false), use_cache_(false) {}
virtual ~RealDiskInterface() {}
virtual TimeStamp Stat(const string& path);
virtual bool MakeDir(const string& path);
@@ -65,6 +66,12 @@ struct RealDiskInterface : public DiskInterface {
/// Whether to print on errors. Used to make a test quieter.
bool quiet_;
+ /// Whether stat information can be cached.
+ bool use_cache_;
+
+ typedef map<string, TimeStamp> DirCache;
+ typedef map<string, DirCache*> Cache;
+ Cache cache_;
};
#endif // NINJA_DISK_INTERFACE_H_
diff --git a/src/ninja.cc b/src/ninja.cc
index 4c8dab7..962480e 100644
--- a/src/ninja.cc
+++ b/src/ninja.cc
@@ -882,6 +882,9 @@ int NinjaMain::RunBuild(int argc, char** argv) {
return 1;
}
+// XXX allow stat caching
+ //disk_interface_.use_cache_ = true;
+
Builder builder(&state_, config_, &build_log_, &deps_log_, &disk_interface_);
for (size_t i = 0; i < targets.size(); ++i) {
if (!builder.AddTarget(targets[i], &err)) {
@@ -895,6 +898,9 @@ int NinjaMain::RunBuild(int argc, char** argv) {
}
}
+// XXX disallow stat caching
+ disk_interface_.use_cache_ = false;
+
if (builder.AlreadyUpToDate()) {
printf("ninja: no work to do.\n");
return 0;