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.
4
5"""PeaceKeeper benchmark suite.
6
7Peacekeeper measures browser's performance by testing its JavaScript
8functionality. JavaScript is a widely used programming language used in the
9creation of modern websites to provide features such as animation, navigation,
10forms and other common requirements. By measuring a browser's ability to handle
11commonly used JavaScript functions Peacekeeper can evaluate its performance.
12Peacekeeper scores are measured in operations per second or rendered frames per
13second depending on the test. Final Score is computed by calculating geometric
14mean of individual tests scores.
15"""
16
17from telemetry import test
18from telemetry.page import page_measurement
19from telemetry.page import page_set
20from telemetry.util import statistics
21from telemetry.value import merge_values
22from telemetry.value import scalar
23
24class _PeaceKeeperMeasurement(page_measurement.PageMeasurement):
25
26  def WillNavigateToPage(self, page, tab):
27    page.script_to_evaluate_on_commit = """
28        var __results = {};
29        var _done = false;
30        var __real_log = window.console.log;
31        var test_frame = null;
32        var benchmark = null;
33        window.console.log = function(msg) {
34          if (typeof(msg) == "string" && (msg.indexOf("benchmark")) == 0) {
35            test_frame = document.getElementById("testFrame");
36            benchmark =  test_frame.contentWindow.benchmark;
37            test_frame.contentWindow.onbeforeunload = {};
38            if ((msg.indexOf("Submit ok.")) != -1) {
39              _done = true;
40              __results["test"] = benchmark.testObjectName;
41              __results["score"] = benchmark.test.result;
42              if (typeof(benchmark.test.unit) != "undefined") {
43                __results["unit"] = benchmark.test.unit;
44              } else {
45                __results["unit"] = benchmark.test.isFps ? "fps" : "ops";
46              }
47            }
48          }
49          __real_log.apply(this, [msg]);
50        }
51        """
52
53  def MeasurePage(self, _, tab, results):
54    tab.WaitForJavaScriptExpression('_done', 600)
55    result = tab.EvaluateJavaScript('__results')
56
57    results.Add('Score', 'score', int(result['score']), result['test'],
58                'unimportant')
59
60  def DidRunTest(self, browser, results):
61    # Calculate geometric mean as the total for the combined tests.
62    combined = merge_values.MergeLikeValuesFromDifferentPages(
63        results.all_page_specific_values,
64        group_by_name_suffix=True)
65    combined_score = [x for x in combined if x.name == 'Score'][0]
66    total = statistics.GeometricMean(combined_score.values)
67    results.AddSummaryValue(
68        scalar.ScalarValue(None, 'Total.Score', 'score', total))
69
70
71class PeaceKeeperBenchmark(test.Test):
72  """A base class for Peackeeper benchmarks."""
73  test = _PeaceKeeperMeasurement
74
75  def CreatePageSet(self, options):
76    """Makes a PageSet for PeaceKeeper benchmarks."""
77    # Subclasses are expected to define a class member called query_param.
78    if not hasattr(self, 'test_param'):
79      raise NotImplementedError('test_param not in PeaceKeeper benchmark.')
80
81    ps = page_set.PageSet(
82      archive_data_file='../page_sets/data/peacekeeper_%s.json' % self.tag,
83      make_javascript_deterministic=False)
84    for test_name in self.test_param:
85      ps.AddPageWithDefaultRunNavigate(
86        ('http://peacekeeper.futuremark.com/run.action?debug=true&'
87         'repeat=false&forceSuiteName=%s&forceTestName=%s') %
88        (self.tag, test_name))
89    return ps
90
91
92class PeaceKeeperRender(PeaceKeeperBenchmark):
93  """PeaceKeeper rendering benchmark suite.
94
95  These tests measure your browser's ability to render and modify specific
96  elements used in typical web pages. Rendering tests manipulate the DOM tree in
97  real-time. The tests measure display updating speed (frames per seconds).
98  """
99  tag = 'render'
100  test_param = ['renderGrid01',
101                'renderGrid02',
102                'renderGrid03',
103                'renderPhysics'
104               ]
105
106
107class PeaceKeeperData(PeaceKeeperBenchmark):
108  """PeaceKeeper Data operations benchmark suite.
109
110  These tests measure your browser's ability to add, remove and modify data
111  stored in an array. The Data suite consists of two tests:
112  1. arrayCombined: This test uses all features of the JavaScript Array object.
113  This is a technical test that is not based on profiled data.
114  The source data are different sized arrays of numbers.
115  2. arrayWeighted: This test is similar to 'arrayCombined', but the load is
116  balanced based on profiled data. The source data is a list of all the
117  countries in the world.
118  """
119
120  tag = 'array'
121  test_param = ['arrayCombined01',
122                'arrayWeighted'
123               ]
124
125
126class PeaceKeeperDom(PeaceKeeperBenchmark):
127  """PeaceKeeper DOM operations benchmark suite.
128
129  These tests emulate the methods used to create typical dynamic webpages.
130  The DOM tests are based on development experience and the capabilities of the
131  jQuery framework.
132  1. domGetElements: This test uses native DOM methods getElementById and
133    getElementsByName. The elements are not modified.
134  2. domDynamicCreationCreateElement: A common use of DOM is to dynamically
135    create content with JavaScript, this test measures creating objects
136    individually and then appending them to DOM.
137  3. domDynamicCreationInnerHTML: This test is similarl to the previous one,
138    but uses the innerHTML-method.
139  4. domJQueryAttributeFilters: This test does a DOM query with jQuery.
140    It searches elements with specific attributes.
141  5. domJQueryBasicFilters: This test uses filters to query elements from DOM.
142  6. domJQueryBasics: This test queries elements from DOM with basic methods.
143    It is similar to domGetElements, but uses jQuery rather than native methods.
144  7. domJQueryContentFilters: Query elements based on content. This does string
145    searching and these methods are assumed to be time consuming.
146  8. domJQueryHierarchy: Query elements based on hierarchy, such as getting
147    sibling, parent or child nodes from a DOM tree.
148  9. domQueryselector: QuerySelector, which allows JavaScript to search elements
149    from the DOM tree directly without the need to iterate the whole tree
150    through domGetElements.
151  """
152
153  tag = 'dom'
154  test_param = ['domGetElements',
155                'domDynamicCreationCreateElement',
156                'domDynamicCreationInnerHTML',
157                'domJQueryAttributeFilters',
158                'domJQueryBasicFilters',
159                'domJQueryBasics',
160                'domJQueryContentFilters',
161                'domJQueryHierarchy',
162                'domQueryselector'
163               ]
164
165
166class PeaceKeeperTextParsing(PeaceKeeperBenchmark):
167  """PeaceKeeper Text Parsing benchmark suite.
168
169  These tests measure your browser's performance in typical text manipulations
170  such as using a profanity filter for chats, browser detection and form
171  validation.
172  1. stringChat: This test removes swearing from artificial chat messages.
173    Test measures looping and string replace-method.
174  2. stringDetectBrowser: This test uses string indexOf-method to detect browser
175    and operating system.
176  3. stringFilter: This test filters a list of movies with a given keyword.
177    The behaviour is known as filtering select or continuous filter. It's used
178    to give real time suggestions while a user is filling input fields.
179    The test uses simple regular expressions.
180  4. stringValidateForm: This test uses complex regular expressions to validate
181    user input.
182  5. stringWeighted: This is an artificial test. Methods used and their
183    intensities are chosen based on profiled data.
184  """
185
186  tag = 'string'
187  test_param = ['stringChat',
188                'stringDetectBrowser',
189                'stringFilter',
190                'stringWeighted',
191                'stringValidateForm'
192               ]
193
194
195class PeaceKeeperHTML5Canvas(PeaceKeeperBenchmark):
196  """PeaceKeeper HTML5 Canvas benchmark suite.
197
198  These tests use HTML5 Canvas, which is a web technology for drawing and
199  manipulating graphics without external plug-ins.
200  1. experimentalRipple01: Simulates a 'water ripple' effect by using HTML 5
201    Canvas. It measures the browser's ability to draw individual pixels.
202  2. experimentalRipple02: Same test as 'experimentalRipple01', but with a
203    larger canvas and thus a heavier workload.
204  """
205
206  tag = 'experimental'
207  test_param = ['experimentalRipple01',
208                'experimentalRipple02'
209               ]
210
211
212class PeaceKeeperHTML5Capabilities(PeaceKeeperBenchmark):
213  """PeaceKeeper HTML5 Capabilities benchmark suite.
214
215  These tests checks browser HTML5 capabilities support for WebGL, Video
216  foramts, simple 2D sprite based games and web worker.
217  This benchmark only tests HTML5 capability and thus is not calculate into the
218  overall score.
219  1. HTML5 - WebGL: WebGL allows full blown 3D graphics to be rendered in a
220    browser without the need for any external plug-ins.
221    a) webglSphere
222  2. HTML5 - Video: hese tests find out which HTML5 video formats are supposed
223    by your browser. Peacekeeper only checks if your browser is able to play a
224    specific format, no other valuation is done.
225    a) videoCodecH264
226    b) videoCodecTheora
227    c) videoCodecWebM
228    d) videoPosterSupport
229  3.HTML5 - Web Worker: These tests use HTML5 Web Worker, which allows
230    JavaScript to multhread - ie. the ability to perform multiple actions
231    concurrently.
232    a) workerContrast01
233    b) workerContrast02
234  4. HTML5 - Game: This test simulates a simple 2D, sprite-based game.
235    The test itself is the real game, and what is shown is a recorded play.
236    a) gamingSpitfire
237  """
238
239  tag = 'html5'
240  test_param = ['webglSphere',
241                'gamingSpitfire',
242                'videoCodecH264',
243                'videoCodecTheora',
244                'videoCodecWebM',
245                'videoPosterSupport',
246                'workerContrast01',
247                'workerContrast02'
248                ]
249