Handle prefetch failures and add result histogram
When restarting Chrome after an update we sometimes observe a large
number of hard page faults for chrome.dll. This suggests that the
prefetching of chrome.dll has failed, and this can significantly impact
startup time, especially for users with spinning disks.
This change updates PreReadFile so that if errors are hit while
initializing the mapped file or calling PrefetchVirtualMemory then
PreReadFileSlow is called, just like in the case where
PrefetchVirtualMemory is not available.
An UMA histogram, Windows.ChromeDllPrefetchResult, is emitted after
any attempt to prefetch chrome.dll. This reports the outcome,
including whether the PreReadFileSlow fallback was used.
This also cleans up the code to avoid an extra use of decltype, and an
unneeded dereference of the function pointer.
Bug: 1096609
Change-Id: I570220ebb7ed148dfdd48ec8948f9480594dbd2e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2248065
Commit-Queue: Jesse McKenna <[email protected]>
Reviewed-by: Steven Holte <[email protected]>
Reviewed-by: Bruce Dawson <[email protected]>
Reviewed-by: Daniel Cheng <[email protected]>
Cr-Commit-Position: refs/heads/master@{#782819}
diff --git a/base/files/file_util.h b/base/files/file_util.h
index c9c2470..fc5d96e 100644
--- a/base/files/file_util.h
+++ b/base/files/file_util.h
@@ -503,6 +503,30 @@
// false.
BASE_EXPORT bool SetNonBlocking(int fd);
+// Possible results of PreReadFile().
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class PrefetchResultCode {
+ kSuccess = 0,
+ kInvalidFile = 1,
+ kSlowSuccess = 2,
+ kSlowFailed = 3,
+ kMemoryMapFailedSlowUsed = 4,
+ kMemoryMapFailedSlowFailed = 5,
+ kFastFailed = 6,
+ kFastFailedSlowUsed = 7,
+ kFastFailedSlowFailed = 8,
+ kMaxValue = kFastFailedSlowFailed
+};
+
+struct PrefetchResult {
+ bool succeeded() const {
+ return code_ == PrefetchResultCode::kSuccess ||
+ code_ == PrefetchResultCode::kSlowSuccess;
+ }
+ const PrefetchResultCode code_;
+};
+
// Hints the OS to prefetch the first |max_bytes| of |file_path| into its cache.
//
// If called at the appropriate time, this can reduce the latency incurred by
@@ -516,17 +540,18 @@
// executable code or as data. Windows treats the file backed pages in RAM
// differently, and specifying the wrong value results in two copies in RAM.
//
-// Returns false if prefetching definitely failed. A return value of true does
-// not guarantee that the entire desired range was prefetched.
+// Returns a PrefetchResult indicating whether prefetch succeeded, and the type
+// of failure if it did not. A return value of kSuccess does not guarantee that
+// the entire desired range was prefetched.
//
// Calling this before using ::LoadLibrary() on Windows is more efficient memory
// wise, but we must be sure no other threads try to LoadLibrary() the file
// while we are doing the mapping and prefetching, or the process will get a
// private copy of the DLL via COW.
-BASE_EXPORT bool PreReadFile(
- const FilePath& file_path,
- bool is_executable,
- int64_t max_bytes = std::numeric_limits<int64_t>::max());
+BASE_EXPORT PrefetchResult
+PreReadFile(const FilePath& file_path,
+ bool is_executable,
+ int64_t max_bytes = std::numeric_limits<int64_t>::max());
#if defined(OS_POSIX) || defined(OS_FUCHSIA)