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"
7 #include "base/strings/stringprintf.h"
8 #include "base/test/trace_event_analyzer.h"
9 #include "base/win/windows_version.h"
10 #include "chrome/browser/extensions/extension_apitest.h"
11 #include "chrome/browser/extensions/extension_service.h"
12 #include "chrome/browser/extensions/tab_helper.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h"
15 #include "chrome/common/chrome_switches.h"
16 #include "chrome/common/chrome_version_info.h"
17 #include "chrome/test/base/test_launcher_utils.h"
18 #include "chrome/test/base/test_switches.h"
19 #include "chrome/test/base/tracing.h"
20 #include "content/public/common/content_switches.h"
21 #include "extensions/common/feature_switch.h"
22 #include "extensions/common/features/base_feature_provider.h"
23 #include "extensions/common/features/complex_feature.h"
24 #include "extensions/common/features/feature.h"
25 #include "extensions/common/features/simple_feature.h"
26 #include "extensions/common/switches.h"
27 #include "extensions/test/extension_test_message_listener.h"
28 #include "testing/gtest/include/gtest/gtest.h"
29 #include "testing/perf/perf_test.h"
30 #include "ui/compositor/compositor_switches.h"
31 #include "ui/gl/gl_switches.h"
35 const char kExtensionId
[] = "ddchlicdkolnonkihahngkmmmjnjlkkf";
38 kUseGpu
= 1 << 0, // Only execute test if --enable-gpu was given
39 // on the command line. This is required for
40 // tests that run on GPU.
41 kForceGpuComposited
= 1 << 1, // Force the test to use the compositor.
42 kDisableVsync
= 1 << 2, // Do not limit framerate to vertical refresh.
43 // when on GPU, nor to 60hz when not on GPU.
44 kTestThroughWebRTC
= 1 << 3, // Send captured frames through webrtc
45 kSmallWindow
= 1 << 4, // 1 = 800x600, 0 = 2000x1000
47 kScaleQualityMask
= 3 << 5, // two bits select which scaling quality
48 kScaleQualityDefault
= 0 << 5, // to use on aura.
49 kScaleQualityFast
= 1 << 5,
50 kScaleQualityGood
= 2 << 5,
51 kScaleQualityBest
= 3 << 5,
54 class TabCapturePerformanceTest
55 : public ExtensionApiTest
,
56 public testing::WithParamInterface
<int> {
58 TabCapturePerformanceTest() {}
60 bool HasFlag(TestFlags flag
) const {
61 return (GetParam() & flag
) == flag
;
64 bool IsGpuAvailable() const {
65 return base::CommandLine::ForCurrentProcess()->HasSwitch("enable-gpu");
68 std::string
ScalingMethod() const {
69 switch (GetParam() & kScaleQualityMask
) {
70 case kScaleQualityFast
:
72 case kScaleQualityGood
:
74 case kScaleQualityBest
:
81 std::string
GetSuffixForTestFlags() {
83 if (HasFlag(kForceGpuComposited
))
87 if (HasFlag(kDisableVsync
))
89 if (HasFlag(kTestThroughWebRTC
))
91 if (!ScalingMethod().empty())
92 suffix
+= "_scale" + ScalingMethod();
93 if (HasFlag(kSmallWindow
))
98 void SetUp() override
{
100 ExtensionApiTest::SetUp();
103 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
104 if (!ScalingMethod().empty()) {
105 command_line
->AppendSwitchASCII(switches::kTabCaptureUpscaleQuality
,
107 command_line
->AppendSwitchASCII(switches::kTabCaptureDownscaleQuality
,
111 // Some of the tests may launch http requests through JSON or AJAX
112 // which causes a security error (cross domain request) when the page
113 // is loaded from the local file system ( file:// ). The following switch
115 command_line
->AppendSwitch(switches::kAllowFileAccessFromFiles
);
117 if (HasFlag(kSmallWindow
)) {
118 command_line
->AppendSwitchASCII(switches::kWindowSize
, "800,600");
120 command_line
->AppendSwitchASCII(switches::kWindowSize
, "2000,1500");
123 if (!HasFlag(kUseGpu
))
124 command_line
->AppendSwitch(switches::kDisableGpu
);
126 if (HasFlag(kDisableVsync
))
127 command_line
->AppendSwitch(switches::kDisableGpuVsync
);
129 command_line
->AppendSwitchASCII(
130 extensions::switches::kWhitelistedExtensionID
,
132 ExtensionApiTest::SetUpCommandLine(command_line
);
135 bool PrintResults(trace_analyzer::TraceAnalyzer
*analyzer
,
136 const std::string
& test_name
,
137 const std::string
& event_name
,
138 const std::string
& unit
) {
139 trace_analyzer::TraceEventVector events
;
140 trace_analyzer::Query query
=
141 trace_analyzer::Query::EventNameIs(event_name
) &&
142 (trace_analyzer::Query::EventPhaseIs(TRACE_EVENT_PHASE_BEGIN
) ||
143 trace_analyzer::Query::EventPhaseIs(TRACE_EVENT_PHASE_COMPLETE
) ||
144 trace_analyzer::Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_BEGIN
) ||
145 trace_analyzer::Query::EventPhaseIs(TRACE_EVENT_PHASE_FLOW_BEGIN
) ||
146 trace_analyzer::Query::EventPhaseIs(TRACE_EVENT_PHASE_INSTANT
));
147 analyzer
->FindEvents(query
, &events
);
148 if (events
.size() < 20) {
149 LOG(ERROR
) << "Not enough events of type " << event_name
<< " found ("
150 << events
.size() << ").";
154 // Ignore some events for startup/setup/caching.
155 trace_analyzer::TraceEventVector
rate_events(events
.begin() + 3,
157 trace_analyzer::RateStats stats
;
158 if (!GetRateStats(rate_events
, &stats
, NULL
)) {
159 LOG(ERROR
) << "GetRateStats failed";
162 double mean_ms
= stats
.mean_us
/ 1000.0;
163 double std_dev_ms
= stats
.standard_deviation_us
/ 1000.0;
164 std::string mean_and_error
= base::StringPrintf("%f,%f", mean_ms
,
166 perf_test::PrintResultMeanAndError(test_name
,
167 GetSuffixForTestFlags(),
175 void RunTest(const std::string
& test_name
) {
176 if (HasFlag(kUseGpu
) && !IsGpuAvailable()) {
178 "Test skipped: requires gpu. Pass --enable-gpu on the command "
179 "line if use of GPU is desired.";
183 std::string json_events
;
184 ASSERT_TRUE(tracing::BeginTracing("gpu,gpu.capture"));
185 std::string page
= "performance.html";
186 page
+= HasFlag(kTestThroughWebRTC
) ? "?WebRTC=1" : "?WebRTC=0";
187 // Ideally we'd like to run a higher capture rate when vsync is disabled,
188 // but libjingle currently doesn't allow that.
189 // page += HasFlag(kDisableVsync) ? "&fps=300" : "&fps=30";
191 ASSERT_TRUE(RunExtensionSubtest("tab_capture", page
)) << message_
;
192 ASSERT_TRUE(tracing::EndTracing(&json_events
));
193 scoped_ptr
<trace_analyzer::TraceAnalyzer
> analyzer
;
194 analyzer
.reset(trace_analyzer::TraceAnalyzer::Create(json_events
));
196 // The printed result will be the average time between frames in the
198 bool gpu_frames
= PrintResults(
201 "RenderWidget::DidCommitAndDrawCompositorFrame",
203 EXPECT_TRUE(gpu_frames
);
205 // This prints out the average time between capture events.
206 // As the capture frame rate is capped at 30fps, this score
207 // cannot get any better than (lower) 33.33 ms.
208 // TODO(ericrk): Remove the "Capture" result once we are confident that
209 // "CaptureSucceeded" is giving the coverage we want. crbug.com/489817
210 EXPECT_TRUE(PrintResults(analyzer
.get(),
215 // Also track the CaptureSucceeded event. Capture only indicates that a
216 // capture was requested, but this capture may later be aborted without
217 // running. CaptureSucceeded tracks successful frame captures.
219 PrintResults(analyzer
.get(), test_name
, "CaptureSucceeded", "ms"));
225 IN_PROC_BROWSER_TEST_P(TabCapturePerformanceTest
, Performance
) {
226 RunTest("TabCapturePerformance");
229 // Note: First argument is optional and intentionally left blank.
230 // (it's a prefix for the generated test cases)
231 INSTANTIATE_TEST_CASE_P(
233 TabCapturePerformanceTest
,
236 kUseGpu
| kForceGpuComposited
,
238 kDisableVsync
| kUseGpu
| kForceGpuComposited
,
240 kTestThroughWebRTC
| kUseGpu
| kForceGpuComposited
,
241 kTestThroughWebRTC
| kDisableVsync
,
242 kTestThroughWebRTC
| kDisableVsync
| kUseGpu
| kForceGpuComposited
));
244 #if defined(USE_AURA)
246 // These are temporary tests for the purpose of determining what the
247 // appropriate scaling quality is. Once that has been determined,
248 // these tests will be removed.
250 const int kScalingTestBase
=
251 kTestThroughWebRTC
| kDisableVsync
| kUseGpu
| kForceGpuComposited
;
253 INSTANTIATE_TEST_CASE_P(
255 TabCapturePerformanceTest
,
257 kScalingTestBase
| kScaleQualityFast
,
258 kScalingTestBase
| kScaleQualityGood
,
259 kScalingTestBase
| kScaleQualityBest
,
260 kScalingTestBase
| kScaleQualityFast
| kSmallWindow
,
261 kScalingTestBase
| kScaleQualityGood
| kSmallWindow
,
262 kScalingTestBase
| kScaleQualityBest
| kSmallWindow
));