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.
5 #include "chrome_frame/test/perf/chrome_frame_perftest.h"
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"
46 const wchar_t kSilverlightControlKey[] =
47 L"CLSID\\{DFEAF541-F3E1-4c24-ACAC-99C30715084A}\\InprocServer32";
49 const wchar_t kFlashControlKey[] =
50 L"CLSID\\{D27CDB6E-AE6D-11cf-96B8-444553540000}\\InprocServer32";
52 using base::TimeDelta;
53 using base::TimeTicks;
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 {
65 ~ChromeFrameActiveXContainer() {
70 DECLARE_WND_CLASS_EX(L"ChromeFrameActiveX_container", 0, 0)
72 BEGIN_COM_MAP(ChromeFrameActiveXContainer)
73 COM_INTERFACE_ENTRY(IPropertyNotifySink)
76 BEGIN_MSG_MAP(ChromeFrameActiveXContainer)
77 MESSAGE_HANDLER(WM_CREATE, OnCreate)
78 MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
81 HRESULT OnMessageCallback(const VARIANT* param) {
82 DVLOG(1) << __FUNCTION__;
83 OnMessageCallbackImpl(param);
87 HRESULT OnLoadErrorCallback(const VARIANT* param) {
88 DVLOG(1) << __FUNCTION__ << " " << param->bstrVal;
89 OnLoadErrorCallbackImpl(param);
93 HRESULT OnLoadCallback(const VARIANT* param) {
94 DVLOG(1) << __FUNCTION__ << " " << param->bstrVal;
95 OnLoadCallbackImpl(param);
99 ChromeFrameActiveXContainer() :
100 prop_notify_cookie_(0),
101 onmsg_(this, &ChromeFrameActiveXContainer::OnMessageCallback),
102 onloaderror_(this, &ChromeFrameActiveXContainer::OnLoadErrorCallback),
103 onload_(this, &ChromeFrameActiveXContainer::OnLoadCallback) {
106 LRESULT OnCreate(UINT , WPARAM , LPARAM , BOOL& ) {
107 chromeview_.Attach(m_hWnd);
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;
125 virtual void OnFinalMessage(HWND /*hWnd*/) {
126 ::PostQuitMessage(6);
129 static const wchar_t* GetWndCaption() {
130 return L"ChromeFrame Container";
133 // IPropertyNotifySink
134 STDMETHOD(OnRequestEdit)(DISPID disp_id) {
135 OnRequestEditImpl(disp_id);
139 STDMETHOD(OnChanged)(DISPID disp_id) {
140 if (disp_id != DISPID_READYSTATE)
144 HRESULT hr = tab_->get_readyState(&ready_state);
147 OnReadyStateChanged(ready_state);
149 if (ready_state == READYSTATE_COMPLETE) {
150 if (!starting_url_.empty()) {
151 Navigate(starting_url_.c_str());
153 PostMessage(WM_CLOSE);
155 } else if (ready_state == READYSTATE_UNINITIALIZED) {
156 DLOG(ERROR) << __FUNCTION__ << " Chrome launch failed.";
162 void CreateChromeFrameWindow(const std::string& starting_url) {
163 starting_url_ = starting_url;
164 RECT rc = { 0, 0, 800, 600 };
167 ShowWindow(SW_SHOWDEFAULT);
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);
176 if (setup_event_sinks)
180 void Navigate(const char* url) {
181 BeforeNavigateImpl(url);
183 HRESULT hr = tab_->put_src(base::win::ScopedBstr(UTF8ToWide(url).c_str()));
184 DCHECK(hr == S_OK) << "Chrome frame NavigateToURL(" << url
185 << base::StringPrintf(L") failed 0x%08X", hr);
188 void SetupEventSinks() {
189 HRESULT hr = AtlAdvise(tab_, this, IID_IPropertyNotifySink,
190 &prop_notify_cookie_);
191 DCHECK(hr == S_OK) << "AtlAdvice for IPropertyNotifySink failed " << hr;
193 base::win::ScopedVariant onmessage(onmsg_.ToDispatch());
194 base::win::ScopedVariant onloaderror(onloaderror_.ToDispatch());
195 base::win::ScopedVariant onload(onload_.ToDispatch());
196 EXPECT_HRESULT_SUCCEEDED(tab_->put_onmessage(onmessage));
197 EXPECT_HRESULT_SUCCEEDED(tab_->put_onloaderror(onloaderror));
198 EXPECT_HRESULT_SUCCEEDED(tab_->put_onload(onload));
202 // These functions are implemented by derived classes for special behavior
203 // like performance measurement, etc.
204 virtual void OnReadyStateChanged(long ready_state) {}
205 virtual void OnRequestEditImpl(DISPID disp_id) {}
207 virtual void OnMessageCallbackImpl(const VARIANT* param) {}
209 virtual void OnLoadCallbackImpl(const VARIANT* param) {
210 PostMessage(WM_CLOSE);
213 virtual void OnLoadErrorCallbackImpl(const VARIANT* param) {
214 PostMessage(WM_CLOSE);
216 virtual void BeforeNavigateImpl(const char* url) {}
218 CAxWindow chromeview_;
219 base::win::ScopedComPtr<IChromeFrame> tab_;
220 DWORD prop_notify_cookie_;
221 DispCallback<ChromeFrameActiveXContainer> onmsg_;
222 DispCallback<ChromeFrameActiveXContainer> onloaderror_;
223 DispCallback<ChromeFrameActiveXContainer> onload_;
224 std::string starting_url_;
227 // This class overrides the hooks provided by the ChromeFrameActiveXContainer
228 // class and measures performance at various stages, like initialzation of
229 // the Chrome frame widget, navigation, etc.
230 class ChromeFrameActiveXContainerPerf : public ChromeFrameActiveXContainer {
232 ChromeFrameActiveXContainerPerf() {}
234 void CreateControl(bool setup_event_sinks) {
235 perf_initialize_.reset(new base::PerfTimeLogger("Fully initialized"));
236 base::PerfTimeLogger perf_create("Create Control");
238 HRESULT hr = chromeview_.CreateControl(L"ChromeTab.ChromeFrame");
239 EXPECT_HRESULT_SUCCEEDED(hr);
240 hr = chromeview_.QueryControl(tab_.Receive());
241 EXPECT_HRESULT_SUCCEEDED(hr);
244 if (setup_event_sinks)
249 virtual void OnReadyStateChanged(long ready_state) {
250 // READYSTATE_COMPLETE is fired when the automation server is ready.
251 if (ready_state == READYSTATE_COMPLETE) {
252 perf_initialize_->Done();
253 } else if (ready_state == READYSTATE_INTERACTIVE) {
254 // Window ready. Currently we never receive this notification because it
255 // is fired before we finish setting up our hosting environment.
256 // This is because of how ATL is written. Moving forward we might
257 // have our own hosting classes and then have more control over when we
258 // set up the prop notify sink.
260 DCHECK(ready_state != READYSTATE_UNINITIALIZED) << "failed to initialize";
264 virtual void OnLoadCallbackImpl(const VARIANT* param) {
265 PostMessage(WM_CLOSE);
266 perf_navigate_->Done();
269 virtual void OnLoadErrorCallbackImpl(const VARIANT* param) {
270 PostMessage(WM_CLOSE);
271 perf_navigate_->Done();
274 virtual void BeforeNavigateImpl(const char* url ) {
275 std::string test_name = "Navigate ";
277 perf_navigate_.reset(new base::PerfTimeLogger(test_name.c_str()));
280 scoped_ptr<base::PerfTimeLogger> perf_initialize_;
281 scoped_ptr<base::PerfTimeLogger> perf_navigate_;
284 // This class provides common functionality which can be used for most of the
285 // ChromeFrame/Tab performance tests.
286 class ChromeFramePerfTestBase : public UIPerfTest {
288 ChromeFramePerfTestBase() {}
290 scoped_ptr<ScopedChromeFrameRegistrar> chrome_frame_registrar_;
293 class ChromeFrameStartupTest : public ChromeFramePerfTestBase {
295 ChromeFrameStartupTest() {}
297 virtual void SetUp() {
298 ASSERT_TRUE(PathService::Get(chrome::DIR_APP, &dir_app_));
300 chrome_dll_ = dir_app_.Append(L"chrome.dll");
301 chrome_exe_ = dir_app_.Append(chrome::kBrowserProcessExecutableName);
302 chrome_frame_dll_ = dir_app_.Append(kChromeFrameDllName);
303 icu_dll_ = dir_app_.Append(L"icudt.dll");
304 ffmpegsumo_dll_ = dir_app_.Append(L"ffmpegsumo.dll");
308 // This function is similar to the RunStartupTest function used in chrome
309 // startup tests. Refactor into a common implementation.
310 void RunStartupTest(const char* graph, const char* trace,
311 const char* startup_url, bool test_cold,
313 const base::FilePath binaries_to_evict[],
314 bool important, bool ignore_cache_error) {
315 const int kNumCycles = 20;
317 startup_url_ = startup_url;
319 TimeDelta timings[kNumCycles];
321 for (int i = 0; i < kNumCycles; ++i) {
323 for (int binary_index = 0; binary_index < total_binaries;
325 bool result = base::EvictFileFromSystemCacheWithRetry(
326 binaries_to_evict[binary_index]);
327 if (!ignore_cache_error) {
329 } else if (!result) {
330 LOG(ERROR) << GetLastError();
331 printf("\nFailed to evict file %ls from cache. Not running test\n",
332 binaries_to_evict[binary_index].value().c_str());
338 TimeTicks start_time, end_time;
340 RunStartupTestImpl(&start_time, &end_time);
342 timings[i] = end_time - start_time;
344 CoFreeUnusedLibraries();
346 // TODO(beng): Can't shut down so quickly. Figure out why, and fix. If we
348 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(50));
352 for (int i = 0; i < kNumCycles; ++i)
353 base::StringAppendF(×, "%.2f,", timings[i].InMillisecondsF());
355 perf_test::PrintResultList(graph, "", trace, times, "ms", important);
358 base::FilePath dir_app_;
359 base::FilePath chrome_dll_;
360 base::FilePath chrome_exe_;
361 base::FilePath chrome_frame_dll_;
362 base::FilePath icu_dll_;
363 base::FilePath ffmpegsumo_dll_;
366 // Individual startup tests should implement this function.
367 virtual void RunStartupTestImpl(TimeTicks* start_time,
368 TimeTicks* end_time) {}
370 // The host is torn down by this function. It should not be used after
371 // this function returns.
372 static void ReleaseHostComReferences(CAxWindow& host) {
373 CComPtr<IAxWinHostWindow> spWinHost;
374 host.QueryHost(&spWinHost);
375 ASSERT_TRUE(spWinHost != NULL);
377 // Hack to get the host to release all interfaces and thus ensure that
378 // the COM server can be unloaded.
379 CAxHostWindow* host_window = static_cast<CAxHostWindow*>(spWinHost.p);
380 host_window->ReleaseAll();
381 host.DestroyWindow();
384 std::string startup_url_;
387 class ChromeFrameStartupTestActiveX : public ChromeFrameStartupTest {
389 virtual void SetUp() {
390 // Register the Chrome Frame DLL in the build directory.
391 chrome_frame_registrar_.reset(new ScopedChromeFrameRegistrar(
392 ScopedChromeFrameRegistrar::SYSTEM_LEVEL));
394 ChromeFrameStartupTest::SetUp();
398 virtual void RunStartupTestImpl(TimeTicks* start_time,
399 TimeTicks* end_time) {
400 *start_time = TimeTicks::Now();
403 CComObjectStackEx<ChromeFrameActiveXContainer> wnd;
404 wnd.CreateChromeFrameWindow(startup_url_);
405 wnd.CreateControl(true);
406 module.RunMessageLoop();
407 *end_time = TimeTicks::Now();
411 // This class measures the load time of chrome and chrome frame binaries
412 class ChromeFrameBinariesLoadTest : public ChromeFrameStartupTestActiveX {
413 static const size_t kStepSize = 4 * 1024;
421 ChromeFrameBinariesLoadTest()
422 : pre_read_type_(kPreReadNone),
423 step_size_(kStepSize),
425 percentage_to_preread_(25) {}
428 virtual void RunStartupTestImpl(TimeTicks* start_time,
429 TimeTicks* end_time) {
430 *start_time = TimeTicks::Now();
432 if (pre_read_type_ == kPreReadFull) {
433 EXPECT_TRUE(ImagePreReader::PreReadImage(chrome_exe_.value().c_str(),
436 EXPECT_TRUE(ImagePreReader::PreReadImage(chrome_dll_.value().c_str(),
439 } else if (pre_read_type_ == kPreReadPartial) {
441 ImagePreReader::PartialPreReadImage(chrome_exe_.value().c_str(),
442 percentage_to_preread_,
445 ImagePreReader::PartialPreReadImage(chrome_dll_.value().c_str(),
446 percentage_to_preread_,
450 HMODULE chrome_exe = LoadLibrary(chrome_exe_.value().c_str());
451 EXPECT_TRUE(chrome_exe != NULL);
453 HMODULE chrome_dll = LoadLibrary(chrome_dll_.value().c_str());
454 EXPECT_TRUE(chrome_dll != NULL);
456 *end_time = TimeTicks::Now();
458 FreeLibrary(chrome_exe);
459 FreeLibrary(chrome_dll);
462 PreReadType pre_read_type_;
463 size_t bytes_to_read_;
465 uint8 percentage_to_preread_;
468 // This class provides functionality to run the startup performance test for
469 // the ChromeFrame ActiveX against a reference build. At this point we only run
470 // this test in warm mode.
471 class ChromeFrameStartupTestActiveXReference
472 : public ChromeFrameStartupTestActiveX {
474 // override the browser directory to use the reference build instead.
475 virtual void SetUp() {
476 // Register the reference build Chrome Frame DLL.
477 chrome_frame_registrar_.reset(new ScopedChromeFrameRegistrar(
478 ScopedChromeFrameRegistrar::SYSTEM_LEVEL));
479 chrome_frame_registrar_->RegisterReferenceChromeFrameBuild();
481 ChromeFrameStartupTest::SetUp();
483 chrome_frame_dll_ = base::FilePath(
484 chrome_frame_registrar_->GetReferenceChromeFrameDllPath());
485 DVLOG(1) << __FUNCTION__ << ": " << chrome_frame_dll_.value();
488 virtual void TearDown() {
489 // Reregister the Chrome Frame DLL in the build directory.
490 chrome_frame_registrar_.reset(NULL);
494 // This class provides base functionality to measure ChromeFrame memory
497 // Some of the functionality in this class like printing the results, etc
498 // is based on the chrome\test\memory_test.cc. We need to factor out
500 class ChromeFrameMemoryTest : public ChromeFramePerfTestBase {
501 // Contains information about the memory consumption of a process.
502 class ProcessMemoryInfo {
504 // Default constructor
505 // Added to enable us to add ProcessMemoryInfo instances to a map.
509 working_set_size_(0),
510 chrome_browser_process_(false),
511 chrome_frame_memory_test_instance_(NULL) {}
513 ProcessMemoryInfo(base::ProcessId process_id, bool chrome_browser_process,
514 ChromeFrameMemoryTest* memory_test_instance)
515 : process_id_(process_id),
517 working_set_size_(0),
518 chrome_browser_process_(chrome_browser_process),
519 chrome_frame_memory_test_instance_(memory_test_instance) {}
521 bool GetMemoryConsumptionDetails() {
522 base::ProcessHandle process_handle;
523 if (!base::OpenPrivilegedProcessHandle(process_id_, &process_handle)) {
527 // TODO(sgk): if/when base::ProcessMetrics can return real memory
528 // stats on mac, convert to:
530 // scoped_ptr<base::ProcessMetrics> process_metrics;
531 // process_metrics.reset(
532 // base::ProcessMetrics::CreateProcessMetrics(process_handle));
533 scoped_ptr<ChromeTestProcessMetrics> process_metrics;
534 process_metrics.reset(
535 ChromeTestProcessMetrics::CreateProcessMetrics(process_handle));
537 virtual_size_ = process_metrics->GetPagefileUsage();
538 working_set_size_ = process_metrics->GetWorkingSetSize();
540 base::CloseProcessHandle(process_handle);
544 void Print(const char* test_name) {
545 std::string trace_name(test_name);
547 ASSERT_TRUE(chrome_frame_memory_test_instance_ != NULL);
549 if (chrome_browser_process_) {
550 perf_test::PrintResult("vm_final_browser", "", trace_name + "_vm_b",
551 virtual_size_ / 1024, "KB", false /* not important */);
552 perf_test::PrintResult("ws_final_browser", "", trace_name + "_ws_b",
553 working_set_size_ / 1024, "KB", false /* not important */);
554 } else if (process_id_ == base::GetCurrentProcId()) {
555 perf_test::PrintResult("vm_current_process", "", trace_name + "_vm_c",
556 virtual_size_ / 1024, "KB", false /* not important */);
557 perf_test::PrintResult("ws_current_process", "", trace_name + "_ws_c",
558 working_set_size_ / 1024, "KB", false /* not important */);
564 base::ProcessId process_id_;
565 size_t virtual_size_;
566 size_t working_set_size_;
567 // Set to true if this is the chrome browser process.
568 bool chrome_browser_process_;
570 // A reference to the ChromeFrameMemoryTest instance. Used to print memory
571 // consumption information.
572 ChromeFrameMemoryTest* chrome_frame_memory_test_instance_;
575 // This map tracks memory usage for a process. It is keyed on the process
577 typedef std::map<DWORD, ProcessMemoryInfo> ProcessMemoryConsumptionMap;
580 ChromeFrameMemoryTest() : current_url_index_(0) {
583 virtual void SetUp() {
584 // Register the Chrome Frame DLL in the build directory.
585 chrome_frame_registrar_.reset(new ScopedChromeFrameRegistrar(
586 ScopedChromeFrameRegistrar::SYSTEM_LEVEL));
589 void RunTest(const char* test_name, char* urls[], int total_urls) {
590 ASSERT_TRUE(urls != NULL);
591 ASSERT_GT(total_urls, 0);
593 // Record the initial CommitCharge. This is a system-wide measurement,
594 // so if other applications are running, they can create variance in this
596 start_commit_charge_ = base::GetSystemCommitCharge();
598 for (int i = 0; i < total_urls; i++)
599 urls_.push_back(urls[i]);
603 ASSERT_TRUE(!url.empty());
605 StartTest(url, test_name);
608 void OnNavigationSuccess(const VARIANT* param) {
609 ASSERT_TRUE(param != NULL);
610 ASSERT_EQ(VT_BSTR, param->vt);
612 DVLOG(1) << __FUNCTION__ << " " << param->bstrVal;
613 InitiateNextNavigation();
616 void OnNavigationFailure(const VARIANT* param) {
617 ASSERT_TRUE(param != NULL);
618 ASSERT_EQ(VT_BSTR, param->vt);
620 DVLOG(1) << __FUNCTION__ << " " << param->bstrVal;
621 InitiateNextNavigation();
625 bool GetNextUrl(std::string* url) {
626 if (current_url_index_ >= urls_.size())
629 *url = urls_[current_url_index_++];
633 void InitiateNextNavigation() {
634 // Get the memory consumption information for the child processes
635 // of the chrome browser.
636 ChromeProcessList child_processes = GetBrowserChildren();
637 ChromeProcessList::iterator index;
638 for (index = child_processes.begin(); index != child_processes.end();
640 AccountProcessMemoryUsage(*index);
643 // TODO(iyengar): Bug 2953
644 // Need to verify if this is still true.
645 // The automation crashes periodically if we cycle too quickly.
646 // To make these tests more reliable, slowing them down a bit.
650 bool next_url = GetNextUrl(&url);
658 void PrintResults(const char* test_name) {
659 PrintMemoryUsageInfo(test_name);
660 memory_consumption_map_.clear();
662 // Added to give the OS some time to flush the used pages for the
663 // chrome processes which would have exited by now.
666 size_t end_commit_charge = base::GetSystemCommitCharge();
667 size_t commit_size = (end_commit_charge - start_commit_charge_) * 1024;
669 std::string trace_name(test_name);
670 trace_name.append("_cc");
672 perf_test::PrintResult("commit_charge", "", trace_name,
673 commit_size / 1024, "KB", true /* important */);
677 base::ProcessId chrome_browser_process_id() {
678 base::NamedProcessIterator iter(L"chrome.exe", NULL);
679 const base::ProcessEntry* entry = iter.NextProcessEntry();
686 ChromeProcessList GetBrowserChildren() {
687 ChromeProcessList list = GetRunningChromeProcesses(
688 chrome_browser_process_id());
689 ChromeProcessList::iterator browser =
690 std::find(list.begin(), list.end(), chrome_browser_process_id());
691 if (browser != list.end()) {
697 void AccountProcessMemoryUsage(DWORD process_id) {
698 ProcessMemoryInfo process_memory_info(
699 process_id, process_id == chrome_browser_process_id(), this);
701 ASSERT_TRUE(process_memory_info.GetMemoryConsumptionDetails());
703 memory_consumption_map_[process_id] = process_memory_info;
706 void PrintMemoryUsageInfo(const char* test_name) {
709 std::string trace_name(test_name);
711 ProcessMemoryConsumptionMap::iterator index;
712 size_t total_virtual_size = 0;
713 size_t total_working_set_size = 0;
715 for (index = memory_consumption_map_.begin();
716 index != memory_consumption_map_.end();
718 ProcessMemoryInfo& memory_info = (*index).second;
719 memory_info.Print(test_name);
721 total_virtual_size += memory_info.virtual_size_;
722 total_working_set_size += memory_info.working_set_size_;
727 perf_test::PrintResult("vm_final_total", "", trace_name + "_vm",
728 total_virtual_size / 1024, "KB",
729 false /* not important */);
730 perf_test::PrintResult("ws_final_total", "", trace_name + "_ws",
731 total_working_set_size / 1024, "KB",
732 true /* important */);
735 // Should never get called.
736 virtual void StartTest(const std::string& url,
737 const std::string& test_name) = 0 {
741 // Should never get called.
742 virtual void NavigateImpl(const std::string& url) = 0 {
746 virtual void TestCompleted() = 0 {
750 // Holds the commit charge in KBytes at the start of the memory test run.
751 size_t start_commit_charge_;
753 // The index of the URL being tested.
754 size_t current_url_index_;
756 // Contains the list of urls against which the tests are run.
757 std::vector<std::string> urls_;
759 ProcessMemoryConsumptionMap memory_consumption_map_;
762 // This class provides functionality to run the memory test against a reference
763 // chrome frame build.
764 class ChromeFrameMemoryTestReference : public ChromeFrameMemoryTest {
766 virtual void SetUp() {
767 chrome_frame_registrar_.reset(new ScopedChromeFrameRegistrar(
768 ScopedChromeFrameRegistrar::SYSTEM_LEVEL));
769 chrome_frame_registrar_->RegisterReferenceChromeFrameBuild();
772 virtual void TearDown() {
773 // Reregisters the chrome frame DLL in the build directory.
774 chrome_frame_registrar_.reset(NULL);
778 // This class overrides the hooks provided by the ChromeFrameActiveXContainer
779 // class and calls back into the ChromeFrameMemoryTest object instance,
780 // which measures ChromeFrame memory usage.
781 class ChromeFrameActiveXContainerMemory : public ChromeFrameActiveXContainer {
783 ChromeFrameActiveXContainerMemory()
786 ~ChromeFrameActiveXContainerMemory() {}
788 void Initialize(ChromeFrameMemoryTest* delegate) {
789 ASSERT_TRUE(delegate != NULL);
790 delegate_ = delegate;
794 virtual void OnLoadCallbackImpl(const VARIANT* param) {
795 delegate_->OnNavigationSuccess(param);
798 virtual void OnLoadErrorCallbackImpl(const VARIANT* param) {
799 delegate_->OnNavigationFailure(param);
802 ChromeFrameMemoryTest* delegate_;
805 // This class runs memory tests against the ChromeFrame ActiveX.
806 template<class MemoryTestBase>
807 class ChromeFrameActiveXMemoryTest : public MemoryTestBase {
809 ChromeFrameActiveXMemoryTest()
810 : chrome_frame_container_(NULL),
811 test_completed_(false) {}
813 ~ChromeFrameActiveXMemoryTest() {
816 void StartTest(const std::string& url, const std::string& test_name) {
817 ASSERT_TRUE(chrome_frame_container_ == NULL);
819 test_name_ = test_name;
824 CComObject<ChromeFrameActiveXContainerMemory>::CreateInstance(
825 &chrome_frame_container_);
826 chrome_frame_container_->AddRef();
828 chrome_frame_container_->Initialize(this);
830 chrome_frame_container_->CreateChromeFrameWindow(url.c_str());
831 chrome_frame_container_->CreateControl(true);
833 module.RunMessageLoop();
835 chrome_frame_container_->Release();
837 PrintResults(test_name_.c_str());
839 CoFreeUnusedLibraries();
840 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
843 void NavigateImpl(const std::string& url) {
844 ASSERT_TRUE(chrome_frame_container_ != NULL);
845 ASSERT_TRUE(!url.empty());
846 chrome_frame_container_->Navigate(url.c_str());
849 void TestCompleted() {
850 // This can get called multiple times if the last url results in a
852 if (!test_completed_) {
853 // Measure memory usage for the browser process.
854 AccountProcessMemoryUsage(chrome_browser_process_id());
855 // Measure memory usage for the current process.
856 AccountProcessMemoryUsage(GetCurrentProcessId());
858 test_completed_ = true;
859 EXPECT_TRUE(PostMessage(static_cast<HWND>(*chrome_frame_container_),
865 CComObject<ChromeFrameActiveXContainerMemory>* chrome_frame_container_;
866 std::string test_name_;
867 bool test_completed_;
870 // This class runs tests to measure chrome frame creation only. This will help
871 // track overall page load performance with chrome frame instances.
872 class ChromeFrameCreationTest : public ChromeFrameStartupTest {
874 virtual void RunStartupTestImpl(TimeTicks* start_time,
875 TimeTicks* end_time) {
878 CComObjectStackEx<ChromeFrameActiveXContainer> wnd;
879 wnd.CreateChromeFrameWindow(startup_url_);
880 *start_time = TimeTicks::Now();
881 wnd.CreateControl(false);
882 *end_time = TimeTicks::Now();
886 // This class provides functionality to run the chrome frame
887 // performance test against a reference build.
888 class ChromeFrameCreationTestReference : public ChromeFrameCreationTest {
890 // override the browser directory to use the reference build instead.
891 virtual void SetUp() {
892 chrome_frame_registrar_.reset(new ScopedChromeFrameRegistrar(
893 ScopedChromeFrameRegistrar::SYSTEM_LEVEL));
894 chrome_frame_registrar_->RegisterReferenceChromeFrameBuild();
895 ChromeFrameStartupTest::SetUp();
898 virtual void TearDown() {
899 chrome_frame_registrar_.reset(NULL);
903 // This class measures the creation time for Flash, which would be used
904 // as a baseline to measure chrome frame creation performance.
905 class FlashCreationTest : public ChromeFrameStartupTest {
907 virtual void RunStartupTestImpl(TimeTicks* start_time,
908 TimeTicks* end_time) {
912 RECT rc = {0, 0, 800, 600};
913 host.Create(NULL, rc, NULL,
914 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
915 WS_EX_APPWINDOW | WS_EX_WINDOWEDGE);
916 EXPECT_TRUE(host.m_hWnd != NULL);
918 *start_time = TimeTicks::Now();
919 HRESULT hr = host.CreateControl(L"ShockwaveFlash.ShockwaveFlash");
920 EXPECT_HRESULT_SUCCEEDED(hr);
921 *end_time = TimeTicks::Now();
923 ReleaseHostComReferences(host);
927 // This class measures the creation time for Silverlight, which would be used
928 // as a baseline to measure chrome frame creation performance.
929 class SilverlightCreationTest : public ChromeFrameStartupTest {
931 virtual void RunStartupTestImpl(TimeTicks* start_time,
932 TimeTicks* end_time) {
936 RECT rc = {0, 0, 800, 600};
937 host.Create(NULL, rc, NULL,
938 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
939 WS_EX_APPWINDOW | WS_EX_WINDOWEDGE);
940 EXPECT_TRUE(host.m_hWnd != NULL);
942 *start_time = TimeTicks::Now();
943 HRESULT hr = host.CreateControl(L"AgControl.AgControl");
944 EXPECT_HRESULT_SUCCEEDED(hr);
945 *end_time = TimeTicks::Now();
947 ReleaseHostComReferences(host);
951 // TODO(rogerm): Flesh out the *PreReadImage* tests to validate an observed
952 // change in paging behaviour between raw loading and pre-reading.
954 // TODO(rogerm): Add checks to the *PreReadImage* tests to validate the
955 // handling of invalid pe files and paths as input.
957 TEST(ImagePreReader, PreReadImage) {
958 base::FilePath current_exe;
959 ASSERT_TRUE(PathService::Get(base::FILE_EXE, ¤t_exe));
961 int64 file_size_64 = 0;
962 ASSERT_TRUE(file_util::GetFileSize(current_exe, &file_size_64));
963 ASSERT_TRUE(file_size_64 < std::numeric_limits<std::size_t>::max());
964 size_t file_size = static_cast<size_t>(file_size_64);
966 const wchar_t* module_path = current_exe.value().c_str();
967 const size_t kStepSize = 2 * 1024 * 1024;
970 ImagePreReader::PreReadImage(module_path, 0, kStepSize));
972 ImagePreReader::PreReadImage(module_path, file_size / 4, kStepSize));
974 ImagePreReader::PreReadImage(module_path, file_size / 2, kStepSize));
976 ImagePreReader::PreReadImage(module_path, file_size, kStepSize));
978 ImagePreReader::PreReadImage(module_path, file_size * 2, kStepSize));
981 TEST(ImagePreReader, PartialPreReadImage) {
982 base::FilePath current_exe;
983 ASSERT_TRUE(PathService::Get(base::FILE_EXE, ¤t_exe));
985 const wchar_t* module_path = current_exe.value().c_str();
986 const size_t kStepSize = 2 * 1024 * 1024;
989 ImagePreReader::PartialPreReadImage(module_path, 0, kStepSize));
991 ImagePreReader::PartialPreReadImage(module_path, 25, kStepSize));
993 ImagePreReader::PartialPreReadImage(module_path, 50, kStepSize));
995 ImagePreReader::PartialPreReadImage(module_path, 100, kStepSize));
997 ImagePreReader::PartialPreReadImage(module_path, 150, kStepSize));
1000 TEST(ImagePreReader, PartialPreReadImageOnDisk) {
1001 base::FilePath current_exe;
1002 ASSERT_TRUE(PathService::Get(base::FILE_EXE, ¤t_exe));
1004 const wchar_t* module_path = current_exe.value().c_str();
1005 const size_t kChunkSize = 2 * 1024 * 1024;
1008 ImagePreReader::PartialPreReadImageOnDisk(module_path, 0, kChunkSize));
1010 ImagePreReader::PartialPreReadImageOnDisk(module_path, 25, kChunkSize));
1012 ImagePreReader::PartialPreReadImageOnDisk(module_path, 50, kChunkSize));
1014 ImagePreReader::PartialPreReadImageOnDisk(module_path, 100, kChunkSize));
1016 ImagePreReader::PartialPreReadImageOnDisk(module_path, 150, kChunkSize));
1019 TEST(ImagePreReader, PartialPreReadImageInMemory) {
1020 base::FilePath current_exe;
1021 ASSERT_TRUE(PathService::Get(base::FILE_EXE, ¤t_exe));
1022 const wchar_t* module_path = current_exe.value().c_str();
1025 ImagePreReader::PartialPreReadImageInMemory(module_path, 0));
1027 ImagePreReader::PartialPreReadImageInMemory(module_path, 25));
1029 ImagePreReader::PartialPreReadImageInMemory(module_path, 50));
1031 ImagePreReader::PartialPreReadImageInMemory(module_path, 100));
1033 ImagePreReader::PartialPreReadImageInMemory(module_path, 150));
1036 TEST(ChromeFramePerf, DISABLED_HostActiveX) {
1037 // TODO(stoyan): Create a low integrity level thread && perform the test there
1038 SimpleModule module;
1040 CComObjectStackEx<ChromeFrameActiveXContainerPerf> wnd;
1041 wnd.CreateChromeFrameWindow("http://www.google.com");
1042 wnd.CreateControl(true);
1043 module.RunMessageLoop();
1046 TEST(ChromeFramePerf, DISABLED_HostActiveXInvalidURL) {
1047 // TODO(stoyan): Create a low integrity level thread && perform the test there
1048 SimpleModule module;
1050 CComObjectStackEx<ChromeFrameActiveXContainerPerf> wnd;
1051 wnd.CreateChromeFrameWindow("http://non-existent-domain.org/");
1052 wnd.CreateControl(true);
1053 module.RunMessageLoop();
1056 TEST_F(ChromeFrameStartupTestActiveX, PerfWarm) {
1057 RunStartupTest("warm", "t", "about:blank", false /* cold */, 0, NULL,
1058 true /* important */, false);
1061 TEST_F(ChromeFrameBinariesLoadTest, PerfWarm) {
1062 RunStartupTest("binary_load_warm", "t", "", false /* cold */, 0, NULL,
1063 true /* important */, false);
1066 TEST_F(ChromeFrameStartupTestActiveX, PerfCold) {
1067 SetConfigInt(L"PreRead", 0);
1068 base::FilePath binaries_to_evict[] = {
1069 ffmpegsumo_dll_, chrome_exe_, chrome_dll_, chrome_frame_dll_
1071 RunStartupTest("cold", "t", "about:blank", true /* cold */,
1072 arraysize(binaries_to_evict), binaries_to_evict,
1073 false /* not important */, false);
1074 DeleteConfigValue(L"PreRead");
1077 TEST_F(ChromeFrameStartupTestActiveX, PerfColdPreRead) {
1078 SetConfigInt(L"PreRead", 1);
1079 base::FilePath binaries_to_evict[] = {
1080 ffmpegsumo_dll_, chrome_exe_, chrome_dll_, chrome_frame_dll_
1082 RunStartupTest("cold_preread", "t", "about:blank", true /* cold */,
1083 arraysize(binaries_to_evict), binaries_to_evict,
1084 false /* not important */, false);
1085 DeleteConfigValue(L"PreRead");
1088 TEST_F(ChromeFrameBinariesLoadTest, PerfCold) {
1089 base::FilePath binaries_to_evict[] = {chrome_exe_, chrome_dll_};
1090 RunStartupTest("binary_load_cold", "t", "", true /* cold */,
1091 arraysize(binaries_to_evict), binaries_to_evict,
1092 false /* not important */, false);
1095 TEST_F(ChromeFrameBinariesLoadTest, PerfColdPreRead) {
1096 base::FilePath binaries_to_evict[] = {chrome_exe_, chrome_dll_};
1097 pre_read_type_ = kPreReadFull;
1098 RunStartupTest("binary_load_cold_preread", "t", "", true /* cold */,
1099 arraysize(binaries_to_evict), binaries_to_evict,
1100 false /* not important */, false);
1103 TEST_F(ChromeFrameBinariesLoadTest, PerfColdPartialPreRead15) {
1104 base::FilePath binaries_to_evict[] = {chrome_exe_, chrome_dll_};
1105 pre_read_type_ = kPreReadPartial;
1106 percentage_to_preread_ = 15;
1107 RunStartupTest("binary_load_cold_partial_preread", "t", "", true /* cold */,
1108 arraysize(binaries_to_evict), binaries_to_evict,
1109 false /* not important */, false);
1113 TEST_F(ChromeFrameBinariesLoadTest, PerfColdPartialPreRead25) {
1114 base::FilePath binaries_to_evict[] = {chrome_exe_, chrome_dll_};
1115 pre_read_type_ = kPreReadPartial;
1116 percentage_to_preread_ = 25;
1117 RunStartupTest("binary_load_cold_partial_preread", "t", "", true /* cold */,
1118 arraysize(binaries_to_evict), binaries_to_evict,
1119 false /* not important */, false);
1122 TEST_F(ChromeFrameBinariesLoadTest, PerfColdPartialPreRead40) {
1123 base::FilePath binaries_to_evict[] = {chrome_exe_, chrome_dll_};
1124 pre_read_type_ = kPreReadPartial;
1125 percentage_to_preread_ = 40;
1126 RunStartupTest("binary_load_cold_partial_preread", "t", "", true /* cold */,
1127 arraysize(binaries_to_evict), binaries_to_evict,
1128 false /* not important */, false);
1131 TEST_F(ChromeFrameStartupTestActiveXReference, PerfWarm) {
1132 RunStartupTest("warm", "t_ref", "about:blank", false /* cold */, 0, NULL,
1133 true /* important */, false);
1136 TEST_F(ChromeFrameStartupTestActiveX, PerfChromeFrameInitializationWarm) {
1137 RunStartupTest("ChromeFrame_init_warm", "t", "", false /* cold */, 0,
1138 NULL, true /* important */, false);
1141 TEST_F(ChromeFrameStartupTestActiveX, PerfChromeFrameInitializationCold) {
1142 base::FilePath binaries_to_evict[] = {chrome_frame_dll_};
1143 RunStartupTest("ChromeFrame_init_cold", "t", "", true /* cold */,
1144 arraysize(binaries_to_evict), binaries_to_evict,
1145 false /* not important */, false);
1148 TEST_F(ChromeFrameStartupTestActiveXReference,
1149 PerfChromeFrameInitializationWarm) {
1150 RunStartupTest("ChromeFrame_init_warm", "t_ref", "", false /* cold */, 0,
1151 NULL, true /* important */, false);
1154 typedef ChromeFrameActiveXMemoryTest<ChromeFrameMemoryTest>
1155 RegularChromeFrameActiveXMemoryTest;
1157 TEST_F(RegularChromeFrameActiveXMemoryTest, MemoryTestAboutBlank) {
1158 char *urls[] = {"about:blank"};
1159 RunTest("memory_about_blank", urls, arraysize(urls));
1163 // Revisit why the chrome frame dll does not unload correctly when this test is
1165 // http://code.google.com/p/chromium/issues/detail?id=47812
1166 TEST_F(RegularChromeFrameActiveXMemoryTest, DISABLED_MemoryTestUrls) {
1168 // We should use static pages to measure memory usage.
1170 "http://www.youtube.com/watch?v=PN2HAroA12w",
1171 "http://www.youtube.com/watch?v=KmLJDrsaJmk&feature=channel"
1174 RunTest("memory", urls, arraysize(urls));
1177 typedef ChromeFrameActiveXMemoryTest<ChromeFrameMemoryTestReference>
1178 ReferenceBuildChromeFrameActiveXMemoryTest;
1180 // Disabled to investigate why the chrome frame dll does not unload while
1181 // running this test.
1182 // http://code.google.com/p/chromium/issues/detail?id=47812
1183 TEST_F(ReferenceBuildChromeFrameActiveXMemoryTest,
1184 DISABLED_MemoryTestAboutBlank) {
1185 char *urls[] = {"about:blank"};
1186 RunTest("memory_about_blank_reference", urls, arraysize(urls));
1190 // Revisit why the chrome frame dll does not unload correctly when this test is
1192 TEST_F(ReferenceBuildChromeFrameActiveXMemoryTest, DISABLED_MemoryTestUrls) {
1194 // We should use static pages to measure memory usage.
1196 "http://www.youtube.com/watch?v=PN2HAroA12w",
1197 "http://www.youtube.com/watch?v=KmLJDrsaJmk&feature=channel"
1200 RunTest("memory_reference", urls, arraysize(urls));
1203 TEST_F(ChromeFrameCreationTest, PerfWarm) {
1204 RunStartupTest("creation_warm", "t", "", false /* cold */, 0,
1205 NULL, true /* important */, false);
1208 TEST_F(ChromeFrameCreationTestReference, PerfWarm) {
1209 RunStartupTest("creation_warm", "t_ref", "about:blank", false /* cold */, 0,
1210 NULL, true /* not important */, false);
1213 TEST_F(FlashCreationTest, DISABLED_PerfWarm) {
1214 RunStartupTest("creation_warm", "t_flash", "", false /* cold */, 0, NULL,
1215 true /* not important */, false);
1218 TEST_F(SilverlightCreationTest, DISABLED_PerfWarm) {
1219 RunStartupTest("creation_warm", "t_silverlight", "", false /* cold */, 0,
1220 NULL, false /* not important */, false);
1223 TEST_F(ChromeFrameCreationTest, PerfCold) {
1224 base::FilePath binaries_to_evict[] = {chrome_frame_dll_};
1226 RunStartupTest("creation_cold", "t", "", true /* cold */,
1227 arraysize(binaries_to_evict), binaries_to_evict,
1228 true /* important */, false);
1231 // Attempt to evict the Flash control can fail on the buildbot as the dll
1232 // is marked read only. The test run is aborted if we fail to evict the file
1233 // from the cache. This could also fail if the Flash control is in use.
1234 // On Vista this could fail because of UAC
1235 TEST_F(FlashCreationTest, PerfCold) {
1236 base::win::RegKey flash_key(HKEY_CLASSES_ROOT, kFlashControlKey, KEY_READ);
1238 std::wstring plugin_path;
1239 ASSERT_EQ(ERROR_SUCCESS, flash_key.ReadValue(L"", &plugin_path));
1240 ASSERT_FALSE(plugin_path.empty());
1242 base::FilePath flash_path = base::FilePath(plugin_path);
1243 base::FilePath binaries_to_evict[] = {flash_path};
1245 RunStartupTest("creation_cold", "t_flash", "", true /* cold */,
1246 arraysize(binaries_to_evict), binaries_to_evict,
1247 false/* important */, true);
1250 // This test would fail on Vista due to UAC or if the Silverlight control is
1251 // in use. The test run is aborted if we fail to evict the file from the cache.
1252 // Disabling this test as the Silverlight dll does not seem to get unloaded
1253 // correctly causing the attempt to evict the dll from the system cache to
1255 TEST_F(SilverlightCreationTest, DISABLED_PerfCold) {
1256 base::win::RegKey silverlight_key(HKEY_CLASSES_ROOT, kSilverlightControlKey,
1259 std::wstring plugin_path;
1260 ASSERT_EQ(ERROR_SUCCESS, silverlight_key.ReadValue(L"", &plugin_path));
1261 ASSERT_FALSE(plugin_path.empty());
1263 base::FilePath silverlight_path = base::FilePath(plugin_path);
1264 base::FilePath binaries_to_evict[] = {silverlight_path};
1266 RunStartupTest("creation_cold", "t_silverlight", "", true /* cold */,
1267 arraysize(binaries_to_evict), binaries_to_evict,
1268 false /* important */, true);
1273 // Derive from this class in order to receive custom events traced
1274 // via TRACE_EVENT_XXXX macros from ChromeFrame/Chrome.
1275 class TracedEvents {
1277 virtual void OnTraceEventBegin(EVENT_TRACE* event) {}
1278 virtual void OnTraceEventEnd(EVENT_TRACE* event) {}
1279 virtual void OnTraceEventInstant(EVENT_TRACE* event) {}
1282 // For the time being we pass to delegate only base::kTraceEventClass32
1283 // events i.e. these generated by TRACE_EVENT_XXXX macros.
1284 // We may need to add kernel provider and pass Process Start/Exit events etc,
1285 // but for the time being we stick with base::kChromeTraceProviderName
1287 class EtwConsumer : public base::win::EtwTraceConsumerBase<EtwConsumer> {
1297 void set_delegate(TracedEvents* delegate) {
1298 delegate_ = delegate;
1301 static void ProcessEvent(EVENT_TRACE* event) {
1303 if (event->Header.Guid != base::debug::kTraceEventClass32)
1305 if (event->Header.Class.Version != 0)
1308 switch (event->Header.Class.Type) {
1309 case base::debug::kTraceEventTypeBegin:
1310 delegate_->OnTraceEventBegin(event);
1312 case base::debug::kTraceEventTypeEnd:
1313 delegate_->OnTraceEventEnd(event);
1315 case base::debug::kTraceEventTypeInstant:
1316 delegate_->OnTraceEventInstant(event);
1324 static TracedEvents* delegate_;
1327 TracedEvents* EtwConsumer::delegate_ = NULL;
1330 class EtwPerfSession {
1336 base::DeleteFile(etl_log_file_, false);
1340 // To ensure there is no session leftover from crashes, previous runs, etc.
1341 base::win::EtwTraceProperties ignore;
1342 base::win::EtwTraceController::Stop(L"cf_perf", &ignore);
1343 ASSERT_TRUE(file_util::CreateTemporaryFile(&etl_log_file_));
1344 ASSERT_HRESULT_SUCCEEDED(controller_.StartFileSession(L"cf_perf",
1345 etl_log_file_.value().c_str(), false));
1346 ASSERT_HRESULT_SUCCEEDED(controller_.EnableProvider(
1347 base::debug::kChromeTraceProviderName,
1348 TRACE_LEVEL_INFORMATION,
1349 ~(base::debug::CAPTURE_STACK_TRACE)));
1353 return controller_.Stop(NULL);
1356 void AnalyzeOutput(TracedEvents* delegate) {
1357 EtwConsumer consumer;
1358 consumer.set_delegate(delegate);
1359 consumer.OpenFileSession(etl_log_file_.value().c_str());
1364 base::FilePath etl_log_file_;
1365 base::win::EtwTraceController controller_;
1368 // Base class for the tracing event helper classes.
1369 class MonitorTraceBase {
1371 static bool IsMatchingEvent(EVENT_TRACE* event,
1372 const base::StringPiece& event_to_compare) {
1373 return event->MofLength > event_to_compare.size() &&
1374 (memcmp(event_to_compare.data(), event->MofData,
1375 event_to_compare.size() + 1) == 0);
1378 bool is_valid() const {
1379 return !start_.is_null() && !end_.is_null() && start_ <= end_;
1382 base::TimeDelta duration() const {
1383 return end_ - start_;
1390 // This class measures the time between begin and end events of a particular
1392 class MonitorTracePair : public MonitorTraceBase,
1393 public TracedEvents {
1395 MonitorTracePair() : event_(NULL) {
1398 void set_interesting_event(const char* event) {
1402 virtual void OnTraceEventBegin(EVENT_TRACE* event) {
1403 if (IsMatchingEvent(event, event_)) {
1404 EXPECT_TRUE(start_.is_null());
1405 start_ = base::Time::FromFileTime(
1406 reinterpret_cast<FILETIME&>(event->Header.TimeStamp));
1410 virtual void OnTraceEventEnd(EVENT_TRACE* event) {
1411 if (IsMatchingEvent(event, event_)) {
1412 EXPECT_FALSE(start_.is_null());
1413 EXPECT_TRUE(end_.is_null());
1414 end_ = base::Time::FromFileTime(
1415 reinterpret_cast<FILETIME&>(event->Header.TimeStamp));
1419 base::StringPiece event_;
1422 // This class measures the time between two events.
1423 class MonitorTraceBetweenEventPair : public MonitorTraceBase,
1424 public TracedEvents {
1426 MonitorTraceBetweenEventPair() : event_end_(NULL),
1427 event_start_(NULL) {
1430 void set_start_event(const char* event) {
1431 event_start_ = event;
1434 void set_end_event(const char* event) {
1438 virtual void OnTraceEventBegin(EVENT_TRACE* event) {
1439 if (IsMatchingEvent(event, event_start_)) {
1440 EXPECT_TRUE(start_.is_null());
1441 EXPECT_TRUE(end_.is_null());
1442 start_ = base::Time::FromFileTime(
1443 reinterpret_cast<FILETIME&>(event->Header.TimeStamp));
1444 } else if (IsMatchingEvent(event, event_end_)) {
1445 EXPECT_FALSE(start_.is_null());
1446 EXPECT_TRUE(end_.is_null());
1447 end_ = base::Time::FromFileTime(
1448 reinterpret_cast<FILETIME&>(event->Header.TimeStamp));
1452 virtual void OnTraceEventEnd(EVENT_TRACE* event) {}
1454 base::StringPiece event_start_;
1455 base::StringPiece event_end_;
1458 // The very same as UIPerfTest::PrintResultXXXX without the need to
1459 // create an UIPerfTest instance.
1460 void PrintResultsImpl(const std::string& measurement,
1461 const std::string& modifier,
1462 const std::string& trace,
1463 const std::string& values,
1464 const std::string& prefix,
1465 const std::string& suffix,
1466 const std::string& units,
1468 // <*>RESULT <graph_name>: <trace_name>= <value> <units>
1469 // <*>RESULT <graph_name>: <trace_name>= {<mean>, <std deviation>} <units>
1470 // <*>RESULT <graph_name>: <trace_name>= [<value>,value,value,...,] <units>
1471 printf("%sRESULT %s%s: %s= %s%s%s %s\n",
1472 important ? "*" : "", measurement.c_str(), modifier.c_str(),
1473 trace.c_str(), prefix.c_str(), values.c_str(), suffix.c_str(),
1477 void PrintResultList(const std::string& measurement,
1478 const std::string& modifier,
1479 const std::string& trace,
1480 const std::string& values,
1481 const std::string& units,
1483 PrintResultsImpl(measurement, modifier, trace, values,
1484 "[", "]", units, important);
1487 bool RunSingleTestOutOfProc(const std::string& test_name) {
1488 base::FilePath path;
1489 if (!PathService::Get(base::DIR_EXE, &path))
1491 path = path.Append(L"chrome_frame_tests.exe");
1493 CommandLine cmd_line(path);
1494 // Always enable disabled tests. This method is not called with disabled
1495 // tests unless this flag was specified to the browser test executable.
1496 cmd_line.AppendSwitch("gtest_also_run_disabled_tests");
1497 cmd_line.AppendSwitchASCII("gtest_filter", test_name);
1499 base::ProcessHandle process_handle;
1500 if (!base::LaunchProcess(cmd_line, base::LaunchOptions(), &process_handle))
1503 base::TimeDelta test_terminate_timeout = base::TimeDelta::FromMinutes(1);
1505 if (!base::WaitForExitCodeWithTimeout(process_handle, &exit_code,
1506 test_terminate_timeout)) {
1507 LOG(ERROR) << "Test timeout (" << test_terminate_timeout.InMilliseconds()
1508 << " ms) exceeded for " << test_name;
1510 exit_code = -1; // Set a non-zero exit code to signal a failure.
1512 // Ensure that the process terminates.
1513 base::KillProcess(process_handle, -1, true);
1516 base::CloseProcessHandle(process_handle);
1518 return exit_code == 0;
1521 template <class Monitor>
1522 void PrintPerfTestResults(const Monitor* monitor,
1524 const char* result_name) {
1527 for (int i = 0; i < num_cycles; ++i) {
1528 ASSERT_TRUE(monitor[i].is_valid());
1529 base::StringAppendF(×,
1531 monitor[i].duration().InMillisecondsF());
1534 PrintResultList(result_name, "", "t", times, "ms", false);
1537 TEST(TestAsPerfTest, MetaTag_createproxy) {
1538 const int kNumCycles = 10;
1540 MonitorTracePair create_proxy_monitor[kNumCycles];
1541 MonitorTraceBetweenEventPair browser_main_start_monitor[kNumCycles];
1542 MonitorTraceBetweenEventPair browser_main_loop_monitor[kNumCycles];
1543 MonitorTraceBetweenEventPair automation_provider_start_monitor[kNumCycles];
1544 MonitorTraceBetweenEventPair automation_provider_connect_monitor[kNumCycles];
1545 MonitorTracePair external_tab_navigate_monitor[kNumCycles];
1546 MonitorTracePair pre_read_chrome_monitor[kNumCycles];
1547 MonitorTraceBetweenEventPair renderer_main_monitor[kNumCycles];
1549 for (int i = 0; i < kNumCycles; ++i) {
1550 EtwPerfSession perf_session;
1551 ASSERT_NO_FATAL_FAILURE(perf_session.Start());
1552 ASSERT_TRUE(RunSingleTestOutOfProc(
1553 "ChromeFrameTestWithWebServer.FullTabModeIE_MetaTag"));
1554 // Since we cannot have array of objects with a non-default constructor,
1555 // dedicated method is used to initialize watched event.
1556 create_proxy_monitor[i].set_interesting_event("chromeframe.createproxy");
1558 browser_main_start_monitor[i].set_start_event("chromeframe.createproxy");
1559 browser_main_start_monitor[i].set_end_event("BrowserMain");
1561 browser_main_loop_monitor[i].set_start_event("BrowserMain");
1562 browser_main_loop_monitor[i].set_end_event("BrowserMain:MESSAGE_LOOP");
1564 automation_provider_start_monitor[i].set_start_event("BrowserMain");
1565 automation_provider_start_monitor[i].set_end_event(
1566 "AutomationProvider::AutomationProvider");
1568 automation_provider_connect_monitor[i].set_start_event(
1569 "AutomationProvider::AutomationProvider");
1570 automation_provider_connect_monitor[i].set_end_event(
1571 "AutomationProvider::InitializeChannel");
1573 external_tab_navigate_monitor[i].set_interesting_event(
1574 "ExternalTabContainerWin::Navigate");
1576 renderer_main_monitor[i].set_start_event(
1577 "ExternalTabContainerWin::Navigate");
1578 renderer_main_monitor[i].set_end_event("RendererMain");
1580 pre_read_chrome_monitor[i].set_interesting_event("PreReadImage");
1582 ASSERT_HRESULT_SUCCEEDED(perf_session.Stop());
1584 perf_session.AnalyzeOutput(&create_proxy_monitor[i]);
1585 perf_session.AnalyzeOutput(&browser_main_start_monitor[i]);
1586 perf_session.AnalyzeOutput(&browser_main_loop_monitor[i]);
1587 perf_session.AnalyzeOutput(&automation_provider_start_monitor[i]);
1588 perf_session.AnalyzeOutput(&automation_provider_connect_monitor[i]);
1589 perf_session.AnalyzeOutput(&external_tab_navigate_monitor[i]);
1590 perf_session.AnalyzeOutput(&pre_read_chrome_monitor[i]);
1591 perf_session.AnalyzeOutput(&renderer_main_monitor[i]);
1595 PrintPerfTestResults(create_proxy_monitor, kNumCycles, "createproxy");
1596 PrintPerfTestResults(browser_main_start_monitor, kNumCycles,
1598 PrintPerfTestResults(browser_main_loop_monitor, kNumCycles,
1600 PrintPerfTestResults(automation_provider_start_monitor, kNumCycles,
1601 "automationproviderstart");
1602 PrintPerfTestResults(automation_provider_connect_monitor, kNumCycles,
1603 "automationproviderconnect");
1604 PrintPerfTestResults(external_tab_navigate_monitor, kNumCycles,
1605 "externaltabnavigate");
1606 PrintPerfTestResults(renderer_main_monitor, kNumCycles,
1607 "beginrenderermain");
1609 PrintPerfTestResults(pre_read_chrome_monitor, kNumCycles, "PreReadImage");