| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome_frame/test/perf/chrome_frame_perftest.h" | |
| 6 | |
| 7 #include <atlhost.h> | |
| 8 #include <atlwin.h> | |
| 9 | |
| 10 #include <map> | |
| 11 #include <string> | |
| 12 #include <vector> | |
| 13 | |
| 14 #include "base/debug/trace_event_win.h" | |
| 15 #include "base/file_util.h" | |
| 16 #include "base/files/file_path.h" | |
| 17 #include "base/memory/scoped_ptr.h" | |
| 18 #include "base/path_service.h" | |
| 19 #include "base/process/kill.h" | |
| 20 #include "base/process/launch.h" | |
| 21 #include "base/process/process_iterator.h" | |
| 22 #include "base/strings/string_util.h" | |
| 23 #include "base/strings/stringprintf.h" | |
| 24 #include "base/strings/utf_string_conversions.h" | |
| 25 #include "base/test/perf_time_logger.h" | |
| 26 #include "base/test/test_file_util.h" | |
| 27 #include "base/threading/platform_thread.h" | |
| 28 #include "base/time/time.h" | |
| 29 #include "base/win/event_trace_consumer.h" | |
| 30 #include "base/win/event_trace_controller.h" | |
| 31 #include "base/win/registry.h" | |
| 32 #include "base/win/scoped_bstr.h" | |
| 33 #include "base/win/scoped_comptr.h" | |
| 34 #include "base/win/scoped_variant.h" | |
| 35 #include "chrome/app/image_pre_reader_win.h" | |
| 36 #include "chrome/common/chrome_constants.h" | |
| 37 #include "chrome/common/chrome_paths.h" | |
| 38 #include "chrome/common/chrome_paths_internal.h" | |
| 39 #include "chrome/test/base/chrome_process_util.h" | |
| 40 #include "chrome/test/ui/ui_perf_test.h" | |
| 41 #include "chrome_frame/chrome_tab.h" | |
| 42 #include "chrome_frame/test_utils.h" | |
| 43 #include "chrome_frame/utils.h" | |
| 44 #include "testing/perf/perf_test.h" | |
| 45 | |
| 46 const wchar_t kSilverlightControlKey[] = | |
| 47 L"CLSID\\{DFEAF541-F3E1-4c24-ACAC-99C30715084A}\\InprocServer32"; | |
| 48 | |
| 49 const wchar_t kFlashControlKey[] = | |
| 50 L"CLSID\\{D27CDB6E-AE6D-11cf-96B8-444553540000}\\InprocServer32"; | |
| 51 | |
| 52 using base::TimeDelta; | |
| 53 using base::TimeTicks; | |
| 54 | |
| 55 // This class implements an ActiveX container which hosts the ChromeFrame | |
| 56 // ActiveX control. It provides hooks which can be implemented by derived | |
| 57 // classes for implementing performance measurement, etc. | |
| 58 class ChromeFrameActiveXContainer | |
| 59 : public CWindowImpl<ChromeFrameActiveXContainer, CWindow, CWinTraits < | |
| 60 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, | |
| 61 WS_EX_APPWINDOW | WS_EX_WINDOWEDGE> >, | |
| 62 public CComObjectRootEx<CComSingleThreadModel>, | |
| 63 public IPropertyNotifySink { | |
| 64 public: | |
| 65 ~ChromeFrameActiveXContainer() { | |
| 66 if (m_hWnd) | |
| 67 DestroyWindow(); | |
| 68 } | |
| 69 | |
| 70 DECLARE_WND_CLASS_EX(L"ChromeFrameActiveX_container", 0, 0) | |
| 71 | |
| 72 BEGIN_COM_MAP(ChromeFrameActiveXContainer) | |
| 73 COM_INTERFACE_ENTRY(IPropertyNotifySink) | |
| 74 END_COM_MAP() | |
| 75 | |
| 76 BEGIN_MSG_MAP(ChromeFrameActiveXContainer) | |
| 77 MESSAGE_HANDLER(WM_CREATE, OnCreate) | |
| 78 MESSAGE_HANDLER(WM_DESTROY, OnDestroy) | |
| 79 END_MSG_MAP() | |
| 80 | |
| 81 HRESULT OnMessageCallback(const VARIANT* param) { | |
| 82 DVLOG(1) << __FUNCTION__; | |
| 83 OnMessageCallbackImpl(param); | |
| 84 return S_OK; | |
| 85 } | |
| 86 | |
| 87 HRESULT OnLoadErrorCallback(const VARIANT* param) { | |
| 88 DVLOG(1) << __FUNCTION__ << " " << param->bstrVal; | |
| 89 OnLoadErrorCallbackImpl(param); | |
| 90 return S_OK; | |
| 91 } | |
| 92 | |
| 93 HRESULT OnLoadCallback(const VARIANT* param) { | |
| 94 DVLOG(1) << __FUNCTION__ << " " << param->bstrVal; | |
| 95 OnLoadCallbackImpl(param); | |
| 96 return S_OK; | |
| 97 } | |
| 98 | |
| 99 ChromeFrameActiveXContainer() : | |
| 100 prop_notify_cookie_(0), | |
| 101 onmsg_(this, &ChromeFrameActiveXContainer::OnMessageCallback), | |
| 102 onloaderror_(this, &ChromeFrameActiveXContainer::OnLoadErrorCallback), | |
| 103 onload_(this, &ChromeFrameActiveXContainer::OnLoadCallback) { | |
| 104 } | |
| 105 | |
| 106 LRESULT OnCreate(UINT , WPARAM , LPARAM , BOOL& ) { | |
| 107 chromeview_.Attach(m_hWnd); | |
| 108 return 0; | |
| 109 } | |
| 110 | |
| 111 // This will be called twice. | |
| 112 // Once from CAxHostWindow::OnDestroy (through DefWindowProc) | |
| 113 // and once more from the ATL since CAxHostWindow::OnDestroy claims the | |
| 114 // message is not handled. | |
| 115 LRESULT OnDestroy(UINT, WPARAM, LPARAM, BOOL& handled) { // NOLINT | |
| 116 if (prop_notify_cookie_) { | |
| 117 AtlUnadvise(tab_, IID_IPropertyNotifySink, prop_notify_cookie_); | |
| 118 prop_notify_cookie_ = 0; | |
| 119 } | |
| 120 | |
| 121 tab_.Release(); | |
| 122 return 0; | |
| 123 } | |
| 124 | |
| 125 virtual void OnFinalMessage(HWND /*hWnd*/) { | |
| 126 ::PostQuitMessage(6); | |
| 127 } | |
| 128 | |
| 129 static const wchar_t* GetWndCaption() { | |
| 130 return L"ChromeFrame Container"; | |
| 131 } | |
| 132 | |
| 133 // IPropertyNotifySink | |
| 134 STDMETHOD(OnRequestEdit)(DISPID disp_id) { | |
| 135 OnRequestEditImpl(disp_id); | |
| 136 return S_OK; | |
| 137 } | |
| 138 | |
| 139 STDMETHOD(OnChanged)(DISPID disp_id) { | |
| 140 if (disp_id != DISPID_READYSTATE) | |
| 141 return S_OK; | |
| 142 | |
| 143 long ready_state; | |
| 144 HRESULT hr = tab_->get_readyState(&ready_state); | |
| 145 DCHECK(hr == S_OK); | |
| 146 | |
| 147 OnReadyStateChanged(ready_state); | |
| 148 | |
| 149 if (ready_state == READYSTATE_COMPLETE) { | |
| 150 if (!starting_url_.empty()) { | |
| 151 Navigate(starting_url_.c_str()); | |
| 152 } else { | |
| 153 PostMessage(WM_CLOSE); | |
| 154 } | |
| 155 } else if (ready_state == READYSTATE_UNINITIALIZED) { | |
| 156 DLOG(ERROR) << __FUNCTION__ << " Chrome launch failed."; | |
| 157 } | |
| 158 | |
| 159 return S_OK; | |
| 160 } | |
| 161 | |
| 162 void CreateChromeFrameWindow(const std::string& starting_url) { | |
| 163 starting_url_ = starting_url; | |
| 164 RECT rc = { 0, 0, 800, 600 }; | |
| 165 Create(NULL, rc); | |
| 166 DCHECK(m_hWnd); | |
| 167 ShowWindow(SW_SHOWDEFAULT); | |
| 168 } | |
| 169 | |
| 170 void CreateControl(bool setup_event_sinks) { | |
| 171 HRESULT hr = chromeview_.CreateControl(L"ChromeTab.ChromeFrame"); | |
| 172 EXPECT_HRESULT_SUCCEEDED(hr); | |
| 173 hr = chromeview_.QueryControl(tab_.Receive()); | |
| 174 EXPECT_HRESULT_SUCCEEDED(hr); | |
| 175 | |
| 176 if (setup_event_sinks) | |
| 177 SetupEventSinks(); | |
| 178 } | |
| 179 | |
| 180 void Navigate(const char* url) { | |
| 181 BeforeNavigateImpl(url); | |
| 182 | |
| 183 HRESULT hr = | |
| 184 tab_->put_src(base::win::ScopedBstr(base::UTF8ToWide(url).c_str())); | |
| 185 DCHECK(hr == S_OK) << "Chrome frame NavigateToURL(" << url | |
| 186 << base::StringPrintf(L") failed 0x%08X", hr); | |
| 187 } | |
| 188 | |
| 189 void SetupEventSinks() { | |
| 190 HRESULT hr = AtlAdvise(tab_, this, IID_IPropertyNotifySink, | |
| 191 &prop_notify_cookie_); | |
| 192 DCHECK(hr == S_OK) << "AtlAdvice for IPropertyNotifySink failed " << hr; | |
| 193 | |
| 194 base::win::ScopedVariant onmessage(onmsg_.ToDispatch()); | |
| 195 base::win::ScopedVariant onloaderror(onloaderror_.ToDispatch()); | |
| 196 base::win::ScopedVariant onload(onload_.ToDispatch()); | |
| 197 EXPECT_HRESULT_SUCCEEDED(tab_->put_onmessage(onmessage)); | |
| 198 EXPECT_HRESULT_SUCCEEDED(tab_->put_onloaderror(onloaderror)); | |
| 199 EXPECT_HRESULT_SUCCEEDED(tab_->put_onload(onload)); | |
| 200 } | |
| 201 | |
| 202 protected: | |
| 203 // These functions are implemented by derived classes for special behavior | |
| 204 // like performance measurement, etc. | |
| 205 virtual void OnReadyStateChanged(long ready_state) {} | |
| 206 virtual void OnRequestEditImpl(DISPID disp_id) {} | |
| 207 | |
| 208 virtual void OnMessageCallbackImpl(const VARIANT* param) {} | |
| 209 | |
| 210 virtual void OnLoadCallbackImpl(const VARIANT* param) { | |
| 211 PostMessage(WM_CLOSE); | |
| 212 } | |
| 213 | |
| 214 virtual void OnLoadErrorCallbackImpl(const VARIANT* param) { | |
| 215 PostMessage(WM_CLOSE); | |
| 216 } | |
| 217 virtual void BeforeNavigateImpl(const char* url) {} | |
| 218 | |
| 219 CAxWindow chromeview_; | |
| 220 base::win::ScopedComPtr<IChromeFrame> tab_; | |
| 221 DWORD prop_notify_cookie_; | |
| 222 DispCallback<ChromeFrameActiveXContainer> onmsg_; | |
| 223 DispCallback<ChromeFrameActiveXContainer> onloaderror_; | |
| 224 DispCallback<ChromeFrameActiveXContainer> onload_; | |
| 225 std::string starting_url_; | |
| 226 }; | |
| 227 | |
| 228 // This class overrides the hooks provided by the ChromeFrameActiveXContainer | |
| 229 // class and measures performance at various stages, like initialzation of | |
| 230 // the Chrome frame widget, navigation, etc. | |
| 231 class ChromeFrameActiveXContainerPerf : public ChromeFrameActiveXContainer { | |
| 232 public: | |
| 233 ChromeFrameActiveXContainerPerf() {} | |
| 234 | |
| 235 void CreateControl(bool setup_event_sinks) { | |
| 236 perf_initialize_.reset(new base::PerfTimeLogger("Fully initialized")); | |
| 237 base::PerfTimeLogger perf_create("Create Control"); | |
| 238 | |
| 239 HRESULT hr = chromeview_.CreateControl(L"ChromeTab.ChromeFrame"); | |
| 240 EXPECT_HRESULT_SUCCEEDED(hr); | |
| 241 hr = chromeview_.QueryControl(tab_.Receive()); | |
| 242 EXPECT_HRESULT_SUCCEEDED(hr); | |
| 243 | |
| 244 perf_create.Done(); | |
| 245 if (setup_event_sinks) | |
| 246 SetupEventSinks(); | |
| 247 } | |
| 248 | |
| 249 protected: | |
| 250 virtual void OnReadyStateChanged(long ready_state) { | |
| 251 // READYSTATE_COMPLETE is fired when the automation server is ready. | |
| 252 if (ready_state == READYSTATE_COMPLETE) { | |
| 253 perf_initialize_->Done(); | |
| 254 } else if (ready_state == READYSTATE_INTERACTIVE) { | |
| 255 // Window ready. Currently we never receive this notification because it | |
| 256 // is fired before we finish setting up our hosting environment. | |
| 257 // This is because of how ATL is written. Moving forward we might | |
| 258 // have our own hosting classes and then have more control over when we | |
| 259 // set up the prop notify sink. | |
| 260 } else { | |
| 261 DCHECK(ready_state != READYSTATE_UNINITIALIZED) << "failed to initialize"; | |
| 262 } | |
| 263 } | |
| 264 | |
| 265 virtual void OnLoadCallbackImpl(const VARIANT* param) { | |
| 266 PostMessage(WM_CLOSE); | |
| 267 perf_navigate_->Done(); | |
| 268 } | |
| 269 | |
| 270 virtual void OnLoadErrorCallbackImpl(const VARIANT* param) { | |
| 271 PostMessage(WM_CLOSE); | |
| 272 perf_navigate_->Done(); | |
| 273 } | |
| 274 | |
| 275 virtual void BeforeNavigateImpl(const char* url ) { | |
| 276 std::string test_name = "Navigate "; | |
| 277 test_name += url; | |
| 278 perf_navigate_.reset(new base::PerfTimeLogger(test_name.c_str())); | |
| 279 } | |
| 280 | |
| 281 scoped_ptr<base::PerfTimeLogger> perf_initialize_; | |
| 282 scoped_ptr<base::PerfTimeLogger> perf_navigate_; | |
| 283 }; | |
| 284 | |
| 285 // This class provides common functionality which can be used for most of the | |
| 286 // ChromeFrame/Tab performance tests. | |
| 287 class ChromeFramePerfTestBase : public UIPerfTest { | |
| 288 public: | |
| 289 ChromeFramePerfTestBase() {} | |
| 290 protected: | |
| 291 scoped_ptr<ScopedChromeFrameRegistrar> chrome_frame_registrar_; | |
| 292 }; | |
| 293 | |
| 294 class ChromeFrameStartupTest : public ChromeFramePerfTestBase { | |
| 295 public: | |
| 296 ChromeFrameStartupTest() {} | |
| 297 | |
| 298 virtual void SetUp() { | |
| 299 ASSERT_TRUE(PathService::Get(chrome::DIR_APP, &dir_app_)); | |
| 300 | |
| 301 chrome_dll_ = dir_app_.Append(L"chrome.dll"); | |
| 302 chrome_exe_ = dir_app_.Append(chrome::kBrowserProcessExecutableName); | |
| 303 chrome_frame_dll_ = dir_app_.Append(kChromeFrameDllName); | |
| 304 icu_dll_ = dir_app_.Append(L"icudt.dll"); | |
| 305 ffmpegsumo_dll_ = dir_app_.Append(L"ffmpegsumo.dll"); | |
| 306 } | |
| 307 | |
| 308 // TODO(iyengar) | |
| 309 // This function is similar to the RunStartupTest function used in chrome | |
| 310 // startup tests. Refactor into a common implementation. | |
| 311 void RunStartupTest(const char* graph, const char* trace, | |
| 312 const char* startup_url, bool test_cold, | |
| 313 int total_binaries, | |
| 314 const base::FilePath binaries_to_evict[], | |
| 315 bool important, bool ignore_cache_error) { | |
| 316 const int kNumCycles = 20; | |
| 317 | |
| 318 startup_url_ = startup_url; | |
| 319 | |
| 320 TimeDelta timings[kNumCycles]; | |
| 321 | |
| 322 for (int i = 0; i < kNumCycles; ++i) { | |
| 323 if (test_cold) { | |
| 324 for (int binary_index = 0; binary_index < total_binaries; | |
| 325 binary_index++) { | |
| 326 bool result = base::EvictFileFromSystemCacheWithRetry( | |
| 327 binaries_to_evict[binary_index]); | |
| 328 if (!ignore_cache_error) { | |
| 329 ASSERT_TRUE(result); | |
| 330 } else if (!result) { | |
| 331 LOG(ERROR) << GetLastError(); | |
| 332 printf("\nFailed to evict file %ls from cache. Not running test\n", | |
| 333 binaries_to_evict[binary_index].value().c_str()); | |
| 334 return; | |
| 335 } | |
| 336 } | |
| 337 } | |
| 338 | |
| 339 TimeTicks start_time, end_time; | |
| 340 | |
| 341 RunStartupTestImpl(&start_time, &end_time); | |
| 342 | |
| 343 timings[i] = end_time - start_time; | |
| 344 | |
| 345 CoFreeUnusedLibraries(); | |
| 346 | |
| 347 // TODO(beng): Can't shut down so quickly. Figure out why, and fix. If we | |
| 348 // do, we crash. | |
| 349 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(50)); | |
| 350 } | |
| 351 | |
| 352 std::string times; | |
| 353 for (int i = 0; i < kNumCycles; ++i) | |
| 354 base::StringAppendF(×, "%.2f,", timings[i].InMillisecondsF()); | |
| 355 | |
| 356 perf_test::PrintResultList(graph, "", trace, times, "ms", important); | |
| 357 } | |
| 358 | |
| 359 base::FilePath dir_app_; | |
| 360 base::FilePath chrome_dll_; | |
| 361 base::FilePath chrome_exe_; | |
| 362 base::FilePath chrome_frame_dll_; | |
| 363 base::FilePath icu_dll_; | |
| 364 base::FilePath ffmpegsumo_dll_; | |
| 365 | |
| 366 protected: | |
| 367 // Individual startup tests should implement this function. | |
| 368 virtual void RunStartupTestImpl(TimeTicks* start_time, | |
| 369 TimeTicks* end_time) {} | |
| 370 | |
| 371 // The host is torn down by this function. It should not be used after | |
| 372 // this function returns. | |
| 373 static void ReleaseHostComReferences(CAxWindow& host) { | |
| 374 CComPtr<IAxWinHostWindow> spWinHost; | |
| 375 host.QueryHost(&spWinHost); | |
| 376 ASSERT_TRUE(spWinHost != NULL); | |
| 377 | |
| 378 // Hack to get the host to release all interfaces and thus ensure that | |
| 379 // the COM server can be unloaded. | |
| 380 CAxHostWindow* host_window = static_cast<CAxHostWindow*>(spWinHost.p); | |
| 381 host_window->ReleaseAll(); | |
| 382 host.DestroyWindow(); | |
| 383 } | |
| 384 | |
| 385 std::string startup_url_; | |
| 386 }; | |
| 387 | |
| 388 class ChromeFrameStartupTestActiveX : public ChromeFrameStartupTest { | |
| 389 public: | |
| 390 virtual void SetUp() { | |
| 391 // Register the Chrome Frame DLL in the build directory. | |
| 392 chrome_frame_registrar_.reset(new ScopedChromeFrameRegistrar( | |
| 393 ScopedChromeFrameRegistrar::SYSTEM_LEVEL)); | |
| 394 | |
| 395 ChromeFrameStartupTest::SetUp(); | |
| 396 } | |
| 397 | |
| 398 protected: | |
| 399 virtual void RunStartupTestImpl(TimeTicks* start_time, | |
| 400 TimeTicks* end_time) { | |
| 401 *start_time = TimeTicks::Now(); | |
| 402 SimpleModule module; | |
| 403 AtlAxWinInit(); | |
| 404 CComObjectStackEx<ChromeFrameActiveXContainer> wnd; | |
| 405 wnd.CreateChromeFrameWindow(startup_url_); | |
| 406 wnd.CreateControl(true); | |
| 407 module.RunMessageLoop(); | |
| 408 *end_time = TimeTicks::Now(); | |
| 409 } | |
| 410 }; | |
| 411 | |
| 412 // This class measures the load time of chrome and chrome frame binaries | |
| 413 class ChromeFrameBinariesLoadTest : public ChromeFrameStartupTestActiveX { | |
| 414 static const size_t kStepSize = 4 * 1024; | |
| 415 public: | |
| 416 enum PreReadType { | |
| 417 kPreReadNone, | |
| 418 kPreReadPartial, | |
| 419 kPreReadFull | |
| 420 }; | |
| 421 | |
| 422 ChromeFrameBinariesLoadTest() | |
| 423 : pre_read_type_(kPreReadNone), | |
| 424 step_size_(kStepSize), | |
| 425 bytes_to_read_(0), | |
| 426 percentage_to_preread_(25) {} | |
| 427 | |
| 428 protected: | |
| 429 virtual void RunStartupTestImpl(TimeTicks* start_time, | |
| 430 TimeTicks* end_time) { | |
| 431 *start_time = TimeTicks::Now(); | |
| 432 | |
| 433 if (pre_read_type_ == kPreReadFull) { | |
| 434 EXPECT_TRUE(ImagePreReader::PreReadImage(chrome_exe_.value().c_str(), | |
| 435 bytes_to_read_, | |
| 436 step_size_)); | |
| 437 EXPECT_TRUE(ImagePreReader::PreReadImage(chrome_dll_.value().c_str(), | |
| 438 bytes_to_read_, | |
| 439 step_size_)); | |
| 440 } else if (pre_read_type_ == kPreReadPartial) { | |
| 441 EXPECT_TRUE( | |
| 442 ImagePreReader::PartialPreReadImage(chrome_exe_.value().c_str(), | |
| 443 percentage_to_preread_, | |
| 444 step_size_)); | |
| 445 EXPECT_TRUE( | |
| 446 ImagePreReader::PartialPreReadImage(chrome_dll_.value().c_str(), | |
| 447 percentage_to_preread_, | |
| 448 step_size_)); | |
| 449 } | |
| 450 | |
| 451 HMODULE chrome_exe = LoadLibrary(chrome_exe_.value().c_str()); | |
| 452 EXPECT_TRUE(chrome_exe != NULL); | |
| 453 | |
| 454 HMODULE chrome_dll = LoadLibrary(chrome_dll_.value().c_str()); | |
| 455 EXPECT_TRUE(chrome_dll != NULL); | |
| 456 | |
| 457 *end_time = TimeTicks::Now(); | |
| 458 | |
| 459 FreeLibrary(chrome_exe); | |
| 460 FreeLibrary(chrome_dll); | |
| 461 } | |
| 462 | |
| 463 PreReadType pre_read_type_; | |
| 464 size_t bytes_to_read_; | |
| 465 size_t step_size_; | |
| 466 uint8 percentage_to_preread_; | |
| 467 }; | |
| 468 | |
| 469 // This class provides functionality to run the startup performance test for | |
| 470 // the ChromeFrame ActiveX against a reference build. At this point we only run | |
| 471 // this test in warm mode. | |
| 472 class ChromeFrameStartupTestActiveXReference | |
| 473 : public ChromeFrameStartupTestActiveX { | |
| 474 public: | |
| 475 // override the browser directory to use the reference build instead. | |
| 476 virtual void SetUp() { | |
| 477 // Register the reference build Chrome Frame DLL. | |
| 478 chrome_frame_registrar_.reset(new ScopedChromeFrameRegistrar( | |
| 479 ScopedChromeFrameRegistrar::SYSTEM_LEVEL)); | |
| 480 chrome_frame_registrar_->RegisterReferenceChromeFrameBuild(); | |
| 481 | |
| 482 ChromeFrameStartupTest::SetUp(); | |
| 483 | |
| 484 chrome_frame_dll_ = base::FilePath( | |
| 485 chrome_frame_registrar_->GetReferenceChromeFrameDllPath()); | |
| 486 DVLOG(1) << __FUNCTION__ << ": " << chrome_frame_dll_.value(); | |
| 487 } | |
| 488 | |
| 489 virtual void TearDown() { | |
| 490 // Reregister the Chrome Frame DLL in the build directory. | |
| 491 chrome_frame_registrar_.reset(NULL); | |
| 492 } | |
| 493 }; | |
| 494 | |
| 495 // This class provides base functionality to measure ChromeFrame memory | |
| 496 // usage. | |
| 497 // TODO(iyengar) | |
| 498 // Some of the functionality in this class like printing the results, etc | |
| 499 // is based on the chrome\test\memory_test.cc. We need to factor out | |
| 500 // the common code. | |
| 501 class ChromeFrameMemoryTest : public ChromeFramePerfTestBase { | |
| 502 // Contains information about the memory consumption of a process. | |
| 503 class ProcessMemoryInfo { | |
| 504 public: | |
| 505 // Default constructor | |
| 506 // Added to enable us to add ProcessMemoryInfo instances to a map. | |
| 507 ProcessMemoryInfo() | |
| 508 : process_id_(0), | |
| 509 virtual_size_(0), | |
| 510 working_set_size_(0), | |
| 511 chrome_browser_process_(false), | |
| 512 chrome_frame_memory_test_instance_(NULL) {} | |
| 513 | |
| 514 ProcessMemoryInfo(base::ProcessId process_id, bool chrome_browser_process, | |
| 515 ChromeFrameMemoryTest* memory_test_instance) | |
| 516 : process_id_(process_id), | |
| 517 virtual_size_(0), | |
| 518 working_set_size_(0), | |
| 519 chrome_browser_process_(chrome_browser_process), | |
| 520 chrome_frame_memory_test_instance_(memory_test_instance) {} | |
| 521 | |
| 522 bool GetMemoryConsumptionDetails() { | |
| 523 base::ProcessHandle process_handle; | |
| 524 if (!base::OpenPrivilegedProcessHandle(process_id_, &process_handle)) { | |
| 525 NOTREACHED(); | |
| 526 } | |
| 527 | |
| 528 // TODO(sgk): if/when base::ProcessMetrics can return real memory | |
| 529 // stats on mac, convert to: | |
| 530 // | |
| 531 // scoped_ptr<base::ProcessMetrics> process_metrics; | |
| 532 // process_metrics.reset( | |
| 533 // base::ProcessMetrics::CreateProcessMetrics(process_handle)); | |
| 534 scoped_ptr<ChromeTestProcessMetrics> process_metrics; | |
| 535 process_metrics.reset( | |
| 536 ChromeTestProcessMetrics::CreateProcessMetrics(process_handle)); | |
| 537 | |
| 538 virtual_size_ = process_metrics->GetPagefileUsage(); | |
| 539 working_set_size_ = process_metrics->GetWorkingSetSize(); | |
| 540 | |
| 541 base::CloseProcessHandle(process_handle); | |
| 542 return true; | |
| 543 } | |
| 544 | |
| 545 void Print(const char* test_name) { | |
| 546 std::string trace_name(test_name); | |
| 547 | |
| 548 ASSERT_TRUE(chrome_frame_memory_test_instance_ != NULL); | |
| 549 | |
| 550 if (chrome_browser_process_) { | |
| 551 perf_test::PrintResult("vm_final_browser", "", trace_name + "_vm_b", | |
| 552 virtual_size_ / 1024, "KB", false /* not important */); | |
| 553 perf_test::PrintResult("ws_final_browser", "", trace_name + "_ws_b", | |
| 554 working_set_size_ / 1024, "KB", false /* not important */); | |
| 555 } else if (process_id_ == base::GetCurrentProcId()) { | |
| 556 perf_test::PrintResult("vm_current_process", "", trace_name + "_vm_c", | |
| 557 virtual_size_ / 1024, "KB", false /* not important */); | |
| 558 perf_test::PrintResult("ws_current_process", "", trace_name + "_ws_c", | |
| 559 working_set_size_ / 1024, "KB", false /* not important */); | |
| 560 } | |
| 561 | |
| 562 printf("\n"); | |
| 563 } | |
| 564 | |
| 565 base::ProcessId process_id_; | |
| 566 size_t virtual_size_; | |
| 567 size_t working_set_size_; | |
| 568 // Set to true if this is the chrome browser process. | |
| 569 bool chrome_browser_process_; | |
| 570 | |
| 571 // A reference to the ChromeFrameMemoryTest instance. Used to print memory | |
| 572 // consumption information. | |
| 573 ChromeFrameMemoryTest* chrome_frame_memory_test_instance_; | |
| 574 }; | |
| 575 | |
| 576 // This map tracks memory usage for a process. It is keyed on the process | |
| 577 // id. | |
| 578 typedef std::map<DWORD, ProcessMemoryInfo> ProcessMemoryConsumptionMap; | |
| 579 | |
| 580 public: | |
| 581 ChromeFrameMemoryTest() : current_url_index_(0) { | |
| 582 } | |
| 583 | |
| 584 virtual void SetUp() { | |
| 585 // Register the Chrome Frame DLL in the build directory. | |
| 586 chrome_frame_registrar_.reset(new ScopedChromeFrameRegistrar( | |
| 587 ScopedChromeFrameRegistrar::SYSTEM_LEVEL)); | |
| 588 } | |
| 589 | |
| 590 void RunTest(const char* test_name, char* urls[], int total_urls) { | |
| 591 ASSERT_TRUE(urls != NULL); | |
| 592 ASSERT_GT(total_urls, 0); | |
| 593 | |
| 594 // Record the initial CommitCharge. This is a system-wide measurement, | |
| 595 // so if other applications are running, they can create variance in this | |
| 596 // test. | |
| 597 start_commit_charge_ = base::GetSystemCommitCharge(); | |
| 598 | |
| 599 for (int i = 0; i < total_urls; i++) | |
| 600 urls_.push_back(urls[i]); | |
| 601 | |
| 602 std::string url; | |
| 603 GetNextUrl(&url); | |
| 604 ASSERT_TRUE(!url.empty()); | |
| 605 | |
| 606 StartTest(url, test_name); | |
| 607 } | |
| 608 | |
| 609 void OnNavigationSuccess(const VARIANT* param) { | |
| 610 ASSERT_TRUE(param != NULL); | |
| 611 ASSERT_EQ(VT_BSTR, param->vt); | |
| 612 | |
| 613 DVLOG(1) << __FUNCTION__ << " " << param->bstrVal; | |
| 614 InitiateNextNavigation(); | |
| 615 } | |
| 616 | |
| 617 void OnNavigationFailure(const VARIANT* param) { | |
| 618 ASSERT_TRUE(param != NULL); | |
| 619 ASSERT_EQ(VT_BSTR, param->vt); | |
| 620 | |
| 621 DVLOG(1) << __FUNCTION__ << " " << param->bstrVal; | |
| 622 InitiateNextNavigation(); | |
| 623 } | |
| 624 | |
| 625 protected: | |
| 626 bool GetNextUrl(std::string* url) { | |
| 627 if (current_url_index_ >= urls_.size()) | |
| 628 return false; | |
| 629 | |
| 630 *url = urls_[current_url_index_++]; | |
| 631 return true; | |
| 632 } | |
| 633 | |
| 634 void InitiateNextNavigation() { | |
| 635 // Get the memory consumption information for the child processes | |
| 636 // of the chrome browser. | |
| 637 ChromeProcessList child_processes = GetBrowserChildren(); | |
| 638 ChromeProcessList::iterator index; | |
| 639 for (index = child_processes.begin(); index != child_processes.end(); | |
| 640 ++index) { | |
| 641 AccountProcessMemoryUsage(*index); | |
| 642 } | |
| 643 | |
| 644 // TODO(iyengar): Bug 2953 | |
| 645 // Need to verify if this is still true. | |
| 646 // The automation crashes periodically if we cycle too quickly. | |
| 647 // To make these tests more reliable, slowing them down a bit. | |
| 648 Sleep(200); | |
| 649 | |
| 650 std::string url; | |
| 651 bool next_url = GetNextUrl(&url); | |
| 652 if (!url.empty()) { | |
| 653 NavigateImpl(url); | |
| 654 } else { | |
| 655 TestCompleted(); | |
| 656 } | |
| 657 } | |
| 658 | |
| 659 void PrintResults(const char* test_name) { | |
| 660 PrintMemoryUsageInfo(test_name); | |
| 661 memory_consumption_map_.clear(); | |
| 662 | |
| 663 // Added to give the OS some time to flush the used pages for the | |
| 664 // chrome processes which would have exited by now. | |
| 665 Sleep(200); | |
| 666 | |
| 667 size_t end_commit_charge = base::GetSystemCommitCharge(); | |
| 668 size_t commit_size = (end_commit_charge - start_commit_charge_) * 1024; | |
| 669 | |
| 670 std::string trace_name(test_name); | |
| 671 trace_name.append("_cc"); | |
| 672 | |
| 673 perf_test::PrintResult("commit_charge", "", trace_name, | |
| 674 commit_size / 1024, "KB", true /* important */); | |
| 675 printf("\n"); | |
| 676 } | |
| 677 | |
| 678 base::ProcessId chrome_browser_process_id() { | |
| 679 base::NamedProcessIterator iter(L"chrome.exe", NULL); | |
| 680 const base::ProcessEntry* entry = iter.NextProcessEntry(); | |
| 681 if (entry) { | |
| 682 return entry->pid(); | |
| 683 } | |
| 684 return -1; | |
| 685 } | |
| 686 | |
| 687 ChromeProcessList GetBrowserChildren() { | |
| 688 ChromeProcessList list = GetRunningChromeProcesses( | |
| 689 chrome_browser_process_id()); | |
| 690 ChromeProcessList::iterator browser = | |
| 691 std::find(list.begin(), list.end(), chrome_browser_process_id()); | |
| 692 if (browser != list.end()) { | |
| 693 list.erase(browser); | |
| 694 } | |
| 695 return list; | |
| 696 } | |
| 697 | |
| 698 void AccountProcessMemoryUsage(DWORD process_id) { | |
| 699 ProcessMemoryInfo process_memory_info( | |
| 700 process_id, process_id == chrome_browser_process_id(), this); | |
| 701 | |
| 702 ASSERT_TRUE(process_memory_info.GetMemoryConsumptionDetails()); | |
| 703 | |
| 704 memory_consumption_map_[process_id] = process_memory_info; | |
| 705 } | |
| 706 | |
| 707 void PrintMemoryUsageInfo(const char* test_name) { | |
| 708 printf("\n"); | |
| 709 | |
| 710 std::string trace_name(test_name); | |
| 711 | |
| 712 ProcessMemoryConsumptionMap::iterator index; | |
| 713 size_t total_virtual_size = 0; | |
| 714 size_t total_working_set_size = 0; | |
| 715 | |
| 716 for (index = memory_consumption_map_.begin(); | |
| 717 index != memory_consumption_map_.end(); | |
| 718 ++index) { | |
| 719 ProcessMemoryInfo& memory_info = (*index).second; | |
| 720 memory_info.Print(test_name); | |
| 721 | |
| 722 total_virtual_size += memory_info.virtual_size_; | |
| 723 total_working_set_size += memory_info.working_set_size_; | |
| 724 } | |
| 725 | |
| 726 printf("\n"); | |
| 727 | |
| 728 perf_test::PrintResult("vm_final_total", "", trace_name + "_vm", | |
| 729 total_virtual_size / 1024, "KB", | |
| 730 false /* not important */); | |
| 731 perf_test::PrintResult("ws_final_total", "", trace_name + "_ws", | |
| 732 total_working_set_size / 1024, "KB", | |
| 733 true /* important */); | |
| 734 } | |
| 735 | |
| 736 // Should never get called. | |
| 737 virtual void StartTest(const std::string& url, | |
| 738 const std::string& test_name) = 0 { | |
| 739 ASSERT_FALSE(false); | |
| 740 } | |
| 741 | |
| 742 // Should never get called. | |
| 743 virtual void NavigateImpl(const std::string& url) = 0 { | |
| 744 ASSERT_FALSE(false); | |
| 745 } | |
| 746 | |
| 747 virtual void TestCompleted() = 0 { | |
| 748 ASSERT_FALSE(false); | |
| 749 } | |
| 750 | |
| 751 // Holds the commit charge in KBytes at the start of the memory test run. | |
| 752 size_t start_commit_charge_; | |
| 753 | |
| 754 // The index of the URL being tested. | |
| 755 size_t current_url_index_; | |
| 756 | |
| 757 // Contains the list of urls against which the tests are run. | |
| 758 std::vector<std::string> urls_; | |
| 759 | |
| 760 ProcessMemoryConsumptionMap memory_consumption_map_; | |
| 761 }; | |
| 762 | |
| 763 // This class provides functionality to run the memory test against a reference | |
| 764 // chrome frame build. | |
| 765 class ChromeFrameMemoryTestReference : public ChromeFrameMemoryTest { | |
| 766 public: | |
| 767 virtual void SetUp() { | |
| 768 chrome_frame_registrar_.reset(new ScopedChromeFrameRegistrar( | |
| 769 ScopedChromeFrameRegistrar::SYSTEM_LEVEL)); | |
| 770 chrome_frame_registrar_->RegisterReferenceChromeFrameBuild(); | |
| 771 } | |
| 772 | |
| 773 virtual void TearDown() { | |
| 774 // Reregisters the chrome frame DLL in the build directory. | |
| 775 chrome_frame_registrar_.reset(NULL); | |
| 776 } | |
| 777 }; | |
| 778 | |
| 779 // This class overrides the hooks provided by the ChromeFrameActiveXContainer | |
| 780 // class and calls back into the ChromeFrameMemoryTest object instance, | |
| 781 // which measures ChromeFrame memory usage. | |
| 782 class ChromeFrameActiveXContainerMemory : public ChromeFrameActiveXContainer { | |
| 783 public: | |
| 784 ChromeFrameActiveXContainerMemory() | |
| 785 : delegate_(NULL) {} | |
| 786 | |
| 787 ~ChromeFrameActiveXContainerMemory() {} | |
| 788 | |
| 789 void Initialize(ChromeFrameMemoryTest* delegate) { | |
| 790 ASSERT_TRUE(delegate != NULL); | |
| 791 delegate_ = delegate; | |
| 792 } | |
| 793 | |
| 794 protected: | |
| 795 virtual void OnLoadCallbackImpl(const VARIANT* param) { | |
| 796 delegate_->OnNavigationSuccess(param); | |
| 797 } | |
| 798 | |
| 799 virtual void OnLoadErrorCallbackImpl(const VARIANT* param) { | |
| 800 delegate_->OnNavigationFailure(param); | |
| 801 } | |
| 802 | |
| 803 ChromeFrameMemoryTest* delegate_; | |
| 804 }; | |
| 805 | |
| 806 // This class runs memory tests against the ChromeFrame ActiveX. | |
| 807 template<class MemoryTestBase> | |
| 808 class ChromeFrameActiveXMemoryTest : public MemoryTestBase { | |
| 809 public: | |
| 810 ChromeFrameActiveXMemoryTest() | |
| 811 : chrome_frame_container_(NULL), | |
| 812 test_completed_(false) {} | |
| 813 | |
| 814 ~ChromeFrameActiveXMemoryTest() { | |
| 815 } | |
| 816 | |
| 817 void StartTest(const std::string& url, const std::string& test_name) { | |
| 818 ASSERT_TRUE(chrome_frame_container_ == NULL); | |
| 819 | |
| 820 test_name_ = test_name; | |
| 821 | |
| 822 SimpleModule module; | |
| 823 AtlAxWinInit(); | |
| 824 | |
| 825 CComObject<ChromeFrameActiveXContainerMemory>::CreateInstance( | |
| 826 &chrome_frame_container_); | |
| 827 chrome_frame_container_->AddRef(); | |
| 828 | |
| 829 chrome_frame_container_->Initialize(this); | |
| 830 | |
| 831 chrome_frame_container_->CreateChromeFrameWindow(url.c_str()); | |
| 832 chrome_frame_container_->CreateControl(true); | |
| 833 | |
| 834 module.RunMessageLoop(); | |
| 835 | |
| 836 chrome_frame_container_->Release(); | |
| 837 | |
| 838 PrintResults(test_name_.c_str()); | |
| 839 | |
| 840 CoFreeUnusedLibraries(); | |
| 841 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100)); | |
| 842 } | |
| 843 | |
| 844 void NavigateImpl(const std::string& url) { | |
| 845 ASSERT_TRUE(chrome_frame_container_ != NULL); | |
| 846 ASSERT_TRUE(!url.empty()); | |
| 847 chrome_frame_container_->Navigate(url.c_str()); | |
| 848 } | |
| 849 | |
| 850 void TestCompleted() { | |
| 851 // This can get called multiple times if the last url results in a | |
| 852 // redirect. | |
| 853 if (!test_completed_) { | |
| 854 // Measure memory usage for the browser process. | |
| 855 AccountProcessMemoryUsage(chrome_browser_process_id()); | |
| 856 // Measure memory usage for the current process. | |
| 857 AccountProcessMemoryUsage(GetCurrentProcessId()); | |
| 858 | |
| 859 test_completed_ = true; | |
| 860 EXPECT_TRUE(PostMessage(static_cast<HWND>(*chrome_frame_container_), | |
| 861 WM_CLOSE, 0, 0)); | |
| 862 } | |
| 863 } | |
| 864 | |
| 865 protected: | |
| 866 CComObject<ChromeFrameActiveXContainerMemory>* chrome_frame_container_; | |
| 867 std::string test_name_; | |
| 868 bool test_completed_; | |
| 869 }; | |
| 870 | |
| 871 // This class runs tests to measure chrome frame creation only. This will help | |
| 872 // track overall page load performance with chrome frame instances. | |
| 873 class ChromeFrameCreationTest : public ChromeFrameStartupTest { | |
| 874 protected: | |
| 875 virtual void RunStartupTestImpl(TimeTicks* start_time, | |
| 876 TimeTicks* end_time) { | |
| 877 SimpleModule module; | |
| 878 AtlAxWinInit(); | |
| 879 CComObjectStackEx<ChromeFrameActiveXContainer> wnd; | |
| 880 wnd.CreateChromeFrameWindow(startup_url_); | |
| 881 *start_time = TimeTicks::Now(); | |
| 882 wnd.CreateControl(false); | |
| 883 *end_time = TimeTicks::Now(); | |
| 884 } | |
| 885 }; | |
| 886 | |
| 887 // This class provides functionality to run the chrome frame | |
| 888 // performance test against a reference build. | |
| 889 class ChromeFrameCreationTestReference : public ChromeFrameCreationTest { | |
| 890 public: | |
| 891 // override the browser directory to use the reference build instead. | |
| 892 virtual void SetUp() { | |
| 893 chrome_frame_registrar_.reset(new ScopedChromeFrameRegistrar( | |
| 894 ScopedChromeFrameRegistrar::SYSTEM_LEVEL)); | |
| 895 chrome_frame_registrar_->RegisterReferenceChromeFrameBuild(); | |
| 896 ChromeFrameStartupTest::SetUp(); | |
| 897 } | |
| 898 | |
| 899 virtual void TearDown() { | |
| 900 chrome_frame_registrar_.reset(NULL); | |
| 901 } | |
| 902 }; | |
| 903 | |
| 904 // This class measures the creation time for Flash, which would be used | |
| 905 // as a baseline to measure chrome frame creation performance. | |
| 906 class FlashCreationTest : public ChromeFrameStartupTest { | |
| 907 protected: | |
| 908 virtual void RunStartupTestImpl(TimeTicks* start_time, | |
| 909 TimeTicks* end_time) { | |
| 910 SimpleModule module; | |
| 911 AtlAxWinInit(); | |
| 912 CAxWindow host; | |
| 913 RECT rc = {0, 0, 800, 600}; | |
| 914 host.Create(NULL, rc, NULL, | |
| 915 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, | |
| 916 WS_EX_APPWINDOW | WS_EX_WINDOWEDGE); | |
| 917 EXPECT_TRUE(host.m_hWnd != NULL); | |
| 918 | |
| 919 *start_time = TimeTicks::Now(); | |
| 920 HRESULT hr = host.CreateControl(L"ShockwaveFlash.ShockwaveFlash"); | |
| 921 EXPECT_HRESULT_SUCCEEDED(hr); | |
| 922 *end_time = TimeTicks::Now(); | |
| 923 | |
| 924 ReleaseHostComReferences(host); | |
| 925 } | |
| 926 }; | |
| 927 | |
| 928 // This class measures the creation time for Silverlight, which would be used | |
| 929 // as a baseline to measure chrome frame creation performance. | |
| 930 class SilverlightCreationTest : public ChromeFrameStartupTest { | |
| 931 protected: | |
| 932 virtual void RunStartupTestImpl(TimeTicks* start_time, | |
| 933 TimeTicks* end_time) { | |
| 934 SimpleModule module; | |
| 935 AtlAxWinInit(); | |
| 936 CAxWindow host; | |
| 937 RECT rc = {0, 0, 800, 600}; | |
| 938 host.Create(NULL, rc, NULL, | |
| 939 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, | |
| 940 WS_EX_APPWINDOW | WS_EX_WINDOWEDGE); | |
| 941 EXPECT_TRUE(host.m_hWnd != NULL); | |
| 942 | |
| 943 *start_time = TimeTicks::Now(); | |
| 944 HRESULT hr = host.CreateControl(L"AgControl.AgControl"); | |
| 945 EXPECT_HRESULT_SUCCEEDED(hr); | |
| 946 *end_time = TimeTicks::Now(); | |
| 947 | |
| 948 ReleaseHostComReferences(host); | |
| 949 } | |
| 950 }; | |
| 951 | |
| 952 // TODO(rogerm): Flesh out the *PreReadImage* tests to validate an observed | |
| 953 // change in paging behaviour between raw loading and pre-reading. | |
| 954 | |
| 955 // TODO(rogerm): Add checks to the *PreReadImage* tests to validate the | |
| 956 // handling of invalid pe files and paths as input. | |
| 957 | |
| 958 TEST(ImagePreReader, PreReadImage) { | |
| 959 base::FilePath current_exe; | |
| 960 ASSERT_TRUE(PathService::Get(base::FILE_EXE, ¤t_exe)); | |
| 961 | |
| 962 int64 file_size_64 = 0; | |
| 963 ASSERT_TRUE(base::GetFileSize(current_exe, &file_size_64)); | |
| 964 ASSERT_TRUE(file_size_64 < std::numeric_limits<std::size_t>::max()); | |
| 965 size_t file_size = static_cast<size_t>(file_size_64); | |
| 966 | |
| 967 const wchar_t* module_path = current_exe.value().c_str(); | |
| 968 const size_t kStepSize = 2 * 1024 * 1024; | |
| 969 | |
| 970 ASSERT_TRUE( | |
| 971 ImagePreReader::PreReadImage(module_path, 0, kStepSize)); | |
| 972 ASSERT_TRUE( | |
| 973 ImagePreReader::PreReadImage(module_path, file_size / 4, kStepSize)); | |
| 974 ASSERT_TRUE( | |
| 975 ImagePreReader::PreReadImage(module_path, file_size / 2, kStepSize)); | |
| 976 ASSERT_TRUE( | |
| 977 ImagePreReader::PreReadImage(module_path, file_size, kStepSize)); | |
| 978 ASSERT_TRUE( | |
| 979 ImagePreReader::PreReadImage(module_path, file_size * 2, kStepSize)); | |
| 980 } | |
| 981 | |
| 982 TEST(ImagePreReader, PartialPreReadImage) { | |
| 983 base::FilePath current_exe; | |
| 984 ASSERT_TRUE(PathService::Get(base::FILE_EXE, ¤t_exe)); | |
| 985 | |
| 986 const wchar_t* module_path = current_exe.value().c_str(); | |
| 987 const size_t kStepSize = 2 * 1024 * 1024; | |
| 988 | |
| 989 ASSERT_TRUE( | |
| 990 ImagePreReader::PartialPreReadImage(module_path, 0, kStepSize)); | |
| 991 ASSERT_TRUE( | |
| 992 ImagePreReader::PartialPreReadImage(module_path, 25, kStepSize)); | |
| 993 ASSERT_TRUE( | |
| 994 ImagePreReader::PartialPreReadImage(module_path, 50, kStepSize)); | |
| 995 ASSERT_TRUE( | |
| 996 ImagePreReader::PartialPreReadImage(module_path, 100, kStepSize)); | |
| 997 ASSERT_TRUE( | |
| 998 ImagePreReader::PartialPreReadImage(module_path, 150, kStepSize)); | |
| 999 } | |
| 1000 | |
| 1001 TEST(ImagePreReader, PartialPreReadImageOnDisk) { | |
| 1002 base::FilePath current_exe; | |
| 1003 ASSERT_TRUE(PathService::Get(base::FILE_EXE, ¤t_exe)); | |
| 1004 | |
| 1005 const wchar_t* module_path = current_exe.value().c_str(); | |
| 1006 const size_t kChunkSize = 2 * 1024 * 1024; | |
| 1007 | |
| 1008 ASSERT_TRUE( | |
| 1009 ImagePreReader::PartialPreReadImageOnDisk(module_path, 0, kChunkSize)); | |
| 1010 ASSERT_TRUE( | |
| 1011 ImagePreReader::PartialPreReadImageOnDisk(module_path, 25, kChunkSize)); | |
| 1012 ASSERT_TRUE( | |
| 1013 ImagePreReader::PartialPreReadImageOnDisk(module_path, 50, kChunkSize)); | |
| 1014 ASSERT_TRUE( | |
| 1015 ImagePreReader::PartialPreReadImageOnDisk(module_path, 100, kChunkSize)); | |
| 1016 ASSERT_TRUE( | |
| 1017 ImagePreReader::PartialPreReadImageOnDisk(module_path, 150, kChunkSize)); | |
| 1018 } | |
| 1019 | |
| 1020 TEST(ImagePreReader, PartialPreReadImageInMemory) { | |
| 1021 base::FilePath current_exe; | |
| 1022 ASSERT_TRUE(PathService::Get(base::FILE_EXE, ¤t_exe)); | |
| 1023 const wchar_t* module_path = current_exe.value().c_str(); | |
| 1024 | |
| 1025 ASSERT_TRUE( | |
| 1026 ImagePreReader::PartialPreReadImageInMemory(module_path, 0)); | |
| 1027 ASSERT_TRUE( | |
| 1028 ImagePreReader::PartialPreReadImageInMemory(module_path, 25)); | |
| 1029 ASSERT_TRUE( | |
| 1030 ImagePreReader::PartialPreReadImageInMemory(module_path, 50)); | |
| 1031 ASSERT_TRUE( | |
| 1032 ImagePreReader::PartialPreReadImageInMemory(module_path, 100)); | |
| 1033 ASSERT_TRUE( | |
| 1034 ImagePreReader::PartialPreReadImageInMemory(module_path, 150)); | |
| 1035 } | |
| 1036 | |
| 1037 TEST(ChromeFramePerf, DISABLED_HostActiveX) { | |
| 1038 // TODO(stoyan): Create a low integrity level thread && perform the test there | |
| 1039 SimpleModule module; | |
| 1040 AtlAxWinInit(); | |
| 1041 CComObjectStackEx<ChromeFrameActiveXContainerPerf> wnd; | |
| 1042 wnd.CreateChromeFrameWindow("http://www.google.com"); | |
| 1043 wnd.CreateControl(true); | |
| 1044 module.RunMessageLoop(); | |
| 1045 } | |
| 1046 | |
| 1047 TEST(ChromeFramePerf, DISABLED_HostActiveXInvalidURL) { | |
| 1048 // TODO(stoyan): Create a low integrity level thread && perform the test there | |
| 1049 SimpleModule module; | |
| 1050 AtlAxWinInit(); | |
| 1051 CComObjectStackEx<ChromeFrameActiveXContainerPerf> wnd; | |
| 1052 wnd.CreateChromeFrameWindow("http://non-existent-domain.org/"); | |
| 1053 wnd.CreateControl(true); | |
| 1054 module.RunMessageLoop(); | |
| 1055 } | |
| 1056 | |
| 1057 TEST_F(ChromeFrameStartupTestActiveX, PerfWarm) { | |
| 1058 RunStartupTest("warm", "t", "about:blank", false /* cold */, 0, NULL, | |
| 1059 true /* important */, false); | |
| 1060 } | |
| 1061 | |
| 1062 TEST_F(ChromeFrameBinariesLoadTest, PerfWarm) { | |
| 1063 RunStartupTest("binary_load_warm", "t", "", false /* cold */, 0, NULL, | |
| 1064 true /* important */, false); | |
| 1065 } | |
| 1066 | |
| 1067 TEST_F(ChromeFrameStartupTestActiveX, PerfCold) { | |
| 1068 SetConfigInt(L"PreRead", 0); | |
| 1069 base::FilePath binaries_to_evict[] = { | |
| 1070 ffmpegsumo_dll_, chrome_exe_, chrome_dll_, chrome_frame_dll_ | |
| 1071 }; | |
| 1072 RunStartupTest("cold", "t", "about:blank", true /* cold */, | |
| 1073 arraysize(binaries_to_evict), binaries_to_evict, | |
| 1074 false /* not important */, false); | |
| 1075 DeleteConfigValue(L"PreRead"); | |
| 1076 } | |
| 1077 | |
| 1078 TEST_F(ChromeFrameStartupTestActiveX, PerfColdPreRead) { | |
| 1079 SetConfigInt(L"PreRead", 1); | |
| 1080 base::FilePath binaries_to_evict[] = { | |
| 1081 ffmpegsumo_dll_, chrome_exe_, chrome_dll_, chrome_frame_dll_ | |
| 1082 }; | |
| 1083 RunStartupTest("cold_preread", "t", "about:blank", true /* cold */, | |
| 1084 arraysize(binaries_to_evict), binaries_to_evict, | |
| 1085 false /* not important */, false); | |
| 1086 DeleteConfigValue(L"PreRead"); | |
| 1087 } | |
| 1088 | |
| 1089 TEST_F(ChromeFrameBinariesLoadTest, PerfCold) { | |
| 1090 base::FilePath binaries_to_evict[] = {chrome_exe_, chrome_dll_}; | |
| 1091 RunStartupTest("binary_load_cold", "t", "", true /* cold */, | |
| 1092 arraysize(binaries_to_evict), binaries_to_evict, | |
| 1093 false /* not important */, false); | |
| 1094 } | |
| 1095 | |
| 1096 TEST_F(ChromeFrameBinariesLoadTest, PerfColdPreRead) { | |
| 1097 base::FilePath binaries_to_evict[] = {chrome_exe_, chrome_dll_}; | |
| 1098 pre_read_type_ = kPreReadFull; | |
| 1099 RunStartupTest("binary_load_cold_preread", "t", "", true /* cold */, | |
| 1100 arraysize(binaries_to_evict), binaries_to_evict, | |
| 1101 false /* not important */, false); | |
| 1102 } | |
| 1103 | |
| 1104 TEST_F(ChromeFrameBinariesLoadTest, PerfColdPartialPreRead15) { | |
| 1105 base::FilePath binaries_to_evict[] = {chrome_exe_, chrome_dll_}; | |
| 1106 pre_read_type_ = kPreReadPartial; | |
| 1107 percentage_to_preread_ = 15; | |
| 1108 RunStartupTest("binary_load_cold_partial_preread", "t", "", true /* cold */, | |
| 1109 arraysize(binaries_to_evict), binaries_to_evict, | |
| 1110 false /* not important */, false); | |
| 1111 } | |
| 1112 | |
| 1113 | |
| 1114 TEST_F(ChromeFrameBinariesLoadTest, PerfColdPartialPreRead25) { | |
| 1115 base::FilePath binaries_to_evict[] = {chrome_exe_, chrome_dll_}; | |
| 1116 pre_read_type_ = kPreReadPartial; | |
| 1117 percentage_to_preread_ = 25; | |
| 1118 RunStartupTest("binary_load_cold_partial_preread", "t", "", true /* cold */, | |
| 1119 arraysize(binaries_to_evict), binaries_to_evict, | |
| 1120 false /* not important */, false); | |
| 1121 } | |
| 1122 | |
| 1123 TEST_F(ChromeFrameBinariesLoadTest, PerfColdPartialPreRead40) { | |
| 1124 base::FilePath binaries_to_evict[] = {chrome_exe_, chrome_dll_}; | |
| 1125 pre_read_type_ = kPreReadPartial; | |
| 1126 percentage_to_preread_ = 40; | |
| 1127 RunStartupTest("binary_load_cold_partial_preread", "t", "", true /* cold */, | |
| 1128 arraysize(binaries_to_evict), binaries_to_evict, | |
| 1129 false /* not important */, false); | |
| 1130 } | |
| 1131 | |
| 1132 TEST_F(ChromeFrameStartupTestActiveXReference, PerfWarm) { | |
| 1133 RunStartupTest("warm", "t_ref", "about:blank", false /* cold */, 0, NULL, | |
| 1134 true /* important */, false); | |
| 1135 } | |
| 1136 | |
| 1137 TEST_F(ChromeFrameStartupTestActiveX, PerfChromeFrameInitializationWarm) { | |
| 1138 RunStartupTest("ChromeFrame_init_warm", "t", "", false /* cold */, 0, | |
| 1139 NULL, true /* important */, false); | |
| 1140 } | |
| 1141 | |
| 1142 TEST_F(ChromeFrameStartupTestActiveX, PerfChromeFrameInitializationCold) { | |
| 1143 base::FilePath binaries_to_evict[] = {chrome_frame_dll_}; | |
| 1144 RunStartupTest("ChromeFrame_init_cold", "t", "", true /* cold */, | |
| 1145 arraysize(binaries_to_evict), binaries_to_evict, | |
| 1146 false /* not important */, false); | |
| 1147 } | |
| 1148 | |
| 1149 TEST_F(ChromeFrameStartupTestActiveXReference, | |
| 1150 PerfChromeFrameInitializationWarm) { | |
| 1151 RunStartupTest("ChromeFrame_init_warm", "t_ref", "", false /* cold */, 0, | |
| 1152 NULL, true /* important */, false); | |
| 1153 } | |
| 1154 | |
| 1155 typedef ChromeFrameActiveXMemoryTest<ChromeFrameMemoryTest> | |
| 1156 RegularChromeFrameActiveXMemoryTest; | |
| 1157 | |
| 1158 TEST_F(RegularChromeFrameActiveXMemoryTest, MemoryTestAboutBlank) { | |
| 1159 char *urls[] = {"about:blank"}; | |
| 1160 RunTest("memory_about_blank", urls, arraysize(urls)); | |
| 1161 } | |
| 1162 | |
| 1163 // TODO(iyengar) | |
| 1164 // Revisit why the chrome frame dll does not unload correctly when this test is | |
| 1165 // run. | |
| 1166 // http://code.google.com/p/chromium/issues/detail?id=47812 | |
| 1167 TEST_F(RegularChromeFrameActiveXMemoryTest, DISABLED_MemoryTestUrls) { | |
| 1168 // TODO(iyengar) | |
| 1169 // We should use static pages to measure memory usage. | |
| 1170 char *urls[] = { | |
| 1171 "http://www.youtube.com/watch?v=PN2HAroA12w", | |
| 1172 "http://www.youtube.com/watch?v=KmLJDrsaJmk&feature=channel" | |
| 1173 }; | |
| 1174 | |
| 1175 RunTest("memory", urls, arraysize(urls)); | |
| 1176 } | |
| 1177 | |
| 1178 typedef ChromeFrameActiveXMemoryTest<ChromeFrameMemoryTestReference> | |
| 1179 ReferenceBuildChromeFrameActiveXMemoryTest; | |
| 1180 | |
| 1181 // Disabled to investigate why the chrome frame dll does not unload while | |
| 1182 // running this test. | |
| 1183 // http://code.google.com/p/chromium/issues/detail?id=47812 | |
| 1184 TEST_F(ReferenceBuildChromeFrameActiveXMemoryTest, | |
| 1185 DISABLED_MemoryTestAboutBlank) { | |
| 1186 char *urls[] = {"about:blank"}; | |
| 1187 RunTest("memory_about_blank_reference", urls, arraysize(urls)); | |
| 1188 } | |
| 1189 | |
| 1190 // TODO(iyengar) | |
| 1191 // Revisit why the chrome frame dll does not unload correctly when this test is | |
| 1192 // run. | |
| 1193 TEST_F(ReferenceBuildChromeFrameActiveXMemoryTest, DISABLED_MemoryTestUrls) { | |
| 1194 // TODO(iyengar) | |
| 1195 // We should use static pages to measure memory usage. | |
| 1196 char *urls[] = { | |
| 1197 "http://www.youtube.com/watch?v=PN2HAroA12w", | |
| 1198 "http://www.youtube.com/watch?v=KmLJDrsaJmk&feature=channel" | |
| 1199 }; | |
| 1200 | |
| 1201 RunTest("memory_reference", urls, arraysize(urls)); | |
| 1202 } | |
| 1203 | |
| 1204 TEST_F(ChromeFrameCreationTest, PerfWarm) { | |
| 1205 RunStartupTest("creation_warm", "t", "", false /* cold */, 0, | |
| 1206 NULL, true /* important */, false); | |
| 1207 } | |
| 1208 | |
| 1209 TEST_F(ChromeFrameCreationTestReference, PerfWarm) { | |
| 1210 RunStartupTest("creation_warm", "t_ref", "about:blank", false /* cold */, 0, | |
| 1211 NULL, true /* not important */, false); | |
| 1212 } | |
| 1213 | |
| 1214 TEST_F(FlashCreationTest, DISABLED_PerfWarm) { | |
| 1215 RunStartupTest("creation_warm", "t_flash", "", false /* cold */, 0, NULL, | |
| 1216 true /* not important */, false); | |
| 1217 } | |
| 1218 | |
| 1219 TEST_F(SilverlightCreationTest, DISABLED_PerfWarm) { | |
| 1220 RunStartupTest("creation_warm", "t_silverlight", "", false /* cold */, 0, | |
| 1221 NULL, false /* not important */, false); | |
| 1222 } | |
| 1223 | |
| 1224 TEST_F(ChromeFrameCreationTest, PerfCold) { | |
| 1225 base::FilePath binaries_to_evict[] = {chrome_frame_dll_}; | |
| 1226 | |
| 1227 RunStartupTest("creation_cold", "t", "", true /* cold */, | |
| 1228 arraysize(binaries_to_evict), binaries_to_evict, | |
| 1229 true /* important */, false); | |
| 1230 } | |
| 1231 | |
| 1232 // Attempt to evict the Flash control can fail on the buildbot as the dll | |
| 1233 // is marked read only. The test run is aborted if we fail to evict the file | |
| 1234 // from the cache. This could also fail if the Flash control is in use. | |
| 1235 // On Vista this could fail because of UAC | |
| 1236 TEST_F(FlashCreationTest, PerfCold) { | |
| 1237 base::win::RegKey flash_key(HKEY_CLASSES_ROOT, kFlashControlKey, KEY_READ); | |
| 1238 | |
| 1239 std::wstring plugin_path; | |
| 1240 ASSERT_EQ(ERROR_SUCCESS, flash_key.ReadValue(L"", &plugin_path)); | |
| 1241 ASSERT_FALSE(plugin_path.empty()); | |
| 1242 | |
| 1243 base::FilePath flash_path = base::FilePath(plugin_path); | |
| 1244 base::FilePath binaries_to_evict[] = {flash_path}; | |
| 1245 | |
| 1246 RunStartupTest("creation_cold", "t_flash", "", true /* cold */, | |
| 1247 arraysize(binaries_to_evict), binaries_to_evict, | |
| 1248 false/* important */, true); | |
| 1249 } | |
| 1250 | |
| 1251 // This test would fail on Vista due to UAC or if the Silverlight control is | |
| 1252 // in use. The test run is aborted if we fail to evict the file from the cache. | |
| 1253 // Disabling this test as the Silverlight dll does not seem to get unloaded | |
| 1254 // correctly causing the attempt to evict the dll from the system cache to | |
| 1255 // fail. | |
| 1256 TEST_F(SilverlightCreationTest, DISABLED_PerfCold) { | |
| 1257 base::win::RegKey silverlight_key(HKEY_CLASSES_ROOT, kSilverlightControlKey, | |
| 1258 KEY_READ); | |
| 1259 | |
| 1260 std::wstring plugin_path; | |
| 1261 ASSERT_EQ(ERROR_SUCCESS, silverlight_key.ReadValue(L"", &plugin_path)); | |
| 1262 ASSERT_FALSE(plugin_path.empty()); | |
| 1263 | |
| 1264 base::FilePath silverlight_path = base::FilePath(plugin_path); | |
| 1265 base::FilePath binaries_to_evict[] = {silverlight_path}; | |
| 1266 | |
| 1267 RunStartupTest("creation_cold", "t_silverlight", "", true /* cold */, | |
| 1268 arraysize(binaries_to_evict), binaries_to_evict, | |
| 1269 false /* important */, true); | |
| 1270 } | |
| 1271 | |
| 1272 namespace { | |
| 1273 | |
| 1274 // Derive from this class in order to receive custom events traced | |
| 1275 // via TRACE_EVENT_XXXX macros from ChromeFrame/Chrome. | |
| 1276 class TracedEvents { | |
| 1277 public: | |
| 1278 virtual void OnTraceEventBegin(EVENT_TRACE* event) {} | |
| 1279 virtual void OnTraceEventEnd(EVENT_TRACE* event) {} | |
| 1280 virtual void OnTraceEventInstant(EVENT_TRACE* event) {} | |
| 1281 }; | |
| 1282 | |
| 1283 // For the time being we pass to delegate only base::kTraceEventClass32 | |
| 1284 // events i.e. these generated by TRACE_EVENT_XXXX macros. | |
| 1285 // We may need to add kernel provider and pass Process Start/Exit events etc, | |
| 1286 // but for the time being we stick with base::kChromeTraceProviderName | |
| 1287 // provider only. | |
| 1288 class EtwConsumer : public base::win::EtwTraceConsumerBase<EtwConsumer> { | |
| 1289 public: | |
| 1290 EtwConsumer() { | |
| 1291 set_delegate(NULL); | |
| 1292 } | |
| 1293 | |
| 1294 ~EtwConsumer() { | |
| 1295 set_delegate(NULL); | |
| 1296 } | |
| 1297 | |
| 1298 void set_delegate(TracedEvents* delegate) { | |
| 1299 delegate_ = delegate; | |
| 1300 } | |
| 1301 | |
| 1302 static void ProcessEvent(EVENT_TRACE* event) { | |
| 1303 DCHECK(delegate_); | |
| 1304 if (event->Header.Guid != base::debug::kTraceEventClass32) | |
| 1305 return; | |
| 1306 if (event->Header.Class.Version != 0) | |
| 1307 return; | |
| 1308 | |
| 1309 switch (event->Header.Class.Type) { | |
| 1310 case base::debug::kTraceEventTypeBegin: | |
| 1311 delegate_->OnTraceEventBegin(event); | |
| 1312 break; | |
| 1313 case base::debug::kTraceEventTypeEnd: | |
| 1314 delegate_->OnTraceEventEnd(event); | |
| 1315 break; | |
| 1316 case base::debug::kTraceEventTypeInstant: | |
| 1317 delegate_->OnTraceEventInstant(event); | |
| 1318 break; | |
| 1319 default: | |
| 1320 NOTREACHED(); | |
| 1321 break; | |
| 1322 } | |
| 1323 } | |
| 1324 | |
| 1325 static TracedEvents* delegate_; | |
| 1326 }; | |
| 1327 | |
| 1328 TracedEvents* EtwConsumer::delegate_ = NULL; | |
| 1329 }; // namespace | |
| 1330 | |
| 1331 class EtwPerfSession { | |
| 1332 public: | |
| 1333 EtwPerfSession() { | |
| 1334 } | |
| 1335 | |
| 1336 ~EtwPerfSession() { | |
| 1337 base::DeleteFile(etl_log_file_, false); | |
| 1338 } | |
| 1339 | |
| 1340 void Start() { | |
| 1341 // To ensure there is no session leftover from crashes, previous runs, etc. | |
| 1342 base::win::EtwTraceProperties ignore; | |
| 1343 base::win::EtwTraceController::Stop(L"cf_perf", &ignore); | |
| 1344 ASSERT_TRUE(base::CreateTemporaryFile(&etl_log_file_)); | |
| 1345 ASSERT_HRESULT_SUCCEEDED(controller_.StartFileSession(L"cf_perf", | |
| 1346 etl_log_file_.value().c_str(), false)); | |
| 1347 ASSERT_HRESULT_SUCCEEDED(controller_.EnableProvider( | |
| 1348 base::debug::kChromeTraceProviderName, | |
| 1349 TRACE_LEVEL_INFORMATION, | |
| 1350 ~(base::debug::CAPTURE_STACK_TRACE))); | |
| 1351 } | |
| 1352 | |
| 1353 HRESULT Stop() { | |
| 1354 return controller_.Stop(NULL); | |
| 1355 } | |
| 1356 | |
| 1357 void AnalyzeOutput(TracedEvents* delegate) { | |
| 1358 EtwConsumer consumer; | |
| 1359 consumer.set_delegate(delegate); | |
| 1360 consumer.OpenFileSession(etl_log_file_.value().c_str()); | |
| 1361 consumer.Consume(); | |
| 1362 consumer.Close(); | |
| 1363 } | |
| 1364 | |
| 1365 base::FilePath etl_log_file_; | |
| 1366 base::win::EtwTraceController controller_; | |
| 1367 }; | |
| 1368 | |
| 1369 // Base class for the tracing event helper classes. | |
| 1370 class MonitorTraceBase { | |
| 1371 public: | |
| 1372 static bool IsMatchingEvent(EVENT_TRACE* event, | |
| 1373 const base::StringPiece& event_to_compare) { | |
| 1374 return event->MofLength > event_to_compare.size() && | |
| 1375 (memcmp(event_to_compare.data(), event->MofData, | |
| 1376 event_to_compare.size() + 1) == 0); | |
| 1377 } | |
| 1378 | |
| 1379 bool is_valid() const { | |
| 1380 return !start_.is_null() && !end_.is_null() && start_ <= end_; | |
| 1381 } | |
| 1382 | |
| 1383 base::TimeDelta duration() const { | |
| 1384 return end_ - start_; | |
| 1385 } | |
| 1386 | |
| 1387 base::Time start_; | |
| 1388 base::Time end_; | |
| 1389 }; | |
| 1390 | |
| 1391 // This class measures the time between begin and end events of a particular | |
| 1392 // type. | |
| 1393 class MonitorTracePair : public MonitorTraceBase, | |
| 1394 public TracedEvents { | |
| 1395 public: | |
| 1396 MonitorTracePair() : event_(NULL) { | |
| 1397 } | |
| 1398 | |
| 1399 void set_interesting_event(const char* event) { | |
| 1400 event_ = event; | |
| 1401 } | |
| 1402 | |
| 1403 virtual void OnTraceEventBegin(EVENT_TRACE* event) { | |
| 1404 if (IsMatchingEvent(event, event_)) { | |
| 1405 EXPECT_TRUE(start_.is_null()); | |
| 1406 start_ = base::Time::FromFileTime( | |
| 1407 reinterpret_cast<FILETIME&>(event->Header.TimeStamp)); | |
| 1408 } | |
| 1409 } | |
| 1410 | |
| 1411 virtual void OnTraceEventEnd(EVENT_TRACE* event) { | |
| 1412 if (IsMatchingEvent(event, event_)) { | |
| 1413 EXPECT_FALSE(start_.is_null()); | |
| 1414 EXPECT_TRUE(end_.is_null()); | |
| 1415 end_ = base::Time::FromFileTime( | |
| 1416 reinterpret_cast<FILETIME&>(event->Header.TimeStamp)); | |
| 1417 } | |
| 1418 } | |
| 1419 | |
| 1420 base::StringPiece event_; | |
| 1421 }; | |
| 1422 | |
| 1423 // This class measures the time between two events. | |
| 1424 class MonitorTraceBetweenEventPair : public MonitorTraceBase, | |
| 1425 public TracedEvents { | |
| 1426 public: | |
| 1427 MonitorTraceBetweenEventPair() : event_end_(NULL), | |
| 1428 event_start_(NULL) { | |
| 1429 } | |
| 1430 | |
| 1431 void set_start_event(const char* event) { | |
| 1432 event_start_ = event; | |
| 1433 } | |
| 1434 | |
| 1435 void set_end_event(const char* event) { | |
| 1436 event_end_ = event; | |
| 1437 } | |
| 1438 | |
| 1439 virtual void OnTraceEventBegin(EVENT_TRACE* event) { | |
| 1440 if (IsMatchingEvent(event, event_start_)) { | |
| 1441 EXPECT_TRUE(start_.is_null()); | |
| 1442 EXPECT_TRUE(end_.is_null()); | |
| 1443 start_ = base::Time::FromFileTime( | |
| 1444 reinterpret_cast<FILETIME&>(event->Header.TimeStamp)); | |
| 1445 } else if (IsMatchingEvent(event, event_end_)) { | |
| 1446 EXPECT_FALSE(start_.is_null()); | |
| 1447 EXPECT_TRUE(end_.is_null()); | |
| 1448 end_ = base::Time::FromFileTime( | |
| 1449 reinterpret_cast<FILETIME&>(event->Header.TimeStamp)); | |
| 1450 } | |
| 1451 } | |
| 1452 | |
| 1453 virtual void OnTraceEventEnd(EVENT_TRACE* event) {} | |
| 1454 | |
| 1455 base::StringPiece event_start_; | |
| 1456 base::StringPiece event_end_; | |
| 1457 }; | |
| 1458 | |
| 1459 // The very same as UIPerfTest::PrintResultXXXX without the need to | |
| 1460 // create an UIPerfTest instance. | |
| 1461 void PrintResultsImpl(const std::string& measurement, | |
| 1462 const std::string& modifier, | |
| 1463 const std::string& trace, | |
| 1464 const std::string& values, | |
| 1465 const std::string& prefix, | |
| 1466 const std::string& suffix, | |
| 1467 const std::string& units, | |
| 1468 bool important) { | |
| 1469 // <*>RESULT <graph_name>: <trace_name>= <value> <units> | |
| 1470 // <*>RESULT <graph_name>: <trace_name>= {<mean>, <std deviation>} <units> | |
| 1471 // <*>RESULT <graph_name>: <trace_name>= [<value>,value,value,...,] <units> | |
| 1472 printf("%sRESULT %s%s: %s= %s%s%s %s\n", | |
| 1473 important ? "*" : "", measurement.c_str(), modifier.c_str(), | |
| 1474 trace.c_str(), prefix.c_str(), values.c_str(), suffix.c_str(), | |
| 1475 units.c_str()); | |
| 1476 } | |
| 1477 | |
| 1478 void PrintResultList(const std::string& measurement, | |
| 1479 const std::string& modifier, | |
| 1480 const std::string& trace, | |
| 1481 const std::string& values, | |
| 1482 const std::string& units, | |
| 1483 bool important) { | |
| 1484 PrintResultsImpl(measurement, modifier, trace, values, | |
| 1485 "[", "]", units, important); | |
| 1486 } | |
| 1487 | |
| 1488 bool RunSingleTestOutOfProc(const std::string& test_name) { | |
| 1489 base::FilePath path; | |
| 1490 if (!PathService::Get(base::DIR_EXE, &path)) | |
| 1491 return false; | |
| 1492 path = path.Append(L"chrome_frame_tests.exe"); | |
| 1493 | |
| 1494 CommandLine cmd_line(path); | |
| 1495 // Always enable disabled tests. This method is not called with disabled | |
| 1496 // tests unless this flag was specified to the browser test executable. | |
| 1497 cmd_line.AppendSwitch("gtest_also_run_disabled_tests"); | |
| 1498 cmd_line.AppendSwitchASCII("gtest_filter", test_name); | |
| 1499 | |
| 1500 base::ProcessHandle process_handle; | |
| 1501 if (!base::LaunchProcess(cmd_line, base::LaunchOptions(), &process_handle)) | |
| 1502 return false; | |
| 1503 | |
| 1504 base::TimeDelta test_terminate_timeout = base::TimeDelta::FromMinutes(1); | |
| 1505 int exit_code = 0; | |
| 1506 if (!base::WaitForExitCodeWithTimeout(process_handle, &exit_code, | |
| 1507 test_terminate_timeout)) { | |
| 1508 LOG(ERROR) << "Test timeout (" << test_terminate_timeout.InMilliseconds() | |
| 1509 << " ms) exceeded for " << test_name; | |
| 1510 | |
| 1511 exit_code = -1; // Set a non-zero exit code to signal a failure. | |
| 1512 | |
| 1513 // Ensure that the process terminates. | |
| 1514 base::KillProcess(process_handle, -1, true); | |
| 1515 } | |
| 1516 | |
| 1517 base::CloseProcessHandle(process_handle); | |
| 1518 | |
| 1519 return exit_code == 0; | |
| 1520 } | |
| 1521 | |
| 1522 template <class Monitor> | |
| 1523 void PrintPerfTestResults(const Monitor* monitor, | |
| 1524 int num_cycles, | |
| 1525 const char* result_name) { | |
| 1526 std::string times; | |
| 1527 | |
| 1528 for (int i = 0; i < num_cycles; ++i) { | |
| 1529 ASSERT_TRUE(monitor[i].is_valid()); | |
| 1530 base::StringAppendF(×, | |
| 1531 "%.2f,", | |
| 1532 monitor[i].duration().InMillisecondsF()); | |
| 1533 } | |
| 1534 | |
| 1535 PrintResultList(result_name, "", "t", times, "ms", false); | |
| 1536 } | |
| 1537 | |
| 1538 TEST(TestAsPerfTest, MetaTag_createproxy) { | |
| 1539 const int kNumCycles = 10; | |
| 1540 | |
| 1541 MonitorTracePair create_proxy_monitor[kNumCycles]; | |
| 1542 MonitorTraceBetweenEventPair browser_main_start_monitor[kNumCycles]; | |
| 1543 MonitorTraceBetweenEventPair browser_main_loop_monitor[kNumCycles]; | |
| 1544 MonitorTraceBetweenEventPair automation_provider_start_monitor[kNumCycles]; | |
| 1545 MonitorTraceBetweenEventPair automation_provider_connect_monitor[kNumCycles]; | |
| 1546 MonitorTracePair external_tab_navigate_monitor[kNumCycles]; | |
| 1547 MonitorTracePair pre_read_chrome_monitor[kNumCycles]; | |
| 1548 MonitorTraceBetweenEventPair renderer_main_monitor[kNumCycles]; | |
| 1549 | |
| 1550 for (int i = 0; i < kNumCycles; ++i) { | |
| 1551 EtwPerfSession perf_session; | |
| 1552 ASSERT_NO_FATAL_FAILURE(perf_session.Start()); | |
| 1553 ASSERT_TRUE(RunSingleTestOutOfProc( | |
| 1554 "ChromeFrameTestWithWebServer.FullTabModeIE_MetaTag")); | |
| 1555 // Since we cannot have array of objects with a non-default constructor, | |
| 1556 // dedicated method is used to initialize watched event. | |
| 1557 create_proxy_monitor[i].set_interesting_event("chromeframe.createproxy"); | |
| 1558 | |
| 1559 browser_main_start_monitor[i].set_start_event("chromeframe.createproxy"); | |
| 1560 browser_main_start_monitor[i].set_end_event("BrowserMain"); | |
| 1561 | |
| 1562 browser_main_loop_monitor[i].set_start_event("BrowserMain"); | |
| 1563 browser_main_loop_monitor[i].set_end_event("BrowserMain:MESSAGE_LOOP"); | |
| 1564 | |
| 1565 automation_provider_start_monitor[i].set_start_event("BrowserMain"); | |
| 1566 automation_provider_start_monitor[i].set_end_event( | |
| 1567 "AutomationProvider::AutomationProvider"); | |
| 1568 | |
| 1569 automation_provider_connect_monitor[i].set_start_event( | |
| 1570 "AutomationProvider::AutomationProvider"); | |
| 1571 automation_provider_connect_monitor[i].set_end_event( | |
| 1572 "AutomationProvider::InitializeChannel"); | |
| 1573 | |
| 1574 external_tab_navigate_monitor[i].set_interesting_event( | |
| 1575 "ExternalTabContainerWin::Navigate"); | |
| 1576 | |
| 1577 renderer_main_monitor[i].set_start_event( | |
| 1578 "ExternalTabContainerWin::Navigate"); | |
| 1579 renderer_main_monitor[i].set_end_event("RendererMain"); | |
| 1580 | |
| 1581 pre_read_chrome_monitor[i].set_interesting_event("PreReadImage"); | |
| 1582 | |
| 1583 ASSERT_HRESULT_SUCCEEDED(perf_session.Stop()); | |
| 1584 | |
| 1585 perf_session.AnalyzeOutput(&create_proxy_monitor[i]); | |
| 1586 perf_session.AnalyzeOutput(&browser_main_start_monitor[i]); | |
| 1587 perf_session.AnalyzeOutput(&browser_main_loop_monitor[i]); | |
| 1588 perf_session.AnalyzeOutput(&automation_provider_start_monitor[i]); | |
| 1589 perf_session.AnalyzeOutput(&automation_provider_connect_monitor[i]); | |
| 1590 perf_session.AnalyzeOutput(&external_tab_navigate_monitor[i]); | |
| 1591 perf_session.AnalyzeOutput(&pre_read_chrome_monitor[i]); | |
| 1592 perf_session.AnalyzeOutput(&renderer_main_monitor[i]); | |
| 1593 } | |
| 1594 | |
| 1595 // Print results | |
| 1596 PrintPerfTestResults(create_proxy_monitor, kNumCycles, "createproxy"); | |
| 1597 PrintPerfTestResults(browser_main_start_monitor, kNumCycles, | |
| 1598 "browserstart"); | |
| 1599 PrintPerfTestResults(browser_main_loop_monitor, kNumCycles, | |
| 1600 "browserloop"); | |
| 1601 PrintPerfTestResults(automation_provider_start_monitor, kNumCycles, | |
| 1602 "automationproviderstart"); | |
| 1603 PrintPerfTestResults(automation_provider_connect_monitor, kNumCycles, | |
| 1604 "automationproviderconnect"); | |
| 1605 PrintPerfTestResults(external_tab_navigate_monitor, kNumCycles, | |
| 1606 "externaltabnavigate"); | |
| 1607 PrintPerfTestResults(renderer_main_monitor, kNumCycles, | |
| 1608 "beginrenderermain"); | |
| 1609 #ifdef NDEBUG | |
| 1610 PrintPerfTestResults(pre_read_chrome_monitor, kNumCycles, "PreReadImage"); | |
| 1611 #endif // NDEBUG | |
| 1612 } | |
| OLD | NEW |