blob: f95c0276b5dbff0ff4b1e5ace5e6015842ef31b4 [file] [log] [blame]
// 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.
#include "chrome/app/file_pre_reader_win.h"
#include <windows.h>
#include "base/files/file.h"
#include "base/files/memory_mapped_file.h"
#include "base/logging.h"
#include "base/threading/platform_thread.h"
#include "base/threading/thread_restrictions.h"
#include "components/startup_metric_utils/common/pre_read_field_trial_utils_win.h"
namespace {
// Pre-reads |file_path| using ::ReadFile.
void PreReadFileUsingReadFile(const base::FilePath& file_path) {
base::File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ |
base::File::FLAG_SEQUENTIAL_SCAN);
if (!file.IsValid())
return;
const DWORD kStepSize = 1024 * 1024;
char* buffer = reinterpret_cast<char*>(
::VirtualAlloc(nullptr, kStepSize, MEM_COMMIT, PAGE_READWRITE));
if (!buffer)
return;
while (file.ReadAtCurrentPos(buffer, kStepSize) > 0) {}
::VirtualFree(buffer, 0, MEM_RELEASE);
}
// Pre-reads |file_path| using ::PrefetchVirtualMemory, if available. Otherwise,
// falls back on using ::ReadFile.
void PreReadFileUsingPrefetchVirtualMemory(const base::FilePath& file_path) {
// Load ::PrefetchVirtualMemory dynamically, because it is only available on
// Win8+.
using PrefetchVirtualMemoryPtr = decltype(::PrefetchVirtualMemory)*;
PrefetchVirtualMemoryPtr prefetch_virtual_memory =
reinterpret_cast<PrefetchVirtualMemoryPtr>(::GetProcAddress(
::GetModuleHandle(L"kernel32.dll"), "PrefetchVirtualMemory"));
if (!prefetch_virtual_memory) {
// If ::PrefetchVirtualMemory is not available, fall back to
// PreReadFileUsingReadFile().
PreReadFileUsingReadFile(file_path);
return;
}
base::MemoryMappedFile memory_mapped_file;
if (!memory_mapped_file.Initialize(file_path)) {
// Initializing the memory map should not fail. If it does fail in a debug
// build, we want to be warned about it so that we can investigate the
// failure.
NOTREACHED();
PreReadFileUsingReadFile(file_path);
return;
}
WIN32_MEMORY_RANGE_ENTRY memory_range;
memory_range.VirtualAddress = const_cast<void*>(
reinterpret_cast<const void*>(memory_mapped_file.data()));
memory_range.NumberOfBytes = memory_mapped_file.length();
prefetch_virtual_memory(::GetCurrentProcess(), 1U, &memory_range, 0);
}
} // namespace
void PreReadFile(const base::FilePath& file_path,
const startup_metric_utils::PreReadOptions& pre_read_options) {
DCHECK(pre_read_options.pre_read);
base::ThreadRestrictions::AssertIOAllowed();
// Increase thread priority if necessary.
base::ThreadPriority previous_priority = base::ThreadPriority::NORMAL;
if (pre_read_options.high_priority) {
previous_priority = base::PlatformThread::GetCurrentThreadPriority();
base::PlatformThread::SetCurrentThreadPriority(
base::ThreadPriority::DISPLAY);
}
// Pre-read |file_path|.
if (pre_read_options.prefetch_virtual_memory)
PreReadFileUsingPrefetchVirtualMemory(file_path);
else
PreReadFileUsingReadFile(file_path);
// Reset thread priority.
if (pre_read_options.high_priority)
base::PlatformThread::SetCurrentThreadPriority(previous_priority);
}