blob: c759e5623689ed7181091e8f23dd03cb30cabf51 [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/basictypes.h"
#include "base/command_line.h"
#if defined(OS_MACOSX)
#include "base/mac/mac_util.h"
#endif
#include "base/strings/stringprintf.h"
#include "base/test/trace_event_analyzer.h"
#include "base/win/windows_version.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_test_message_listener.h"
#include "chrome/browser/extensions/tab_helper.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/fullscreen/fullscreen_controller.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/chrome_version_info.h"
#include "chrome/common/extensions/feature_switch.h"
#include "chrome/common/extensions/features/base_feature_provider.h"
#include "chrome/common/extensions/features/complex_feature.h"
#include "chrome/common/extensions/features/simple_feature.h"
#include "chrome/test/base/test_launcher_utils.h"
#include "chrome/test/base/test_switches.h"
#include "chrome/test/base/tracing.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/common/content_switches.h"
#include "extensions/common/features/feature.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/perf/perf_test.h"
#include "ui/compositor/compositor_switches.h"
#include "ui/gl/gl_switches.h"
namespace chrome {
namespace {
const char kExtensionId[] = "ddchlicdkolnonkihahngkmmmjnjlkkf";
enum TestFlags {
kUseGpu = 1 << 0, // Only execute test if --enable-gpu was given
// on the command line. This is required for
// tests that run on GPU.
kForceGpuComposited = 1 << 1, // Force the test to use the compositor.
kDisableVsync = 1 << 2, // Do not limit framerate to vertical refresh.
// when on GPU, nor to 60hz when not on GPU.
kTestThroughWebRTC = 1 << 3, // Send captured frames through webrtc
kSmallWindow = 1 << 4, // 1 = 800x600, 0 = 2000x1000
kScaleQualityMask = 3 << 5, // two bits select which scaling quality
kScaleQualityDefault = 0 << 5, // to use on aura.
kScaleQualityFast = 1 << 5,
kScaleQualityGood = 2 << 5,
kScaleQualityBest = 3 << 5,
};
class TabCapturePerformanceTest
: public ExtensionApiTest,
public testing::WithParamInterface<int> {
public:
TabCapturePerformanceTest() {}
bool HasFlag(TestFlags flag) const {
return (GetParam() & flag) == flag;
}
bool IsGpuAvailable() const {
return CommandLine::ForCurrentProcess()->HasSwitch("enable-gpu");
}
std::string ScalingMethod() const {
switch (GetParam() & kScaleQualityMask) {
case kScaleQualityFast:
return "fast";
case kScaleQualityGood:
return "good";
case kScaleQualityBest:
return "best";
default:
return "";
}
}
std::string GetSuffixForTestFlags() {
std::string suffix;
if (HasFlag(kForceGpuComposited))
suffix += "_comp";
if (HasFlag(kUseGpu))
suffix += "_gpu";
if (HasFlag(kDisableVsync))
suffix += "_novsync";
if (HasFlag(kTestThroughWebRTC))
suffix += "_webrtc";
if (!ScalingMethod().empty())
suffix += "_scale" + ScalingMethod();
if (HasFlag(kSmallWindow))
suffix += "_small";
return suffix;
}
virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
if (!ScalingMethod().empty()) {
command_line->AppendSwitchASCII(switches::kTabCaptureUpscaleQuality,
ScalingMethod());
command_line->AppendSwitchASCII(switches::kTabCaptureDownscaleQuality,
ScalingMethod());
}
// UI tests boot up render views starting from about:blank. This causes
// the renderer to start up thinking it cannot use the GPU. To work
// around that, and allow the frame rate test to use the GPU, we must
// pass kAllowWebUICompositing.
command_line->AppendSwitch(switches::kAllowWebUICompositing);
// Some of the tests may launch http requests through JSON or AJAX
// which causes a security error (cross domain request) when the page
// is loaded from the local file system ( file:// ). The following switch
// fixes that error.
command_line->AppendSwitch(switches::kAllowFileAccessFromFiles);
if (HasFlag(kSmallWindow)) {
command_line->AppendSwitchASCII(switches::kWindowSize, "800,600");
} else {
command_line->AppendSwitchASCII(switches::kWindowSize, "2000,1500");
}
command_line->AppendSwitch(switches::kDisableTestCompositor);
if (!HasFlag(kUseGpu)) {
command_line->AppendSwitch(switches::kDisableAcceleratedCompositing);
command_line->AppendSwitch(switches::kDisableExperimentalWebGL);
command_line->AppendSwitch(switches::kDisableAccelerated2dCanvas);
} else {
command_line->AppendSwitch(switches::kForceCompositingMode);
}
if (HasFlag(kDisableVsync))
command_line->AppendSwitch(switches::kDisableGpuVsync);
command_line->AppendSwitchASCII(switches::kWhitelistedExtensionID,
kExtensionId);
ExtensionApiTest::SetUpCommandLine(command_line);
}
bool PrintResults(trace_analyzer::TraceAnalyzer *analyzer,
const std::string& test_name,
const std::string& event_name,
const std::string& unit) {
trace_analyzer::TraceEventVector events;
trace_analyzer::Query query =
trace_analyzer::Query::EventNameIs(event_name) &&
(trace_analyzer::Query::EventPhaseIs(TRACE_EVENT_PHASE_BEGIN) ||
trace_analyzer::Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_BEGIN) ||
trace_analyzer::Query::EventPhaseIs(TRACE_EVENT_PHASE_FLOW_BEGIN) ||
trace_analyzer::Query::EventPhaseIs(TRACE_EVENT_PHASE_INSTANT));
analyzer->FindEvents(query, &events);
if (events.size() < 20) {
LOG(INFO) << "Not enough events of type " << event_name << " found.";
return false;
}
// Ignore some events for startup/setup/caching.
trace_analyzer::TraceEventVector rate_events(events.begin() + 3,
events.end() - 3);
trace_analyzer::RateStats stats;
if (!GetRateStats(rate_events, &stats, NULL)) {
LOG(INFO) << "GetRateStats failed";
return false;
}
double mean_ms = stats.mean_us / 1000.0;
double std_dev_ms = stats.standard_deviation_us / 1000.0;
std::string mean_and_error = base::StringPrintf("%f,%f", mean_ms,
std_dev_ms);
perf_test::PrintResultMeanAndError(test_name,
GetSuffixForTestFlags(),
event_name,
mean_and_error,
unit,
true);
return true;
}
void RunTest(const std::string& test_name) {
if (HasFlag(kUseGpu) && !IsGpuAvailable()) {
LOG(WARNING) <<
"Test skipped: requires gpu. Pass --enable-gpu on the command "
"line if use of GPU is desired.";
return;
}
std::string json_events;
ASSERT_TRUE(tracing::BeginTracing("test_fps,mirroring"));
std::string page = "performance.html";
page += HasFlag(kTestThroughWebRTC) ? "?WebRTC=1" : "?WebRTC=0";
// Ideally we'd like to run a higher capture rate when vsync is disabled,
// but libjingle currently doesn't allow that.
// page += HasFlag(kDisableVsync) ? "&fps=300" : "&fps=30";
page += "&fps=30";
ASSERT_TRUE(RunExtensionSubtest("tab_capture/experimental", page))
<< message_;
ASSERT_TRUE(tracing::EndTracing(&json_events));
scoped_ptr<trace_analyzer::TraceAnalyzer> analyzer;
analyzer.reset(trace_analyzer::TraceAnalyzer::Create(json_events));
// Only one of these PrintResults should actually print something.
// The printed result will be the average time between frames in the
// browser window.
bool sw_frames = PrintResults(analyzer.get(),
test_name,
"TestFrameTickSW",
"frame_time");
bool gpu_frames = PrintResults(analyzer.get(),
test_name,
"TestFrameTickGPU",
"frame_time");
EXPECT_TRUE(sw_frames || gpu_frames);
EXPECT_NE(sw_frames, gpu_frames);
EXPECT_EQ(gpu_frames, HasFlag(kUseGpu));
// This prints out the average time between capture events.
// As the capture frame rate is capped at 30fps, this score
// cannot get any better than 33.33 ms.
EXPECT_TRUE(PrintResults(analyzer.get(),
test_name,
"Capture",
"capture_time"));
}
};
} // namespace
// Disabled due to failures on GPU bots (crbug.com/279443)
IN_PROC_BROWSER_TEST_P(TabCapturePerformanceTest, DISABLED_Performance) {
RunTest("TabCapturePerformance");
}
// Note: First argument is optional and intentionally left blank.
// (it's a prefix for the generated test cases)
INSTANTIATE_TEST_CASE_P(
,
TabCapturePerformanceTest,
testing::Values(
0,
kUseGpu | kForceGpuComposited,
kDisableVsync,
kDisableVsync | kUseGpu | kForceGpuComposited,
kTestThroughWebRTC,
kTestThroughWebRTC | kUseGpu | kForceGpuComposited,
kTestThroughWebRTC | kDisableVsync,
kTestThroughWebRTC | kDisableVsync | kUseGpu | kForceGpuComposited));
#ifdef USE_AURA
// TODO(hubbe):
// These are temporary tests for the purpose of determining what the
// appropriate scaling quality is. Once that has been determined,
// these tests will be removed.
const int kScalingTestBase =
kTestThroughWebRTC | kDisableVsync | kUseGpu | kForceGpuComposited;
INSTANTIATE_TEST_CASE_P(
ScalingTests,
TabCapturePerformanceTest,
testing::Values(
kScalingTestBase | kScaleQualityFast,
kScalingTestBase | kScaleQualityGood,
kScalingTestBase | kScaleQualityBest,
kScalingTestBase | kScaleQualityFast | kSmallWindow,
kScalingTestBase | kScaleQualityGood | kSmallWindow,
kScalingTestBase | kScaleQualityBest | kSmallWindow));
#endif // USE_AURA
} // namespace chrome