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 "base/command_line.h" 6#include "base/environment.h" 7#include "base/file_util.h" 8#include "base/files/file_path.h" 9#include "base/memory/scoped_ptr.h" 10#include "base/path_service.h" 11#include "base/strings/stringprintf.h" 12#include "base/strings/utf_string_conversions.h" 13#include "base/threading/platform_thread.h" 14#include "base/time/time.h" 15#include "chrome/app/chrome_command_ids.h" 16#include "chrome/common/chrome_paths.h" 17#include "chrome/common/chrome_switches.h" 18#include "chrome/common/env_vars.h" 19#include "chrome/test/automation/automation_proxy.h" 20#include "chrome/test/automation/browser_proxy.h" 21#include "chrome/test/automation/tab_proxy.h" 22#include "chrome/test/perf/perf_test.h" 23#include "chrome/test/ui/ui_perf_test.h" 24#include "net/base/net_util.h" 25#include "url/gurl.h" 26 27using base::TimeDelta; 28 29namespace { 30 31// This Automated UI test opens static files in different tabs in a proxy 32// browser. After all the tabs have opened, it switches between tabs, and notes 33// time taken for each switch. It then prints out the times on the console, 34// with the aim that the page cycler parser can interpret these numbers to 35// draw graphs for page cycler Tab Switching Performance. 36class TabSwitchingUITest : public UIPerfTest { 37 public: 38 TabSwitchingUITest() { 39 PathService::Get(base::DIR_SOURCE_ROOT, &path_prefix_); 40 path_prefix_ = path_prefix_.AppendASCII("data"); 41 path_prefix_ = path_prefix_.AppendASCII("tab_switching"); 42 43 show_window_ = true; 44 } 45 46 virtual void SetUp() { 47 // Set the log_file_name_ path according to the selected browser_directory_. 48 log_file_name_ = browser_directory_.AppendASCII("chrome_debug.log"); 49 50 // Set the log file path for the browser test. 51 scoped_ptr<base::Environment> env(base::Environment::Create()); 52#if defined(OS_WIN) 53 env->SetVar(env_vars::kLogFileName, WideToUTF8(log_file_name_.value())); 54#else 55 env->SetVar(env_vars::kLogFileName, log_file_name_.value()); 56#endif 57 58 // Add the necessary arguments to Chrome's launch command for these tests. 59 AddLaunchArguments(); 60 61 // Run the rest of the UITest initialization. 62 UITest::SetUp(); 63 } 64 65 static const int kNumCycles = 5; 66 67 void PrintTimings(const char* label, TimeDelta timings[kNumCycles], 68 bool important) { 69 std::string times; 70 for (int i = 0; i < kNumCycles; ++i) 71 base::StringAppendF(×, "%.2f,", timings[i].InMillisecondsF()); 72 perf_test::PrintResultList( 73 "times", std::string(), label, times, "ms", important); 74 } 75 76 void RunTabSwitchingUITest(const char* label, bool important) { 77 // Shut down from window UITest sets up automatically. 78 UITest::TearDown(); 79 80 TimeDelta timings[kNumCycles]; 81 for (int i = 0; i < kNumCycles; ++i) { 82 // Prepare for this test run. 83 SetUp(); 84 85 // Create a browser proxy. 86 browser_proxy_ = automation()->GetBrowserWindow(0); 87 88 // Open all the tabs. 89 int initial_tab_count = 0; 90 ASSERT_TRUE(browser_proxy_->GetTabCount(&initial_tab_count)); 91 int new_tab_count = OpenTabs(); 92 int tab_count = -1; 93 ASSERT_TRUE(browser_proxy_->GetTabCount(&tab_count)); 94 ASSERT_EQ(initial_tab_count + new_tab_count, tab_count); 95 96 // Switch linearly between tabs. 97 ASSERT_TRUE(browser_proxy_->ActivateTab(0)); 98 int final_tab_count = 0; 99 ASSERT_TRUE(browser_proxy_->GetTabCount(&final_tab_count)); 100 for (int j = initial_tab_count; j < final_tab_count; ++j) { 101 ASSERT_TRUE(browser_proxy_->ActivateTab(j)); 102 ASSERT_TRUE(browser_proxy_->WaitForTabToBecomeActive( 103 j, base::TimeDelta::FromSeconds(10))); 104 } 105 106 // Close the browser to force a dump of log. 107 bool application_closed = false; 108 EXPECT_TRUE(CloseBrowser(browser_proxy_.get(), &application_closed)); 109 110 // Open the corresponding log file and collect average from the 111 // histogram stats generated for RenderWidgetHost_TabSwitchPaintDuration. 112 bool log_has_been_dumped = false; 113 std::string contents; 114 int max_tries = 20; 115 do { 116 log_has_been_dumped = file_util::ReadFileToString(log_file_name_, 117 &contents); 118 if (!log_has_been_dumped) 119 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100)); 120 } while (!log_has_been_dumped && max_tries--); 121 ASSERT_TRUE(log_has_been_dumped) << "Failed to read the log file"; 122 123 // Parse the contents to get average. 124 int64 average = 0; 125 const std::string average_str("average = "); 126 std::string::size_type pos = contents.find( 127 "Histogram: MPArch.RWH_TabSwitchPaintDuration", 0); 128 std::string::size_type comma_pos; 129 std::string::size_type number_length; 130 131 ASSERT_NE(pos, std::string::npos) << 132 "Histogram: MPArch.RWH_TabSwitchPaintDuration wasn't found\n" << 133 contents; 134 135 // Get the average. 136 pos = contents.find(average_str, pos); 137 comma_pos = contents.find(",", pos); 138 pos += average_str.length(); 139 number_length = comma_pos - pos; 140 average = atoi(contents.substr(pos, number_length).c_str()); 141 142 // Print the average and standard deviation. 143 timings[i] = TimeDelta::FromMilliseconds(average); 144 145 // Clean up from the test run. 146 UITest::TearDown(); 147 } 148 PrintTimings(label, timings, important); 149 } 150 151 protected: 152 // Opens new tabs. Returns the number of tabs opened. 153 int OpenTabs() { 154 // Add tabs. 155 static const char* files[] = { "espn.go.com", "bugzilla.mozilla.org", 156 "news.cnet.com", "www.amazon.com", 157 "kannada.chakradeo.net", "allegro.pl", 158 "ml.wikipedia.org", "www.bbc.co.uk", 159 "126.com", "www.altavista.com"}; 160 int number_of_new_tabs_opened = 0; 161 base::FilePath file_name; 162 for (size_t i = 0; i < arraysize(files); ++i) { 163 file_name = path_prefix_; 164 file_name = file_name.AppendASCII(files[i]); 165 file_name = file_name.AppendASCII("index.html"); 166 bool success = 167 browser_proxy_->AppendTab(net::FilePathToFileURL(file_name)); 168 EXPECT_TRUE(success); 169 if (success) 170 number_of_new_tabs_opened++; 171 } 172 173 return number_of_new_tabs_opened; 174 } 175 176 base::FilePath path_prefix_; 177 base::FilePath log_file_name_; 178 scoped_refptr<BrowserProxy> browser_proxy_; 179 180 private: 181 void AddLaunchArguments() { 182 launch_arguments_.AppendSwitch(switches::kEnableLogging); 183 launch_arguments_.AppendSwitchASCII(switches::kLoggingLevel, "0"); 184 } 185 186 DISALLOW_COPY_AND_ASSIGN(TabSwitchingUITest); 187}; 188 189// This is failing, and taking forever to finish when doing so. 190// http://crbug.com/102162 191 192TEST_F(TabSwitchingUITest, DISABLED_TabSwitch) { 193 RunTabSwitchingUITest("t", true); 194} 195 196// Started failing with a webkit roll in r49936. See http://crbug.com/46751 197TEST_F(TabSwitchingUITest, DISABLED_TabSwitchRef) { 198 UseReferenceBuild(); 199 RunTabSwitchingUITest("t_ref", true); 200} 201 202} // namespace 203