Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(530)

Side by Side Diff: chrome_frame/test/perf/chrome_frame_perftest.cc

Issue 126143005: Remove Chrome Frame code and resources. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: sync to r244038 Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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(&times, "%.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, &current_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, &current_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, &current_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, &current_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(&times,
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 }
OLDNEW
« no previous file with comments | « chrome_frame/test/perf/chrome_frame_perftest.h ('k') | chrome_frame/test/perf/chrometab_perftests.vcproj » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698