1 // Copyright 2013 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 "base/basictypes.h"
6 #include "base/command_line.h"
8 #include "base/mac/mac_util.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/test/trace_event_analyzer.h"
12 #include "base/win/windows_version.h"
13 #include "chrome/browser/extensions/extension_apitest.h"
14 #include "chrome/browser/extensions/extension_service.h"
15 #include "chrome/browser/extensions/extension_test_message_listener.h"
16 #include "chrome/browser/extensions/tab_helper.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/ui/fullscreen/fullscreen_controller.h"
19 #include "chrome/common/chrome_switches.h"
20 #include "chrome/common/chrome_version_info.h"
21 #include "chrome/common/extensions/features/base_feature_provider.h"
22 #include "chrome/common/extensions/features/complex_feature.h"
23 #include "chrome/common/extensions/features/simple_feature.h"
24 #include "chrome/test/base/test_launcher_utils.h"
25 #include "chrome/test/base/test_switches.h"
26 #include "chrome/test/base/tracing.h"
27 #include "content/public/browser/render_process_host.h"
28 #include "content/public/browser/render_view_host.h"
29 #include "content/public/common/content_switches.h"
30 #include "extensions/common/feature_switch.h"
31 #include "extensions/common/features/feature.h"
32 #include "testing/gtest/include/gtest/gtest.h"
33 #include "testing/perf/perf_test.h"
34 #include "ui/compositor/compositor_switches.h"
35 #include "ui/gl/gl_switches.h"
39 const char kExtensionId[] = "ddchlicdkolnonkihahngkmmmjnjlkkf";
42 kUseGpu = 1 << 0, // Only execute test if --enable-gpu was given
43 // on the command line. This is required for
44 // tests that run on GPU.
45 kForceGpuComposited = 1 << 1, // Force the test to use the compositor.
46 kDisableVsync = 1 << 2, // Do not limit framerate to vertical refresh.
47 // when on GPU, nor to 60hz when not on GPU.
48 kTestThroughWebRTC = 1 << 3, // Send captured frames through webrtc
49 kSmallWindow = 1 << 4, // 1 = 800x600, 0 = 2000x1000
51 kScaleQualityMask = 3 << 5, // two bits select which scaling quality
52 kScaleQualityDefault = 0 << 5, // to use on aura.
53 kScaleQualityFast = 1 << 5,
54 kScaleQualityGood = 2 << 5,
55 kScaleQualityBest = 3 << 5,
58 class TabCapturePerformanceTest
59 : public ExtensionApiTest,
60 public testing::WithParamInterface<int> {
62 TabCapturePerformanceTest() {}
64 bool HasFlag(TestFlags flag) const {
65 return (GetParam() & flag) == flag;
68 bool IsGpuAvailable() const {
69 return CommandLine::ForCurrentProcess()->HasSwitch("enable-gpu");
72 std::string ScalingMethod() const {
73 switch (GetParam() & kScaleQualityMask) {
74 case kScaleQualityFast:
76 case kScaleQualityGood:
78 case kScaleQualityBest:
85 std::string GetSuffixForTestFlags() {
87 if (HasFlag(kForceGpuComposited))
91 if (HasFlag(kDisableVsync))
93 if (HasFlag(kTestThroughWebRTC))
95 if (!ScalingMethod().empty())
96 suffix += "_scale" + ScalingMethod();
97 if (HasFlag(kSmallWindow))
102 virtual void SetUp() OVERRIDE {
104 ExtensionApiTest::SetUp();
107 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
108 if (!ScalingMethod().empty()) {
109 command_line->AppendSwitchASCII(switches::kTabCaptureUpscaleQuality,
111 command_line->AppendSwitchASCII(switches::kTabCaptureDownscaleQuality,
115 // Some of the tests may launch http requests through JSON or AJAX
116 // which causes a security error (cross domain request) when the page
117 // is loaded from the local file system ( file:// ). The following switch
119 command_line->AppendSwitch(switches::kAllowFileAccessFromFiles);
121 if (HasFlag(kSmallWindow)) {
122 command_line->AppendSwitchASCII(switches::kWindowSize, "800,600");
124 command_line->AppendSwitchASCII(switches::kWindowSize, "2000,1500");
127 if (!HasFlag(kUseGpu)) {
128 command_line->AppendSwitch(switches::kDisableGpu);
130 command_line->AppendSwitch(switches::kForceCompositingMode);
133 if (HasFlag(kDisableVsync))
134 command_line->AppendSwitch(switches::kDisableGpuVsync);
136 command_line->AppendSwitchASCII(switches::kWhitelistedExtensionID,
138 ExtensionApiTest::SetUpCommandLine(command_line);
141 bool PrintResults(trace_analyzer::TraceAnalyzer *analyzer,
142 const std::string& test_name,
143 const std::string& event_name,
144 const std::string& unit) {
145 trace_analyzer::TraceEventVector events;
146 trace_analyzer::Query query =
147 trace_analyzer::Query::EventNameIs(event_name) &&
148 (trace_analyzer::Query::EventPhaseIs(TRACE_EVENT_PHASE_BEGIN) ||
149 trace_analyzer::Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_BEGIN) ||
150 trace_analyzer::Query::EventPhaseIs(TRACE_EVENT_PHASE_FLOW_BEGIN) ||
151 trace_analyzer::Query::EventPhaseIs(TRACE_EVENT_PHASE_INSTANT));
152 analyzer->FindEvents(query, &events);
153 if (events.size() < 20) {
154 LOG(ERROR) << "Not enough events of type " << event_name << " found.";
158 // Ignore some events for startup/setup/caching.
159 trace_analyzer::TraceEventVector rate_events(events.begin() + 3,
161 trace_analyzer::RateStats stats;
162 if (!GetRateStats(rate_events, &stats, NULL)) {
163 LOG(ERROR) << "GetRateStats failed";
166 double mean_ms = stats.mean_us / 1000.0;
167 double std_dev_ms = stats.standard_deviation_us / 1000.0;
168 std::string mean_and_error = base::StringPrintf("%f,%f", mean_ms,
170 perf_test::PrintResultMeanAndError(test_name,
171 GetSuffixForTestFlags(),
179 void RunTest(const std::string& test_name) {
180 if (HasFlag(kUseGpu) && !IsGpuAvailable()) {
182 "Test skipped: requires gpu. Pass --enable-gpu on the command "
183 "line if use of GPU is desired.";
187 std::string json_events;
188 ASSERT_TRUE(tracing::BeginTracing("test_fps,mirroring"));
189 std::string page = "performance.html";
190 page += HasFlag(kTestThroughWebRTC) ? "?WebRTC=1" : "?WebRTC=0";
191 // Ideally we'd like to run a higher capture rate when vsync is disabled,
192 // but libjingle currently doesn't allow that.
193 // page += HasFlag(kDisableVsync) ? "&fps=300" : "&fps=30";
195 ASSERT_TRUE(RunExtensionSubtest("tab_capture", page)) << message_;
196 ASSERT_TRUE(tracing::EndTracing(&json_events));
197 scoped_ptr<trace_analyzer::TraceAnalyzer> analyzer;
198 analyzer.reset(trace_analyzer::TraceAnalyzer::Create(json_events));
200 // Only one of these PrintResults should actually print something.
201 // The printed result will be the average time between frames in the
203 bool sw_frames = PrintResults(analyzer.get(),
207 bool gpu_frames = PrintResults(analyzer.get(),
211 EXPECT_TRUE(sw_frames || gpu_frames);
212 EXPECT_NE(sw_frames, gpu_frames);
214 // This prints out the average time between capture events.
215 // As the capture frame rate is capped at 30fps, this score
216 // cannot get any better than (lower) 33.33 ms.
217 EXPECT_TRUE(PrintResults(analyzer.get(),
226 IN_PROC_BROWSER_TEST_P(TabCapturePerformanceTest, Performance) {
227 RunTest("TabCapturePerformance");
230 // Note: First argument is optional and intentionally left blank.
231 // (it's a prefix for the generated test cases)
232 INSTANTIATE_TEST_CASE_P(
234 TabCapturePerformanceTest,
237 kUseGpu | kForceGpuComposited,
239 kDisableVsync | kUseGpu | kForceGpuComposited,
241 kTestThroughWebRTC | kUseGpu | kForceGpuComposited,
242 kTestThroughWebRTC | kDisableVsync,
243 kTestThroughWebRTC | kDisableVsync | kUseGpu | kForceGpuComposited));
245 #if defined(USE_AURA)
247 // These are temporary tests for the purpose of determining what the
248 // appropriate scaling quality is. Once that has been determined,
249 // these tests will be removed.
251 const int kScalingTestBase =
252 kTestThroughWebRTC | kDisableVsync | kUseGpu | kForceGpuComposited;
254 INSTANTIATE_TEST_CASE_P(
256 TabCapturePerformanceTest,
258 kScalingTestBase | kScaleQualityFast,
259 kScalingTestBase | kScaleQualityGood,
260 kScalingTestBase | kScaleQualityBest,
261 kScalingTestBase | kScaleQualityFast | kSmallWindow,
262 kScalingTestBase | kScaleQualityGood | kSmallWindow,
263 kScalingTestBase | kScaleQualityBest | kSmallWindow));