0

Prefetch commonly used database files that are hard faulted on during

startup

BUG: 992003
Change-Id: Idac6ddfc0870fbe8f7a2bc7211b87b0ee5bb9c1f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1741782
Commit-Queue: Joe Laughlin <joel@microsoft.com>
Reviewed-by: Scott Violet <sky@chromium.org>
Reviewed-by: Victor Costan <pwnall@chromium.org>
Reviewed-by: Alex Ilin <alexilin@chromium.org>
Reviewed-by: Greg Thompson <grt@chromium.org>
Cr-Commit-Position: refs/heads/master@{#690760}
This commit is contained in:
Joe Laughlin
2019-08-27 16:42:08 +00:00
committed by Commit Bot
parent 8c511aa049
commit 346bbba175
11 changed files with 60 additions and 40 deletions

@ -1061,6 +1061,8 @@ jumbo_component("base") {
"win/event_trace_controller.h",
"win/event_trace_provider.cc",
"win/event_trace_provider.h",
"win/file_pre_reader.cc",
"win/file_pre_reader.h",
"win/hstring_compare.cc",
"win/hstring_compare.h",
"win/hstring_reference.cc",

@ -2,16 +2,20 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/app/file_pre_reader_win.h"
#include "base/win/file_pre_reader.h"
#include <windows.h>
#include <memoryapi.h> // NOLINT(build/include_order)
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/files/memory_mapped_file.h"
void PreReadFile(const base::FilePath& file_path) {
namespace base {
namespace win {
void PreReadFile(const FilePath& file_path, bool is_executable) {
// On Win8 and higher use ::PrefetchVirtualMemory(). This is better than
// a simple data file read, more from a RAM perspective than CPU. This is
// because reading the file as data results in double mapping to
@ -31,8 +35,8 @@ void PreReadFile(const base::FilePath& file_path) {
constexpr DWORD kStepSize = 1024 * 1024;
base::File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ |
base::File::FLAG_SEQUENTIAL_SCAN);
File file(file_path,
File::FLAG_OPEN | File::FLAG_READ | File::FLAG_SEQUENTIAL_SCAN);
if (!file.IsValid())
return;
@ -51,9 +55,12 @@ void PreReadFile(const base::FilePath& file_path) {
// 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::MemoryMappedFile mapped_file;
if (mapped_file.Initialize(file_path,
base::MemoryMappedFile::READ_CODE_IMAGE)) {
MemoryMappedFile mapped_file;
MemoryMappedFile::Access access = is_executable
? MemoryMappedFile::READ_CODE_IMAGE
: MemoryMappedFile::READ_ONLY;
if (mapped_file.Initialize(file_path, access)) {
_WIN32_MEMORY_RANGE_ENTRY address_range = {mapped_file.data(),
mapped_file.length()};
@ -64,3 +71,6 @@ void PreReadFile(const base::FilePath& file_path) {
}
}
}
} // namespace win
} // namespace base

@ -0,0 +1,28 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This file defines a function to pre-read a file in order to avoid touching
// the disk when it is subsequently used.
#include "base/base_export.h"
#ifndef BASE_WIN_FILE_PRE_READER_H_
#define BASE_WIN_FILE_PRE_READER_H_
namespace base {
class FilePath;
namespace win {
// Pre-reads |file_path| to avoid touching the disk when the file is actually
// used. |is_executable| specifies whether the file is to be prefetched as
// executable code or as data. Windows treats the file backed pages in RAM
// differently and specifying the wrong one results in two copies in RAM.
BASE_EXPORT void PreReadFile(const FilePath& file_path, bool is_executable);
} // namespace win
} // namespace base
#endif // BASE_WIN_FILE_PRE_READER_H_

@ -195,7 +195,6 @@ if (!is_android && !is_mac) {
":chrome_dll",
":chrome_exe_version",
":copy_first_run",
":file_pre_reader",
":visual_elements_resources",
"//base",
"//chrome/app/version_assembly:chrome_exe_manifest",
@ -1493,16 +1492,6 @@ if (is_win) {
]
output = "$target_gen_dir/other_version.rc"
}
source_set("file_pre_reader") {
sources = [
"app/file_pre_reader_win.cc",
"app/file_pre_reader_win.h",
]
deps = [
"//base",
]
}
}
copy("visual_elements_resources") {

@ -1,19 +0,0 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This file defines a function to pre-read a file in order to avoid touching
// the disk when it is subsequently used.
#ifndef CHROME_APP_FILE_PRE_READER_WIN_H_
#define CHROME_APP_FILE_PRE_READER_WIN_H_
namespace base {
class FilePath;
}
// Pre-reads |file_path| to avoid touching the disk when the file is actually
// used.
void PreReadFile(const base::FilePath& file_path);
#endif // CHROME_APP_FILE_PRE_READER_WIN_H_

@ -27,12 +27,12 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/trace_event/trace_event.h"
#include "base/win/file_pre_reader.h"
#include "base/win/scoped_handle.h"
#include "base/win/shlwapi.h"
#include "base/win/windows_version.h"
#include "chrome/app/chrome_watcher_client_win.h"
#include "chrome/app/chrome_watcher_command_line_win.h"
#include "chrome/app/file_pre_reader_win.h"
#include "chrome/browser/active_use_util.h"
#include "chrome/chrome_watcher/chrome_watcher_main_api.h"
#include "chrome/common/chrome_constants.h"
@ -57,7 +57,7 @@ typedef void (*RelaunchChromeBrowserWithNewCommandLineIfNeededFunc)();
// reference to the loaded module on success, or null on error.
HMODULE LoadModuleWithDirectory(const base::FilePath& module) {
::SetCurrentDirectoryW(module.DirName().value().c_str());
PreReadFile(module);
base::win::PreReadFile(module, true);
return ::LoadLibraryExW(module.value().c_str(), nullptr,
LOAD_WITH_ALTERED_SEARCH_PATH);
}

@ -3759,7 +3759,6 @@ jumbo_split_static_library("browser") {
]
deps += [
":chrome_process_finder",
"//chrome:file_pre_reader",
"//chrome/browser/safe_browsing/chrome_cleaner",
"//chrome/browser/safe_browsing/chrome_cleaner:public",
"//chrome/browser/win/conflicts:module_info",

@ -103,6 +103,7 @@ void PredictorDatabaseInternal::Initialize() {
}
bool success = db_->Open(db_path_);
db_->Preload();
if (!success)
return;

@ -1047,6 +1047,7 @@ sql::InitStatus ThumbnailDatabase::OpenDatabase(sql::Database* db,
if (!db->Open(db_name))
return sql::INIT_FAILURE;
db->Preload();
return sql::INIT_OK;
}

@ -102,6 +102,7 @@ bool SQLitePersistentStoreBackendBase::InitializeDatabase() {
Reset();
return false;
}
db_->Preload();
if (!MigrateDatabaseSchema() || !CreateDatabaseSchema()) {
DLOG(ERROR) << "Unable to update or initialize " << histogram_tag_

@ -36,6 +36,10 @@
#include "sql/vfs_wrapper.h"
#include "third_party/sqlite/sqlite3.h"
#if defined(OS_WIN)
#include "base/win/file_pre_reader.h"
#endif
namespace {
// Spin for up to a second waiting for the lock to clear when setting
@ -355,6 +359,9 @@ void Database::Preload() {
return;
}
#if defined(OS_WIN)
base::win::PreReadFile(DbPath(), false);
#else
// The constructor and set_page_size() ensure that page_size_ is never zero.
const int page_size = page_size_;
DCHECK(page_size);
@ -383,6 +390,7 @@ void Database::Preload() {
if (rc != SQLITE_OK)
return;
}
#endif
}
// SQLite keeps unused pages associated with a database in a cache. It asks