summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorananta@chromium.org <ananta@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-03 06:14:45 +0000
committerananta@chromium.org <ananta@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-03 06:14:45 +0000
commit85286b53fce1ded5c4ad5a9aaea6b1a7c2e7a2b1 (patch)
treeb9507924c0cd2c70890289357a427e5dd69f979f
parentd27893f65dbd01a0d88dcda2a69f518e4b8a636d (diff)
downloadchromium_src-85286b53fce1ded5c4ad5a9aaea6b1a7c2e7a2b1.zip
chromium_src-85286b53fce1ded5c4ad5a9aaea6b1a7c2e7a2b1.tar.gz
chromium_src-85286b53fce1ded5c4ad5a9aaea6b1a7c2e7a2b1.tar.bz2
Changing the pre-reading of chrome.dll to read it as an image section instead. XP ignores pages read as data
while mapping image sections. This shows a reasonable improvement in cold startup performance on XP. This change only comes into effect for headless mode which enables us to try out the effect on the perf bots and for chrome frame processes. Code mostly written by Amit. Added a chrome frame perf tests which measures LoadLibrary in cold mode with pre-reading. Bug=45510 Review URL: http://codereview.chromium.org/2805064 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@51594 0039d316-1c4b-4281-b951-d872f2087c98
-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);