summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authordtu@chromium.org <dtu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-31 06:49:22 +0000
committerdtu@chromium.org <dtu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-31 06:49:22 +0000
commitf3835b4e4f91f6f924259da893860d8eea20ff11 (patch)
tree3cad0b2c9699bea79c263ffac5e80491c75c1856 /tools
parent4321b18bf08725bd21026ffc4f65bccd842810b3 (diff)
downloadchromium_src-f3835b4e4f91f6f924259da893860d8eea20ff11.zip
chromium_src-f3835b4e4f91f6f924259da893860d8eea20ff11.tar.gz
chromium_src-f3835b4e4f91f6f924259da893860d8eea20ff11.tar.bz2
Devtools-based scroll test.
BUG= Review URL: https://chromiumcodereview.appspot.com/10871097 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@154398 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'tools')
-rw-r--r--tools/chrome_remote_control/chrome_remote_control/__init__.py1
-rw-r--r--tools/chrome_remote_control/chrome_remote_control/browser.py4
-rw-r--r--tools/chrome_remote_control/chrome_remote_control/browser_finder.py23
-rw-r--r--tools/chrome_remote_control/chrome_remote_control/browser_options.py37
-rw-r--r--tools/chrome_remote_control/chrome_remote_control/browser_unittest.py4
-rw-r--r--tools/chrome_remote_control/chrome_remote_control/desktop_browser_backend.py13
-rw-r--r--tools/chrome_remote_control/chrome_remote_control/inspector_backend.py3
-rw-r--r--tools/chrome_remote_control/chrome_remote_control/tab.py36
-rw-r--r--tools/chrome_remote_control/chrome_remote_control/tab_runtime.py3
-rw-r--r--tools/chrome_remote_control/chrome_remote_control/util.py34
-rwxr-xr-xtools/chrome_remote_control/examples/rendering_microbenchmark_test.py4
-rw-r--r--tools/gpu/OWNERS4
-rw-r--r--tools/gpu/data/scrollable_page.html9
-rw-r--r--tools/gpu/data/urls.txt218
-rw-r--r--tools/gpu/pylib/__init__.py9
-rw-r--r--tools/gpu/pylib/browser.py15
-rw-r--r--tools/gpu/pylib/file_server.py28
-rw-r--r--tools/gpu/pylib/scroll.js253
-rw-r--r--tools/gpu/pylib/scroll.py33
-rw-r--r--tools/gpu/pylib/scroll_results.py41
-rw-r--r--tools/gpu/pylib/url_test.py48
-rw-r--r--tools/gpu/run_scroll_test.py34
-rw-r--r--tools/gpu/scroll_test_unittest.py30
23 files changed, 821 insertions, 63 deletions
diff --git a/tools/chrome_remote_control/chrome_remote_control/__init__.py b/tools/chrome_remote_control/chrome_remote_control/__init__.py
index 37227f4..ebc83d2 100644
--- a/tools/chrome_remote_control/chrome_remote_control/__init__.py
+++ b/tools/chrome_remote_control/chrome_remote_control/__init__.py
@@ -8,3 +8,4 @@ from browser_finder import *
from browser_options import *
from browser import *
from tab import *
+from util import *
diff --git a/tools/chrome_remote_control/chrome_remote_control/browser.py b/tools/chrome_remote_control/chrome_remote_control/browser.py
index f7ba1b9..925cec9 100644
--- a/tools/chrome_remote_control/chrome_remote_control/browser.py
+++ b/tools/chrome_remote_control/chrome_remote_control/browser.py
@@ -34,8 +34,8 @@ class Browser(object):
def num_tabs(self):
return self._backend.num_tabs
- def GetNthTabURL(self, index):
- return self._backend.GetNthTabURL(index)
+ def GetNthTabUrl(self, index):
+ return self._backend.GetNthTabUrl(index)
def ConnectToNthTab(self, index):
return self._backend.ConnectToNthTab(index)
diff --git a/tools/chrome_remote_control/chrome_remote_control/browser_finder.py b/tools/chrome_remote_control/chrome_remote_control/browser_finder.py
index 1144bca..62e235b 100644
--- a/tools/chrome_remote_control/chrome_remote_control/browser_finder.py
+++ b/tools/chrome_remote_control/chrome_remote_control/browser_finder.py
@@ -10,13 +10,10 @@ import desktop_browser_backend
"""Finds browsers that can be controlled by chrome_remote_control."""
-ALL_BROWSER_TYPES = "exact,release,debug,canary,system"
-DEFAULT_BROWSER_TYPES_TO_RUN = "exact,release,canary,system"
-
class PossibleBrowser(object):
"""A browser that can be controlled.
- Call connect() to launch the browser and begin manipulating it..
+ Call Create() to launch the browser and begin manipulating it.
"""
def __init__(self, type, options, executable):
@@ -34,10 +31,8 @@ class PossibleBrowser(object):
return browser.Browser(backend)
raise Exception("Not implemented.")
-def FindBestPossibleBrowser(options,
- os = real_os,
- sys = real_sys,
- subprocess = real_subprocess):
+def FindBestPossibleBrowser(options, os=real_os, sys=real_sys,
+ subprocess=real_subprocess):
"""Finds the best PossibleBrowser object to run given the provided
BrowserOptions object. The returned possiblity object can then be used to
connect to and control the located browser."""
@@ -55,10 +50,8 @@ def GetAllAvailableBrowserTypes(options):
type_list.sort()
return type_list
-def FindAllPossibleBrowsers(options,
- os = real_os,
- sys = real_sys,
- subprocess = real_subprocess):
+def FindAllPossibleBrowsers(options, os=real_os, sys=real_sys,
+ subprocess=real_subprocess):
"""Finds all browsers that can be created given the options. Returns an array
of PossibleBrowser objects, sorted and filtered by
options.browser_types_to_use."""
@@ -74,10 +67,8 @@ def FindAllPossibleBrowsers(options,
selected_browsers.sort(compare_browsers_on_priority)
return selected_browsers
-def _UnsortedFindAllLocalBrowserPossibilities(options,
- os = real_os,
- sys = real_sys,
- subprocess = real_subprocess):
+def _UnsortedFindAllLocalBrowserPossibilities(options, os=real_os, sys=real_sys,
+ subprocess=real_subprocess):
browsers = []
# Add the explicit browser executable if given.
diff --git a/tools/chrome_remote_control/chrome_remote_control/browser_options.py b/tools/chrome_remote_control/chrome_remote_control/browser_options.py
index 9176841..5b3a466 100644
--- a/tools/chrome_remote_control/chrome_remote_control/browser_options.py
+++ b/tools/chrome_remote_control/chrome_remote_control/browser_options.py
@@ -3,29 +3,27 @@
# found in the LICENSE file.
import optparse
-import browser_finder
+ALL_BROWSER_TYPES = 'exact,release,debug,canary,system'
+DEFAULT_BROWSER_TYPES_TO_RUN = 'exact,release,canary,system'
class BrowserOptions(object):
@staticmethod
def CreateParser(usage=None):
parser = optparse.OptionParser(usage=usage)
- parser.add_option('--dont-override-profile', action="store_true",
- dest="dont_override_profile",
- help="Uses the regular user profile instead of a clean one")
- parser.add_option('--browser-executable', action="store_true",
- dest="browser_executable",
- help="The exact browser to run.")
- parser.add_option('--browser-types-to-use', action="store_true",
- dest="browser_types_to_use",
- help="Comma-separated list of browsers to run, "
- "in order of priority. Possible values: %s" %
- browser_finder.DEFAULT_BROWSER_TYPES_TO_RUN)
- parser.add_option('--chrome-root', action="store_true",
- dest="chrome_root",
- help="Where to look for chrome builds."
- "Defaults to searching parent dirs by default.")
+ parser.add_option('--dont-override-profile', action='store_true',
+ dest='dont_override_profile',
+ help='Uses the regular user profile instead of a clean one')
+ parser.add_option('--browser-executable', dest='browser_executable',
+ help='The exact browser to run.')
+ parser.add_option('--browser-types-to-use', dest='browser_types_to_use',
+ help='Comma-separated list of browsers to run, '
+ 'in order of priority. Possible values: %s' %
+ DEFAULT_BROWSER_TYPES_TO_RUN)
+ parser.add_option('--chrome-root', dest='chrome_root',
+ help='Where to look for chrome builds. '
+ 'Defaults to searching parent dirs.')
real_parse = parser.parse_args
- def ParseArgs(args = None):
+ def ParseArgs(args=None):
options = BrowserOptions()
ret = real_parse(args, options)
return ret
@@ -36,8 +34,7 @@ class BrowserOptions(object):
self.dont_override_profile = False
self.hide_stdout = True
self.browser_executable = None
- self._browser_types_to_use = (
- browser_finder.DEFAULT_BROWSER_TYPES_TO_RUN.split(","))
+ self.browser_types_to_use = DEFAULT_BROWSER_TYPES_TO_RUN
self.chrome_root = None
self.extra_browser_args = []
@@ -47,5 +44,5 @@ class BrowserOptions(object):
@browser_types_to_use.setter
def browser_types_to_use(self, value):
- self._browser_types_to_use.split(",")
+ self._browser_types_to_use = value.split(',')
diff --git a/tools/chrome_remote_control/chrome_remote_control/browser_unittest.py b/tools/chrome_remote_control/chrome_remote_control/browser_unittest.py
index 07714c3..a602a93 100644
--- a/tools/chrome_remote_control/chrome_remote_control/browser_unittest.py
+++ b/tools/chrome_remote_control/chrome_remote_control/browser_unittest.py
@@ -9,8 +9,8 @@ import browser_options
class BrowserTest(unittest.TestCase):
def testBasic(self):
options = browser_options.BrowserOptions()
- options.browser_to_use = browser_finder.ALL_BROWSER_TYPES
+ options.browser_to_use = browser_options.ALL_BROWSER_TYPES
browser_to_create = browser_finder.FindBestPossibleBrowser(options)
with browser_to_create.Create() as b:
self.assertEquals(1, b.num_tabs)
- self.assertEquals("chrome://newtab/", b.GetNthTabURL(0))
+ self.assertEquals("chrome://newtab/", b.GetNthTabUrl(0))
diff --git a/tools/chrome_remote_control/chrome_remote_control/desktop_browser_backend.py b/tools/chrome_remote_control/chrome_remote_control/desktop_browser_backend.py
index aa8563a..5bba710 100644
--- a/tools/chrome_remote_control/chrome_remote_control/desktop_browser_backend.py
+++ b/tools/chrome_remote_control/chrome_remote_control/desktop_browser_backend.py
@@ -12,6 +12,7 @@ import json
import browser_finder
import inspector_backend
import tab
+import util
DEFAULT_PORT = 9273
@@ -56,12 +57,14 @@ class DesktopBrowserBackend(object):
self.Close()
def _WaitForBrowserToComeUp(self):
- while True:
+ def IsBrowserUp():
try:
self._ListTabs()
- break
- except urllib2.URLError, ex:
- pass
+ except urllib2.URLError:
+ return False
+ else:
+ return True
+ util.WaitFor(IsBrowserUp)
def _ListTabs(self):
req = urllib2.urlopen("http://localhost:%i/json" % self._port)
@@ -72,7 +75,7 @@ class DesktopBrowserBackend(object):
def num_tabs(self):
return len(self._ListTabs())
- def GetNthTabURL(self, index):
+ def GetNthTabUrl(self, index):
return self._ListTabs()[index]["url"]
def ConnectToNthTab(self, index):
diff --git a/tools/chrome_remote_control/chrome_remote_control/inspector_backend.py b/tools/chrome_remote_control/chrome_remote_control/inspector_backend.py
index 8494bdf..e7889e5 100644
--- a/tools/chrome_remote_control/chrome_remote_control/inspector_backend.py
+++ b/tools/chrome_remote_control/chrome_remote_control/inspector_backend.py
@@ -6,6 +6,9 @@ import time
import websocket
import socket
+class InspectorException(Exception):
+ pass
+
class InspectorBackend(object):
def __init__(self, backend, descriptor):
self._backend = backend
diff --git a/tools/chrome_remote_control/chrome_remote_control/tab.py b/tools/chrome_remote_control/chrome_remote_control/tab.py
index e7863d8..d4766f6 100644
--- a/tools/chrome_remote_control/chrome_remote_control/tab.py
+++ b/tools/chrome_remote_control/chrome_remote_control/tab.py
@@ -2,11 +2,12 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import json
-import time
import websocket
import socket
+import time
import tab_runtime
+import util
class Tab(object):
def __init__(self, inspector_backend):
@@ -27,26 +28,31 @@ class Tab(object):
def __exit__(self, *args):
self.Close()
- def BeginToLoadURL(self, url):
+ def BeginToLoadUrl(self, url):
# In order to tell when the document has actually changed,
# we go to about:blank first and wait. When that has happened, we
# to go the new URL and detect the document being non-about:blank as
# indication that the new document is loading.
- self.runtime.Evaluate("document.location = 'about:blank';")
- while self.runtime.Evaluate("document.location.href") != "about:blank":
- time.sleep(0.01)
+ self.runtime.Evaluate('document.location = "about:blank";')
+ util.WaitFor(lambda:
+ self.runtime.Evaluate('document.location.href') == 'about:blank')
+
+ self.runtime.Evaluate('document.location = "%s";' % url)
+ util.WaitFor(lambda:
+ self.runtime.Evaluate('document.location.href') != 'about:blank')
- self.runtime.Evaluate("document.location = '%s';" % url)
- while self.runtime.Evaluate("document.location.href") == "about:blank":
- time.sleep(0.01)
+ def LoadUrl(self, url):
+ self.BeginToLoadUrl(url)
+ # TODO(dtu): Detect HTTP redirects.
+ time.sleep(2) # Wait for unpredictable redirects.
+ self.WaitForDocumentReadyStateToBeInteractiveOrBetter()
def WaitForDocumentReadyStateToBeComplete(self):
- while self.runtime.Evaluate("document.readyState") != 'complete':
- time.sleep(0.01)
+ util.WaitFor(
+ lambda: self.runtime.Evaluate('document.readyState') == 'complete')
def WaitForDocumentReadyStateToBeInteractiveOrBetter(self):
- while True:
- rs = self.runtime.Evaluate("document.readyState")
- if rs == 'complete' or rs == 'interactive':
- break
- time.sleep(0.01)
+ def IsReadyStateInteractiveOrBetter():
+ rs = self.runtime.Evaluate('document.readyState')
+ return rs == 'complete' or rs == 'interactive'
+ util.WaitFor(IsReadyStateInteractiveOrBetter)
diff --git a/tools/chrome_remote_control/chrome_remote_control/tab_runtime.py b/tools/chrome_remote_control/chrome_remote_control/tab_runtime.py
index c78b123..4d3fc13 100644
--- a/tools/chrome_remote_control/chrome_remote_control/tab_runtime.py
+++ b/tools/chrome_remote_control/chrome_remote_control/tab_runtime.py
@@ -1,6 +1,7 @@
# Copyright (c) 2012 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.
+import inspector_backend
class EvaluateException(Exception):
pass
@@ -29,7 +30,7 @@ class TabRuntime(object):
}
res = self._inspector_backend.SyncRequest(request)
if "error" in res:
- raise EvaluateException(res["error"]["message"])
+ raise inspector_backend.InspectorException(res["error"]["message"])
if res["result"]["wasThrown"]:
# TODO(nduca): propagate stacks from javascript up to the python
diff --git a/tools/chrome_remote_control/chrome_remote_control/util.py b/tools/chrome_remote_control/chrome_remote_control/util.py
new file mode 100644
index 0000000..ec2df2b
--- /dev/null
+++ b/tools/chrome_remote_control/chrome_remote_control/util.py
@@ -0,0 +1,34 @@
+# Copyright (c) 2012 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.
+import inspect
+import time
+
+_timeout = 60
+
+class TimeoutException(Exception):
+ pass
+
+class TimeoutChanger(object):
+ def __init__(self, new_timeout):
+ self._timeout = new_timeout
+
+ def __enter__(self):
+ _timeout, self._timeout = self._timeout, _timeout
+ return self
+
+ def __exit__(self, *args):
+ _timeout = self._timeout
+
+def WaitFor(condition):
+ assert isinstance(condition, type(lambda: None)) # is function
+ start_time = time.time()
+ while not condition():
+ if time.time() - start_time > _timeout:
+ if condition.__name__ == '<lambda>':
+ condition_string = inspect.getsource(condition).strip()
+ else:
+ condition_string = condition.__name__
+ raise TimeoutException('Timed out while waiting %ds for %s.' %
+ (_timeout, condition_string))
+ time.sleep(0.01)
diff --git a/tools/chrome_remote_control/examples/rendering_microbenchmark_test.py b/tools/chrome_remote_control/examples/rendering_microbenchmark_test.py
index 01220b5..6139977 100755
--- a/tools/chrome_remote_control/examples/rendering_microbenchmark_test.py
+++ b/tools/chrome_remote_control/examples/rendering_microbenchmark_test.py
@@ -38,7 +38,7 @@ def Main(args):
with browser_to_create.Create() as b:
with b.ConnectToNthTab(0) as tab:
# Check browser for benchmark API. Can only be done on non-chrome URLs.
- tab.BeginToLoadURL("http://www.google.com")
+ tab.BeginToLoadUrl("http://www.google.com")
tab.WaitForDocumentReadyStateToBeComplete()
if tab.runtime.Evaluate("window.chrome.gpuBenchmarking === undefined"):
print "Browser does not support gpu benchmarks API."
@@ -64,7 +64,7 @@ def Main(args):
print ",".join(cols)
for u in urls:
- tab.BeginToLoadURL(u)
+ tab.BeginToLoadUrl(u)
tab.WaitForDocumentReadyStateToBeInteractiveOrBetter()
results = tab.runtime.Evaluate(
"window.chrome.gpuBenchmarking.runRenderingBenchmarks();")
diff --git a/tools/gpu/OWNERS b/tools/gpu/OWNERS
new file mode 100644
index 0000000..77fa7f3
--- /dev/null
+++ b/tools/gpu/OWNERS
@@ -0,0 +1,4 @@
+set noparent
+nduca@chromium.org
+alokp@chromium.org
+dtu@chromium.org
diff --git a/tools/gpu/data/scrollable_page.html b/tools/gpu/data/scrollable_page.html
new file mode 100644
index 0000000..5dcdd4f
--- /dev/null
+++ b/tools/gpu/data/scrollable_page.html
@@ -0,0 +1,9 @@
+<!doctype html>
+<html>
+ <head>
+ <style type="text/css">
+ body { height: 10000px; }
+ </style>
+ </head>
+ <body></body>
+</html>
diff --git a/tools/gpu/data/urls.txt b/tools/gpu/data/urls.txt
new file mode 100644
index 0000000..051228b
--- /dev/null
+++ b/tools/gpu/data/urls.txt
@@ -0,0 +1,218 @@
+http://www.facebook.com/barackobama
+https://www.google.com/search?q=barack%20obama
+http://youtube.com
+http://yahoo.com
+http://www.baidu.com/s?wd=barack+obama
+http://en.wikipedia.org/wiki/Wikipedia
+http://qq.com
+http://www.amazon.com/Kindle-Fire-Amazon-Tablet/dp/B0051VVOB2
+http://googleblog.blogspot.com/
+http://taobao.com
+http://www.linkedin.com/in/linustorvalds
+http://yahoo.co.jp
+http://sina.com.cn
+http://msn.com
+http://yandex.ru/yandsearch?text=barack+obama
+http://translation.babylon.com/
+http://www.bing.com/search?q=barack+obama
+http://wordpress.org/news/
+http://www.ebay.com/sch/i.html?_nkw=antiques
+http://163.com
+http://www.soso.com/q?w=barack+obama
+http://www.microsoft.com/en-us/default.aspx
+http://go.mail.ru/search?mailru=1&mg=1&q=barack+obama
+http://vk.com/id118712387
+http://staff.tumblr.com/
+http://sohu.com
+http://sfbay.craigslist.org/mis/
+http://www.ask.com/web?q=barack+obama&search=&qsrc=0&o=0&l=dir
+http://www.apple.com/ipodtouch/
+http://blog.pinterest.com/
+http://pinterest.com/backdrophome/
+http://paypal.com
+http://bbc.co.uk
+http://www.avg.com/us-en/avg-premium-security
+http://googlesystem.blogspot.com/
+http://tudou.com
+http://blog.fc2.com/en/
+http://imdb.com
+http://youku.com
+http://www.flickr.com/photos/thomashawk/
+http://www.flickr.com/photos/thomashawk/sets/72157600284219965/detail/
+http://search.yahoo.com/search?ei=UTF-8&trackingType=go_search_home&p=barack+obama&fr=hsusgo1&sa.x=0&sa.y=0
+http://www.conduit.com/
+http://ifeng.com
+http://tmall.com
+http://hao123.com
+http://aol.com
+http://zedo.com
+http://search.mywebsearch.com/mywebsearch/GGmain.jhtml?searchfor=barack+obama
+http://cnn.com
+http://portal.ebay.de/deutschland-schraubt-angebote
+http://www.adobe.com/products/photoshopfamily.html?promoid=JOLIW
+http://global.rakuten.com/us/
+http://laundry.about.com/od/kidsandlaundry/f/How-Do-I-Wash-A-Backpack.htm
+http://thepiratebay.se/search/barack%20obama/0/99/0
+http://360buy.com
+http://huffingtonpost.com
+http://alibaba.com
+http://chinaz.com
+http://www.sogou.com/web?query=barack+obama
+http://www.amazon.de/gp/product/B0051QVF7A/ref=amb_link_170625867_1/275-4711375-4099801?ie=UTF8&nav_sdd=aps&pf_rd_m=A3JWKAKR8XB7XF&pf_rd_s=center-1&pf_rd_r=1C0XDBPB12WHDM63V11R&pf_rd_t=101&pf_rd_p=320475427&pf_rd_i=301128
+http://google.pl
+http://mediafire.com
+http://espn.go.com
+http://uol.com.br
+http://www.godaddy.com/products/secure-hosting.aspx?ci=72738
+http://imgur.com/gallery/b90ZE
+http://home.alipay.com/bank/paymentKJ.htm
+http://amazon.co.jp
+http://stackoverflow.com/questions/11227809/why-is-processing-a-sorted-array-faster-than-an-unsorted-array
+http://www.google.com/doubleclick/
+http://search.4shared.com/q/CCAD/1/barack%20obama
+http://dailymotion.com
+http://globo.com
+http://instagram.com/developer/
+http://livedoor.com
+http://wordpress.org/showcase/
+http://bp.blogspot.com
+http://wigetmedia.com/advertisers
+http://www.search-results.com/web?&q=barack%20obama
+http://cnet.com
+http://nytimes.com
+http://torrentz.eu/search?f=barack+obama
+http://livejournal.com
+http://douban.com
+http://www.weather.com/weather/right-now/Mountain+View+CA+94043
+http://dailymail.co.uk
+http://www.tianya.cn/bbs/index.shtml
+http://ehow.com
+http://theproject.badoo.com/final.phtml
+http://www.bankofamerica.com/deposits/checksave/index.cfm?template=check_eBanking
+http://vimeo.com
+http://360.cn
+http://indiatimes.com
+http://deviantart.com
+http://reddit.com
+http://aweber.com
+http://warriorforum.com
+http://spiegel.de
+http://pconline.com.cn
+http://mozilla.org
+http://booking.com
+http://goo.ne.jp
+https://www.chase.com/online/Home-Lending/mortgages.htm
+http://addthis.com
+http://56.com
+http://news.blogfa.com/
+http://www.stumbleupon.com/jobs
+https://www.dropbox.com/about
+http://www.clicksor.com/publishers/adformat
+http://answers.com
+http://en.softonic.com/
+http://walmart.com
+http://pengyou.com
+http://outbrain.com
+http://comcast.net
+http://foxnews.com
+http://photobucket.com/findstuff/photography%20styles/
+http://bleach.wikia.com/?redirect=no
+http://sourceforge.net/projects/xoops/?source=frontpage&position=1
+http://onet.pl
+http://guardian.co.uk
+https://www.wellsfargo.com/jump/enterprise/doublediscount?msc=5589&mplx=10918-70119-3408-64
+http://wikimediafoundation.org/wiki/Home
+http://xunlei.com
+http://as.58.com/shuma/
+http://skype.com
+http://etsy.com
+http://bild.de
+http://search.naver.com/search.naver?where=nexearch&query=barack+obama&sm=top_hty&fbm=0&ie=utf8
+http://statcounter.com/features/?PHPSESSID=bbjcvjr681bcul4vqvgq2qgmo7
+http://iqiyi.com
+http://fbcdn.net
+http://www.myspace.com/browse/people
+http://allegro.pl/antyki-i-sztuka
+http://yesky.com
+http://justbeenpaid.com
+http://adultfriendfinder.com
+http://fiverr.com
+http://www.leboncoin.fr/annonces/offres/centre/
+http://dictionary.reference.com/
+http://realtime.rediff.com/instasearch#!barack%20obama
+http://zol.com.cn
+http://optmd.com
+http://www.filestube.com/search.html?q=barack+obama&select=All
+http://xinhuanet.com
+http://www.salesforce.com/sales-cloud/overview/
+http://www.squidoo.com/make-cards-and-gift-bags-with-antique-photos
+http://www.domaintools.com/research/
+http://download.cnet.com/windows/?tag=hdr;brandnav
+https://rapidshare.com/#!shop
+http://people.com.cn
+http://ucoz.ru
+http://free.fr
+http://nicovideo.jp
+http://www.yelp.com/search?find_desc=food&find_loc=San+Jose%2C+CA&ns=1
+http://slideshare.net
+http://archive.org/web/web.php
+http://www.cntv.cn/index.shtml
+http://english.cntv.cn/01/index.shtml
+http://abonnez-vous.orange.fr/residentiel/accueil/accueil.aspx
+http://v.it168.com/
+http://nbcolympics.com
+http://hootsuite.com
+http://www.scribd.com/doc/52210329/The-Masters-Augusta-National-s-Amen-Corner-up-close
+http://themeforest.net
+http://4399.com
+http://www.soku.com/v?keyword=barack%20obama
+http://google.se
+http://funmoods.com
+http://csdn.net
+http://telegraph.co.uk
+http://taringa.net
+http://www.tripadvisor.com/Tourism-g32701-Mendocino_California-Vacations.html
+http://pof.com
+http://wp.pl
+http://soundcloud.com/flosstradamus/tracks
+http://w3schools.com/html/default.asp
+http://ameblo.jp/staff/
+http://wsj.com
+http://web.de
+http://sweetim.com
+http://rambler.ru
+http://gmx.net
+http://www.indeed.com/jobs?q=software&l=Mountain+View%2C+CA
+http://ilivid.com
+http://www.xing.com/search/people?search%5Bq%5D=lufthansa
+http://reuters.com
+http://hostgator.com
+http://www.ikea.com/us/en/catalog/categories/departments/living_room/
+http://www.kaixin001.com/award2012/wenming/index.php
+http://ku6.com
+http://libero.it
+http://samsung.com
+http://hudong.com
+http://espncricinfo.com
+http://china.com
+http://www.ups.com/content/us/en/bussol/browse/smallbiz/new-to-ups.html?WT.svl=SolExp
+http://letv.com
+http://ero-advertising.com
+http://mashable.com
+http://iminent.com
+http://rutracker.org
+http://www.shopping.hp.com/en_US/home-office/-/products/Laptops/Laptops
+http://www.clickbank.com/buy_products.htm?dores=true&mainCategoryId=1340&sortField=POPULARITY&b1=1340
+http://b.hatena.ne.jp/
+http://www.youdao.com/search?q=barack+obama&ue=utf8&keyfrom=web.index
+http://forbes.com
+http://nbcnews.com
+http://bitauto.com
+http://php.net
+http://www.target.com/c/women/-/N-5xtd3#?lnk=nav_t_spc_1_0
+http://dianxin.cn
+http://www.aizhan.com/siteall/www.youboy.com/
+http://veiculos-home.mercadolivre.com.br/
+http://kakaku.com
+http://flipkart.com
+http://paipai.com
diff --git a/tools/gpu/pylib/__init__.py b/tools/gpu/pylib/__init__.py
new file mode 100644
index 0000000..e20abd1
--- /dev/null
+++ b/tools/gpu/pylib/__init__.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2012 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.
+"""A library for Chrome-based tests."""
+import os
+import sys
+
+sys.path.append(os.path.join(os.path.dirname(__file__),
+ '..', '..', 'chrome_remote_control'))
diff --git a/tools/gpu/pylib/browser.py b/tools/gpu/pylib/browser.py
new file mode 100644
index 0000000..0882bac7
--- /dev/null
+++ b/tools/gpu/pylib/browser.py
@@ -0,0 +1,15 @@
+# Copyright (c) 2012 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.
+import chrome_remote_control
+
+def StartBrowser():
+ parser = chrome_remote_control.BrowserOptions.CreateParser()
+ options, _ = parser.parse_args()
+
+ possible_browser = chrome_remote_control.FindBestPossibleBrowser(options)
+ if possible_browser is None:
+ raise Exception('No browsers found of the following types: %s.' %
+ options.browser_types_to_use)
+
+ return possible_browser.Create()
diff --git a/tools/gpu/pylib/file_server.py b/tools/gpu/pylib/file_server.py
new file mode 100644
index 0000000..4056619
--- /dev/null
+++ b/tools/gpu/pylib/file_server.py
@@ -0,0 +1,28 @@
+# Copyright (c) 2012 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.
+import os
+import subprocess
+
+class FileServer(object):
+ def __init__(self, path, port=8000):
+ assert os.path.exists(path)
+ if os.path.isdir(path):
+ self._path = path
+ else:
+ self._path = os.path.dirname(path)
+ self._port = port
+
+ def __enter__(self):
+ self._server = subprocess.Popen(
+ ['python', '-m', 'SimpleHTTPServer', str(self._port)],
+ cwd=self._path)
+ return 'http://localhost:%d' % self._port
+
+ def __exit__(self, *args):
+ self._server.kill()
+ self._server = None
+
+ def __del__(self):
+ if self._server:
+ self._server.kill()
diff --git a/tools/gpu/pylib/scroll.js b/tools/gpu/pylib/scroll.js
new file mode 100644
index 0000000..48688d0
--- /dev/null
+++ b/tools/gpu/pylib/scroll.js
@@ -0,0 +1,253 @@
+// Copyright (c) 2012 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.
+
+// Inject this script on any page to measure framerate as the page is scrolled
+// from top to bottom.
+//
+// Usage:
+// 1. Define a callback that takes the results array as a parameter.
+// 2. To start the test, call new __ScrollTest(callback).
+// 3a. When the test is complete, the callback will be called.
+// 3b. If no callback is specified, the results are sent to the console.
+
+(function() {
+ var getTimeMs = (function() {
+ if (window.performance)
+ return (performance.now ||
+ performance.mozNow ||
+ performance.msNow ||
+ performance.oNow ||
+ performance.webkitNow).bind(window.performance);
+ else
+ return function() { return new Date().getTime(); };
+ })();
+
+ var requestAnimationFrame = (function() {
+ return window.requestAnimationFrame ||
+ window.webkitRequestAnimationFrame ||
+ window.mozRequestAnimationFrame ||
+ window.oRequestAnimationFrame ||
+ window.msRequestAnimationFrame ||
+ function(callback) {
+ window.setTimeout(callback, 1000 / 60);
+ };
+ })().bind(window);
+
+ /**
+ * Scrolls a given element down a certain amount to emulate user scrolling.
+ * Uses smooth scrolling capabilities provided by the platform, if available.
+ * @constructor
+ */
+ function SmoothScrollDownGesture(opt_element, opt_isGmailTest) {
+ this.element_ = opt_element || document.body;
+ this.isGmailTest_ = opt_isGmailTest;
+ };
+
+ SmoothScrollDownGesture.prototype.start = function(callback) {
+ this.callback_ = callback;
+ if (chrome &&
+ chrome.gpuBenchmarking &&
+ chrome.gpuBenchmarking.beginSmoothScrollDown) {
+ chrome.gpuBenchmarking.beginSmoothScrollDown(true, function() {
+ callback();
+ });
+ return;
+ }
+
+ if (this.isGmailTest_) {
+ this.element_.scrollByLines(1);
+ requestAnimationFrame(callback);
+ return;
+ }
+
+ var SCROLL_DELTA = 100;
+ this.element_.scrollTop += SCROLL_DELTA;
+ requestAnimationFrame(callback);
+ }
+
+ /**
+ * Tracks rendering performance using the gpuBenchmarking.renderingStats API.
+ * @constructor
+ */
+ function GpuBenchmarkingRenderingStats() {
+ }
+
+ GpuBenchmarkingRenderingStats.prototype.start = function() {
+ this.initialStats_ = this.getRenderingStats_();
+ }
+ GpuBenchmarkingRenderingStats.prototype.stop = function() {
+ this.finalStats_ = this.getRenderingStats_();
+ }
+
+ GpuBenchmarkingRenderingStats.prototype.getResult = function() {
+ if (!this.initialStats_)
+ throw new Error("Start not called.");
+
+ if (!this.finalStats_)
+ throw new Error("Stop was not called.");
+
+ var stats = this.finalStats_;
+ for (var key in stats)
+ stats[key] -= this.initialStats_[key];
+ return stats;
+ };
+
+ GpuBenchmarkingRenderingStats.prototype.getRenderingStats_ = function() {
+ var stats = chrome.gpuBenchmarking.renderingStats();
+ stats.totalTimeInSeconds = getTimeMs() / 1000;
+ return stats;
+ };
+
+ /**
+ * Tracks rendering performance using requestAnimationFrame.
+ * @constructor
+ */
+ function RafRenderingStats() {
+ this.recording_ = false;
+ this.frameTimes_ = [];
+ }
+
+ RafRenderingStats.prototype.start = function() {
+ if (this.recording_)
+ throw new Error("Already started.");
+ this.recording_ = true;
+ requestAnimationFrame(this.recordFrameTime_.bind(this));
+ }
+
+ RafRenderingStats.prototype.stop = function() {
+ this.recording_ = false;
+ }
+
+ RafRenderingStats.prototype.getResult = function() {
+ var result = {};
+ result.numAnimationFrames = this.frameTimes_.length - 1;
+ result.droppedFrameCount = this.getDroppedFrameCount_(this.frameTimes_);
+ result.totalTimeInSeconds = (this.frameTimes_[this.frameTimes_.length - 1] -
+ this.frameTimes_[0]) / 1000;
+ return result;
+ };
+
+ RafRenderingStats.prototype.recordFrameTime_ = function(timestamp) {
+ if (!this.recording_)
+ return;
+
+ this.frameTimes_.push(timestamp);
+ requestAnimationFrame(this.recordFrameTime_.bind(this));
+ };
+
+ RafRenderingStats.prototype.getDroppedFrameCount_ = function(frameTimes) {
+ var droppedFrameCount = 0;
+ for (var i = 1; i < frameTimes.length; i++) {
+ var frameTime = frameTimes[i] - frameTimes[i-1];
+ if (frameTime > 1000 / 55)
+ droppedFrameCount++;
+ }
+ return droppedFrameCount;
+ };
+
+ // This class scrolls a page from the top to the bottom a given number of
+ // times.
+ //
+ // Each full transit of the page is called a "pass."
+ //
+ // The page is scrolled down by a set of scroll gestures. These gestures
+ // correspond to a reading gesture on that platform.
+ //
+ // i.e. for TOTAL_ITERATIONS_ = 2, we do
+ // start_ -> startPass_ -> ...scrolling... -> onGestureComplete_ ->
+ // -> startPass_ -> .. scrolling... -> onGestureComplete_ -> callback_
+ //
+ // TODO(nduca): This test starts in its constructor. That is strange. We
+ // should change it to start explicitly.
+ function ScrollTest(opt_callback, opt_isGmailTest) {
+ var self = this;
+
+ this.TOTAL_ITERATIONS_ = 1;
+
+ this.callback_ = opt_callback;
+ this.isGmailTest_ = opt_isGmailTest;
+ this.iteration_ = 0;
+
+ this.results_ = []
+
+ if (this.isGmailTest_) {
+ gmonkey.load('2.0', function(api) {
+ self.start_(api.getScrollableElement());
+ });
+ } else {
+ if (document.readyState == 'interactive' ||
+ document.readyState == 'complete')
+ this.start_();
+ else
+ window.addEventListener('load', function() { self.start_(); });
+ }
+ }
+
+ ScrollTest.prototype.start_ = function(opt_element) {
+ // Assign this.element_ here instead of constructor, because the constructor
+ // ensures this method will be called after the document is loaded.
+ this.element_ = opt_element || document.body;
+ // Some pages load more content when you scroll to the bottom. Record
+ // the original element height here and only scroll to that point.
+ this.scrollHeight_ = this.element_.scrollHeight
+ requestAnimationFrame(this.startPass_.bind(this));
+ };
+
+ ScrollTest.prototype.startPass_ = function() {
+ this.element_.scrollTop = 0;
+ if (window.chrome && chrome.gpuBenchmarking)
+ this.renderingStats_ = new GpuBenchmarkingRenderingStats();
+ else
+ this.renderingStats_ = new RafRenderingStats();
+ this.renderingStats_.start();
+
+ this.gesture_ = new SmoothScrollDownGesture(this.element_,
+ this.isGmailTest_);
+ this.gesture_.start(this.onGestureComplete_.bind(this));
+ };
+
+ ScrollTest.prototype.onGestureComplete_ = function(timestamp) {
+ // clientHeight is "special" for the body element.
+ var clientHeight;
+ if (this.element_ == document.body)
+ clientHeight = window.innerHeight;
+ else
+ clientHeight = this.element_.clientHeight;
+
+ // If the scrollHeight went down, only scroll to the new scrollHeight.
+ this.scrollHeight_ = Math.min(this.scrollHeight_,
+ this.element_.scrollHeight);
+
+ var isPassComplete =
+ this.element_.scrollTop + clientHeight >= this.scrollHeight_;
+
+ if (!isPassComplete) {
+ this.gesture_.start(this.onGestureComplete_.bind(this));
+ return;
+ }
+
+ this.endPass_();
+
+ var isTestComplete = this.iteration_ >= this.TOTAL_ITERATIONS_;
+ if (!isTestComplete) {
+ this.startPass_();
+ return;
+ }
+
+ // Send results.
+ if (this.callback_)
+ this.callback_(this.results_);
+ else
+ console.log(this.results_);
+ };
+
+ ScrollTest.prototype.endPass_ = function() {
+ this.renderingStats_.stop();
+ this.results_.push(this.renderingStats_.getResult());
+ this.iteration_++;
+ };
+
+
+ window.__ScrollTest = ScrollTest;
+})();
diff --git a/tools/gpu/pylib/scroll.py b/tools/gpu/pylib/scroll.py
new file mode 100644
index 0000000..fea5e3e
--- /dev/null
+++ b/tools/gpu/pylib/scroll.py
@@ -0,0 +1,33 @@
+# Copyright (c) 2012 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.
+import os
+
+import chrome_remote_control
+import scroll_results
+
+def Scroll(tab):
+ scroll_js_path = os.path.join(os.path.dirname(__file__), 'scroll.js')
+ scroll_js = open(scroll_js_path, 'r').read()
+
+ # Run scroll test.
+ tab.runtime.Evaluate(scroll_js)
+ tab.runtime.Evaluate("""
+ window.__scrollTestResult = null;
+ new __ScrollTest(function(result) {
+ window.__scrollTestResult = result;
+ });
+ null; // Avoid returning the entire __ScrollTest object.
+ """)
+
+ # Poll for scroll result.
+ chrome_remote_control.WaitFor(
+ lambda: tab.runtime.Evaluate('window.__scrollTestResult'))
+
+ # Get scroll results.
+ url = tab.runtime.Evaluate('document.location.href')
+ first_paint_secs = tab.runtime.Evaluate(
+ 'chrome.loadTimes().firstPaintTime - chrome.loadTimes().startLoadTime')
+ results_list = tab.runtime.Evaluate('window.__scrollTestResult')
+
+ return scroll_results.ScrollResults(url, first_paint_secs, results_list)
diff --git a/tools/gpu/pylib/scroll_results.py b/tools/gpu/pylib/scroll_results.py
new file mode 100644
index 0000000..ea0ac19
--- /dev/null
+++ b/tools/gpu/pylib/scroll_results.py
@@ -0,0 +1,41 @@
+# Copyright (c) 2012 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.
+class ScrollResults(object):
+ """Container for ScrollTest results."""
+
+ def __init__(self, url, first_paint_seconds, results_list):
+ self._url = url
+ self._first_paint_time = first_paint_seconds
+ self._results_list = results_list
+
+ def DidScroll(self):
+ for index in xrange(len(self._results_list)):
+ if self.GetFrameCount(index) > 0:
+ return True
+ return False
+
+ def GetFirstPaintTime(self):
+ return self._first_paint_time
+
+ def GetFps(self, index):
+ return (self.GetFrameCount(index) /
+ self.GetResult(index)['totalTimeInSeconds'])
+
+ def GetFrameCount(self, index):
+ results = self.GetResult(index)
+ return results.get('numFramesSentToScreen', results['numAnimationFrames'])
+
+ def GetMeanFrameTime(self, index):
+ return (self.GetResult(index)['totalTimeInSeconds'] /
+ self.GetFrameCount(index))
+
+ def GetPercentBelow60Fps(self, index):
+ return (float(self.GetResult(index)['droppedFrameCount']) /
+ self.GetFrameCount(index))
+
+ def GetResult(self, index):
+ return self._results_list[index]
+
+ def GetUrl(self):
+ return self._url
diff --git a/tools/gpu/pylib/url_test.py b/tools/gpu/pylib/url_test.py
new file mode 100644
index 0000000..c3a5ed2
--- /dev/null
+++ b/tools/gpu/pylib/url_test.py
@@ -0,0 +1,48 @@
+# Copyright (c) 2012 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.
+import logging
+import re
+import traceback
+
+import browser
+import chrome_remote_control
+
+def UrlTest(test_method, url_list):
+ skipped_urls = []
+ with browser.StartBrowser() as b:
+ with b.ConnectToNthTab(0) as tab:
+ for url in url_list:
+ url = url.strip()
+ if not url:
+ continue
+ if not re.match('(.+)://', url):
+ url = 'http://%s' % url
+
+ try:
+ logging.info('Loading %s...', url)
+ tab.LoadUrl(url)
+ logging.info('Loaded page: %s', url)
+ except chrome_remote_control.TimeoutException:
+ logging.warning('Timed out while loading: %s', url)
+ continue
+
+ try:
+ logging.info('Running test on %s...', url)
+ result = test_method(tab)
+ logging.info('Ran test:', url)
+ except:
+ logging.error('Failed on URL: %s', url)
+ traceback.print_exc()
+ skipped_urls.append(url)
+ continue
+
+ if not result:
+ logging.warning('No result for URL: %s', url)
+ skipped_urls.append(url)
+ continue
+
+ yield result
+
+ if len(skipped_urls) > 0:
+ logging.warning('Skipped URLs: %s', skipped_urls)
diff --git a/tools/gpu/run_scroll_test.py b/tools/gpu/run_scroll_test.py
new file mode 100644
index 0000000..a6405a1
--- /dev/null
+++ b/tools/gpu/run_scroll_test.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+# Copyright (c) 2012 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.
+
+# The test takes a list of URLs through stdin and prints results in CSV format.
+# Example: python run_scroll_test.py < data/urls.txt > test_results.csv
+import csv
+import logging
+import sys
+
+import pylib.scroll
+import pylib.url_test
+
+def Main():
+ results_writer = csv.writer(sys.stdout)
+ results_writer.writerow(['URL', 'FPS', 'Mean Frame Time (s)',
+ '% Dropped Frames', 'First Paint Time (s)'])
+ sys.stdout.flush()
+
+ for result in pylib.url_test.UrlTest(pylib.scroll.Scroll, sys.stdin):
+ if not result.DidScroll():
+ # Most likely the page was shorter than the window height.
+ logging.warning('Page did not scroll: %s', result.GetUrl())
+ continue
+
+ results_writer.writerow([result.GetUrl(), result.GetFps(0),
+ result.GetMeanFrameTime(0),
+ result.GetPercentBelow60Fps(0),
+ result.GetFirstPaintTime()])
+ sys.stdout.flush()
+
+if __name__ == '__main__':
+ Main()
diff --git a/tools/gpu/scroll_test_unittest.py b/tools/gpu/scroll_test_unittest.py
new file mode 100644
index 0000000..e2c295f
--- /dev/null
+++ b/tools/gpu/scroll_test_unittest.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+# Copyright (c) 2012 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.
+import os
+import unittest
+
+import pylib.file_server
+import pylib.scroll
+import pylib.url_test
+
+class ScrollTestUnitTest(unittest.TestCase):
+
+ def runTest(self):
+ test_file_path = os.path.join(os.path.dirname(__file__),
+ 'data', 'scrollable_page.html')
+
+ result_count = 0
+ with pylib.file_server.FileServer(test_file_path) as root_url:
+ url = '%s/%s' % (root_url, os.path.basename(test_file_path))
+ for result in pylib.url_test.UrlTest(pylib.scroll.Scroll, [url]):
+ result_count += 1
+
+ self.assertEqual(result_count, 1, 'Wrong number of test results.')
+ self.assertEqual(result.GetUrl(), url, 'Did not navigate to right URL.')
+ self.assertTrue(result.GetFirstPaintTime() < 1, 'The page load was slow.')
+ self.assertTrue(result.GetFps(0) > 55, 'Scroll seemed kind of slow.')
+
+if __name__ == '__main__':
+ unittest.main()