summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/file_util.h9
-rw-r--r--base/file_util_win.cc25
-rw-r--r--chrome/app/client_util.cc62
-rw-r--r--chrome_frame/test/perf/chrome_frame_perftest.cc52
4 files changed, 101 insertions, 47 deletions
diff --git a/base/file_util.h b/base/file_util.h
index 6277748..d52bba9 100644
--- a/base/file_util.h
+++ b/base/file_util.h
@@ -603,6 +603,15 @@ inline bool MakeFileUnreadable(const FilePath& path) {
#endif // UNIT_TEST
+#if defined(OS_WIN)
+ // Loads the file passed in as an image section and touches pages to avoid
+ // subsequent hard page faults during LoadLibrary. The size to be pre read
+ // is passed in. If it is 0 then the whole file is paged in. The step size
+ // which indicates the number of bytes to skip after every page touched is
+ // also passed in.
+ bool PreReadImage(const wchar_t* file_path, size_t size_to_read,
+ size_t step_size);
+#endif // OS_WIN
} // namespace file_util
// Deprecated functions have been moved to this separate header file,
diff --git a/base/file_util_win.cc b/base/file_util_win.cc
index 74b9406..26955f2 100644
--- a/base/file_util_win.cc
+++ b/base/file_util_win.cc
@@ -14,6 +14,7 @@
#include "base/file_path.h"
#include "base/logging.h"
+#include "base/pe_image.h"
#include "base/scoped_comptr_win.h"
#include "base/scoped_handle.h"
#include "base/string_util.h"
@@ -1100,4 +1101,28 @@ bool NormalizeFilePath(const FilePath& path, FilePath* real_path) {
return success;
}
+bool PreReadImage(const wchar_t* file_path, size_t size_to_read,
+ size_t step_size) {
+ HMODULE dll_module = LoadLibraryExW(
+ file_path,
+ NULL,
+ LOAD_WITH_ALTERED_SEARCH_PATH | DONT_RESOLVE_DLL_REFERENCES);
+
+ if (!dll_module)
+ return false;
+
+ PEImage pe_image(dll_module);
+ PIMAGE_NT_HEADERS nt_headers = pe_image.GetNTHeaders();
+ size_t actual_size_to_read = size_to_read ? size_to_read :
+ nt_headers->OptionalHeader.SizeOfImage;
+ volatile uint8* touch = reinterpret_cast<uint8*>(dll_module);
+ size_t offset = 0;
+ while (offset < actual_size_to_read) {
+ uint8 unused = *(touch + offset);
+ offset += step_size;
+ }
+ FreeLibrary(dll_module);
+ return true;
+}
+
} // namespace file_util
diff --git a/chrome/app/client_util.cc b/chrome/app/client_util.cc
index e361db3..a47f3cb 100644
--- a/chrome/app/client_util.cc
+++ b/chrome/app/client_util.cc
@@ -5,6 +5,7 @@
#include <windows.h>
#include <shlwapi.h>
+#include "base/file_util.h"
#include "chrome/app/breakpad_win.h"
#include "chrome/app/client_util.h"
#include "chrome/common/chrome_switches.h"
@@ -110,54 +111,35 @@ HMODULE LoadChromeWithDirectory(std::wstring* dir) {
// Experimental pre-reading optimization
// The idea is to pre read significant portion of chrome.dll in advance
// so that subsequent hard page faults are avoided.
- DWORD pre_read_size_mb = 0;
if (!cmd_line.HasSwitch(switches::kProcessType) &&
(IsRunningHeadless() || InstallUtil::IsChromeFrameProcess())) {
+ // The kernel brings in 8 pages for the code section at a time and 4 pages
+ // for other sections. We can skip over these pages to avoid a soft page
+ // fault which may not occur during code execution. However skipping 4K at
+ // a time still has better performance over 32K and 16K according to data.
+ // TODO(ananta)
+ // Investigate this and tune.
+ const size_t kStepSize = 4 * 1024;
+
+ DWORD pre_read_size = 0;
+ DWORD pre_read_step_size = kStepSize;
+ DWORD pre_read = 1;
+
HKEY key = NULL;
if (::RegOpenKeyEx(HKEY_CURRENT_USER, L"Software\\Google\\ChromeFrame",
0, KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) {
- DWORD unused = sizeof(pre_read_size_mb);
- if (::RegQueryValueEx(key, L"PreRead", NULL, NULL,
- reinterpret_cast<LPBYTE>(&pre_read_size_mb),
- &unused) != ERROR_SUCCESS) {
- pre_read_size_mb = 16; // Default
- }
+ DWORD unused = sizeof(pre_read_size);
+ RegQueryValueEx(key, L"PreReadSize", NULL, NULL,
+ reinterpret_cast<LPBYTE>(&pre_read_size), &unused);
+ RegQueryValueEx(key, L"PreReadStepSize", NULL, NULL,
+ reinterpret_cast<LPBYTE>(&pre_read_step_size), &unused);
+ RegQueryValueEx(key, L"PreRead", NULL, NULL,
+ reinterpret_cast<LPBYTE>(&pre_read), &unused);
RegCloseKey(key);
key = NULL;
- } else {
- pre_read_size_mb = 16; // Read in first 16 MB by default.
}
- }
-
- if (pre_read_size_mb) {
- HANDLE chrome_dll = CreateFile(dir->c_str(),
- GENERIC_READ,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL,
- OPEN_EXISTING,
- FILE_FLAG_SEQUENTIAL_SCAN,
- NULL);
- if (chrome_dll == INVALID_HANDLE_VALUE) {
- DWORD error = GetLastError();
- DLOG(ERROR) << __FUNCTION__ << " CreateFile( "
- << dir->c_str() << " ) failed. Error: " << error;
- } else {
- const size_t kChunkSize = 1024 * 1024; // 1 MB
- void* buffer = VirtualAlloc(NULL, kChunkSize, MEM_COMMIT, PAGE_READWRITE);
- if (buffer) {
- size_t read_size = pre_read_size_mb * kChunkSize;
- DWORD read = 0;
- while (::ReadFile(chrome_dll, buffer, kChunkSize, &read, NULL)) {
- // nothing to do here...
- read_size -= std::min(size_t(read), read_size);
- if (!read || !read_size)
- break;
- }
-
- VirtualFree(buffer, 0, MEM_RELEASE);
- }
-
- CloseHandle(chrome_dll);
+ if (pre_read) {
+ file_util::PreReadImage(dir->c_str(), pre_read_size, pre_read_step_size);
}
}
diff --git a/chrome_frame/test/perf/chrome_frame_perftest.cc b/chrome_frame/test/perf/chrome_frame_perftest.cc
index e22b143..614cb0d 100644
--- a/chrome_frame/test/perf/chrome_frame_perftest.cc
+++ b/chrome_frame/test/perf/chrome_frame_perftest.cc
@@ -12,6 +12,7 @@
#include "chrome_tab.h" // Generated from chrome_tab.idl.
#include "base/file_path.h"
+#include "base/file_util.h"
#include "base/path_service.h"
#include "base/process_util.h"
#include "base/registry.h"
@@ -404,26 +405,42 @@ class ChromeFrameStartupTestActiveX : public ChromeFrameStartupTest {
// This class measures the load time of chrome and chrome frame binaries
class ChromeFrameBinariesLoadTest : public ChromeFrameStartupTestActiveX {
+ static const size_t kStepSize = 4 * 1024;
+ public:
+ ChromeFrameBinariesLoadTest()
+ : pre_read_(false),
+ step_size_(kStepSize),
+ bytes_to_read_(0) {}
+
protected:
virtual void RunStartupTestImpl(TimeTicks* start_time,
TimeTicks* end_time) {
*start_time = TimeTicks::Now();
+ if (pre_read_) {
+ EXPECT_TRUE(file_util::PreReadImage(chrome_exe_.value().c_str(),
+ bytes_to_read_,
+ step_size_));
+ EXPECT_TRUE(file_util::PreReadImage(chrome_dll_.value().c_str(),
+ bytes_to_read_,
+ step_size_));
+ }
+
HMODULE chrome_exe = LoadLibrary(chrome_exe_.value().c_str());
- ASSERT_TRUE(chrome_exe != NULL);
+ EXPECT_TRUE(chrome_exe != NULL);
HMODULE chrome_dll = LoadLibrary(chrome_dll_.value().c_str());
- ASSERT_TRUE(chrome_dll != NULL);
-
- HMODULE chrome_tab_dll = LoadLibrary(chrome_frame_dll_.value().c_str());
- ASSERT_TRUE(chrome_tab_dll != NULL);
+ EXPECT_TRUE(chrome_dll != NULL);
*end_time = TimeTicks::Now();
FreeLibrary(chrome_exe);
FreeLibrary(chrome_dll);
- FreeLibrary(chrome_tab_dll);
}
+
+ bool pre_read_;
+ size_t bytes_to_read_;
+ size_t step_size_;
};
// This class provides functionality to run the startup performance test for
@@ -929,21 +946,42 @@ TEST_F(ChromeFrameBinariesLoadTest, PerfWarm) {
}
TEST_F(ChromeFrameStartupTestActiveX, PerfCold) {
+ SetConfigInt(L"PreRead", 0);
FilePath binaries_to_evict[] = { gears_dll_, avcodec52_dll_,
avformat52_dll_, avutil50_dll_, chrome_exe_, chrome_dll_,
chrome_frame_dll_};
RunStartupTest("cold", "t", "about:blank", true /* cold */,
arraysize(binaries_to_evict), binaries_to_evict,
false /* not important */, false);
+ DeleteConfigValue(L"PreRead");
+}
+
+TEST_F(ChromeFrameStartupTestActiveX, PerfColdPreRead) {
+ SetConfigInt(L"PreRead", 1);
+ FilePath binaries_to_evict[] = { gears_dll_, avcodec52_dll_,
+ avformat52_dll_, avutil50_dll_, chrome_exe_, chrome_dll_,
+ chrome_frame_dll_};
+ RunStartupTest("cold_preread", "t", "about:blank", true /* cold */,
+ arraysize(binaries_to_evict), binaries_to_evict,
+ false /* not important */, false);
+ DeleteConfigValue(L"PreRead");
}
TEST_F(ChromeFrameBinariesLoadTest, PerfCold) {
- FilePath binaries_to_evict[] = {chrome_exe_, chrome_dll_, chrome_frame_dll_};
+ FilePath binaries_to_evict[] = {chrome_exe_, chrome_dll_};
RunStartupTest("binary_load_cold", "t", "", true /* cold */,
arraysize(binaries_to_evict), binaries_to_evict,
false /* not important */, false);
}
+TEST_F(ChromeFrameBinariesLoadTest, PerfColdPreRead) {
+ FilePath binaries_to_evict[] = {chrome_exe_, chrome_dll_};
+ pre_read_ = true;
+ RunStartupTest("binary_load_cold_preread", "t", "", true /* cold */,
+ arraysize(binaries_to_evict), binaries_to_evict,
+ false /* not important */, false);
+}
+
TEST_F(ChromeFrameStartupTestActiveXReference, PerfWarm) {
RunStartupTest("warm", "t_ref", "about:blank", false /* cold */, 0, NULL,
true /* important */, false);