diff --git a/tools/OWNERS b/tools/OWNERS index 945ca919..b4e4d992 100644 --- a/tools/OWNERS +++ b/tools/OWNERS
@@ -5,6 +5,7 @@ # If you're changing existing tools, have your change reviewed by the # OWNERS of the existing tool. +brucedawson@chromium.org dpranke@chromium.org scottmg@chromium.org thakis@chromium.org @@ -19,10 +20,6 @@ per-file bisect*.py=anantha@chromium.org per-file bisect*.py=prasadv@chromium.org per-file bisect*.py=robertocn@chromium.org -per-file run-bisect*.py=prasadv@chromium.org -per-file run-bisect*.py=robertocn@chromium.org -per-file prepare-bisect*.py=prasadv@chromium.org -per-file prepare-bisect*.py=robertocn@chromium.org per-file boilerplate.py=rsesek@chromium.org @@ -39,25 +36,22 @@ per-file ipc_messages_log.py=yfriedman@chromium.org -per-file licenses.py=phajdan.jr@chromium.org -per-file licenses.py=sgurun@chromium.org -per-file licenses.py=torne@chromium.org +per-file licenses.py=ichikawa@chromium.org per-file remove_stale_pyc_files.py=dtu@chromium.org per-file roll_angle.py=kbr@chromium.org -per-file roll_angle.py=kjellander@chromium.org per-file roll_angle.py=geofflang@chromium.org +per-file roll_swiftshader.py=capn@chromium.org +per-file roll_swiftshader.py=sugoi@chromium.org per-file roll_webgl_conformance.py=bajones@chromium.org per-file roll_webgl_conformance.py=kbr@chromium.org -per-file roll_webgl_conformance.py=kjellander@chromium.org per-file roll_webgl_conformance.py=geofflang@chromium.org per-file roll_webgl_conformance.py=zmo@chromium.org -per-file roll_webrtc.py=kjellander@chromium.org +per-file roll_webrtc.py=phoglund@chromium.org per-file safely-roll-deps.py=borenet@chromium.org per-file sort-headers.py=satorux@chromium.org per-file sort-sources.py=satorux@chromium.org per-file yes_no.py=satorux@chromium.org -
diff --git a/tools/accessibility/DEPS b/tools/accessibility/DEPS new file mode 100644 index 0000000..02d3a21c --- /dev/null +++ b/tools/accessibility/DEPS
@@ -0,0 +1,3 @@ +include_rules = [ + "+content/browser/accessibility", +]
diff --git a/tools/accessibility/inspect/BUILD.gn b/tools/accessibility/inspect/BUILD.gn new file mode 100644 index 0000000..1876000 --- /dev/null +++ b/tools/accessibility/inspect/BUILD.gn
@@ -0,0 +1,43 @@ +# Use of this source code is governed by a BSD-style license that can be +# Copyright 2017 The Chromium Authors. All rights reserved. +# found in the LICENSE file. + +if (is_win) { + executable("ax_dump_events") { + testonly = true + + sources = [ + "ax_dump_events.cc", + "ax_event_server.cc", + ] + + deps = [ + "//base", + "//base/test:test_support", + "//content/test:test_support", + ] + + if (is_win) { + libs = [ "oleacc.lib" ] + } + } + + executable("ax_dump_tree") { + testonly = true + + sources = [ + "ax_dump_tree.cc", + "ax_tree_server.cc", + ] + + deps = [ + "//base", + "//base/test:test_support", + "//content/test:test_support", + ] + + if (is_win) { + libs = [ "oleacc.lib" ] + } + } +}
diff --git a/tools/accessibility/inspect/README.md b/tools/accessibility/inspect/README.md new file mode 100644 index 0000000..af2ee4e --- /dev/null +++ b/tools/accessibility/inspect/README.md
@@ -0,0 +1,9 @@ +# ax_dump_events + +This tool helps monitor accessibility events. It currently works on Windows, +and Mac is TBD. + +Events are currently dumped to the console. To use it, run +`ax_dump_events --pid=[processid]` + +Press Ctrl+C to quit. \ No newline at end of file
diff --git a/tools/accessibility/inspect/ax_dump_events.cc b/tools/accessibility/inspect/ax_dump_events.cc new file mode 100644 index 0000000..fbd77a2 --- /dev/null +++ b/tools/accessibility/inspect/ax_dump_events.cc
@@ -0,0 +1,41 @@ +// Copyright 2017 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 <string> + +#include "base/at_exit.h" +#include "base/command_line.h" +#include "base/strings/string_number_conversions.h" +#include "tools/accessibility/inspect/ax_event_server.h" + +char kPidSwitch[] = "pid"; + +// Convert from string to int, whether in 0x hex format or decimal format. +bool StringToInt(std::string str, int* result) { + if (str.empty()) + return false; + bool is_hex = + str.size() > 2 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X'); + return is_hex ? base::HexStringToInt(str, result) + : base::StringToInt(str, result); +} + +int main(int argc, char** argv) { + base::AtExitManager at_exit_manager; + // TODO(aleventhal) Want callback after Ctrl+C or some global keystroke: + // base::AtExitManager::RegisterCallback(content::OnExit, nullptr); + + base::CommandLine::Init(argc, argv); + std::string pid_str = + base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(kPidSwitch); + int pid; + if (!pid_str.empty()) { + if (StringToInt(pid_str, &pid)) { + std::unique_ptr<content::AXEventServer> server( + new content::AXEventServer(pid)); + } + } + + return 0; +}
diff --git a/tools/accessibility/inspect/ax_dump_tree.cc b/tools/accessibility/inspect/ax_dump_tree.cc new file mode 100644 index 0000000..7eb549a --- /dev/null +++ b/tools/accessibility/inspect/ax_dump_tree.cc
@@ -0,0 +1,63 @@ +// Copyright 2017 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 <string> + +#include "base/at_exit.h" +#include "base/command_line.h" +#include "base/strings/string_number_conversions.h" +#include "tools/accessibility/inspect/ax_tree_server.h" + +char kPidSwitch[] = "pid"; +char kWindowSwitch[] = "window"; +char kFiltersSwitch[] = "filters"; +char kJsonSwitch[] = "json"; + +// Convert from string to int, whether in 0x hex format or decimal format. +bool StringToInt(std::string str, int* result) { + if (str.empty()) + return false; + bool is_hex = + str.size() > 2 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X'); + return is_hex ? base::HexStringToInt(str, result) + : base::StringToInt(str, result); +} + +int main(int argc, char** argv) { + base::AtExitManager at_exit_manager; + + base::CommandLine::Init(argc, argv); + + base::string16 filters_path = base::ASCIIToUTF16( + base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( + kFiltersSwitch)); + + bool use_json = + base::CommandLine::ForCurrentProcess()->HasSwitch(kJsonSwitch); + + std::string window_str = + base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( + kWindowSwitch); + if (!window_str.empty()) { + int window; + if (StringToInt(window_str, &window)) { + gfx::AcceleratedWidget widget( + reinterpret_cast<gfx::AcceleratedWidget>(window)); + std::unique_ptr<content::AXTreeServer> server( + new content::AXTreeServer(widget, filters_path, use_json)); + return 0; + } + } + std::string pid_str = + base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(kPidSwitch); + if (!pid_str.empty()) { + int pid; + if (StringToInt(pid_str, &pid)) { + base::ProcessId process_id = static_cast<base::ProcessId>(pid); + std::unique_ptr<content::AXTreeServer> server( + new content::AXTreeServer(process_id, filters_path, use_json)); + } + } + return 0; +}
diff --git a/tools/accessibility/inspect/ax_event_server.cc b/tools/accessibility/inspect/ax_event_server.cc new file mode 100644 index 0000000..b02af0f11 --- /dev/null +++ b/tools/accessibility/inspect/ax_event_server.cc
@@ -0,0 +1,39 @@ +// Copyright 2017 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 "tools/accessibility/inspect/ax_event_server.h" + +#include <string> + +#include "base/at_exit.h" +#include "base/bind.h" +#include "base/command_line.h" +#include "base/run_loop.h" +#include "base/strings/string_number_conversions.h" +#include "base/test/scoped_task_environment.h" + +namespace content { + +static void OnEvent(std::string event) { + printf("Event %s\n", event.c_str()); +} + +AXEventServer::AXEventServer(int pid) + : recorder_(AccessibilityEventRecorder::Create(nullptr, pid)) { + printf("Events for process id: %d\n", pid); + + base::test::ScopedTaskEnvironment scoped_task_environment( + base::test::ScopedTaskEnvironment::MainThreadType::UI); + + recorder_->ListenToEvents(base::BindRepeating(OnEvent)); + + base::RunLoop run_loop; + run_loop.Run(); +} + +AXEventServer::~AXEventServer() { + delete recorder_.release(); +} + +} // namespace content
diff --git a/tools/accessibility/inspect/ax_event_server.h b/tools/accessibility/inspect/ax_event_server.h new file mode 100644 index 0000000..e15f05b --- /dev/null +++ b/tools/accessibility/inspect/ax_event_server.h
@@ -0,0 +1,26 @@ +// Copyright 2017 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. + +#ifndef AX_EVENT_SERVER_H_ +#define AX_EVENT_SERVER_H_ + +#include <string> + +#include "content/browser/accessibility/accessibility_event_recorder.h" + +namespace content { + +class AXEventServer { + public: + explicit AXEventServer(int pid); + + ~AXEventServer(); + + private: + std::unique_ptr<AccessibilityEventRecorder> recorder_; +}; + +} // namespace content + +#endif // AX_EVENT_SERVER_H_
diff --git a/tools/accessibility/inspect/ax_tree_server.cc b/tools/accessibility/inspect/ax_tree_server.cc new file mode 100644 index 0000000..89d0501 --- /dev/null +++ b/tools/accessibility/inspect/ax_tree_server.cc
@@ -0,0 +1,131 @@ +// Copyright 2017 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 "tools/accessibility/inspect/ax_tree_server.h" + +#include <iostream> +#include <string> + +#include "base/at_exit.h" +#include "base/bind.h" +#include "base/files/file_util.h" +#include "base/json/json_writer.h" +#include "base/path_service.h" +#include "base/run_loop.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" + +namespace content { + +constexpr char kAllowOptEmptyStr[] = "@ALLOW-EMPTY:"; +constexpr char kAllowOptStr[] = "@ALLOW:"; +constexpr char kDenyOptStr[] = "@DENY:"; + +AXTreeServer::AXTreeServer(base::ProcessId pid, + base::string16& filters_path, + bool use_json) { + std::unique_ptr<AccessibilityTreeFormatter> formatter( + AccessibilityTreeFormatter::Create()); + + // Get accessibility tree as nested dictionary. + base::string16 accessibility_contents_utf16; + std::unique_ptr<base::DictionaryValue> dict = + formatter->BuildAccessibilityTreeForProcess(pid); + + if (!dict) { + std::cout << "Failed to get accessibility tree"; + return; + } + + Format(*formatter, *dict, filters_path, use_json); +} + +AXTreeServer::AXTreeServer(gfx::AcceleratedWidget widget, + base::string16& filters_path, + bool use_json) { + std::unique_ptr<AccessibilityTreeFormatter> formatter( + AccessibilityTreeFormatter::Create()); + + // Get accessibility tree as nested dictionary. + std::unique_ptr<base::DictionaryValue> dict = + formatter->BuildAccessibilityTreeForWindow(widget); + + if (!dict) { + std::cout << "Failed to get accessibility tree"; + return; + } + + Format(*formatter, *dict, filters_path, use_json); +} + +std::vector<AccessibilityTreeFormatter::Filter> GetFilters( + const base::string16& filters_path) { + std::vector<AccessibilityTreeFormatter::Filter> filters; + if (!filters_path.empty()) { + std::string raw_filters_text; + base::ScopedAllowBlockingForTesting allow_io_for_test_setup; + if (base::ReadFileToString(base::FilePath(filters_path), + &raw_filters_text)) { + for (const std::string& line : + base::SplitString(raw_filters_text, "\n", base::TRIM_WHITESPACE, + base::SPLIT_WANT_ALL)) { + if (base::StartsWith(line, kAllowOptEmptyStr, + base::CompareCase::SENSITIVE)) { + filters.push_back(AccessibilityTreeFormatter::Filter( + base::UTF8ToUTF16(line.substr(strlen(kAllowOptEmptyStr))), + AccessibilityTreeFormatter::Filter::ALLOW_EMPTY)); + } else if (base::StartsWith(line, kAllowOptStr, + base::CompareCase::SENSITIVE)) { + filters.push_back(AccessibilityTreeFormatter::Filter( + base::UTF8ToUTF16(line.substr(strlen(kAllowOptStr))), + AccessibilityTreeFormatter::Filter::ALLOW)); + } else if (base::StartsWith(line, kDenyOptStr, + base::CompareCase::SENSITIVE)) { + filters.push_back(AccessibilityTreeFormatter::Filter( + base::UTF8ToUTF16(line.substr(strlen(kDenyOptStr))), + AccessibilityTreeFormatter::Filter::DENY)); + } + } + } + } + if (filters.empty()) { + filters = {AccessibilityTreeFormatter::Filter( + base::ASCIIToUTF16("*"), AccessibilityTreeFormatter::Filter::ALLOW)}; + } + + return filters; +} + +void AXTreeServer::Format(AccessibilityTreeFormatter& formatter, + base::DictionaryValue& dict, + base::string16& filters_path, + bool use_json) { + std::vector<AccessibilityTreeFormatter::Filter> filters = + GetFilters(filters_path); + + // Set filters. + formatter.SetFilters(filters); + + std::string accessibility_contents_utf8; + + // Format accessibility tree as JSON or text. + if (use_json) { + const std::unique_ptr<base::DictionaryValue> filtered_dict = + formatter.FilterAccessibilityTree(dict); + base::JSONWriter::WriteWithOptions(*filtered_dict, + base::JSONWriter::OPTIONS_PRETTY_PRINT, + &accessibility_contents_utf8); + } else { + base::string16 accessibility_contents_utf16; + formatter.FormatAccessibilityTree(dict, &accessibility_contents_utf16); + accessibility_contents_utf8 = + base::UTF16ToUTF8(accessibility_contents_utf16); + } + + // Write to console. + std::cout << accessibility_contents_utf8; +} + +} // namespace content
diff --git a/tools/accessibility/inspect/ax_tree_server.h b/tools/accessibility/inspect/ax_tree_server.h new file mode 100644 index 0000000..267ff39 --- /dev/null +++ b/tools/accessibility/inspect/ax_tree_server.h
@@ -0,0 +1,34 @@ +// Copyright 2017 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. + +#ifndef AX_TREE_SERVER_H_ +#define AX_TREE_SERVER_H_ + +#include <string> + +#include "content/browser/accessibility/accessibility_tree_formatter.h" + +namespace content { + +class AXTreeServer { + public: + AXTreeServer(base::ProcessId pid, + base::string16& filters_path, + bool use_json); + AXTreeServer(gfx::AcceleratedWidget widget, + base::string16& filters_path, + bool use_json); + + private: + DISALLOW_COPY_AND_ASSIGN(AXTreeServer); + + void Format(AccessibilityTreeFormatter& formatter, + base::DictionaryValue& dict, + base::string16& filters_path, + bool use_json); +}; + +} // namespace content + +#endif // AX_TREE_SERVER_H_
diff --git a/tools/accessibility/rebase_dump_accessibility_tree_test.py b/tools/accessibility/rebase_dump_accessibility_tree_test.py index 7f3aed0..bdcfaf3 100755 --- a/tools/accessibility/rebase_dump_accessibility_tree_test.py +++ b/tools/accessibility/rebase_dump_accessibility_tree_test.py
@@ -115,6 +115,8 @@ if builder['result'] == 'FAILURE': url = builder['url'] tokens = url.split('/') + if len(tokens) < 9: + continue bucket = tokens[4] platform = tokens[6] build = tokens[8]
diff --git a/tools/android/BUILD.gn b/tools/android/BUILD.gn index 23320039..3fdc092d 100644 --- a/tools/android/BUILD.gn +++ b/tools/android/BUILD.gn
@@ -16,8 +16,8 @@ "//tools/android/forwarder2", "//tools/android/md5sum", "//tools/android/memtrack_helper:memtrack_helper", - "//tools/android/purge_ashmem", "//tools/perf:run_benchmark_wrapper", + "//tools/perf/clear_system_cache", ] }
diff --git a/tools/android/checkstyle/checkstyle.py b/tools/android/checkstyle/checkstyle.py index 56589d6..af510ca 100644 --- a/tools/android/checkstyle/checkstyle.py +++ b/tools/android/checkstyle/checkstyle.py
@@ -6,6 +6,7 @@ import os import subprocess +import sys import xml.dom.minidom @@ -25,6 +26,10 @@ def RunCheckstyle(input_api, output_api, style_file, black_list=None): + # Android toolchain is only available on Linux. + if not sys.platform.startswith('linux'): + return [] + if not os.path.exists(style_file): file_error = (' Java checkstyle configuration file is missing: ' + style_file)
diff --git a/tools/android/checkstyle/chromium-style-5.0.xml b/tools/android/checkstyle/chromium-style-5.0.xml index 1af7385e..03d7bcf 100644 --- a/tools/android/checkstyle/chromium-style-5.0.xml +++ b/tools/android/checkstyle/chromium-style-5.0.xml
@@ -2,7 +2,7 @@ <!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.3//EN" "http://www.puppycrawl.com/dtds/configuration_1_3.dtd"> <!-- - See installation instructions: https://sites.google.com/a/chromium.org/dev/checkstyle + See installation instructions: https://sites.google.com/a/chromium.org/dev/developers/checkstyle --> <module name="Checker"> <property name="severity" value="warning"/> @@ -90,116 +90,23 @@ <property name="format" value="^m|s|((([ms][a-z0-9])|([a-ln-rt-z]))[a-zA-Z0-9]*)$"/> <message key="name.invalidPattern" value="Local variables should be camel-cased (e.g. int minWidth = 4)."/> </module> - <module name="LineLength"> - <property name="severity" value="error"/> - <property name="ignorePattern" value="^package.*|^import.*|a href|href|http://|https://|ftp://"/> - <property name="max" value="100"/> - </module> - <module name="LeftCurly"> - <property name="severity" value="error"/> - </module> - <module name="RightCurly"> - <property name="severity" value="error"/> - </module> - <module name="NeedBraces"> - <message key="needBraces" value="if, for, while, and do require curly braces unless they are single-line statements."/> - <property name="severity" value="error"/> - <property name="tokens" value="LITERAL_FOR, LITERAL_WHILE, LITERAL_DO, LITERAL_IF"/> - <property name="allowSingleLineStatement" value="true"/> - </module> - <module name="EmptyBlock"> - <property name="severity" value="error"/> - <property name="option" value="text"/> - <metadata name="altname" value="EmptyCatchBlock"/> - </module> - <module name="UpperEll"> - <property name="severity" value="error"/> - </module> <module name="FallThrough"> <property name="severity" value="error"/> <property name="reliefPattern" value=".*"/> </module> - <module name="ModifierOrder"> - <property name="severity" value="error"/> - </module> - <module name="WhitespaceAround"> - <property name="severity" value="error"/> - <property name="tokens" value="ASSIGN, BAND, BAND_ASSIGN, BOR, BOR_ASSIGN, BSR, BSR_ASSIGN, BXOR, BXOR_ASSIGN, COLON, DIV, DIV_ASSIGN, EQUAL, GE, GT, LAND, LE, LITERAL_ASSERT, LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE, LITERAL_FINALLY, LITERAL_FOR, LITERAL_IF, LITERAL_RETURN, LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE, LOR, LT, MINUS, MINUS_ASSIGN, MOD, MOD_ASSIGN, NOT_EQUAL, PLUS, PLUS_ASSIGN, QUESTION, SL, SLIST, SL_ASSIGN, SR, SR_ASSIGN, STAR, STAR_ASSIGN, TYPE_EXTENSION_AND" /> - <property name="allowEmptyConstructors" value="true"/> - <property name="allowEmptyMethods" value="true"/> - </module> - <module name="WhitespaceAfter"> - <property name="severity" value="error"/> - <property name="tokens" value="COMMA, SEMI, TYPECAST"/> - </module> - <module name="NoWhitespaceAfter"> - <property name="severity" value="error"/> - <property name="tokens" value="BNOT, DEC, DOT, INC, LNOT, UNARY_MINUS, UNARY_PLUS"/> - </module> - <module name="NoWhitespaceBefore"> - <property name="severity" value="error"/> - <property name="allowLineBreaks" value="true"/> - <property name="tokens" value="SEMI, DOT, POST_DEC, POST_INC"/> - </module> - <module name="GenericWhitespace"> - <property name="severity" value="error"/> - <message key="ws.followed" - value="GenericWhitespace ''{0}'' is followed by whitespace."/> - <message key="ws.preceded" - value="GenericWhitespace ''{0}'' is preceded with whitespace."/> - <message key="ws.illegalFollow" - value="GenericWhitespace ''{0}'' should followed by whitespace."/> - <message key="ws.notPreceded" - value="GenericWhitespace ''{0}'' is not preceded with whitespace."/> - </module> - <module name="EmptyStatement"> - <property name="severity" value="error"/> - </module> <module name="NoFinalizer"> <property name="severity" value="info"/> </module> - <module name="ParenPad"> - <property name="severity" value="error"/> - </module> - <module name="MethodParamPad"> - <property name="severity" value="error"/> - </module> <module name="ImportOrder"> <property name="severity" value="error"/> - <message key="import.ordering" value="Wrong order for {0} import. Use :JavaImportOrganize (ECLIM), Ctrl+Shift+O (Eclipse), or Ctrl+Alt+O (Android Studio) to sort imports. An importorder file for configuring Eclipse can be found at //tools/android/eclipse/android.importorder. A style configuration file for Android Studio can be found at //tools/android/android_studio/ChromiumStyle.xml."/> + <message key="import.ordering" value="Wrong order for {0} import. Follow the AOSP Java Code Style: https://source.android.com/setup/code-style#order-import-statements. When using Android Studio, use Ctrl+Alt+O to sort imports. A style configuration file can be found at //tools/android/android_studio/ChromiumStyle.xml."/> <property name="groups" value="android, com, dalvik, junit, org, com.google.android.apps.chrome, org.chromium, java, javax"/> <property name="ordered" value="true"/> <property name="option" value="top"/> <property name="separated" value="true"/> </module> - <module name="Indentation"> - <property name="severity" value="error"/> - <property name="basicOffset" value="4"/> - <property name="throwsIndent" value="8"/> - <property name="lineWrappingIndentation" value="8"/> - </module> - <!-- TODO(aurimas): make OperatorWrap into an error once all the warnings are fixed. --> - <module name="OperatorWrap"> - <property name="severity" value="error"/> - <property name="option" value="NL" /> - <property name="tokens" value="BAND, BOR, BSR, BXOR, DIV, EQUAL, GE, GT, LAND, LE, LITERAL_INSTANCEOF, LOR, LT, MINUS, MOD, NOT_EQUAL, PLUS, QUESTION, SL, SR, STAR " /> - </module> - <module name="OperatorWrap"> - <property name="severity" value="error"/> - <property name="option" value="eol"/> - <property name="tokens" value="ASSIGN"/> - </module> - <module name="SeparatorWrap"> - <property name="severity" value="error"/> - <property name="tokens" value="DOT"/> - <property name="option" value="nl"/> - </module> - <module name="SeparatorWrap"> - <property name="severity" value="error"/> - <property name="tokens" value="COMMA"/> - <property name="option" value="EOL"/> - </module> <module name="RegexpSinglelineJava"> + <property name="id" value="StringBufferCheck"/> <property name="severity" value="error"/> <property name="format" value="StringBuffer"/> <property name="ignoreComments" value="true"/> @@ -220,18 +127,4 @@ <property name="message" value="Use ContextUtils.getAppSharedPreferences() instead to access app-wide SharedPreferences."/> </module> </module> - - <!-- Non-TreeWalker modules --> - <module name="FileTabCharacter"> - <property name="severity" value="error"/> - </module> - <module name="RegexpSingleline"> - <property name="severity" value="error"/> - <property name="format" value="[ \t]+$"/> - <property name="message" value="Trailing whitespace"/> - </module> - <module name="RegexpHeader"> - <property name="severity" value="error"/> - <property name="header" value="^// Copyright 20\d\d The Chromium Authors. All rights reserved.$\n^// Use of this source code is governed by a BSD-style license that can be$\n^// found in the LICENSE file.$"/> - </module> </module>
diff --git a/tools/android/checkstyle/suppressions.xml b/tools/android/checkstyle/suppressions.xml index a5e865b4..3ff06d91 100644 --- a/tools/android/checkstyle/suppressions.xml +++ b/tools/android/checkstyle/suppressions.xml
@@ -7,4 +7,5 @@ Ref: crbug.com/640248 --> <suppress id="AlertDialogCheck" files="src/(android_webview|base|build|chromecast|components|content|device|media|mojo|net|printing|services|testing|third_party|tools|ui|url)/"/> + <suppress id="StringBufferCheck" files="src/chrome/android/webapk/"/> </suppressions>
diff --git a/tools/android/customtabs_benchmark/scripts/customtabs_benchmark.py b/tools/android/customtabs_benchmark/scripts/customtabs_benchmark.py index c115dff..0d033c2 100755 --- a/tools/android/customtabs_benchmark/scripts/customtabs_benchmark.py +++ b/tools/android/customtabs_benchmark/scripts/customtabs_benchmark.py
@@ -31,7 +31,6 @@ sys.path.append(os.path.join(_SRC_PATH, 'tools', 'android', 'loading')) import chrome_setup -import device_setup # Local build of Chrome (not Chromium). @@ -137,61 +136,54 @@ max(_INVALID_VALUE, int(tokens[8]) - intent_sent_timestamp)) -def LoopOnDevice(device, configs, output_filename, wpr_archive_path=None, - wpr_record=None, network_condition=None, wpr_log_path=None, - once=False, should_stop=None): +def LoopOnDevice(device, configs, output_filename, once=False, + should_stop=None): """Loops the tests on a device. Args: device: (DeviceUtils) device to run the tests on. configs: ([dict]) output_filename: (str) Output filename. '-' for stdout. - wpr_archive_path: (str) Path to the WPR archive. - wpr_record: (bool) Whether WPR is set to recording. - network_condition: (str) Name of the network configuration for throttling. - wpr_log_path: (str) Path the the WPR log. once: (bool) Run only once. should_stop: (threading.Event or None) When the event is set, stop looping. """ - with SetupWpr(device, wpr_archive_path, wpr_record, network_condition, - wpr_log_path) as wpr_attributes: - to_stdout = output_filename == '-' - out = sys.stdout if to_stdout else open(output_filename, 'a') - try: - while should_stop is None or not should_stop.is_set(): - config = configs[random.randint(0, len(configs) - 1)] - chrome_args = chrome_setup.CHROME_ARGS + wpr_attributes.chrome_args - if config['speculation_mode'] == 'no_state_prefetch': - # NoStatePrefetch is enabled through an experiment. - chrome_args.extend([ - '--force-fieldtrials=trial/group', - '--force-fieldtrial-params=trial.group:mode/no_state_prefetch', - '--enable-features=NoStatePrefetch<trial']) - elif config['speculation_mode'] == 'speculative_prefetch': - # Speculative Prefetch is enabled through an experiment. - chrome_args.extend([ - '--force-fieldtrials=trial/group', - '--force-fieldtrial-params=trial.group:mode/external-prefetching', - '--enable-features=SpeculativeResourcePrefetching<trial']) + to_stdout = output_filename == '-' + out = sys.stdout if to_stdout else open(output_filename, 'a') + try: + while should_stop is None or not should_stop.is_set(): + config = configs[random.randint(0, len(configs) - 1)] + chrome_args = chrome_setup.CHROME_ARGS + if config['speculation_mode'] == 'no_state_prefetch': + # NoStatePrefetch is enabled through an experiment. + chrome_args.extend([ + '--force-fieldtrials=trial/group', + '--force-fieldtrial-params=trial.group:mode/no_state_prefetch', + '--enable-features=NoStatePrefetch<trial']) + elif config['speculation_mode'] == 'speculative_prefetch': + # Speculative Prefetch is enabled through an experiment. + chrome_args.extend([ + '--force-fieldtrials=trial/group', + '--force-fieldtrial-params=trial.group:mode/external-prefetching', + '--enable-features=SpeculativeResourcePrefetching<trial']) - result = RunOnce(device, config['url'], config['speculated_url'], - config['warmup'], config['skip_launcher_activity'], - config['speculation_mode'], - config['delay_to_may_launch_url'], - config['delay_to_launch_url'], config['cold'], - chrome_args, reset_chrome_state=True) - if result is not None: - out.write(result + '\n') - out.flush() - if once: - return - if should_stop is not None: - should_stop.wait(10.) - else: - time.sleep(10) - finally: - if not to_stdout: - out.close() + result = RunOnce(device, config['url'], config['speculated_url'], + config['warmup'], config['skip_launcher_activity'], + config['speculation_mode'], + config['delay_to_may_launch_url'], + config['delay_to_launch_url'], config['cold'], + chrome_args, reset_chrome_state=True) + if result is not None: + out.write(result + '\n') + out.flush() + if once: + return + if should_stop is not None: + should_stop.wait(10.) + else: + time.sleep(10) + finally: + if not to_stdout: + out.close() def ProcessOutput(filename): @@ -246,42 +238,13 @@ parser.add_option('--cold', help='Purge the page cache before each run.', default=False, action='store_true') parser.add_option('--output_file', help='Output file (append). "-" for ' - 'stdout') + 'stdout (this is the default)', default='-') parser.add_option('--once', help='Run only one iteration.', action='store_true', default=False) - # WebPageReplay-related options. - group = optparse.OptionGroup( - parser, 'WebPageReplay options', - 'Setting any of these enables WebPageReplay.') - group.add_option('--record', help='Record the WPR archive.', - action='store_true', default=False) - group.add_option('--wpr_archive', help='WPR archive path.') - group.add_option('--wpr_log', help='WPR log path.') - group.add_option('--network_condition', - help='Network condition for emulation.') - parser.add_option_group(group) - return parser -@contextlib.contextmanager -def DummyWprHost(): - """Dummy context used to run without WebPageReplay.""" - yield device_setup.WprAttribute(chrome_args=[], chrome_env_override={}) - - -def SetupWpr(device, wpr_archive_path, record, network_condition_name, - out_log_path): - """Sets up the WebPageReplay server if needed.""" - if wpr_archive_path or record or network_condition_name or out_log_path: - return device_setup.RemoteWprHost(device, wpr_archive_path, record, - network_condition_name, - out_log_path=out_log_path) - # WebPageReplay disabled. - return DummyWprHost() - - def main(): parser = _CreateOptionParser() options, _ = parser.parse_args() @@ -308,9 +271,7 @@ 'delay_to_launch_url': options.delay_to_launch_url, 'cold': options.cold, } - LoopOnDevice(device, [config], options.output_file, options.wpr_archive, - options.record, options.network_condition, options.wpr_log, - once=options.once) + LoopOnDevice(device, [config], options.output_file, once=options.once) if __name__ == '__main__':
diff --git a/tools/android/eclipse/.classpath b/tools/android/eclipse/.classpath index 6b91efc..bb412fb 100644 --- a/tools/android/eclipse/.classpath +++ b/tools/android/eclipse/.classpath
@@ -70,7 +70,6 @@ <classpathentry kind="src" path="components/policy/android/junit/src"/> <classpathentry kind="src" path="components/precache/android/java/src"/> <classpathentry kind="src" path="components/precache/android/javatests/src"/> - <classpathentry kind="src" path="components/safe_json/android/java/src"/> <classpathentry kind="src" path="components/signin/core/browser/android/java/src"/> <classpathentry kind="src" path="components/signin/core/browser/android/javatests/src"/> <classpathentry kind="src" path="components/sync/android/java/src"/> @@ -113,6 +112,7 @@ <classpathentry kind="src" path="remoting/android/java/src"/> <classpathentry kind="src" path="remoting/android/javatests/src"/> <classpathentry kind="src" path="services/service_manager/public/java/src"/> + <classpathentry kind="src" path="services/data_decoder/public/cpp/android/src"/> <classpathentry kind="src" path="testing/android/appurify_support/java/src"/> <classpathentry kind="src" path="testing/android/broker/java/src"/> <classpathentry kind="src" path="testing/android/driver/java/src"/> @@ -132,8 +132,6 @@ <classpathentry kind="src" path="third_party/leakcanary/src/leakcanary-android/src/main/java"/> <classpathentry kind="src" path="third_party/leakcanary/src/leakcanary-watcher/src/main/java"/> <classpathentry kind="src" path="third_party/mockito/src/src/main/java"/> - <classpathentry kind="src" path="tools/android/findbugs_plugin/src"/> - <classpathentry kind="src" path="tools/android/findbugs_plugin/test/java/src"/> <classpathentry kind="src" path="tools/android/memconsumer/java/src"/> <classpathentry kind="src" path="ui/android/java/src"/> <classpathentry kind="src" path="ui/android/javatests/src"/> @@ -229,7 +227,7 @@ <classpathentry kind="src" path="out/Debug/remoting_apk/gen"/> <classpathentry kind="src" path="out/Debug/webview_instrumentation_test_apk/gen"/> <classpathentry kind="lib" path="third_party/android_tools/sdk/extras/google/gcm/gcm-client/dist/gcm.jar" sourcepath="third_party/android_tools/sdk/extras/google/gcm/gcm-client/src"/> - <classpathentry kind="lib" path="third_party/android_tools/sdk/platforms/android-26/android.jar" sourcepath="third_party/android_tools/sdk/sources/"> + <classpathentry kind="lib" path="third_party/android_tools/sdk/platforms/android-27/android.jar" sourcepath="third_party/android_tools/sdk/sources/"> <attributes> <attribute name="javadoc_location" value="http://developer.android.com/reference/"/> </attributes> @@ -273,7 +271,6 @@ <classpathentry kind="lib" path="out/Debug/lib.java/components/policy/android/policy_java.jar"/> <classpathentry kind="lib" path="out/Debug/lib.java/components/payments/content/payment_request_java.jar"/> <classpathentry kind="lib" path="out/Debug/lib.java/components/precache/android/precache_java.jar"/> - <classpathentry kind="lib" path="out/Debug/lib.java/components/safe_json/android/safe_json_java.jar"/> <classpathentry kind="lib" path="out/Debug/lib.java/components/service_tab_launcher/service_tab_launcher_java.jar"/> <classpathentry kind="lib" path="out/Debug/lib.java/components/signin/core/browser/android/java.jar"/> <classpathentry kind="lib" path="out/Debug/lib.java/components/variations/android/variations_java.jar"/> @@ -292,7 +289,8 @@ <classpathentry kind="lib" path="out/Debug/lib.java/mojo/public/java/system.jar"/> <classpathentry kind="lib" path="out/Debug/lib.java/net/android/net_java.jar"/> <classpathentry kind="lib" path="out/Debug/lib.java/printing/printing_java.jar"/> - <classpathentry kind="lib" path="out/Debug/lib.java/services/service_manager/public/interfaces/interfaces_java.jar"/> + <classpathentry kind="lib" path="out/Debug/lib.java/services/data_decoder/public/android/safe_json_java.jar"/> + <classpathentry kind="lib" path="out/Debug/lib.java/services/service_manager/public/mojom/mojom_java.jar"/> <classpathentry kind="lib" path="out/Debug/lib.java/sync/android/sync_java.jar"/> <classpathentry kind="lib" path="out/Debug/lib.java/sync/test_support_proto_java.jar"/> <classpathentry kind="lib" path="out/Debug/lib.java/third_party/android_data_chart/android_data_chart_java.jar"/>
diff --git a/tools/android/errorprone_plugin/BUILD.gn b/tools/android/errorprone_plugin/BUILD.gn new file mode 100644 index 0000000..be727d8c --- /dev/null +++ b/tools/android/errorprone_plugin/BUILD.gn
@@ -0,0 +1,24 @@ +# Copyright 2017 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("//build/config/android/rules.gni") + +java_library("errorprone_plugin_java") { + java_files = [ + "src/org/chromium/tools/errorprone/plugin/NoSynchronizedMethodCheck.java", + "src/org/chromium/tools/errorprone/plugin/NoSynchronizedThisCheck.java", + ] + + # Necessary to avoid dependency cycle + enable_errorprone = false + + # So that we don't need to inject emma runtime into the compiler's classpath. + emma_never_instrument = true + + annotation_processor_deps = [ "//third_party/auto:auto_service_processor" ] + deps = [ + "//third_party/auto:auto_service_java", + "//third_party/errorprone:errorprone_java", + ] +}
diff --git a/tools/android/errorprone_plugin/OWNERS b/tools/android/errorprone_plugin/OWNERS new file mode 100644 index 0000000..80e6172 --- /dev/null +++ b/tools/android/errorprone_plugin/OWNERS
@@ -0,0 +1,3 @@ +agrieve@chromium.org +nyquist@chromium.org +wnwen@chromium.org
diff --git a/tools/android/errorprone_plugin/src/org/chromium/tools/errorprone/plugin/NoSynchronizedMethodCheck.java b/tools/android/errorprone_plugin/src/org/chromium/tools/errorprone/plugin/NoSynchronizedMethodCheck.java new file mode 100644 index 0000000..b99f1871 --- /dev/null +++ b/tools/android/errorprone_plugin/src/org/chromium/tools/errorprone/plugin/NoSynchronizedMethodCheck.java
@@ -0,0 +1,52 @@ +// Copyright 2017 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. + +package org.chromium.tools.errorprone.plugin; + +import com.google.auto.service.AutoService; +import com.google.errorprone.BugPattern; +import com.google.errorprone.VisitorState; +import com.google.errorprone.bugpatterns.BugChecker; +import com.google.errorprone.fixes.SuggestedFixes; +import com.google.errorprone.matchers.Description; +import com.google.errorprone.util.ASTHelpers; +import com.sun.source.tree.MethodTree; +import com.sun.tools.javac.code.Symbol; + +import javax.lang.model.element.Modifier; + +/** + * Triggers an error for public methods that use "synchronized" in their signature. + */ +@AutoService(BugChecker.class) +@BugPattern(name = "NoSynchronizedMethodCheck", category = BugPattern.Category.JDK, + summary = "Use of synchronized in public method signature disallowed.", + severity = BugPattern.SeverityLevel.ERROR, linkType = BugPattern.LinkType.CUSTOM, + link = "https://stackoverflow.com/questions/20906548/why-is-synchronized-block-better-than-synchronized-method") +public class NoSynchronizedMethodCheck extends BugChecker implements BugChecker.MethodTreeMatcher { + @Override + public Description matchMethod(MethodTree methodTree, VisitorState visitorState) { + Symbol.MethodSymbol method = ASTHelpers.getSymbol(methodTree); + // Skip methods that aren't synchronized and non-public methods + if (!method.getModifiers().contains(Modifier.SYNCHRONIZED) + || !method.getModifiers().contains(Modifier.PUBLIC)) { + return Description.NO_MATCH; + } + // Skip methods that are only public due to VisibleForTesting + if (ASTHelpers.hasDirectAnnotationWithSimpleName(method, "VisibleForTesting")) { + return Description.NO_MATCH; + } + // Skip non-public classes + Symbol.ClassSymbol enclosingClass = ASTHelpers.enclosingClass(method); + if (!enclosingClass.getModifiers().contains(Modifier.PUBLIC)) { + return Description.NO_MATCH; + } + return buildDescription(methodTree) + .addFix(SuggestedFixes.removeModifiers( + methodTree, visitorState, Modifier.SYNCHRONIZED)) + .setMessage(String.format( + "Used synchronized modifier in public method %s", method.getSimpleName())) + .build(); + } +}
diff --git a/tools/android/errorprone_plugin/src/org/chromium/tools/errorprone/plugin/NoSynchronizedThisCheck.java b/tools/android/errorprone_plugin/src/org/chromium/tools/errorprone/plugin/NoSynchronizedThisCheck.java new file mode 100644 index 0000000..f82664e --- /dev/null +++ b/tools/android/errorprone_plugin/src/org/chromium/tools/errorprone/plugin/NoSynchronizedThisCheck.java
@@ -0,0 +1,46 @@ +// Copyright 2017 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. + +package org.chromium.tools.errorprone.plugin; + +import com.google.auto.service.AutoService; +import com.google.errorprone.BugPattern; +import com.google.errorprone.VisitorState; +import com.google.errorprone.bugpatterns.BugChecker; +import com.google.errorprone.matchers.Description; +import com.google.errorprone.util.ASTHelpers; +import com.sun.source.tree.SynchronizedTree; +import com.sun.tools.javac.code.Symbol; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.TreeInfo; + +import javax.lang.model.element.Modifier; + +/** + * This class detects the synchronized method. + */ +@AutoService(BugChecker.class) +@BugPattern(name = "NoSynchronizedThisCheck", category = BugPattern.Category.JDK, + summary = "Do not synchronized on 'this' in public classes", + severity = BugPattern.SeverityLevel.ERROR, linkType = BugPattern.LinkType.CUSTOM, + link = "https://stackoverflow.com/questions/442564/avoid-synchronizedthis-in-java") +public class NoSynchronizedThisCheck + extends BugChecker implements BugChecker.SynchronizedTreeMatcher { + @Override + public Description matchSynchronized(SynchronizedTree tree, VisitorState visitorState) { + Symbol lock = ASTHelpers.getSymbol(TreeInfo.skipParens((JCTree) tree.getExpression())); + // Skip locks that are not 'this' + if (!lock.getSimpleName().contentEquals("this")) { + return Description.NO_MATCH; + } + // Skip non-public classes + Symbol.ClassSymbol enclosingClass = ASTHelpers.enclosingClass(lock); + if (!enclosingClass.getModifiers().contains(Modifier.PUBLIC)) { + return Description.NO_MATCH; + } + return buildDescription(tree) + .setMessage("Used instance variable as synchronization lock") + .build(); + } +}
diff --git a/tools/android/findbugs_plugin/README b/tools/android/findbugs_plugin/README deleted file mode 100644 index 3ba3f53..0000000 --- a/tools/android/findbugs_plugin/README +++ /dev/null
@@ -1,15 +0,0 @@ -This is the FindBugs plugin for chrome on android. - -Currently it detects: -- synchronized method -- synchronized 'this' - -We don't want the synchronized method and synchronized 'this' to be -used, the exception is the synchronized method defined in Android -API. - -The plugin jar file was prebuilt and checked in, to rebuild the -plugin, you need ant, and run below command, the new jar file will -be in lib directory. - -ant install
diff --git a/tools/android/findbugs_plugin/build.xml b/tools/android/findbugs_plugin/build.xml deleted file mode 100644 index 09ee13c..0000000 --- a/tools/android/findbugs_plugin/build.xml +++ /dev/null
@@ -1,48 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - 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. ---> - -<project name="findbugs_plugin" basedir="."> - - <description> - Build findbugs_plugin for Chromium Android - </description> - <property name="src.dir" location="src" /> - <property name="lib.dir" location="../../../third_party/findbugs/lib" /> - <property name="bin.dir" location="lib" /> - <property name="intermediate.dir" location="intermediate" /> - <property name="jar.name" value="chromiumPlugin.jar" /> - - <path id="classpath.id"> - <fileset dir="${lib.dir}"> - <include name="**/*.jar" /> - </fileset> - </path> - - <target name="makedir"> - <mkdir dir="${intermediate.dir}" /> - <mkdir dir="${bin.dir}" /> - </target> - - <target name="findbugs_plugin_classes" depends="makedir"> - <javac srcdir="${src.dir}" destdir="${intermediate.dir}" - classpathref="classpath.id" includeantruntime="false" /> - </target> - - <target name="copy_xml_files" depends="makedir"> - <copy file="messages.xml" todir="${intermediate.dir}" /> - <copy file="findbugs.xml" todir="${intermediate.dir}" /> - </target> - - <target name="findbugs_plugin_jar" depends="findbugs_plugin_classes, copy_xml_files"> - <jar destfile="${bin.dir}/${jar.name}" basedir="${intermediate.dir}"> - </jar> - </target> - - <target name="install" depends="findbugs_plugin_jar"> - <delete dir="${intermediate.dir}" /> - </target> -</project>
diff --git a/tools/android/findbugs_plugin/findbugs.xml b/tools/android/findbugs_plugin/findbugs.xml deleted file mode 100644 index 002e841..0000000 --- a/tools/android/findbugs_plugin/findbugs.xml +++ /dev/null
@@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - 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. ---> - -<FindbugsPlugin xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="findbugsplugin.xsd" - pluginid="SynchronizedThisDetector" - provider="chromium" - website="https://chromium.googlesource.com/chromium/src/+/master/docs/use_find_bugs_for_android.md"> - <Detector class="org.chromium.tools.findbugs.plugin.SynchronizedThisDetector" reports="CHROMIUM_SYNCHRONIZED_THIS" /> - <BugPattern type="CHROMIUM_SYNCHRONIZED_THIS" abbrev="CHROMIUM" category="CORRECTNESS"/> - - <Detector class="org.chromium.tools.findbugs.plugin.SynchronizedMethodDetector" reports="CHROMIUM_SYNCHRONIZED_METHOD" /> - <BugPattern type="CHROMIUM_SYNCHRONIZED_METHOD" abbrev="CHROMIUM" category="CORRECTNESS"/> -</FindbugsPlugin>
diff --git a/tools/android/findbugs_plugin/lib/chromiumPlugin.jar b/tools/android/findbugs_plugin/lib/chromiumPlugin.jar deleted file mode 100644 index 451566d2e..0000000 --- a/tools/android/findbugs_plugin/lib/chromiumPlugin.jar +++ /dev/null Binary files differ
diff --git a/tools/android/findbugs_plugin/messages.xml b/tools/android/findbugs_plugin/messages.xml deleted file mode 100644 index aea983b..0000000 --- a/tools/android/findbugs_plugin/messages.xml +++ /dev/null
@@ -1,56 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!-- - 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. ---> - -<MessageCollection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="messagecollection.xsd"> - - <Plugin> - <ShortDescription>Chromium FindBugs Plugin </ShortDescription> - <Details>Adds style checks enforced in the chromium project.</Details> - </Plugin> - - <Detector class="org.chromium.tools.findbugs.plugin.SynchronizedThisDetector"> - <Details> - <![CDATA[ - Shouldn't use synchronized(this). - ]]> - </Details> - - </Detector> - - <BugPattern type="CHROMIUM_SYNCHRONIZED_THIS"> - <ShortDescription>Shouldn't use synchronized(this)</ShortDescription> - <LongDescription>Shouldn't use synchronized(this), please narrow down the synchronization scope.</LongDescription> - <Details> -<![CDATA[ -<p>Shouldn't use synchronized(this), please narrow down the synchronization scope.</p> -]]> - </Details> - </BugPattern> - - <Detector class="org.chromium.tools.findbugs.plugin.SynchronizedMethodDetector"> - <Details> - <![CDATA[ - Shouldn't use synchronized method. - ]]> - </Details> - - </Detector> - - <BugPattern type="CHROMIUM_SYNCHRONIZED_METHOD"> - <ShortDescription>Shouldn't use synchronized method</ShortDescription> - <LongDescription>Shouldn't use synchronized method, please narrow down the synchronization scope.</LongDescription> - <Details> -<![CDATA[ -<p>Shouldn't use synchronized method, please narrow down the synchronization scope.</p> -]]> - </Details> - </BugPattern> - - <BugCode abbrev="CHROMIUM">CHROMIUM</BugCode> -</MessageCollection>
diff --git a/tools/android/findbugs_plugin/src/org/chromium/tools/findbugs/plugin/SynchronizedMethodDetector.java b/tools/android/findbugs_plugin/src/org/chromium/tools/findbugs/plugin/SynchronizedMethodDetector.java deleted file mode 100644 index d1d7614..0000000 --- a/tools/android/findbugs_plugin/src/org/chromium/tools/findbugs/plugin/SynchronizedMethodDetector.java +++ /dev/null
@@ -1,37 +0,0 @@ -// Copyright 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. - -package org.chromium.tools.findbugs.plugin; - -import org.apache.bcel.classfile.Code; - -import edu.umd.cs.findbugs.BugInstance; -import edu.umd.cs.findbugs.BugReporter; -import edu.umd.cs.findbugs.bcel.OpcodeStackDetector; - -/** - * This class detects the synchronized method. - */ -public class SynchronizedMethodDetector extends OpcodeStackDetector { - private BugReporter mBugReporter; - - public SynchronizedMethodDetector(BugReporter bugReporter) { - this.mBugReporter = bugReporter; - } - - @Override - public void visit(Code code) { - if (getMethod().isSynchronized()) { - mBugReporter.reportBug(new BugInstance(this, "CHROMIUM_SYNCHRONIZED_METHOD", - NORMAL_PRIORITY) - .addClassAndMethod(this) - .addSourceLine(this)); - } - super.visit(code); - } - - @Override - public void sawOpcode(int arg0) { - } -}
diff --git a/tools/android/findbugs_plugin/src/org/chromium/tools/findbugs/plugin/SynchronizedThisDetector.java b/tools/android/findbugs_plugin/src/org/chromium/tools/findbugs/plugin/SynchronizedThisDetector.java deleted file mode 100644 index 9a4e5e1..0000000 --- a/tools/android/findbugs_plugin/src/org/chromium/tools/findbugs/plugin/SynchronizedThisDetector.java +++ /dev/null
@@ -1,73 +0,0 @@ -// Copyright 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. - -package org.chromium.tools.findbugs.plugin; - -import org.apache.bcel.classfile.Code; - -import edu.umd.cs.findbugs.BugInstance; -import edu.umd.cs.findbugs.BugReporter; -import edu.umd.cs.findbugs.bcel.OpcodeStackDetector; - -/** - * This class detects the synchronized(this). - * - * The pattern of byte code of synchronized(this) is - * aload_0 # Load the 'this' pointer on top of stack - * dup # Duplicate the 'this' pointer - * astore_x # Store this for late use, it might be astore. - * monitorenter - */ -public class SynchronizedThisDetector extends OpcodeStackDetector { - private static final int PATTERN[] = {ALOAD_0, DUP, 0xff, 0xff, MONITORENTER}; - - private int mStep = 0; - private BugReporter mBugReporter; - - public SynchronizedThisDetector(BugReporter bugReporter) { - mBugReporter = bugReporter; - } - - @Override - public void visit(Code code) { - mStep = 0; - super.visit(code); - } - - @Override - public void sawOpcode(int seen) { - if (PATTERN[mStep] == seen) { - mStep++; - if (mStep == PATTERN.length) { - mBugReporter.reportBug(new BugInstance(this, "CHROMIUM_SYNCHRONIZED_THIS", - NORMAL_PRIORITY) - .addClassAndMethod(this) - .addSourceLine(this)); - mStep = 0; - return; - } - } else if (mStep == 2) { - // This could be astore_x - switch (seen) { - case ASTORE_0: - case ASTORE_1: - case ASTORE_2: - case ASTORE_3: - mStep += 2; - break; - case ASTORE: - mStep++; - break; - default: - mStep = 0; - break; - } - } else if (mStep == 3) { - // Could be any byte following the ASTORE. - mStep++; - } else { - mStep = 0; - } - } -}
diff --git a/tools/android/findbugs_plugin/test/java/src/org/chromium/tools/findbugs/plugin/SimpleSynchronizedMethod.java b/tools/android/findbugs_plugin/test/java/src/org/chromium/tools/findbugs/plugin/SimpleSynchronizedMethod.java deleted file mode 100644 index ded7848..0000000 --- a/tools/android/findbugs_plugin/test/java/src/org/chromium/tools/findbugs/plugin/SimpleSynchronizedMethod.java +++ /dev/null
@@ -1,17 +0,0 @@ -// Copyright 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. - -package org.chromium.tools.findbugs.plugin; - -/** - * This class has synchronized method and is used to test - * SynchronizedMethodDetector. - */ -class SimpleSynchronizedMethod { - private int mCounter = 0; - - synchronized void synchronizedMethod() { - mCounter++; - } -}
diff --git a/tools/android/findbugs_plugin/test/java/src/org/chromium/tools/findbugs/plugin/SimpleSynchronizedStaticMethod.java b/tools/android/findbugs_plugin/test/java/src/org/chromium/tools/findbugs/plugin/SimpleSynchronizedStaticMethod.java deleted file mode 100644 index d652dbe5..0000000 --- a/tools/android/findbugs_plugin/test/java/src/org/chromium/tools/findbugs/plugin/SimpleSynchronizedStaticMethod.java +++ /dev/null
@@ -1,16 +0,0 @@ -// Copyright 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. - -package org.chromium.tools.findbugs.plugin; - -/** - * This class is used to test SynchronizedMethodDetector - */ -class SimpleSynchronizedStaticMethod { - private static int sCounter = 0; - - static synchronized void synchronizedStaticMethod() { - sCounter++; - } -}
diff --git a/tools/android/findbugs_plugin/test/java/src/org/chromium/tools/findbugs/plugin/SimpleSynchronizedThis.java b/tools/android/findbugs_plugin/test/java/src/org/chromium/tools/findbugs/plugin/SimpleSynchronizedThis.java deleted file mode 100644 index 91251559..0000000 --- a/tools/android/findbugs_plugin/test/java/src/org/chromium/tools/findbugs/plugin/SimpleSynchronizedThis.java +++ /dev/null
@@ -1,19 +0,0 @@ -// Copyright 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. - -package org.chromium.tools.findbugs.plugin; - -/** - * This class has synchronized(this) statement and is used to test - * SynchronizedThisDetector. - */ -class SimpleSynchronizedThis { - private int mCounter = 0; - - void synchronizedThis() { - synchronized (this) { - mCounter++; - } - } -}
diff --git a/tools/android/findbugs_plugin/test/run_findbugs_plugin_tests.py b/tools/android/findbugs_plugin/test/run_findbugs_plugin_tests.py deleted file mode 100755 index 603659e6..0000000 --- a/tools/android/findbugs_plugin/test/run_findbugs_plugin_tests.py +++ /dev/null
@@ -1,104 +0,0 @@ -#!/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. - -# This is used to test the findbugs plugin, it calls -# build/android/pylib/utils/findbugs.py to analyze the classes in -# org.chromium.tools.findbugs.plugin package, and expects to get the same -# issue with those in expected_result.txt. -# -# Useful command line: -# --rebaseline to generate the expected_result.txt, please make sure don't -# remove the expected result of exsting tests. - - -import argparse -import os -import sys - -sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), - '..', '..', '..', '..', - 'build', 'android'))) - -from pylib import constants -from pylib.utils import findbugs - - -_EXPECTED_WARNINGS = set([ - findbugs.FindBugsWarning( - bug_type='CHROMIUM_SYNCHRONIZED_THIS', - start_line=15, - end_line=15, - file_name='SimpleSynchronizedThis.java', - message=( - "Shouldn't use synchronized(this)", - 'In class org.chromium.tools.findbugs.plugin.' - + 'SimpleSynchronizedThis', - 'In method org.chromium.tools.findbugs.plugin.' - + 'SimpleSynchronizedThis.synchronizedThis()', - 'At SimpleSynchronizedThis.java:[line 15]', - )), - findbugs.FindBugsWarning( - bug_type='CHROMIUM_SYNCHRONIZED_METHOD', - start_line=14, - end_line=14, - file_name='SimpleSynchronizedStaticMethod.java', - message=( - "Shouldn't use synchronized method", - 'In class org.chromium.tools.findbugs.plugin.' - + 'SimpleSynchronizedStaticMethod', - 'In method org.chromium.tools.findbugs.plugin.' - + 'SimpleSynchronizedStaticMethod.synchronizedStaticMethod()', - 'At SimpleSynchronizedStaticMethod.java:[line 14]', - )), - findbugs.FindBugsWarning( - bug_type='CHROMIUM_SYNCHRONIZED_METHOD', - start_line=15, - end_line=15, - file_name='SimpleSynchronizedMethod.java', - message=( - "Shouldn't use synchronized method", - 'In class org.chromium.tools.findbugs.plugin.' - + 'SimpleSynchronizedMethod', - 'In method org.chromium.tools.findbugs.plugin.' - + 'SimpleSynchronizedMethod.synchronizedMethod()', - 'At SimpleSynchronizedMethod.java:[line 15]', - )), -]) - - -def main(argv): - - parser = argparse.ArgumentParser() - parser.add_argument( - '-l', '--release-build', action='store_true', dest='release', - help='Run the release build of the findbugs plugin test.') - args = parser.parse_args() - - test_jar_path = os.path.join( - constants.GetOutDirectory( - 'Release' if args.release else 'Debug'), - 'lib.java', 'findbugs_plugin_test.jar') - - findbugs_command, findbugs_warnings = findbugs.Run( - None, 'org.chromium.tools.findbugs.plugin.*', None, None, None, None, - [test_jar_path]) - - missing_warnings = _EXPECTED_WARNINGS.difference(findbugs_warnings) - if missing_warnings: - print 'Missing warnings:' - for w in missing_warnings: - print '%s' % str(w) - - unexpected_warnings = findbugs_warnings.difference(_EXPECTED_WARNINGS) - if unexpected_warnings: - print 'Unexpected warnings:' - for w in unexpected_warnings: - print '%s' % str(w) - - return len(unexpected_warnings) + len(missing_warnings) - -if __name__ == '__main__': - sys.exit(main(sys.argv))
diff --git a/tools/android/loading/device_setup.py b/tools/android/loading/device_setup.py index cfa19bf0..16abfa6 100644 --- a/tools/android/loading/device_setup.py +++ b/tools/android/loading/device_setup.py
@@ -360,11 +360,6 @@ def RemoteSpeedIndexRecorder(device, connection, local_output_path): """Records on a device a video compatible for speed-index computation. - Note: - Chrome should be opened with the --disable-infobars command line argument to - avoid web page viewport size to be changed, that can change speed-index - value. - Args: device: (device_utils.DeviceUtils) Android device to connect to. connection: devtools connection.
diff --git a/tools/android/loading/sandwich_runner.py b/tools/android/loading/sandwich_runner.py index 5c3bb949..cb2a80d 100644 --- a/tools/android/loading/sandwich_runner.py +++ b/tools/android/loading/sandwich_runner.py
@@ -331,7 +331,6 @@ self._chrome_ctl = controller.RemoteChromeController(self.android_device) else: self._chrome_ctl = controller.LocalChromeController() - self._chrome_ctl.AddChromeArguments(['--disable-infobars']) self._chrome_ctl.AddChromeArguments(self.chrome_args) if self.cache_operation == CacheOperation.SAVE: self._chrome_ctl.SetSlowDeath()
diff --git a/tools/android/memconsumer/java/AndroidManifest.xml b/tools/android/memconsumer/java/AndroidManifest.xml index c7f12e42..f886d7b 100644 --- a/tools/android/memconsumer/java/AndroidManifest.xml +++ b/tools/android/memconsumer/java/AndroidManifest.xml
@@ -9,6 +9,8 @@ package="org.chromium.memconsumer" android:versionCode="1" android:versionName="1.0"> + <uses-sdk android:minSdkVersion="16"/> + <application android:label="MemConsumer"> <activity android:name=".MemConsumer" android:icon="@drawable/icon" android:launchMode="singleTop">
diff --git a/tools/android/memconsumer/memconsumer_hook.cc b/tools/android/memconsumer/memconsumer_hook.cc index 78a98d9..7526b66 100644 --- a/tools/android/memconsumer/memconsumer_hook.cc +++ b/tools/android/memconsumer/memconsumer_hook.cc
@@ -6,6 +6,7 @@ #include <jni.h> #include <stdio.h> #include <string.h> +#include <cstdlib> extern "C" { JNIEXPORT void JNICALL @@ -40,10 +41,9 @@ } g_memory = static_cast<uint32_t*>(malloc(memory)); if (!g_memory) { - __android_log_print(ANDROID_LOG_WARN, - "MemConsumer", + __android_log_print(ANDROID_LOG_WARN, "MemConsumer", "Unable to allocate %lld bytes", - memory); + static_cast<long long>(memory)); } // If memory allocation failed, try to allocate as much as possible. while (!g_memory) {
diff --git a/tools/android/memtrack_helper/memtrack_helper.c b/tools/android/memtrack_helper/memtrack_helper.c index b1185573..0585705 100644 --- a/tools/android/memtrack_helper/memtrack_helper.c +++ b/tools/android/memtrack_helper/memtrack_helper.c
@@ -17,6 +17,7 @@ #include <sys/stat.h> #include <sys/types.h> #include <sys/wait.h> +#include <unistd.h> /* * This is a helper daemon for Android which makes memtrack graphics information
diff --git a/tools/android/native_lib_memory/OWNERS b/tools/android/native_lib_memory/OWNERS new file mode 100644 index 0000000..d45b803a --- /dev/null +++ b/tools/android/native_lib_memory/OWNERS
@@ -0,0 +1,3 @@ +lizeb@chromium.org +mattcary@chromium.org +pasko@chromium.org
diff --git a/tools/android/native_lib_memory/extract_symbols.py b/tools/android/native_lib_memory/extract_symbols.py new file mode 100755 index 0000000..fa992719 --- /dev/null +++ b/tools/android/native_lib_memory/extract_symbols.py
@@ -0,0 +1,294 @@ +#!/usr/bin/python +# +# Copyright 2017 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. + +"""Maps code pages to object files. + +For all pages from the native library .text section, extract all object files +the code maps to. Outputs a web-based visualization of page -> symbol mappings, +reached symbols and code residency. +""" + +import argparse +import collections +import json +import logging +import multiprocessing +import os +import shutil +import SimpleHTTPServer +import SocketServer +import sys + +_SRC_PATH = os.path.abspath(os.path.join( + os.path.dirname(__file__), os.pardir, os.pardir, os.pardir)) + +sys.path.append(os.path.join(_SRC_PATH, 'tools', 'cygprofile')) +import cyglog_to_orderfile +import symbol_extractor + +_PAGE_SIZE = 1 << 12 +_PAGE_MASK = ~(_PAGE_SIZE - 1) + + +def GetSymbolNameToFilename(build_directory): + """Parses object files in a directory, and maps mangled symbol names to files. + + Args: + build_directory: (str) Build directory. + + Returns: + {symbol_info.name: (symbol_info, object filename)}. Filenames are stripped + of the output_directory part. + """ + path = os.path.join(build_directory, 'obj') + object_filenames = cyglog_to_orderfile.GetObjectFileNames(path) + pool = multiprocessing.Pool() + symbol_infos_filename = zip( + pool.map(symbol_extractor.SymbolInfosFromBinary, object_filenames), + object_filenames) + result = {} + for (symbol_infos, filename) in symbol_infos_filename: + stripped_filename = filename[len(build_directory):] + if stripped_filename.startswith('/obj/'): + stripped_filename = stripped_filename[len('/obj/'):] + for s in symbol_infos: + result[s.name] = (s, stripped_filename) + return result + + +def CodePagesToMangledSymbols(symbol_infos, text_start_offset): + """Groups a list of symbol per code page. + + Args: + symbol_infos: (symbol_extractor.SymbolInfo) List of symbols. + text_start_offset: (int) Offset to add to symbol offsets. This is used to + account for the start of .text not being at the start of + a page in memory. + + Returns: + {offset: [(mangled_name, size_in_page), ...]} + """ + # Different symbols can be at the same address, through identical code folding + # for instance. In this case, only keep the first one. This is not ideal, as + # file attribution will be incorrect in this case. However ICF mostly works + # with small symbols, so it shouldn't impact numbers too much. + result = collections.defaultdict(set) + known_offsets = set() + for s in symbol_infos: + assert s.offset % 2 == 0, 'Wrong alignment' + if s.offset in known_offsets: + continue + known_offsets.add(s.offset) + start, end = (s.offset + text_start_offset, + (s.offset + s.size + text_start_offset)) + start_page, end_page = start & _PAGE_MASK, end & _PAGE_MASK + page = start_page + while page <= end_page: + symbol_start_in_page = max(page, start) + symbol_end_in_page = min(page + _PAGE_SIZE, end) + size_in_page = symbol_end_in_page - symbol_start_in_page + result[page].add((s.name, size_in_page)) + page += _PAGE_SIZE + for page in result: + total_size = sum(s[1] for s in result[page]) + if total_size > _PAGE_SIZE: + logging.warning('Too many symbols in page (%d * 4k)! Total size: %d', + page / _PAGE_SIZE, total_size) + return result + + +def ReadReachedSymbols(filename): + """Reads a list of reached symbols from a file. + + Args: + filename: (str) File to read. + + Returns: + [str] List of symbol names. + """ + with open(filename, 'r') as f: + return [line.strip() for line in f.readlines()] + + +def WriteReachedData(filename, page_to_reached_data): + """Writes the page to reached fraction to a JSON file. + + The output format is suited for visualize.html. + + Args: + filename: (str) Output filename. + page_to_reached_data: (dict) As returned by CodePagesToReachedSize(). + """ + json_object = [] + for (offset, data) in page_to_reached_data.items(): + json_object.append({'offset': offset, 'total': data['total'], + 'reached': data['reached']}) + with open(filename, 'w') as f: + json.dump(json_object, f) + + +def CodePagesToReachedSize(reached_symbol_names, page_to_symbols): + """From page offset -> [all_symbols], return the reached portion per page. + + Args: + reached_symbol_names: ([str]) List of reached symbol names. + page_to_symbols: (dict) As returned by CodePagesToMangledSymbols(). + + Returns: + {page offset (int) -> {'total': int, 'reached': int}} + """ + reached_symbol_names = set(reached_symbol_names) + page_to_reached = {} + for offset in page_to_symbols: + total_size = sum(x[1] for x in page_to_symbols[offset]) + reached_size = sum( + size_in_page for (name, size_in_page) in page_to_symbols[offset] + if name in reached_symbol_names) + page_to_reached[offset] = {'total': total_size, 'reached': reached_size} + return page_to_reached + + +def CodePagesToObjectFiles(symbols_to_object_files, code_pages_to_symbols): + """From symbols in object files and symbols in pages, gives code page to + object files. + + Args: + symbols_to_object_files: (dict) as returned by GetSymbolNameToFilename() + code_pages_to_symbols: (dict) as returned by CodePagesToMangledSymbols() + + Returns: + {page_offset: {object_filename: size_in_page}} + """ + result = {} + unmatched_symbols_count = 0 + for page_address in code_pages_to_symbols: + result[page_address] = {} + for name, size_in_page in code_pages_to_symbols[page_address]: + if name not in symbols_to_object_files: + unmatched_symbols_count += 1 + continue + object_filename = symbols_to_object_files[name][1] + if object_filename not in result[page_address]: + result[page_address][object_filename] = 0 + result[page_address][object_filename] += size_in_page + logging.warning('%d unmatched symbols.', unmatched_symbols_count) + return result + + +def WriteCodePageAttribution(page_to_object_files, text_filename, + json_filename): + """Writes the code page -> file mapping in text and JSON format. + + Args: + page_to_object_files: As returned by CodePagesToObjectFiles(). + text_filename: (str) Text output filename. + json_filename: (str) JSON output filename. + """ + json_data = [] + with open(text_filename, 'w') as f: + for page_offset in sorted(page_to_object_files.keys()): + size_and_filenames = [(kv[1], kv[0]) + for kv in page_to_object_files[page_offset].items()] + size_and_filenames.sort(reverse=True) + total_size = sum(x[0] for x in size_and_filenames) + json_data.append({'offset': page_offset, 'accounted_for': total_size, + 'size_and_filenames': size_and_filenames}) + f.write('Page Offset: %d * 4k (accounted for: %d)\n' % ( + page_offset / (1 << 12), total_size)) + for size, filename in size_and_filenames: + f.write(' %d\t%s\n' % (size, filename)) + with open(json_filename, 'w') as f: + json.dump(json_data, f) + + +def CreateArgumentParser(): + """Creates and returns the argument parser.""" + parser = argparse.ArgumentParser(description='Map code pages to paths') + parser.add_argument('--native-library', type=str, default='libchrome.so', + help=('Native Library, e.g. libchrome.so or ' + 'libmonochrome.so')) + parser.add_argument('--reached-symbols-file', type=str, + help='Path to the list of reached symbols, as generated ' + 'by tools/cygprofile/process_profiles.py', + required=False) + parser.add_argument('--residency', type=str, + help='Path to a JSON file with residency data, as written' + ' by process_resdency.py', required=False) + parser.add_argument('--build-directory', type=str, help='Build directory', + required=True) + parser.add_argument('--output-directory', type=str, help='Output directory', + required=True) + parser.add_argument('--arch', type=str, help='Architecture', default='arm') + parser.add_argument('--start-server', action='store_true', default=False, + help='Run an HTTP server in the output directory') + parser.add_argument('--port', type=int, default=8000, + help='Port to use for the HTTP server.') + return parser + + +def main(): + parser = CreateArgumentParser() + args = parser.parse_args() + logging.basicConfig(level=logging.INFO) + + symbol_extractor.SetArchitecture(args.arch) + logging.info('Parsing object files in %s', args.build_directory) + object_files_symbols = GetSymbolNameToFilename(args.build_directory) + native_lib_filename = os.path.join( + args.build_directory, 'lib.unstripped', args.native_library) + if not os.path.exists(native_lib_filename): + logging.error('Native library not found. Did you build the APK?') + return 1 + + offset = 0 + if args.residency: + with open(args.residency) as f: + residency = json.load(f) + offset = residency['offset'] + + logging.info('Extracting symbols from %s', native_lib_filename) + native_lib_symbols = symbol_extractor.SymbolInfosFromBinary( + native_lib_filename) + logging.info('Mapping symbols and object files to code pages') + page_to_symbols = CodePagesToMangledSymbols(native_lib_symbols, offset) + page_to_object_files = CodePagesToObjectFiles(object_files_symbols, + page_to_symbols) + + + if args.reached_symbols_file: + logging.info('Mapping reached symbols to code pages') + reached_symbol_names = ReadReachedSymbols(args.reached_symbols_file) + reached_data = CodePagesToReachedSize(reached_symbol_names, page_to_symbols) + WriteReachedData(os.path.join(args.output_directory, 'reached.json'), + reached_data) + + if not os.path.exists(args.output_directory): + os.makedirs(args.output_directory) + text_output_filename = os.path.join(args.output_directory, 'map.txt') + json_output_filename = os.path.join(args.output_directory, 'map.json') + WriteCodePageAttribution( + page_to_object_files, text_output_filename, json_output_filename) + directory = os.path.dirname(__file__) + + for filename in ['visualize.html', 'visualize.js', 'visualize.css']: + if args.residency: + shutil.copy(args.residency, + os.path.join(args.output_directory, 'residency.json')) + shutil.copy(os.path.join(directory, filename), + os.path.join(args.output_directory, filename)) + + if args.start_server: + os.chdir(args.output_directory) + httpd = SocketServer.TCPServer( + ('', args.port), SimpleHTTPServer.SimpleHTTPRequestHandler) + logging.warning('Serving on port %d', args.port) + httpd.serve_forever() + + return 0 + + +if __name__ == '__main__': + sys.exit(main())
diff --git a/tools/android/native_lib_memory/process_residency.py b/tools/android/native_lib_memory/process_residency.py new file mode 100755 index 0000000..51d3d81 --- /dev/null +++ b/tools/android/native_lib_memory/process_residency.py
@@ -0,0 +1,131 @@ +#!/usr/bin/python +# Copyright 2017 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. + +"""From a native code residency dump created by log_residency.cc, generate a +visual timeline, and serialize the parsed data to JSON. +""" + +import argparse +import json +import logging +from matplotlib import collections as mc +from matplotlib import pylab as plt +import numpy as np + + +def CreateArgumentParser(): + """Creates and returns an argument parser.""" + parser = argparse.ArgumentParser( + description='Reads and shows native library residency data.') + parser.add_argument('--dump', type=str, required=True, help='Residency dump') + parser.add_argument('--output', type=str, required=True, + help='Output filename in text format') + parser.add_argument('--json', type=str, help='Output filename in JSON output') + return parser + + +def ParseDump(filename): + """Parses a residency dump, as generated from lightweight_cygprofile.cc. + + Args: + filename: (str) dump filename. + + Returns: + {"start": offset, "end": offset, + "residency": {timestamp (int): data ([bool])}} + """ + result = {} + with open(filename, 'r') as f: + (start, end) = f.readline().strip().split(' ') + result = {'start': int(start), 'end': int(end), 'residency': {}} + for line in f: + line = line.strip() + timestamp, data = line.split(' ') + data_array = [x == '1' for x in data] + result['residency'][int(timestamp)] = data_array + return result + + +def WriteJsonOutput(data, filename): + """Serializes the parsed data to JSON. + + Args: + data: (dict) As returned by ParseDump() + filename: (str) output filename. + + JSON format: + {'offset': int, 'data': { + relative_timestamp: [{'page_offset': int, 'resident': bool}]}} + + Where: + - offset is the code start offset into its page + - relative_timestamp is the offset in ns since the first measurement + - page_offset is the page offset in bytes + """ + result = {'offset': data['start'], 'data': {}} + start_timestamp = min(data['residency'].keys()) + for timestamp in data['residency']: + adjusted_timestamp = timestamp - start_timestamp + result[adjusted_timestamp] = [] + residency = data['residency'][timestamp] + for (index, resident) in enumerate(residency): + result[adjusted_timestamp].append( + {'offset': index * (1 << 12), 'resident': resident}) + with open(filename, 'w') as f: + json.dump(result, f) + + +def PlotResidency(data, output_filename): + """Creates a graph of residency. + + Args: + data: (dict) As returned by ParseDump(). + output_filename: (str) Output filename. + """ + residency = data['residency'] + max_percentage = max((100. * sum(d)) / len(d) for d in residency.values()) + logging.info('Max residency = %.2f%%', max_percentage) + + start = data['start'] + end = data['end'] + fig, ax = plt.subplots(figsize=(20, 10)) + timestamps = sorted(residency.keys()) + x_max = len(residency.values()[0]) * 4096 + for t in timestamps: + offset_ms = (t - timestamps[0]) / 1e6 + incore = [i * 4096 for (i, x) in enumerate(residency[t]) if x] + outcore = [i * 4096 for (i, x) in enumerate(residency[t]) if not x] + percentage = 100. * len(incore) / (len(incore) + len(outcore)) + plt.text(x_max, offset_ms, '%.1f%%' % percentage) + for (d, color) in ((incore, (.2, .6, .05, 1)), (outcore, (1, 0, 0, 1))): + segments = [[(x, offset_ms), (x + 4096, offset_ms)] for x in d] + colors = np.array([color] * len(segments)) + lc = mc.LineCollection(segments, colors=colors, linewidths=8) + ax.add_collection(lc) + + plt.axvline(start) + plt.axvline(end) + plt.title('Code residency vs time since startup.') + plt.xlabel('Code page offset (bytes)') + plt.ylabel('Time since startup (ms)') + plt.ylim(0, ymax=(timestamps[-1] - timestamps[0]) / 1e6) + plt.xlim(xmin=0, xmax=x_max) + plt.savefig(output_filename, bbox_inches='tight', dpi=300) + + +def main(): + parser = CreateArgumentParser() + args = parser.parse_args() + logging.basicConfig(level=logging.INFO) + logging.info('Parsing the data') + data = ParseDump(args.dump) + if args.json: + WriteJsonOutput(data, args.json) + logging.info('Plotting the results') + PlotResidency(data, args.output) + + +if __name__ == '__main__': + main()
diff --git a/tools/android/native_lib_memory/visualize.css b/tools/android/native_lib_memory/visualize.css new file mode 100644 index 0000000..d66a8880 --- /dev/null +++ b/tools/android/native_lib_memory/visualize.css
@@ -0,0 +1,50 @@ +/* Copyright 2017 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. + */ + +html, html * { + font-family: "Roboto", sans-serif; +} + +.chart { + shape-rendering: crispEdges; +} +.mini text { + font: 9px sans-serif; +} +.main text { + font: 12px sans-serif; +} +.miniItem { + stroke-width: 6; +} +.mainItem { + stroke-width: 6; +} +.brush .extent { + stroke: gray; + fill: dodgerblue; + fill-opacity: .365; +} +.legend { + position: fixed; + bottom: 0; + color: #ffffff; + background-color: rgba(0, 0, 0, .8); + border-radius: 25px; + padding: 20px; + display: none; +} +.colors-legend { + border: solid; + position: fixed; + bottom: 0; + right: 0; + border-radius: 25px; + padding: 20px; +} +.legend-rectangle { + width: 2em; + height: 1em; +}
diff --git a/tools/android/native_lib_memory/visualize.html b/tools/android/native_lib_memory/visualize.html new file mode 100644 index 0000000..012d800 --- /dev/null +++ b/tools/android/native_lib_memory/visualize.html
@@ -0,0 +1,28 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<html> + <head> + <link rel="stylesheet" type="text/css" href="visualize.css"> + </head> + <body> + <center> + <h1>Code Pages to component</h1> + </center> + <div id="legend" class="legend"> + <div id="legend-title"></div> + <p/> + <table id="legend-table"></table> + </div> + <div class="colors-legend"> + <b>Components and colors</b> + <table id="colors-legend-table"></table> + </div> + <script src="https://d3js.org/d3.v3.min.js"></script> + <script src="visualize.js"></script> + <script type="text/javascript"> + fetchAllAndCreateGraph( + ["map.json", "reached.json", "residency.json"]); + buildColorLegend(); + </script> + </body> +</html>
diff --git a/tools/android/native_lib_memory/visualize.js b/tools/android/native_lib_memory/visualize.js new file mode 100644 index 0000000..d4beeee --- /dev/null +++ b/tools/android/native_lib_memory/visualize.js
@@ -0,0 +1,381 @@ +// Copyright 2017 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. + +/** + * Fetches all the urls, and calls {@link createGraph} with the JSON contents. + */ +function fetchAllAndCreateGraph(urls) { + Promise.all( + urls.map(url => fetch(url) + .then(response => response.ok ? response.json() : undefined))) + .then(jsonContents => createGraph.apply(this, jsonContents)); +} + +const CODE_PAGE = "code_page"; +const REACHED_PAGE = "reached_page"; +const RESIDENCY = "residency"; + +/** + * @return {string} the fill color for a given page slice. + */ +function getFillColor(d) { + switch (d.type) { + case CODE_PAGE: + return pageFillColor(d.data); + case REACHED_PAGE: + return reachedPageFillColor(d.data); + case RESIDENCY: + return residencyPageFillColor(d.data); + } +} + +// Prefixes, color, description. +const colors = d3.scale.category20(); +let colorIndex = 1; +const COLOR_MAPPING = [ + [["third_party/WebKit"], colors(colorIndex++), "Blink"], + [["v8"], colors(colorIndex++), "V8"], + [["base"], colors(colorIndex++), "//base"], + [["content"], colors(colorIndex++), "//content"], + [["components"], colors(colorIndex++), "//components"], + [["chrome/android"], colors(colorIndex++), "//chrome/android"], + [["chrome"], colors(colorIndex++), "//chrome"], + [["net", "third_party/boringssl"], colors(colorIndex++), "Net"], + [["third_party/webrtc", "third_party/opus", "third_party/usrsctp"], + colors(colorIndex++), "WebRTC"], + [["third_party/ffmpeg", "third_party/libvpx"], colors(colorIndex++), "Media"], + [["third_party/icu"], colors(colorIndex++), "ICU"], + [["skia"], colors(colorIndex++), "Skia"], + [["ui"], colors(colorIndex++), "UI"], + [["cc"], colors(colorIndex++), "CC"]]; + +/** + * @return the fill color for an item representing a code page. + */ +function pageFillColor(page) { + const sizeAndFilename = page.size_and_filenames[0]; + if (!sizeAndFilename) return "lightgrey"; + + const dominantFilename = sizeAndFilename[1]; + for (let i = 0; i < COLOR_MAPPING.length; i++) { + const prefixes = COLOR_MAPPING[i][0]; + const color = COLOR_MAPPING[i][1]; + for (let j = 0; j < prefixes.length; j++) { + if (dominantFilename.startsWith(prefixes[j])) return color; + } + } + return "darkgrey"; +} + +const reachedColorScale = d3.scale.linear() + .domain([0, 100]) + .range(["black", "green"]); +/** + * @return the fill color for an item reprensting reached data. + */ +function reachedPageFillColor(page) { + if (page.total == 0) return "white"; + if (page.reached == 0) return "red"; + const percentage = 100 * page.reached / page.total; + return reachedColorScale(percentage); +} + +function residencyPageFillColor(page) { + return page.resident ? "green" : "red"; +} + +/** + * Adds the color legend to the document. + */ +function buildColorLegend() { + let table = document.getElementById("colors-legend-table"); + for (let i = 0; i < COLOR_MAPPING.length; i++) { + let color = COLOR_MAPPING[i][1]; + let name = COLOR_MAPPING[i][2]; + let row = document.createElement("tr"); + row.setAttribute("align", "left"); + let colorRectangle = document.createElement("td"); + colorRectangle.setAttribute("class", "legend-rectangle"); + colorRectangle.setAttribute("style", `background-color: ${color}`); + let label = document.createElement("td"); + label.innerHTML = name; + row.appendChild(colorRectangle); + row.appendChild(label); + table.appendChild(row); + } +} + +/** + * Updates the legend. + * + * @param offset Offset of the item to label in the legend. + * @param offsetToData {offset: data} map. + */ +function updateLegend(offset, offsetToData) { + let data = offsetToData[offset]; + if (!data) return; + + let page = data[CODE_PAGE]; + let reached = data[REACHED_PAGE]; + + let legend = document.getElementById("legend"); + legend.style.display = "block"; + + let title = document.getElementById("legend-title"); + let sizeAndFilename = page.size_and_filenames[0]; + let filename = ""; + if (sizeAndFilename) filename = sizeAndFilename[1]; + + let reachedSize = reached ? reached.reached : 0; + let reachedPercentage = reachedSize ? 100 * reachedSize / reached.total : 0; + title.innerHTML = ` + <b>Page offset:</b> ${page.offset} + <br/> + <b>Accounted for:</b> ${page.accounted_for} + <br/> + <b>Reached: </b> ${reachedSize} (${reachedPercentage.toFixed(2)}%) + <br/> + <b>Dominant filename:</b> ${filename}`; + + let table = document.getElementById("legend-table"); + table.innerHTML = ""; + let header = document.createElement("tr"); + header.setAttribute("align", "left"); + header.innerHTML = "<th>Size</th><th>Filename</th>"; + table.appendChild(header); + for (let i = 0; i < page.size_and_filenames.length; i++) { + let row = document.createElement("tr"); + row.setAttribute("align", "left"); + row.innerHTML = `<td>${page.size_and_filenames[i][0]}</td> + <td>${page.size_and_filenames[i][1]}</td>`; + table.appendChild(row); + } +} + + +/** + * @return {int} the lane index for a given data item. + */ +function typeToLane(d) { + switch (d.type) { + case CODE_PAGE: + return 0; + case REACHED_PAGE: + return 1; + case RESIDENCY: + return 2; + } +} + +/** + * Returns: offset -> {"code_page": codeData, "reached": reachedData} + */ +function getOffsetToData(flatData) { + let result = []; + for (let i = 0; i < flatData.length; i++) { + let data = flatData[i].data; + let type = flatData[i].type; + let offset = data["offset"]; + if (!result[offset]) result[offset] = {}; + result[offset][type] = data; + } + return result; +} + +/** + * Creates the graph, and adds it to the DOM. + * + * reachedData can be undefined. In this case, only the code page data is shown. + * + * @param codePages data relative to code pages and their content. + * @param reachedData data relative to which fraction of code pages is reached. + */ +function createGraph(codePages, reachedPerPage, residency) { + const PAGE_SIZE = 4096; + + let offsets = codePages.map((x) => x.offset).sort((a, b) => a - b); + let minOffset = +offsets[0]; + let maxOffset = +offsets[offsets.length - 1] + PAGE_SIZE; + + const labels = ["Component", "Reached", "Residency"]; + const lanes = labels.length; + // [{type: REACHED_PAGE | CODE_PAGE | RESIDENCY, data: pageData}] + let flatData = codePages.map((page) => ({"type": CODE_PAGE, "data": page})); + if (reachedPerPage) { + let typedReachedPerPage = reachedPerPage.map( + (page) => ({"type": REACHED_PAGE, "data": page})); + flatData = flatData.concat(typedReachedPerPage); + } + + if (residency) { + let timestamps = Object.keys( + residency).map((x) => +x).sort((a, b) => a - b); + let lastTimestamp = +timestamps[timestamps.length - 1]; + let residencyData = residency[lastTimestamp]; + // Other offsets are relative to start of the native library. + let typedResidencyData = residencyData.map( + (page) => ( + {"type": RESIDENCY, "data": {"offset": page.offset + minOffset, + "resident": page.resident}})); + flatData = flatData.concat(typedResidencyData); + } + + const offsetToData = getOffsetToData(flatData); + + let margins = [20, 15, 15, 120] // top right bottom left + let width = window.innerWidth - margins[1] - margins[3] + let height = 500 - margins[0] - margins[2] + let miniHeight = lanes * 12 + 50 + let mainHeight = height - miniHeight - 50 + + let globalXScale = d3.scale.linear().domain([minOffset, maxOffset]) + .range([0, width]); + const globalScalePageWidth = globalXScale(PAGE_SIZE) - globalXScale(0); + + let zoomedXScale = d3.scale.linear().domain([minOffset, maxOffset]) + .range([0, width]); + + let mainYScale = d3.scale.linear().domain([0, lanes]).range([0, mainHeight]); + let miniYScale = d3.scale.linear().domain([0, lanes]).range([0, miniHeight]); + + let drag = d3.behavior.drag().on("drag", dragmove); + + let chart = d3.select("body") + .append("svg") + .attr("width", width + margins[1] + margins[3]) + .attr("height", height + margins[0] + margins[2]) + .attr("class", "chart"); + + chart.append("defs").append("clipPath") + .attr("id", "clip") + .append("rect") + .attr("width", width) + .attr("height", mainHeight); + + let main = chart.append("g") + .attr("transform", `translate(${margins[3]}, ${margins[0]})`) + .attr("width", width) + .attr("height", mainHeight) + .attr("class", "main"); + + let mini = chart.append("g") + .attr("transform", `translate(${margins[3]}, ${mainHeight + margins[0]})`) + .attr("width", width) + .attr("height", miniHeight) + .attr("class", "mini"); + + let miniAxisScale = d3.scale.linear() + .domain([0, (maxOffset - minOffset) / 1e6]) + .range([0, width]); + let miniAxis = d3.svg.axis().scale(miniAxisScale).orient("bottom"); + let miniXAxis = mini.append("g") + .attr("transform", `translate(0, ${miniHeight})`) + .call(miniAxis); + + let mainAxisScale = d3.scale.linear() + .domain([0, (maxOffset - minOffset) / 1e6]) + .range([0, width]); + let mainAxis = d3.svg.axis().scale(mainAxisScale).orient("bottom"); + let mainXAxis = main.append("g") + .attr("class", "x axis") + .attr("transform", `translate(0, -10)`) + .call(mainAxis); + + main.append("g").selectAll(".laneLines") + .data(labels) + .enter().append("line") + .attr("x1", margins[1]) + .attr("y1", (d, i) => mainYScale(i)) + .attr("x2", width) + .attr("y2", (d, i) => mainYScale(i)) + .attr("stroke", "lightgray"); + + main.append("g").selectAll(".laneText") + .data(labels) + .enter().append("text") + .text((d) => d) + .attr("x", -margins[1]) + .attr("y", (d, i) => mainYScale(i + .5)) + .attr("dy", ".5ex") + .attr("text-anchor", "end") + .attr("class", "laneText"); + + let itemRects = main.append("g") + .attr("clip-path", "url(#clip)"); + + mini.append("g").selectAll(".laneLines") + .data(labels) + .enter().append("line") + .attr("x1", margins[1]) + .attr("y1", (d, i) => miniYScale(i)) + .attr("x2", width) + .attr("y2", (d, i) => miniYScale(i)) + .attr("stroke", "lightgray"); + + mini.append("g").selectAll(".laneText") + .data(labels) + .enter().append("text") + .text((d) => d) + .attr("x", -margins[1]) + .attr("y", (d, i) => miniYScale(i + .5)) + .attr("dy", ".5ex") + .attr("text-anchor", "end"); + + mini.append("g").selectAll("miniItems") + .data(flatData) + .enter().append("rect") + .attr("class", (d) => "miniItem") + .attr("x", (d) => globalXScale(d.data.offset)) + .attr("y", (d) => miniYScale(typeToLane(d) + .5) - 5) + .attr("width", (d) => globalScalePageWidth) + .attr("height", 10) + .style("fill", getFillColor); + + let brush = d3.svg.brush().x(globalXScale).on("brush", display); + mini.append("g") + .attr("class", "x brush") + .call(brush) + .selectAll("rect") + .attr("y", 1) + .attr("height", miniHeight - 1); + + display(); + + function display() { + let rects, labels, + minExtent = brush.extent()[0]; + maxExtent = brush.extent()[1]; + visibleItems = flatData.filter((d) => d.data.offset < maxExtent && + d.data.offset + PAGE_SIZE > minExtent); + + mini.select(".brush").call(brush.extent([minExtent, maxExtent])); + zoomedXScale.domain([minExtent, maxExtent]); + + mainAxisScale.domain([(minExtent - minOffset) / 1e6, + (maxExtent - minOffset) / 1e6]); + chart.selectAll(".axis").call(mainAxis); + + // Update the main rects. + const zoomedXScalePageWidth = zoomedXScale(PAGE_SIZE) - zoomedXScale(0); + rects = itemRects.selectAll("rect") + .data(visibleItems, (d) => d.data.offset + d.type) + .attr("x", (d) => zoomedXScale(d.data.offset)) + .attr("width", (d) => zoomedXScalePageWidth); + + rects.enter().append("rect") + .attr("class", (d) => "mainItem") + .attr("x", (d) => zoomedXScale(d.data.offset)) + .attr("y", (d) => mainYScale(typeToLane(d)) + 10) + .attr("width", (d) => zoomedXScalePageWidth) + .attr("height", (d) => .8 * mainYScale(1)) + .style("fill", getFillColor) + .on("mouseover", (d) => updateLegend(d.data.offset, offsetToData)); + + rects.exit().remove(); + } + + function dragmove(d) { + d3.select(this).attr("x", d.x = Math.max(0, d3.event.x)); + } +}
diff --git a/tools/android/purge_ashmem/BUILD.gn b/tools/android/purge_ashmem/BUILD.gn deleted file mode 100644 index e717fb13..0000000 --- a/tools/android/purge_ashmem/BUILD.gn +++ /dev/null
@@ -1,12 +0,0 @@ -# Copyright 2015 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. - -executable("purge_ashmem") { - sources = [ - "purge_ashmem.c", - ] - deps = [ - "//third_party/ashmem", - ] -}
diff --git a/tools/android/purge_ashmem/purge_ashmem.c b/tools/android/purge_ashmem/purge_ashmem.c deleted file mode 100644 index 0de582de..0000000 --- a/tools/android/purge_ashmem/purge_ashmem.c +++ /dev/null
@@ -1,20 +0,0 @@ -// 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 <stdio.h> -#include <stdlib.h> -#include <unistd.h> - -#include "third_party/ashmem/ashmem.h" - -int main(void) { - const int pages_purged = ashmem_purge_all(); - if (pages_purged < 0) { - perror("ashmem_purge_all"); - return EXIT_FAILURE; - } - printf("Purged %d pages (%d KBytes)\n", - pages_purged, pages_purged * getpagesize() / 1024); - return EXIT_SUCCESS; -}
diff --git a/tools/android/roll/update_support_library.py b/tools/android/roll/update_support_library.py index b81ad107..07c42f2 100755 --- a/tools/android/roll/update_support_library.py +++ b/tools/android/roll/update_support_library.py
@@ -4,63 +4,71 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -""" +''' Updates the Android support repository (m2repository). -""" +''' import argparse -import fnmatch import os -import subprocess -import shutil +import logging import sys -DIR_SOURCE_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), - '..', '..', '..')) -ANDROID_SDK_PATH = os.path.abspath(os.path.join(DIR_SOURCE_ROOT, 'third_party', - 'android_tools', 'sdk')) -TARGET_NAME = 'extra-android-m2repository' -# The first version we included was 23.2.1. Any folders that are older than -# that should not be included by Chrome's git repo. Unstable versions should -# also be excluded. -REMOVE_LIST = ['databinding', '13.*', '18.*', '19.*', '20.*', '21.*', '22.*', - '23.0.*', '23.1.*', '23.2.0', '*-alpha*', '*-beta*'] +_SRC_DIR = os.path.abspath(os.path.join( + os.path.dirname(__file__), '..', '..', '..')) +sys.path.append(os.path.join(_SRC_DIR, 'build', 'android')) + +from pylib.constants import host_paths +from pylib.utils import logging_utils +from pylib.utils import maven_downloader + +SUPPORT_LIB_REPO = os.path.join(host_paths.DIR_SOURCE_ROOT, 'third_party', + 'android_tools', 'sdk', 'extras', 'android', + 'm2repository') def main(): parser = argparse.ArgumentParser(description='Updates the Android support ' 'repository in third_party/android_tools') - parser.add_argument('--sdk-dir', - help='Directory for the Android SDK.') + parser.add_argument('--target-repo', + help='Maven repo where the library will be installed.', + default=SUPPORT_LIB_REPO) + parser.add_argument('--debug', + help='Debug mode, synchronous and with extra logging.', + action='store_true') args = parser.parse_args() - sdk_path = ANDROID_SDK_PATH - if args.sdk_dir is not None: - sdk_path = os.path.abspath(os.path.join(DIR_SOURCE_ROOT, args.sdk_dir)) + if (args.debug): + logging.basicConfig(level=logging.DEBUG) + else: + logging.basicConfig(level=logging.INFO) + logging_utils.ColorStreamHandler.MakeDefault() - sdk_tool = os.path.abspath(os.path.join(sdk_path, 'tools', 'android')) - if not os.path.exists(sdk_tool): - print 'SDK tool not found at %s' % sdk_tool - return 1 - - # Run the android sdk update tool in command line. - subprocess.check_call([sdk_tool, 'update', 'sdk' , '--no-ui', - '--filter', TARGET_NAME]) - - m2repo = os.path.abspath(os.path.join(sdk_path, 'extras', 'android', - 'm2repository')) - # Remove obsolete folders and unused folders according to REMOVE_LIST. - count = 0 - for folder, _, _ in os.walk(m2repo): - for pattern in REMOVE_LIST: - if fnmatch.fnmatch(os.path.basename(folder), pattern): - count += 1 - print 'Removing %s' % os.path.relpath(folder, sdk_path) - shutil.rmtree(folder) - if count == 0: - print ('No files were removed from the updated support library. ' - 'Did you update it successfully?') - return 1 + maven_downloader.MavenDownloader(args.debug).Install(args.target_repo, [ + 'android.arch.core:common:1.0.0:jar', + 'android.arch.lifecycle:common:1.0.0:jar', + 'android.arch.lifecycle:runtime:1.0.0:aar', + 'com.android.support:animated-vector-drawable:27.0.0:aar', + 'com.android.support:appcompat-v7:27.0.0:aar', + 'com.android.support:cardview-v7:27.0.0:aar', + 'com.android.support:design:27.0.0:aar', + 'com.android.support:gridlayout-v7:27.0.0:aar', + 'com.android.support:leanback-v17:27.0.0:aar', + 'com.android.support:mediarouter-v7:27.0.0:aar', + 'com.android.support:palette-v7:27.0.0:aar', + 'com.android.support:preference-leanback-v17:27.0.0:aar', + 'com.android.support:preference-v14:27.0.0:aar', + 'com.android.support:preference-v7:27.0.0:aar', + 'com.android.support:recyclerview-v7:27.0.0:aar', + 'com.android.support:support-annotations:27.0.0:jar', + 'com.android.support:support-compat:27.0.0:aar', + 'com.android.support:support-core-ui:27.0.0:aar', + 'com.android.support:support-core-utils:27.0.0:aar', + 'com.android.support:support-fragment:27.0.0:aar', + 'com.android.support:support-media-compat:27.0.0:aar', + 'com.android.support:support-v13:27.0.0:aar', + 'com.android.support:support-vector-drawable:27.0.0:aar', + 'com.android.support:transition:27.0.0:aar', + ], include_poms=True) if __name__ == '__main__':
diff --git a/tools/android/sdk_updater/update_sdk.py b/tools/android/sdk_updater/update_sdk.py new file mode 100755 index 0000000..7fad775 --- /dev/null +++ b/tools/android/sdk_updater/update_sdk.py
@@ -0,0 +1,361 @@ +#!/usr/bin/env python +# +# Copyright 2017 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. + +"""This script downloads / packages & uploads Android SDK packages. + + It could be run when we need to update sdk packages to latest version. + It has 2 usages: + 1) download: downloading a new version of the SDK via sdkmanager + 2) package: wrapping SDK directory into CIPD-compatible packages and + uploading the new packages via CIPD to server. + Providing '--dry-run' option to show what packages to be + created and uploaded without actually doing either. + + Both downloading and uploading allows to either specify a package, or + deal with default packages (build-tools, platform-tools, platforms and + tools). + + Example usage: + 1) updating default packages: + $ update_sdk.py download + (optional) $ update_sdk.py package --dry-run + $ update_sdk.py package + 2) updating a specified package: + $ update_sdk.py download -p "build-tools;27.0.3" + (optional) $ update_sdk.py package --dry-run -p build-tools \ + --version 27.0.3 + $ update_sdk.py package -p build-tools --version 27.0.3 + + Note that `package` could update the package argument to the checkout + version in .gn file //build/config/android/config.gni. If having git + changes, please prepare to upload a CL that updates the SDK version. +""" + +import argparse +import os +import re +import shutil +import subprocess +import sys +import tempfile + + +_SRC_ROOT = os.path.realpath( + os.path.join(os.path.dirname(__file__), '..', '..', '..')) + +_SDK_ROOT = os.path.join(_SRC_ROOT, 'third_party', 'android_sdk', 'public') + +# TODO(shenghuazhang): Update sdkmanager path when gclient can download SDK +# via CIPD: crug/789809 +_SDKMANAGER_PATH = os.path.join(_SRC_ROOT, 'third_party', 'android_tools', + 'sdk', 'tools', 'bin', 'sdkmanager') + +_ANDROID_CONFIG_GNI_PATH = os.path.join(_SRC_ROOT, 'build', 'config', + 'android', 'config.gni') + +_TOOLS_LIB_PATH = os.path.join(_SDK_ROOT, 'tools', 'lib') + +_DEFAULT_DOWNLOAD_PACKAGES = [ + 'build-tools', + 'platform-tools', + 'platforms', + 'tools' +] + +_DEFAULT_PACKAGES_DICT = { + 'build-tools': 'build-tools;27.0.3', + 'platforms': 'platforms;android-27', + 'sources': 'sources;android-26', +} + +_GN_ARGUMENTS_TO_UPDATE = { + 'build-tools': 'default_android_sdk_build_tools_version', + 'tools': 'default_android_sdk_tools_version_suffix', + 'platforms': 'default_android_sdk_version', +} + +_COMMON_JAR_SUFFIX_PATTERN= re.compile( + r'^common' # file name begins with 'common' + r'(-[\d\.]+(-dev)?)' # group of suffix e.g.'-26.0.0-dev', '-25.3.2' + r'\.jar$' # ends with .jar +) + + +def _DownloadSdk(arguments): + """Download sdk package from sdkmanager. + + If package isn't provided, update build-tools, platform-tools, platforms, + and tools. + """ + for pkg in arguments.packages: + # If package is not a sdk-style path, try to match a default path to it. + if pkg in _DEFAULT_PACKAGES_DICT: + print 'Coercing %s to %s' % (pkg, _DEFAULT_PACKAGES_DICT[pkg]) + pkg = _DEFAULT_PACKAGES_DICT[pkg] + + download_sdk_cmd = [ + _SDKMANAGER_PATH, + '--install', + '--sdk_root=%s' % arguments.sdk_root, + pkg + ] + if arguments.verbose: + download_sdk_cmd.append('--verbose') + + subprocess.check_call(download_sdk_cmd) + + +def _FindPackageVersion(package): + """Find sdk package version + + Two options for package version: + 1) Use the version in name if package name contains ';version' + 2) For simple name package, search its version from 'Installed packages' + via `sdkmanager --list` + """ + sdkmanager_list_cmd = [ + _SDKMANAGER_PATH, + '--list' + ] + if package in _DEFAULT_PACKAGES_DICT: + # Get the version after ';' from package name + package = _DEFAULT_PACKAGES_DICT[package] + return package.split(';')[1] + else: + # Get the package version via `sdkmanager --list`. The logic is: + # Check through 'Installed packages' which is at the first section of + # `sdkmanager --list` output, example: + # Installed packages:=====================] 100% Computing updates... + # Path | Version | Description + # ------- | ------- | ------- + # build-tools;27.0.3 | 27.0.3 | Android SDK Build-Tools 27.0.3 + # emulator | 26.0.3 | Android Emulator + # platforms;android-27 | 1 | Android SDK Platform 27 + # tools | 26.1.1 | Android SDK Tools + # + # Available Packages: + # .... + # When found a line containing the package path, grap its version between + # the first and second '|'. Since the 'Installed packages' list section ends + # by the first new line, the check loop should be ended when reaches a '\n'. + output = subprocess.check_output(sdkmanager_list_cmd) + for line in output.splitlines(): + if package in line: + # if found package path, catch its version which in the first '|...|' + return line.split('|')[1].strip() + if line == '\n': # Reaches the end of 'Installed packages' list + break + raise Exception('Cannot find the version of package %s' % package) + + +def _ReplaceVersionInFile(file_path, pattern, version, dry_run=False): + """Replace the version of sdk package argument in file. + + Check whether the version in file is the same as the new version first. + Replace the version if not dry run. + + Args: + file_path: Path to the file to update the version of sdk package argument. + pattern: Pattern for the sdk package argument. Must capture at least one + group that the first group is the argument line excluding version. + version: The new version of the package. + dry_run: Bool. To show what packages would be created and packages, without + actually doing either. + """ + try: + with tempfile.NamedTemporaryFile(delete=False) as temp_file: + with open(file_path) as f: + for line in f: + new_line = re.sub(pattern, r'\g<1>"%s"\n' % version, line) + if new_line != line: + print ' Note: file %s argument %s would be updated to "%s".' % ( + file_path, line.strip(), version) + temp_file.write(new_line) + if not dry_run: + shutil.move(temp_file.name, file_path) + + finally: + if os.path.exists(temp_file.name): + os.remove(temp_file.name) + + +def UploadSdkPackage(sdk_root, dry_run, service_url, package, yaml_file, + pkg_version, verbose): + """Build and upload a package instance file to CIPD. + + This would also update gn and ensure files to the package version as + uploading to CIPD. + + Args: + sdk_root: Root of the sdk packages. + dry_run: Bool. To show what packages would be created and packages, without + actually doing either. + service_url: The url of the CIPD service. + package: The package to be uploaded to CIPD. + yaml_file: Path to the yaml file that defines what to put into the package. + Default as //third_pary/android_sdk/public/cipd_*.yaml + pkg_version: The version of the package instance. + verbose: Enable more logging. + """ + pkg_yaml_file = yaml_file or os.path.join(sdk_root, 'cipd_%s.yaml' % package) + if not os.path.exists(pkg_yaml_file): + raise IOError('Cannot find .yaml file for package %s' % package) + + if dry_run: + print 'This `package` command (without -n/--dry-run) would create and', + print 'upload the package %s version:%s to CIPD.' % (package, pkg_version) + else: + upload_sdk_cmd = [ + 'cipd', 'create', + '-pkg-def', pkg_yaml_file, + '-tag', 'version:%s' % pkg_version, + '-service-url', service_url + ] + + if verbose: + upload_sdk_cmd.extend(['-log-level', 'debug']) + + subprocess.check_call(upload_sdk_cmd) + + +def ChangeVersionInGNI(package, arg_version, gn_args_dict, gni_file_path, + dry_run): + """Change the sdk package version in config.gni file.""" + if package in gn_args_dict: + version_config_name = gn_args_dict.get(package) + # Regex to parse the line of sdk package version gn argument, e.g. + # ' default_android_sdk_version = "27"'. Capture a group for the line + # excluding the version. + gn_arg_pattern = re.compile( + # Match the argument with '=' and whitespaces. Capture a group for it. + r'(^\s*%s\s*=\s*)' % version_config_name + + # version number with double quote. E.g. "27", "27.0.3", "-26.0.0-dev" + r'([-\w\s."]+)' + # End of string + r'$' + ) + + _ReplaceVersionInFile(gni_file_path, gn_arg_pattern, arg_version, dry_run) + + +def GetToolsSuffix(tools_lib_path): + """Get the gn config of package 'tools' suffix. + + Check jar file name of 'common*.jar' in tools/lib, which could be + 'common.jar', common-<version>-dev.jar' or 'common-<version>.jar'. + If suffix exists, return the suffix. + """ + tools_lib_jars_list = os.listdir(tools_lib_path) + for file_name in tools_lib_jars_list: + found = re.match(_COMMON_JAR_SUFFIX_PATTERN, file_name) + if found: + return found.group(1) + + +def _GetArgVersion(pkg_version, package): + # Remove all chars except for digits and dots in version + arg_version = re.sub(r'[^\d\.]','', pkg_version) + + if package == 'tools': + suffix = GetToolsSuffix(_TOOLS_LIB_PATH) + if suffix: + arg_version = suffix + else: + arg_version = '-%s' % arg_version + return arg_version + + +def _UploadSdkPackage(arguments): + packages = arguments.package + if not packages: + packages = _DEFAULT_DOWNLOAD_PACKAGES + if arguments.version or arguments.yaml_file: + raise IOError("Don't use --version/--yaml-file for default packages.") + + for package in packages: + pkg_version = arguments.version + if not pkg_version: + pkg_version = _FindPackageVersion(package) + UploadSdkPackage(arguments.sdk_root, arguments.dry_run, + arguments.service_url, package, arguments.yaml_file, + pkg_version, arguments.verbose) + + if package in _GN_ARGUMENTS_TO_UPDATE: + arg_version = _GetArgVersion(pkg_version, package) + ChangeVersionInGNI(package, pkg_version, _GN_ARGUMENTS_TO_UPDATE, + _ANDROID_CONFIG_GNI_PATH, arguments.dry_run) + + +def main(): + parser = argparse.ArgumentParser( + description='A script to download Android SDK packages via sdkmanager ' + + 'and upload to CIPD.') + + subparsers = parser.add_subparsers(title='commands') + + download_parser = subparsers.add_parser( + 'download', + help='Download sdk package to the latest version from sdkmanager.') + download_parser.set_defaults(func=_DownloadSdk) + download_parser.add_argument( + '-p', + '--packages', + nargs='+', + default=_DEFAULT_DOWNLOAD_PACKAGES, + help='The packages of the SDK needs to be installed/updated. ' + + 'Note that package name should be a sdk-style path e.g. ' + + '"platforms;android-27" or "platform-tools". If package ' + + 'is not specified, update "build-tools;27.0.3", "tools" ' + + '"platform-tools" and "platforms;android-27" by default.') + download_parser.add_argument('--sdk-root', + default=_SDK_ROOT, + help='base path to the Android SDK root') + download_parser.add_argument('-v', '--verbose', + action='store_true', + help='print debug information') + + package_parser = subparsers.add_parser( + 'package', help='Create and upload package instance file to CIPD.') + package_parser.set_defaults(func=_UploadSdkPackage) + package_parser.add_argument( + '-n', + '--dry-run', + action='store_true', + help='Dry run won\'t trigger creating instances or uploading packages. ' + + 'It shows what packages would be created and uploaded to CIPD. ' + + 'It also shows the possible updates of sdk version on files.') + package_parser.add_argument( + '-p', + '--package', + nargs=1, + help='The package to be uploaded to CIPD. Note that package ' + + 'name is a simple path e.g. "platforms" or "build-tools" ' + + 'which matches package name on CIPD service. Default by ' + + 'build-tools, platform-tools, platforms and tools') + package_parser.add_argument( + '--version', + help='Version of the uploading package instance through CIPD.') + package_parser.add_argument( + '--yaml-file', + help='Path to *.yaml file that defines what to put into the package.' + + 'Default as //third_pary/android_sdk/public/cipd_<package>.yaml') + package_parser.add_argument('--service-url', + help='The url of the CIPD service.', + default='https://chrome-infra-packages.appspot.com') + package_parser.add_argument('--sdk-root', + default=_SDK_ROOT, + help='base path to the Android SDK root') + package_parser.add_argument('-v', '--verbose', + action='store_true', + help='print debug information') + + args = parser.parse_args() + + args.func(args) + + +if __name__ == '__main__': + sys.exit(main())
diff --git a/tools/battor_agent/battor_agent.cc b/tools/battor_agent/battor_agent.cc index 7c126f94..231581b 100644 --- a/tools/battor_agent/battor_agent.cc +++ b/tools/battor_agent/battor_agent.cc
@@ -8,10 +8,12 @@ #include <vector> #include "base/bind.h" +#include "base/strings/stringprintf.h" #include "base/threading/sequenced_task_runner_handle.h" #include "tools/battor_agent/battor_connection_impl.h" #include "tools/battor_agent/battor_sample_converter.h" +using base::StringPrintf; using std::vector; namespace battor { @@ -65,46 +67,9 @@ memcpy(eeprom.get(), msg.data(), sizeof(BattOrEEPROM)); return eeprom; } - -// Returns true if the specified vector of bytes decodes to a valid BattOr -// samples frame. The frame header and samples are returned via the frame_header -// and samples paramaters. -bool ParseSampleFrame(BattOrMessageType type, - const vector<char>& msg, - uint32_t expected_sequence_number, - BattOrFrameHeader* frame_header, - vector<RawBattOrSample>* samples) { - if (type != BATTOR_MESSAGE_TYPE_SAMPLES) - return false; - - // Each frame should contain a header and an integer number of BattOr samples. - if ((msg.size() - sizeof(BattOrFrameHeader)) % sizeof(RawBattOrSample) != 0) - return false; - - // The first bytes in the frame contain the frame header. - const char* frame_ptr = reinterpret_cast<const char*>(msg.data()); - memcpy(frame_header, frame_ptr, sizeof(BattOrFrameHeader)); - frame_ptr += sizeof(BattOrFrameHeader); - - if (frame_header->sequence_number != expected_sequence_number) { - LOG(WARNING) << "Unexpected sequence number: wanted " - << expected_sequence_number << ", but got " - << frame_header->sequence_number << "."; - return false; - } - - size_t remaining_bytes = msg.size() - sizeof(BattOrFrameHeader); - if (remaining_bytes != frame_header->length) - return false; - - samples->resize(remaining_bytes / sizeof(RawBattOrSample)); - memcpy(samples->data(), frame_ptr, remaining_bytes); - - return true; -} } // namespace -BattOrResults::BattOrResults() {} +BattOrResults::BattOrResults() = default; BattOrResults::BattOrResults(std::string details, std::vector<float> power_samples_W, @@ -115,7 +80,7 @@ BattOrResults::BattOrResults(const BattOrResults&) = default; -BattOrResults::~BattOrResults() {} +BattOrResults::~BattOrResults() = default; BattOrAgent::BattOrAgent( const std::string& path, @@ -139,6 +104,8 @@ void BattOrAgent::StartTracing() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + connection_->LogSerial("Starting command StartTracing."); + // When tracing is restarted, all previous clock sync markers are invalid. clock_sync_markers_.clear(); last_clock_sync_time_ = base::TimeTicks(); @@ -150,6 +117,8 @@ void BattOrAgent::StopTracing() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + connection_->LogSerial("Starting command StopTracing."); + command_ = Command::STOP_TRACING; PerformAction(Action::REQUEST_CONNECTION); } @@ -157,6 +126,8 @@ void BattOrAgent::RecordClockSyncMarker(const std::string& marker) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + connection_->LogSerial("Starting command RecordClockSyncMarker."); + command_ = Command::RECORD_CLOCK_SYNC_MARKER; pending_clock_sync_marker_ = marker; PerformAction(Action::REQUEST_CONNECTION); @@ -165,6 +136,8 @@ void BattOrAgent::GetFirmwareGitHash() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + connection_->LogSerial("Starting command GetFirmwareGitHash."); + command_ = Command::GET_FIRMWARE_GIT_HASH; PerformAction(Action::REQUEST_CONNECTION); } @@ -181,22 +154,36 @@ return; } - switch (command_) { - case Command::START_TRACING: - PerformAction(Action::SEND_INIT); - return; - case Command::STOP_TRACING: - PerformAction(Action::SEND_EEPROM_REQUEST); - return; - case Command::RECORD_CLOCK_SYNC_MARKER: - PerformAction(Action::SEND_CURRENT_SAMPLE_REQUEST); - return; - case Command::GET_FIRMWARE_GIT_HASH: - PerformAction(Action::SEND_GIT_HASH_REQUEST); - return; - case Command::INVALID: - NOTREACHED(); - return; + PerformAction(Action::POST_CONNECT_FLUSH); +} + +void BattOrAgent::OnConnectionFlushed(bool success) { + if (!success) { + CompleteCommand(BATTOR_ERROR_CONNECTION_FAILED); + return; + } + + // Flush after opening connection. + if (last_action_ == Action::POST_CONNECT_FLUSH) { + switch (command_) { + case Command::START_TRACING: + PerformAction(Action::SEND_INIT); + return; + case Command::STOP_TRACING: + PerformAction(Action::SEND_EEPROM_REQUEST); + return; + case Command::RECORD_CLOCK_SYNC_MARKER: + PerformAction(Action::SEND_CURRENT_SAMPLE_REQUEST); + return; + case Command::GET_FIRMWARE_GIT_HASH: + PerformAction(Action::SEND_GIT_HASH_REQUEST); + return; + case Command::INVALID: + NOTREACHED(); + return; + } + } else { + NOTREACHED(); } } @@ -239,6 +226,8 @@ void BattOrAgent::OnMessageRead(bool success, BattOrMessageType type, std::unique_ptr<vector<char>> bytes) { + timeout_callback_.Cancel(); + if (!success) { switch (last_action_) { case Action::READ_GIT_HASH: @@ -261,9 +250,6 @@ } } - // Successfully read a message, cancel any timeouts. - timeout_callback_.Cancel(); - switch (last_action_) { case Action::READ_INIT_ACK: if (!IsAckOfControlCommand(type, BATTOR_CONTROL_MESSAGE_TYPE_INIT, @@ -351,8 +337,6 @@ // Check for the empty frame the BattOr uses to indicate it's done // streaming samples. if (frame.empty()) { - // Cancel the next data frame timeout. - timeout_callback_.Cancel(); CompleteCommand(BATTOR_ERROR_NONE); return; } @@ -402,6 +386,9 @@ case Action::REQUEST_CONNECTION: BeginConnect(); return; + case Action::POST_CONNECT_FLUSH: + connection_->Flush(); + return; // The following actions are required for StartTracing: case Action::SEND_INIT: SendControlMessage(BATTOR_CONTROL_MESSAGE_TYPE_INIT, 0, 0); @@ -448,6 +435,7 @@ // Clear stored samples from prior attempts to read sample frames. samples_.clear(); calibration_frame_.clear(); + FALLTHROUGH; case Action::READ_DATA_FRAME: // The first frame sent back from the BattOr contains voltage and current // data that excludes whatever device is being measured from the @@ -469,8 +457,8 @@ return; case Action::SEND_GIT_HASH_REQUEST: - SendControlMessage( - BATTOR_CONTROL_MESSAGE_TYPE_GET_FIRMWARE_GIT_HASH, 0, 0); + SendControlMessage(BATTOR_CONTROL_MESSAGE_TYPE_GET_FIRMWARE_GIT_HASH, 0, + 0); return; case Action::READ_GIT_HASH: @@ -518,12 +506,72 @@ connection_->SendBytes(BATTOR_MESSAGE_TYPE_CONTROL, &msg, sizeof(msg)); } +// Returns true if the specified vector of bytes decodes to a valid BattOr +// samples frame. The frame header and samples are returned via the frame_header +// and samples paramaters. +bool BattOrAgent::ParseSampleFrame(BattOrMessageType type, + const vector<char>& msg, + uint32_t expected_sequence_number, + BattOrFrameHeader* frame_header, + vector<RawBattOrSample>* samples) { + if (type != BATTOR_MESSAGE_TYPE_SAMPLES) { + connection_->LogSerial( + StringPrintf("ParseSampleFrame failed due to unexpected message type " + "number (wanted BATTOR_MESSAGE_TYPE_SAMPLES, but got %d).", + type)); + return false; + } + + // Each frame should contain a header and an integer number of BattOr samples. + if ((msg.size() - sizeof(BattOrFrameHeader)) % sizeof(RawBattOrSample) != 0) { + connection_->LogSerial( + "ParseSampleFrame failed due to containing a noninteger number of " + "BattOr samples."); + return false; + } + + // The first bytes in the frame contain the frame header. + const char* frame_ptr = reinterpret_cast<const char*>(msg.data()); + memcpy(frame_header, frame_ptr, sizeof(BattOrFrameHeader)); + frame_ptr += sizeof(BattOrFrameHeader); + + if (frame_header->sequence_number != expected_sequence_number) { + connection_->LogSerial( + StringPrintf("ParseSampleFrame failed due to unexpected sequence " + "number (wanted %d, but got %d).", + expected_sequence_number, frame_header->sequence_number)); + return false; + } + + size_t remaining_bytes = msg.size() - sizeof(BattOrFrameHeader); + if (remaining_bytes != frame_header->length) { + connection_->LogSerial(StringPrintf( + "ParseSampleFrame failed due to to a mismatch between the length of " + "the frame as stated in the frame header and the actual length of the " + "frame (frame header %d, actual length %zu).", + frame_header->length, remaining_bytes)); + return false; + } + + samples->resize(remaining_bytes / sizeof(RawBattOrSample)); + memcpy(samples->data(), frame_ptr, remaining_bytes); + + return true; +} + void BattOrAgent::RetryCommand() { if (++num_command_attempts_ >= kMaxCommandAttempts) { + connection_->LogSerial(StringPrintf( + "Exhausted retry attempts (would have been attempt %d of %d).", + num_command_attempts_ + 1, kMaxCommandAttempts)); CompleteCommand(BATTOR_ERROR_TOO_MANY_COMMAND_RETRIES); return; } + connection_->LogSerial(StringPrintf("Retrying command (attempt %d of %d).", + num_command_attempts_ + 1, + kMaxCommandAttempts)); + // Restart the serial connection to guarantee that the connection gets flushed // before retrying the command. connection_->Close(); @@ -550,6 +598,9 @@ } void BattOrAgent::CompleteCommand(BattOrError error) { + connection_->LogSerial( + StringPrintf("Completing command with error code: %d.", error)); + switch (command_) { case Command::START_TRACING: base::SequencedTaskRunnerHandle::Get()->PostTask( @@ -625,6 +676,17 @@ trace_stream << std::endl; } + for (auto it = clock_sync_markers_.begin(); it != clock_sync_markers_.end(); + ++it) { + size_t total_sample_count = calibration_frame_.size() + samples_.size(); + if (it->first >= total_sample_count) { + connection_->LogSerial(StringPrintf( + "Clock sync occurred at a sample not included in the result (clock " + "sync sample index: %d, total sample count: %zu).", + it->first, total_sample_count)); + } + } + // Convert to a vector of power in watts. std::vector<float> samples(samples_.size()); for (size_t i = 0; i < samples_.size(); i++)
diff --git a/tools/battor_agent/battor_agent.h b/tools/battor_agent/battor_agent.h index f0179be3..809d264 100644 --- a/tools/battor_agent/battor_agent.h +++ b/tools/battor_agent/battor_agent.h
@@ -90,6 +90,7 @@ // BattOrConnection::Listener implementation. void OnConnectionOpened(bool success) override; + void OnConnectionFlushed(bool success) override; void OnBytesSent(bool success) override; void OnMessageRead(bool success, BattOrMessageType type, @@ -124,6 +125,7 @@ // Actions required to connect to a BattOr. REQUEST_CONNECTION, + POST_CONNECT_FLUSH, // Actions required for starting tracing. SEND_INIT, @@ -162,6 +164,12 @@ uint16_t param1, uint16_t param2); + bool ParseSampleFrame(BattOrMessageType type, + const std::vector<char>& msg, + uint32_t expected_sequence_number, + BattOrFrameHeader* frame_header, + std::vector<RawBattOrSample>* samples); + // Retry the last command. void RetryCommand();
diff --git a/tools/battor_agent/battor_agent_unittest.cc b/tools/battor_agent/battor_agent_unittest.cc index 978de54..e07af5d3 100644 --- a/tools/battor_agent/battor_agent_unittest.cc +++ b/tools/battor_agent/battor_agent_unittest.cc
@@ -60,9 +60,10 @@ public: MockBattOrConnection(BattOrConnection::Listener* listener) : BattOrConnection(listener) {} - ~MockBattOrConnection() override {} + ~MockBattOrConnection() override = default; MOCK_METHOD0(Open, void()); + MOCK_METHOD0(Flush, void()); MOCK_METHOD0(Close, void()); MOCK_METHOD3(SendBytes, void(BattOrMessageType type, @@ -70,7 +71,7 @@ size_t bytes_to_send)); MOCK_METHOD1(ReadMessage, void(BattOrMessageType type)); MOCK_METHOD0(CancelReadMessage, void()); - MOCK_METHOD0(Flush, void()); + MOCK_METHOD1(LogSerial, void(const std::string& str)); private: DISALLOW_COPY_AND_ASSIGN(MockBattOrConnection); @@ -149,6 +150,10 @@ command_error_ = BATTOR_ERROR_NONE; } + void AdvanceTickClock(base::TimeDelta delta) { + task_runner_->FastForwardBy(delta); + } + // Possible states that the BattOrAgent can be in. enum class BattOrAgentState { // States required to connect to a BattOr. @@ -186,6 +191,9 @@ GetAgent()->OnConnectionOpened(true); GetTaskRunner()->RunUntilIdle(); + GetAgent()->OnConnectionFlushed(true); + GetTaskRunner()->RunUntilIdle(); + if (end_state == BattOrAgentState::CONNECTED) return; @@ -227,6 +235,9 @@ GetAgent()->OnConnectionOpened(true); GetTaskRunner()->RunUntilIdle(); + GetAgent()->OnConnectionFlushed(true); + GetTaskRunner()->RunUntilIdle(); + if (end_state == BattOrAgentState::CONNECTED) return; @@ -275,6 +286,9 @@ GetAgent()->OnConnectionOpened(true); GetTaskRunner()->RunUntilIdle(); + GetAgent()->OnConnectionFlushed(true); + GetTaskRunner()->RunUntilIdle(); + if (end_state == BattOrAgentState::CONNECTED) return; @@ -297,6 +311,9 @@ GetAgent()->OnConnectionOpened(true); GetTaskRunner()->RunUntilIdle(); + GetAgent()->OnConnectionFlushed(true); + GetTaskRunner()->RunUntilIdle(); + if (end_state == BattOrAgentState::CONNECTED) return; @@ -339,6 +356,8 @@ testing::InSequence s; EXPECT_CALL(*GetAgent()->GetConnection(), Open()); + EXPECT_CALL(*GetAgent()->GetConnection(), Flush()); + BattOrControlMessage init_msg{BATTOR_CONTROL_MESSAGE_TYPE_INIT, 0, 0}; EXPECT_CALL( *GetAgent()->GetConnection(), @@ -529,10 +548,12 @@ TEST_F(BattOrAgentTest, StartTracingFailsAfterTooManyCumulativeFailures) { GetAgent()->StartTracing(); + RunStartTracingTo(BattOrAgentState::SET_GAIN_SENT); for (int i = 0; i < 9; i++) { - RunStartTracingTo(BattOrAgentState::SET_GAIN_SENT); OnMessageRead(false, BATTOR_MESSAGE_TYPE_CONTROL_ACK, nullptr); + AdvanceTickClock(base::TimeDelta::FromSeconds(2)); + RunStartTracingTo(BattOrAgentState::SET_GAIN_SENT); EXPECT_FALSE(IsCommandComplete()); } @@ -562,6 +583,8 @@ testing::InSequence s; EXPECT_CALL(*GetAgent()->GetConnection(), Open()); + EXPECT_CALL(*GetAgent()->GetConnection(), Flush()); + BattOrControlMessage request_eeprom_msg{ BATTOR_CONTROL_MESSAGE_TYPE_READ_EEPROM, sizeof(BattOrEEPROM), 0}; EXPECT_CALL( @@ -688,10 +711,10 @@ GetAgent()->StopTracing(); RunStopTracingTo(BattOrAgentState::SAMPLES_REQUEST_SENT); + // Make a read fail in order to make sure that the agent will retry. OnMessageRead(false, BATTOR_MESSAGE_TYPE_SAMPLES, nullptr); - - RunStopTracingTo(BattOrAgentState::SAMPLES_REQUEST_SENT); + AdvanceTickClock(base::TimeDelta::FromSeconds(2)); EXPECT_FALSE(IsCommandComplete()); @@ -708,6 +731,7 @@ // Make a read fail in order to make sure that the agent will retry. OnMessageRead(false, BATTOR_MESSAGE_TYPE_SAMPLES, nullptr); + AdvanceTickClock(base::TimeDelta::FromSeconds(2)); EXPECT_FALSE(IsCommandComplete()); @@ -723,6 +747,7 @@ for (int i = 0; i < 9; i++) { RunStopTracingTo(BattOrAgentState::SAMPLES_REQUEST_SENT); OnMessageRead(false, BATTOR_MESSAGE_TYPE_SAMPLES, nullptr); + AdvanceTickClock(base::TimeDelta::FromSeconds(2)); EXPECT_FALSE(IsCommandComplete()); } @@ -740,6 +765,7 @@ for (int i = 0; i < 9; i++) { RunStopTracingTo(BattOrAgentState::CALIBRATION_FRAME_RECEIVED); OnMessageRead(false, BATTOR_MESSAGE_TYPE_SAMPLES, nullptr); + AdvanceTickClock(base::TimeDelta::FromSeconds(2)); EXPECT_FALSE(IsCommandComplete()); } @@ -759,6 +785,7 @@ RunStopTracingTo(BattOrAgentState::CALIBRATION_FRAME_RECEIVED); OnMessageRead(false, BATTOR_MESSAGE_TYPE_SAMPLES, nullptr); + AdvanceTickClock(base::TimeDelta::FromSeconds(2)); EXPECT_FALSE(IsCommandComplete()); @@ -766,6 +793,7 @@ OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES, CreateFrame(frame_header, frame, 1)); OnMessageRead(false, BATTOR_MESSAGE_TYPE_SAMPLES, nullptr); + AdvanceTickClock(base::TimeDelta::FromSeconds(2)); EXPECT_FALSE(IsCommandComplete()); @@ -780,6 +808,7 @@ RunStopTracingTo(BattOrAgentState::SAMPLES_REQUEST_SENT); OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK, ToCharVector(kInitAck)); + AdvanceTickClock(base::TimeDelta::FromSeconds(2)); EXPECT_FALSE(IsCommandComplete()); @@ -802,6 +831,7 @@ RunStopTracingTo(BattOrAgentState::SAMPLES_REQUEST_SENT); OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES, CreateFrame(cal_frame_header, cal_frame, 2)); + AdvanceTickClock(base::TimeDelta::FromSeconds(2)); EXPECT_FALSE(IsCommandComplete()); @@ -822,6 +852,7 @@ RunStopTracingTo(BattOrAgentState::CALIBRATION_FRAME_RECEIVED); OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES, CreateFrame(frame_header, frame, 1)); + AdvanceTickClock(base::TimeDelta::FromSeconds(2)); EXPECT_FALSE(IsCommandComplete()); @@ -846,6 +877,7 @@ RunStopTracingTo(BattOrAgentState::SAMPLES_REQUEST_SENT); OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES, std::move(cal_frame_bytes)); + AdvanceTickClock(base::TimeDelta::FromSeconds(2)); EXPECT_FALSE(IsCommandComplete()); @@ -868,6 +900,7 @@ RunStopTracingTo(BattOrAgentState::CALIBRATION_FRAME_RECEIVED); OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES, std::move(frame_bytes)); + AdvanceTickClock(base::TimeDelta::FromSeconds(2)); EXPECT_FALSE(IsCommandComplete()); @@ -894,6 +927,7 @@ CreateFrame(frame_header1, frame1, 1)); OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES, CreateFrame(frame_header3, frame3, 1)); + AdvanceTickClock(base::TimeDelta::FromSeconds(2)); EXPECT_FALSE(IsCommandComplete()); @@ -910,6 +944,8 @@ EXPECT_CALL(*GetAgent()->GetConnection(), Close()); OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK, ToCharVector(kInitAck)); + AdvanceTickClock(base::TimeDelta::FromSeconds(2)); + RunStopTracingTo(BattOrAgentState::SAMPLES_END_FRAME_RECEIVED); EXPECT_TRUE(IsCommandComplete());
diff --git a/tools/battor_agent/battor_connection.cc b/tools/battor_agent/battor_connection.cc index b999100..e6befa1 100644 --- a/tools/battor_agent/battor_connection.cc +++ b/tools/battor_agent/battor_connection.cc
@@ -13,6 +13,6 @@ namespace battor { BattOrConnection::BattOrConnection(Listener* listener) : listener_(listener) {} -BattOrConnection::~BattOrConnection() {} +BattOrConnection::~BattOrConnection() = default; } // namespace battor
diff --git a/tools/battor_agent/battor_connection.h b/tools/battor_agent/battor_connection.h index 7583693..fefcc332 100644 --- a/tools/battor_agent/battor_connection.h +++ b/tools/battor_agent/battor_connection.h
@@ -33,6 +33,7 @@ class Listener { public: virtual void OnConnectionOpened(bool success) = 0; + virtual void OnConnectionFlushed(bool success) = 0; virtual void OnBytesSent(bool success) = 0; virtual void OnMessageRead(bool success, BattOrMessageType type, @@ -53,6 +54,9 @@ virtual void Open() = 0; // Closes the serial connection and releases any handles being held. virtual void Close() = 0; + // Flushes the serial connection by reading and throwing away bytes until the + // serial connection remains quiet for a sufficiently long time. + virtual void Flush() = 0; // Sends the specified buffer over the serial connection and calls the // listener's OnBytesSent() when complete. Note that bytes_to_send should not @@ -70,6 +74,9 @@ // Cancels the current message read operation. virtual void CancelReadMessage() = 0; + // Appends |str| to the serial log file if it exists. + virtual void LogSerial(const std::string& str) = 0; + protected: // The listener receiving the results of the commands being executed. Listener* listener_;
diff --git a/tools/battor_agent/battor_connection_impl.cc b/tools/battor_agent/battor_connection_impl.cc index efda2e1..b0fab10f 100644 --- a/tools/battor_agent/battor_connection_impl.cc +++ b/tools/battor_agent/battor_connection_impl.cc
@@ -85,7 +85,7 @@ tick_clock_ = std::make_unique<base::DefaultTickClock>(); } -BattOrConnectionImpl::~BattOrConnectionImpl() {} +BattOrConnectionImpl::~BattOrConnectionImpl() = default; void BattOrConnectionImpl::Open() { if (io_handler_) { @@ -128,7 +128,9 @@ return; } - Flush(); + base::SequencedTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(&Listener::OnConnectionOpened, + base::Unretained(listener_), true)); } void BattOrConnectionImpl::Close() { @@ -151,9 +153,9 @@ for (size_t i = 0; i < bytes_to_send; i++) { if (bytes[i] == BATTOR_CONTROL_BYTE_START || - bytes[i] == BATTOR_CONTROL_BYTE_END) { + bytes[i] == BATTOR_CONTROL_BYTE_END || + bytes[i] == BATTOR_CONTROL_BYTE_ESCAPE) data.push_back(BATTOR_CONTROL_BYTE_ESCAPE); - } data.push_back(bytes[i]); } @@ -214,8 +216,7 @@ LogSerial(StringPrintf("(message) Starting read of up to %zu bytes.", max_bytes_to_read)); - pending_read_buffer_ = - make_scoped_refptr(new net::IOBuffer(max_bytes_to_read)); + pending_read_buffer_ = base::MakeRefCounted<net::IOBuffer>(max_bytes_to_read); io_handler_->Read(base::MakeUnique<device::ReceiveBuffer>( pending_read_buffer_, static_cast<uint32_t>(max_bytes_to_read), @@ -318,8 +319,7 @@ StringPrintf("(flush) Starting read (quiet period has lasted %f ms).", quiet_period_duration.InMillisecondsF())); - pending_read_buffer_ = - make_scoped_refptr(new net::IOBuffer(kFlushBufferSize)); + pending_read_buffer_ = base::MakeRefCounted<net::IOBuffer>(kFlushBufferSize); io_handler_->Read(base::MakeUnique<device::ReceiveBuffer>( pending_read_buffer_, static_cast<uint32_t>(kFlushBufferSize), @@ -347,7 +347,7 @@ static_cast<int>(error))); pending_read_buffer_ = nullptr; base::SequencedTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(&Listener::OnConnectionOpened, + FROM_HERE, base::Bind(&Listener::OnConnectionFlushed, base::Unretained(listener_), false)); return; } @@ -363,7 +363,7 @@ LogSerial("(flush) Quiet period has finished."); pending_read_buffer_ = nullptr; base::SequencedTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(&Listener::OnConnectionOpened, + FROM_HERE, base::Bind(&Listener::OnConnectionFlushed, base::Unretained(listener_), true)); return; }
diff --git a/tools/battor_agent/battor_connection_impl.h b/tools/battor_agent/battor_connection_impl.h index 3e1cf40..3ac3559 100644 --- a/tools/battor_agent/battor_connection_impl.h +++ b/tools/battor_agent/battor_connection_impl.h
@@ -48,6 +48,13 @@ size_t bytes_to_send) override; void ReadMessage(BattOrMessageType type) override; void CancelReadMessage() override; + void LogSerial(const std::string& str) override; + + // Flushes the serial connection to the BattOr, reading and throwing away + // bytes from the serial connection until the connection is quiet for a + // sufficiently long time. This also discards any trailing bytes from past + // successful reads. + void Flush() override; protected: // Overridden by the test to use a fake serial connection. @@ -74,12 +81,6 @@ BattOrMessageType type, std::unique_ptr<std::vector<char>> data); - // Flushes the serial connection to the BattOr, reading and throwing away - // bytes from the serial connection until the connection is quiet for a - // sufficiently long time. This also discards any trailing bytes from past - // successful reads. - void Flush(); - void BeginReadBytesForFlush(); void OnBytesReadForFlush(int bytes_read, device::mojom::SerialReceiveError error); @@ -102,9 +103,6 @@ // Internal callback for when bytes are sent. void OnBytesSent(int bytes_sent, device::mojom::SerialSendError error); - // Appends |str| to the serial log file if it exists. - void LogSerial(const std::string& str); - // The path of the BattOr. std::string path_;
diff --git a/tools/battor_agent/battor_connection_impl_unittest.cc b/tools/battor_agent/battor_connection_impl_unittest.cc index 98de9ee..bc1bab4 100644 --- a/tools/battor_agent/battor_connection_impl_unittest.cc +++ b/tools/battor_agent/battor_connection_impl_unittest.cc
@@ -57,6 +57,10 @@ is_open_complete_ = true; open_success_ = success; }; + void OnConnectionFlushed(bool success) override { + is_flush_complete_ = true; + flush_success_ = success; + }; void OnBytesSent(bool success) override { send_success_ = success; } void OnMessageRead(bool success, BattOrMessageType type, @@ -80,6 +84,12 @@ task_runner_->RunUntilIdle(); } + void FlushConnection() { + is_flush_complete_ = false; + connection_->Flush(); + task_runner_->RunUntilIdle(); + } + void CloseConnection() { connection_->Close(); } void ReadMessage(BattOrMessageType type) { @@ -127,7 +137,9 @@ } bool GetOpenSuccess() { return open_success_; } + bool GetFlushSuccess() { return flush_success_; } bool IsOpenComplete() { return is_open_complete_; } + bool IsFlushComplete() { return is_flush_complete_; } bool GetSendSuccess() { return send_success_; } bool IsReadComplete() { return is_read_complete_; } bool GetReadSuccess() { return read_success_; } @@ -142,7 +154,10 @@ // Result from the last connect command. bool open_success_; + // Results from the last flush command. + bool flush_success_; bool is_open_complete_; + bool is_flush_complete_; // Result from the last send command. bool send_success_; // Results from the last read command. @@ -152,48 +167,30 @@ std::unique_ptr<std::vector<char>> read_bytes_; }; -TEST_F(BattOrConnectionImplTest, OpenConnectionSucceedsAfterTimeout) { - OpenConnection(); - ASSERT_FALSE(IsOpenComplete()); - - AdvanceTickClock(base::TimeDelta::FromMilliseconds(50)); - - ASSERT_TRUE(IsOpenComplete()); - ASSERT_TRUE(GetOpenSuccess()); -} - -TEST_F(BattOrConnectionImplTest, OpenConnectionSucceedsImmediatelyIfOpen) { - OpenConnection(); - ASSERT_FALSE(IsOpenComplete()); - - AdvanceTickClock(base::TimeDelta::FromMilliseconds(50)); - +TEST_F(BattOrConnectionImplTest, OpenConnectionSucceedsImmediately) { OpenConnection(); ASSERT_TRUE(IsOpenComplete()); ASSERT_TRUE(GetOpenSuccess()); } -TEST_F(BattOrConnectionImplTest, OpenConnectionFlushesIfAlreadyOpen) { +TEST_F(BattOrConnectionImplTest, FlushConnectionSucceedsOnlyAfterTimeout) { OpenConnection(); + ASSERT_TRUE(IsOpenComplete()); + ASSERT_TRUE(GetOpenSuccess()); + + FlushConnection(); + ASSERT_FALSE(IsFlushComplete()); + AdvanceTickClock(base::TimeDelta::FromMilliseconds(50)); - SendControlMessage(BATTOR_CONTROL_MESSAGE_TYPE_RESET, 4, 7); - - CloseConnection(); - OpenConnection(); - AdvanceTickClock(base::TimeDelta::FromMilliseconds(50)); - - ReadMessage(BATTOR_MESSAGE_TYPE_CONTROL); - - // Opening the connection the second time should have cleared all bytes that - // were already on the wire, including the reset control message. This read - // will hang until more bytes are sent. - ASSERT_FALSE(IsReadComplete()); + ASSERT_TRUE(IsFlushComplete()); + ASSERT_TRUE(GetFlushSuccess()); } -TEST_F(BattOrConnectionImplTest, OpenConnectionFlushesAlreadyReadBuffer) { +TEST_F(BattOrConnectionImplTest, FlushConnectionFlushesAlreadyReadBuffer) { OpenConnection(); - AdvanceTickClock(base::TimeDelta::FromMilliseconds(50)); + ASSERT_TRUE(IsOpenComplete()); + ASSERT_TRUE(GetOpenSuccess()); // Send two data frames and only read one of them. When reading data frames, // we try to read a large chunk from the wire due to the large potential size @@ -220,11 +217,12 @@ CloseConnection(); OpenConnection(); - AdvanceTickClock(base::TimeDelta::FromMilliseconds(50)); - ASSERT_TRUE(IsOpenComplete()); ASSERT_TRUE(GetOpenSuccess()); + FlushConnection(); + AdvanceTickClock(base::TimeDelta::FromMilliseconds(50)); + ReadMessage(BATTOR_MESSAGE_TYPE_SAMPLES); // The read should be incomplete due to no data being on the wire - the second @@ -232,32 +230,41 @@ ASSERT_FALSE(IsReadComplete()); } -TEST_F(BattOrConnectionImplTest, OpenConnectionNewBytesRestartQuietPeriod) { +TEST_F(BattOrConnectionImplTest, FlushConnectionNewBytesRestartQuietPeriod) { OpenConnection(); + ASSERT_TRUE(IsOpenComplete()); + ASSERT_TRUE(GetOpenSuccess()); + + FlushConnection(); AdvanceTickClock(base::TimeDelta::FromMilliseconds(49)); SendControlMessage(BATTOR_CONTROL_MESSAGE_TYPE_RESET, 4, 7); AdvanceTickClock(base::TimeDelta::FromMilliseconds(49)); // The connection should not yet be opened because we received new bytes at // t=49ms, and at t=98ms the new 50ms quiet period hasn't yet elapsed. - ASSERT_FALSE(IsOpenComplete()); + ASSERT_FALSE(IsFlushComplete()); AdvanceTickClock(base::TimeDelta::FromMilliseconds(1)); - ASSERT_TRUE(IsOpenComplete()); + ASSERT_TRUE(IsFlushComplete()); } TEST_F(BattOrConnectionImplTest, - OpenConnectionFlushesBytesReceivedInQuietPeriod) { + FlushConnectionFlushesBytesReceivedInQuietPeriod) { OpenConnection(); - SendControlMessage(BATTOR_CONTROL_MESSAGE_TYPE_RESET, 4, 7); - AdvanceTickClock(base::TimeDelta::FromMilliseconds(5)); - SendControlMessage(BATTOR_CONTROL_MESSAGE_TYPE_RESET, 4, 7); - AdvanceTickClock(base::TimeDelta::FromMilliseconds(50)); - ASSERT_TRUE(IsOpenComplete()); ASSERT_TRUE(GetOpenSuccess()); + FlushConnection(); + SendControlMessage(BATTOR_CONTROL_MESSAGE_TYPE_RESET, 4, 7); + AdvanceTickClock(base::TimeDelta::FromMilliseconds(5)); + ASSERT_FALSE(IsFlushComplete()); + + SendControlMessage(BATTOR_CONTROL_MESSAGE_TYPE_RESET, 4, 7); + AdvanceTickClock(base::TimeDelta::FromMilliseconds(50)); + ASSERT_TRUE(IsFlushComplete()); + ASSERT_TRUE(GetFlushSuccess()); + ReadMessage(BATTOR_MESSAGE_TYPE_CONTROL); // The read should hang because the control message that arrived mid quiet @@ -265,9 +272,10 @@ ASSERT_FALSE(IsReadComplete()); } -TEST_F(BattOrConnectionImplTest, OpenConnectionFlushesMultipleReadsOfData) { +TEST_F(BattOrConnectionImplTest, FlushConnectionFlushesMultipleReadsOfData) { OpenConnection(); - AdvanceTickClock(base::TimeDelta::FromMilliseconds(50)); + ASSERT_TRUE(IsOpenComplete()); + ASSERT_TRUE(GetOpenSuccess()); // Send 10 full flush buffers worth of data. char data[50000]; @@ -276,13 +284,9 @@ for (int i = 0; i < 10; i++) SendBytesRaw(data, 50000); - CloseConnection(); - OpenConnection(); + FlushConnection(); AdvanceTickClock(base::TimeDelta::FromMilliseconds(50)); - ASSERT_TRUE(IsOpenComplete()); - ASSERT_TRUE(GetOpenSuccess()); - SendControlMessage(BATTOR_CONTROL_MESSAGE_TYPE_RESET, 4, 7); ReadMessage(BATTOR_MESSAGE_TYPE_CONTROL); @@ -293,21 +297,118 @@ ASSERT_TRUE(GetReadSuccess()); } -TEST_F(BattOrConnectionImplTest, OpenConnectionIncompleteBeforeTimeout) { +TEST_F(BattOrConnectionImplTest, FlushIncompleteBeforeTimeout) { OpenConnection(); + ASSERT_TRUE(IsOpenComplete()); + ASSERT_TRUE(GetOpenSuccess()); + FlushConnection(); AdvanceTickClock(base::TimeDelta::FromMilliseconds(49)); - ASSERT_FALSE(IsOpenComplete()); + ASSERT_FALSE(IsFlushComplete()); } TEST_F(BattOrConnectionImplTest, FlushFailsWithNonTimeoutError) { OpenConnection(); + ASSERT_TRUE(IsOpenComplete()); + ASSERT_TRUE(GetOpenSuccess()); + FlushConnection(); ForceReceiveError(device::mojom::SerialReceiveError::DISCONNECTED); - ASSERT_TRUE(IsOpenComplete()); - ASSERT_FALSE(GetOpenSuccess()); + ASSERT_FALSE(GetFlushSuccess()); +} + +TEST_F(BattOrConnectionImplTest, ControlSendEscapesStartBytesCorrectly) { + OpenConnection(); + AdvanceTickClock(base::TimeDelta::FromMilliseconds(50)); + + SendControlMessage( + BATTOR_CONTROL_MESSAGE_TYPE_INIT, + BATTOR_CONTROL_BYTE_START, + BATTOR_CONTROL_BYTE_START); + + const char expected_data[] = { + BATTOR_CONTROL_BYTE_START, BATTOR_MESSAGE_TYPE_CONTROL, + BATTOR_CONTROL_BYTE_ESCAPE, BATTOR_CONTROL_MESSAGE_TYPE_INIT, + BATTOR_CONTROL_BYTE_ESCAPE, BATTOR_CONTROL_BYTE_START, + BATTOR_CONTROL_BYTE_ESCAPE, 0x00, + BATTOR_CONTROL_BYTE_ESCAPE, BATTOR_CONTROL_BYTE_START, + BATTOR_CONTROL_BYTE_ESCAPE, 0x00, + BATTOR_CONTROL_BYTE_END, + }; + + ASSERT_TRUE(GetSendSuccess()); + ASSERT_EQ(0, std::memcmp(ReadMessageRaw(13)->data(), expected_data, 13)); +} + +TEST_F(BattOrConnectionImplTest, ControlSendEscapesEndBytesCorrectly) { + OpenConnection(); + AdvanceTickClock(base::TimeDelta::FromMilliseconds(50)); + + SendControlMessage( + BATTOR_CONTROL_MESSAGE_TYPE_RESET, + BATTOR_CONTROL_BYTE_END, + BATTOR_CONTROL_BYTE_END); + + const char expected_data[] = { + BATTOR_CONTROL_BYTE_START, BATTOR_MESSAGE_TYPE_CONTROL, + BATTOR_CONTROL_BYTE_ESCAPE, BATTOR_CONTROL_MESSAGE_TYPE_RESET, + BATTOR_CONTROL_BYTE_ESCAPE, BATTOR_CONTROL_BYTE_END, + BATTOR_CONTROL_BYTE_ESCAPE, 0x00, + BATTOR_CONTROL_BYTE_ESCAPE, BATTOR_CONTROL_BYTE_END, + BATTOR_CONTROL_BYTE_ESCAPE, 0x00, + BATTOR_CONTROL_BYTE_END, + }; + + ASSERT_TRUE(GetSendSuccess()); + ASSERT_EQ(0, std::memcmp(ReadMessageRaw(13)->data(), expected_data, 13)); +} + +TEST_F(BattOrConnectionImplTest, ControlSendEscapesEscapeBytesCorrectly) { + OpenConnection(); + AdvanceTickClock(base::TimeDelta::FromMilliseconds(50)); + + SendControlMessage( + BATTOR_CONTROL_MESSAGE_TYPE_SELF_TEST, + BATTOR_CONTROL_BYTE_ESCAPE, + BATTOR_CONTROL_BYTE_ESCAPE); + + const char expected_data[] = { + BATTOR_CONTROL_BYTE_START, BATTOR_MESSAGE_TYPE_CONTROL, + BATTOR_CONTROL_BYTE_ESCAPE, BATTOR_CONTROL_MESSAGE_TYPE_SELF_TEST, + BATTOR_CONTROL_BYTE_ESCAPE, BATTOR_CONTROL_BYTE_ESCAPE, + BATTOR_CONTROL_BYTE_ESCAPE, 0x00, + BATTOR_CONTROL_BYTE_ESCAPE, BATTOR_CONTROL_BYTE_ESCAPE, + BATTOR_CONTROL_BYTE_ESCAPE, 0x00, + BATTOR_CONTROL_BYTE_END, + }; + + ASSERT_TRUE(GetSendSuccess()); + ASSERT_EQ(0, std::memcmp(ReadMessageRaw(13)->data(), expected_data, 13)); +} + +TEST_F(BattOrConnectionImplTest, ControlSendEscapesParametersCorrectly) { + OpenConnection(); + AdvanceTickClock(base::TimeDelta::FromMilliseconds(50)); + + // Check if the two control parameters are ordered and escaped properly. + // This also checks the byte ordering of the two 16-bit control message + // parameters, which should be little-endian on the wire. + SendControlMessage(BATTOR_CONTROL_MESSAGE_TYPE_READ_SD_UART, 0x0100, 0x0002); + + const char expected_data[] = { + BATTOR_CONTROL_BYTE_START, BATTOR_MESSAGE_TYPE_CONTROL, + BATTOR_CONTROL_MESSAGE_TYPE_READ_SD_UART, + BATTOR_CONTROL_BYTE_ESCAPE, 0x00, + BATTOR_CONTROL_BYTE_ESCAPE, 0x01, + BATTOR_CONTROL_BYTE_ESCAPE, 0x02, + BATTOR_CONTROL_BYTE_ESCAPE, 0x00, + BATTOR_CONTROL_BYTE_END, + }; + + ASSERT_TRUE(GetSendSuccess()); + ASSERT_EQ(0, std::memcmp(ReadMessageRaw(12)->data(), expected_data, 12)); } TEST_F(BattOrConnectionImplTest, InitSendsCorrectBytes) {
diff --git a/tools/battor_agent/battor_sample_converter.cc b/tools/battor_agent/battor_sample_converter.cc index bcee95b..efbf046 100644 --- a/tools/battor_agent/battor_sample_converter.cc +++ b/tools/battor_agent/battor_sample_converter.cc
@@ -49,7 +49,7 @@ baseline_voltage_ /= calibration_frame.size(); } -BattOrSampleConverter::~BattOrSampleConverter() {} +BattOrSampleConverter::~BattOrSampleConverter() = default; BattOrSample BattOrSampleConverter::ToSample(const RawBattOrSample& sample, size_t sample_number) const {
diff --git a/tools/binary_size/README.md b/tools/binary_size/README.md index 8e4f94caa..b7afdb12 100644 --- a/tools/binary_size/README.md +++ b/tools/binary_size/README.md
@@ -39,8 +39,8 @@ # Diff BEFORE_REV and AFTER_REV using build artifacts downloaded from perf bots. tools/binary_size/diagnose_bloat.py AFTER_REV --reference-rev BEFORE_REV --cloud -v -# Fetch a single .size and .apk from the bots: -tools/binary_size/diagnose_bloat.py AFTER_REV --cloud --single +# Fetch a .size, libmonochrome.so, and MonochromePublic.apk from perf bots (Googlers only): +tools/binary_size/diagnose_bloat.py AFTER_REV --cloud --unstripped --single # Build and diff all contiguous revs in range BEFORE_REV..AFTER_REV for src/v8. tools/binary_size/diagnose_bloat.py AFTER_REV --reference-rev BEFORE_REV --subrepo v8 --all -v @@ -72,13 +72,12 @@ 1. A list of symbols, including name, address, size, padding (caused by alignment), and associated `.o` / `.cc` files. - #### How are Symbols Collected? 1. Symbol list is Extracted from linker `.map` file. - * Map files contain some unique pieces of information, such as - `** merge strings` entries, and the odd unnamed symbol (which map at least - lists a `.o` path). + * Map files contain some unique pieces of information compared to `nm` output, + such as `** merge strings` entries, and some unnamed symbols (which + although unnamed, contain the `.o` path). 1. `.o` files are mapped to `.cc` files by parsing `.ninja` files. * This means that `.h` files are never listed as sources. No information about inlined symbols is gathered. @@ -87,8 +86,15 @@ * Aliases are created by identical code folding (linker optimization). * Aliases have the same address and size, but report their `.pss` as `.size / .num_aliases`. -1. Paths for shared symbols (those found in multiple `.o` files) are collected - by running `nm` on every `.o` file. +1. `** merge strings` symbols are further broken down into individual string + literal symbols. This is done by reading string literals from `.o` files, and + then searching for them within the `** merge strings` sections. +1. "Shared symbols" are those that are owned by multiple `.o` files. These include + inline functions defined in `.h` files, and string literals that are de-duped + at link-time. Shared symbols are normally represented using one symbol alias + per path, but are sometimes collapsed into a single symbol where the path is + set to `{shared}/$SYMBOL_COUNT`. This collapsing is done only for symbols owned + by a large number of paths. #### What Other Processing Happens? @@ -140,6 +146,11 @@ **Note:** Refer to [diagnose_bloat.py](https://cs.chromium.org/search/?q=file:diagnose_bloat.py+gn_args) for list of GN args to build a Release binary (or just use the tool with --single). + +**Googlers:** If you just want a `.size` for a commit on master: + + GIT_REV="HEAD~200" + tools/binary_size/diagnose_bloat.py --single --cloud --unstripped $GIT_REV *** Example Usage: @@ -150,7 +161,6 @@ tools/binary_size/supersize archive chrome.size --apk-file out/Release/apks/ChromePublic.apk -v # Linux: -LLVM_DOWNLOAD_GOLD_PLUGIN=1 gclient runhooks # One-time download. ninja -C out/Release -j 1000 chrome tools/binary_size/supersize archive chrome.size --elf-file out/Release/chrome -v ``` @@ -182,7 +192,7 @@ ### Usage: console Starts a Python interpreter where you can run custom queries, or run pre-made -queries from canned_queries.py. +queries from `canned_queries.py`. Example Usage: @@ -208,6 +218,12 @@ >>> help(canned_queries) ... >>> Print(canned_queries.TemplatesByName(depth=-1)) +... +>>> syms = size_info.symbols.WherePathMatches(r'skia').Sorted() +>>> Print(syms, verbose=True) # Show full symbol names with parameter types. +... +>>> # Dump all string literals from skia files to "strings.txt". +>>> Print((t[1] for t in ReadStringLiterals(syms)), to_file='strings.txt') ``` ### Roadmap @@ -220,11 +236,8 @@ * Collect java symbol information * Collect .apk entry information 1. More `console` features: - * CSV output (for pasting into a spreadsheet). * Add `SplitByName()` - Like `GroupByName()`, but recursive. * A canned query, that does what ShowGlobals does (as described in [Windows Binary Sizes](https://www.chromium.org/developers/windows-binary-sizes)). - * Show symbol counts by bucket size. - * 3 symbols < 64 bytes. 10 symbols < 128, 3 < 256, 5 < 512, 0 < 1024, 3 < 2048 1. More `html_report` features: * Able to render size diffs (tint negative size red). * Break down by other groupings (Create from result of `SplitByName()`)
diff --git a/tools/binary_size/diagnose_bloat.py b/tools/binary_size/diagnose_bloat.py index 8b354ce..815cf44 100755 --- a/tools/binary_size/diagnose_bloat.py +++ b/tools/binary_size/diagnose_bloat.py
@@ -263,15 +263,19 @@ if os.path.exists(os.path.join(os.path.dirname(_SRC_ROOT), 'src-internal')): self.extra_gn_args_str = ' is_chrome_branded=true' else: - self.extra_gn_args_str = (' exclude_unwind_tables=true ' - 'ffmpeg_branding="Chrome" proprietary_codecs=true') + self.extra_gn_args_str = ( + ' ffmpeg_branding="Chrome" proprietary_codecs=true') if self.IsLinux(): self.extra_gn_args_str += ( - ' allow_posix_link_time_opt=false generate_linker_map=true') + ' is_cfi=false generate_linker_map=true') self.target = self.target if self.IsAndroid() else 'chrome' def _GenGnCmd(self): - gn_args = 'is_official_build=true symbol_level=1' + gn_args = 'is_official_build=true' + gn_args += ' symbol_level=0' + # Variables often become unused when experimenting with macros to reduce + # size, so don't fail on warnings. + gn_args += ' treat_warnings_as_errors=false' gn_args += ' use_goma=%s' % str(self.use_goma).lower() gn_args += ' target_os="%s"' % self.target_os if self.IsAndroid(): @@ -315,13 +319,15 @@ class _BuildArchive(object): """Class for managing a directory with build results and build metadata.""" - def __init__(self, rev, base_archive_dir, build, subrepo, slow_options): + def __init__(self, rev, base_archive_dir, build, subrepo, slow_options, + save_unstripped): self.build = build self.dir = os.path.join(base_archive_dir, rev) metadata_path = os.path.join(self.dir, 'metadata.txt') self.rev = rev self.metadata = _Metadata([self], build, metadata_path, subrepo) self._slow_options = slow_options + self._save_unstripped = save_unstripped def ArchiveBuildResults(self, supersize_path): """Save build artifacts necessary for diffing.""" @@ -332,10 +338,24 @@ self._ArchiveFile(self.build.abs_apk_path + '.mapping') self._ArchiveResourceSizes() self._ArchiveSizeFile(supersize_path) + if self._save_unstripped: + self._ArchiveFile(self.build.abs_main_lib_path) self.metadata.Write() + assert self.Exists() def Exists(self): - return self.metadata.Exists() + ret = self.metadata.Exists() and os.path.exists(self.archived_size_path) + if self._save_unstripped: + ret = ret and os.path.exists(self.archived_unstripped_path) + return ret + + @property + def archived_unstripped_path(self): + return os.path.join(self.dir, os.path.basename(self.build.main_lib_path)) + + @property + def archived_size_path(self): + return os.path.join(self.dir, self.build.size_name) def _ArchiveResourceSizes(self): cmd = [_RESOURCE_SIZES_PATH, self.build.abs_apk_path,'--output-dir', @@ -355,12 +375,10 @@ existing_size_file = self.build.abs_apk_path + '.size' if os.path.exists(existing_size_file): logging.info('Found existing .size file') - os.rename( - existing_size_file, os.path.join(self.dir, self.build.size_name)) + shutil.copy(existing_size_file, self.archived_size_path) else: - size_path = os.path.join(self.dir, self.build.size_name) - supersize_cmd = [supersize_path, 'archive', size_path, '--elf-file', - self.build.abs_main_lib_path] + supersize_cmd = [supersize_path, 'archive', self.archived_size_path, + '--elf-file', self.build.abs_main_lib_path] if self.build.IsCloud(): supersize_cmd += ['--no-source-paths'] else: @@ -373,11 +391,13 @@ class _DiffArchiveManager(object): """Class for maintaining BuildArchives and their related diff artifacts.""" - def __init__(self, revs, archive_dir, diffs, build, subrepo, slow_options): + def __init__(self, revs, archive_dir, diffs, build, subrepo, slow_options, + save_unstripped): self.archive_dir = archive_dir self.build = build self.build_archives = [ - _BuildArchive(rev, archive_dir, build, subrepo, slow_options) + _BuildArchive(rev, archive_dir, build, subrepo, slow_options, + save_unstripped) for rev in revs ] self.diffs = diffs @@ -410,18 +430,10 @@ with open(diff_path, 'a') as diff_file: for d in self.diffs: d.RunDiff(diff_file, before.dir, after.dir) - logging.info('See detailed diff results here: %s', - os.path.relpath(diff_path)) - if len(self.build_archives) == 2: - supersize_path = os.path.join(_BINARY_SIZE_DIR, 'supersize') - size_paths = [os.path.join(a.dir, a.build.size_name) - for a in self.build_archives] - logging.info('Enter supersize console via: %s console %s %s', - os.path.relpath(supersize_path), - os.path.relpath(size_paths[0]), - os.path.relpath(size_paths[1])) metadata.Write() self._AddDiffSummaryStat(before, after) + logging.info('See detailed diff results here: %s', + os.path.relpath(diff_path)) def Summarize(self): if self._summary_stats: @@ -433,11 +445,14 @@ for s, before, after in stats: _PrintAndWriteToFile(f, '{:>+10} {} {} for range: {}..{}', s.value, s.units, s.name, before, after) - elif self.build_archives: + if self.build_archives: supersize_path = os.path.join(_BINARY_SIZE_DIR, 'supersize') - size_path = os.path.join(self.build_archives[0].dir, self.build.size_name) - logging.info('Enter supersize console via: %s console %s', - os.path.relpath(supersize_path), os.path.relpath(size_path)) + size2 = '' + if len(self.build_archives) > 1: + size2 = os.path.relpath(self.build_archives[-1].archived_size_path) + logging.info('Enter supersize console via: %s console %s %s', + os.path.relpath(supersize_path), + os.path.relpath(self.build_archives[0].archived_size_path), size2) def _AddDiffSummaryStat(self, before, after): @@ -649,25 +664,33 @@ def _DownloadAndArchive(gsutil_path, archive, dl_dir, build, supersize_path): - proc = subprocess.Popen([gsutil_path, 'version'], stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) - output, _ = proc.communicate() - if proc.returncode: - _Die('gsutil error. Please file a bug in Tools>BinarySize. Output:\n%s', - output) + # Wraps gsutil calls and returns stdout + stderr. + def gsutil_cmd(args, fail_msg=None): + fail_msg = fail_msg or '' + proc = subprocess.Popen([gsutil_path] + args, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + output = proc.communicate()[0].rstrip() + if proc.returncode or not output: + _Die(fail_msg + ' Process output:\n%s' % output) + return output + # Fails if gsutil isn't configured. + gsutil_cmd(['version'], + 'gsutil error. Please file a bug in Tools>BinarySize.') dl_dst = os.path.join(dl_dir, archive.rev) logging.info('Downloading build artifacts for %s', archive.rev) - # gsutil writes stdout and stderr to stderr, so pipe stdout and stderr to - # sys.stdout. - retcode = subprocess.call( - [gsutil_path, 'cp', build.DownloadUrl(archive.rev), dl_dst], - stdout=sys.stdout, stderr=subprocess.STDOUT) - if retcode: - _Die('unexpected error while downloading %s. It may no longer exist on ' - 'the server or it may not have been uploaded yet (check %s). ' - 'Otherwise, you may not have the correct access permissions.', - build.DownloadUrl(archive.rev), build.builder_url) + + # Fails if archive isn't found. + output = gsutil_cmd(['stat', build.DownloadUrl(archive.rev)], + 'Unexpected error while downloading %s. It may no longer exist on the ' + 'server or it may not have been uploaded yet (check %s). Otherwise, you ' + 'may not have the correct access permissions.' % ( + build.DownloadUrl(archive.rev), build.builder_url)) + size = re.search(r'Content-Length:\s+([0-9]+)', output).group(1) + logging.info('File size: %s', _ReadableBytes(int(size))) + + # Download archive. Any failures here are unexpected. + gsutil_cmd(['cp', build.DownloadUrl(archive.rev), dl_dst]) # Files needed for supersize and resource_sizes. Paths relative to out dir. to_extract = [build.main_lib_path, build.map_file_path, 'args.gn'] @@ -683,6 +706,17 @@ build.output_directory = output_directory +def _ReadableBytes(b): + val = b + units = ['Bytes','KB', 'MB', 'GB'] + for unit in units: + if val < 1024: + return '%.2f %s' % (val, unit) + val /= 1024.0 + else: + return '%d %s' % (b, 'Bytes') + + def _ExtractFiles(to_extract, dst, z): """Extract a list of files. Returns the common prefix of the extracted files. @@ -756,6 +790,9 @@ parser.add_argument('--single', action='store_true', help='Sets --reference-rev=rev') + parser.add_argument('--unstripped', + action='store_true', + help='Save the unstripped native library when archiving.') parser.add_argument('--depot-tools-path', help='Custom path to depot tools. Needed for --cloud if ' 'depot tools isn\'t in your PATH.') @@ -836,7 +873,8 @@ ResourceSizesDiff(build.apk_name) ] diff_mngr = _DiffArchiveManager(revs, args.archive_directory, diffs, build, - subrepo, args.include_slow_options) + subrepo, args.include_slow_options, + args.unstripped) consecutive_failures = 0 for i, archive in enumerate(diff_mngr.IterArchives()): if archive.Exists():
diff --git a/tools/binary_size/libsupersize/archive.py b/tools/binary_size/libsupersize/archive.py index 44f1e3a5..105ccaa 100644 --- a/tools/binary_size/libsupersize/archive.py +++ b/tools/binary_size/libsupersize/archive.py
@@ -9,6 +9,7 @@ import collections import datetime import gzip +import itertools import logging import os import posixpath @@ -19,6 +20,7 @@ import zipfile import concurrent +import demangle import describe import file_format import function_signature @@ -26,16 +28,29 @@ import models import ninja_parser import nm -import paths +import path_util + +sys.path.insert(1, os.path.join(path_util.SRC_ROOT, 'tools', 'grit')) +from grit.format import data_pack -def _OpenMaybeGz(path, mode=None): +# Effect of _MAX_SAME_NAME_ALIAS_COUNT (as of Oct 2017, with min_pss = max): +# 1: shared .text symbols = 1772874 bytes, file size = 9.43MiB (645476 symbols). +# 2: shared .text symbols = 1065654 bytes, file size = 9.58MiB (669952 symbols). +# 6: shared .text symbols = 464058 bytes, file size = 10.11MiB (782693 symbols). +# 10: shared .text symbols = 365648 bytes, file size =10.24MiB (813758 symbols). +# 20: shared .text symbols = 86202 bytes, file size = 10.38MiB (854548 symbols). +# 40: shared .text symbols = 48424 bytes, file size = 10.50MiB (890396 symbols). +# 50: shared .text symbols = 41860 bytes, file size = 10.54MiB (902304 symbols). +# max: shared .text symbols = 0 bytes, file size = 11.10MiB (1235449 symbols). +_MAX_SAME_NAME_ALIAS_COUNT = 40 # 50kb is basically negligable. + + +def _OpenMaybeGz(path): """Calls `gzip.open()` if |path| ends in ".gz", otherwise calls `open()`.""" if path.endswith('.gz'): - if mode and 'w' in mode: - return gzip.GzipFile(path, mode, 1) - return gzip.open(path, mode) - return open(path, mode or 'r') + return gzip.open(path, 'rb') + return open(path, 'rb') def _StripLinkerAddedSymbolPrefixes(raw_symbols): @@ -57,22 +72,9 @@ elif full_name.startswith('rel.'): symbol.flags |= models.FLAG_REL symbol.full_name = full_name[4:] - - -def _UnmangleRemainingSymbols(raw_symbols, tool_prefix): - """Uses c++filt to unmangle any symbols that need it.""" - to_process = [s for s in raw_symbols if s.full_name.startswith('_Z')] - if not to_process: - return - - logging.info('Unmangling %d names', len(to_process)) - proc = subprocess.Popen([tool_prefix + 'c++filt'], stdin=subprocess.PIPE, - stdout=subprocess.PIPE) - stdout = proc.communicate('\n'.join(s.full_name for s in to_process))[0] - assert proc.returncode == 0 - - for i, line in enumerate(stdout.splitlines()): - to_process[i].full_name = line + elif full_name.startswith('hot.'): + symbol.flags |= models.FLAG_HOT + symbol.full_name = full_name[4:] def _NormalizeNames(raw_symbols): @@ -180,76 +182,133 @@ return True, path -def _SourcePathForObjectPath(object_path, source_mapper): - """Returns (is_generated, normalized_path)""" - # We don't have source info for prebuilt .a files. - if not os.path.isabs(object_path) and not object_path.startswith('..'): - source_path = source_mapper.FindSourceForPath(object_path) - if source_path: - return _NormalizeSourcePath(source_path) - return False, '' +def _ExtractSourcePathsAndNormalizeObjectPaths(raw_symbols, source_mapper): + """Fills in the |source_path| attribute and normalizes |object_path|.""" + if source_mapper: + logging.info('Looking up source paths from ninja files') + for symbol in raw_symbols: + object_path = symbol.object_path + if object_path: + # We don't have source info for prebuilt .a files. + if not os.path.isabs(object_path) and not object_path.startswith('..'): + source_path = source_mapper.FindSourceForPath(object_path) + if source_path: + symbol.generated_source, symbol.source_path = ( + _NormalizeSourcePath(source_path)) + symbol.object_path = _NormalizeObjectPath(object_path) + assert source_mapper.unmatched_paths_count == 0, ( + 'One or more source file paths could not be found. Likely caused by ' + '.ninja files being generated at a different time than the .map file.') + else: + logging.info('Normalizing object paths') + for symbol in raw_symbols: + if symbol.object_path: + symbol.object_path = _NormalizeObjectPath(symbol.object_path) -def _ExtractSourcePaths(raw_symbols, source_mapper): - """Fills in the |source_path| attribute.""" - for symbol in raw_symbols: - object_path = symbol.object_path - if object_path and not symbol.source_path: - symbol.generated_source, symbol.source_path = ( - _SourcePathForObjectPath(object_path, source_mapper)) - - -def _ComputeAncestorPath(path_list): +def _ComputeAncestorPath(path_list, symbol_count): """Returns the common ancestor of the given paths.""" - # Ignore missing paths. - path_list = [p for p in path_list if p] + if not path_list: + return '' + prefix = os.path.commonprefix(path_list) - # Put the path count as a subdirectory to allow for better grouping when - # path-based breakdowns. - if not prefix: - if len(path_list) < 2: - return '' - return os.path.join('{shared}', str(len(path_list))) + # Check if all paths were the same. if prefix == path_list[0]: return prefix - assert len(path_list) > 1, 'path_list: ' + repr(path_list) - return os.path.join(os.path.dirname(prefix), '{shared}', str(len(path_list))) + + # Put in buckets to cut down on the number of unique paths. + if symbol_count >= 100: + symbol_count_str = '100+' + elif symbol_count >= 50: + symbol_count_str = '50-99' + elif symbol_count >= 20: + symbol_count_str = '20-49' + elif symbol_count >= 10: + symbol_count_str = '10-19' + else: + symbol_count_str = str(symbol_count) + + # Put the path count as a subdirectory so that grouping by path will show + # "{shared}" as a bucket, and the symbol counts as leafs. + if not prefix: + return os.path.join('{shared}', symbol_count_str) + return os.path.join(os.path.dirname(prefix), '{shared}', symbol_count_str) -# This must normalize object paths at the same time because normalization -# needs to occur before finding common ancestor. -def _ComputeAncestorPathsAndNormalizeObjectPaths( - raw_symbols, object_paths_by_name, source_mapper): +def _CompactLargeAliasesIntoSharedSymbols(raw_symbols): + """Converts symbols with large number of aliases into single symbols. + + The merged symbol's path fields are changed to common-ancestor paths in + the form: common/dir/{shared}/$SYMBOL_COUNT + + Assumes aliases differ only by path (not by name). + """ + num_raw_symbols = len(raw_symbols) + num_shared_symbols = 0 + src_cursor = 0 + dst_cursor = 0 + while src_cursor < num_raw_symbols: + symbol = raw_symbols[src_cursor] + raw_symbols[dst_cursor] = symbol + dst_cursor += 1 + aliases = symbol.aliases + if aliases and len(aliases) > _MAX_SAME_NAME_ALIAS_COUNT: + symbol.source_path = _ComputeAncestorPath( + [s.source_path for s in aliases if s.source_path], len(aliases)) + symbol.object_path = _ComputeAncestorPath( + [s.object_path for s in aliases if s.object_path], len(aliases)) + symbol.generated_source = all(s.generated_source for s in aliases) + symbol.aliases = None + num_shared_symbols += 1 + src_cursor += len(aliases) + else: + src_cursor += 1 + raw_symbols[dst_cursor:] = [] + num_removed = src_cursor - dst_cursor + logging.debug('Converted %d aliases into %d shared-path symbols', + num_removed, num_shared_symbols) + + +def _ConnectNmAliases(raw_symbols): + """Ensures |aliases| is set correctly for all symbols.""" + prev_sym = raw_symbols[0] + for sym in raw_symbols[1:]: + # Don't merge bss symbols. + if sym.address > 0 and prev_sym.address == sym.address: + # Don't merge padding-only symbols (** symbol gaps). + if prev_sym.size > 0: + # Don't merge if already merged. + if prev_sym.aliases is None or prev_sym.aliases is not sym.aliases: + if prev_sym.aliases: + prev_sym.aliases.append(sym) + else: + prev_sym.aliases = [prev_sym, sym] + sym.aliases = prev_sym.aliases + prev_sym = sym + + +def _AssignNmAliasPathsAndCreatePathAliases(raw_symbols, object_paths_by_name): num_found_paths = 0 num_unknown_names = 0 num_path_mismatches = 0 - num_unmatched_aliases = 0 + num_aliases_created = 0 + ret = [] for symbol in raw_symbols: + ret.append(symbol) full_name = symbol.full_name if (symbol.IsBss() or not full_name or full_name[0] in '*.' or # e.g. ** merge symbols, .Lswitch.table full_name == 'startup'): - symbol.object_path = _NormalizeObjectPath(symbol.object_path) continue object_paths = object_paths_by_name.get(full_name) if object_paths: num_found_paths += 1 else: - if not symbol.object_path and symbol.aliases: - # Happens when aliases are from object files where all symbols were - # pruned or de-duped as aliases. Since we are only scanning .o files - # referenced by included symbols, such files are missed. - # TODO(agrieve): This could be fixed by retrieving linker inputs from - # build.ninja, or by looking for paths within the .map file's - # discarded sections. - num_unmatched_aliases += 1 - continue if num_unknown_names < 10: logging.warning('Symbol not found in any .o files: %r', symbol) num_unknown_names += 1 - symbol.object_path = _NormalizeObjectPath(symbol.object_path) continue if symbol.object_path and symbol.object_path not in object_paths: @@ -257,21 +316,30 @@ logging.warning('Symbol path reported by .map not found by nm.') logging.warning('sym=%r', symbol) logging.warning('paths=%r', object_paths) + object_paths.append(symbol.object_path) + object_paths.sort() num_path_mismatches += 1 - if source_mapper: - tups = [ - _SourcePathForObjectPath(p, source_mapper) for p in object_paths] - symbol.source_path = _ComputeAncestorPath(t[1] for t in tups) - symbol.generated_source = all(t[0] for t in tups) + symbol.object_path = object_paths[0] - object_paths = [_NormalizeObjectPath(p) for p in object_paths] - symbol.object_path = _ComputeAncestorPath(object_paths) + if len(object_paths) > 1: + # Create one symbol for each object_path. + aliases = symbol.aliases or [symbol] + symbol.aliases = aliases + num_aliases_created += len(object_paths) - 1 + for object_path in object_paths[1:]: + new_sym = models.Symbol( + symbol.section_name, symbol.size, address=symbol.address, + full_name=full_name, object_path=object_path, aliases=aliases) + aliases.append(new_sym) + ret.append(new_sym) logging.debug('Cross-referenced %d symbols with nm output. ' 'num_unknown_names=%d num_path_mismatches=%d ' - 'num_unused_aliases=%d', num_found_paths, num_unknown_names, - num_path_mismatches, num_unmatched_aliases) + 'num_aliases_created=%d', + num_found_paths, num_unknown_names, num_path_mismatches, + num_aliases_created) + return ret def _DiscoverMissedObjectPaths(raw_symbols, elf_object_paths): @@ -289,6 +357,77 @@ return missed_inputs +def _CreateMergeStringsReplacements(merge_string_syms, + list_of_positions_by_object_path): + """Creates replacement symbols for |merge_syms|.""" + ret = [] + STRING_LITERAL_NAME = models.STRING_LITERAL_NAME + assert len(merge_string_syms) == len(list_of_positions_by_object_path) + tups = itertools.izip(merge_string_syms, list_of_positions_by_object_path) + for merge_sym, positions_by_object_path in tups: + merge_sym_address = merge_sym.address + new_symbols = [] + ret.append(new_symbols) + for object_path, positions in positions_by_object_path.iteritems(): + for offset, size in positions: + address = merge_sym_address + offset + symbol = models.Symbol( + models.SECTION_RODATA, size, address, STRING_LITERAL_NAME, + object_path=object_path) + new_symbols.append(symbol) + + logging.debug('Created %d string literal symbols', sum(len(x) for x in ret)) + logging.debug('Sorting string literals') + for symbols in ret: + # In order to achieve a total ordering in the presense of aliases, need to + # include both |address| and |object_path|. + # In order to achieve consistent deduping, need to include |size|. + symbols.sort(key=lambda x: (x.address, -x.size, x.object_path)) + + logging.debug('Deduping string literals') + num_removed = 0 + size_removed = 0 + num_aliases = 0 + for i, symbols in enumerate(ret): + if not symbols: + continue + prev_symbol = symbols[0] + new_symbols = [prev_symbol] + for symbol in symbols[1:]: + padding = symbol.address - prev_symbol.end_address + if (prev_symbol.address == symbol.address and + prev_symbol.size == symbol.size): + # String is an alias. + num_aliases += 1 + aliases = prev_symbol.aliases + if aliases: + aliases.append(symbol) + symbol.aliases = aliases + else: + aliases = [prev_symbol, symbol] + prev_symbol.aliases = aliases + symbol.aliases = aliases + elif padding + symbol.size <= 0: + # String is a substring of prior one. + num_removed += 1 + size_removed += symbol.size + continue + elif padding < 0: + # String overlaps previous one. Adjust to not overlap. + symbol.address -= padding + symbol.size += padding + new_symbols.append(symbol) + prev_symbol = symbol + ret[i] = new_symbols + # Aliases come out in random order, so sort to be deterministic. + ret[i].sort(key=lambda s: (s.address, s.object_path)) + + logging.debug( + 'Removed %d overlapping string literals (%d bytes) & created %d aliases', + num_removed, size_removed, num_aliases) + return ret + + def _CalculatePadding(raw_symbols): """Populates the |padding| field based on symbol addresses. @@ -302,7 +441,8 @@ 'Input symbols must be sorted by section, then address.') seen_sections.append(symbol.section_name) continue - if symbol.address <= 0 or prev_symbol.address <= 0: + if (symbol.address <= 0 or prev_symbol.address <= 0 or + symbol.IsPak() or prev_symbol.IsPak()): continue if symbol.address == prev_symbol.address: @@ -319,9 +459,10 @@ # E.g.: Set them to 0 and see what warnings get logged, then take max value. # TODO(agrieve): See if these thresholds make sense for architectures # other than arm32. - if not symbol.full_name.startswith('*') and ( + if (not symbol.full_name.startswith('*') and + not symbol.IsStringLiteral() and ( symbol.section in 'rd' and padding >= 256 or - symbol.section in 't' and padding >= 64): + symbol.section in 't' and padding >= 64)): # Should not happen. logging.warning('Large padding of %d between:\n A) %r\n B) %r' % ( padding, prev_symbol, symbol)) @@ -332,34 +473,41 @@ '%r\nprev symbol: %r' % (symbol, prev_symbol)) -def _AddSymbolAliases(raw_symbols, aliases_by_address): +def _AddNmAliases(raw_symbols, names_by_address): + """Adds symbols that were removed by identical code folding.""" # Step 1: Create list of (index_of_symbol, name_list). logging.debug('Creating alias list') replacements = [] num_new_symbols = 0 + missing_names = collections.defaultdict(list) for i, s in enumerate(raw_symbols): # Don't alias padding-only symbols (e.g. ** symbol gap) if s.size_without_padding == 0: continue - name_list = aliases_by_address.get(s.address) + name_list = names_by_address.get(s.address) if name_list: if s.full_name not in name_list: + missing_names[s.full_name].append(s.address) logging.warning('Name missing from aliases: %s %s', s.full_name, name_list) continue replacements.append((i, name_list)) num_new_symbols += len(name_list) - 1 + if missing_names and logging.getLogger().isEnabledFor(logging.INFO): + for address, names in names_by_address.iteritems(): + for name in names: + if name in missing_names: + logging.info('Missing name %s is at address %x instead of [%s]' % + (name, address, ','.join('%x' % a for a in missing_names[name]))) + if float(num_new_symbols) / len(raw_symbols) < .05: - # TODO(agrieve): Figure out if there's a way to get alias information from - # clang-compiled nm. logging.warning('Number of aliases is oddly low (%.0f%%). It should ' - 'usually be around 25%%. Ensure --tool-prefix is correct. ' - 'Ignore this if you compiled with clang.', + 'usually be around 25%%. Ensure --tool-prefix is correct. ', float(num_new_symbols) / len(raw_symbols) * 100) # Step 2: Create new symbols as siblings to each existing one. - logging.debug('Creating %d aliases', num_new_symbols) + logging.debug('Creating %d new symbols from nm output', num_new_symbols) src_cursor_end = len(raw_symbols) raw_symbols += [None] * num_new_symbols dst_cursor_end = len(raw_symbols) @@ -373,15 +521,14 @@ sym = raw_symbols[src_index] src_cursor_end -= 1 - # Create aliases (does not bother reusing the existing symbol). - aliases = [None] * len(name_list) + # Create symbols (does not bother reusing the existing symbol). for i, full_name in enumerate(name_list): - aliases[i] = models.Symbol( - sym.section_name, sym.size, address=sym.address, full_name=full_name, - aliases=aliases) - - dst_cursor_end -= len(aliases) - raw_symbols[dst_cursor_end:dst_cursor_end + len(aliases)] = aliases + dst_cursor_end -= 1 + # Do not set |aliases| in order to avoid being pruned by + # _CompactLargeAliasesIntoSharedSymbols(), which assumes aliases differ + # only by path. The field will be set afterwards by _ConnectNmAliases(). + raw_symbols[dst_cursor_end] = models.Symbol( + sym.section_name, sym.size, address=sym.address, full_name=full_name) assert dst_cursor_end == src_cursor_end @@ -408,7 +555,7 @@ timestamp_obj = datetime.datetime.utcfromtimestamp(os.path.getmtime( elf_path)) timestamp = calendar.timegm(timestamp_obj.timetuple()) - relative_tool_prefix = paths.ToSrcRootRelative(tool_prefix) + relative_tool_prefix = path_util.ToSrcRootRelative(tool_prefix) metadata = { models.METADATA_GIT_REVISION: git_rev, @@ -427,33 +574,13 @@ if apk_path: metadata[models.METADATA_APK_FILENAME] = relative_to_out(apk_path) + metadata[models.METADATA_APK_SIZE] = os.path.getsize(apk_path) return metadata -def CreateSizeInfo(map_path, elf_path, tool_prefix, output_directory, - normalize_names=True): - """Creates a SizeInfo. - - Args: - map_path: Path to the linker .map(.gz) file to parse. - elf_path: Path to the corresponding unstripped ELF file. Used to find symbol - aliases and inlined functions. Can be None. - tool_prefix: Prefix for c++filt & nm (required). - output_directory: Build output directory. If None, source_paths and symbol - alias information will not be recorded. - """ - source_mapper = None - if output_directory: - # Start by finding the elf_object_paths, so that nm can run on them while - # the linker .map is being parsed. - logging.info('Parsing ninja files.') - source_mapper, elf_object_paths = ninja_parser.Parse( - output_directory, elf_path) - logging.debug('Parsed %d .ninja files.', source_mapper.parsed_file_count) - assert not elf_path or elf_object_paths, ( - 'Failed to find link command in ninja files for ' + - os.path.relpath(elf_path, output_directory)) - +def _ParseElfInfo(map_path, elf_path, tool_prefix, output_directory, + track_string_literals, elf_object_paths): + """Adds Elf section sizes and symbols.""" if elf_path: # Run nm on the elf file to retrieve the list of symbol names per-address. # This list is required because the .map file contains only a single name @@ -493,43 +620,311 @@ missed_object_paths = _DiscoverMissedObjectPaths( raw_symbols, elf_object_paths) bulk_analyzer.AnalyzePaths(missed_object_paths) - bulk_analyzer.Close() - - if source_mapper: - logging.info('Looking up source paths from ninja files') - _ExtractSourcePaths(raw_symbols, source_mapper) - assert source_mapper.unmatched_paths_count == 0, ( - 'One or more source file paths could not be found. Likely caused by ' - '.ninja files being generated at a different time than the .map file.') + bulk_analyzer.SortPaths() + if track_string_literals: + merge_string_syms = [s for s in raw_symbols if + s.full_name == '** merge strings' or + s.full_name == '** lld merge strings'] + # More likely for there to be a bug in supersize than an ELF to not have a + # single string literal. + assert merge_string_syms + string_positions = [(s.address, s.size) for s in merge_string_syms] + bulk_analyzer.AnalyzeStringLiterals(elf_path, string_positions) logging.info('Stripping linker prefixes from symbol names') _StripLinkerAddedSymbolPrefixes(raw_symbols) - # Map file for some reason doesn't unmangle all names. - # Unmangle prints its own log statement. - _UnmangleRemainingSymbols(raw_symbols, tool_prefix) + # Map file for some reason doesn't demangle all names. + # Demangle prints its own log statement. + demangle.DemangleRemainingSymbols(raw_symbols, tool_prefix) if elf_path: - logging.info('Adding aliased symbols, as reported by nm') + logging.info( + 'Adding symbols removed by identical code folding (as reported by nm)') # This normally does not block (it's finished by this time). - aliases_by_address = elf_nm_result.get() - _AddSymbolAliases(raw_symbols, aliases_by_address) + names_by_address = elf_nm_result.get() + _AddNmAliases(raw_symbols, names_by_address) if output_directory: - # For aliases, this provides path information where there wasn't any. - logging.info('Computing ancestor paths for inline functions and ' - 'normalizing object paths') - - object_paths_by_name = bulk_analyzer.Get() + object_paths_by_name = bulk_analyzer.GetSymbolNames() logging.debug('Fetched path information for %d symbols from %d files', len(object_paths_by_name), len(elf_object_paths) + len(missed_object_paths)) - _ComputeAncestorPathsAndNormalizeObjectPaths( - raw_symbols, object_paths_by_name, source_mapper) - if not elf_path or not output_directory: - logging.info('Normalizing object paths.') - for symbol in raw_symbols: - symbol.object_path = _NormalizeObjectPath(symbol.object_path) + # For aliases, this provides path information where there wasn't any. + logging.info('Creating aliases for symbols shared by multiple paths') + raw_symbols = _AssignNmAliasPathsAndCreatePathAliases( + raw_symbols, object_paths_by_name) + + if track_string_literals: + logging.info('Waiting for string literal extraction to complete.') + list_of_positions_by_object_path = bulk_analyzer.GetStringPositions() + bulk_analyzer.Close() + + if track_string_literals: + logging.info('Deconstructing ** merge strings into literals') + replacements = _CreateMergeStringsReplacements(merge_string_syms, + list_of_positions_by_object_path) + for merge_sym, literal_syms in itertools.izip( + merge_string_syms, replacements): + # Don't replace if no literals were found. + if literal_syms: + # Re-find the symbols since aliases cause their indices to change. + idx = raw_symbols.index(merge_sym) + # This assignment is a bit slow (causes array to be shifted), but + # is fast enough since len(merge_string_syms) < 10. + raw_symbols[idx:idx + 1] = literal_syms + + logging.debug('Connecting nm aliases') + _ConnectNmAliases(raw_symbols) + return section_sizes, raw_symbols + + +def _ComputePakFileSymbols( + file_name, contents, res_info, symbols_by_id, expected_size, + compression_ratio=1): + id_map = {id(v): k + for k, v in sorted(contents.resources.items(), reverse=True)} + alias_map = {k: id_map[id(v)] for k, v in contents.resources.iteritems() + if id_map[id(v)] != k} + # Longest locale pak is es-419.pak + if len(os.path.basename(file_name)) <= 9: + section_name = models.SECTION_PAK_TRANSLATIONS + else: + section_name = models.SECTION_PAK_NONTRANSLATED + overhead = (12 + 6) * compression_ratio # Header size plus extra offset + symbols_by_id[file_name] = models.Symbol( + section_name, overhead, full_name='{}: overhead'.format(file_name)) + total = overhead + for resource_id in sorted(contents.resources): + if resource_id in alias_map: + # 4 extra bytes of metadata (2 16-bit ints) + size = 4 + resource_id = alias_map[resource_id] + else: + # 6 extra bytes of metadata (1 32-bit int, 1 16-bit int) + size = len(contents.resources[resource_id]) + 6 + name, source_path = res_info[resource_id] + if resource_id not in symbols_by_id: + full_name = '{}: {}'.format(source_path, name) + symbols_by_id[resource_id] = models.Symbol( + section_name, 0, address=resource_id, full_name=full_name) + size *= compression_ratio + symbols_by_id[resource_id].size += size + total += size + total = int(round(total)) + assert expected_size == total, ( + '{} bytes in pak file not accounted for'.format(expected_size - total)) + + +def _ParsePakInfoFile(pak_info_path): + with open(pak_info_path, 'r') as info_file: + res_info = {} + for line in info_file.readlines(): + name, res_id, path = line.split(',') + res_info[int(res_id)] = (name, path.strip()) + return res_info + + +def _ParsePakSymbols( + section_sizes, object_paths, output_directory, symbols_by_id): + for path in object_paths: + whitelist_path = os.path.join(output_directory, path + '.whitelist') + if (not os.path.exists(whitelist_path) + or os.path.getsize(whitelist_path) == 0): + continue + with open(whitelist_path, 'r') as f: + for line in f: + resource_id = int(line.rstrip()) + # There may be object files in static libraries that are removed by the + # linker when there are no external references to its symbols. These + # files may be included in object_paths which our apk does not use, + # resulting in resource_ids that don't end up being in the final apk. + if resource_id not in symbols_by_id: + continue + symbols_by_id[resource_id].object_path = path + + raw_symbols = sorted(symbols_by_id.values(), + key=lambda s: (s.section_name, s.address)) + raw_total = 0.0 + int_total = 0 + for symbol in raw_symbols: + raw_total += symbol.size + # We truncate rather than round to ensure that we do not over attribute. It + # is easier to add another symbol to make up the difference. + symbol.size = int(symbol.size) + int_total += symbol.size + # Attribute excess to translations since only those are compressed. + raw_symbols.append(models.Symbol( + models.SECTION_PAK_TRANSLATIONS, int(round(raw_total - int_total)), + full_name='Pak compression leftover artifacts')) + + for symbol in raw_symbols: + prev = section_sizes.setdefault(symbol.section_name, 0) + section_sizes[symbol.section_name] = prev + symbol.size + return raw_symbols + + +def _ParseApkElfSectionSize(section_sizes, metadata, apk_elf_result): + if metadata: + logging.debug('Extracting section sizes from .so within .apk') + apk_build_id, apk_section_sizes, elf_overhead_size = apk_elf_result.get() + assert apk_build_id == metadata[models.METADATA_ELF_BUILD_ID], ( + 'BuildID from apk_elf_result did not match') + + packed_section_name = None + architecture = metadata[models.METADATA_ELF_ARCHITECTURE] + # Packing occurs enabled only arm32 & arm64. + if architecture == 'arm': + packed_section_name = '.rel.dyn' + elif architecture == 'arm64': + packed_section_name = '.rela.dyn' + + if packed_section_name: + logging.debug('Recording size of unpacked relocations') + if packed_section_name not in section_sizes: + logging.warning('Packed section not present: %s', packed_section_name) + else: + apk_section_sizes['%s (unpacked)' % packed_section_name] = ( + section_sizes.get(packed_section_name)) + return apk_section_sizes, elf_overhead_size + return section_sizes + + +def _ParseApkOtherSymbols(section_sizes, apk_path): + apk_symbols = [] + zip_info_total = 0 + with zipfile.ZipFile(apk_path) as z: + for zip_info in z.infolist(): + zip_info_total += zip_info.compress_size + # Skip shared library and pak files as they are already accounted for. + if (zip_info.filename.endswith('.so') + or zip_info.filename.endswith('.pak')): + continue + apk_symbols.append(models.Symbol( + models.SECTION_OTHER, zip_info.compress_size, + full_name=zip_info.filename)) + overhead_size = os.path.getsize(apk_path) - zip_info_total + apk_symbols.append(models.Symbol( + models.SECTION_OTHER, overhead_size, + full_name='APK zip overhead')) + prev = section_sizes.setdefault(models.SECTION_OTHER, 0) + section_sizes[models.SECTION_OTHER] = prev + sum(s.size for s in apk_symbols) + return apk_symbols + + +def _FindPakSymbolsFromApk(apk_path, output_directory): + with zipfile.ZipFile(apk_path) as z: + pak_zip_infos = (f for f in z.infolist() if f.filename.endswith('.pak')) + apk_info_name = os.path.basename(apk_path) + '.pak.info' + pak_info_path = os.path.join(output_directory, 'size-info', apk_info_name) + res_info = _ParsePakInfoFile(pak_info_path) + symbols_by_id = {} + for zip_info in pak_zip_infos: + contents = data_pack.ReadDataPackFromString(z.read(zip_info)) + compression_ratio = float(zip_info.compress_size) / zip_info.file_size + _ComputePakFileSymbols( + os.path.relpath(zip_info.filename, output_directory), contents, + res_info, symbols_by_id, expected_size=zip_info.compress_size, + compression_ratio=compression_ratio) + return symbols_by_id + + +def _FindPakSymbolsFromFiles(pak_files, pak_info_path, output_directory): + """Uses files from args to find and add pak symbols.""" + res_info = _ParsePakInfoFile(pak_info_path) + symbols_by_id = {} + for pak_file_path in pak_files: + with open(pak_file_path, 'r') as f: + contents = data_pack.ReadDataPackFromString(f.read()) + _ComputePakFileSymbols( + os.path.relpath(pak_file_path, output_directory), contents, res_info, + symbols_by_id, expected_size=os.path.getsize(pak_file_path)) + return symbols_by_id + + +def _CalculateElfOverhead(section_sizes, elf_path): + if elf_path: + section_sizes_total_without_bss = sum( + s for k, s in section_sizes.iteritems() if k != models.SECTION_BSS) + elf_overhead_size = ( + os.path.getsize(elf_path) - section_sizes_total_without_bss) + assert elf_overhead_size >= 0, ( + 'Negative ELF overhead {}'.format(elf_overhead_size)) + return elf_overhead_size + return 0 + + +def CreateSectionSizesAndSymbols( + map_path=None, tool_prefix=None, output_directory=None, elf_path=None, + apk_path=None, track_string_literals=True, metadata=None, + apk_elf_result=None, pak_files=None, pak_info_file=None): + """Creates sections sizes and symbols for a SizeInfo. + + Args: + map_path: Path to the linker .map(.gz) file to parse. + elf_path: Path to the corresponding unstripped ELF file. Used to find symbol + aliases and inlined functions. Can be None. + tool_prefix: Prefix for c++filt & nm (required). + output_directory: Build output directory. If None, source_paths and symbol + alias information will not be recorded. + track_string_literals: Whether to break down "** merge string" sections into + smaller symbols (requires output_directory). + """ + source_mapper = None + elf_object_paths = None + if output_directory: + # Start by finding the elf_object_paths, so that nm can run on them while + # the linker .map is being parsed. + logging.info('Parsing ninja files.') + source_mapper, elf_object_paths = ninja_parser.Parse( + output_directory, elf_path) + logging.debug('Parsed %d .ninja files.', source_mapper.parsed_file_count) + assert not elf_path or elf_object_paths, ( + 'Failed to find link command in ninja files for ' + + os.path.relpath(elf_path, output_directory)) + + section_sizes, raw_symbols = _ParseElfInfo( + map_path, elf_path, tool_prefix, output_directory, track_string_literals, + elf_object_paths) + elf_overhead_size = _CalculateElfOverhead(section_sizes, elf_path) + + pak_symbols_by_id = None + if apk_path: + pak_symbols_by_id = _FindPakSymbolsFromApk(apk_path, output_directory) + section_sizes, elf_overhead_size = _ParseApkElfSectionSize( + section_sizes, metadata, apk_elf_result) + raw_symbols.extend(_ParseApkOtherSymbols(section_sizes, apk_path)) + elif pak_files and pak_info_file: + pak_symbols_by_id = _FindPakSymbolsFromFiles( + pak_files, pak_info_file, output_directory) + + if elf_path: + elf_overhead_symbol = models.Symbol( + models.SECTION_OTHER, elf_overhead_size, + full_name='ELF file overhead') + prev = section_sizes.setdefault(models.SECTION_OTHER, 0) + section_sizes[models.SECTION_OTHER] = prev + elf_overhead_size + raw_symbols.append(elf_overhead_symbol) + + if pak_symbols_by_id: + object_paths = (p for p in source_mapper.IterAllPaths() if p.endswith('.o')) + pak_raw_symbols = _ParsePakSymbols( + section_sizes, object_paths, output_directory, pak_symbols_by_id) + raw_symbols.extend(pak_raw_symbols) + + _ExtractSourcePathsAndNormalizeObjectPaths(raw_symbols, source_mapper) + logging.info('Converting excessive aliases into shared-path symbols') + _CompactLargeAliasesIntoSharedSymbols(raw_symbols) + return section_sizes, raw_symbols + + +def CreateSizeInfo( + section_sizes, raw_symbols, metadata=None, normalize_names=True): + """Performs operations on all symbols and creates a SizeInfo object.""" + logging.debug('Sorting %d symbols', len(raw_symbols)) + raw_symbols.sort(key=lambda s: ( + s.IsPak(), s.IsBss(), s.section_name, s.address)) + logging.info('Processed %d symbols', len(raw_symbols)) # Padding not really required, but it is useful to check for large padding and # log a warning. @@ -542,14 +937,7 @@ if normalize_names: _NormalizeNames(raw_symbols) - logging.info('Processed %d symbols', len(raw_symbols)) - size_info = models.SizeInfo(section_sizes, raw_symbols) - - if logging.getLogger().isEnabledFor(logging.INFO): - for line in describe.DescribeSizeInfoCoverage(size_info): - logging.info(line) - logging.info('Recorded info for %d symbols', len(size_info.raw_symbols)) - return size_info + return models.SizeInfo(section_sizes, raw_symbols, metadata=metadata) def _DetectGitRevision(directory): @@ -563,7 +951,7 @@ def BuildIdFromElf(elf_path, tool_prefix): - args = [tool_prefix + 'readelf', '-n', elf_path] + args = [path_util.GetReadElfPath(tool_prefix), '-n', elf_path] stdout = subprocess.check_output(args) match = re.search(r'Build ID: (\w+)', stdout) assert match, 'Build ID not found from running: ' + ' '.join(args) @@ -571,7 +959,7 @@ def _SectionSizesFromElf(elf_path, tool_prefix): - args = [tool_prefix + 'readelf', '-S', '--wide', elf_path] + args = [path_util.GetReadElfPath(tool_prefix), '-S', '--wide', elf_path] stdout = subprocess.check_output(args) section_sizes = {} # Matches [ 2] .hash HASH 00000000006681f0 0001f0 003154 04 A 3 0 8 @@ -582,7 +970,7 @@ def _ArchFromElf(elf_path, tool_prefix): - args = [tool_prefix + 'readelf', '-h', elf_path] + args = [path_util.GetReadElfPath(tool_prefix), '-h', elf_path] stdout = subprocess.check_output(args) machine = re.search('Machine:\s*(.+)', stdout).group(1) if machine == 'Intel 80386': @@ -609,6 +997,11 @@ return ["%s=%s" % x for x in sorted(args.iteritems())] +def _DetectLinkerName(map_path): + with _OpenMaybeGz(map_path) as map_file: + return linker_map_parser.DetectLinkerNameFromMapFileHeader(next(map_file)) + + def _ElfInfoFromApk(apk_path, apk_so_path, tool_prefix): """Returns a tuple of (build_id, section_sizes).""" with zipfile.ZipFile(apk_path) as apk, \ @@ -617,7 +1010,8 @@ f.flush() build_id = BuildIdFromElf(f.name, tool_prefix) section_sizes = _SectionSizesFromElf(f.name, tool_prefix) - return build_id, section_sizes + elf_overhead_size = _CalculateElfOverhead(section_sizes, f.name) + return build_id, section_sizes, elf_overhead_size def AddArguments(parser): @@ -633,6 +1027,11 @@ help='Path to input .map(.gz) file. Defaults to ' '{{elf_file}}.map(.gz)?. If given without ' '--elf-file, no size metadata will be recorded.') + parser.add_argument('--pak-file', action='append', + help='Paths to pak files.') + parser.add_argument('--pak-info-file', + help='This file should contain all ids found in the pak ' + 'files that have been passed in.') parser.add_argument('--no-source-paths', action='store_true', help='Do not use .ninja files to map ' 'object_path -> source_path') @@ -640,6 +1039,10 @@ help='Path prefix for c++filt, nm, readelf.') parser.add_argument('--output-directory', help='Path to the root build directory.') + parser.add_argument('--no-string-literals', dest='track_string_literals', + default=True, action='store_false', + help='Disable breaking down "** merge strings" into more ' + 'granular symbols.') def Run(args, parser): @@ -652,9 +1055,9 @@ any_input = apk_path or elf_path or map_path if not any_input: parser.error('Most pass at least one of --apk-file, --elf-file, --map-file') - lazy_paths = paths.LazyPaths(tool_prefix=args.tool_prefix, - output_directory=args.output_directory, - any_path_within_output_directory=any_input) + output_directory_finder = path_util.OutputDirectoryFinder( + value=args.output_directory, + any_path_within_output_directory=any_input) if apk_path: with zipfile.ZipFile(apk_path) as z: lib_infos = [f for f in z.infolist() @@ -664,9 +1067,9 @@ # secondary architectures. apk_so_path = max(lib_infos, key=lambda x:x.file_size).filename logging.debug('Sub-apk path=%s', apk_so_path) - if not elf_path and lazy_paths.output_directory: + if not elf_path and output_directory_finder.Tentative(): elf_path = os.path.join( - lazy_paths.output_directory, 'lib.unstripped', + output_directory_finder.Tentative(), 'lib.unstripped', os.path.basename(apk_so_path.replace('crazy.', ''))) logging.debug('Detected --elf-file=%s', elf_path) @@ -682,50 +1085,41 @@ 'is_official_build=true, or use --map-file to point me a ' 'linker map file.') - tool_prefix = lazy_paths.VerifyToolPrefix() + linker_name = _DetectLinkerName(map_path) + tool_prefix_finder = path_util.ToolPrefixFinder( + value=args.tool_prefix, + output_directory_finder=output_directory_finder, + linker_name=linker_name) + tool_prefix = tool_prefix_finder.Finalized() output_directory = None if not args.no_source_paths: - output_directory = lazy_paths.VerifyOutputDirectory() + output_directory = output_directory_finder.Finalized() metadata = CreateMetadata(map_path, elf_path, apk_path, tool_prefix, output_directory) + + apk_elf_result = None if apk_path and elf_path: # Extraction takes around 1 second, so do it in parallel. apk_elf_result = concurrent.ForkAndCall( _ElfInfoFromApk, (apk_path, apk_so_path, tool_prefix)) - size_info = CreateSizeInfo(map_path, elf_path, tool_prefix, output_directory, - normalize_names=False) + section_sizes, raw_symbols = CreateSectionSizesAndSymbols( + map_path=map_path, tool_prefix=tool_prefix, elf_path=elf_path, + apk_path=apk_path, output_directory=output_directory, + track_string_literals=args.track_string_literals, + metadata=metadata, apk_elf_result=apk_elf_result, + pak_files=args.pak_file, pak_info_file=args.pak_info_file) + size_info = CreateSizeInfo( + section_sizes, raw_symbols, metadata=metadata, normalize_names=False) - if metadata: - size_info.metadata = metadata - - if apk_path: - logging.debug('Extracting section sizes from .so within .apk') - unstripped_section_sizes = size_info.section_sizes - apk_build_id, size_info.section_sizes = apk_elf_result.get() - assert apk_build_id == metadata[models.METADATA_ELF_BUILD_ID], ( - 'BuildID for %s within %s did not match the one at %s' % - (apk_so_path, apk_path, elf_path)) - - packed_section_name = None - architecture = metadata[models.METADATA_ELF_ARCHITECTURE] - # Packing occurs enabled only arm32 & arm64. - if architecture == 'arm': - packed_section_name = '.rel.dyn' - elif architecture == 'arm64': - packed_section_name = '.rela.dyn' - - if packed_section_name: - logging.debug('Recording size of unpacked relocations') - if packed_section_name not in size_info.section_sizes: - logging.warning('Packed section not present: %s', packed_section_name) - else: - size_info.section_sizes['%s (unpacked)' % packed_section_name] = ( - unstripped_section_sizes.get(packed_section_name)) - + if logging.getLogger().isEnabledFor(logging.INFO): + for line in describe.DescribeSizeInfoCoverage(size_info): + logging.info(line) + logging.info('Recorded info for %d symbols', len(size_info.raw_symbols)) logging.info('Recording metadata: \n %s', '\n '.join(describe.DescribeMetadata(size_info.metadata))) logging.info('Saving result to %s', args.size_file) file_format.SaveSizeInfo(size_info, args.size_file) - logging.info('Done') + size_in_mb = os.path.getsize(args.size_file) / 1024.0 / 1024.0 + logging.info('Done. File size is %.2fMiB.', size_in_mb)
diff --git a/tools/binary_size/libsupersize/canned_queries.py b/tools/binary_size/libsupersize/canned_queries.py index 2a5411e..ce4e46d 100644 --- a/tools/binary_size/libsupersize/canned_queries.py +++ b/tools/binary_size/libsupersize/canned_queries.py
@@ -13,14 +13,14 @@ self.groups = [] def Add(self, name, group): - logging.debug('Computed %s', name) + logging.debug('Computed %s (%d syms)', name, len(group)) sorted_group = group.Sorted() sorted_group.SetName(name) self.groups.append(sorted_group) return group.Inverted() def Finalize(self, remaining): - self.groups.sort(key=lambda s:(s.name.startswith('Other'), -s.pss)) + self.groups.sort(key=lambda s:(s.name.startswith('Other'), -abs(s.pss))) if remaining: stars = remaining.Filter(lambda s: s.name.startswith('*')) if stars: @@ -41,9 +41,23 @@ # Put things that filter out a lot of symbols at the beginning where possible # to optimize speed. symbols = g.Add('WebRTC', symbols.WhereMatches(r'(?i)webrtc')) - symbols = g.Add('Skia', symbols.Filter(lambda s: 'skia/' in s.source_path)) - symbols = g.Add('V8', symbols.Filter( + symbols = g.Add('v8', symbols.Filter( lambda s: s.source_path.startswith('v8/'))) + symbols = g.Add('Skia', symbols.Filter(lambda s: 'skia/' in s.source_path)) + symbols = g.Add('net', symbols.Filter( + lambda s: s.source_path.startswith('net/'))) + symbols = g.Add('media', symbols.Filter( + lambda s: s.source_path.startswith('media/'))) + symbols = g.Add('gpu', symbols.Filter( + lambda s: s.source_path.startswith('gpu/'))) + symbols = g.Add('cc', symbols.Filter( + lambda s: s.source_path.startswith('cc/'))) + symbols = g.Add('base', symbols.Filter( + lambda s: s.source_path.startswith('base/'))) + symbols = g.Add('viz', symbols.Filter( + lambda s: s.source_path.startswith('components/viz'))) + symbols = g.Add('ui/gfx', symbols.Filter( + lambda s: s.source_path.startswith('ui/gfx/'))) # Next, put non-regex queries, since they're a bit faster. symbols = g.Add('ICU', symbols.Filter(lambda s: '/icu/' in s.source_path)) @@ -99,6 +113,8 @@ # than having them be inline. symbols = g.Add('RegisterJNI', symbols.WhereFullNameMatches( r'Register.*JNIEnv\*\)|RegisteredMethods$')) + symbols = g.Add('gl_bindings_autogen', + symbols.WherePathMatches('gl_bindings_autogen')) symbols = symbols.WhereSourceIsGenerated() symbols = g.Add('Protocol Buffers', symbols.Filter(lambda s: ( @@ -118,6 +134,14 @@ 'WebKit/Source/core' in s.object_path))) symbols = g.Add('Blink (Other)', symbols.Filter(lambda s: ( 'WebKit' in s.object_path or 'blink/' in s.object_path))) + symbols = g.Add('prepopulated_engines.cc', symbols.Filter(lambda s: ( + 'prepopulated_engines' in s.object_path))) + symbols = g.Add('Metrics-related code', symbols.Filter(lambda s: ( + '/metrics/' in s.object_path))) + symbols = g.Add('gpu_driver_bug_list_autogen.cc', symbols.Filter(lambda s: ( + 'gpu_driver_bug_list' in s.object_path))) + symbols = g.Add('components/policy', symbols.Filter(lambda s: ( + 'components/policy' in s.object_path))) return g.Finalize(symbols) @@ -128,10 +152,15 @@ def __init__(self, size_infos): self._size_infos = size_infos - def _SymbolsArg(self, arg): + def _SymbolsArg(self, arg, native_only=False, pak_only=False): arg = arg if arg is not None else self._size_infos[-1] - if isinstance(arg, models.SizeInfo): - arg = arg.symbols + if isinstance(arg, models.BaseSizeInfo): + if native_only: + arg = arg.native_symbols + elif pak_only: + arg = arg.pak_symbols + else: + arg = arg.symbols return arg def CategorizeGenerated(self, symbols=None): @@ -144,13 +173,24 @@ def TemplatesByName(self, symbols=None, depth=0): """Lists C++ templates grouped by name.""" - symbols = self._SymbolsArg(symbols) + symbols = self._SymbolsArg(symbols, native_only=True) # Call Sorted() twice so that subgroups will be sorted. # TODO(agrieve): Might be nice to recursively GroupedByName() on these. return symbols.WhereIsTemplate().Sorted().GroupedByName(depth).Sorted() def StaticInitializers(self, symbols=None): """Lists Static Initializers.""" - symbols = self._SymbolsArg(symbols) + symbols = self._SymbolsArg(symbols, native_only=True) # GCC generates "_GLOBAL__" symbols. Clang generates "startup". return symbols.WhereNameMatches('^startup$|^_GLOBAL__') + + def LargeFiles(self, symbols=None, min_size=50 * 1024): + """Lists source files that are larger than a certain size (default 50kb).""" + symbols = self._SymbolsArg(symbols) + return symbols.GroupedByPath(fallback=None).WherePssBiggerThan( + min_size).Sorted() + + def PakByPath(self, symbols=None): + """Groups .pak.* symbols by path.""" + symbols = self._SymbolsArg(symbols, pak_only=True) + return symbols.WhereIsPak().Sorted().GroupedByPath().Sorted()
diff --git a/tools/binary_size/libsupersize/concurrent.py b/tools/binary_size/libsupersize/concurrent.py index 416a5016..104308c 100644 --- a/tools/binary_size/libsupersize/concurrent.py +++ b/tools/binary_size/libsupersize/concurrent.py
@@ -4,7 +4,9 @@ """Helpers related to multiprocessing.""" +import __builtin__ # __builtins__ does not have exception types. import atexit +import itertools import logging import multiprocessing import multiprocessing.dummy @@ -22,6 +24,9 @@ _is_child_process = False _silence_exceptions = False +# Used to pass parameters to forked processes without pickling. +_fork_params = None + class _ImmediateResult(object): def __init__(self, value): @@ -42,8 +47,14 @@ class _ExceptionWrapper(object): """Used to marshal exception messages back to main process.""" - def __init__(self, msg): + def __init__(self, msg, exception_type=None): self.msg = msg + self.exception_type = exception_type + + def MaybeThrow(self): + if self.exception_type: + raise getattr(__builtin__, self.exception_type)( + 'Originally caused by: ' + self.msg) class _FuncWrapper(object): @@ -53,13 +64,19 @@ _is_child_process = True self._func = func - def __call__(self, args, _=None): + def __call__(self, index, _=None): try: - return self._func(*args) - except: # pylint: disable=bare-except + return self._func(*_fork_params[index]) + except Exception, e: + # Only keep the exception type for builtin exception types or else risk + # further marshalling exceptions. + exception_type = None + if type(e).__name__ in dir(__builtin__): + exception_type = type(e).__name__ # multiprocessing is supposed to catch and return exceptions automatically # but it doesn't seem to work properly :(. - logging.warning('CAUGHT EXCEPTION') + return _ExceptionWrapper(traceback.format_exc(), exception_type) + except: # pylint: disable=bare-except return _ExceptionWrapper(traceback.format_exc()) @@ -127,14 +144,20 @@ if isinstance(value, _ExceptionWrapper): global _silence_exceptions if not _silence_exceptions: + value.MaybeThrow() _silence_exceptions = True logging.error('Subprocess raised an exception:\n%s', value.msg) sys.exit(1) -def _MakeProcessPool(*args): +def _MakeProcessPool(job_params): global _all_pools - ret = multiprocessing.Pool(*args) + global _fork_params + assert _fork_params is None + pool_size = min(len(job_params), multiprocessing.cpu_count()) + _fork_params = job_params + ret = multiprocessing.Pool(pool_size) + _fork_params = None if _all_pools is None: _all_pools = [] atexit.register(_TerminatePools) @@ -152,8 +175,8 @@ pool = None result = _ImmediateResult(func(*args)) else: - pool = _MakeProcessPool(1) - result = pool.apply_async(_FuncWrapper(func), (args,)) + pool = _MakeProcessPool([args]) + result = pool.apply_async(_FuncWrapper(func), (0,)) pool.close() return _WrappedResult(result, pool=pool, decode_func=decode_func) @@ -163,14 +186,18 @@ Yields the return values as they come in. """ - pool_size = min(len(arg_tuples), multiprocessing.cpu_count()) + arg_tuples = list(arg_tuples) + if not len(arg_tuples): + return + if DISABLE_ASYNC: for args in arg_tuples: yield func(*args) return - pool = _MakeProcessPool(pool_size) + + pool = _MakeProcessPool(arg_tuples) wrapped_func = _FuncWrapper(func) - for result in pool.imap_unordered(wrapped_func, arg_tuples): + for result in pool.imap_unordered(wrapped_func, xrange(len(arg_tuples))): _CheckForException(result) yield result pool.close() @@ -189,7 +216,12 @@ def EncodeDictOfLists(d, key_transform=None): - """Serializes a dict where values are lists of strings.""" + """Serializes a dict where values are lists of strings. + + Does not support '' as keys, nor [''] as values. + """ + assert '' not in d + assert [''] not in d.itervalues() keys = iter(d) if key_transform: keys = (key_transform(k) for k in keys) @@ -198,13 +230,33 @@ return keys, values -def DecodeDictOfLists(encoded_keys, encoded_values, key_transform=None): +def JoinEncodedDictOfLists(encoded_values): + assert isinstance(encoded_values, list), 'Does not work with generators' + return ('\x01'.join(x[0] for x in encoded_values if x[0]), + '\x01'.join(x[1] for x in encoded_values if x[1])) + + +def DecodeDictOfLists(encoded_keys_and_values, key_transform=None, + value_transform=None): """Deserializes a dict where values are lists of strings.""" + encoded_keys, encoded_values = encoded_keys_and_values + if not encoded_keys: + return {} keys = encoded_keys.split('\x01') if key_transform: keys = (key_transform(k) for k in keys) - values = encoded_values.split('\x01') + encoded_lists = encoded_values.split('\x01') ret = {} - for i, key in enumerate(keys): - ret[key] = values[i].split('\x02') + for key, encoded_list in itertools.izip(keys, encoded_lists): + if not encoded_list: + values = [] + else: + values = encoded_list.split('\x02') + if value_transform: + for i in xrange(len(values)): + values[i] = value_transform(values[i]) + ret[key] = values return ret + + +EMPTY_ENCODED_DICT = EncodeDictOfLists({})
diff --git a/tools/binary_size/libsupersize/concurrent_test.py b/tools/binary_size/libsupersize/concurrent_test.py new file mode 100755 index 0000000..68f1fb8 --- /dev/null +++ b/tools/binary_size/libsupersize/concurrent_test.py
@@ -0,0 +1,131 @@ +#!/usr/bin/env python +# Copyright 2017 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 threading +import unittest + +import concurrent + + +def _ForkTestHelper(test_instance, parent_pid, arg1, arg2, _=None): + test_instance.assertNotEquals(os.getpid(), parent_pid) + return arg1 + arg2 + + +class Unpicklable(object): + """Ensures that pickle() is not called on parameters.""" + def __getstate__(self): + raise AssertionError('Tried to pickle') + + +class ConcurrentTest(unittest.TestCase): + def testEncodeDictOfLists_Empty(self): + test_dict = {} + encoded = concurrent.EncodeDictOfLists(test_dict) + decoded = concurrent.DecodeDictOfLists(encoded) + self.assertEquals(test_dict, decoded) + + def testEncodeDictOfLists_EmptyValue(self): + test_dict = {'foo': []} + encoded = concurrent.EncodeDictOfLists(test_dict) + decoded = concurrent.DecodeDictOfLists(encoded) + self.assertEquals(test_dict, decoded) + + def testEncodeDictOfLists_AllStrings(self): + test_dict = {'foo': ['a', 'b', 'c'], 'foo2': ['a', 'b']} + encoded = concurrent.EncodeDictOfLists(test_dict) + decoded = concurrent.DecodeDictOfLists(encoded) + self.assertEquals(test_dict, decoded) + + def testEncodeDictOfLists_KeyTransform(self): + test_dict = {0: ['a', 'b', 'c'], 9: ['a', 'b']} + encoded = concurrent.EncodeDictOfLists(test_dict, key_transform=str) + decoded = concurrent.DecodeDictOfLists(encoded, key_transform=int) + self.assertEquals(test_dict, decoded) + + def testEncodeDictOfLists_ValueTransform(self): + test_dict = {'a': ['0', '1', '2'], 'b': ['3', '4']} + expected = {'a': [0, 1, 2], 'b': [3, 4]} + encoded = concurrent.EncodeDictOfLists(test_dict) + decoded = concurrent.DecodeDictOfLists(encoded, value_transform=int) + self.assertEquals(expected, decoded) + + def testEncodeDictOfLists_Join_Empty(self): + test_dict1 = {} + test_dict2 = {} + expected = {} + encoded1 = concurrent.EncodeDictOfLists(test_dict1) + encoded2 = concurrent.EncodeDictOfLists(test_dict2) + encoded = concurrent.JoinEncodedDictOfLists([encoded1, encoded2]) + decoded = concurrent.DecodeDictOfLists(encoded) + self.assertEquals(expected, decoded) + + def testEncodeDictOfLists_Join_Singl(self): + test_dict1 = {'key1': ['a']} + encoded1 = concurrent.EncodeDictOfLists(test_dict1) + encoded = concurrent.JoinEncodedDictOfLists([encoded1]) + decoded = concurrent.DecodeDictOfLists(encoded) + self.assertEquals(test_dict1, decoded) + + def testEncodeDictOfLists_JoinMultiple(self): + test_dict1 = {'key1': ['a']} + test_dict2 = {'key2': ['b']} + expected = {'key1': ['a'], 'key2': ['b']} + encoded1 = concurrent.EncodeDictOfLists(test_dict1) + encoded2 = concurrent.EncodeDictOfLists({}) + encoded3 = concurrent.EncodeDictOfLists(test_dict2) + encoded = concurrent.JoinEncodedDictOfLists([encoded1, encoded2, encoded3]) + decoded = concurrent.DecodeDictOfLists(encoded) + self.assertEquals(expected, decoded) + + def testCallOnThread(self): + main_thread = threading.current_thread() + def callback(arg1, arg2): + self.assertEquals(1, arg1) + self.assertEquals(2, arg2) + my_thread = threading.current_thread() + self.assertNotEquals(my_thread, main_thread) + return 3 + + result = concurrent.CallOnThread(callback, 1, arg2=2) + self.assertEquals(3, result.get()) + + def testForkAndCall_normal(self): + parent_pid = os.getpid() + result = concurrent.ForkAndCall( + _ForkTestHelper, (self, parent_pid, 1, 2, Unpicklable())) + self.assertEquals(3, result.get()) + + def testForkAndCall_exception(self): + parent_pid = os.getpid() + result = concurrent.ForkAndCall(_ForkTestHelper, (self, parent_pid, 1, 'a')) + self.assertRaises(TypeError, result.get) + + def testBulkForkAndCall_none(self): + results = concurrent.BulkForkAndCall(_ForkTestHelper, []) + self.assertEquals([], list(results)) + + def testBulkForkAndCall_few(self): + parent_pid = os.getpid() + results = concurrent.BulkForkAndCall(_ForkTestHelper, [ + (self, parent_pid, 1, 2, Unpicklable()), + (self, parent_pid, 3, 4)]) + self.assertEquals({3, 7}, set(results)) + + def testBulkForkAndCall_many(self): + parent_pid = os.getpid() + args = [(self, parent_pid, 1, 2, Unpicklable())] * 100 + results = concurrent.BulkForkAndCall(_ForkTestHelper, args) + self.assertEquals([3] * 100, list(results)) + + def testBulkForkAndCall_exception(self): + parent_pid = os.getpid() + results = concurrent.BulkForkAndCall(_ForkTestHelper, [ + (self, parent_pid, 1, 'a')]) + self.assertRaises(TypeError, results.next) + +if __name__ == '__main__': + unittest.main()
diff --git a/tools/binary_size/libsupersize/console.py b/tools/binary_size/libsupersize/console.py index bd0cb15..c6756e5 100644 --- a/tools/binary_size/libsupersize/console.py +++ b/tools/binary_size/libsupersize/console.py
@@ -23,7 +23,8 @@ import file_format import match_util import models -import paths +import nm +import path_util # Number of lines before using less for Print(). @@ -50,8 +51,7 @@ if use_pager is None and sys.stdout.isatty(): # Does not take into account line-wrapping... Oh well. first_lines = list(itertools.islice(lines, _THRESHOLD_FOR_PAGER)) - if len(first_lines) == _THRESHOLD_FOR_PAGER: - use_pager = True + use_pager = len(first_lines) == _THRESHOLD_FOR_PAGER lines = itertools.chain(first_lines, lines) if use_pager: @@ -67,12 +67,13 @@ class _Session(object): _readline_initialized = False - def __init__(self, size_infos, lazy_paths): + def __init__(self, size_infos, output_directory_finder, tool_prefix_finder): self._printed_variables = [] self._variables = { 'Print': self._PrintFunc, 'Csv': self._CsvFunc, 'Diff': self._DiffFunc, + 'ReadStringLiterals': self._ReadStringLiterals, 'Disassemble': self._DisassembleFunc, 'ExpandRegex': match_util.ExpandRegexIdentifierPlaceholder, 'ShowExamples': self._ShowExamplesFunc, @@ -80,7 +81,8 @@ 'printed': self._printed_variables, 'models': models, } - self._lazy_paths = lazy_paths + self._output_directory_finder = output_directory_finder + self._tool_prefix_finder = tool_prefix_finder self._size_infos = size_infos self._disassemble_prefix_len = None @@ -90,6 +92,56 @@ for i, size_info in enumerate(size_infos): self._variables['size_info%d' % (i + 1)] = size_info + def _ReadStringLiterals(self, thing=None, all_rodata=False, elf_path=None): + """Returns a list of (symbol, string value) for all string literal symbols. + + E.g.: + # Print sorted list of all string literals: + Print(sorted(x[1] for x in ReadStringLiterals())) + Args: + thing: Can be a Symbol, iterable of symbols, or SizeInfo. + Defaults to the current SizeInfo. + all_rodata: Assume every symbol within .rodata that ends in a \0 is a + string literal. + elf_path: Path to the executable containing the symbol. Required only + when auto-detection fails. + """ + if thing is None: + thing = self._size_infos[-1] + if isinstance(thing, models.SizeInfo): + thing = thing.raw_symbols.IterUniqueSymbols() + elif isinstance(thing, models.BaseSymbol): + thing = thing.IterLeafSymbols() + + thing, thing_clone = itertools.tee(thing) + first_sym = next(thing_clone, None) + if not first_sym: + return [] + size_info = self._SizeInfoForSymbol(first_sym) + tool_prefix = self._ToolPrefixForSymbol(size_info) + elf_path = self._ElfPathForSymbol( + size_info, tool_prefix, elf_path) + + address, offset, _ = nm.LookupElfRodataInfo(elf_path, tool_prefix) + adjust = offset - address + ret = [] + with open(elf_path, 'rb') as f: + for symbol in thing: + if symbol.section != 'r' or ( + not all_rodata and not symbol.IsStringLiteral()): + continue + f.seek(symbol.address + adjust) + data = f.read(symbol.size_without_padding) + # As of Oct 2017, there are ~90 symbols name .L.str(.##). These appear + # in the linker map file explicitly, and there doesn't seem to be a + # pattern as to which variables lose their kConstant name (the more + # common case), or which string literals don't get moved to + # ** merge strings (less common). + if symbol.IsStringLiteral() or ( + all_rodata and data and data[-1] == '\0'): + ret.append((symbol, data)) + return ret + def _DiffFunc(self, before=None, after=None, sort=True): """Diffs two SizeInfo objects. Returns a DeltaSizeInfo. @@ -102,17 +154,16 @@ after = after if after is not None else self._size_infos[1] ret = diff.Diff(before, after) if sort: - ret.symbols = ret.symbols.Sorted() + syms = ret.symbols # Triggers clustering. + logging.debug('Grouping') + # Group path aliases so that functions defined in headers will be sorted + # by their actual size rather than shown as many small symbols. + syms = syms.GroupedByAliases(same_name_only=True) + logging.debug('Sorting') + ret.symbols = syms.Sorted() + logging.debug('Diff complete') return ret - def _GetObjToPrint(self, obj=None): - if isinstance(obj, int): - obj = self._printed_variables[obj] - elif not self._printed_variables or self._printed_variables[-1] != obj: - if not isinstance(obj, models.SymbolGroup) or len(obj) > 0: - self._printed_variables.append(obj) - return obj if obj is not None else self._size_infos[-1] - def _PrintFunc(self, obj=None, verbose=False, summarize=True, recursive=False, use_pager=None, to_file=None): """Prints out the given Symbol / SymbolGroup / SizeInfo. @@ -120,9 +171,7 @@ For convenience, |obj| will be appended to the global "printed" list. Args: - obj: The object to be printed. Defaults to |size_infos[-1]|. Also accepts - an index into the |_printed_variables| array for showing previous - results. + obj: The object to be printed. verbose: Show more detailed output. summarize: If False, show symbols only (no headers / summaries). recursive: Print children of nested SymbolGroups. @@ -130,7 +179,8 @@ default is to automatically pipe when output is long. to_file: Rather than print to stdio, write to the given file. """ - obj = self._GetObjToPrint(obj) + if obj is not None: + self._printed_variables.append(obj) lines = describe.GenerateLines( obj, verbose=verbose, recursive=recursive, summarize=summarize, format_name='text') @@ -142,24 +192,23 @@ For convenience, |obj| will be appended to the global "printed" list. Args: - obj: The object to be printed as CSV. Defaults to |size_infos[-1]|. Also - accepts an index into the |_printed_variables| array for showing - previous results. + obj: The object to be printed as CSV. use_pager: Pipe output through `less`. Ignored when |obj| is a Symbol. default is to automatically pipe when output is long. to_file: Rather than print to stdio, write to the given file. """ - obj = self._GetObjToPrint(obj) + if obj is not None: + self._printed_variables.append(obj) lines = describe.GenerateLines(obj, verbose=verbose, recursive=False, format_name='csv') _WriteToStream(lines, use_pager=use_pager, to_file=to_file) - def _ElfPathAndToolPrefixForSymbol(self, size_info, elf_path): - tool_prefix = self._lazy_paths.tool_prefix + def _ToolPrefixForSymbol(self, size_info): + tool_prefix = self._tool_prefix_finder.Tentative() orig_tool_prefix = size_info.metadata.get(models.METADATA_TOOL_PREFIX) if orig_tool_prefix: - orig_tool_prefix = paths.FromSrcRootRelative(orig_tool_prefix) - if os.path.exists(orig_tool_prefix + 'objdump'): + orig_tool_prefix = path_util.FromSrcRootRelative(orig_tool_prefix) + if os.path.exists(path_util.GetObjDumpPath(orig_tool_prefix)): tool_prefix = orig_tool_prefix # TODO(agrieve): Would be even better to use objdump --info to check that @@ -167,7 +216,9 @@ assert tool_prefix is not None, ( 'Could not determine --tool-prefix. Possible fixes include setting ' '--tool-prefix, or setting --output-directory') + return tool_prefix + def _ElfPathForSymbol(self, size_info, tool_prefix, elf_path): def build_id_matches(elf_path): found_build_id = archive.BuildIdFromElf(elf_path, tool_prefix) expected_build_id = size_info.metadata.get(models.METADATA_ELF_BUILD_ID) @@ -178,11 +229,12 @@ if elf_path: paths_to_try.append(elf_path) else: - auto_lazy_paths = [ - paths.LazyPaths(any_path_within_output_directory=s.size_path) - for s in self._size_infos] - for lazy_paths in auto_lazy_paths + [self._lazy_paths]: - output_dir = lazy_paths.output_directory + auto_output_directory_finders = [ + path_util.OutputDirectoryFinder( + any_path_within_output_directory=s.size_path) + for s in self._size_infos] + [self._output_directory_finder] + for output_directory_finder in auto_output_directory_finders: + output_dir = output_directory_finder.Tentative() if output_dir: # Local build: File is located in output directory. paths_to_try.append( @@ -195,7 +247,7 @@ for i, elf_path in enumerate(paths_to_try): if build_id_matches(elf_path): - return elf_path, tool_prefix + return elf_path # Show an error only once all paths are tried. if i + 1 == len(paths_to_try): @@ -227,6 +279,12 @@ logging.warning('Found no source paths in objdump output.') return None + def _SizeInfoForSymbol(self, symbol): + for size_info in self._size_infos: + if symbol in size_info.raw_symbols: + return size_info + assert False, 'Symbol does not belong to a size_info.' + def _DisassembleFunc(self, symbol, elf_path=None, use_pager=None, to_file=None): """Shows objdump disassembly for the given symbol. @@ -237,20 +295,15 @@ when auto-detection fails. """ assert not symbol.IsGroup() - assert symbol.address and symbol.section_name == '.text' + assert symbol.address and symbol.section_name == models.SECTION_TEXT assert not symbol.IsDelta(), ('Cannot disasseble a Diff\'ed symbol. Try ' 'passing .before_symbol or .after_symbol.') - size_info = None - for size_info in self._size_infos: - if symbol in size_info.raw_symbols: - break - else: - assert False, 'Symbol does not belong to a size_info.' + size_info = self._SizeInfoForSymbol(symbol) + tool_prefix = self._ToolPrefixForSymbol(size_info) + elf_path = self._ElfPathForSymbol( + size_info, tool_prefix, elf_path) - elf_path, tool_prefix = self._ElfPathAndToolPrefixForSymbol( - size_info, elf_path) - - args = [tool_prefix + 'objdump', '--disassemble', '--source', + args = [path_util.GetObjDumpPath(tool_prefix), '--disassemble', '--source', '--line-numbers', '--demangle', '--start-address=0x%x' % symbol.address, '--stop-address=0x%x' % symbol.end_address, elf_path] @@ -260,10 +313,10 @@ self._disassemble_prefix_len = prefix_len if self._disassemble_prefix_len is not None: - output_directory = self._lazy_paths.output_directory + output_directory = self._output_directory_finder.Tentative() # Only matters for non-generated paths, so be lenient here. if output_directory is None: - output_directory = os.path.join(paths.SRC_ROOT, 'out', 'Release') + output_directory = os.path.join(path_util.SRC_ROOT, 'out', 'Release') if not os.path.exists(output_directory): os.makedirs(output_directory) @@ -292,6 +345,9 @@ '# Dump section info and all symbols in CSV format:', 'Csv(size_info)', '', + '# Print sorted list of all string literals:', + 'Print(sorted(x[1] for x in ReadStringLiterals()))', + '', '# Show two levels of .text, grouped by first two subdirectories', 'text_syms = size_info.symbols.WhereInSection("t")', 'by_path = text_syms.GroupedByPath(depth=2)', @@ -410,10 +466,13 @@ parser.error('All inputs must end with ".size"') size_infos = [archive.LoadAndPostProcessSizeInfo(p) for p in args.inputs] - lazy_paths = paths.LazyPaths(tool_prefix=args.tool_prefix, - output_directory=args.output_directory, - any_path_within_output_directory=args.inputs[0]) - session = _Session(size_infos, lazy_paths) + output_directory_finder = path_util.OutputDirectoryFinder( + value=args.output_directory, + any_path_within_output_directory=args.inputs[0]) + tool_prefix_finder = path_util.ToolPrefixFinder( + value=args.tool_prefix, + output_directory_finder=output_directory_finder) + session = _Session(size_infos, output_directory_finder, tool_prefix_finder) if args.query: logging.info('Running query from command-line.')
diff --git a/tools/binary_size/libsupersize/demangle.py b/tools/binary_size/libsupersize/demangle.py new file mode 100644 index 0000000..748bf7b3 --- /dev/null +++ b/tools/binary_size/libsupersize/demangle.py
@@ -0,0 +1,76 @@ +# Copyright 2017 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. + +"""Utilities for demangling C++ symbols.""" + +import collections +import logging +import subprocess + +import path_util + +def _DemangleNames(names, tool_prefix): + """Uses c++filt to demangle a list of names.""" + proc = subprocess.Popen([path_util.GetCppFiltPath(tool_prefix)], + stdin=subprocess.PIPE, stdout=subprocess.PIPE) + stdout = proc.communicate('\n'.join(names))[0] + assert proc.returncode == 0 + ret = stdout.splitlines() + if logging.getLogger().isEnabledFor(logging.INFO): + fail_count = sum(1 for s in ret if s.startswith('_Z')) + if fail_count: + logging.info('* Failed to demangle %d/%d items', fail_count, len(ret)) + return ret + + +def DemangleRemainingSymbols(raw_symbols, tool_prefix): + """Demangles any symbols that need it.""" + to_process = [s for s in raw_symbols if s.full_name.startswith('_Z')] + if not to_process: + return + + logging.info('Demangling %d symbols', len(to_process)) + names = _DemangleNames((s.full_name for s in to_process), tool_prefix) + for i, name in enumerate(names): + to_process[i].full_name = name + + +def DemangleSetsInDicts(key_to_names, tool_prefix): + """Demangles values as sets, and returns the result. + + |key_to_names| is a dict from key to sets (or lists) of mangled names. + """ + all_names = [] + for names in key_to_names.itervalues(): + all_names.extend(n for n in names if n.startswith('_Z')) + if not all_names: + return key_to_names + + logging.info('Demangling %d values', len(all_names)) + it = iter(_DemangleNames(all_names, tool_prefix)) + ret = {} + for key, names in key_to_names.iteritems(): + ret[key] = set(next(it) if n.startswith('_Z') else n for n in names) + assert(next(it, None) is None) + return ret + + +def DemangleKeysAndMergeLists(name_to_list, tool_prefix): + """Demangles keys of a dict of lists, and returns the result. + + Keys may demangle to a common name. When this happens, the corresponding lists + are merged in arbitrary order. + """ + keys = [key for key in name_to_list if key.startswith('_Z')] + if not keys: + return name_to_list + + logging.info('Demangling %d keys', len(keys)) + key_iter = iter(_DemangleNames(keys, tool_prefix)) + ret = collections.defaultdict(list) + for key, val in name_to_list.iteritems(): + ret[next(key_iter) if key.startswith('_Z') else key] += val + assert(next(key_iter, None) is None) + logging.info('* %d keys become %d keys' % (len(name_to_list), len(ret))) + return ret
diff --git a/tools/binary_size/libsupersize/describe.py b/tools/binary_size/libsupersize/describe.py index b3857b75..f303aae 100644 --- a/tools/binary_size/libsupersize/describe.py +++ b/tools/binary_size/libsupersize/describe.py
@@ -9,6 +9,7 @@ import csv import datetime import itertools +import math import time import models @@ -51,7 +52,7 @@ def _IncludeInTotals(section_name): - return section_name != '.bss' and '(' not in section_name + return section_name != models.SECTION_BSS and '(' not in section_name def _GetSectionSizeInfo(section_sizes): @@ -75,6 +76,58 @@ return (total_bytes, section_names) +class Histogram(object): + BUCKET_NAMES_FOR_SMALL_VALUES = {-1: '(-1,0)', 0: '{0}', 1: '(0,1)'} + + def __init__(self): + self.data = collections.defaultdict(int) + + # Input: (-8,-4], (-4,-2], (-2,-1], (-1,0), {0}, (0,1), [1,2), [2,4), [4,8). + # Output: -4, -3, -2, -1, 0, 1, 2, 3, 4. + @staticmethod + def _Bucket(v): + absv = abs(v) + if absv < 1: + return 0 if v == 0 else (-1 if v < 0 else 1) + mag = int(math.log(absv, 2.0)) + 2 + return mag if v > 0 else -mag + + @staticmethod + def _BucketName(k): + if abs(k) <= 1: + return Histogram.BUCKET_NAMES_FOR_SMALL_VALUES[k] + if k < 0: + return '(-{},-{}]'.format(1 << (-k - 1), 1 << (-k - 2)) + return '[{},{})'.format(1 << (k - 2), 1 << (k - 1)) + + def Add(self, v): + self.data[self._Bucket(v)] += 1 + + def Generate(self): + keys = sorted(self.data.keys()) + bucket_names = [self._BucketName(k) for k in keys] + bucket_values = [str(self.data[k]) for k in keys] + num_items = len(keys) + num_cols = 6 + num_rows = (num_items + num_cols - 1) / num_cols # Divide and round up. + # Needed for xrange to not throw due to step by 0. + if num_rows == 0: + return + # Spaces needed by items in each column, to align on ':'. + name_col_widths = [] + value_col_widths = [] + for i in xrange(0, num_items, num_rows): + name_col_widths.append(max(len(s) for s in bucket_names[i:][:num_rows])) + value_col_widths.append(max(len(s) for s in bucket_values[i:][:num_rows])) + + yield 'Histogram of symbols based on PSS:' + for r in xrange(num_rows): + row = zip(bucket_names[r::num_rows], name_col_widths, + bucket_values[r::num_rows], value_col_widths) + line = ' ' + ' '.join('{:>{}}: {:<{}}'.format(*t) for t in row) + yield line.rstrip() + + class Describer(object): def __init__(self): pass @@ -99,6 +152,10 @@ def _DescribeSymbol(self, sym, single_line=False): pass + def _DescribeIterable(self, obj): + for i, x in enumerate(obj): + yield '{}: {!r}'.format(i, x) + def GenerateLines(self, obj): if isinstance(obj, models.DeltaSizeInfo): return self._DescribeDeltaSizeInfo(obj) @@ -108,9 +165,11 @@ return self._DescribeDeltaSymbolGroup(obj) if isinstance(obj, models.SymbolGroup): return self._DescribeSymbolGroup(obj) - if isinstance(obj, models.Symbol) or isinstance(obj, models.DeltaSymbol): + if isinstance(obj, (models.Symbol, models.DeltaSymbol)): return self._DescribeSymbol(obj) - return (repr(obj),) + if hasattr(obj, '__iter__'): + return self._DescribeIterable(obj) + return iter((repr(obj),)) class DescriberText(Describer): @@ -245,10 +304,13 @@ # Apply this filter after calcualating size since an alias being removed # causes some symbols to be UNCHANGED, yet have pss != 0. - if group.IsDelta() and not self.verbose: + if group.IsDelta(): group = group.WhereDiffStatusIs(models.DIFF_STATUS_UNCHANGED).Inverted() if self.summarize: + histogram = Histogram() + for s in group: + histogram.Add(s.pss) unique_paths = set() for s in group.IterLeafSymbols(): # Ignore paths like foo/{shared}/2 @@ -256,15 +318,16 @@ unique_paths.add(s.object_path) if group.IsDelta(): - unique_part = 'aliases not grouped for diffs' + before_unique, after_unique = group.CountUniqueSymbols() + unique_part = '{:,} -> {:,} unique'.format(before_unique, after_unique) else: unique_part = '{:,} unique'.format(group.CountUniqueSymbols()) relevant_sections = [ s for s in models.SECTION_TO_SECTION_NAME.itervalues() if s in section_sizes] - if models.SECTION_NAME_MULTIPLE in relevant_sections: - relevant_sections.remove(models.SECTION_NAME_MULTIPLE) + if models.SECTION_MULTIPLE in relevant_sections: + relevant_sections.remove(models.SECTION_MULTIPLE) size_summary = ' '.join( '{}={:<10}'.format(k, _PrettySize(int(section_sizes[k]))) @@ -275,14 +338,15 @@ '{}={}'.format(models.SECTION_NAME_TO_SECTION[k], k) for k in relevant_sections if k in models.SECTION_NAME_TO_SECTION) - summary_desc = [ - 'Showing {:,} symbols ({}) with total pss: {} bytes'.format( - len(group), unique_part, int(total_size)), - size_summary, - 'Number of unique paths: {}'.format(len(unique_paths)), - '', - 'Section Legend: {}'.format(section_legend), - ] + summary_desc = itertools.chain( + ['Showing {:,} symbols ({}) with total pss: {} bytes'.format( + len(group), unique_part, int(total_size))], + histogram.Generate(), + [size_summary.rstrip()], + ['Number of unique paths: {}'.format(len(unique_paths))], + [''], + ['Section Legend: {}'.format(section_legend)], + ) else: summary_desc = () @@ -337,8 +401,13 @@ def _DescribeDeltaSymbolGroup(self, delta_group): if self.summarize: header_template = ('{} symbols added (+), {} changed (~), ' - '{} removed (-), {} unchanged ({})') - unchanged_msg = '=' if self.verbose else 'not shown' + '{} removed (-), {} unchanged (not shown)') + # Apply this filter since an alias being removed causes some symbols to be + # UNCHANGED, yet have pss != 0. + changed_delta_group = delta_group.WhereDiffStatusIs( + models.DIFF_STATUS_UNCHANGED).Inverted() + num_inc = sum(1 for s in changed_delta_group if s.pss > 0) + num_dec = sum(1 for s in changed_delta_group if s.pss < 0) counts = delta_group.CountsByDiffStatus() num_unique_before_symbols, num_unique_after_symbols = ( delta_group.CountUniqueSymbols()) @@ -347,8 +416,8 @@ counts[models.DIFF_STATUS_ADDED], counts[models.DIFF_STATUS_CHANGED], counts[models.DIFF_STATUS_REMOVED], - counts[models.DIFF_STATUS_UNCHANGED], - unchanged_msg), + counts[models.DIFF_STATUS_UNCHANGED]), + 'Of changed symbols, {} grew, {} shrank'.format(num_inc, num_dec), 'Number of unique symbols {} -> {} ({:+})'.format( num_unique_before_symbols, num_unique_after_symbols, num_unique_after_symbols - num_unique_before_symbols), @@ -363,11 +432,11 @@ return itertools.chain(diff_summary_desc, path_delta_desc, group_desc) def _DescribeDeltaSizeInfo(self, diff): - common_metadata = {k: v for k, v in diff.before_metadata.iteritems() - if diff.after_metadata[k] == v} - before_metadata = {k: v for k, v in diff.before_metadata.iteritems() + common_metadata = {k: v for k, v in diff.before.metadata.iteritems() + if diff.after.metadata[k] == v} + before_metadata = {k: v for k, v in diff.before.metadata.iteritems() if k not in common_metadata} - after_metadata = {k: v for k, v in diff.after_metadata.iteritems() + after_metadata = {k: v for k, v in diff.after.metadata.iteritems() if k not in common_metadata} metadata_desc = itertools.chain( ('Common Metadata:',), @@ -396,6 +465,8 @@ def DescribeSizeInfoCoverage(size_info): """Yields lines describing how accurate |size_info| is.""" for section, section_name in models.SECTION_TO_SECTION_NAME.iteritems(): + if section_name not in size_info.section_sizes: + continue expected_size = size_info.section_sizes[section_name] in_section = size_info.raw_symbols.WhereInSection(section_name) @@ -420,15 +491,22 @@ len(anonymous_syms), int(anonymous_syms.pss), _Divide(star_syms.size, in_section.size)) + if section == 'r': + string_literals = in_section.Filter(lambda s: s.IsStringLiteral()) + yield '* Contains {} string literals. Total size={}, padding={}'.format( + len(string_literals), string_literals.size_without_padding, + string_literals.padding) + aliased_symbols = in_section.Filter(lambda s: s.aliases) - if section == 't': - if len(aliased_symbols): - uniques = sum(1 for s in aliased_symbols.IterUniqueSymbols()) - yield ('* Contains {} aliases, mapped to {} unique addresses ' - '({} bytes)').format( - len(aliased_symbols), uniques, aliased_symbols.size) - else: - yield '* Contains 0 aliases' + if len(aliased_symbols): + uniques = sum(1 for s in aliased_symbols.IterUniqueSymbols()) + saved = sum(s.size_without_padding * (s.num_aliases - 1) + for s in aliased_symbols.IterUniqueSymbols()) + yield ('* Contains {} aliases, mapped to {} unique addresses ' + '({} bytes saved)').format( + len(aliased_symbols), uniques, saved) + else: + yield '* Contains 0 aliases' inlined_symbols = in_section.WhereObjectPathMatches('{shared}') if len(inlined_symbols): @@ -479,9 +557,8 @@ def _DescribeDeltaSymbolGroup(self, delta_group): yield self._RenderSymbolHeader(True); # Apply filter to remove UNCHANGED groups. - if not self.verbose: - delta_group = delta_group.WhereDiffStatusIs( - models.DIFF_STATUS_UNCHANGED).Inverted() + delta_group = delta_group.WhereDiffStatusIs( + models.DIFF_STATUS_UNCHANGED).Inverted() for sym in delta_group: yield self._RenderSymbolData(sym)
diff --git a/tools/binary_size/libsupersize/diff.py b/tools/binary_size/libsupersize/diff.py index 85d2341..793754b 100644 --- a/tools/binary_size/libsupersize/diff.py +++ b/tools/binary_size/libsupersize/diff.py
@@ -4,12 +4,26 @@ """Logic for diffing two SizeInfo objects.""" import collections +import logging import re import models -def _SymbolKey(symbol): +_STRIP_NUMBER_SUFFIX_PATTERN = re.compile(r'[.0-9]+$') +_NORMALIZE_STAR_SYMBOLS_PATTERN = re.compile(r'\s+\d+( \(.*\))?$') + + +def _ExactMatchKey(s): + # Remove numbers and periods for symbols defined by macros that use __line__ + # in names, or for linker symbols like ".L.ref.tmp.2". + name = _STRIP_NUMBER_SUFFIX_PATTERN.sub('', s.full_name) + # Use section rather than section_name since clang & gcc use + # .data.rel.ro vs. .data.rel.ro.local. + return s.section, name, s.object_path, s.size_without_padding + + +def _GoodMatchKey(symbol): """Returns a tuple that can be used to see if two Symbol are the same. Keys are not guaranteed to be unique within a SymbolGroup. When multiple @@ -18,56 +32,78 @@ Examples of symbols with shared keys: "** merge strings" - "** symbol gap 3", "** symbol gap 5" + "** symbol gap 3", "** symbol gap 5 (end of section)" "foo() [clone ##]" "CSWTCH.61", "CSWTCH.62" + ".L.ref.tmp.2", ".L.ref.tmp" "._468", "._467" ".L__unnamed_1193", ".L__unnamed_712" """ - name = symbol.full_name + name = _STRIP_NUMBER_SUFFIX_PATTERN.sub('', symbol.full_name) clone_idx = name.find(' [clone ') if clone_idx != -1: name = name[:clone_idx] if name.startswith('*'): # "symbol gap 3 (bar)" -> "symbol gaps" - name = re.sub(r'\s+\d+( \(.*\))?$', 's', name) + name = _NORMALIZE_STAR_SYMBOLS_PATTERN.sub('s', name) - # Use section rather than section_name since clang & gcc use - # .data.rel.ro vs .data.rel.ro.local. - if '.' not in name: - return (symbol.section, name) + return symbol.section, symbol.object_path, name - # Compiler or Linker generated symbol. - name = re.sub(r'[.0-9]', '', name) # Strip out all numbers and dots. - return (symbol.section, name, symbol.object_path) + +def _PoorMatchKey(symbol): + section, _, name = _GoodMatchKey(symbol) + return section, name + + +def _MatchSymbols(before, after, key_func, padding_by_section_name): + logging.debug('%s: Building symbol index', key_func.__name__) + before_symbols_by_key = collections.defaultdict(list) + for s in before: + before_symbols_by_key[key_func(s)].append(s) + + logging.debug('%s: Creating delta symbols', key_func.__name__) + unmatched_after = [] + delta_symbols = [] + for after_sym in after: + before_sym = before_symbols_by_key.get(key_func(after_sym)) + if before_sym: + before_sym = before_sym.pop(0) + # Padding tracked in aggregate, except for padding-only symbols. + if before_sym.size_without_padding != 0: + padding_by_section_name[before_sym.section_name] += ( + after_sym.padding_pss - before_sym.padding_pss) + delta_symbols.append(models.DeltaSymbol(before_sym, after_sym)) + else: + unmatched_after.append(after_sym) + + logging.debug('%s: Matched %d of %d symbols', key_func.__name__, + len(delta_symbols), len(after)) + + unmatched_before = [] + for syms in before_symbols_by_key.itervalues(): + unmatched_before.extend(syms) + return delta_symbols, unmatched_before, unmatched_after def _DiffSymbolGroups(before, after): - before_symbols_by_key = collections.defaultdict(list) - for s in before: - before_symbols_by_key[_SymbolKey(s)].append(s) - - delta_symbols = [] # For changed symbols, padding is zeroed out. In order to not lose the # information entirely, store it in aggregate. padding_by_section_name = collections.defaultdict(int) - # Create a DeltaSymbol for each after symbol. - for after_sym in after: - matching_syms = before_symbols_by_key.get(_SymbolKey(after_sym)) - before_sym = None - if matching_syms: - before_sym = matching_syms.pop(0) - # Padding tracked in aggregate, except for padding-only symbols. - if before_sym.size_without_padding: - padding_by_section_name[before_sym.section_name] += ( - after_sym.padding_pss - before_sym.padding_pss) - delta_symbols.append(models.DeltaSymbol(before_sym, after_sym)) + # Usually >90% of symbols are exact matches, so all of the time is spent in + # this first pass. + all_deltas, before, after = _MatchSymbols( + before, after, _ExactMatchKey, padding_by_section_name) + for key_func in (_GoodMatchKey, _PoorMatchKey): + delta_syms, before, after = _MatchSymbols( + before, after, key_func, padding_by_section_name) + all_deltas.extend(delta_syms) - # Create a DeltaSymbol for each unmatched before symbol. - for remaining_syms in before_symbols_by_key.itervalues(): - for before_sym in remaining_syms: - delta_symbols.append(models.DeltaSymbol(before_sym, None)) + logging.debug('Creating %d unmatched symbols', len(after) + len(before)) + for after_sym in after: + all_deltas.append(models.DeltaSymbol(None, after_sym)) + for before_sym in before: + all_deltas.append(models.DeltaSymbol(before_sym, None)) # Create a DeltaSymbol to represent the zero'd out padding of matched symbols. for section_name, padding in padding_by_section_name.iteritems(): @@ -75,9 +111,9 @@ after_sym = models.Symbol(section_name, padding, name="** aggregate padding of diff'ed symbols") after_sym.padding = padding - delta_symbols.append(models.DeltaSymbol(None, after_sym)) + all_deltas.append(models.DeltaSymbol(None, after_sym)) - return models.DeltaSymbolGroup(delta_symbols) + return models.DeltaSymbolGroup(all_deltas) def Diff(before, after): @@ -91,5 +127,4 @@ section_sizes[k] = v symbol_diff = _DiffSymbolGroups(before.raw_symbols, after.raw_symbols) - return models.DeltaSizeInfo(section_sizes, symbol_diff, before.metadata, - after.metadata) + return models.DeltaSizeInfo(before, after, section_sizes, symbol_diff)
diff --git a/tools/binary_size/libsupersize/file_format.py b/tools/binary_size/libsupersize/file_format.py index 223fe24..3ad8b53a 100644 --- a/tools/binary_size/libsupersize/file_format.py +++ b/tools/binary_size/libsupersize/file_format.py
@@ -6,7 +6,7 @@ import cStringIO import calendar -import collections +import contextlib import datetime import gzip import json @@ -43,18 +43,17 @@ _LogSize(file_obj, 'header') # For libchrome: 570 bytes. # Store a single copy of all paths and have them referenced by index. - # Using an OrderedDict makes the indices more repetitive (better compression). - path_tuples = collections.OrderedDict.fromkeys( - (s.object_path, s.source_path) for s in size_info.raw_symbols) - for i, key in enumerate(path_tuples): - path_tuples[key] = i - file_obj.write('%d\n' % len(path_tuples)) - file_obj.writelines('%s\t%s\n' % pair for pair in path_tuples) + unique_path_tuples = sorted(set( + (s.object_path, s.source_path) for s in size_info.raw_symbols)) + path_tuples = dict.fromkeys(unique_path_tuples) + for i, tup in enumerate(unique_path_tuples): + path_tuples[tup] = i + file_obj.write('%d\n' % len(unique_path_tuples)) + file_obj.writelines('%s\t%s\n' % pair for pair in unique_path_tuples) _LogSize(file_obj, 'paths') # For libchrome, adds 200kb. # Symbol counts by section. - by_section = size_info.raw_symbols.GroupedBySectionName().Sorted( - key=lambda s:(s[0].IsBss(), s[0].address, s.full_name)) + by_section = size_info.raw_symbols.GroupedBySectionName() file_obj.write('%s\n' % '\t'.join(g.name for g in by_section)) file_obj.write('%s\n' % '\t'.join(str(len(g)) for g in by_section)) @@ -151,6 +150,9 @@ flags_part = parts[1] full_name = parts[0] + # Use a bit less RAM by using the same instance for this common string. + if full_name == models.STRING_LITERAL_NAME: + full_name = models.STRING_LITERAL_NAME flags = int(flags_part, 16) if flags_part else 0 num_aliases = int(aliases_part, 16) if aliases_part else 0 @@ -185,10 +187,18 @@ size_path=size_path) +@contextlib.contextmanager +def _OpenGzipForWrite(path): + # Open in a way that doesn't set any gzip header fields. + with open(path, 'wb') as f: + with gzip.GzipFile(filename='', mode='wb', fileobj=f, mtime=0) as fz: + yield fz + + def SaveSizeInfo(size_info, path): """Saves |size_info| to |path}.""" if os.environ.get('SUPERSIZE_MEASURE_GZIP') == '1': - with gzip.open(path, 'wb') as f: + with _OpenGzipForWrite(path) as f: _SaveSizeInfoToFile(size_info, f) else: # It is seconds faster to do gzip in a separate step. 6s -> 3.5s. @@ -197,7 +207,7 @@ logging.debug('Serialization complete. Gzipping...') stringio.seek(0) - with gzip.open(path, 'wb') as f: + with _OpenGzipForWrite(path) as f: shutil.copyfileobj(stringio, f)
diff --git a/tools/binary_size/libsupersize/function_signature.py b/tools/binary_size/libsupersize/function_signature.py index fbd1e67..4fb954c 100644 --- a/tools/binary_size/libsupersize/function_signature.py +++ b/tools/binary_size/libsupersize/function_signature.py
@@ -77,9 +77,11 @@ space_idx = paren_idx - 6 while True: space_idx = _FindLastCharOutsideOfBrackets(name, ' ', space_idx) - # Special case: "operator new", and "operator<< <template>". + # Special cases: "operator new", "operator< <templ>", "operator<< <tmpl>". + # No space is added for operator>><tmpl>. if -1 == space_idx or ( -1 == name.find('operator', space_idx - 8, space_idx) and + -1 == name.find('operator<', space_idx - 9, space_idx) and -1 == name.find('operator<<', space_idx - 10, space_idx)): break space_idx -= 8 @@ -93,13 +95,10 @@ if last_right_idx == -1: return name left_idx = _FindLastCharOutsideOfBrackets(name, '<', last_right_idx + 1) - if left_idx == -1: - return name - # Special case: std::operator<< < - if left_idx > 0 and name[left_idx - 1] == ' ': - left_idx -= 1 - name = name[:left_idx] + name[last_right_idx + 1:] - last_right_idx = left_idx + if left_idx != -1: + # Leave in empty <>s to denote that it's a template. + name = name[:left_idx + 1] + name[last_right_idx:] + last_right_idx = left_idx def _NormalizeTopLevelGccLambda(name, left_paren_idx):
diff --git a/tools/binary_size/libsupersize/function_signature_test.py b/tools/binary_size/libsupersize/function_signature_test.py index b830366..65e755bfb 100755 --- a/tools/binary_size/libsupersize/function_signature_test.py +++ b/tools/binary_size/libsupersize/function_signature_test.py
@@ -16,7 +16,7 @@ def check(ret_part, name_part, params_part, after_part='', name_without_templates=None): if name_without_templates is None: - name_without_templates = re.sub(r'<.*?>', '', name_part) + after_part + name_without_templates = re.sub(r'<.*?>', '<>', name_part) + after_part signature = ''.join((name_part, params_part, after_part)) got_full_name, got_template_name, got_name = ( @@ -60,7 +60,22 @@ check('std::basic_ostream<char, std::char_traits<char> >& ', 'std::operator<< <std::char_traits<char> >', '(std::basic_ostream<char, std::char_traits<char> >&, char)', - name_without_templates='std::operator<<') + name_without_templates='std::operator<< <>') + check('', + 'std::basic_istream<char, std::char_traits<char> >' + '::operator>>', + '(unsigned int&)', + name_without_templates='std::basic_istream<>::operator>>') + check('', + 'std::operator><std::allocator<char> >', '()', + name_without_templates='std::operator><>') + check('', + 'std::operator>><std::allocator<char> >', + '(std::basic_istream<char, std::char_traits<char> >&)', + name_without_templates='std::operator>><>') + check('', + 'std::basic_istream<char>::operator>', '(unsigned int&)', + name_without_templates='std::basic_istream<>::operator>') check('v8::internal::SlotCallbackResult ', 'v8::internal::UpdateTypedSlotHelper::UpdateCodeTarget' '<v8::PointerUpdateJobTraits<(v8::Direction)1>::Foo(v8::Heap*, ' @@ -71,7 +86,7 @@ '{lambda(v8::SlotType)#2}::operator()(v8::SlotType) const::' '{lambda(v8::Object**)#1})', name_without_templates=( - 'v8::internal::UpdateTypedSlotHelper::UpdateCodeTarget')) + 'v8::internal::UpdateTypedSlotHelper::UpdateCodeTarget<>')) check('', 'WTF::StringAppend<WTF::String, WTF::String>::operator WTF::String', '()', @@ -86,7 +101,7 @@ # Test with multiple template args. check('int ', 'Foo<int()>::bar<a<b> >', '()', - name_without_templates='Foo::bar') + name_without_templates='Foo<>::bar<>') # SkArithmeticImageFilter.cpp has class within function body. e.g.: # ArithmeticFP::onCreateGLSLInstance() looks like: @@ -125,7 +140,7 @@ check('', 'blink::CSSValueKeywordsHash::findValueImpl', '(char const*)', '::value_word_list') check('', 'foo::Bar<Z<Y> >::foo<bar>', '(abc)', '::var<baz>', - name_without_templates='foo::Bar::foo::var') + name_without_templates='foo::Bar<>::foo<>::var<>') if __name__ == '__main__': logging.basicConfig(level=logging.DEBUG,
diff --git a/tools/binary_size/libsupersize/html_report.py b/tools/binary_size/libsupersize/html_report.py index d5073bdc..d339bf8 100644 --- a/tools/binary_size/libsupersize/html_report.py +++ b/tools/binary_size/libsupersize/html_report.py
@@ -12,7 +12,7 @@ import sys import archive -import paths +import path_util # Node dictionary keys. These are output in json read by the webapp so @@ -92,16 +92,16 @@ def _AddSymbolIntoFileNode(node, symbol_type, symbol_name, symbol_size, - include_symbols): + min_symbol_size): """Puts symbol into the file path node |node|.""" node[_NODE_LAST_PATH_ELEMENT_KEY] = True # Don't bother with buckets when not including symbols. - if include_symbols: + if min_symbol_size == 0: node = _GetOrMakeChildNode(node, _NODE_TYPE_BUCKET, symbol_type) node[_NODE_SYMBOL_TYPE_KEY] = symbol_type # 'node' is now the symbol-type bucket. Make the child entry. - if include_symbols or not symbol_name: + if not symbol_name or symbol_size >= min_symbol_size: node_name = symbol_name or '[Anonymous]' elif symbol_name.startswith('*'): node_name = symbol_name @@ -112,7 +112,7 @@ node[_NODE_SYMBOL_TYPE_KEY] = symbol_type -def _MakeCompactTree(symbols, include_symbols): +def _MakeCompactTree(symbols, min_symbol_size): result = { _NODE_NAME_KEY: '/', _NODE_CHILDREN_KEY: {}, @@ -135,14 +135,14 @@ elif symbol.name.endswith(']'): symbol_type = _NODE_SYMBOL_TYPE_GENERATED _AddSymbolIntoFileNode(node, symbol_type, symbol.template_name, symbol.pss, - include_symbols) + min_symbol_size) depth += 2 result[_NODE_MAX_DEPTH_KEY] = max(result[_NODE_MAX_DEPTH_KEY], depth) # The (no path) bucket can be extremely large if we failed to get # path information. Split it into subgroups if needed. no_path_bucket = result[_NODE_CHILDREN_KEY].get(_NAME_NO_PATH_BUCKET) - if no_path_bucket and include_symbols: + if no_path_bucket and min_symbol_size == 0: _SplitLargeBucket(no_path_bucket) _MakeChildrenDictsIntoLists(result) @@ -154,7 +154,7 @@ d3_out = os.path.join(dest_dir, 'd3') if not os.path.exists(d3_out): os.makedirs(d3_out, 0755) - d3_src = os.path.join(paths.SRC_ROOT, 'third_party', 'd3', 'src') + d3_src = os.path.join(path_util.SRC_ROOT, 'third_party', 'd3', 'src') template_src = os.path.join(os.path.dirname(__file__), 'template') shutil.copy(os.path.join(d3_src, 'LICENSE'), d3_out) shutil.copy(os.path.join(d3_src, 'd3.js'), d3_out) @@ -171,8 +171,9 @@ parser.add_argument('--include-bss', action='store_true', help='Include symbols from .bss (which consume no real ' 'space)') - parser.add_argument('--include-symbols', action='store_true', - help='Use per-symbol granularity rather than per-file.') + parser.add_argument('--min-symbol-size', type=float, default=1024, + help='Minimum size (PSS) for a symbol to be included as ' + 'an independent node.') def Run(args, parser): @@ -181,7 +182,7 @@ logging.info('Reading .size file') size_info = archive.LoadAndPostProcessSizeInfo(args.input_file) - symbols = size_info.symbols + symbols = size_info.raw_symbols if not args.include_bss: symbols = symbols.WhereInSection('b').Inverted() symbols = symbols.WherePssBiggerThan(0) @@ -192,7 +193,7 @@ _CopyTemplateFiles(args.report_dir) logging.info('Creating JSON objects') - tree_root = _MakeCompactTree(symbols, args.include_symbols) + tree_root = _MakeCompactTree(symbols, args.min_symbol_size) logging.info('Serializing JSON') with open(os.path.join(args.report_dir, 'data.js'), 'w') as out_file:
diff --git a/tools/binary_size/libsupersize/integration_test.py b/tools/binary_size/libsupersize/integration_test.py index 92fa1da..7befa94 100755 --- a/tools/binary_size/libsupersize/integration_test.py +++ b/tools/binary_size/libsupersize/integration_test.py
@@ -12,6 +12,7 @@ import os import unittest import re +import shutil import subprocess import sys import tempfile @@ -29,15 +30,18 @@ _TEST_TOOL_PREFIX = os.path.join( os.path.abspath(_TEST_DATA_DIR), 'mock_toolchain', '') _TEST_MAP_PATH = os.path.join(_TEST_DATA_DIR, 'test.map') -_TEST_ELF_PATH = os.path.join(_TEST_OUTPUT_DIR, 'elf') +_TEST_PAK_PATH = os.path.join(_TEST_OUTPUT_DIR, 'en-US.pak') +_TEST_PAK_INFO_PATH = os.path.join(_TEST_OUTPUT_DIR, 'en-US.pak.info') +_TEST_ELF_PATH = os.path.join(_TEST_OUTPUT_DIR, 'elf') # Dynamically created +_TEST_ELF_FILE_BEGIN = os.path.join(_TEST_OUTPUT_DIR, 'elf.begin') update_goldens = False -def _AssertGolden(expected_lines, actual_lines): +def _AssertGolden(expected_lines, actual_lines, golden_path): expected = list(expected_lines) actual = list(l + '\n' for l in actual_lines) - assert actual == expected, ('Did not match .golden.\n' + + assert actual == expected, (('Did not match %s.\n' % golden_path) + ''.join(difflib.unified_diff(expected, actual, 'expected', 'actual'))) @@ -61,7 +65,7 @@ logging.info('Wrote %s', golden_path) else: with open(golden_path) as file_obj: - _AssertGolden(file_obj, actual_lines) + _AssertGolden(file_obj, actual_lines, golden_path) return inner return real_decorator @@ -96,46 +100,81 @@ class IntegrationTest(unittest.TestCase): maxDiff = None # Don't trucate diffs in errors. - cached_size_info = [None, None, None] + cached_size_info = {} - def _CloneSizeInfo(self, use_output_directory=True, use_elf=True): + @classmethod + def setUpClass(cls): + shutil.copy(_TEST_ELF_FILE_BEGIN, _TEST_ELF_PATH) + with open(_TEST_ELF_PATH, 'a') as elf_file: + data = '0' + # Exactly 128MB of data (2^27), extra bytes will be accounted in overhead. + for _ in range(27): + data = data + data + elf_file.write(data) + + @classmethod + def tearDownClass(cls): + os.remove(_TEST_ELF_PATH) + + def _CloneSizeInfo(self, use_output_directory=True, use_elf=True, + use_pak=False): assert not use_elf or use_output_directory - i = int(use_output_directory) + int(use_elf) - if not IntegrationTest.cached_size_info[i]: + cache_key = (use_output_directory, use_elf, use_pak) + if cache_key not in IntegrationTest.cached_size_info: elf_path = _TEST_ELF_PATH if use_elf else None output_directory = _TEST_OUTPUT_DIR if use_output_directory else None - IntegrationTest.cached_size_info[i] = archive.CreateSizeInfo( - _TEST_MAP_PATH, elf_path, _TEST_TOOL_PREFIX, output_directory) + if use_pak: + section_sizes, raw_symbols = archive.CreateSectionSizesAndSymbols( + map_path=_TEST_MAP_PATH, tool_prefix=_TEST_TOOL_PREFIX, + elf_path=elf_path, output_directory=output_directory, + pak_files=[_TEST_PAK_PATH], pak_info_file=_TEST_PAK_INFO_PATH) + else: + section_sizes, raw_symbols = archive.CreateSectionSizesAndSymbols( + map_path=_TEST_MAP_PATH, tool_prefix=_TEST_TOOL_PREFIX, + elf_path=elf_path, output_directory=output_directory) + metadata = None if use_elf: with _AddMocksToPath(): - IntegrationTest.cached_size_info[i].metadata = archive.CreateMetadata( + metadata = archive.CreateMetadata( _TEST_MAP_PATH, elf_path, None, _TEST_TOOL_PREFIX, output_directory) - return copy.deepcopy(IntegrationTest.cached_size_info[i]) + IntegrationTest.cached_size_info[cache_key] = archive.CreateSizeInfo( + section_sizes, raw_symbols, metadata=metadata) + return copy.deepcopy(IntegrationTest.cached_size_info[cache_key]) + + def _DoArchive(self, archive_path, use_output_directory=True, use_elf=True, + use_pak=False, debug_measures=False): + args = [archive_path, '--map-file', _TEST_MAP_PATH] + if use_output_directory: + # Let autodetection find output_directory when --elf-file is used. + if not use_elf: + args += ['--output-directory', _TEST_OUTPUT_DIR] + else: + args += ['--no-source-paths'] + if use_elf: + args += ['--elf-file', _TEST_ELF_PATH] + if use_pak: + args += ['--pak-file', _TEST_PAK_PATH, + '--pak-info-file', _TEST_PAK_INFO_PATH] + _RunApp('archive', args, debug_measures=debug_measures) def _DoArchiveTest(self, use_output_directory=True, use_elf=True, - debug_measures=False): + use_pak=False, debug_measures=False): with tempfile.NamedTemporaryFile(suffix='.size') as temp_file: - args = [temp_file.name, '--map-file', _TEST_MAP_PATH] - if use_output_directory: - # Let autodetection find output_directory when --elf-file is used. - if not use_elf: - args += ['--output-directory', _TEST_OUTPUT_DIR] - else: - args += ['--no-source-paths'] - if use_elf: - args += ['--elf-file', _TEST_ELF_PATH] - _RunApp('archive', args, debug_measures=debug_measures) + self._DoArchive( + temp_file.name, use_output_directory=use_output_directory, + use_elf=use_elf, use_pak=use_pak, debug_measures=debug_measures) size_info = archive.LoadAndPostProcessSizeInfo(temp_file.name) - # Check that saving & loading is the same as directly parsing the .map. + # Check that saving & loading is the same as directly parsing. expected_size_info = self._CloneSizeInfo( - use_output_directory=use_output_directory, use_elf=use_elf) + use_output_directory=use_output_directory, use_elf=use_elf, + use_pak=use_pak) self.assertEquals(expected_size_info.metadata, size_info.metadata) # Don't cluster. expected_size_info.symbols = expected_size_info.raw_symbols size_info.symbols = size_info.raw_symbols - expected = list(describe.GenerateLines(expected_size_info)) - actual = list(describe.GenerateLines(size_info)) + expected = list(describe.GenerateLines(expected_size_info, verbose=True)) + actual = list(describe.GenerateLines(size_info, verbose=True)) self.assertEquals(expected, actual) sym_strs = (repr(sym) for sym in size_info.symbols) @@ -158,6 +197,10 @@ def test_Archive_Elf(self): return self._DoArchiveTest() + @_CompareWithGolden() + def test_Archive_Pak(self): + return self._DoArchiveTest(use_pak=True) + @_CompareWithGolden(name='Archive_Elf') def test_Archive_Elf_DebugMeasures(self): return self._DoArchiveTest(debug_measures=True) @@ -172,7 +215,11 @@ 'ExpandRegex("_foo_")', 'canned_queries.CategorizeGenerated()', 'canned_queries.CategorizeByChromeComponent()', + 'canned_queries.LargeFiles()', 'canned_queries.TemplatesByName()', + 'canned_queries.StaticInitializers()', + 'canned_queries.PakByPath()', + 'Print(ReadStringLiterals(elf_path={}))'.format(repr(_TEST_ELF_PATH)), 'Print(size_info, to_file=%r)' % output_file.name, ] ret = _RunApp('console', [size_file.name, '--query', '; '.join(query)]) @@ -199,6 +246,16 @@ file_format.SaveSizeInfo(self._CloneSizeInfo(), temp_file.name) return _RunApp('diff', [temp_file.name, temp_file.name]) + # Runs archive 3 times, and asserts the contents are the same each time. + def test_Idempotent(self): + prev_contents = None + for _ in xrange(3): + with tempfile.NamedTemporaryFile(suffix='.size') as temp_file: + self._DoArchive(temp_file.name) + contents = temp_file.read() + self.assertTrue(prev_contents is None or contents == prev_contents) + prev_contents = contents + @_CompareWithGolden() def test_Diff_Basic(self): size_info1 = self._CloneSizeInfo(use_elf=False) @@ -217,8 +274,8 @@ size_info2 = self._CloneSizeInfo() # Removing 1 alias should not change the size. - a1, _, _ = ( - size_info2.raw_symbols.Filter(lambda s: s.num_aliases == 3)[0].aliases) + a1, _, _, _ = ( + size_info2.raw_symbols.Filter(lambda s: s.num_aliases == 4)[0].aliases) size_info2.raw_symbols -= [a1] a1.aliases.remove(a1) d = diff.Diff(size_info1, size_info2) @@ -238,8 +295,8 @@ size_info2 = self._CloneSizeInfo() # Removing 2 aliases should not change the size. - a1, a2, _ = ( - size_info2.raw_symbols.Filter(lambda s: s.num_aliases == 3)[0].aliases) + a1, _, a2, _ = ( + size_info2.raw_symbols.Filter(lambda s: s.num_aliases == 4)[0].aliases) size_info2.raw_symbols -= [a1, a2] a1.aliases.remove(a1) a1.aliases.remove(a2) @@ -254,28 +311,28 @@ self.assertEquals((0, 2, 0), _DiffCounts(d.raw_symbols)) self.assertEquals((1, 1, 0), _DiffCounts(d.symbols.GroupedByFullName())) - def test_Diff_Aliases3(self): + def test_Diff_Aliases4(self): size_info1 = self._CloneSizeInfo() size_info2 = self._CloneSizeInfo() - # Removing all 3 aliases should change the size. - a1, a2, a3 = ( - size_info2.raw_symbols.Filter(lambda s: s.num_aliases == 3)[0].aliases) - size_info2.raw_symbols -= [a1, a2, a3] + # Removing all 4 aliases should change the size. + a1, a2, a3, a4 = ( + size_info2.raw_symbols.Filter(lambda s: s.num_aliases == 4)[0].aliases) + size_info2.raw_symbols -= [a1, a2, a3, a4] d = diff.Diff(size_info1, size_info2) - self.assertEquals((0, 0, 3), _DiffCounts(d.raw_symbols)) + self.assertEquals((0, 0, 4), _DiffCounts(d.raw_symbols)) self.assertEquals((1, 0, 2), _DiffCounts(d.symbols.GroupedByFullName())) - # Adding all 3 aliases should change size. + # Adding all 4 aliases should change size. d = diff.Diff(size_info2, size_info1) self.assertEquals(d.raw_symbols.pss, a1.size) - self.assertEquals((0, 3, 0), _DiffCounts(d.raw_symbols)) + self.assertEquals((0, 4, 0), _DiffCounts(d.raw_symbols)) self.assertEquals((1, 2, 0), _DiffCounts(d.symbols.GroupedByFullName())) def test_Diff_Clustering(self): size_info1 = self._CloneSizeInfo() size_info2 = self._CloneSizeInfo() - S = '.text' + S = models.SECTION_TEXT size_info1.symbols += [ models.Symbol(S, 11, name='.L__unnamed_1193', object_path='a'), # 1 models.Symbol(S, 22, name='.L__unnamed_1194', object_path='a'), # 2
diff --git a/tools/binary_size/libsupersize/linker_map_parser.py b/tools/binary_size/libsupersize/linker_map_parser.py index 47d6141..e726795 100644 --- a/tools/binary_size/libsupersize/linker_map_parser.py +++ b/tools/binary_size/libsupersize/linker_map_parser.py
@@ -3,6 +3,8 @@ # found in the LICENSE file. import logging +import os +import re import models @@ -14,8 +16,8 @@ # * The parse time for compressed linker maps is dominated by ungzipping. -class MapFileParser(object): - """Parses a linker map file (tested only on files from gold linker).""" +class MapFileParserGold(object): + """Parses a linker map file from gold linker.""" # Map file writer for gold linker: # https://github.com/gittup/binutils/blob/HEAD/gold/mapfile.cc @@ -29,7 +31,8 @@ """Parses a linker map file. Args: - lines: Iterable of lines. + lines: Iterable of lines, the first of which has been consumed to + identify file type. Returns: A tuple of (section_sizes, symbols). @@ -79,8 +82,8 @@ if not parts: break name, size_str, path = parts - sym = models.Symbol('.bss', int(size_str[2:], 16), full_name=name, - object_path=path) + sym = models.Symbol(models.SECTION_BSS, int(size_str[2:], 16), + full_name=name, object_path=path) ret.append(sym) return ret @@ -125,10 +128,12 @@ section_address = int(section_address_str[2:], 16) section_size = int(section_size_str[2:], 16) self._section_sizes[section_name] = section_size - if (section_name in ('.bss', '.rodata', '.text') or - section_name.startswith('.data')): + if (section_name in (models.SECTION_BSS, + models.SECTION_RODATA, + models.SECTION_TEXT) or + section_name.startswith(models.SECTION_DATA)): logging.info('Parsing %s', section_name) - if section_name == '.bss': + if section_name == models.SECTION_BSS: # Common symbols have no address. syms.extend(self._common_symbols) prefix_len = len(section_name) + 1 # + 1 for the trailing . @@ -224,12 +229,25 @@ symbol_gap_count += 1 syms.append(sym) + # .text.res_findResource_60 + # 0x00178de8 0x12a obj/... + # 0x00178de9 res_findResource_60 + # .text._ZN3url6ParsedC2Ev + # 0x0021ad62 0x2e obj/url/url/url_parse.o + # 0x0021ad63 url::Parsed::Parsed() + # .text.unlikely._ZN4base3CPUC2Ev + # 0x003f9d3c 0x48 obj/base/base/cpu.o + # 0x003f9d3d base::CPU::CPU() + full_name = name + if mangled_name and (not name or mangled_name.startswith('_Z') or + '._Z' in mangled_name): + full_name = mangled_name + sym = models.Symbol(section_name, size, address=address, - full_name=name or mangled_name, - object_path=path) + full_name=full_name, object_path=path) syms.append(sym) section_end_address = section_address + section_size - if section_name != '.bss' and ( + if section_name != models.SECTION_BSS and ( syms[-1].end_address < section_end_address): # Set size=0 so that it will show up as padding. sym = models.Symbol( @@ -244,3 +262,140 @@ logging.error('Problem line: %r', line) logging.error('In section: %r', section_name) raise + + +class _SymbolMaker(object): + def __init__(self): + self.syms = [] + self.cur_sym = None + + def Flush(self): + if self.cur_sym: + self.syms.append(self.cur_sym) + self.cur_sym = None + + def Create(self, *args, **kwargs): + self.Flush() + self.cur_sym = models.Symbol(*args, **kwargs) + + +class MapFileParserLld(object): + """Parses a linker map file from LLD.""" + # TODO(huangs): Add LTO support. + # Map file writer for LLD linker (for ELF): + # https://github.com/llvm-mirror/lld/blob/HEAD/ELF/MapFile.cpp + _MAIN_RE = re.compile(r'([0-9a-f]+)\s+([0-9a-f]+)\s+(\d+) ( *)(.*)') + + def __init__(self): + self._common_symbols = [] + self._section_sizes = {} + self._lines = None + + def Parse(self, lines): + """Parses a linker map file. + + Args: + lines: Iterable of lines, the first of which has been consumed to + identify file type. + + Returns: + A tuple of (section_sizes, symbols). + """ +# Address Size Align Out In Symbol +# 00000000002002a8 000000000000001c 1 .interp +# 00000000002002a8 000000000000001c 1 <internal>:(.interp) +# ... +# 0000000000201000 0000000000000202 16 .text +# 0000000000201000 000000000000002a 1 /[...]/crt1.o:(.text) +# 0000000000201000 0000000000000000 0 _start +# 000000000020102a 0000000000000000 1 /[...]/crti.o:(.text) +# 0000000000201030 00000000000000bd 16 /[...]/crtbegin.o:(.text) +# 0000000000201030 0000000000000000 0 deregister_tm_clones +# 0000000000201060 0000000000000000 0 register_tm_clones +# 00000000002010a0 0000000000000000 0 __do_global_dtors_aux +# 00000000002010c0 0000000000000000 0 frame_dummy +# 00000000002010ed 0000000000000071 1 a.o:(.text) +# 00000000002010ed 0000000000000071 0 main + sym_maker = _SymbolMaker() + cur_section = None + cur_section_is_useful = None + + for line in lines: + m = MapFileParserLld._MAIN_RE.match(line) + if m is None: + continue + address = int(m.group(1), 16) + size = int(m.group(2), 16) + indent_size = len(m.group(4)) + tok = m.group(5) + + if indent_size == 0: + sym_maker.Flush() + self._section_sizes[tok] = size + cur_section = tok + cur_section_is_useful = ( + cur_section in (models.SECTION_BSS, + models.SECTION_RODATA, + models.SECTION_TEXT) or + cur_section.startswith(models.SECTION_DATA)) + cur_obj = None + + elif cur_section_is_useful: + if indent_size == 8: + sym_maker.Flush() + cur_obj = tok.split(':')[0] + sym_maker.Create(cur_section, size, address=address) + # As of 2017/11 LLD does not distinguish merged strings from other + # merged data. Feature request is filed under: + # https://bugs.llvm.org/show_bug.cgi?id=35248 + if cur_obj == '<internal>': + # Treat all literals as stirng literals. + # FIXME(huangs): Refine this. Checking align == 1 is insufficient. + sym_maker.cur_sym.full_name = '** lld merge strings' + else: + sym_maker.cur_sym.object_path = cur_obj + + elif indent_size == 16: + # If multiple entries exist, take the first on that reports a size. + # Zero-length symbols look like "$t.4", "$d.5". + if size and not sym_maker.cur_sym.full_name: + sym_maker.cur_sym.full_name = tok + + else: + logging.error('Problem line: %r', line) + + sym_maker.Flush() + return self._section_sizes, sym_maker.syms + + +def DetectLinkerNameFromMapFileHeader(first_line): + if first_line.startswith('Address'): + return 'lld' + if first_line.startswith('Archive member'): + return 'gold' + raise Exception('Invalid map file.') + + +class MapFileParser(object): + """Parses a linker map file, with heuristic linker detection.""" + def Parse(self, lines): + """Parses a linker map file. + + Args: + lines: Iterable of lines. + + Returns: + A tuple of (section_sizes, symbols). + """ + linker_name = DetectLinkerNameFromMapFileHeader(next(lines)) + if linker_name == 'lld': + inner_parser = MapFileParserLld() + elif linker_name == 'gold': + inner_parser = MapFileParserGold() + else: + raise Exception('.map file is from a unsupported linker.') + section_sizes, syms = inner_parser.Parse(lines) + for sym in syms: + if sym.object_path: # Don't want '' to become '.'. + sym.object_path = os.path.normpath(sym.object_path) + return (section_sizes, syms)
diff --git a/tools/binary_size/libsupersize/models.py b/tools/binary_size/libsupersize/models.py index 38168f9..5ac5dd5 100644 --- a/tools/binary_size/libsupersize/models.py +++ b/tools/binary_size/libsupersize/models.py
@@ -36,6 +36,7 @@ METADATA_GIT_REVISION = 'git_revision' METADATA_APK_FILENAME = 'apk_file_name' # Path relative to output_directory. +METADATA_APK_SIZE = 'apk_size' # File size of apk in bytes. METADATA_MAP_FILENAME = 'map_file_name' # Path relative to output_directory. METADATA_ELF_ARCHITECTURE = 'elf_arch' # "Machine" field from readelf -h METADATA_ELF_FILENAME = 'elf_file_name' # Path relative to output_directory. @@ -44,26 +45,53 @@ METADATA_GN_ARGS = 'gn_args' METADATA_TOOL_PREFIX = 'tool_prefix' # Path relative to SRC_ROOT. - +SECTION_BSS = '.bss' +SECTION_DATA = '.data' +SECTION_DATA_REL_RO = '.data.rel.ro' +SECTION_DATA_REL_RO_LOCAL = '.data.rel.ro.local' +SECTION_OTHER = '.other' +SECTION_PAK_NONTRANSLATED = '.pak.nontranslated' +SECTION_PAK_TRANSLATIONS = '.pak.translations' +SECTION_RODATA = '.rodata' +SECTION_TEXT = '.text' # Used by SymbolGroup when they contain a mix of sections. -SECTION_NAME_MULTIPLE = '.*' +SECTION_MULTIPLE = '.*' + +NATIVE_SECTIONS = ( + SECTION_BSS, + SECTION_DATA, + SECTION_DATA_REL_RO, + SECTION_DATA_REL_RO_LOCAL, + SECTION_RODATA, + SECTION_TEXT, +) +PAK_SECTIONS = ( + SECTION_PAK_NONTRANSLATED, + SECTION_PAK_TRANSLATIONS, +) SECTION_NAME_TO_SECTION = { - '.bss': 'b', - '.data': 'd', - '.data.rel.ro.local': 'R', - '.data.rel.ro': 'R', - '.rodata': 'r', - '.text': 't', - SECTION_NAME_MULTIPLE: '*', + SECTION_BSS: 'b', + SECTION_DATA: 'd', + SECTION_DATA_REL_RO_LOCAL: 'R', + SECTION_DATA_REL_RO: 'R', + SECTION_OTHER: 'o', + SECTION_PAK_NONTRANSLATED: 'P', + SECTION_PAK_TRANSLATIONS: 'p', + SECTION_RODATA: 'r', + SECTION_TEXT: 't', + SECTION_MULTIPLE: '*', } SECTION_TO_SECTION_NAME = collections.OrderedDict(( - ('t', '.text'), - ('r', '.rodata'), - ('R', '.data.rel.ro'), - ('d', '.data'), - ('b', '.bss'), + ('t', SECTION_TEXT), + ('r', SECTION_RODATA), + ('R', SECTION_DATA_REL_RO), + ('d', SECTION_DATA), + ('b', SECTION_BSS), + ('p', SECTION_PAK_TRANSLATIONS), + ('P', SECTION_PAK_NONTRANSLATED), + ('o', SECTION_OTHER), )) @@ -74,6 +102,7 @@ FLAG_REL_LOCAL = 16 FLAG_GENERATED_SOURCE = 32 FLAG_CLONE = 64 +FLAG_HOT = 128 DIFF_STATUS_UNCHANGED = 0 @@ -83,86 +112,101 @@ DIFF_PREFIX_BY_STATUS = ['= ', '~ ', '+ ', '- '] -class SizeInfo(object): - """Represents all size information for a single binary. +STRING_LITERAL_NAME = 'string literal' + + +class BaseSizeInfo(object): + """Base class for SizeInfo and DeltaSizeInfo. Fields: section_sizes: A dict of section_name -> size. raw_symbols: A SymbolGroup containing all top-level symbols (no groups). - symbols: A SymbolGroup where symbols have been grouped by full_name (where - applicable). May be re-assigned when it is desirable to show custom - groupings while still printing metadata and section_sizes. + symbols: A SymbolGroup of all symbols, where symbols have been + grouped by full_name (where applicable). May be re-assigned when it is + desirable to show custom groupings while still printing metadata and + section_sizes. + native_symbols: Subset of |symbols| that are from native code. + pak_symbols: Subset of |symbols| that are from pak files. + """ + __slots__ = ( + 'section_sizes', + 'raw_symbols', + '_symbols', + '_native_symbols', + '_pak_symbols', + ) + + def __init__(self, section_sizes, raw_symbols, symbols=None): + if isinstance(raw_symbols, list): + raw_symbols = SymbolGroup(raw_symbols) + self.section_sizes = section_sizes # E.g. {SECTION_TEXT: 0} + self.raw_symbols = raw_symbols + self._symbols = symbols + self._native_symbols = None + self._pak_symbols = None + + @property + def symbols(self): + if self._symbols is None: + logging.debug('Clustering symbols') + self._symbols = self.raw_symbols._Clustered() + logging.debug('Done clustering symbols') + return self._symbols + + @symbols.setter + def symbols(self, value): + self._symbols = value + + @property + def native_symbols(self): + if self._native_symbols is None: + # Use self.symbols rather than raw_symbols here so that _Clustered() + # is not performed twice (slow) if accessing both properties. + self._native_symbols = self.symbols.WhereIsNative() + return self._native_symbols + + @property + def pak_symbols(self): + if self._pak_symbols is None: + self._pak_symbols = self.raw_symbols.WhereIsPak() + return self._pak_symbols + + +class SizeInfo(BaseSizeInfo): + """Represents all size information for a single binary. + + Fields: metadata: A dict. size_path: Path to .size file this was loaded from (or None). """ __slots__ = ( - 'section_sizes', - 'raw_symbols', - '_symbols', 'metadata', 'size_path', ) - """Root size information.""" def __init__(self, section_sizes, raw_symbols, metadata=None, symbols=None, size_path=None): - if isinstance(raw_symbols, list): - raw_symbols = SymbolGroup(raw_symbols) - self.section_sizes = section_sizes # E.g. {'.text': 0} - self.raw_symbols = raw_symbols - self._symbols = symbols + super(SizeInfo, self).__init__(section_sizes, raw_symbols, symbols=symbols) self.metadata = metadata or {} self.size_path = size_path - @property - def symbols(self): - if self._symbols is None: - self._symbols = self.raw_symbols._Clustered() - return self._symbols - @symbols.setter - def symbols(self, value): - self._symbols = value - - -class DeltaSizeInfo(object): +class DeltaSizeInfo(BaseSizeInfo): """What you get when you Diff() two SizeInfo objects. Fields: - section_sizes: A dict of section_name -> size delta. - raw_symbols: A DeltaSymbolGroup with all top-level symbols in it - (no groups). - symbols: A DeltaSymbolGroup where symbols have been grouped by full_name - (where applicable). May be re-assigned when it is desirable to show - custom groupings while still printing metadata and section_sizes. - before_metadata: metadata of the "before" SizeInfo. - after_metadata: metadata of the "after" SizeInfo. + before: SizeInfo for "before". + after: SizeInfo for "after". """ __slots__ = ( - 'section_sizes', - 'raw_symbols', - '_symbols', - 'before_metadata', - 'after_metadata', + 'before', + 'after', ) - def __init__(self, section_sizes, raw_symbols, before_metadata, - after_metadata): - self.section_sizes = section_sizes - self.raw_symbols = raw_symbols - self.before_metadata = before_metadata - self.after_metadata = after_metadata - self._symbols = None - - @property - def symbols(self): - if self._symbols is None: - self._symbols = self.raw_symbols._Clustered() - return self._symbols - - @symbols.setter - def symbols(self, value): - self._symbols = value + def __init__(self, before, after, section_sizes, raw_symbols): + super(DeltaSizeInfo, self).__init__(section_sizes, raw_symbols) + self.before = before + self.after = after class BaseSymbol(object): @@ -174,15 +218,7 @@ @property def section(self): - """Returns the one-letter section. - - Mappings: - 'b': '.bss' - 'd': '.data' - 'R': '.data.rel.ro' - 'r': '.rodata' - 't': '.text' - """ + """Returns the one-letter section.""" # Fallback to section_name if there is no short-form defined. return SECTION_NAME_TO_SECTION.get(self.section_name, self.section_name) @@ -233,10 +269,16 @@ parts.append('gen') if flags & FLAG_CLONE: parts.append('clone') + if flags & FLAG_HOT: + parts.append('hot') return '{%s}' % ','.join(parts) def IsBss(self): - return self.section_name == '.bss' + return self.section_name == SECTION_BSS + + def IsPak(self): + return (self.section_name == SECTION_PAK_TRANSLATIONS or + self.section_name == SECTION_PAK_NONTRANSLATED) def IsGroup(self): return False @@ -248,6 +290,9 @@ return '.' in self.name or ( self.name.endswith(']') and not self.name.endswith('[]')) + def IsStringLiteral(self): + return self.full_name == STRING_LITERAL_NAME + def IterLeafSymbols(self): yield self @@ -475,7 +520,7 @@ self.full_name = full_name if full_name is not None else name self.template_name = template_name if template_name is not None else name self.name = name or '' - self.section_name = section_name or SECTION_NAME_MULTIPLE + self.section_name = section_name or SECTION_MULTIPLE self.is_sorted = is_sorted def __repr__(self): @@ -663,6 +708,14 @@ ret.section_name = SECTION_TO_SECTION_NAME[section] return ret + def WhereIsNative(self): + return self.WhereInSection( + ''.join(SECTION_NAME_TO_SECTION[s] for s in NATIVE_SECTIONS)) + + def WhereIsPak(self): + return self.WhereInSection( + ''.join(SECTION_NAME_TO_SECTION[s] for s in PAK_SECTIONS)) + def WhereIsTemplate(self): return self.Filter(lambda s: s.template_name is not s.name) @@ -737,7 +790,7 @@ """ return self._CreateTransformed( self._filtered_symbols, filtered_symbols=self._symbols, - section_name=SECTION_NAME_MULTIPLE, is_sorted=False) + section_name=SECTION_MULTIPLE, is_sorted=False) def GroupedBy(self, func, min_count=0, group_factory=None): """Returns a SymbolGroup of SymbolGroups, indexed by |func|. @@ -805,14 +858,17 @@ The main function of clustering is to put symbols that were broken into multiple parts under a group so that they once again look like a single - symbol. It also groups together symbols like "** merge strings". + symbol. This is to prevent someone thinking that a symbol got smaller, when + all it did was get split into parts. + + It also groups together "** symbol gap", since these are mostly just noise. To view created groups: Print(size_info.symbols.WhereIsGroup()) """ def cluster_func(symbol): name = symbol.full_name - if not name: + if not name or symbol.IsStringLiteral(): # min_count=2 will ensure order is maintained while not being grouped. # "&" to distinguish from real symbol names, id() to ensure uniqueness. name = '&' + hex(id(symbol)) @@ -844,6 +900,30 @@ return self._CreateTransformed(ret) + def GroupedByAliases(self, same_name_only=False, min_count=2): + """Groups by symbol.aliases (leaving non-aliases alone). + + Useful when wanting an overview of symbol sizes without having their PSS + divided by number of aliases. + + Args: + same_name_only: When True, groups only aliases with the same full_name + (those that differ only by path). + min_count: Miniumum number of symbols for a group. If fewer than this many + symbols end up in a group, they will not be put within a group. + Use a negative value to omit symbols entirely rather than + include them outside of a group. + """ + def group_factory(_, symbols): + sym = symbols[0] + return self._CreateTransformed( + symbols, full_name=sym.full_name, template_name=sym.template_name, + name=sym.name, section_name=sym.section_name) + + return self.GroupedBy( + lambda s: (same_name_only and s.full_name, id(s.aliases or s)), + min_count=min_count, group_factory=group_factory) + def GroupedBySectionName(self): return self.GroupedBy(lambda s: s.section_name) @@ -886,7 +966,7 @@ return self.GroupedBy(extract_namespace, min_count=min_count) def GroupedByPath(self, depth=0, fallback='{no path}', - fallback_to_object_path=True, min_count=0): + fallback_to_object_path=True, min_count=0): """Groups by source_path. Due to path sharing (symbols where path looks like foo/bar/{shared}/3), @@ -895,7 +975,8 @@ Args: depth: When 0 (default), groups by entire path. When 1, groups by top-level directory, when 2, groups by top 2 directories, etc. - fallback: Use this value when no namespace exists. + fallback: Use this value when no path exists. Pass None here to omit + symbols that do not path information. fallback_to_object_path: When True (default), uses object_path when source_path is missing. min_count: Miniumum number of symbols for a group. If fewer than this many @@ -908,6 +989,8 @@ if fallback_to_object_path and not path: path = symbol.object_path path = path or fallback + if path is None: + return None # Group by base of foo/bar/{shared}/2 shared_idx = path.find('{shared}') if shared_idx != -1:
diff --git a/tools/binary_size/libsupersize/ninja_parser.py b/tools/binary_size/libsupersize/ninja_parser.py index b8a2784..6b776539 100644 --- a/tools/binary_size/libsupersize/ninja_parser.py +++ b/tools/binary_size/libsupersize/ninja_parser.py
@@ -55,6 +55,9 @@ def unmatched_paths_count(self): return len(self._unmatched_paths) + def IterAllPaths(self): + return self._dep_map.iterkeys() + def _ParseNinjaPathList(path_list): ret = path_list.replace('\\ ', '\b')
diff --git a/tools/binary_size/libsupersize/nm.py b/tools/binary_size/libsupersize/nm.py old mode 100644 new mode 100755 index 5a711c96..6f97d3a1 --- a/tools/binary_size/libsupersize/nm.py +++ b/tools/binary_size/libsupersize/nm.py
@@ -1,31 +1,97 @@ +#!/usr/bin/env python # Copyright 2017 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. -"""Functions that rely on parsing output of "nm" tool.""" +"""Runs nm on every .o file that comprises an ELF (plus some analysis). +The design of this file is entirely to work around Python's lack of concurrency. + +CollectAliasesByAddress: + Runs "nm" on the elf to collect all symbol names. This reveals symbol names of + identical-code-folded functions. + +CollectAliasesByAddressAsync: + Runs CollectAliasesByAddress in a subprocess and returns a promise. + +_BulkObjectFileAnalyzerMaster: + Creates a subprocess and sends IPCs to it asking it to do work. + +_BulkObjectFileAnalyzerSlave: + Receives IPCs and delegates logic to _BulkObjectFileAnalyzerWorker. + Runs _BulkObjectFileAnalyzerWorker on a background thread in order to stay + responsive to IPCs. + +_BulkObjectFileAnalyzerWorker: + Performs the actual work. Uses Process Pools to shard out per-object-file + work and then aggregates results. + +BulkObjectFileAnalyzer: + Alias for _BulkObjectFileAnalyzerMaster, but when SUPERSIZE_DISABLE_ASYNC=1, + alias for _BulkObjectFileAnalyzerWorker. + * AnalyzePaths: Run "nm" on all .o files to collect symbol names that exist + within each. + * SortPaths: Sort results of AnalyzePaths(). + * AnalyzeStringLiterals: Must be run after AnalyzePaths() has completed. + Extracts string literals from .o files, and then locates them within the + "** merge strings" sections within an ELF's .rodata section. + +This file can also be run stand-alone in order to test out the logic on smaller +sample sizes. +""" + +from __future__ import print_function + +import argparse import atexit import collections import errno +import itertools import logging import os +import multiprocessing +import Queue +import signal import subprocess import sys +import threading +import traceback import concurrent +import demangle +import models +import path_util -_active_subprocesses = None +_MSG_ANALYZE_PATHS = 1 +_MSG_SORT_PATHS = 2 +_MSG_ANALYZE_STRINGS = 3 +_MSG_GET_SYMBOL_NAMES = 4 +_MSG_GET_STRINGS = 5 + +_active_pids = None + + +def _DecodePosition(x): + # Encoded as "123:123" + sep_idx = x.index(':') + return (int(x[:sep_idx]), int(x[sep_idx + 1:])) + + +def _MakeToolPrefixAbsolute(tool_prefix): + # Ensure tool_prefix is absolute so that CWD does not affect it + if os.path.sep in tool_prefix: + # Use abspath() on the dirname to avoid it stripping a trailing /. + dirname = os.path.dirname(tool_prefix) + tool_prefix = os.path.abspath(dirname) + tool_prefix[len(dirname):] + return tool_prefix def _IsRelevantNmName(name): # Skip lines like: # 00000000 t $t - # 00000000 r $d - # 0000041b r .L.str - # 0000041b r .L.str.38 + # 00000000 r $d.23 # 00000344 N - return name and not name.startswith('.L.str') and not ( - len(name) == 2 and name.startswith('$')) + return name and not name.startswith('$') def _IsRelevantObjectFileName(name): @@ -47,6 +113,10 @@ # __compound_literal.12 # .L.ref.tmp.1 # .L.str, .L.str.3 + # .L__func__.main: (when using __func__) + # .L__FUNCTION__._ZN6webrtc17AudioDeviceBuffer11StopPlayoutEv + # .L__PRETTY_FUNCTION__._Unwind_Resume + # .L_ZZ24ScaleARGBFilterCols_NEONE9dx_offset (an array literal) if name in ('__tcf_0', 'startup'): return False if name.startswith('._') and name[2:].isdigit(): @@ -59,46 +129,44 @@ return True name = name[:dot_idx] - return name not in ( - 'CSWTCH', 'lock', '__compound_literal', '__func__', 'table') + return name not in ('CSWTCH', 'lock', '__compound_literal', 'table') def CollectAliasesByAddress(elf_path, tool_prefix): """Runs nm on |elf_path| and returns a dict of address->[names]""" - names_by_address = collections.defaultdict(list) + # Constructors often show up twice, so use sets to ensure no duplicates. + names_by_address = collections.defaultdict(set) # About 60mb of output, but piping takes ~30s, and loading it into RAM # directly takes 3s. - args = [tool_prefix + 'nm', '--no-sort', '--defined-only', '--demangle', + args = [path_util.GetNmPath(tool_prefix), '--no-sort', '--defined-only', elf_path] output = subprocess.check_output(args) for line in output.splitlines(): space_idx = line.find(' ') address_str = line[:space_idx] section = line[space_idx + 1] - name = line[space_idx + 3:] + mangled_name = line[space_idx + 3:] # To verify that rodata does not have aliases: # nm --no-sort --defined-only libchrome.so > nm.out # grep -v '\$' nm.out | grep ' r ' | sort | cut -d' ' -f1 > addrs # wc -l < addrs; uniq < addrs | wc -l - if section not in 'tT' or not _IsRelevantNmName(name): + if section not in 'tTW' or not _IsRelevantNmName(mangled_name): continue address = int(address_str, 16) if not address: continue - # Constructors often show up twice. - name_list = names_by_address[address] - if name not in name_list: - name_list.append(name) + names_by_address[address].add(mangled_name) + + # Demangle all names. + names_by_address = demangle.DemangleSetsInDicts(names_by_address, tool_prefix) # Since this is run in a separate process, minimize data passing by returning # only aliased symbols. - names_by_address = {k: v for k, v in names_by_address.iteritems() - if len(v) > 1} - - return names_by_address + # Also: Sort to ensure stable ordering. + return {k: sorted(v) for k, v in names_by_address.iteritems() if len(v) > 1} def _CollectAliasesByAddressAsyncHelper(elf_path, tool_prefix): @@ -109,42 +177,306 @@ def CollectAliasesByAddressAsync(elf_path, tool_prefix): """Calls CollectAliasesByAddress in a helper process. Returns a Result.""" def decode(encoded): - return concurrent.DecodeDictOfLists( - encoded[0], encoded[1], key_transform=int) + return concurrent.DecodeDictOfLists(encoded, key_transform=int) return concurrent.ForkAndCall( _CollectAliasesByAddressAsyncHelper, (elf_path, tool_prefix), decode_func=decode) -def _ParseOneObjectFileOutput(lines): +def _LookupStringSectionPositions(target, tool_prefix, output_directory): + """Returns a dict of object_path -> [(offset, size)...] of .rodata sections. + + Args: + target: An archive path string (e.g., "foo.a") or a list of object paths. + """ + is_archive = isinstance(target, basestring) + args = [path_util.GetReadElfPath(tool_prefix), '-S', '--wide'] + if is_archive: + args.append(target) + else: + # Assign path for when len(target) == 1, (no File: line exists). + path = target[0] + args.extend(target) + + output = subprocess.check_output(args, cwd=output_directory) + lines = output.splitlines() + section_positions_by_path = {} + cur_offsets = [] + for line in lines: + # File: base/third_party/libevent/libevent.a(buffer.o) + # [Nr] Name Type Addr Off Size ES Flg Lk Inf Al + # [11] .rodata.str1.1 PROGBITS 00000000 0000b4 000004 01 AMS 0 0 1 + # [11] .rodata.str4.4 PROGBITS 00000000 0000b4 000004 01 AMS 0 0 4 + # [11] .rodata.str8.8 PROGBITS 00000000 0000b4 000004 01 AMS 0 0 8 + # [80] .rodata..L.str PROGBITS 00000000 000530 000002 00 A 0 0 1 + # The various string sections differ by alignment. + # The presence of a wchar_t literal (L"asdf") seems to make a str4 section. + # When multiple sections exist, nm gives us no indication as to which + # section each string corresponds to. + if line.startswith('File: '): + if cur_offsets: + section_positions_by_path[path] = cur_offsets + cur_offsets = [] + path = line[6:] + elif '.rodata.' in line: + progbits_idx = line.find('PROGBITS ') + if progbits_idx != -1: + fields = line[progbits_idx:].split() + position = (int(fields[2], 16), int(fields[3], 16)) + # The heuristics in _IterStringLiterals rely on str1 coming first. + if fields[-1] == '1': + cur_offsets.insert(0, position) + else: + cur_offsets.append(position) + if cur_offsets: + section_positions_by_path[path] = cur_offsets + return section_positions_by_path + + +def LookupElfRodataInfo(elf_path, tool_prefix): + """Returns (address, offset, size) for the .rodata section.""" + args = [path_util.GetReadElfPath(tool_prefix), '-S', '--wide', elf_path] + output = subprocess.check_output(args) + lines = output.splitlines() + for line in lines: + # [Nr] Name Type Addr Off Size ES Flg Lk Inf Al + # [07] .rodata PROGBITS 025e7000 237c000 5ec4f6 00 A 0 0 256 + if '.rodata ' in line: + fields = line[line.index(models.SECTION_RODATA):].split() + return int(fields[2], 16), int(fields[3], 16), int(fields[4], 16) + raise AssertionError('No .rodata for command: ' + repr(args)) + + +def _ReadFileChunks(path, positions): + """Returns a list of strings corresponding to |positions|. + + Args: + positions: List of (offset, size). + """ ret = [] + if not positions: + return ret + with open(path, 'rb') as f: + for offset, size in positions: + f.seek(offset) + ret.append(f.read(size)) + return ret + + +def _IterArchiveChunks(path): + """For each .o embedded in the given .a file, yields (foo.o, foo_contents).""" + with open(path, 'rb') as f: + if f.read(8) != '!<arch>\n' : + raise Exception('Invalid .a: ' + path) + while True: + line = f.readline() + if not line: + return + parts = line.split() + chunk_size = int(parts[-2]) + chunk_data = f.read(chunk_size) + + name = parts[0] + if name == '/': + # Initial metadata chunk. + continue + elif name == '//': + name_list = chunk_data + continue + elif name[0] == '/': + # Name is specified as location in name table. + # E.g.: /123 + name_offset = int(name[1:]) + slash_idx = name_list.index('/', name_offset) + name = name_list[name_offset:slash_idx] + else: + # Name is specified inline. + # E.g.: foo.o/ + # Name may not have whitespace before next field, so use rindex. + # E.g.: somelongername.o/1234 + name = name[:name.rindex('/')] + yield name, chunk_data + + +def _ParseOneObjectFileNmOutput(lines): + # Constructors are often repeated because they have the same unmangled + # name, but multiple mangled names. See: + # https://stackoverflow.com/questions/6921295/dual-emission-of-constructor-symbols + symbol_names = set() + string_addresses = [] for line in lines: if not line: break space_idx = line.find(' ') # Skip over address. - name = line[space_idx + 3:] - if _IsRelevantNmName(name) and _IsRelevantObjectFileName(name): - ret.append(name) - return ret + section = line[space_idx + 1] + mangled_name = line[space_idx + 3:] + if _IsRelevantNmName(mangled_name): + # Refer to _IsRelevantObjectFileName() for examples of names. + if section == 'r' and ( + mangled_name.startswith('.L.str') or + mangled_name.startswith('.L__') and mangled_name.find('.', 3) != -1): + # Leave as a string for easier marshalling. + string_addresses.append(line[:space_idx].lstrip('0') or '0') + elif _IsRelevantObjectFileName(mangled_name): + symbol_names.add(mangled_name) + return string_addresses, symbol_names -def _BatchCollectNames(target, tool_prefix, output_directory): +def _ReadStringSections(target, output_directory, positions_by_path): + """Returns a dict of object_path -> [string...] of .rodata chunks. + + Args: + target: An archive path string (e.g., "foo.a") or a list of object paths. + positions_by_path: A dict of object_path -> [(offset, size)...] + """ is_archive = isinstance(target, basestring) - # Ensure tool_prefix is absolute so that CWD does not affect it - if os.path.sep in tool_prefix: - # Use abspath() on the dirname to avoid it stripping a trailing /. - dirname = os.path.dirname(tool_prefix) - tool_prefix = os.path.abspath(dirname) + tool_prefix[len(dirname):] + string_sections_by_path = {} + if is_archive: + for subpath, chunk in _IterArchiveChunks( + os.path.join(output_directory, target)): + path = '{}({})'.format(target, subpath) + positions = positions_by_path.get(path) + # No positions if file has no string literals. + if positions: + string_sections_by_path[path] = ( + [chunk[offset:offset + size] for offset, size in positions]) + else: + for path in target: + positions = positions_by_path.get(path) + # We already log a warning about this in _IterStringLiterals(). + if positions: + string_sections_by_path[path] = _ReadFileChunks( + os.path.join(output_directory, path), positions) + return string_sections_by_path - args = [tool_prefix + 'nm', '--no-sort', '--defined-only', '--demangle'] + +def _ExtractArchivePath(path): + # E.g. foo/bar.a(baz.o) + if path.endswith(')'): + start_idx = path.index('(') + return path[:start_idx] + return None + + +def _IterStringLiterals(path, addresses, obj_sections): + """Yields all string literals (including \0) for the given object path. + + Args: + path: Object file path. + addresses: List of string offsets encoded as hex strings. + obj_sections: List of contents of .rodata.str sections read from the given + object file. + """ + + next_offsets = sorted(int(a, 16) for a in addresses) + if not obj_sections: + # Happens when there is an address for a symbol which is not actually a + # string literal, or when string_sections_by_path is missing an entry. + logging.warning('Object has %d strings but no string sections: %s', + len(addresses), path) + return + for section_data in obj_sections: + cur_offsets = next_offsets + # Always assume first element is 0. I'm not entirely sure why this is + # necessary, but strings get missed without it. + next_offsets = [0] + prev_offset = 0 + # TODO(agrieve): Switch to using nm --print-size in order to capture the + # address+size of each string rather than just the address. + for offset in cur_offsets[1:]: + if offset >= len(section_data): + # Remaining offsets are for next section. + next_offsets.append(offset) + continue + # Figure out which offsets apply to this section via heuristic of them + # all ending with a null character. + if offset == prev_offset or section_data[offset - 1] != '\0': + next_offsets.append(offset) + continue + yield section_data[prev_offset:offset] + prev_offset = offset + + if prev_offset < len(section_data): + yield section_data[prev_offset:] + + +# This is a target for BulkForkAndCall(). +def _ResolveStringPieces(encoded_string_addresses_by_path, string_data, + tool_prefix, output_directory): + string_addresses_by_path = concurrent.DecodeDictOfLists( + encoded_string_addresses_by_path) + # Assign |target| as archive path, or a list of object paths. + any_path = next(string_addresses_by_path.iterkeys()) + target = _ExtractArchivePath(any_path) + if not target: + target = string_addresses_by_path.keys() + + # Run readelf to find location of .rodata within the .o files. + section_positions_by_path = _LookupStringSectionPositions( + target, tool_prefix, output_directory) + # Load the .rodata sections (from object files) as strings. + string_sections_by_path = _ReadStringSections( + target, output_directory, section_positions_by_path) + + # list of elf_positions_by_path. + ret = [collections.defaultdict(list) for _ in string_data] + # Brute-force search of strings within ** merge strings sections. + # This is by far the slowest part of AnalyzeStringLiterals(). + # TODO(agrieve): Pre-process string_data into a dict of literal->address (at + # least for ascii strings). + for path, object_addresses in string_addresses_by_path.iteritems(): + for value in _IterStringLiterals( + path, object_addresses, string_sections_by_path.get(path)): + first_match = -1 + first_match_dict = None + for target_dict, data in itertools.izip(ret, string_data): + # Set offset so that it will be 0 when len(value) is added to it below. + offset = -len(value) + while True: + offset = data.find(value, offset + len(value)) + if offset == -1: + break + # Preferring exact matches (those following \0) over substring matches + # significantly increases accuracy (although shows that linker isn't + # being optimal). + if offset == 0 or data[offset - 1] == '\0': + break + if first_match == -1: + first_match = offset + first_match_dict = target_dict + if offset != -1: + break + if offset == -1: + # Exact match not found, so take suffix match if it exists. + offset = first_match + target_dict = first_match_dict + # Missing strings happen when optimization make them unused. + if offset != -1: + # Encode tuple as a string for easier mashalling. + target_dict[path].append( + str(offset) + ':' + str(len(value))) + + return [concurrent.EncodeDictOfLists(x) for x in ret] + + +# This is a target for BulkForkAndCall(). +def _RunNmOnIntermediates(target, tool_prefix, output_directory): + """Returns encoded_symbol_names_by_path, encoded_string_addresses_by_path. + + Args: + target: Either a single path to a .a (as a string), or a list of .o paths. + """ + is_archive = isinstance(target, basestring) + args = [path_util.GetNmPath(tool_prefix), '--no-sort', '--defined-only'] if is_archive: args.append(target) else: args.extend(target) output = subprocess.check_output(args, cwd=output_directory) lines = output.splitlines() + # Empty .a file has no output. if not lines: - return '', '' + return concurrent.EMPTY_ENCODED_DICT, concurrent.EMPTY_ENCODED_DICT is_multi_file = not lines[0] lines = iter(lines) if is_multi_file: @@ -154,32 +486,40 @@ assert not is_archive path = target[0] - ret = {} - while True: + string_addresses_by_path = {} + symbol_names_by_path = {} + while path: if is_archive: # E.g. foo/bar.a(baz.o) path = '%s(%s)' % (target, path) - # The multiprocess API uses pickle, which is ridiculously slow. More than 2x - # faster to use join & split. - ret[path] = _ParseOneObjectFileOutput(lines) + + string_addresses, mangled_symbol_names = _ParseOneObjectFileNmOutput(lines) + symbol_names_by_path[path] = mangled_symbol_names + if string_addresses: + string_addresses_by_path[path] = string_addresses path = next(lines, ':')[:-1] - if not path: - return concurrent.EncodeDictOfLists(ret) + + # The multiprocess API uses pickle, which is ridiculously slow. More than 2x + # faster to use join & split. + # TODO(agrieve): We could use path indices as keys rather than paths to cut + # down on marshalling overhead. + return (concurrent.EncodeDictOfLists(symbol_names_by_path), + concurrent.EncodeDictOfLists(string_addresses_by_path)) class _BulkObjectFileAnalyzerWorker(object): - """Runs nm on all given paths and returns a dict of name->[paths]""" - def __init__(self, tool_prefix, output_directory): - self._tool_prefix = tool_prefix + self._tool_prefix = _MakeToolPrefixAbsolute(tool_prefix) self._output_directory = output_directory - self._batches = [] - self._result = None + self._paths_by_name = collections.defaultdict(list) + self._encoded_string_addresses_by_path_chunks = [] + self._list_of_encoded_elf_string_positions_by_path = None def AnalyzePaths(self, paths): def iter_job_params(): object_paths = [] for path in paths: + # Note: _ResolveStringPieces relies upon .a not being grouped. if path.endswith('.a'): yield path, self._tool_prefix, self._output_directory else: @@ -190,80 +530,206 @@ batch = object_paths[i:i + BATCH_SIZE] yield batch, self._tool_prefix, self._output_directory - paths_by_name = collections.defaultdict(list) params = list(iter_job_params()) - for encoded_ret in concurrent.BulkForkAndCall(_BatchCollectNames, params): - names_by_path = concurrent.DecodeDictOfLists(*encoded_ret) - for path, names in names_by_path.iteritems(): + # Order of the jobs doesn't matter since each job owns independent paths, + # and our output is a dict where paths are the key. + results = concurrent.BulkForkAndCall(_RunNmOnIntermediates, params) + + # Names are still mangled. + all_paths_by_name = self._paths_by_name + for encoded_syms, encoded_strs in results: + symbol_names_by_path = concurrent.DecodeDictOfLists(encoded_syms) + for path, names in symbol_names_by_path.iteritems(): for name in names: - paths_by_name[name].append(path) - self._batches.append(paths_by_name) + all_paths_by_name[name].append(path) + + if encoded_strs != concurrent.EMPTY_ENCODED_DICT: + self._encoded_string_addresses_by_path_chunks.append(encoded_strs) + logging.debug('worker: AnalyzePaths() completed.') + + def SortPaths(self): + # Finally, demangle all names, which can result in some merging of lists. + self._paths_by_name = demangle.DemangleKeysAndMergeLists( + self._paths_by_name, self._tool_prefix) + # Sort and uniquefy. + for key in self._paths_by_name.iterkeys(): + self._paths_by_name[key] = sorted(set(self._paths_by_name[key])) + + def AnalyzeStringLiterals(self, elf_path, elf_string_positions): + logging.debug('worker: AnalyzeStringLiterals() started.') + # Read string_data from elf_path, to be shared by forked processes. + address, offset, _ = LookupElfRodataInfo(elf_path, self._tool_prefix) + adjust = address - offset + abs_string_positions = ( + (addr - adjust, s) for addr, s in elf_string_positions) + string_data = _ReadFileChunks(elf_path, abs_string_positions) + + params = ( + (chunk, string_data, self._tool_prefix, self._output_directory) + for chunk in self._encoded_string_addresses_by_path_chunks) + # Order of the jobs doesn't matter since each job owns independent paths, + # and our output is a dict where paths are the key. + results = concurrent.BulkForkAndCall(_ResolveStringPieces, params) + results = list(results) + + final_result = [] + for i in xrange(len(elf_string_positions)): + final_result.append( + concurrent.JoinEncodedDictOfLists([r[i] for r in results])) + self._list_of_encoded_elf_string_positions_by_path = final_result + logging.debug('worker: AnalyzeStringLiterals() completed.') + + def GetSymbolNames(self): + return self._paths_by_name + + def GetStringPositions(self): + return [concurrent.DecodeDictOfLists(x, value_transform=_DecodePosition) + for x in self._list_of_encoded_elf_string_positions_by_path] + + def GetEncodedStringPositions(self): + return self._list_of_encoded_elf_string_positions_by_path def Close(self): - assert self._result is None - assert self._batches - paths_by_name = self._batches[0] - for batch in self._batches[1:]: - for name, path_list in batch.iteritems(): - paths_by_name.setdefault(name, []).extend(path_list) - - # It would speed up mashalling of the values by removing all entries - # that have only 1 path. However, these entries are needed to give - # path information to symbol aliases. - self._result = paths_by_name - - def Get(self): - assert self._result is not None - return self._result + pass def _TerminateSubprocesses(): - for proc in _active_subprocesses: - proc.kill() + global _active_pids + if _active_pids: + for pid in _active_pids: + os.kill(pid, signal.SIGKILL) + _active_pids = [] class _BulkObjectFileAnalyzerMaster(object): """Runs BulkObjectFileAnalyzer in a subprocess.""" - def __init__(self, tool_prefix, output_directory): - self._process = None + self._child_pid = None + self._pipe = None self._tool_prefix = tool_prefix self._output_directory = output_directory def _Spawn(self): - global _active_subprocesses - log_level = str(logging.getLogger().getEffectiveLevel()) - args = [sys.executable, __file__, log_level, self._tool_prefix, - self._output_directory] - self._process = subprocess.Popen( - args, stdin=subprocess.PIPE, stdout=subprocess.PIPE) - if _active_subprocesses is None: - _active_subprocesses = [] - atexit.register(_TerminateSubprocesses) - _active_subprocesses.append(self._process) + global _active_pids + parent_conn, child_conn = multiprocessing.Pipe() + self._child_pid = os.fork() + if self._child_pid: + # We are the parent process. + if _active_pids is None: + _active_pids = [] + atexit.register(_TerminateSubprocesses) + _active_pids.append(self._child_pid) + self._pipe = parent_conn + else: + # We are the child process. + logging.root.handlers[0].setFormatter(logging.Formatter( + 'nm: %(levelname).1s %(relativeCreated)6d %(message)s')) + worker_analyzer = _BulkObjectFileAnalyzerWorker( + self._tool_prefix, self._output_directory) + slave = _BulkObjectFileAnalyzerSlave(worker_analyzer, child_conn) + slave.Run() def AnalyzePaths(self, paths): - if self._process is None: + if self._child_pid is None: self._Spawn() logging.debug('Sending batch of %d paths to subprocess', len(paths)) payload = '\x01'.join(paths) - self._process.stdin.write('{:08x}'.format(len(payload))) - self._process.stdin.write(payload) + self._pipe.send((_MSG_ANALYZE_PATHS, payload)) + + def SortPaths(self): + self._pipe.send((_MSG_SORT_PATHS,)) + + def AnalyzeStringLiterals(self, elf_path, string_positions): + self._pipe.send((_MSG_ANALYZE_STRINGS, elf_path, string_positions)) + + def GetSymbolNames(self): + self._pipe.send((_MSG_GET_SYMBOL_NAMES,)) + self._pipe.recv() # None + logging.debug('Decoding nm results from forked process') + encoded_paths_by_name = self._pipe.recv() + return concurrent.DecodeDictOfLists(encoded_paths_by_name) + + def GetStringPositions(self): + self._pipe.send((_MSG_GET_STRINGS,)) + self._pipe.recv() # None + logging.debug('Decoding string symbol results from forked process') + result = self._pipe.recv() + return [concurrent.DecodeDictOfLists(x, value_transform=_DecodePosition) + for x in result] def Close(self): - assert not self._process.stdin.closed - self._process.stdin.close() - _active_subprocesses.remove(self._process) + self._pipe.close() + # Child process should terminate gracefully at this point, but leave it in + # _active_pids to be killed just in case. - def Get(self): - assert self._process.stdin.closed - logging.debug('Decoding nm results from forked process') - encoded_keys_len = int(self._process.stdout.read(8), 16) - encoded_keys = self._process.stdout.read(encoded_keys_len) - encoded_values = self._process.stdout.read() - return concurrent.DecodeDictOfLists(encoded_keys, encoded_values) +class _BulkObjectFileAnalyzerSlave(object): + """The subprocess entry point.""" + def __init__(self, worker_analyzer, pipe): + self._worker_analyzer = worker_analyzer + self._pipe = pipe + # Use a worker thread so that AnalyzeStringLiterals() is non-blocking. The + # thread allows the main thread to process a call to GetSymbolNames() while + # AnalyzeStringLiterals() is in progress. + self._job_queue = Queue.Queue() + self._worker_thread = threading.Thread(target=self._WorkerThreadMain) + self._allow_analyze_paths = True + + def _WorkerThreadMain(self): + while True: + # Handle exceptions so test failure will be explicit and not block. + try: + func = self._job_queue.get() + func() + except Exception: + traceback.print_exc() + self._job_queue.task_done() + + def _WaitForAnalyzePathJobs(self): + if self._allow_analyze_paths: + self._job_queue.join() + self._allow_analyze_paths = False + + def Run(self): + try: + self._worker_thread.start() + while True: + message = self._pipe.recv() + if message[0] == _MSG_ANALYZE_PATHS: + assert self._allow_analyze_paths, ( + 'Cannot call AnalyzePaths() after AnalyzeStringLiterals()s.') + paths = message[1].split('\x01') + self._job_queue.put(lambda: self._worker_analyzer.AnalyzePaths(paths)) + elif message[0] == _MSG_SORT_PATHS: + assert self._allow_analyze_paths, ( + 'Cannot call SortPaths() after AnalyzeStringLiterals()s.') + self._job_queue.put(self._worker_analyzer.SortPaths) + elif message[0] == _MSG_ANALYZE_STRINGS: + self._WaitForAnalyzePathJobs() + elf_path, string_positions = message[1:] + self._job_queue.put( + lambda: self._worker_analyzer.AnalyzeStringLiterals( + elf_path, string_positions)) + elif message[0] == _MSG_GET_SYMBOL_NAMES: + self._WaitForAnalyzePathJobs() + self._pipe.send(None) + paths_by_name = self._worker_analyzer.GetSymbolNames() + self._pipe.send(concurrent.EncodeDictOfLists(paths_by_name)) + elif message[0] == _MSG_GET_STRINGS: + self._job_queue.join() + # Send a None packet so that other side can measure IPC transfer time. + self._pipe.send(None) + self._pipe.send(self._worker_analyzer.GetEncodedStringPositions()) + except EOFError: + pass + except EnvironmentError, e: + # Parent process exited so don't log. + if e.errno in (errno.EPIPE, errno.ECONNRESET): + sys.exit(1) + + logging.debug('nm bulk subprocess finished.') + sys.exit(0) BulkObjectFileAnalyzer = _BulkObjectFileAnalyzerMaster @@ -271,33 +737,55 @@ BulkObjectFileAnalyzer = _BulkObjectFileAnalyzerWorker -def _SubMain(log_level, tool_prefix, output_directory): - logging.basicConfig( - level=int(log_level), - format='nm: %(levelname).1s %(relativeCreated)6d %(message)s') - bulk_analyzer = _BulkObjectFileAnalyzerWorker(tool_prefix, output_directory) - while True: - payload_len = int(sys.stdin.read(8) or '0', 16) - if not payload_len: - logging.debug('nm bulk subprocess received eof.') - break - paths = sys.stdin.read(payload_len).split('\x01') - bulk_analyzer.AnalyzePaths(paths) +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--multiprocess', action='store_true') + parser.add_argument('--tool-prefix', required=True) + parser.add_argument('--output-directory', required=True) + parser.add_argument('--elf-file', type=os.path.realpath) + parser.add_argument('--show-names', action='store_true') + parser.add_argument('--show-strings', action='store_true') + parser.add_argument('objects', type=os.path.realpath, nargs='+') - bulk_analyzer.Close() - paths_by_name = bulk_analyzer.Get() - encoded_keys, encoded_values = concurrent.EncodeDictOfLists(paths_by_name) - try: - sys.stdout.write('%08x' % len(encoded_keys)) - sys.stdout.write(encoded_keys) - sys.stdout.write(encoded_values) - except IOError, e: - # Parent process exited. - if e.errno == errno.EPIPE: - sys.exit(1) + args = parser.parse_args() + logging.basicConfig(level=logging.DEBUG, + format='%(levelname).1s %(relativeCreated)6d %(message)s') - logging.debug('nm bulk subprocess finished.') + if args.multiprocess: + bulk_analyzer = _BulkObjectFileAnalyzerMaster( + args.tool_prefix, args.output_directory) + else: + concurrent.DISABLE_ASYNC = True + bulk_analyzer = _BulkObjectFileAnalyzerWorker( + args.tool_prefix, args.output_directory) + + # Pass individually to test multiple calls. + for path in args.objects: + bulk_analyzer.AnalyzePaths([path]) + bulk_analyzer.SortPaths() + + names_to_paths = bulk_analyzer.GetSymbolNames() + print('Found {} names'.format(len(names_to_paths))) + if args.show_names: + for name, paths in names_to_paths.iteritems(): + print('{}: {!r}'.format(name, paths)) + + if args.elf_file: + address, offset, size = LookupElfRodataInfo( + args.elf_file, args.tool_prefix) + bulk_analyzer.AnalyzeStringLiterals(args.elf_file, ((address, size),)) + + positions_by_path = bulk_analyzer.GetStringPositions()[0] + print('Found {} string literals'.format(sum( + len(v) for v in positions_by_path.itervalues()))) + if args.show_strings: + logging.debug('.rodata adjust=%d', address - offset) + for path, positions in positions_by_path.iteritems(): + strs = _ReadFileChunks( + args.elf_file, ((offset + addr, size) for addr, size in positions)) + print('{}: {!r}'.format( + path, [s if len(s) < 20 else s[:20] + '...' for s in strs])) if __name__ == '__main__': - _SubMain(*sys.argv[1:]) + main()
diff --git a/tools/binary_size/libsupersize/path_util.py b/tools/binary_size/libsupersize/path_util.py new file mode 100644 index 0000000..ab2ff1c --- /dev/null +++ b/tools/binary_size/libsupersize/path_util.py
@@ -0,0 +1,166 @@ +# Copyright 2017 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. + +"""Functions for dealing with determining --tool-prefix.""" + +import abc +import distutils.spawn +import logging +import os + +_STATUS_DETECTED = 1 +_STATUS_VERIFIED = 2 + +SRC_ROOT = os.environ.get('CHECKOUT_SOURCE_ROOT', + os.path.abspath(os.path.join(os.path.dirname(__file__), + os.pardir, os.pardir, os.pardir))) + +_SAMPLE_TOOL_SUFFIX = 'readelf' + + +class _PathFinder(object): + def __init__(self, name, value): + self._status = _STATUS_DETECTED if value is not None else 0 + self._name = name + self._value = value + + @abc.abstractmethod + def Detect(self): + pass + + @abc.abstractmethod + def Verify(self): + pass + + def Tentative(self): + if self._status < _STATUS_DETECTED: + self._value = self.Detect() + logging.debug('Detected --%s=%s', self._name, self._value) + self._status = _STATUS_DETECTED + return self._value + + def Finalized(self): + if self._status < _STATUS_VERIFIED: + self.Tentative() + self.Verify() + logging.info('Using --%s=%s', self._name, self._value) + self._status = _STATUS_VERIFIED + return self._value + + +class OutputDirectoryFinder(_PathFinder): + def __init__(self, value=None, any_path_within_output_directory=None): + super(OutputDirectoryFinder, self).__init__( + name='output-directory', value=value) + self._any_path_within_output_directory = any_path_within_output_directory + + def Detect(self): + # Try and find build.ninja. + abs_path = os.path.abspath(self._any_path_within_output_directory) + while True: + if os.path.exists(os.path.join(abs_path, 'build.ninja')): + return os.path.relpath(abs_path) + parent_dir = os.path.dirname(abs_path) + if parent_dir == abs_path: + break + abs_path = abs_path = parent_dir + + # See if CWD=output directory. + if os.path.exists('build.ninja'): + return '.' + return None + + def Verify(self): + if not self._value or not os.path.isdir(self._value): + raise Exception('Bad --%s. Path not found: %s' % + (self._name, self._value)) + + +class ToolPrefixFinder(_PathFinder): + def __init__(self, value=None, output_directory_finder=None, + linker_name=None): + super(ToolPrefixFinder, self).__init__( + name='tool-prefix', value=value) + self._output_directory_finder = output_directory_finder + self._linker_name = linker_name; + + def Detect(self): + output_directory = self._output_directory_finder.Tentative() + if output_directory: + ret = None + if self._linker_name == 'lld': + ret = os.path.join(SRC_ROOT, 'third_party', 'llvm-build', + 'Release+Asserts', 'bin', 'llvm-') + else: + # Auto-detect from build_vars.txt + build_vars_path = os.path.join(output_directory, 'build_vars.txt') + if os.path.exists(build_vars_path): + with open(build_vars_path) as f: + build_vars = dict(l.rstrip().split('=', 1) for l in f if '=' in l) + tool_prefix = build_vars['android_tool_prefix'] + ret = os.path.normpath(os.path.join(output_directory, tool_prefix)) + # Maintain a trailing '/' if needed. + if tool_prefix.endswith(os.path.sep): + ret += os.path.sep + if ret: + # Check for output directories that have a stale build_vars.txt. + if os.path.isfile(ret + _SAMPLE_TOOL_SUFFIX): + return ret + else: + err_lines = ['tool-prefix not found: %s' % ret] + if ret.endswith('llvm-'): + err_lines.append('Probably need to run: ' + 'tools/clang/scripts/download_objdump.py') + raise Exception('\n'.join(err_lines)) + from_path = distutils.spawn.find_executable(_SAMPLE_TOOL_SUFFIX) + if from_path: + return from_path[:-7] + return None + + def Verify(self): + if os.path.sep not in self._value: + full_path = distutils.spawn.find_executable( + self._value + _SAMPLE_TOOL_SUFFIX) + else: + full_path = self._value + _SAMPLE_TOOL_SUFFIX + if not full_path or not os.path.isfile(full_path): + raise Exception('Bad --%s. Path not found: %s' % (self._name, full_path)) + + +def FromSrcRootRelative(path): + ret = os.path.relpath(os.path.join(SRC_ROOT, path)) + # Need to maintain a trailing /. + if path.endswith(os.path.sep): + ret += os.path.sep + return ret + + +def ToSrcRootRelative(path): + ret = os.path.relpath(path, SRC_ROOT) + # Need to maintain a trailing /. + if path.endswith(os.path.sep): + ret += os.path.sep + return ret + + +def GetCppFiltPath(tool_prefix): + if tool_prefix[-5:] == 'llvm-': + return tool_prefix + 'cxxfilt' + return tool_prefix + 'c++filt' + + +def GetNmPath(tool_prefix): + return tool_prefix + 'nm' + + +def GetObjDumpPath(tool_prefix): + return tool_prefix + 'objdump' + + +def GetReadElfPath(tool_prefix): + # Work-around for llvm-readobj bug where 'File: ...' info is not printed: + # https://bugs.llvm.org/show_bug.cgi?id=35351 + if tool_prefix[-5:] == 'llvm-': + return 'readelf' + return tool_prefix + 'readelf'
diff --git a/tools/binary_size/libsupersize/paths.py b/tools/binary_size/libsupersize/paths.py deleted file mode 100644 index a610e22..0000000 --- a/tools/binary_size/libsupersize/paths.py +++ /dev/null
@@ -1,120 +0,0 @@ -# Copyright 2017 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. - -"""Functions for dealing with determining --tool-prefix.""" - -import distutils.spawn -import logging -import os - -_STATUS_DETECTED = 1 -_STATUS_VERIFIED = 2 - -SRC_ROOT = os.path.dirname( - os.path.dirname(os.path.dirname(os.path.dirname(__file__)))) - - -class LazyPaths(object): - def __init__(self, tool_prefix=None, output_directory=None, - any_path_within_output_directory=None): - self._tool_prefix = tool_prefix - self._output_directory = output_directory - self._any_path_within_output_directory = any_path_within_output_directory - self._output_directory_status = ( - _STATUS_DETECTED if output_directory is not None else 0) - self._tool_prefix_status = ( - _STATUS_DETECTED if tool_prefix is not None else 0) - - @property - def tool_prefix(self): - if self._tool_prefix_status < _STATUS_DETECTED: - self._tool_prefix_status = _STATUS_DETECTED - self._tool_prefix = self._DetectToolPrefix() or '' - logging.debug('Detected --tool-prefix=%s', self._tool_prefix) - return self._tool_prefix - - @property - def output_directory(self): - if self._output_directory_status < _STATUS_DETECTED: - self._output_directory_status = _STATUS_DETECTED - self._output_directory = self._DetectOutputDirectory() - logging.debug('Detected --output-directory=%s', self._output_directory) - return self._output_directory - - def VerifyOutputDirectory(self): - output_directory = self.output_directory - if self._output_directory_status < _STATUS_VERIFIED: - self._output_directory_status = _STATUS_VERIFIED - if not output_directory or not os.path.isdir(output_directory): - raise Exception('Bad --output-directory. Path not found: %s' % - output_directory) - logging.info('Using --output-directory=%s', output_directory) - return output_directory - - def VerifyToolPrefix(self): - tool_prefix = self.tool_prefix - if self._tool_prefix_status < _STATUS_VERIFIED: - self._tool_prefix_status = _STATUS_VERIFIED - if os.path.sep not in tool_prefix: - full_path = distutils.spawn.find_executable(tool_prefix + 'c++filt') - else: - full_path = tool_prefix + 'c++filt' - - if not full_path or not os.path.isfile(full_path): - raise Exception('Bad --tool-prefix. Path not found: %s' % full_path) - logging.info('Using --tool-prefix=%s', self._tool_prefix) - return tool_prefix - - def _DetectOutputDirectory(self): - # Try and find build.ninja. - abs_path = os.path.abspath(self._any_path_within_output_directory) - while True: - if os.path.exists(os.path.join(abs_path, 'build.ninja')): - return os.path.relpath(abs_path) - parent_dir = os.path.dirname(abs_path) - if parent_dir == abs_path: - break - abs_path = abs_path = parent_dir - - # See if CWD=output directory. - if os.path.exists('build.ninja'): - return '.' - return None - - def _DetectToolPrefix(self): - output_directory = self.output_directory - if output_directory: - # Auto-detect from build_vars.txt - build_vars_path = os.path.join(output_directory, 'build_vars.txt') - if os.path.exists(build_vars_path): - with open(build_vars_path) as f: - build_vars = dict(l.rstrip().split('=', 1) for l in f if '=' in l) - tool_prefix = build_vars['android_tool_prefix'] - ret = os.path.normpath(os.path.join(output_directory, tool_prefix)) - # Need to maintain a trailing /. - if tool_prefix.endswith(os.path.sep): - ret += os.path.sep - # Check for output directories that have a stale build_vars.txt. - if os.path.isfile(ret + 'c++filt'): - return ret - from_path = distutils.spawn.find_executable('c++filt') - if from_path: - return from_path[:-7] - return None - - -def FromSrcRootRelative(path): - ret = os.path.relpath(os.path.join(SRC_ROOT, path)) - # Need to maintain a trailing /. - if path.endswith(os.path.sep): - ret += os.path.sep - return ret - - -def ToSrcRootRelative(path): - ret = os.path.relpath(path, SRC_ROOT) - # Need to maintain a trailing /. - if path.endswith(os.path.sep): - ret += os.path.sep - return ret
diff --git a/tools/binary_size/libsupersize/template/D3SymbolTreeMap.js b/tools/binary_size/libsupersize/template/D3SymbolTreeMap.js index 654a503..e7d3b6f 100644 --- a/tools/binary_size/libsupersize/template/D3SymbolTreeMap.js +++ b/tools/binary_size/libsupersize/template/D3SymbolTreeMap.js
@@ -78,6 +78,9 @@ 't': '.text', 'v': 'Vtable entry', '!': 'Generated Symbols (typeinfo, thunks, etc)', + 'p': 'Locale Pak Entries', + 'P': 'Non-Locale Pak Entries', + 'o': 'Other Entries', }; D3SymbolTreeMap._NM_SYMBOL_TYPES = ''; for (var symbol_type in D3SymbolTreeMap._NM_SYMBOL_TYPE_DESCRIPTIONS) { @@ -105,6 +108,9 @@ 'rgb(128,177,211)', 'rgb(255,237,111)', 'rgb(204,235,197)', + 'rgb(93,156,110)', + 'rgb(61,109,55)', + 'rgb(255,111,111)', ] D3SymbolTreeMap._initColorMap = function() {
diff --git a/tools/binary_size/libsupersize/template/index.html b/tools/binary_size/libsupersize/template/index.html index 0d41597..81a9e70 100644 --- a/tools/binary_size/libsupersize/template/index.html +++ b/tools/binary_size/libsupersize/template/index.html
@@ -24,7 +24,7 @@ var treemap; var filterChanging = false; var savedSettings = {}; -var NUM_SYMBOL_TYPES = 6 +var NUM_SYMBOL_TYPES = 9; function init() { if (window.metadata !== undefined && window.metadata.subtitle) { @@ -36,6 +36,7 @@ savedSettings.height, savedSettings.maxLevels); treemap.init(); + applyFilter(); // Required to make .other hidden by default. } function getIdealSizes() { @@ -209,7 +210,12 @@ } function initFilterOptions() { - updateFilterText(); + var filterFromUrl = new URL(window.location).searchParams.get('sections'); + if (filterFromUrl) { + document.getElementById('symbol_types_filter').value = filterFromUrl; + } else { + updateFilterText(); + } for (var x=0; x<NUM_SYMBOL_TYPES; x++) { var checkBox = document.getElementById('check_' + x); checkBox.onchange=updateFilterText; @@ -256,6 +262,67 @@ container.style.visibility = 'hidden'; } +function applyFilter() { + // Type filters + var typeFilter = function(datum) { + if (datum.depth === 0) return true; // root node + if (datum.t === undefined) return true; + return savedSettings.symbolTypes !== undefined && + savedSettings.symbolTypes.indexOf(datum.t) !== -1; + } + + // Regex filter + var regexFilter; + if (savedSettings.regex !== undefined && savedSettings.regex.length > 0) { + console.log('filter: regex is "' + savedSettings.regex + '"'); + var regex = new RegExp(savedSettings.regex); + regexFilter = function(datum) { + if (datum.depth === 0) return true; // root node + var fullName = this.pathFor(datum); + if (datum.children === undefined) { // it is a leaf node (symbol) + fullName += ':' + datum.n; + } + return regex.test(fullName); + } + } + + // Exclude regex filter + var excludeRegexFilter = undefined; + if (savedSettings.excludeRegex !== undefined && savedSettings.excludeRegex.length > 0) { + console.log('filter: exclude-regex is "' + savedSettings.excludeRegex + '"'); + var excludeRegex = new RegExp(savedSettings.excludeRegex); + excludeRegexFilter = function(datum) { + if (datum.depth === 0) return true; // root node + var fullName = this.pathFor(datum); + if (datum.children === undefined) { // it is a leaf node (symbol) + fullName += ':' + datum.n; + } + return !excludeRegex.test(fullName); + } + } + + // Size filter + var sizeFilter = undefined; + if (savedSettings.gte !== undefined) { + console.log('filter: minimum size is ' + savedSettings.gte + ' bytes'); + sizeFilter = function(datum) { + if (datum.children !== undefined) return true; // non-leaf + if (datum.value === undefined) console.log('whoops'); + return datum.value >= savedSettings.gte; + } + } + + // Make a filter to apply to the tree + var filter = function(datum) { + if (!typeFilter.call(this, datum)) return false; + if (regexFilter && !regexFilter.call(this, datum)) return false; + if (excludeRegexFilter && !excludeRegexFilter.call(this, datum)) return false; + if (sizeFilter && !sizeFilter.call(this, datum)) return false; + return true; + }; + treemap.filter(filter); +} + function applySettings() { hideOptions(); var oldWidth = savedSettings.width; @@ -275,64 +342,7 @@ var maxLevelsChanged = oldMaxLevels !== savedSettings.maxLevels; if (filterChanged) { - // Type filters - typeFilter = function(datum) { - if (datum.depth === 0) return true; // root node - if (datum.t === undefined) return true; - return savedSettings.symbolTypes !== undefined && - savedSettings.symbolTypes.indexOf(datum.t) !== -1; - } - - // Regex filter - var regexFilter = undefined; - if (savedSettings.regex !== undefined && savedSettings.regex.length > 0) { - console.log('filter: regex is "' + savedSettings.regex + '"'); - var regex = new RegExp(savedSettings.regex); - regexFilter = function(datum) { - if (datum.depth === 0) return true; // root node - var fullName = this.pathFor(datum); - if (datum.children === undefined) { // it is a leaf node (symbol) - fullName += ':' + datum.n; - } - return regex.test(fullName); - } - } - - // Exclude regex filter - var excludeRegexFilter = undefined; - if (savedSettings.excludeRegex !== undefined && savedSettings.excludeRegex.length > 0) { - console.log('filter: exclude-regex is "' + savedSettings.excludeRegex + '"'); - var excludeRegex = new RegExp(savedSettings.excludeRegex); - excludeRegexFilter = function(datum) { - if (datum.depth === 0) return true; // root node - var fullName = this.pathFor(datum); - if (datum.children === undefined) { // it is a leaf node (symbol) - fullName += ':' + datum.n; - } - return !excludeRegex.test(fullName); - } - } - - // Size filter - var sizeFilter = undefined; - if (savedSettings.gte !== undefined) { - console.log('filter: minimum size is ' + savedSettings.gte + ' bytes'); - sizeFilter = function(datum) { - if (datum.children !== undefined) return true; // non-leaf - if (datum.value === undefined) console.log('whoops'); - return datum.value >= savedSettings.gte; - } - } - - // Make a filter to apply to the tree - var filter = function(datum) { - if (typeFilter && !typeFilter.call(this, datum)) return false; - if (regexFilter && !regexFilter.call(this, datum)) return false; - if (excludeRegexFilter && !excludeRegexFilter.call(this, datum)) return false; - if (sizeFilter && !sizeFilter.call(this, datum)) return false; - return true; - }; - treemap.filter(filter); + applyFilter(); } // Adjust levels if needed. @@ -433,6 +443,9 @@ <br><span class='swatch' id='swatch_3'> </span><input checked type='checkbox' id='check_3' value='t'>Code (.text) <br><span class='swatch' id='swatch_4'> </span><input checked type='checkbox' id='check_4' value='v'>Vtable entries <br><span class='swatch' id='swatch_5'> </span><input checked type='checkbox' id='check_5' value='!'>Generated Symbols (typeinfo, thunks, etc) + <br><span class='swatch' id='swatch_6'> </span><input checked type='checkbox' id='check_6' value='p'>Locale Pak Entries + <br><span class='swatch' id='swatch_7'> </span><input checked type='checkbox' id='check_7' value='P'>Non-Locale Pak Entries + <br><span class='swatch' id='swatch_8'> </span><input type='checkbox' id='check_8' value='o'>Other Entries </td> </tr> <tr><td style='text-align: center; white-space: nowrap; padding-top: 1em;'>
diff --git a/tools/binary_size/libsupersize/testdata/Archive.golden b/tools/binary_size/libsupersize/testdata/Archive.golden index 6875255d..75c121e3 100644 --- a/tools/binary_size/libsupersize/testdata/Archive.golden +++ b/tools/binary_size/libsupersize/testdata/Archive.golden
@@ -4,20 +4,50 @@ * Contains 0 aliases * 0 symbols have shared ownership Section .rodata: has 100.0% of 5927652 bytes accounted for from 10 symbols. 0 bytes are unaccounted for. -* Padding accounts for 11 bytes (0.0%) -* 5 placeholders (symbols that start with **) account for 5927509 bytes (100.0%) +* Padding accounts for 675996 bytes (11.4%) +* 5 placeholders (symbols that start with **) account for 5251524 bytes (88.6%) +* Contains 0 string literals. Total size=0, padding=0 +* Contains 0 aliases * 0 symbols have shared ownership Section .data.rel.ro: has 100.0% of 1065224 bytes accounted for from 4 symbols. 0 bytes are unaccounted for. * Padding accounts for 0 bytes (0.0%) * 1 placeholders (symbols that start with **) account for 1065132 bytes (100.0%) +* Contains 0 aliases * 0 symbols have shared ownership Section .data: has 100.0% of 101768 bytes accounted for from 6 symbols. 0 bytes are unaccounted for. * Padding accounts for 0 bytes (0.0%) * 1 placeholders (symbols that start with **) account for 101600 bytes (99.8%) +* Contains 0 aliases * 0 symbols have shared ownership Section .bss: has 40.3% of 524520 bytes accounted for from 6 symbols. 775936 bytes are unaccounted for. * Padding accounts for 196 bytes (0.0%) +* Contains 0 aliases * 0 symbols have shared ownership +.data@2de7000(size_without_padding=4,padding=0,full_name=google::protobuf::internal::pLinuxKernelCmpxchg,object_path=base/base/page_allocator.o,source_path=,flags={},num_aliases=1) +.data@2de7004(size_without_padding=4,padding=0,full_name=google::protobuf::internal::pLinuxKernelMemoryBarrier,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=,flags={},num_aliases=1) +.data@2de7008(size_without_padding=152,padding=0,full_name=base::android::kBaseRegisteredMethods,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=,flags={rel},num_aliases=1) +.data@2de70a0(size_without_padding=4,padding=0,full_name=base::android::g_renderer_histogram_code,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=,flags={anon},num_aliases=1) +.data@2de70a4(size_without_padding=4,padding=0,full_name=base::android::g_library_version_number,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=,flags={anon,rel.loc},num_aliases=1) +.data@2dffd88(size_without_padding=0,padding=101600,full_name=** symbol gap 0 (end of section),object_path=,source_path=,flags={},num_aliases=1) +.data.rel.ro@2cd8500(size_without_padding=56,padding=0,full_name=ChromeMainDelegateAndroid [vtable],object_path=third_party/WebKit.a/PaintChunker.o,source_path=,flags={},num_aliases=1) +.data.rel.ro@2cd8538(size_without_padding=24,padding=0,full_name=mojo::MessageReceiver [vtable],object_path=base/base/page_allocator.o,source_path=,flags={},num_aliases=1) +.data.rel.ro@2cd8550(size_without_padding=12,padding=0,full_name=kMethodsAnimationFrameTimeHistogram,object_path=base/base/page_allocator.o,source_path=,flags={},num_aliases=1) +.data.rel.ro@2ddc608(size_without_padding=0,padding=1065132,full_name=** symbol gap 0 (end of section),object_path=,source_path=,flags={},num_aliases=1) +.data.rel.ro.local@2c176f0(size_without_padding=56,padding=0,full_name=ChromeMainDelegate [vtable],object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=,flags={},num_aliases=1) +.data.rel.ro.local@2c17728(size_without_padding=24,padding=0,full_name=chrome::mojom::FieldTrialRecorder [vtable],object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=,flags={},num_aliases=1) +.data.rel.ro.local@2c17740(size_without_padding=789904,padding=0,full_name=chrome::mojom::FieldTrialRecorderProxy [vtable],object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=,flags={},num_aliases=1) +.data.rel.ro.local@2cd84e0(size_without_padding=16,padding=16,full_name=.Lswitch.table.45,object_path=third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libcontroller_api_impl.a_controller_api_impl.o,source_path=,flags={},num_aliases=1) +.data.rel.ro.local@2cd84f0(size_without_padding=8,padding=0,full_name=kSystemClassPrefixes,object_path=third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libport_android_jni.a_jni_utils.o,source_path=,flags={anon},num_aliases=1) +.rodata@266e600(size_without_padding=32,padding=0,full_name=** merge strings,object_path=,source_path=,flags={},num_aliases=1) +.rodata@266e630(size_without_padding=16,padding=16,full_name=** merge strings,object_path=,source_path=,flags={},num_aliases=1) +.rodata@284d600(size_without_padding=3425,padding=1961920,full_name=** merge constants,object_path=,source_path=,flags={},num_aliases=1) +.rodata@284e364(size_without_padding=0,padding=3,full_name=** symbol gap 0,object_path=,source_path=,flags={},num_aliases=1) +.rodata@284e364(size_without_padding=8,padding=0,full_name=,object_path=base/base/page_allocator.o,source_path=,flags={},num_aliases=1) +.rodata@284e370(size_without_padding=40,padding=4,full_name=Name,object_path=base/base/page_allocator.o,source_path=,flags={},num_aliases=1) +.rodata@284e398(size_without_padding=32,padding=0,full_name=chrome::mojom::FilePatcher::Name_,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=,flags={},num_aliases=1) +.rodata@28f3450(size_without_padding=48,padding=675992,full_name=kAnimationFrameTimeHistogramClassPath,object_path=third_party/WebKit.a/PaintChunker.o,source_path=,flags={anon},num_aliases=1) +.rodata@28f3480(size_without_padding=4,padding=0,full_name=blink::CSSValueKeywordsHash::findValueImpl(char const*, unsigned int)::value_word_list,object_path=third_party/WebKit.a/PaintChunker.o,source_path=,flags={anon},num_aliases=1) +.rodata@2c158e4(size_without_padding=0,padding=3286112,full_name=** symbol gap 1 (end of section),object_path=,source_path=,flags={},num_aliases=1) .text@28d900(size_without_padding=16,padding=0,full_name=_GLOBAL__sub_I_page_allocator.cc,object_path=base/base/page_allocator.o,source_path=,flags={startup},num_aliases=1) .text@28d910(size_without_padding=56,padding=0,full_name=_GLOBAL__sub_I_bbr_sender.cc,object_path=base/base/page_allocator.o,source_path=,flags={startup},num_aliases=1) .text@28d948(size_without_padding=28,padding=0,full_name=_GLOBAL__sub_I_pacing_sender.cc,object_path=base/base/page_allocator.o,source_path=,flags={startup},num_aliases=1) @@ -28,36 +58,11 @@ .text@28f1c8(size_without_padding=20,padding=8,full_name=_GLOBAL__sub_I_SkDeviceProfile.cpp,object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=,flags={startup},num_aliases=1) .text@28f1e0(size_without_padding=69120,padding=4,full_name=foo_bar,object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=,flags={unlikely},num_aliases=1) .text@2a0000(size_without_padding=16,padding=32,full_name=blink::ContiguousContainerBase::shrinkToFit(),object_path=third_party/WebKit.a/PaintChunker.o,source_path=,flags={},num_aliases=1) -.text@2a0010(size_without_padding=12,padding=0,full_name=blink::ContiguousContainerBase::shrinkToFit(),object_path=third_party/WebKit.a/PaintChunker.o,source_path=,flags={clone},num_aliases=1) +.text@2a0010(size_without_padding=12,padding=0,full_name=blink::ContiguousContainerBase::shrinkToFit(),object_path=third_party/WebKit.a/PaintChunker.o,source_path=,flags={clone,hot},num_aliases=1) .text@2a0020(size_without_padding=24,padding=4,full_name=blink::ContiguousContainerBase::ContiguousContainerBase(blink::ContiguousContainerBase&&),object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=,flags={},num_aliases=1) .text@2a1000(size_without_padding=0,padding=4040,full_name=** symbol gap 1,object_path=,source_path=,flags={},num_aliases=1) .text@2a1000(size_without_padding=94,padding=0,full_name=blink::PaintChunker::releasePaintChunks(),object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=,flags={anon,clone},num_aliases=1) .text@24ca628(size_without_padding=0,padding=35821002,full_name=** symbol gap 2 (end of section),object_path=,source_path=,flags={},num_aliases=1) -.rodata@266e600(size_without_padding=1961984,padding=0,full_name=** merge strings,object_path=,source_path=,flags={},num_aliases=1) -.rodata@284d600(size_without_padding=3425,padding=0,full_name=** merge constants,object_path=,source_path=,flags={},num_aliases=1) -.rodata@284e364(size_without_padding=0,padding=3,full_name=** symbol gap 0,object_path=,source_path=,flags={},num_aliases=1) -.rodata@284e364(size_without_padding=8,padding=0,full_name=,object_path=base/base/page_allocator.o,source_path=,flags={},num_aliases=1) -.rodata@284e370(size_without_padding=40,padding=4,full_name=Name,object_path=base/base/page_allocator.o,source_path=,flags={},num_aliases=1) -.rodata@284e398(size_without_padding=32,padding=0,full_name=chrome::mojom::FilePatcher::Name_,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=,flags={},num_aliases=1) -.rodata@284e518(size_without_padding=675633,padding=352,full_name=** merge strings,object_path=,source_path=,flags={},num_aliases=1) -.rodata@28f3450(size_without_padding=48,padding=7,full_name=kAnimationFrameTimeHistogramClassPath,object_path=third_party/WebKit.a/PaintChunker.o,source_path=,flags={anon},num_aliases=1) -.rodata@28f3480(size_without_padding=4,padding=0,full_name=blink::CSSValueKeywordsHash::findValueImpl(char const*, unsigned int)::value_word_list,object_path=third_party/WebKit.a/PaintChunker.o,source_path=,flags={anon},num_aliases=1) -.rodata@2c158e4(size_without_padding=0,padding=3286112,full_name=** symbol gap 1 (end of section),object_path=,source_path=,flags={},num_aliases=1) -.data.rel.ro.local@2c176f0(size_without_padding=56,padding=0,full_name=ChromeMainDelegate [vtable],object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=,flags={},num_aliases=1) -.data.rel.ro.local@2c17728(size_without_padding=24,padding=0,full_name=chrome::mojom::FieldTrialRecorder [vtable],object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=,flags={},num_aliases=1) -.data.rel.ro.local@2c17740(size_without_padding=789904,padding=0,full_name=chrome::mojom::FieldTrialRecorderProxy [vtable],object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=,flags={},num_aliases=1) -.data.rel.ro.local@2cd84e0(size_without_padding=16,padding=16,full_name=.Lswitch.table.45,object_path=third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libcontroller_api_impl.a_controller_api_impl.o,source_path=,flags={},num_aliases=1) -.data.rel.ro.local@2cd84f0(size_without_padding=8,padding=0,full_name=kSystemClassPrefixes,object_path=third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libport_android_jni.a_jni_utils.o,source_path=,flags={anon},num_aliases=1) -.data.rel.ro@2cd8500(size_without_padding=56,padding=0,full_name=ChromeMainDelegateAndroid [vtable],object_path=third_party/WebKit.a/PaintChunker.o,source_path=,flags={},num_aliases=1) -.data.rel.ro@2cd8538(size_without_padding=24,padding=0,full_name=mojo::MessageReceiver [vtable],object_path=base/base/page_allocator.o,source_path=,flags={},num_aliases=1) -.data.rel.ro@2cd8550(size_without_padding=12,padding=0,full_name=kMethodsAnimationFrameTimeHistogram,object_path=base/base/page_allocator.o,source_path=,flags={},num_aliases=1) -.data.rel.ro@2ddc608(size_without_padding=0,padding=1065132,full_name=** symbol gap 0 (end of section),object_path=,source_path=,flags={},num_aliases=1) -.data@2de7000(size_without_padding=4,padding=0,full_name=google::protobuf::internal::pLinuxKernelCmpxchg,object_path=base/base/page_allocator.o,source_path=,flags={},num_aliases=1) -.data@2de7004(size_without_padding=4,padding=0,full_name=google::protobuf::internal::pLinuxKernelMemoryBarrier,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=,flags={},num_aliases=1) -.data@2de7008(size_without_padding=152,padding=0,full_name=base::android::kBaseRegisteredMethods,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=,flags={rel},num_aliases=1) -.data@2de70a0(size_without_padding=4,padding=0,full_name=base::android::g_renderer_histogram_code,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=,flags={anon},num_aliases=1) -.data@2de70a4(size_without_padding=4,padding=0,full_name=base::android::g_library_version_number,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=,flags={anon,rel.loc},num_aliases=1) -.data@2dffd88(size_without_padding=0,padding=101600,full_name=** symbol gap 0 (end of section),object_path=,source_path=,flags={},num_aliases=1) .bss@0(size_without_padding=262144,padding=0,full_name=ff_cos_131072,object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o,source_path=,flags={},num_aliases=1) .bss@0(size_without_padding=131072,padding=0,full_name=ff_cos_131072_fixed,object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_fixed.o,source_path=,flags={},num_aliases=1) .bss@0(size_without_padding=131072,padding=0,full_name=ff_cos_65536,object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o,source_path=,flags={},num_aliases=1)
diff --git a/tools/binary_size/libsupersize/testdata/Archive_Elf.golden b/tools/binary_size/libsupersize/testdata/Archive_Elf.golden index 2baf1d8b..e735455 100644 --- a/tools/binary_size/libsupersize/testdata/Archive_Elf.golden +++ b/tools/binary_size/libsupersize/testdata/Archive_Elf.golden
@@ -6,26 +6,63 @@ gn_args=var1=true var2="foo" map_file_name=../test.map tool_prefix=tools/binary_size/libsupersize/testdata/mock_toolchain/ -Section .text: has 100.0% of 35900712 bytes accounted for from 18 symbols. 0 bytes are unaccounted for. +Section .text: has 100.0% of 35900712 bytes accounted for from 19 symbols. 0 bytes are unaccounted for. * Padding accounts for 48 bytes (0.0%) * 3 placeholders (symbols that start with **) account for 35830760 bytes (99.8%) -* Contains 5 aliases, mapped to 2 unique addresses (60 bytes) -* 1 symbols have shared ownership (12 bytes) -Section .rodata: has 100.0% of 5927652 bytes accounted for from 10 symbols. 0 bytes are unaccounted for. -* Padding accounts for 11 bytes (0.0%) -* 5 placeholders (symbols that start with **) account for 5927509 bytes (100.0%) +* Contains 6 aliases, mapped to 2 unique addresses (52 bytes saved) +* 0 symbols have shared ownership +Section .rodata: has 100.0% of 5927652 bytes accounted for from 12 symbols. 0 bytes are unaccounted for. +* Padding accounts for 675996 bytes (11.4%) +* 4 placeholders (symbols that start with **) account for 5251503 bytes (88.6%) +* Contains 3 string literals. Total size=21, padding=0 +* Contains 2 aliases, mapped to 1 unique addresses (5 bytes saved) * 0 symbols have shared ownership Section .data.rel.ro: has 100.0% of 1065224 bytes accounted for from 4 symbols. 0 bytes are unaccounted for. * Padding accounts for 0 bytes (0.0%) * 1 placeholders (symbols that start with **) account for 1065132 bytes (100.0%) +* Contains 0 aliases * 0 symbols have shared ownership Section .data: has 100.0% of 101768 bytes accounted for from 6 symbols. 0 bytes are unaccounted for. * Padding accounts for 0 bytes (0.0%) * 1 placeholders (symbols that start with **) account for 101600 bytes (99.8%) +* Contains 0 aliases * 0 symbols have shared ownership Section .bss: has 40.3% of 524520 bytes accounted for from 6 symbols. 775936 bytes are unaccounted for. * Padding accounts for 196 bytes (0.0%) +* Contains 0 aliases * 0 symbols have shared ownership +Section .other: has 100.0% of 33984171 bytes accounted for from 1 symbols. 0 bytes are unaccounted for. +* Padding accounts for 0 bytes (0.0%) +* Contains 0 aliases +* 0 symbols have shared ownership +.data@2de7000(size_without_padding=4,padding=0,full_name=google::protobuf::internal::pLinuxKernelCmpxchg,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=1) +.data@2de7004(size_without_padding=4,padding=0,full_name=google::protobuf::internal::pLinuxKernelMemoryBarrier,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={},num_aliases=1) +.data@2de7008(size_without_padding=152,padding=0,full_name=base::android::kBaseRegisteredMethods,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={rel},num_aliases=1) +.data@2de70a0(size_without_padding=4,padding=0,full_name=base::android::g_renderer_histogram_code,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={anon},num_aliases=1) +.data@2de70a4(size_without_padding=4,padding=0,full_name=base::android::g_library_version_number,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={anon,rel.loc},num_aliases=1) +.data@2dffd88(size_without_padding=0,padding=101600,full_name=** symbol gap 0 (end of section),object_path=,source_path=,flags={},num_aliases=1) +.data.rel.ro@2cd8500(size_without_padding=56,padding=0,full_name=ChromeMainDelegateAndroid [vtable],object_path=third_party/WebKit.a/PaintChunker.o,source_path=third_party/paint.cc,flags={},num_aliases=1) +.data.rel.ro@2cd8538(size_without_padding=24,padding=0,full_name=mojo::MessageReceiver [vtable],object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=1) +.data.rel.ro@2cd8550(size_without_padding=12,padding=0,full_name=kMethodsAnimationFrameTimeHistogram,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=1) +.data.rel.ro@2ddc608(size_without_padding=0,padding=1065132,full_name=** symbol gap 0 (end of section),object_path=,source_path=,flags={},num_aliases=1) +.data.rel.ro.local@2c176f0(size_without_padding=56,padding=0,full_name=ChromeMainDelegate [vtable],object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={gen},num_aliases=1) +.data.rel.ro.local@2c17728(size_without_padding=24,padding=0,full_name=chrome::mojom::FieldTrialRecorder [vtable],object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={gen},num_aliases=1) +.data.rel.ro.local@2c17740(size_without_padding=789904,padding=0,full_name=chrome::mojom::FieldTrialRecorderProxy [vtable],object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={},num_aliases=1) +.data.rel.ro.local@2cd84e0(size_without_padding=16,padding=16,full_name=.Lswitch.table.45,object_path=third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libcontroller_api_impl.a_controller_api_impl.o,source_path=,flags={},num_aliases=1) +.data.rel.ro.local@2cd84f0(size_without_padding=8,padding=0,full_name=kSystemClassPrefixes,object_path=third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libport_android_jni.a_jni_utils.o,source_path=,flags={anon},num_aliases=1) +.other@0(size_without_padding=33984171,padding=0,full_name=ELF file overhead,object_path=,source_path=,flags={},num_aliases=1) +.rodata@266e600(size_without_padding=5,padding=0,full_name=string literal,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=2) +.rodata@266e600(size_without_padding=5,padding=0,full_name=string literal,object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={gen},num_aliases=2) +.rodata@266e605(size_without_padding=16,padding=0,full_name=string literal,object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={gen},num_aliases=1) +.rodata@266e630(size_without_padding=16,padding=27,full_name=** merge strings,object_path=,source_path=,flags={},num_aliases=1) +.rodata@284d600(size_without_padding=3425,padding=1961920,full_name=** merge constants,object_path=,source_path=,flags={},num_aliases=1) +.rodata@284e364(size_without_padding=0,padding=3,full_name=** symbol gap 0,object_path=,source_path=,flags={},num_aliases=1) +.rodata@284e364(size_without_padding=8,padding=0,full_name=,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=1) +.rodata@284e370(size_without_padding=40,padding=4,full_name=Name,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=1) +.rodata@284e398(size_without_padding=32,padding=0,full_name=chrome::mojom::FilePatcher::Name_,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={},num_aliases=1) +.rodata@28f3450(size_without_padding=48,padding=675992,full_name=kAnimationFrameTimeHistogramClassPath,object_path=third_party/WebKit.a/PaintChunker.o,source_path=third_party/paint.cc,flags={anon},num_aliases=1) +.rodata@28f3480(size_without_padding=4,padding=0,full_name=blink::CSSValueKeywordsHash::findValueImpl(char const*, unsigned int)::value_word_list,object_path=third_party/WebKit.a/PaintChunker.o,source_path=third_party/paint.cc,flags={anon},num_aliases=1) +.rodata@2c158e4(size_without_padding=0,padding=3286112,full_name=** symbol gap 1 (end of section),object_path=,source_path=,flags={},num_aliases=1) .text@28d900(size_without_padding=16,padding=0,full_name=_GLOBAL__sub_I_page_allocator.cc,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={startup},num_aliases=1) .text@28d910(size_without_padding=56,padding=0,full_name=_GLOBAL__sub_I_bbr_sender.cc,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={startup},num_aliases=1) .text@28d948(size_without_padding=28,padding=0,full_name=_GLOBAL__sub_I_pacing_sender.cc,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={startup},num_aliases=1) @@ -37,38 +74,14 @@ .text@28f1e0(size_without_padding=69120,padding=4,full_name=foo_bar,object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={unlikely,gen},num_aliases=1) .text@2a0000(size_without_padding=16,padding=32,full_name=blink::ContiguousContainerBase::shrinkToFit(),object_path=,source_path=,flags={},num_aliases=2) .text@2a0000(size_without_padding=16,padding=32,full_name=BazAlias(bool),object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={gen},num_aliases=2) -.text@2a0010(size_without_padding=12,padding=0,full_name=blink::ContiguousContainerBase::shrinkToFit(),object_path=third_party/{shared}/2,source_path=third_party/{shared}/2,flags={clone},num_aliases=3) -.text@2a0010(size_without_padding=12,padding=0,full_name=FooAlias(),object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o,source_path=third_party/fft_float.cc,flags={},num_aliases=3) -.text@2a0010(size_without_padding=12,padding=0,full_name=BarAlias(),object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o,source_path=third_party/fft_float.cc,flags={},num_aliases=3) +.text@2a0010(size_without_padding=12,padding=0,full_name=blink::ContiguousContainerBase::shrinkToFit(),object_path=third_party/WebKit.a/PaintChunker.o,source_path=third_party/paint.cc,flags={clone},num_aliases=4) +.text@2a0010(size_without_padding=12,padding=0,full_name=blink::ContiguousContainerBase::shrinkToFit(),object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={gen,clone},num_aliases=4) +.text@2a0010(size_without_padding=12,padding=0,full_name=FooAlias(),object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o,source_path=third_party/fft_float.cc,flags={},num_aliases=4) +.text@2a0010(size_without_padding=12,padding=0,full_name=BarAlias(),object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o,source_path=third_party/fft_float.cc,flags={},num_aliases=4) .text@2a0020(size_without_padding=24,padding=4,full_name=blink::ContiguousContainerBase::ContiguousContainerBase(blink::ContiguousContainerBase&&),object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={},num_aliases=1) .text@2a1000(size_without_padding=0,padding=4040,full_name=** symbol gap 1,object_path=,source_path=,flags={},num_aliases=1) .text@2a1000(size_without_padding=94,padding=0,full_name=blink::PaintChunker::releasePaintChunks(),object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={anon,clone},num_aliases=1) .text@24ca628(size_without_padding=0,padding=35821002,full_name=** symbol gap 2 (end of section),object_path=,source_path=,flags={},num_aliases=1) -.rodata@266e600(size_without_padding=1961984,padding=0,full_name=** merge strings,object_path=,source_path=,flags={},num_aliases=1) -.rodata@284d600(size_without_padding=3425,padding=0,full_name=** merge constants,object_path=,source_path=,flags={},num_aliases=1) -.rodata@284e364(size_without_padding=0,padding=3,full_name=** symbol gap 0,object_path=,source_path=,flags={},num_aliases=1) -.rodata@284e364(size_without_padding=8,padding=0,full_name=,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=1) -.rodata@284e370(size_without_padding=40,padding=4,full_name=Name,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=1) -.rodata@284e398(size_without_padding=32,padding=0,full_name=chrome::mojom::FilePatcher::Name_,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={},num_aliases=1) -.rodata@284e518(size_without_padding=675633,padding=352,full_name=** merge strings,object_path=,source_path=,flags={},num_aliases=1) -.rodata@28f3450(size_without_padding=48,padding=7,full_name=kAnimationFrameTimeHistogramClassPath,object_path=third_party/WebKit.a/PaintChunker.o,source_path=third_party/paint.cc,flags={anon},num_aliases=1) -.rodata@28f3480(size_without_padding=4,padding=0,full_name=blink::CSSValueKeywordsHash::findValueImpl(char const*, unsigned int)::value_word_list,object_path=third_party/WebKit.a/PaintChunker.o,source_path=third_party/paint.cc,flags={anon},num_aliases=1) -.rodata@2c158e4(size_without_padding=0,padding=3286112,full_name=** symbol gap 1 (end of section),object_path=,source_path=,flags={},num_aliases=1) -.data.rel.ro.local@2c176f0(size_without_padding=56,padding=0,full_name=ChromeMainDelegate [vtable],object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={gen},num_aliases=1) -.data.rel.ro.local@2c17728(size_without_padding=24,padding=0,full_name=chrome::mojom::FieldTrialRecorder [vtable],object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={gen},num_aliases=1) -.data.rel.ro.local@2c17740(size_without_padding=789904,padding=0,full_name=chrome::mojom::FieldTrialRecorderProxy [vtable],object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={},num_aliases=1) -.data.rel.ro.local@2cd84e0(size_without_padding=16,padding=16,full_name=.Lswitch.table.45,object_path=third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libcontroller_api_impl.a_controller_api_impl.o,source_path=,flags={},num_aliases=1) -.data.rel.ro.local@2cd84f0(size_without_padding=8,padding=0,full_name=kSystemClassPrefixes,object_path=third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libport_android_jni.a_jni_utils.o,source_path=,flags={anon},num_aliases=1) -.data.rel.ro@2cd8500(size_without_padding=56,padding=0,full_name=ChromeMainDelegateAndroid [vtable],object_path=third_party/WebKit.a/PaintChunker.o,source_path=third_party/paint.cc,flags={},num_aliases=1) -.data.rel.ro@2cd8538(size_without_padding=24,padding=0,full_name=mojo::MessageReceiver [vtable],object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=1) -.data.rel.ro@2cd8550(size_without_padding=12,padding=0,full_name=kMethodsAnimationFrameTimeHistogram,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=1) -.data.rel.ro@2ddc608(size_without_padding=0,padding=1065132,full_name=** symbol gap 0 (end of section),object_path=,source_path=,flags={},num_aliases=1) -.data@2de7000(size_without_padding=4,padding=0,full_name=google::protobuf::internal::pLinuxKernelCmpxchg,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=1) -.data@2de7004(size_without_padding=4,padding=0,full_name=google::protobuf::internal::pLinuxKernelMemoryBarrier,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={},num_aliases=1) -.data@2de7008(size_without_padding=152,padding=0,full_name=base::android::kBaseRegisteredMethods,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={rel},num_aliases=1) -.data@2de70a0(size_without_padding=4,padding=0,full_name=base::android::g_renderer_histogram_code,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={anon},num_aliases=1) -.data@2de70a4(size_without_padding=4,padding=0,full_name=base::android::g_library_version_number,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={anon,rel.loc},num_aliases=1) -.data@2dffd88(size_without_padding=0,padding=101600,full_name=** symbol gap 0 (end of section),object_path=,source_path=,flags={},num_aliases=1) .bss@0(size_without_padding=262144,padding=0,full_name=ff_cos_131072,object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o,source_path=third_party/fft_float.cc,flags={},num_aliases=1) .bss@0(size_without_padding=131072,padding=0,full_name=ff_cos_131072_fixed,object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_fixed.o,source_path=third_party/fft_fixed.cc,flags={},num_aliases=1) .bss@0(size_without_padding=131072,padding=0,full_name=ff_cos_65536,object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o,source_path=third_party/fft_float.cc,flags={},num_aliases=1)
diff --git a/tools/binary_size/libsupersize/testdata/Archive_OutputDirectory.golden b/tools/binary_size/libsupersize/testdata/Archive_OutputDirectory.golden index 82b614c..a8cf239b 100644 --- a/tools/binary_size/libsupersize/testdata/Archive_OutputDirectory.golden +++ b/tools/binary_size/libsupersize/testdata/Archive_OutputDirectory.golden
@@ -4,20 +4,50 @@ * Contains 0 aliases * 0 symbols have shared ownership Section .rodata: has 100.0% of 5927652 bytes accounted for from 10 symbols. 0 bytes are unaccounted for. -* Padding accounts for 11 bytes (0.0%) -* 5 placeholders (symbols that start with **) account for 5927509 bytes (100.0%) +* Padding accounts for 675996 bytes (11.4%) +* 5 placeholders (symbols that start with **) account for 5251524 bytes (88.6%) +* Contains 0 string literals. Total size=0, padding=0 +* Contains 0 aliases * 0 symbols have shared ownership Section .data.rel.ro: has 100.0% of 1065224 bytes accounted for from 4 symbols. 0 bytes are unaccounted for. * Padding accounts for 0 bytes (0.0%) * 1 placeholders (symbols that start with **) account for 1065132 bytes (100.0%) +* Contains 0 aliases * 0 symbols have shared ownership Section .data: has 100.0% of 101768 bytes accounted for from 6 symbols. 0 bytes are unaccounted for. * Padding accounts for 0 bytes (0.0%) * 1 placeholders (symbols that start with **) account for 101600 bytes (99.8%) +* Contains 0 aliases * 0 symbols have shared ownership Section .bss: has 40.3% of 524520 bytes accounted for from 6 symbols. 775936 bytes are unaccounted for. * Padding accounts for 196 bytes (0.0%) +* Contains 0 aliases * 0 symbols have shared ownership +.data@2de7000(size_without_padding=4,padding=0,full_name=google::protobuf::internal::pLinuxKernelCmpxchg,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=1) +.data@2de7004(size_without_padding=4,padding=0,full_name=google::protobuf::internal::pLinuxKernelMemoryBarrier,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={},num_aliases=1) +.data@2de7008(size_without_padding=152,padding=0,full_name=base::android::kBaseRegisteredMethods,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={rel},num_aliases=1) +.data@2de70a0(size_without_padding=4,padding=0,full_name=base::android::g_renderer_histogram_code,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={anon},num_aliases=1) +.data@2de70a4(size_without_padding=4,padding=0,full_name=base::android::g_library_version_number,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={anon,rel.loc},num_aliases=1) +.data@2dffd88(size_without_padding=0,padding=101600,full_name=** symbol gap 0 (end of section),object_path=,source_path=,flags={},num_aliases=1) +.data.rel.ro@2cd8500(size_without_padding=56,padding=0,full_name=ChromeMainDelegateAndroid [vtable],object_path=third_party/WebKit.a/PaintChunker.o,source_path=third_party/paint.cc,flags={},num_aliases=1) +.data.rel.ro@2cd8538(size_without_padding=24,padding=0,full_name=mojo::MessageReceiver [vtable],object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=1) +.data.rel.ro@2cd8550(size_without_padding=12,padding=0,full_name=kMethodsAnimationFrameTimeHistogram,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=1) +.data.rel.ro@2ddc608(size_without_padding=0,padding=1065132,full_name=** symbol gap 0 (end of section),object_path=,source_path=,flags={},num_aliases=1) +.data.rel.ro.local@2c176f0(size_without_padding=56,padding=0,full_name=ChromeMainDelegate [vtable],object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={gen},num_aliases=1) +.data.rel.ro.local@2c17728(size_without_padding=24,padding=0,full_name=chrome::mojom::FieldTrialRecorder [vtable],object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={gen},num_aliases=1) +.data.rel.ro.local@2c17740(size_without_padding=789904,padding=0,full_name=chrome::mojom::FieldTrialRecorderProxy [vtable],object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={},num_aliases=1) +.data.rel.ro.local@2cd84e0(size_without_padding=16,padding=16,full_name=.Lswitch.table.45,object_path=third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libcontroller_api_impl.a_controller_api_impl.o,source_path=,flags={},num_aliases=1) +.data.rel.ro.local@2cd84f0(size_without_padding=8,padding=0,full_name=kSystemClassPrefixes,object_path=third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libport_android_jni.a_jni_utils.o,source_path=,flags={anon},num_aliases=1) +.rodata@266e600(size_without_padding=32,padding=0,full_name=** merge strings,object_path=,source_path=,flags={},num_aliases=1) +.rodata@266e630(size_without_padding=16,padding=16,full_name=** merge strings,object_path=,source_path=,flags={},num_aliases=1) +.rodata@284d600(size_without_padding=3425,padding=1961920,full_name=** merge constants,object_path=,source_path=,flags={},num_aliases=1) +.rodata@284e364(size_without_padding=0,padding=3,full_name=** symbol gap 0,object_path=,source_path=,flags={},num_aliases=1) +.rodata@284e364(size_without_padding=8,padding=0,full_name=,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=1) +.rodata@284e370(size_without_padding=40,padding=4,full_name=Name,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=1) +.rodata@284e398(size_without_padding=32,padding=0,full_name=chrome::mojom::FilePatcher::Name_,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={},num_aliases=1) +.rodata@28f3450(size_without_padding=48,padding=675992,full_name=kAnimationFrameTimeHistogramClassPath,object_path=third_party/WebKit.a/PaintChunker.o,source_path=third_party/paint.cc,flags={anon},num_aliases=1) +.rodata@28f3480(size_without_padding=4,padding=0,full_name=blink::CSSValueKeywordsHash::findValueImpl(char const*, unsigned int)::value_word_list,object_path=third_party/WebKit.a/PaintChunker.o,source_path=third_party/paint.cc,flags={anon},num_aliases=1) +.rodata@2c158e4(size_without_padding=0,padding=3286112,full_name=** symbol gap 1 (end of section),object_path=,source_path=,flags={},num_aliases=1) .text@28d900(size_without_padding=16,padding=0,full_name=_GLOBAL__sub_I_page_allocator.cc,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={startup},num_aliases=1) .text@28d910(size_without_padding=56,padding=0,full_name=_GLOBAL__sub_I_bbr_sender.cc,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={startup},num_aliases=1) .text@28d948(size_without_padding=28,padding=0,full_name=_GLOBAL__sub_I_pacing_sender.cc,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={startup},num_aliases=1) @@ -28,36 +58,11 @@ .text@28f1c8(size_without_padding=20,padding=8,full_name=_GLOBAL__sub_I_SkDeviceProfile.cpp,object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={startup,gen},num_aliases=1) .text@28f1e0(size_without_padding=69120,padding=4,full_name=foo_bar,object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={unlikely,gen},num_aliases=1) .text@2a0000(size_without_padding=16,padding=32,full_name=blink::ContiguousContainerBase::shrinkToFit(),object_path=third_party/WebKit.a/PaintChunker.o,source_path=third_party/paint.cc,flags={},num_aliases=1) -.text@2a0010(size_without_padding=12,padding=0,full_name=blink::ContiguousContainerBase::shrinkToFit(),object_path=third_party/WebKit.a/PaintChunker.o,source_path=third_party/paint.cc,flags={clone},num_aliases=1) +.text@2a0010(size_without_padding=12,padding=0,full_name=blink::ContiguousContainerBase::shrinkToFit(),object_path=third_party/WebKit.a/PaintChunker.o,source_path=third_party/paint.cc,flags={clone,hot},num_aliases=1) .text@2a0020(size_without_padding=24,padding=4,full_name=blink::ContiguousContainerBase::ContiguousContainerBase(blink::ContiguousContainerBase&&),object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={},num_aliases=1) .text@2a1000(size_without_padding=0,padding=4040,full_name=** symbol gap 1,object_path=,source_path=,flags={},num_aliases=1) .text@2a1000(size_without_padding=94,padding=0,full_name=blink::PaintChunker::releasePaintChunks(),object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={anon,clone},num_aliases=1) .text@24ca628(size_without_padding=0,padding=35821002,full_name=** symbol gap 2 (end of section),object_path=,source_path=,flags={},num_aliases=1) -.rodata@266e600(size_without_padding=1961984,padding=0,full_name=** merge strings,object_path=,source_path=,flags={},num_aliases=1) -.rodata@284d600(size_without_padding=3425,padding=0,full_name=** merge constants,object_path=,source_path=,flags={},num_aliases=1) -.rodata@284e364(size_without_padding=0,padding=3,full_name=** symbol gap 0,object_path=,source_path=,flags={},num_aliases=1) -.rodata@284e364(size_without_padding=8,padding=0,full_name=,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=1) -.rodata@284e370(size_without_padding=40,padding=4,full_name=Name,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=1) -.rodata@284e398(size_without_padding=32,padding=0,full_name=chrome::mojom::FilePatcher::Name_,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={},num_aliases=1) -.rodata@284e518(size_without_padding=675633,padding=352,full_name=** merge strings,object_path=,source_path=,flags={},num_aliases=1) -.rodata@28f3450(size_without_padding=48,padding=7,full_name=kAnimationFrameTimeHistogramClassPath,object_path=third_party/WebKit.a/PaintChunker.o,source_path=third_party/paint.cc,flags={anon},num_aliases=1) -.rodata@28f3480(size_without_padding=4,padding=0,full_name=blink::CSSValueKeywordsHash::findValueImpl(char const*, unsigned int)::value_word_list,object_path=third_party/WebKit.a/PaintChunker.o,source_path=third_party/paint.cc,flags={anon},num_aliases=1) -.rodata@2c158e4(size_without_padding=0,padding=3286112,full_name=** symbol gap 1 (end of section),object_path=,source_path=,flags={},num_aliases=1) -.data.rel.ro.local@2c176f0(size_without_padding=56,padding=0,full_name=ChromeMainDelegate [vtable],object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={gen},num_aliases=1) -.data.rel.ro.local@2c17728(size_without_padding=24,padding=0,full_name=chrome::mojom::FieldTrialRecorder [vtable],object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={gen},num_aliases=1) -.data.rel.ro.local@2c17740(size_without_padding=789904,padding=0,full_name=chrome::mojom::FieldTrialRecorderProxy [vtable],object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={},num_aliases=1) -.data.rel.ro.local@2cd84e0(size_without_padding=16,padding=16,full_name=.Lswitch.table.45,object_path=third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libcontroller_api_impl.a_controller_api_impl.o,source_path=,flags={},num_aliases=1) -.data.rel.ro.local@2cd84f0(size_without_padding=8,padding=0,full_name=kSystemClassPrefixes,object_path=third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libport_android_jni.a_jni_utils.o,source_path=,flags={anon},num_aliases=1) -.data.rel.ro@2cd8500(size_without_padding=56,padding=0,full_name=ChromeMainDelegateAndroid [vtable],object_path=third_party/WebKit.a/PaintChunker.o,source_path=third_party/paint.cc,flags={},num_aliases=1) -.data.rel.ro@2cd8538(size_without_padding=24,padding=0,full_name=mojo::MessageReceiver [vtable],object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=1) -.data.rel.ro@2cd8550(size_without_padding=12,padding=0,full_name=kMethodsAnimationFrameTimeHistogram,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=1) -.data.rel.ro@2ddc608(size_without_padding=0,padding=1065132,full_name=** symbol gap 0 (end of section),object_path=,source_path=,flags={},num_aliases=1) -.data@2de7000(size_without_padding=4,padding=0,full_name=google::protobuf::internal::pLinuxKernelCmpxchg,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=1) -.data@2de7004(size_without_padding=4,padding=0,full_name=google::protobuf::internal::pLinuxKernelMemoryBarrier,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={},num_aliases=1) -.data@2de7008(size_without_padding=152,padding=0,full_name=base::android::kBaseRegisteredMethods,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={rel},num_aliases=1) -.data@2de70a0(size_without_padding=4,padding=0,full_name=base::android::g_renderer_histogram_code,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={anon},num_aliases=1) -.data@2de70a4(size_without_padding=4,padding=0,full_name=base::android::g_library_version_number,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={anon,rel.loc},num_aliases=1) -.data@2dffd88(size_without_padding=0,padding=101600,full_name=** symbol gap 0 (end of section),object_path=,source_path=,flags={},num_aliases=1) .bss@0(size_without_padding=262144,padding=0,full_name=ff_cos_131072,object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o,source_path=third_party/fft_float.cc,flags={},num_aliases=1) .bss@0(size_without_padding=131072,padding=0,full_name=ff_cos_131072_fixed,object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_fixed.o,source_path=third_party/fft_fixed.cc,flags={},num_aliases=1) .bss@0(size_without_padding=131072,padding=0,full_name=ff_cos_65536,object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o,source_path=third_party/fft_float.cc,flags={},num_aliases=1)
diff --git a/tools/binary_size/libsupersize/testdata/Archive_Pak.golden b/tools/binary_size/libsupersize/testdata/Archive_Pak.golden new file mode 100644 index 0000000..daa279c --- /dev/null +++ b/tools/binary_size/libsupersize/testdata/Archive_Pak.golden
@@ -0,0 +1,301 @@ +elf_arch=arm +elf_build_id=WhatAnAmazingBuildId +elf_file_name=elf +elf_mtime={redacted} +git_revision=abc123 +gn_args=var1=true var2="foo" +map_file_name=../test.map +tool_prefix=tools/binary_size/libsupersize/testdata/mock_toolchain/ +Section .text: has 100.0% of 35900712 bytes accounted for from 19 symbols. 0 bytes are unaccounted for. +* Padding accounts for 48 bytes (0.0%) +* 3 placeholders (symbols that start with **) account for 35830760 bytes (99.8%) +* Contains 6 aliases, mapped to 2 unique addresses (52 bytes saved) +* 0 symbols have shared ownership +Section .rodata: has 100.0% of 5927652 bytes accounted for from 12 symbols. 0 bytes are unaccounted for. +* Padding accounts for 675996 bytes (11.4%) +* 4 placeholders (symbols that start with **) account for 5251503 bytes (88.6%) +* Contains 3 string literals. Total size=21, padding=0 +* Contains 2 aliases, mapped to 1 unique addresses (5 bytes saved) +* 0 symbols have shared ownership +Section .data.rel.ro: has 100.0% of 1065224 bytes accounted for from 4 symbols. 0 bytes are unaccounted for. +* Padding accounts for 0 bytes (0.0%) +* 1 placeholders (symbols that start with **) account for 1065132 bytes (100.0%) +* Contains 0 aliases +* 0 symbols have shared ownership +Section .data: has 100.0% of 101768 bytes accounted for from 6 symbols. 0 bytes are unaccounted for. +* Padding accounts for 0 bytes (0.0%) +* 1 placeholders (symbols that start with **) account for 101600 bytes (99.8%) +* Contains 0 aliases +* 0 symbols have shared ownership +Section .bss: has 40.3% of 524520 bytes accounted for from 6 symbols. 775936 bytes are unaccounted for. +* Padding accounts for 196 bytes (0.0%) +* Contains 0 aliases +* 0 symbols have shared ownership +Section .pak.translations: has 100.0% of 6821 bytes accounted for from 207 symbols. 0 bytes are unaccounted for. +* Padding accounts for 0 bytes (0.0%) +* Contains 0 aliases +* 0 symbols have shared ownership +Section .other: has 100.0% of 33984171 bytes accounted for from 1 symbols. 0 bytes are unaccounted for. +* Padding accounts for 0 bytes (0.0%) +* Contains 0 aliases +* 0 symbols have shared ownership +.data@2de7000(size_without_padding=4,padding=0,full_name=google::protobuf::internal::pLinuxKernelCmpxchg,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=1) +.data@2de7004(size_without_padding=4,padding=0,full_name=google::protobuf::internal::pLinuxKernelMemoryBarrier,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={},num_aliases=1) +.data@2de7008(size_without_padding=152,padding=0,full_name=base::android::kBaseRegisteredMethods,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={rel},num_aliases=1) +.data@2de70a0(size_without_padding=4,padding=0,full_name=base::android::g_renderer_histogram_code,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={anon},num_aliases=1) +.data@2de70a4(size_without_padding=4,padding=0,full_name=base::android::g_library_version_number,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={anon,rel.loc},num_aliases=1) +.data@2dffd88(size_without_padding=0,padding=101600,full_name=** symbol gap 0 (end of section),object_path=,source_path=,flags={},num_aliases=1) +.data.rel.ro@2cd8500(size_without_padding=56,padding=0,full_name=ChromeMainDelegateAndroid [vtable],object_path=third_party/WebKit.a/PaintChunker.o,source_path=third_party/paint.cc,flags={},num_aliases=1) +.data.rel.ro@2cd8538(size_without_padding=24,padding=0,full_name=mojo::MessageReceiver [vtable],object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=1) +.data.rel.ro@2cd8550(size_without_padding=12,padding=0,full_name=kMethodsAnimationFrameTimeHistogram,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=1) +.data.rel.ro@2ddc608(size_without_padding=0,padding=1065132,full_name=** symbol gap 0 (end of section),object_path=,source_path=,flags={},num_aliases=1) +.data.rel.ro.local@2c176f0(size_without_padding=56,padding=0,full_name=ChromeMainDelegate [vtable],object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={gen},num_aliases=1) +.data.rel.ro.local@2c17728(size_without_padding=24,padding=0,full_name=chrome::mojom::FieldTrialRecorder [vtable],object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={gen},num_aliases=1) +.data.rel.ro.local@2c17740(size_without_padding=789904,padding=0,full_name=chrome::mojom::FieldTrialRecorderProxy [vtable],object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={},num_aliases=1) +.data.rel.ro.local@2cd84e0(size_without_padding=16,padding=16,full_name=.Lswitch.table.45,object_path=third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libcontroller_api_impl.a_controller_api_impl.o,source_path=,flags={},num_aliases=1) +.data.rel.ro.local@2cd84f0(size_without_padding=8,padding=0,full_name=kSystemClassPrefixes,object_path=third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libport_android_jni.a_jni_utils.o,source_path=,flags={anon},num_aliases=1) +.other@0(size_without_padding=33984171,padding=0,full_name=ELF file overhead,object_path=,source_path=,flags={},num_aliases=1) +.rodata@266e600(size_without_padding=5,padding=0,full_name=string literal,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=2) +.rodata@266e600(size_without_padding=5,padding=0,full_name=string literal,object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={gen},num_aliases=2) +.rodata@266e605(size_without_padding=16,padding=0,full_name=string literal,object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={gen},num_aliases=1) +.rodata@266e630(size_without_padding=16,padding=27,full_name=** merge strings,object_path=,source_path=,flags={},num_aliases=1) +.rodata@284d600(size_without_padding=3425,padding=1961920,full_name=** merge constants,object_path=,source_path=,flags={},num_aliases=1) +.rodata@284e364(size_without_padding=0,padding=3,full_name=** symbol gap 0,object_path=,source_path=,flags={},num_aliases=1) +.rodata@284e364(size_without_padding=8,padding=0,full_name=,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=1) +.rodata@284e370(size_without_padding=40,padding=4,full_name=Name,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=1) +.rodata@284e398(size_without_padding=32,padding=0,full_name=chrome::mojom::FilePatcher::Name_,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={},num_aliases=1) +.rodata@28f3450(size_without_padding=48,padding=675992,full_name=kAnimationFrameTimeHistogramClassPath,object_path=third_party/WebKit.a/PaintChunker.o,source_path=third_party/paint.cc,flags={anon},num_aliases=1) +.rodata@28f3480(size_without_padding=4,padding=0,full_name=blink::CSSValueKeywordsHash::findValueImpl(char const*, unsigned int)::value_word_list,object_path=third_party/WebKit.a/PaintChunker.o,source_path=third_party/paint.cc,flags={anon},num_aliases=1) +.rodata@2c158e4(size_without_padding=0,padding=3286112,full_name=** symbol gap 1 (end of section),object_path=,source_path=,flags={},num_aliases=1) +.text@28d900(size_without_padding=16,padding=0,full_name=_GLOBAL__sub_I_page_allocator.cc,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={startup},num_aliases=1) +.text@28d910(size_without_padding=56,padding=0,full_name=_GLOBAL__sub_I_bbr_sender.cc,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={startup},num_aliases=1) +.text@28d948(size_without_padding=28,padding=0,full_name=_GLOBAL__sub_I_pacing_sender.cc,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={startup},num_aliases=1) +.text@28d964(size_without_padding=38,padding=0,full_name=extFromUUseMapping(signed char, unsigned int, int),object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=1) +.text@28d98a(size_without_padding=32,padding=0,full_name=extFromUUseMapping(aj, int),object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=1) +.text@28f000(size_without_padding=0,padding=5718,full_name=** symbol gap 0,object_path=,source_path=,flags={},num_aliases=1) +.text@28f000(size_without_padding=448,padding=0,full_name=ucnv_extMatchFromU(int const*, int, unsigned short const*, int, unsigned short const*, int, unsigned int*, signed char, signed char),object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={gen},num_aliases=1) +.text@28f1c8(size_without_padding=20,padding=8,full_name=_GLOBAL__sub_I_SkDeviceProfile.cpp,object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={startup,gen},num_aliases=1) +.text@28f1e0(size_without_padding=69120,padding=4,full_name=foo_bar,object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={unlikely,gen},num_aliases=1) +.text@2a0000(size_without_padding=16,padding=32,full_name=blink::ContiguousContainerBase::shrinkToFit(),object_path=,source_path=,flags={},num_aliases=2) +.text@2a0000(size_without_padding=16,padding=32,full_name=BazAlias(bool),object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={gen},num_aliases=2) +.text@2a0010(size_without_padding=12,padding=0,full_name=blink::ContiguousContainerBase::shrinkToFit(),object_path=third_party/WebKit.a/PaintChunker.o,source_path=third_party/paint.cc,flags={clone},num_aliases=4) +.text@2a0010(size_without_padding=12,padding=0,full_name=blink::ContiguousContainerBase::shrinkToFit(),object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={gen,clone},num_aliases=4) +.text@2a0010(size_without_padding=12,padding=0,full_name=FooAlias(),object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o,source_path=third_party/fft_float.cc,flags={},num_aliases=4) +.text@2a0010(size_without_padding=12,padding=0,full_name=BarAlias(),object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o,source_path=third_party/fft_float.cc,flags={},num_aliases=4) +.text@2a0020(size_without_padding=24,padding=4,full_name=blink::ContiguousContainerBase::ContiguousContainerBase(blink::ContiguousContainerBase&&),object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={},num_aliases=1) +.text@2a1000(size_without_padding=0,padding=4040,full_name=** symbol gap 1,object_path=,source_path=,flags={},num_aliases=1) +.text@2a1000(size_without_padding=94,padding=0,full_name=blink::PaintChunker::releasePaintChunks(),object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={anon,clone},num_aliases=1) +.text@24ca628(size_without_padding=0,padding=35821002,full_name=** symbol gap 2 (end of section),object_path=,source_path=,flags={},num_aliases=1) +.bss@0(size_without_padding=262144,padding=0,full_name=ff_cos_131072,object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o,source_path=third_party/fft_float.cc,flags={},num_aliases=1) +.bss@0(size_without_padding=131072,padding=0,full_name=ff_cos_131072_fixed,object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_fixed.o,source_path=third_party/fft_fixed.cc,flags={},num_aliases=1) +.bss@0(size_without_padding=131072,padding=0,full_name=ff_cos_65536,object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o,source_path=third_party/fft_float.cc,flags={},num_aliases=1) +.bss@2dffda0(size_without_padding=28,padding=0,full_name=g_chrome_content_browser_client,object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={gen},num_aliases=1) +.bss@2dffe80(size_without_padding=4,padding=196,full_name=SaveHistogram(_JNIEnv*, base::android::JavaParamRef<_jobject*> const&, base::android::JavaParamRef<_jstring*> const&, base::android::JavaParamRef<_jlongArray*> const&, int)::atomic_histogram_pointer,object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={gen},num_aliases=1) +.bss@2dffe84(size_without_padding=4,padding=0,full_name=g_AnimationFrameTimeHistogram_clazz,object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={anon,gen},num_aliases=1) +.pak.translations@0(size_without_padding=18,padding=0,full_name=en-US.pak: overhead,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@0(size_without_padding=0,padding=0,full_name=Pak compression leftover artifacts,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@3ac6(size_without_padding=40,padding=0,full_name=../../components/app_modal_strings.grdp: IDS_BEFOREUNLOAD_MESSAGEBOX_MESSAGE,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@3d7c(size_without_padding=24,padding=0,full_name=../../components/policy_strings.grdp: IDS_POLICY_TYPE_ERROR,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@3d82(size_without_padding=25,padding=0,full_name=../../components/policy_strings.grdp: IDS_POLICY_LIST_ENTRY_ERROR,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@3d83(size_without_padding=41,padding=0,full_name=../../components/policy_strings.grdp: IDS_POLICY_SCHEMA_VALIDATION_ERROR,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@3dd2(size_without_padding=51,padding=0,full_name=../../components/safe_browsing_strings.grdp: IDS_SB_UNDER_CONSTRUCTION,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@3df8(size_without_padding=20,padding=0,full_name=../../components/security_interstitials_strings.grdp: IDS_SAFEBROWSING_V3_TITLE,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@3df9(size_without_padding=17,padding=0,full_name=../../components/security_interstitials_strings.grdp: IDS_SAFEBROWSING_V3_OPEN_DETAILS_BUTTON,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@3dfa(size_without_padding=18,padding=0,full_name=../../components/security_interstitials_strings.grdp: IDS_SAFEBROWSING_V3_CLOSE_DETAILS_BUTTON,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@3dfb(size_without_padding=20,padding=0,full_name=../../components/security_interstitials_strings.grdp: IDS_SAFEBROWSING_OVERRIDABLE_SAFETY_BUTTON,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@3dfc(size_without_padding=44,padding=0,full_name=../../components/security_interstitials_strings.grdp: IDS_MALWARE_V3_HEADING,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@3dfd(size_without_padding=226,padding=0,full_name=../../components/security_interstitials_strings.grdp: IDS_MALWARE_V3_PRIMARY_PARAGRAPH,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@3dfe(size_without_padding=165,padding=0,full_name=../../components/security_interstitials_strings.grdp: IDS_MALWARE_V3_EXPLANATION_PARAGRAPH,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@3dff(size_without_padding=231,padding=0,full_name=../../components/security_interstitials_strings.grdp: IDS_MALWARE_V3_EXPLANATION_PARAGRAPH_SUBRESOURCE,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@3e00(size_without_padding=165,padding=0,full_name=../../components/security_interstitials_strings.grdp: IDS_MALWARE_V3_PROCEED_PARAGRAPH,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@3e01(size_without_padding=20,padding=0,full_name=../../components/security_interstitials_strings.grdp: IDS_SAFE_BROWSING_PRIVACY_POLICY_PAGE,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@3e02(size_without_padding=116,padding=0,full_name=../../components/security_interstitials_strings.grdp: IDS_SAFE_BROWSING_MALWARE_REPORTING_AGREE,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@3e03(size_without_padding=156,padding=0,full_name=../../components/security_interstitials_strings.grdp: IDS_SAFE_BROWSING_SCOUT_REPORTING_AGREE,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@3e08(size_without_padding=26,padding=0,full_name=../../components/security_interstitials_strings.grdp: IDS_PHISHING_V4_HEADING,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@3e09(size_without_padding=253,padding=0,full_name=../../components/security_interstitials_strings.grdp: IDS_PHISHING_V4_PRIMARY_PARAGRAPH,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@3e0a(size_without_padding=155,padding=0,full_name=../../components/security_interstitials_strings.grdp: IDS_PHISHING_V4_EXPLANATION_PARAGRAPH,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@3e0b(size_without_padding=187,padding=0,full_name=../../components/security_interstitials_strings.grdp: IDS_PHISHING_V4_PROCEED_AND_REPORT_PARAGRAPH,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@3e0c(size_without_padding=32,padding=0,full_name=../../components/security_interstitials_strings.grdp: IDS_MALWARE_WEBVIEW_HEADING,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@3e0d(size_without_padding=160,padding=0,full_name=../../components/security_interstitials_strings.grdp: IDS_MALWARE_WEBVIEW_EXPLANATION_PARAGRAPH,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@3e0e(size_without_padding=32,padding=0,full_name=../../components/security_interstitials_strings.grdp: IDS_PHISHING_WEBVIEW_HEADING,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@3e0f(size_without_padding=147,padding=0,full_name=../../components/security_interstitials_strings.grdp: IDS_PHISHING_WEBVIEW_EXPLANATION_PARAGRAPH,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4e85(size_without_padding=11,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_CALENDAR_CLEAR,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4e86(size_without_padding=11,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_CALENDAR_TODAY,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4e87(size_without_padding=16,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_SUBMIT_LABEL,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4e89(size_without_padding=11,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_RESET_LABEL,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4e8a(size_without_padding=17,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_FILE_BUTTON_LABEL,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4e8b(size_without_padding=18,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_MULTIPLE_FILES_BUTTON_LABEL,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4e8c(size_without_padding=20,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_FILE_NO_FILE_LABEL,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4e8d(size_without_padding=14,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_FILE_MULTIPLE_UPLOAD,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4e8e(size_without_padding=26,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_OTHER_COLOR_LABEL,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4e92(size_without_padding=8,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_PLACEHOLDER_FOR_DAY_OF_MONTH_FIELD,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4e93(size_without_padding=8,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_PLACEHOLDER_FOR_MONTH_FIELD,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4e94(size_without_padding=10,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_PLACEHOLDER_FOR_YEAR_FIELD,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4e95(size_without_padding=17,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_SELECT_MENU_LIST_TEXT,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4e96(size_without_padding=16,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_THIS_MONTH_LABEL,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4e97(size_without_padding=15,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_THIS_WEEK_LABEL,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4e98(size_without_padding=14,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_WEEK_NUMBER_LABEL,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4e99(size_without_padding=32,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_CALENDAR_SHOW_MONTH_SELECTOR,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4e9a(size_without_padding=21,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_CALENDAR_SHOW_NEXT_MONTH,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4e9b(size_without_padding=25,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_CALENDAR_SHOW_PREVIOUS_MONTH,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4e9c(size_without_padding=24,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_CALENDAR_WEEK_DESCRIPTION,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4e9d(size_without_padding=13,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_ARTICLE,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4e9e(size_without_padding=12,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_BANNER,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4e9f(size_without_padding=19,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_COMPLEMENTARY,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ea0(size_without_padding=14,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_CHECK_BOX,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ea1(size_without_padding=18,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_CONTENT_INFO,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ea2(size_without_padding=16,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_DEFINITION,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ea4(size_without_padding=10,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_DESCRIPTION_TERM,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ea5(size_without_padding=25,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_DISCLOSURE_TRIANGLE,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ea6(size_without_padding=10,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_FEED,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ea9(size_without_padding=12,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_FOOTER,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4eac(size_without_padding=19,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_TOGGLE_BUTTON,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ead(size_without_padding=13,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_HEADING,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4eae(size_without_padding=10,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_LINK,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4eaf(size_without_padding=10,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_MAIN_CONTENT,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4eb0(size_without_padding=25,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_MARK,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4eb1(size_without_padding=10,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_MATH,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4eb2(size_without_padding=16,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_NAVIGATIONAL_LINK,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4eb3(size_without_padding=12,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_REGION,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4eb4(size_without_padding=23,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_SEARCH_BOX,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4eb5(size_without_padding=12,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_STATUS,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4eb6(size_without_padding=12,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_SWITCH,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4eb8(size_without_padding=11,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_ALERT,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4eb9(size_without_padding=18,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_ALERT_DIALOG,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4eba(size_without_padding=17,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_APPLICATION,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ebb(size_without_padding=16,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_BLOCKQUOTE,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ebc(size_without_padding=12,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_BUTTON,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ebd(size_without_padding=22,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_BUTTON_DROP_DOWN,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ebe(size_without_padding=10,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_CELL,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ebf(size_without_padding=18,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_COLOR_WELL,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ec0(size_without_padding=19,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_COLUMN_HEADER,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ec2(size_without_padding=17,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_DATE,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ec3(size_without_padding=26,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_DATE_TIME,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ec4(size_without_padding=12,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_DIALOG,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ec5(size_without_padding=15,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_DIRECTORY,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ec6(size_without_padding=14,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_DOCUMENT,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ec7(size_without_padding=12,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_EMBEDDED_OBJECT,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ec8(size_without_padding=13,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_GRAPHIC,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ec9(size_without_padding=16,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_HEADING_WITH_LEVEL,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4eca(size_without_padding=17,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_INPUT_TIME,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ecb(size_without_padding=14,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_LIST_BOX,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ecc(size_without_padding=9,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_LOG,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ecd(size_without_padding=13,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_MARQUEE,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ece(size_without_padding=10,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_MENU,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ecf(size_without_padding=14,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_MENU_BAR,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ed0(size_without_padding=17,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_MENU_BUTTON,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ed1(size_without_padding=15,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_MENU_ITEM,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ed2(size_without_padding=11,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_METER,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ed3(size_without_padding=10,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_NOTE,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ed4(size_without_padding=19,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_POP_UP_BUTTON,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ed5(size_without_padding=24,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_PROGRESS_INDICATOR,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ed6(size_without_padding=18,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_RADIO,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ed7(size_without_padding=17,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_RADIO_GROUP,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ed8(size_without_padding=16,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_ROW_HEADER,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ed9(size_without_padding=16,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_SCROLL_BAR,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4eda(size_without_padding=12,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_SEARCH,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4edb(size_without_padding=12,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_SLIDER,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4edc(size_without_padding=17,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_SPIN_BUTTON,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4edd(size_without_padding=14,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_SPLITTER,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ede(size_without_padding=9,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_TAB,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4edf(size_without_padding=11,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_TABLE,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ee0(size_without_padding=14,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_TAB_LIST,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ee1(size_without_padding=15,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_TAB_PANEL,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ee2(size_without_padding=10,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_TIME,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ee3(size_without_padding=11,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_TIMER,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ee4(size_without_padding=13,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_TOOLBAR,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ee5(size_without_padding=13,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_TOOLTIP,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ee6(size_without_padding=10,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_TREE,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ee7(size_without_padding=15,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_TREE_GRID,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ee8(size_without_padding=15,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_ROLE_TREE_ITEM,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ee9(size_without_padding=11,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_AM_PM_FIELD_TEXT,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4eea(size_without_padding=9,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_DAY_OF_MONTH_FIELD_TEXT,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4eeb(size_without_padding=11,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_HOUR_FIELD_TEXT,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4eec(size_without_padding=19,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_MEDIA_DEFAULT,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4eed(size_without_padding=15,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_MEDIA_AUDIO_ELEMENT,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4eee(size_without_padding=15,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_MEDIA_VIDEO_ELEMENT,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4eef(size_without_padding=10,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_MEDIA_MUTE_BUTTON,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ef0(size_without_padding=12,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_MEDIA_UNMUTE_BUTTON,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ef1(size_without_padding=10,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_MEDIA_PLAY_BUTTON,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ef2(size_without_padding=11,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_MEDIA_PAUSE_BUTTON,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ef3(size_without_padding=18,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_MEDIA_CURRENT_TIME_DISPLAY,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ef4(size_without_padding=20,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_MEDIA_TIME_REMAINING_DISPLAY,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ef5(size_without_padding=23,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_MEDIA_ENTER_FULL_SCREEN_BUTTON,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ef6(size_without_padding=26,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_MEDIA_EXIT_FULL_SCREEN_BUTTON,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ef7(size_without_padding=26,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_MEDIA_SHOW_CLOSED_CAPTIONS_BUTTON,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ef8(size_without_padding=26,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_MEDIA_HIDE_CLOSED_CAPTIONS_BUTTON,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4ef9(size_without_padding=31,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_MEDIA_CAST_OFF_BUTTON,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4efa(size_without_padding=33,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_MEDIA_CAST_ON_BUTTON,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4efb(size_without_padding=20,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_MEDIA_DOWNLOAD_BUTTON,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4efc(size_without_padding=30,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_MEDIA_OVERFLOW_BUTTON,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4eff(size_without_padding=22,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_MEDIA_MUTE_BUTTON_HELP,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f00(size_without_padding=24,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_MEDIA_UNMUTE_BUTTON_HELP,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f01(size_without_padding=20,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_MEDIA_PLAY_BUTTON_HELP,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f02(size_without_padding=20,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_MEDIA_PAUSE_BUTTON_HELP,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f03(size_without_padding=25,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_MEDIA_AUDIO_SLIDER_HELP,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f04(size_without_padding=25,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_MEDIA_VIDEO_SLIDER_HELP,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f05(size_without_padding=29,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_MEDIA_CURRENT_TIME_DISPLAY_HELP,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f06(size_without_padding=42,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_MEDIA_TIME_REMAINING_DISPLAY_HELP,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f07(size_without_padding=36,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_MEDIA_ENTER_FULL_SCREEN_BUTTON_HELP,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f09(size_without_padding=38,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_MEDIA_SHOW_CLOSED_CAPTIONS_BUTTON_HELP,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f0a(size_without_padding=37,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_MEDIA_HIDE_CLOSED_CAPTIONS_BUTTON_HELP,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f0d(size_without_padding=18,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_MEDIA_OVERFLOW_BUTTON_HELP,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f0e(size_without_padding=18,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_MILLISECOND_FIELD_TEXT,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f0f(size_without_padding=13,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_MINUTE_FIELD_TEXT,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f10(size_without_padding=11,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_MONTH_FIELD_TEXT,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f11(size_without_padding=13,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_SECOND_FIELD_TEXT,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f13(size_without_padding=10,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_AX_YEAR_FIELD_TEXT,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f14(size_without_padding=17,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_INPUT_WEEK_TEMPLATE,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f15(size_without_padding=38,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_VALIDATION_VALUE_MISSING_MULTIPLE_FILE,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f16(size_without_padding=20,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_VALIDATION_TYPE_MISMATCH,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f17(size_without_padding=45,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_VALIDATION_TYPE_MISMATCH_EMAIL_EMPTY,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f18(size_without_padding=61,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_VALIDATION_TYPE_MISMATCH_EMAIL_EMPTY_DOMAIN,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f19(size_without_padding=63,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_VALIDATION_TYPE_MISMATCH_EMAIL_EMPTY_LOCAL,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f1a(size_without_padding=63,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_VALIDATION_TYPE_MISMATCH_EMAIL_INVALID_DOMAIN,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f1b(size_without_padding=47,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_VALIDATION_TYPE_MISMATCH_EMAIL_INVALID_DOTS,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f1c(size_without_padding=65,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_VALIDATION_TYPE_MISMATCH_EMAIL_INVALID_LOCAL,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f1d(size_without_padding=75,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_VALIDATION_TYPE_MISMATCH_EMAIL_NO_AT_SIGN,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f1e(size_without_padding=61,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_VALIDATION_TYPE_MISMATCH_MULTIPLE_EMAIL,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f1f(size_without_padding=48,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_VALIDATION_RANGE_UNDERFLOW,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f20(size_without_padding=32,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_VALIDATION_RANGE_UNDERFLOW_DATETIME,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f21(size_without_padding=45,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_VALIDATION_RANGE_OVERFLOW,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f22(size_without_padding=34,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_VALIDATION_RANGE_OVERFLOW_DATETIME,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f23(size_without_padding=81,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_VALIDATION_BAD_INPUT_DATETIME,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f24(size_without_padding=28,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_VALIDATION_BAD_INPUT_NUMBER,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f25(size_without_padding=33,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_VALIDATION_VALUE_MISSING,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f26(size_without_padding=51,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_VALIDATION_VALUE_MISSING_CHECKBOX,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f27(size_without_padding=27,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_VALIDATION_VALUE_MISSING_FILE,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f28(size_without_padding=41,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_VALIDATION_VALUE_MISSING_RADIO,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f29(size_without_padding=40,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_VALIDATION_VALUE_MISSING_SELECT,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f2a(size_without_padding=36,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_VALIDATION_TYPE_MISMATCH_EMAIL,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f2b(size_without_padding=25,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_VALIDATION_TYPE_MISMATCH_URL,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f2c(size_without_padding=40,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_VALIDATION_PATTERN_MISMATCH,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f2d(size_without_padding=77,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_VALIDATION_STEP_MISMATCH,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f2e(size_without_padding=64,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_VALIDATION_STEP_MISMATCH_CLOSE_TO_LIMIT,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f2f(size_without_padding=96,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_VALIDATION_TOO_LONG,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f30(size_without_padding=95,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_VALIDATION_TOO_SHORT,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f31(size_without_padding=97,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_FORM_VALIDATION_TOO_SHORT_PLURAL,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f32(size_without_padding=14,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_MEDIA_OVERFLOW_MENU_CLOSED_CAPTIONS,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f33(size_without_padding=13,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_MEDIA_OVERFLOW_MENU_CLOSED_CAPTIONS_SUBMENU_TITLE,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f34(size_without_padding=10,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_MEDIA_OVERFLOW_MENU_CAST,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f35(size_without_padding=16,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_MEDIA_OVERFLOW_MENU_ENTER_FULLSCREEN,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f36(size_without_padding=21,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_MEDIA_OVERFLOW_MENU_EXIT_FULLSCREEN,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f37(size_without_padding=18,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_MEDIA_OVERFLOW_MENU_STOP_CAST,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f38(size_without_padding=10,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_MEDIA_OVERFLOW_MENU_MUTE,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f39(size_without_padding=12,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_MEDIA_OVERFLOW_MENU_UNMUTE,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f3a(size_without_padding=10,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_MEDIA_OVERFLOW_MENU_PLAY,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f3b(size_without_padding=11,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_MEDIA_OVERFLOW_MENU_PAUSE,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f3c(size_without_padding=14,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_MEDIA_OVERFLOW_MENU_DOWNLOAD,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f3d(size_without_padding=26,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_MEDIA_REMOTING_DISABLE_TEXT,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f3e(size_without_padding=23,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_MEDIA_REMOTING_CAST_TEXT,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f3f(size_without_padding=28,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_MEDIA_REMOTING_CAST_TO_UNKNOWN_DEVICE_TEXT,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f40(size_without_padding=14,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_MEDIA_TRACKS_NO_LABEL,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f41(size_without_padding=9,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_MEDIA_TRACKS_OFF,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@4f42(size_without_padding=27,padding=0,full_name=../../content/app/strings/content_strings.grd: IDS_PLUGIN_INITIALIZATION_ERROR,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@5bd6(size_without_padding=27,padding=0,full_name=../../android_webview/ui/aw_strings.grd: IDS_AW_WEBPAGE_NOT_AVAILABLE,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@5bd7(size_without_padding=69,padding=0,full_name=../../android_webview/ui/aw_strings.grd: IDS_AW_WEBPAGE_CAN_NOT_BE_LOADED,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@5bd8(size_without_padding=121,padding=0,full_name=../../android_webview/ui/aw_strings.grd: IDS_AW_WEBPAGE_TEMPORARILY_DOWN,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@5bd9(size_without_padding=161,padding=0,full_name=../../android_webview/ui/aw_strings.grd: IDS_AW_WEBPAGE_TEMPORARILY_DOWN_SUGGESTIONS,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@5bda(size_without_padding=80,padding=0,full_name=../../android_webview/ui/aw_strings.grd: IDS_AW_WEBPAGE_PARENTAL_PERMISSION_NEEDED,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@6917(size_without_padding=23,padding=0,full_name=../../ui/strings/app_locale_settings.grd: IDS_WEB_FONT_FAMILY,object_path=,source_path=,flags={},num_aliases=1) +.pak.translations@6918(size_without_padding=9,padding=0,full_name=../../ui/strings/app_locale_settings.grd: IDS_WEB_FONT_SIZE,object_path=,source_path=,flags={},num_aliases=1)
diff --git a/tools/binary_size/libsupersize/testdata/Console.golden b/tools/binary_size/libsupersize/testdata/Console.golden index 1e5fa7e..f54920a 100644 --- a/tools/binary_size/libsupersize/testdata/Console.golden +++ b/tools/binary_size/libsupersize/testdata/Console.golden
@@ -1,18 +1,18 @@ ******************************************************************************** Entering interactive Python shell. Quick reference: -SizeInfo: metadata, raw_symbols, section_sizes, size_path, symbols -Symbol: FlagsString, IsBss, IsDelta, IsGeneratedByToolchain, IsGroup, IterLeafSymbols, address, aliases, end_address, flags, full_name, generated_source, is_anonymous, name, num_aliases, object_path, padding, padding_pss, pss, pss_without_padding, section, section_name, size, size_without_padding, source_path, template_name +SizeInfo: metadata, native_symbols, pak_symbols, raw_symbols, section_sizes, size_path, symbols +Symbol: FlagsString, IsBss, IsDelta, IsGeneratedByToolchain, IsGroup, IsPak, IsStringLiteral, IterLeafSymbols, address, aliases, end_address, flags, full_name, generated_source, is_anonymous, name, num_aliases, object_path, padding, padding_pss, pss, pss_without_padding, section, section_name, size, size_without_padding, source_path, template_name -SymbolGroup (extends Symbol): CountUniqueSymbols, Filter, GroupedBy, GroupedByFullName, GroupedByName, GroupedByPath, GroupedBySectionName, Inverted, IterUniqueSymbols, SetName, Sorted, SortedByAddress, SortedByCount, SortedByName, WhereAddressInRange, WhereFullNameMatches, WhereGeneratedByToolchain, WhereHasAnyAttribution, WhereHasPath, WhereInSection, WhereIsGroup, WhereIsTemplate, WhereMatches, WhereNameMatches, WhereObjectPathMatches, WherePathMatches, WherePssBiggerThan, WhereSizeBiggerThan, WhereSourceIsGenerated, WhereSourcePathMatches, WhereTemplateNameMatches, index, is_sorted +SymbolGroup (extends Symbol): CountUniqueSymbols, Filter, GroupedBy, GroupedByAliases, GroupedByFullName, GroupedByName, GroupedByPath, GroupedBySectionName, Inverted, IterUniqueSymbols, SetName, Sorted, SortedByAddress, SortedByCount, SortedByName, WhereAddressInRange, WhereFullNameMatches, WhereGeneratedByToolchain, WhereHasAnyAttribution, WhereHasPath, WhereInSection, WhereIsGroup, WhereIsNative, WhereIsPak, WhereIsTemplate, WhereMatches, WhereNameMatches, WhereObjectPathMatches, WherePathMatches, WherePssBiggerThan, WhereSizeBiggerThan, WhereSourceIsGenerated, WhereSourcePathMatches, WhereTemplateNameMatches, index, is_sorted -DeltaSizeInfo: after_metadata, before_metadata, raw_symbols, section_sizes, symbols +DeltaSizeInfo: after, before, native_symbols, pak_symbols, raw_symbols, section_sizes, symbols DeltaSymbol (extends Symbol): after_symbol, before_symbol, diff_status DeltaSymbolGroup (extends SymbolGroup): CountsByDiffStatus, WhereDiffStatusIs, diff_status -canned_queries: CategorizeByChromeComponent, CategorizeGenerated, StaticInitializers, TemplatesByName +canned_queries: CategorizeByChromeComponent, CategorizeGenerated, LargeFiles, PakByPath, StaticInitializers, TemplatesByName -Functions: Csv(), Diff(), Disassemble(), ExpandRegex(), Print(), ShowExamples() +Functions: Csv(), Diff(), Disassemble(), ExpandRegex(), Print(), ReadStringLiterals(), ShowExamples() Variables: printed: List of objects passed to Print(). size_info: Loaded from {redacted} @@ -27,6 +27,9 @@ # Dump section info and all symbols in CSV format: Csv(size_info) +# Print sorted list of all string literals: +Print(sorted(x[1] for x in ReadStringLiterals())) + # Show two levels of .text, grouped by first two subdirectories text_syms = size_info.symbols.WhereInSection("t") by_path = text_syms.GroupedByPath(depth=2) @@ -53,6 +56,8 @@ # For even more inspiration, look at canned_queries.py # (and feel free to add your own!). +0: (.rodata@266e600(size_without_padding=5,padding=0,full_name=string literal,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=2), 'Str1\x00') +1: (.rodata@266e605(size_without_padding=16,padding=0,full_name=string literal,object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={gen},num_aliases=1), 'String literal2\x00') Metadata: elf_arch=arm elf_build_id=WhatAnAmazingBuildId @@ -63,110 +68,125 @@ map_file_name=../test.map tool_prefix=tools/binary_size/libsupersize/testdata/mock_toolchain/ -Section Sizes (Total=95.6mb (100233874 bytes)): - .ARM.exidx: 1.47mb (1536456 bytes) (1.5%) +Section Sizes (Total=128.0mb (134218045 bytes)): + .ARM.exidx: 1.47mb (1536456 bytes) (1.1%) .bss: 1.24mb (1300456 bytes) (not included in totals) .data: 99.4kb (101768 bytes) (0.1%) - .data.rel.ro: 1.02mb (1065224 bytes) (1.1%) - .rel.dyn: 2.53mb (2655384 bytes) (2.6%) - .rodata: 5.65mb (5927652 bytes) (5.9%) - .strtab: 33.2mb (34841854 bytes) (34.8%) - .symtab: 16.4mb (17166112 bytes) (17.1%) - .text: 34.2mb (35900712 bytes) (35.8%) + .data.rel.ro: 1.02mb (1065224 bytes) (0.8%) + .other: 32.4mb (33984171 bytes) (25.3%) + .rel.dyn: 2.53mb (2655384 bytes) (2.0%) + .rodata: 5.65mb (5927652 bytes) (4.4%) + .strtab: 33.2mb (34841854 bytes) (26.0%) + .symtab: 16.4mb (17166112 bytes) (12.8%) + .text: 34.2mb (35900712 bytes) (26.7%) -Showing 45 symbols (42 unique) with total pss: 43785380 bytes -.text=34.2mb .rodata=5.65mb .data.rel.ro=1.02mb .data=99.4kb .bss=512kb total=41.8mb +Showing 50 symbols (45 unique) with total pss: 77769551 bytes +Histogram of symbols based on PSS: + [2,4): 6 [16,32): 10 [128,256): 2 [131072,262144): 2 [1048576,2097152): 2 + [4,8): 6 [32,64): 9 [256,512): 1 [262144,524288): 1 [2097152,4194304): 1 + [8,16): 3 [64,128): 1 [65536,131072): 2 [524288,1048576): 2 [33554432,67108864): 2 +.text=34.2mb .rodata=5.65mb .data.rel.ro=1.02mb .data=99.4kb .bss=512kb .other=32.4mb total=74.2mb Number of unique paths: 9 -Section Legend: t=.text, r=.rodata, R=.data.rel.ro, d=.data, b=.bss +Section Legend: t=.text, r=.rodata, R=.data.rel.ro, d=.data, b=.bss, o=.other Index | Running Total | Section@Address | PSS | Path ------------------------------------------------------------ -0) 16 (0.0%) t@0x28d900 16 base/page_allocator.cc - _GLOBAL__sub_I_page_allocator.cc -1) 72 (0.0%) t@0x28d910 56 base/page_allocator.cc - _GLOBAL__sub_I_bbr_sender.cc -2) 100 (0.0%) t@0x28d948 28 base/page_allocator.cc - _GLOBAL__sub_I_pacing_sender.cc -3) 138 (0.0%) t@0x28d964 38 base/page_allocator.cc - extFromUUseMapping -4) 170 (0.0%) t@0x28d98a 32 base/page_allocator.cc - extFromUUseMapping -5) 35830930 (81.8%) t@Group 35830760 {no path} - ** symbol gaps (count=3) -6) 35831378 (81.8%) t@0x28f000 448 third_party/icu/ucnv_ext.c - ucnv_extMatchFromU -7) 35831406 (81.8%) t@0x28f1c8 28 third_party/icu/ucnv_ext.c - _GLOBAL__sub_I_SkDeviceProfile.cpp -8) 35900530 (82.0%) t@0x28f1e0 69124 third_party/icu/ucnv_ext.c - foo_bar -9) 35900554 (82.0%) t@0x2a0000 24 (size=48) {no path} - blink::ContiguousContainerBase::shrinkToFit (num_aliases=2) -10) 35900578 (82.0%) t@0x2a0000 24 (size=48) third_party/icu/ucnv_ext.c - BazAlias (num_aliases=2) -11) 35900582 (82.0%) t@0x2a0010 4 (size=12) third_party/{shared}/2 - blink::ContiguousContainerBase::shrinkToFit (num_aliases=3) -12) 35900586 (82.0%) t@0x2a0010 4 (size=12) third_party/fft_float.cc - FooAlias (num_aliases=3) -13) 35900590 (82.0%) t@0x2a0010 4 (size=12) third_party/fft_float.cc - BarAlias (num_aliases=3) -14) 35900618 (82.0%) t@0x2a0020 28 third_party/container.c - blink::ContiguousContainerBase::ContiguousContainerBase -15) 35900712 (82.0%) t@0x2a1000 94 third_party/container.c - blink::PaintChunker::releasePaintChunks -16) 38538681 (88.0%) r@Group 2637969 {no path} - ** merge strings (count=2) -17) 38542106 (88.0%) r@0x284d600 3425 {no path} - ** merge constants -18) 41828221 (95.5%) r@Group 3286115 {no path} - ** symbol gaps (count=2) -19) 41828229 (95.5%) r@0x284e364 8 base/page_allocator.cc -20) 41828273 (95.5%) r@0x284e370 44 base/page_allocator.cc - Name -21) 41828305 (95.5%) r@0x284e398 32 third_party/container.c - chrome::mojom::FilePatcher::Name_ -22) 41828360 (95.5%) r@0x28f3450 55 third_party/paint.cc - kAnimationFrameTimeHistogramClassPath -23) 41828364 (95.5%) r@0x28f3480 4 third_party/paint.cc - blink::CSSValueKeywordsHash::findValueImpl::value_word_list -24) 41828420 (95.5%) R@0x2c176f0 56 third_party/icu/ucnv_ext.c - ChromeMainDelegate [vtable] -25) 41828444 (95.5%) R@0x2c17728 24 third_party/icu/ucnv_ext.c - chrome::mojom::FieldTrialRecorder [vtable] -26) 42618348 (97.3%) R@0x2c17740 789904 third_party/container.c - chrome::mojom::FieldTrialRecorderProxy [vtable] -27) 42618380 (97.3%) R@0x2cd84e0 32 third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libcontroller_api_impl.a_controller_api_impl.o - .Lswitch.table.45 -28) 42618388 (97.3%) R@0x2cd84f0 8 third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libport_android_jni.a_jni_utils.o - kSystemClassPrefixes -29) 42618444 (97.3%) R@0x2cd8500 56 third_party/paint.cc - ChromeMainDelegateAndroid [vtable] -30) 42618468 (97.3%) R@0x2cd8538 24 base/page_allocator.cc - mojo::MessageReceiver [vtable] -31) 42618480 (97.3%) R@0x2cd8550 12 base/page_allocator.cc - kMethodsAnimationFrameTimeHistogram -32) 43683612 (99.8%) R@0x2ddc608 1065132 {no path} - ** symbol gap 0 (end of section) -33) 43683616 (99.8%) d@0x2de7000 4 base/page_allocator.cc +0) 4 (0.0%) d@0x2de7000 4 base/page_allocator.cc google::protobuf::internal::pLinuxKernelCmpxchg -34) 43683620 (99.8%) d@0x2de7004 4 third_party/container.c +1) 8 (0.0%) d@0x2de7004 4 third_party/container.c google::protobuf::internal::pLinuxKernelMemoryBarrier -35) 43683772 (99.8%) d@0x2de7008 152 third_party/container.c +2) 160 (0.0%) d@0x2de7008 152 third_party/container.c base::android::kBaseRegisteredMethods -36) 43683776 (99.8%) d@0x2de70a0 4 third_party/container.c +3) 164 (0.0%) d@0x2de70a0 4 third_party/container.c base::android::g_renderer_histogram_code -37) 43683780 (99.8%) d@0x2de70a4 4 third_party/container.c +4) 168 (0.0%) d@0x2de70a4 4 third_party/container.c base::android::g_library_version_number -38) 43785380 (100.0%) d@0x2dffd88 101600 {no path} +5) 101768 (0.1%) d@0x2dffd88 101600 {no path} ** symbol gap 0 (end of section) -39) 43785380 (100.0%) b@0x0 262144 third_party/fft_float.cc +6) 101824 (0.1%) R@0x2cd8500 56 third_party/paint.cc + ChromeMainDelegateAndroid [vtable] +7) 101848 (0.1%) R@0x2cd8538 24 base/page_allocator.cc + mojo::MessageReceiver [vtable] +8) 101860 (0.1%) R@0x2cd8550 12 base/page_allocator.cc + kMethodsAnimationFrameTimeHistogram +9) 1166992 (1.5%) R@0x2ddc608 1065132 {no path} + ** symbol gap 0 (end of section) +10) 1167048 (1.5%) R@0x2c176f0 56 third_party/icu/ucnv_ext.c + ChromeMainDelegate [vtable] +11) 1167072 (1.5%) R@0x2c17728 24 third_party/icu/ucnv_ext.c + chrome::mojom::FieldTrialRecorder [vtable] +12) 1956976 (2.5%) R@0x2c17740 789904 third_party/container.c + chrome::mojom::FieldTrialRecorderProxy [vtable] +13) 1957008 (2.5%) R@0x2cd84e0 32 third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libcontroller_api_impl.a_controller_api_impl.o + .Lswitch.table.45 +14) 1957016 (2.5%) R@0x2cd84f0 8 third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libport_android_jni.a_jni_utils.o + kSystemClassPrefixes +15) 35941187 (46.2%) o@0x0 33984171 {no path} + ELF file overhead +16) 35941189 (46.2%) r@0x266e600 2.5 (size=5) base/page_allocator.cc + string literal (num_aliases=2) +17) 35941192 (46.2%) r@0x266e600 2.5 (size=5) third_party/icu/ucnv_ext.c + string literal (num_aliases=2) +18) 35941208 (46.2%) r@0x266e605 16 third_party/icu/ucnv_ext.c + string literal +19) 35941251 (46.2%) r@0x266e630 43 {no path} + ** merge strings +20) 37906596 (48.7%) r@0x284d600 1965345 {no path} + ** merge constants +21) 41192711 (53.0%) r@Group 3286115 {no path} + ** symbol gaps (count=2) +22) 41192719 (53.0%) r@0x284e364 8 base/page_allocator.cc +23) 41192763 (53.0%) r@0x284e370 44 base/page_allocator.cc + Name +24) 41192795 (53.0%) r@0x284e398 32 third_party/container.c + chrome::mojom::FilePatcher::Name_ +25) 41868835 (53.8%) r@0x28f3450 676040 third_party/paint.cc + kAnimationFrameTimeHistogramClassPath +26) 41868839 (53.8%) r@0x28f3480 4 third_party/paint.cc + blink::CSSValueKeywordsHash::findValueImpl::value_word_list +27) 41868855 (53.8%) t@0x28d900 16 base/page_allocator.cc + _GLOBAL__sub_I_page_allocator.cc +28) 41868911 (53.8%) t@0x28d910 56 base/page_allocator.cc + _GLOBAL__sub_I_bbr_sender.cc +29) 41868939 (53.8%) t@0x28d948 28 base/page_allocator.cc + _GLOBAL__sub_I_pacing_sender.cc +30) 41868977 (53.8%) t@0x28d964 38 base/page_allocator.cc + extFromUUseMapping +31) 41869009 (53.8%) t@0x28d98a 32 base/page_allocator.cc + extFromUUseMapping +32) 77699769 (99.9%) t@Group 35830760 {no path} + ** symbol gaps (count=3) +33) 77700217 (99.9%) t@0x28f000 448 third_party/icu/ucnv_ext.c + ucnv_extMatchFromU +34) 77700245 (99.9%) t@0x28f1c8 28 third_party/icu/ucnv_ext.c + _GLOBAL__sub_I_SkDeviceProfile.cpp +35) 77769369 (100.0%) t@0x28f1e0 69124 third_party/icu/ucnv_ext.c + foo_bar +36) 77769393 (100.0%) t@0x2a0000 24 (size=48) {no path} + blink::ContiguousContainerBase::shrinkToFit (num_aliases=2) +37) 77769417 (100.0%) t@0x2a0000 24 (size=48) third_party/icu/ucnv_ext.c + BazAlias (num_aliases=2) +38) 77769420 (100.0%) t@0x2a0010 3 (size=12) third_party/paint.cc + blink::ContiguousContainerBase::shrinkToFit (num_aliases=4) +39) 77769423 (100.0%) t@0x2a0010 3 (size=12) third_party/icu/ucnv_ext.c + blink::ContiguousContainerBase::shrinkToFit (num_aliases=4) +40) 77769426 (100.0%) t@0x2a0010 3 (size=12) third_party/fft_float.cc + FooAlias (num_aliases=4) +41) 77769429 (100.0%) t@0x2a0010 3 (size=12) third_party/fft_float.cc + BarAlias (num_aliases=4) +42) 77769457 (100.0%) t@0x2a0020 28 third_party/container.c + blink::ContiguousContainerBase::ContiguousContainerBase +43) 77769551 (100.0%) t@0x2a1000 94 third_party/container.c + blink::PaintChunker::releasePaintChunks +44) 77769551 (100.0%) b@0x0 262144 third_party/fft_float.cc ff_cos_131072 -40) 43785380 (100.0%) b@0x0 131072 third_party/fft_fixed.cc +45) 77769551 (100.0%) b@0x0 131072 third_party/fft_fixed.cc ff_cos_131072_fixed -41) 43785380 (100.0%) b@0x0 131072 third_party/fft_float.cc +46) 77769551 (100.0%) b@0x0 131072 third_party/fft_float.cc ff_cos_65536 -42) 43785380 (100.0%) b@0x2dffda0 28 third_party/icu/ucnv_ext.c +47) 77769551 (100.0%) b@0x2dffda0 28 third_party/icu/ucnv_ext.c g_chrome_content_browser_client -43) 43785380 (100.0%) b@0x2dffe80 200 third_party/icu/ucnv_ext.c +48) 77769551 (100.0%) b@0x2dffe80 200 third_party/icu/ucnv_ext.c SaveHistogram::atomic_histogram_pointer -44) 43785380 (100.0%) b@0x2dffe84 4 third_party/icu/ucnv_ext.c +49) 77769551 (100.0%) b@0x2dffe84 4 third_party/icu/ucnv_ext.c g_AnimationFrameTimeHistogram_clazz
diff --git a/tools/binary_size/libsupersize/testdata/Csv.golden b/tools/binary_size/libsupersize/testdata/Csv.golden index ed95da8..d2f1ded 100644 --- a/tools/binary_size/libsupersize/testdata/Csv.golden +++ b/tools/binary_size/libsupersize/testdata/Csv.golden
@@ -3,6 +3,7 @@ .bss,1300456 .data,101768 .data.rel.ro,1065224 +.other,33984171 .rel.dyn,2655384 .rodata,5927652 .strtab,34841854 @@ -10,6 +11,33 @@ .text,35900712 GroupCount,Address,SizeWithoutPadding,Padding,NumAliases,PSS,Section,Name +,0x2de7000,4,0,1,4.0,d,google::protobuf::internal::pLinuxKernelCmpxchg +,0x2de7004,4,0,1,4.0,d,google::protobuf::internal::pLinuxKernelMemoryBarrier +,0x2de7008,152,0,1,152.0,d,base::android::kBaseRegisteredMethods +,0x2de70a0,4,0,1,4.0,d,base::android::g_renderer_histogram_code +,0x2de70a4,4,0,1,4.0,d,base::android::g_library_version_number +,0x2dffd88,0,101600,1,101600.0,d,** symbol gap 0 (end of section) +,0x2cd8500,56,0,1,56.0,R,ChromeMainDelegateAndroid [vtable] +,0x2cd8538,24,0,1,24.0,R,mojo::MessageReceiver [vtable] +,0x2cd8550,12,0,1,12.0,R,kMethodsAnimationFrameTimeHistogram +,0x2ddc608,0,1065132,1,1065132.0,R,** symbol gap 0 (end of section) +,0x2c176f0,56,0,1,56.0,R,ChromeMainDelegate [vtable] +,0x2c17728,24,0,1,24.0,R,chrome::mojom::FieldTrialRecorder [vtable] +,0x2c17740,789904,0,1,789904.0,R,chrome::mojom::FieldTrialRecorderProxy [vtable] +,0x2cd84e0,16,16,1,32.0,R,.Lswitch.table.45 +,0x2cd84f0,8,0,1,8.0,R,kSystemClassPrefixes +,0x0,33984171,0,1,33984171.0,o,ELF file overhead +,0x266e600,5,0,2,2.5,r,string literal +,0x266e600,5,0,2,2.5,r,string literal +,0x266e605,16,0,1,16.0,r,string literal +,0x266e630,16,27,1,43.0,r,** merge strings +,0x284d600,3425,1961920,1,1965345.0,r,** merge constants +2,,0,3286115,1,3286115.0,r,** symbol gaps +,0x284e364,8,0,1,8.0,r, +,0x284e370,40,4,1,44.0,r,Name +,0x284e398,32,0,1,32.0,r,chrome::mojom::FilePatcher::Name_ +,0x28f3450,48,675992,1,676040.0,r,kAnimationFrameTimeHistogramClassPath +,0x28f3480,4,0,1,4.0,r,blink::CSSValueKeywordsHash::findValueImpl::value_word_list ,0x28d900,16,0,1,16.0,t,_GLOBAL__sub_I_page_allocator.cc ,0x28d910,56,0,1,56.0,t,_GLOBAL__sub_I_bbr_sender.cc ,0x28d948,28,0,1,28.0,t,_GLOBAL__sub_I_pacing_sender.cc @@ -21,34 +49,12 @@ ,0x28f1e0,69120,4,1,69124.0,t,foo_bar ,0x2a0000,16,32,2,24.0,t,blink::ContiguousContainerBase::shrinkToFit ,0x2a0000,16,32,2,24.0,t,BazAlias -,0x2a0010,12,0,3,4.0,t,blink::ContiguousContainerBase::shrinkToFit -,0x2a0010,12,0,3,4.0,t,FooAlias -,0x2a0010,12,0,3,4.0,t,BarAlias +,0x2a0010,12,0,4,3.0,t,blink::ContiguousContainerBase::shrinkToFit +,0x2a0010,12,0,4,3.0,t,blink::ContiguousContainerBase::shrinkToFit +,0x2a0010,12,0,4,3.0,t,FooAlias +,0x2a0010,12,0,4,3.0,t,BarAlias ,0x2a0020,24,4,1,28.0,t,blink::ContiguousContainerBase::ContiguousContainerBase ,0x2a1000,94,0,1,94.0,t,blink::PaintChunker::releasePaintChunks -2,,2637617,352,1,2637969.0,r,** merge strings -,0x284d600,3425,0,1,3425.0,r,** merge constants -2,,0,3286115,1,3286115.0,r,** symbol gaps -,0x284e364,8,0,1,8.0,r, -,0x284e370,40,4,1,44.0,r,Name -,0x284e398,32,0,1,32.0,r,chrome::mojom::FilePatcher::Name_ -,0x28f3450,48,7,1,55.0,r,kAnimationFrameTimeHistogramClassPath -,0x28f3480,4,0,1,4.0,r,blink::CSSValueKeywordsHash::findValueImpl::value_word_list -,0x2c176f0,56,0,1,56.0,R,ChromeMainDelegate [vtable] -,0x2c17728,24,0,1,24.0,R,chrome::mojom::FieldTrialRecorder [vtable] -,0x2c17740,789904,0,1,789904.0,R,chrome::mojom::FieldTrialRecorderProxy [vtable] -,0x2cd84e0,16,16,1,32.0,R,.Lswitch.table.45 -,0x2cd84f0,8,0,1,8.0,R,kSystemClassPrefixes -,0x2cd8500,56,0,1,56.0,R,ChromeMainDelegateAndroid [vtable] -,0x2cd8538,24,0,1,24.0,R,mojo::MessageReceiver [vtable] -,0x2cd8550,12,0,1,12.0,R,kMethodsAnimationFrameTimeHistogram -,0x2ddc608,0,1065132,1,1065132.0,R,** symbol gap 0 (end of section) -,0x2de7000,4,0,1,4.0,d,google::protobuf::internal::pLinuxKernelCmpxchg -,0x2de7004,4,0,1,4.0,d,google::protobuf::internal::pLinuxKernelMemoryBarrier -,0x2de7008,152,0,1,152.0,d,base::android::kBaseRegisteredMethods -,0x2de70a0,4,0,1,4.0,d,base::android::g_renderer_histogram_code -,0x2de70a4,4,0,1,4.0,d,base::android::g_library_version_number -,0x2dffd88,0,101600,1,101600.0,d,** symbol gap 0 (end of section) ,0x0,262144,0,1,262144.0,b,ff_cos_131072 ,0x0,131072,0,1,131072.0,b,ff_cos_131072_fixed ,0x0,131072,0,1,131072.0,b,ff_cos_65536
diff --git a/tools/binary_size/libsupersize/testdata/Diff_Basic.golden b/tools/binary_size/libsupersize/testdata/Diff_Basic.golden index 8ab6fc1a..fec9c5f 100644 --- a/tools/binary_size/libsupersize/testdata/Diff_Basic.golden +++ b/tools/binary_size/libsupersize/testdata/Diff_Basic.golden
@@ -38,146 +38,22 @@ .strtab: 0 bytes (0 bytes) .symtab: 0 bytes (0 bytes) -0 symbols added (+), 1 changed (~), 0 removed (-), 40 unchanged (=) +0 symbols added (+), 1 changed (~), 0 removed (-), 40 unchanged (not shown) +Of changed symbols, 1 grew, 0 shrank Number of unique symbols 46 -> 46 (+0) 0 paths added, 0 removed, 1 changed Changed files: - base/page_allocator.cc + third_party/container.c -Showing 41 symbols (aliases not grouped for diffs) with total pss: 10 bytes -.text=10 bytes .rodata=0 bytes .data.rel.ro=0 bytes .data=0 bytes .bss=0 bytes total=10 bytes -Number of unique paths: 9 +Showing 1 symbols (1 -> 1 unique) with total pss: 10 bytes +Histogram of symbols based on PSS: + [8,16): 1 +.text=0 bytes .rodata=0 bytes .data.rel.ro=0 bytes .data=10 bytes .bss=0 bytes total=10 bytes +Number of unique paths: 1 Section Legend: t=.text, r=.rodata, R=.data.rel.ro, d=.data, b=.bss Index | Running Total | Section@Address | ... ------------------------------------------------------------ -~ 0) 10 (100.0%) t@0x28d964 +10 (28->38) num_aliases=1 - source_path=base/page_allocator.cc object_path=base/base/page_allocator.o - flags={} name=extFromUUseMapping - full_name=extFromUUseMapping(signed char, unsigned int, int) -= 1) 10 (100.0%) r@0x284e364 +0 (8->8) num_aliases=1 - source_path=base/page_allocator.cc object_path=base/base/page_allocator.o -= 2) 10 (100.0%) r@0x284d600 +0 (3425->3425) num_aliases=1 - source_path= object_path= - flags={} name=** merge constants -= 3) 10 (100.0%) r@Group +0 (2637617->2637617) count=2 - source_path= object_path= - flags={} name=** merge strings -= 4) 10 (100.0%) R@0x2ddc608 +0 (0->0) num_aliases=1 - source_path= object_path= - flags={} name=** symbol gap 0 (end of section) -= 5) 10 (100.0%) d@0x2dffd88 +0 (0->0) num_aliases=1 - source_path= object_path= - flags={} name=** symbol gap 0 (end of section) -= 6) 10 (100.0%) t@Group +0 (0->0) count=3 - source_path= object_path= - flags={} name=** symbol gaps -= 7) 10 (100.0%) r@Group +0 (0->0) count=2 - source_path= object_path= - flags={} name=** symbol gaps -= 8) 10 (100.0%) R@0x2cd84e0 +0 (16->16) num_aliases=1 - source_path= object_path=third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libcontroller_api_impl.a_controller_api_impl.o - flags={} name=.Lswitch.table.45 -= 9) 10 (100.0%) R@0x2c176f0 +0 (56->56) num_aliases=1 - source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o - flags={} name=ChromeMainDelegate [vtable] -= 10) 10 (100.0%) R@0x2cd8500 +0 (56->56) num_aliases=1 - source_path=third_party/paint.cc object_path=third_party/WebKit.a/PaintChunker.o - flags={} name=ChromeMainDelegateAndroid [vtable] -= 11) 10 (100.0%) r@0x284e370 +0 (40->40) num_aliases=1 - source_path=base/page_allocator.cc object_path=base/base/page_allocator.o - flags={} name=Name -= 12) 10 (100.0%) t@0x28f1c8 +0 (20->20) num_aliases=1 - source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o - flags={} name=_GLOBAL__sub_I_SkDeviceProfile.cpp -= 13) 10 (100.0%) t@0x28d910 +0 (56->56) num_aliases=1 - source_path=base/page_allocator.cc object_path=base/base/page_allocator.o - flags={} name=_GLOBAL__sub_I_bbr_sender.cc -= 14) 10 (100.0%) t@0x28d948 +0 (28->28) num_aliases=1 - source_path=base/page_allocator.cc object_path=base/base/page_allocator.o - flags={} name=_GLOBAL__sub_I_pacing_sender.cc -= 15) 10 (100.0%) t@0x28d900 +0 (16->16) num_aliases=1 - source_path=base/page_allocator.cc object_path=base/base/page_allocator.o - flags={} name=_GLOBAL__sub_I_page_allocator.cc -= 16) 10 (100.0%) d@0x2de70a4 +0 (4->4) num_aliases=1 - source_path=third_party/container.c object_path=third_party/WebKit.a/ContiguousContainer.o - flags={} name=base::android::g_library_version_number -= 17) 10 (100.0%) d@0x2de70a0 +0 (4->4) num_aliases=1 +~ 0) 10 (100.0%) d@0x2de70a0 +10 (-6->4) num_aliases=1 source_path=third_party/container.c object_path=third_party/WebKit.a/ContiguousContainer.o flags={} name=base::android::g_renderer_histogram_code -= 18) 10 (100.0%) d@0x2de7008 +0 (152->152) num_aliases=1 - source_path=third_party/container.c object_path=third_party/WebKit.a/ContiguousContainer.o - flags={} name=base::android::kBaseRegisteredMethods -= 19) 10 (100.0%) r@0x28f3480 +0 (4->4) num_aliases=1 - source_path=third_party/paint.cc object_path=third_party/WebKit.a/PaintChunker.o - flags={} name=blink::CSSValueKeywordsHash::findValueImpl::value_word_list - full_name=blink::CSSValueKeywordsHash::findValueImpl(char const*, unsigned int)::value_word_list -= 20) 10 (100.0%) t@0x2a0020 +0 (24->24) num_aliases=1 - source_path=third_party/container.c object_path=third_party/WebKit.a/ContiguousContainer.o - flags={} name=blink::ContiguousContainerBase::ContiguousContainerBase - full_name=blink::ContiguousContainerBase::ContiguousContainerBase(blink::ContiguousContainerBase&&) -= 21) 10 (100.0%) t@Group +0 (28->28) count=2 - source_path=third_party/paint.cc object_path=third_party/WebKit.a/PaintChunker.o - flags={} name=blink::ContiguousContainerBase::shrinkToFit - full_name=blink::ContiguousContainerBase::shrinkToFit() -= 22) 10 (100.0%) t@0x2a1000 +0 (94->94) num_aliases=1 - source_path=third_party/container.c object_path=third_party/WebKit.a/ContiguousContainer.o - flags={} name=blink::PaintChunker::releasePaintChunks - full_name=blink::PaintChunker::releasePaintChunks() -= 23) 10 (100.0%) R@0x2c17728 +0 (24->24) num_aliases=1 - source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o - flags={} name=chrome::mojom::FieldTrialRecorder [vtable] -= 24) 10 (100.0%) R@0x2c17740 +0 (789904->789904) num_aliases=1 - source_path=third_party/container.c object_path=third_party/WebKit.a/ContiguousContainer.o - flags={} name=chrome::mojom::FieldTrialRecorderProxy [vtable] -= 25) 10 (100.0%) r@0x284e398 +0 (32->32) num_aliases=1 - source_path=third_party/container.c object_path=third_party/WebKit.a/ContiguousContainer.o - flags={} name=chrome::mojom::FilePatcher::Name_ -= 26) 10 (100.0%) t@0x28d98a +0 (32->32) num_aliases=1 - source_path=base/page_allocator.cc object_path=base/base/page_allocator.o - flags={} name=extFromUUseMapping - full_name=extFromUUseMapping(aj, int) -= 27) 10 (100.0%) t@0x28f1e0 +0 (69120->69120) num_aliases=1 - source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o - flags={} name=foo_bar -= 28) 10 (100.0%) d@0x2de7000 +0 (4->4) num_aliases=1 - source_path=base/page_allocator.cc object_path=base/base/page_allocator.o - flags={} name=google::protobuf::internal::pLinuxKernelCmpxchg -= 29) 10 (100.0%) d@0x2de7004 +0 (4->4) num_aliases=1 - source_path=third_party/container.c object_path=third_party/WebKit.a/ContiguousContainer.o - flags={} name=google::protobuf::internal::pLinuxKernelMemoryBarrier -= 30) 10 (100.0%) r@0x28f3450 +0 (48->48) num_aliases=1 - source_path=third_party/paint.cc object_path=third_party/WebKit.a/PaintChunker.o - flags={} name=kAnimationFrameTimeHistogramClassPath -= 31) 10 (100.0%) R@0x2cd8550 +0 (12->12) num_aliases=1 - source_path=base/page_allocator.cc object_path=base/base/page_allocator.o - flags={} name=kMethodsAnimationFrameTimeHistogram -= 32) 10 (100.0%) R@0x2cd84f0 +0 (8->8) num_aliases=1 - source_path= object_path=third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libport_android_jni.a_jni_utils.o - flags={} name=kSystemClassPrefixes -= 33) 10 (100.0%) R@0x2cd8538 +0 (24->24) num_aliases=1 - source_path=base/page_allocator.cc object_path=base/base/page_allocator.o - flags={} name=mojo::MessageReceiver [vtable] -= 34) 10 (100.0%) t@0x28f000 +0 (448->448) num_aliases=1 - source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o - flags={} name=ucnv_extMatchFromU - full_name=ucnv_extMatchFromU(int const*, int, unsigned short const*, int, unsigned short const*, int, unsigned int*, signed char, signed char) -= 35) 10 (100.0%) b@0x2dffe80 +0 (4->4) num_aliases=1 - source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o - flags={} name=SaveHistogram::atomic_histogram_pointer - full_name=SaveHistogram(_JNIEnv*, base::android::JavaParamRef<_jobject*> const&, base::android::JavaParamRef<_jstring*> const&, base::android::JavaParamRef<_jlongArray*> const&, int)::atomic_histogram_pointer -= 36) 10 (100.0%) b@0x0 +0 (262144->262144) num_aliases=1 - source_path=third_party/fft_float.cc object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o - flags={} name=ff_cos_131072 -= 37) 10 (100.0%) b@0x0 +0 (131072->131072) num_aliases=1 - source_path=third_party/fft_fixed.cc object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_fixed.o - flags={} name=ff_cos_131072_fixed -= 38) 10 (100.0%) b@0x0 +0 (131072->131072) num_aliases=1 - source_path=third_party/fft_float.cc object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o - flags={} name=ff_cos_65536 -= 39) 10 (100.0%) b@0x2dffe84 +0 (4->4) num_aliases=1 - source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o - flags={} name=g_AnimationFrameTimeHistogram_clazz -= 40) 10 (100.0%) b@0x2dffda0 +0 (28->28) num_aliases=1 - source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o - flags={} name=g_chrome_content_browser_client
diff --git a/tools/binary_size/libsupersize/testdata/Diff_NullDiff.golden b/tools/binary_size/libsupersize/testdata/Diff_NullDiff.golden index e95b0c7..3f77d804 100644 --- a/tools/binary_size/libsupersize/testdata/Diff_NullDiff.golden +++ b/tools/binary_size/libsupersize/testdata/Diff_NullDiff.golden
@@ -14,18 +14,20 @@ .bss: 0 bytes (0 bytes) (not included in totals) .data: 0 bytes (0 bytes) (0.0%) .data.rel.ro: 0 bytes (0 bytes) (0.0%) + .other: 0 bytes (0 bytes) (0.0%) .rel.dyn: 0 bytes (0 bytes) (0.0%) .rodata: 0 bytes (0 bytes) (0.0%) .text: 0 bytes (0 bytes) (0.0%) -0 symbols added (+), 0 changed (~), 0 removed (-), 45 unchanged (not shown) -Number of unique symbols 46 -> 46 (+0) +0 symbols added (+), 0 changed (~), 0 removed (-), 50 unchanged (not shown) +Of changed symbols, 0 grew, 0 shrank +Number of unique symbols 48 -> 48 (+0) 0 paths added, 0 removed, 0 changed -Showing 0 symbols (aliases not grouped for diffs) with total pss: 0 bytes -.text=0 bytes .rodata=0 bytes .data.rel.ro=0 bytes .data=0 bytes .bss=0 bytes total=0 bytes +Showing 0 symbols (0 -> 0 unique) with total pss: 0 bytes +.text=0 bytes .rodata=0 bytes .data.rel.ro=0 bytes .data=0 bytes .bss=0 bytes .other=0 bytes total=0 bytes Number of unique paths: 0 -Section Legend: t=.text, r=.rodata, R=.data.rel.ro, d=.data, b=.bss +Section Legend: t=.text, r=.rodata, R=.data.rel.ro, d=.data, b=.bss, o=.other Index | Running Total | Section@Address | Δ PSS (Δ size_without_padding) | Path ------------------------------------------------------------
diff --git a/tools/binary_size/libsupersize/testdata/FullDescription.golden b/tools/binary_size/libsupersize/testdata/FullDescription.golden index dbfcade..83ccda7 100644 --- a/tools/binary_size/libsupersize/testdata/FullDescription.golden +++ b/tools/binary_size/libsupersize/testdata/FullDescription.golden
@@ -8,16 +8,17 @@ map_file_name=../test.map tool_prefix=tools/binary_size/libsupersize/testdata/mock_toolchain/ -Section Sizes (Total=95.6mb (100233874 bytes)): - .ARM.exidx: 1.47mb (1536456 bytes) (1.5%) +Section Sizes (Total=128.0mb (134218045 bytes)): + .ARM.exidx: 1.47mb (1536456 bytes) (1.1%) .bss: 1.24mb (1300456 bytes) (not included in totals) .data: 99.4kb (101768 bytes) (0.1%) - .data.rel.ro: 1.02mb (1065224 bytes) (1.1%) - .rel.dyn: 2.53mb (2655384 bytes) (2.6%) - .rodata: 5.65mb (5927652 bytes) (5.9%) - .strtab: 33.2mb (34841854 bytes) (34.8%) - .symtab: 16.4mb (17166112 bytes) (17.1%) - .text: 34.2mb (35900712 bytes) (35.8%) + .data.rel.ro: 1.02mb (1065224 bytes) (0.8%) + .other: 32.4mb (33984171 bytes) (25.3%) + .rel.dyn: 2.53mb (2655384 bytes) (2.0%) + .rodata: 5.65mb (5927652 bytes) (4.4%) + .strtab: 33.2mb (34841854 bytes) (26.0%) + .symtab: 16.4mb (17166112 bytes) (12.8%) + .text: 34.2mb (35900712 bytes) (26.7%) Other section sizes: .ARM.attributes: 60 bytes (60 bytes) @@ -40,217 +41,334 @@ .rel.plt: 2.75kb (2816 bytes) .shstrtab: 436 bytes (436 bytes) -Section .text: has 100.0% of 35900712 bytes accounted for from 18 symbols. 0 bytes are unaccounted for. +Section .text: has 100.0% of 35900712 bytes accounted for from 19 symbols. 0 bytes are unaccounted for. * Padding accounts for 48 bytes (0.0%) * 3 placeholders (symbols that start with **) account for 35830760 bytes (99.8%) -* Contains 5 aliases, mapped to 2 unique addresses (60 bytes) -* 1 symbols have shared ownership (12 bytes) -Section .rodata: has 100.0% of 5927652 bytes accounted for from 10 symbols. 0 bytes are unaccounted for. -* Padding accounts for 11 bytes (0.0%) -* 5 placeholders (symbols that start with **) account for 5927509 bytes (100.0%) +* Contains 6 aliases, mapped to 2 unique addresses (52 bytes saved) +* 0 symbols have shared ownership +Section .rodata: has 100.0% of 5927652 bytes accounted for from 12 symbols. 0 bytes are unaccounted for. +* Padding accounts for 675996 bytes (11.4%) +* 4 placeholders (symbols that start with **) account for 5251503 bytes (88.6%) +* Contains 3 string literals. Total size=21, padding=0 +* Contains 2 aliases, mapped to 1 unique addresses (5 bytes saved) * 0 symbols have shared ownership Section .data.rel.ro: has 100.0% of 1065224 bytes accounted for from 4 symbols. 0 bytes are unaccounted for. * Padding accounts for 0 bytes (0.0%) * 1 placeholders (symbols that start with **) account for 1065132 bytes (100.0%) +* Contains 0 aliases * 0 symbols have shared ownership Section .data: has 100.0% of 101768 bytes accounted for from 6 symbols. 0 bytes are unaccounted for. * Padding accounts for 0 bytes (0.0%) * 1 placeholders (symbols that start with **) account for 101600 bytes (99.8%) +* Contains 0 aliases * 0 symbols have shared ownership Section .bss: has 40.3% of 524520 bytes accounted for from 6 symbols. 775936 bytes are unaccounted for. * Padding accounts for 196 bytes (0.0%) +* Contains 0 aliases +* 0 symbols have shared ownership +Section .other: has 100.0% of 33984171 bytes accounted for from 1 symbols. 0 bytes are unaccounted for. +* Padding accounts for 0 bytes (0.0%) +* Contains 0 aliases * 0 symbols have shared ownership -Showing 49 symbols (46 unique) with total pss: 43785380 bytes -.text=34.2mb .rodata=5.65mb .data.rel.ro=1.02mb .data=99.4kb .bss=512kb total=41.8mb +Showing 53 symbols (48 unique) with total pss: 77769551 bytes +Histogram of symbols based on PSS: + [2,4): 7 [16,32): 10 [128,256): 2 [4096,8192): 1 [262144,524288): 1 [2097152,4194304): 1 + [4,8): 6 [32,64): 9 [256,512): 1 [65536,131072): 2 [524288,1048576): 2 [33554432,67108864): 2 + [8,16): 3 [64,128): 1 [2048,4096): 1 [131072,262144): 2 [1048576,2097152): 2 +.text=34.2mb .rodata=5.65mb .data.rel.ro=1.02mb .data=99.4kb .bss=512kb .other=32.4mb total=74.2mb Number of unique paths: 9 -Section Legend: t=.text, r=.rodata, R=.data.rel.ro, d=.data, b=.bss +Section Legend: t=.text, r=.rodata, R=.data.rel.ro, d=.data, b=.bss, o=.other Index | Running Total | Section@Address | ... ------------------------------------------------------------ -0) 16 (0.0%) t@0x28d900 pss=16 padding=0 num_aliases=1 +0) 4 (0.0%) d@0x2de7000 pss=4 padding=0 num_aliases=1 source_path=base/page_allocator.cc object_path=base/base/page_allocator.o - flags={startup} name=_GLOBAL__sub_I_page_allocator.cc -1) 72 (0.0%) t@0x28d910 pss=56 padding=0 num_aliases=1 - source_path=base/page_allocator.cc object_path=base/base/page_allocator.o - flags={startup} name=_GLOBAL__sub_I_bbr_sender.cc -2) 100 (0.0%) t@0x28d948 pss=28 padding=0 num_aliases=1 - source_path=base/page_allocator.cc object_path=base/base/page_allocator.o - flags={startup} name=_GLOBAL__sub_I_pacing_sender.cc -3) 138 (0.0%) t@0x28d964 pss=38 padding=0 num_aliases=1 - source_path=base/page_allocator.cc object_path=base/base/page_allocator.o - flags={} name=extFromUUseMapping - full_name=extFromUUseMapping(signed char, unsigned int, int) -4) 170 (0.0%) t@0x28d98a pss=32 padding=0 num_aliases=1 - source_path=base/page_allocator.cc object_path=base/base/page_allocator.o - flags={} name=extFromUUseMapping - full_name=extFromUUseMapping(aj, int) -5) 5888 (0.0%) t@0x28f000 pss=5718 padding=5718 num_aliases=1 - source_path= object_path= - flags={} name=** symbol gap 0 -6) 6336 (0.0%) t@0x28f000 pss=448 padding=0 num_aliases=1 - source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o - flags={gen} name=ucnv_extMatchFromU - full_name=ucnv_extMatchFromU(int const*, int, unsigned short const*, int, unsigned short const*, int, unsigned int*, signed char, signed char) -7) 6364 (0.0%) t@0x28f1c8 pss=28 padding=8 num_aliases=1 - source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o - flags={startup,gen} name=_GLOBAL__sub_I_SkDeviceProfile.cpp -8) 75488 (0.2%) t@0x28f1e0 pss=69124 padding=4 num_aliases=1 - source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o - flags={unlikely,gen} name=foo_bar -9) 75512 (0.2%) t@0x2a0000 pss=24 (size=48) padding=32 num_aliases=2 - source_path= object_path= - flags={} name=blink::ContiguousContainerBase::shrinkToFit - full_name=blink::ContiguousContainerBase::shrinkToFit() -10) 75536 (0.2%) t@0x2a0000 pss=24 (size=48) padding=32 num_aliases=2 - source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o - flags={gen} name=BazAlias - full_name=BazAlias(bool) -11) 75540 (0.2%) t@0x2a0010 pss=4 (size=12) padding=0 num_aliases=3 - source_path=third_party/{shared}/2 object_path=third_party/{shared}/2 - flags={clone} name=blink::ContiguousContainerBase::shrinkToFit - full_name=blink::ContiguousContainerBase::shrinkToFit() -12) 75544 (0.2%) t@0x2a0010 pss=4 (size=12) padding=0 num_aliases=3 - source_path=third_party/fft_float.cc object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o - flags={} name=FooAlias - full_name=FooAlias() -13) 75548 (0.2%) t@0x2a0010 pss=4 (size=12) padding=0 num_aliases=3 - source_path=third_party/fft_float.cc object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o - flags={} name=BarAlias - full_name=BarAlias() -14) 75576 (0.2%) t@0x2a0020 pss=28 padding=4 num_aliases=1 + flags={} name=google::protobuf::internal::pLinuxKernelCmpxchg +1) 8 (0.0%) d@0x2de7004 pss=4 padding=0 num_aliases=1 source_path=third_party/container.c object_path=third_party/WebKit.a/ContiguousContainer.o - flags={} name=blink::ContiguousContainerBase::ContiguousContainerBase - full_name=blink::ContiguousContainerBase::ContiguousContainerBase(blink::ContiguousContainerBase&&) -15) 79616 (0.2%) t@0x2a1000 pss=4040 padding=4040 num_aliases=1 - source_path= object_path= - flags={} name=** symbol gap 1 -16) 79710 (0.2%) t@0x2a1000 pss=94 padding=0 num_aliases=1 + flags={} name=google::protobuf::internal::pLinuxKernelMemoryBarrier +2) 160 (0.0%) d@0x2de7008 pss=152 padding=0 num_aliases=1 source_path=third_party/container.c object_path=third_party/WebKit.a/ContiguousContainer.o - flags={anon,clone} name=blink::PaintChunker::releasePaintChunks - full_name=blink::PaintChunker::releasePaintChunks() -17) 35900712 (82.0%) t@0x24ca628 pss=35821002 padding=35821002 num_aliases=1 + flags={rel} name=base::android::kBaseRegisteredMethods +3) 164 (0.0%) d@0x2de70a0 pss=4 padding=0 num_aliases=1 + source_path=third_party/container.c object_path=third_party/WebKit.a/ContiguousContainer.o + flags={anon} name=base::android::g_renderer_histogram_code +4) 168 (0.0%) d@0x2de70a4 pss=4 padding=0 num_aliases=1 + source_path=third_party/container.c object_path=third_party/WebKit.a/ContiguousContainer.o + flags={anon,rel.loc} name=base::android::g_library_version_number +5) 101768 (0.1%) d@0x2dffd88 pss=101600 padding=101600 num_aliases=1 source_path= object_path= - flags={} name=** symbol gap 2 (end of section) -18) 37862696 (86.5%) r@0x266e600 pss=1961984 padding=0 num_aliases=1 + flags={} name=** symbol gap 0 (end of section) +6) 101824 (0.1%) R@0x2cd8500 pss=56 padding=0 num_aliases=1 + source_path=third_party/paint.cc object_path=third_party/WebKit.a/PaintChunker.o + flags={} name=ChromeMainDelegateAndroid [vtable] +7) 101848 (0.1%) R@0x2cd8538 pss=24 padding=0 num_aliases=1 + source_path=base/page_allocator.cc object_path=base/base/page_allocator.o + flags={} name=mojo::MessageReceiver [vtable] +8) 101860 (0.1%) R@0x2cd8550 pss=12 padding=0 num_aliases=1 + source_path=base/page_allocator.cc object_path=base/base/page_allocator.o + flags={} name=kMethodsAnimationFrameTimeHistogram +9) 1166992 (1.5%) R@0x2ddc608 pss=1065132 padding=1065132 num_aliases=1 + source_path= object_path= + flags={} name=** symbol gap 0 (end of section) +10) 1167048 (1.5%) R@0x2c176f0 pss=56 padding=0 num_aliases=1 + source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o + flags={gen} name=ChromeMainDelegate [vtable] +11) 1167072 (1.5%) R@0x2c17728 pss=24 padding=0 num_aliases=1 + source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o + flags={gen} name=chrome::mojom::FieldTrialRecorder [vtable] +12) 1956976 (2.5%) R@0x2c17740 pss=789904 padding=0 num_aliases=1 + source_path=third_party/container.c object_path=third_party/WebKit.a/ContiguousContainer.o + flags={} name=chrome::mojom::FieldTrialRecorderProxy [vtable] +13) 1957008 (2.5%) R@0x2cd84e0 pss=32 padding=16 num_aliases=1 + source_path= object_path=third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libcontroller_api_impl.a_controller_api_impl.o + flags={} name=.Lswitch.table.45 +14) 1957016 (2.5%) R@0x2cd84f0 pss=8 padding=0 num_aliases=1 + source_path= object_path=third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libport_android_jni.a_jni_utils.o + flags={anon} name=kSystemClassPrefixes +15) 35941187 (46.2%) o@0x0 pss=33984171 padding=0 num_aliases=1 + source_path= object_path= + flags={} name=ELF file overhead +16) 35941189 (46.2%) r@0x266e600 pss=2.5 (size=5) padding=0 num_aliases=2 + source_path=base/page_allocator.cc object_path=base/base/page_allocator.o + flags={} name=string literal +17) 35941192 (46.2%) r@0x266e600 pss=2.5 (size=5) padding=0 num_aliases=2 + source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o + flags={gen} name=string literal +18) 35941208 (46.2%) r@0x266e605 pss=16 padding=0 num_aliases=1 + source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o + flags={gen} name=string literal +19) 35941251 (46.2%) r@0x266e630 pss=43 padding=27 num_aliases=1 source_path= object_path= flags={} name=** merge strings -19) 37866121 (86.5%) r@0x284d600 pss=3425 padding=0 num_aliases=1 +20) 37906596 (48.7%) r@0x284d600 pss=1965345 padding=1961920 num_aliases=1 source_path= object_path= flags={} name=** merge constants -20) 37866124 (86.5%) r@0x284e364 pss=3 padding=3 num_aliases=1 +21) 37906599 (48.7%) r@0x284e364 pss=3 padding=3 num_aliases=1 source_path= object_path= flags={} name=** symbol gap 0 -21) 37866132 (86.5%) r@0x284e364 pss=8 padding=0 num_aliases=1 +22) 37906607 (48.7%) r@0x284e364 pss=8 padding=0 num_aliases=1 source_path=base/page_allocator.cc object_path=base/base/page_allocator.o -22) 37866176 (86.5%) r@0x284e370 pss=44 padding=4 num_aliases=1 +23) 37906651 (48.7%) r@0x284e370 pss=44 padding=4 num_aliases=1 source_path=base/page_allocator.cc object_path=base/base/page_allocator.o flags={} name=Name -23) 37866208 (86.5%) r@0x284e398 pss=32 padding=0 num_aliases=1 +24) 37906683 (48.7%) r@0x284e398 pss=32 padding=0 num_aliases=1 source_path=third_party/container.c object_path=third_party/WebKit.a/ContiguousContainer.o flags={} name=chrome::mojom::FilePatcher::Name_ -24) 38542193 (88.0%) r@0x284e518 pss=675985 padding=352 num_aliases=1 - source_path= object_path= - flags={} name=** merge strings -25) 38542248 (88.0%) r@0x28f3450 pss=55 padding=7 num_aliases=1 +25) 38582723 (49.6%) r@0x28f3450 pss=676040 padding=675992 num_aliases=1 source_path=third_party/paint.cc object_path=third_party/WebKit.a/PaintChunker.o flags={anon} name=kAnimationFrameTimeHistogramClassPath -26) 38542252 (88.0%) r@0x28f3480 pss=4 padding=0 num_aliases=1 +26) 38582727 (49.6%) r@0x28f3480 pss=4 padding=0 num_aliases=1 source_path=third_party/paint.cc object_path=third_party/WebKit.a/PaintChunker.o flags={anon} name=blink::CSSValueKeywordsHash::findValueImpl::value_word_list full_name=blink::CSSValueKeywordsHash::findValueImpl(char const*, unsigned int)::value_word_list -27) 41828364 (95.5%) r@0x2c158e4 pss=3286112 padding=3286112 num_aliases=1 +27) 41868839 (53.8%) r@0x2c158e4 pss=3286112 padding=3286112 num_aliases=1 source_path= object_path= flags={} name=** symbol gap 1 (end of section) -28) 41828420 (95.5%) R@0x2c176f0 pss=56 padding=0 num_aliases=1 - source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o - flags={gen} name=ChromeMainDelegate [vtable] -29) 41828444 (95.5%) R@0x2c17728 pss=24 padding=0 num_aliases=1 - source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o - flags={gen} name=chrome::mojom::FieldTrialRecorder [vtable] -30) 42618348 (97.3%) R@0x2c17740 pss=789904 padding=0 num_aliases=1 - source_path=third_party/container.c object_path=third_party/WebKit.a/ContiguousContainer.o - flags={} name=chrome::mojom::FieldTrialRecorderProxy [vtable] -31) 42618380 (97.3%) R@0x2cd84e0 pss=32 padding=16 num_aliases=1 - source_path= object_path=third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libcontroller_api_impl.a_controller_api_impl.o - flags={} name=.Lswitch.table.45 -32) 42618388 (97.3%) R@0x2cd84f0 pss=8 padding=0 num_aliases=1 - source_path= object_path=third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libport_android_jni.a_jni_utils.o - flags={anon} name=kSystemClassPrefixes -33) 42618444 (97.3%) R@0x2cd8500 pss=56 padding=0 num_aliases=1 - source_path=third_party/paint.cc object_path=third_party/WebKit.a/PaintChunker.o - flags={} name=ChromeMainDelegateAndroid [vtable] -34) 42618468 (97.3%) R@0x2cd8538 pss=24 padding=0 num_aliases=1 - source_path=base/page_allocator.cc object_path=base/base/page_allocator.o - flags={} name=mojo::MessageReceiver [vtable] -35) 42618480 (97.3%) R@0x2cd8550 pss=12 padding=0 num_aliases=1 - source_path=base/page_allocator.cc object_path=base/base/page_allocator.o - flags={} name=kMethodsAnimationFrameTimeHistogram -36) 43683612 (99.8%) R@0x2ddc608 pss=1065132 padding=1065132 num_aliases=1 - source_path= object_path= - flags={} name=** symbol gap 0 (end of section) -37) 43683616 (99.8%) d@0x2de7000 pss=4 padding=0 num_aliases=1 - source_path=base/page_allocator.cc object_path=base/base/page_allocator.o - flags={} name=google::protobuf::internal::pLinuxKernelCmpxchg -38) 43683620 (99.8%) d@0x2de7004 pss=4 padding=0 num_aliases=1 - source_path=third_party/container.c object_path=third_party/WebKit.a/ContiguousContainer.o - flags={} name=google::protobuf::internal::pLinuxKernelMemoryBarrier -39) 43683772 (99.8%) d@0x2de7008 pss=152 padding=0 num_aliases=1 - source_path=third_party/container.c object_path=third_party/WebKit.a/ContiguousContainer.o - flags={rel} name=base::android::kBaseRegisteredMethods -40) 43683776 (99.8%) d@0x2de70a0 pss=4 padding=0 num_aliases=1 - source_path=third_party/container.c object_path=third_party/WebKit.a/ContiguousContainer.o - flags={anon} name=base::android::g_renderer_histogram_code -41) 43683780 (99.8%) d@0x2de70a4 pss=4 padding=0 num_aliases=1 - source_path=third_party/container.c object_path=third_party/WebKit.a/ContiguousContainer.o - flags={anon,rel.loc} name=base::android::g_library_version_number -42) 43785380 (100.0%) d@0x2dffd88 pss=101600 padding=101600 num_aliases=1 - source_path= object_path= - flags={} name=** symbol gap 0 (end of section) -43) 43785380 (100.0%) b@0x0 pss=262144 padding=0 num_aliases=1 - source_path=third_party/fft_float.cc object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o - flags={} name=ff_cos_131072 -44) 43785380 (100.0%) b@0x0 pss=131072 padding=0 num_aliases=1 - source_path=third_party/fft_fixed.cc object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_fixed.o - flags={} name=ff_cos_131072_fixed -45) 43785380 (100.0%) b@0x0 pss=131072 padding=0 num_aliases=1 - source_path=third_party/fft_float.cc object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o - flags={} name=ff_cos_65536 -46) 43785380 (100.0%) b@0x2dffda0 pss=28 padding=0 num_aliases=1 - source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o - flags={gen} name=g_chrome_content_browser_client -47) 43785380 (100.0%) b@0x2dffe80 pss=200 padding=196 num_aliases=1 - source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o - flags={gen} name=SaveHistogram::atomic_histogram_pointer - full_name=SaveHistogram(_JNIEnv*, base::android::JavaParamRef<_jobject*> const&, base::android::JavaParamRef<_jstring*> const&, base::android::JavaParamRef<_jlongArray*> const&, int)::atomic_histogram_pointer -48) 43785380 (100.0%) b@0x2dffe84 pss=4 padding=0 num_aliases=1 - source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o - flags={anon,gen} name=g_AnimationFrameTimeHistogram_clazz -Showing 45 symbols (42 unique) with total pss: 43785380 bytes -.text=34.2mb .rodata=5.65mb .data.rel.ro=1.02mb .data=99.4kb .bss=512kb total=41.8mb -Number of unique paths: 9 - -Section Legend: t=.text, r=.rodata, R=.data.rel.ro, d=.data, b=.bss -Index | Running Total | Section@Address | ... ------------------------------------------------------------- -0) 16 (0.0%) t@0x28d900 pss=16 padding=0 num_aliases=1 +28) 41868855 (53.8%) t@0x28d900 pss=16 padding=0 num_aliases=1 source_path=base/page_allocator.cc object_path=base/base/page_allocator.o flags={startup} name=_GLOBAL__sub_I_page_allocator.cc -1) 72 (0.0%) t@0x28d910 pss=56 padding=0 num_aliases=1 +29) 41868911 (53.8%) t@0x28d910 pss=56 padding=0 num_aliases=1 source_path=base/page_allocator.cc object_path=base/base/page_allocator.o flags={startup} name=_GLOBAL__sub_I_bbr_sender.cc -2) 100 (0.0%) t@0x28d948 pss=28 padding=0 num_aliases=1 +30) 41868939 (53.8%) t@0x28d948 pss=28 padding=0 num_aliases=1 source_path=base/page_allocator.cc object_path=base/base/page_allocator.o flags={startup} name=_GLOBAL__sub_I_pacing_sender.cc -3) 138 (0.0%) t@0x28d964 pss=38 padding=0 num_aliases=1 +31) 41868977 (53.8%) t@0x28d964 pss=38 padding=0 num_aliases=1 source_path=base/page_allocator.cc object_path=base/base/page_allocator.o flags={} name=extFromUUseMapping full_name=extFromUUseMapping(signed char, unsigned int, int) -4) 170 (0.0%) t@0x28d98a pss=32 padding=0 num_aliases=1 +32) 41869009 (53.8%) t@0x28d98a pss=32 padding=0 num_aliases=1 source_path=base/page_allocator.cc object_path=base/base/page_allocator.o flags={} name=extFromUUseMapping full_name=extFromUUseMapping(aj, int) -5) 35830930 (81.8%) t@Group pss=35830760 padding=35830760 count=3 +33) 41874727 (53.8%) t@0x28f000 pss=5718 padding=5718 num_aliases=1 + source_path= object_path= + flags={} name=** symbol gap 0 +34) 41875175 (53.8%) t@0x28f000 pss=448 padding=0 num_aliases=1 + source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o + flags={gen} name=ucnv_extMatchFromU + full_name=ucnv_extMatchFromU(int const*, int, unsigned short const*, int, unsigned short const*, int, unsigned int*, signed char, signed char) +35) 41875203 (53.8%) t@0x28f1c8 pss=28 padding=8 num_aliases=1 + source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o + flags={startup,gen} name=_GLOBAL__sub_I_SkDeviceProfile.cpp +36) 41944327 (53.9%) t@0x28f1e0 pss=69124 padding=4 num_aliases=1 + source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o + flags={unlikely,gen} name=foo_bar +37) 41944351 (53.9%) t@0x2a0000 pss=24 (size=48) padding=32 num_aliases=2 + source_path= object_path= + flags={} name=blink::ContiguousContainerBase::shrinkToFit + full_name=blink::ContiguousContainerBase::shrinkToFit() +38) 41944375 (53.9%) t@0x2a0000 pss=24 (size=48) padding=32 num_aliases=2 + source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o + flags={gen} name=BazAlias + full_name=BazAlias(bool) +39) 41944378 (53.9%) t@0x2a0010 pss=3 (size=12) padding=0 num_aliases=4 + source_path=third_party/paint.cc object_path=third_party/WebKit.a/PaintChunker.o + flags={clone} name=blink::ContiguousContainerBase::shrinkToFit + full_name=blink::ContiguousContainerBase::shrinkToFit() +40) 41944381 (53.9%) t@0x2a0010 pss=3 (size=12) padding=0 num_aliases=4 + source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o + flags={gen,clone} name=blink::ContiguousContainerBase::shrinkToFit + full_name=blink::ContiguousContainerBase::shrinkToFit() +41) 41944384 (53.9%) t@0x2a0010 pss=3 (size=12) padding=0 num_aliases=4 + source_path=third_party/fft_float.cc object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o + flags={} name=FooAlias + full_name=FooAlias() +42) 41944387 (53.9%) t@0x2a0010 pss=3 (size=12) padding=0 num_aliases=4 + source_path=third_party/fft_float.cc object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o + flags={} name=BarAlias + full_name=BarAlias() +43) 41944415 (53.9%) t@0x2a0020 pss=28 padding=4 num_aliases=1 + source_path=third_party/container.c object_path=third_party/WebKit.a/ContiguousContainer.o + flags={} name=blink::ContiguousContainerBase::ContiguousContainerBase + full_name=blink::ContiguousContainerBase::ContiguousContainerBase(blink::ContiguousContainerBase&&) +44) 41948455 (53.9%) t@0x2a1000 pss=4040 padding=4040 num_aliases=1 + source_path= object_path= + flags={} name=** symbol gap 1 +45) 41948549 (53.9%) t@0x2a1000 pss=94 padding=0 num_aliases=1 + source_path=third_party/container.c object_path=third_party/WebKit.a/ContiguousContainer.o + flags={anon,clone} name=blink::PaintChunker::releasePaintChunks + full_name=blink::PaintChunker::releasePaintChunks() +46) 77769551 (100.0%) t@0x24ca628 pss=35821002 padding=35821002 num_aliases=1 + source_path= object_path= + flags={} name=** symbol gap 2 (end of section) +47) 77769551 (100.0%) b@0x0 pss=262144 padding=0 num_aliases=1 + source_path=third_party/fft_float.cc object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o + flags={} name=ff_cos_131072 +48) 77769551 (100.0%) b@0x0 pss=131072 padding=0 num_aliases=1 + source_path=third_party/fft_fixed.cc object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_fixed.o + flags={} name=ff_cos_131072_fixed +49) 77769551 (100.0%) b@0x0 pss=131072 padding=0 num_aliases=1 + source_path=third_party/fft_float.cc object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o + flags={} name=ff_cos_65536 +50) 77769551 (100.0%) b@0x2dffda0 pss=28 padding=0 num_aliases=1 + source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o + flags={gen} name=g_chrome_content_browser_client +51) 77769551 (100.0%) b@0x2dffe80 pss=200 padding=196 num_aliases=1 + source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o + flags={gen} name=SaveHistogram::atomic_histogram_pointer + full_name=SaveHistogram(_JNIEnv*, base::android::JavaParamRef<_jobject*> const&, base::android::JavaParamRef<_jstring*> const&, base::android::JavaParamRef<_jlongArray*> const&, int)::atomic_histogram_pointer +52) 77769551 (100.0%) b@0x2dffe84 pss=4 padding=0 num_aliases=1 + source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o + flags={anon,gen} name=g_AnimationFrameTimeHistogram_clazz +Showing 50 symbols (45 unique) with total pss: 77769551 bytes +Histogram of symbols based on PSS: + [2,4): 6 [16,32): 10 [128,256): 2 [131072,262144): 2 [1048576,2097152): 2 + [4,8): 6 [32,64): 9 [256,512): 1 [262144,524288): 1 [2097152,4194304): 1 + [8,16): 3 [64,128): 1 [65536,131072): 2 [524288,1048576): 2 [33554432,67108864): 2 +.text=34.2mb .rodata=5.65mb .data.rel.ro=1.02mb .data=99.4kb .bss=512kb .other=32.4mb total=74.2mb +Number of unique paths: 9 + +Section Legend: t=.text, r=.rodata, R=.data.rel.ro, d=.data, b=.bss, o=.other +Index | Running Total | Section@Address | ... +------------------------------------------------------------ +0) 4 (0.0%) d@0x2de7000 pss=4 padding=0 num_aliases=1 + source_path=base/page_allocator.cc object_path=base/base/page_allocator.o + flags={} name=google::protobuf::internal::pLinuxKernelCmpxchg +1) 8 (0.0%) d@0x2de7004 pss=4 padding=0 num_aliases=1 + source_path=third_party/container.c object_path=third_party/WebKit.a/ContiguousContainer.o + flags={} name=google::protobuf::internal::pLinuxKernelMemoryBarrier +2) 160 (0.0%) d@0x2de7008 pss=152 padding=0 num_aliases=1 + source_path=third_party/container.c object_path=third_party/WebKit.a/ContiguousContainer.o + flags={rel} name=base::android::kBaseRegisteredMethods +3) 164 (0.0%) d@0x2de70a0 pss=4 padding=0 num_aliases=1 + source_path=third_party/container.c object_path=third_party/WebKit.a/ContiguousContainer.o + flags={anon} name=base::android::g_renderer_histogram_code +4) 168 (0.0%) d@0x2de70a4 pss=4 padding=0 num_aliases=1 + source_path=third_party/container.c object_path=third_party/WebKit.a/ContiguousContainer.o + flags={anon,rel.loc} name=base::android::g_library_version_number +5) 101768 (0.1%) d@0x2dffd88 pss=101600 padding=101600 num_aliases=1 + source_path= object_path= + flags={} name=** symbol gap 0 (end of section) +6) 101824 (0.1%) R@0x2cd8500 pss=56 padding=0 num_aliases=1 + source_path=third_party/paint.cc object_path=third_party/WebKit.a/PaintChunker.o + flags={} name=ChromeMainDelegateAndroid [vtable] +7) 101848 (0.1%) R@0x2cd8538 pss=24 padding=0 num_aliases=1 + source_path=base/page_allocator.cc object_path=base/base/page_allocator.o + flags={} name=mojo::MessageReceiver [vtable] +8) 101860 (0.1%) R@0x2cd8550 pss=12 padding=0 num_aliases=1 + source_path=base/page_allocator.cc object_path=base/base/page_allocator.o + flags={} name=kMethodsAnimationFrameTimeHistogram +9) 1166992 (1.5%) R@0x2ddc608 pss=1065132 padding=1065132 num_aliases=1 + source_path= object_path= + flags={} name=** symbol gap 0 (end of section) +10) 1167048 (1.5%) R@0x2c176f0 pss=56 padding=0 num_aliases=1 + source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o + flags={gen} name=ChromeMainDelegate [vtable] +11) 1167072 (1.5%) R@0x2c17728 pss=24 padding=0 num_aliases=1 + source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o + flags={gen} name=chrome::mojom::FieldTrialRecorder [vtable] +12) 1956976 (2.5%) R@0x2c17740 pss=789904 padding=0 num_aliases=1 + source_path=third_party/container.c object_path=third_party/WebKit.a/ContiguousContainer.o + flags={} name=chrome::mojom::FieldTrialRecorderProxy [vtable] +13) 1957008 (2.5%) R@0x2cd84e0 pss=32 padding=16 num_aliases=1 + source_path= object_path=third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libcontroller_api_impl.a_controller_api_impl.o + flags={} name=.Lswitch.table.45 +14) 1957016 (2.5%) R@0x2cd84f0 pss=8 padding=0 num_aliases=1 + source_path= object_path=third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libport_android_jni.a_jni_utils.o + flags={anon} name=kSystemClassPrefixes +15) 35941187 (46.2%) o@0x0 pss=33984171 padding=0 num_aliases=1 + source_path= object_path= + flags={} name=ELF file overhead +16) 35941189 (46.2%) r@0x266e600 pss=2.5 (size=5) padding=0 num_aliases=2 + source_path=base/page_allocator.cc object_path=base/base/page_allocator.o + flags={} name=string literal +17) 35941192 (46.2%) r@0x266e600 pss=2.5 (size=5) padding=0 num_aliases=2 + source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o + flags={gen} name=string literal +18) 35941208 (46.2%) r@0x266e605 pss=16 padding=0 num_aliases=1 + source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o + flags={gen} name=string literal +19) 35941251 (46.2%) r@0x266e630 pss=43 padding=27 num_aliases=1 + source_path= object_path= + flags={} name=** merge strings +20) 37906596 (48.7%) r@0x284d600 pss=1965345 padding=1961920 num_aliases=1 + source_path= object_path= + flags={} name=** merge constants +21) 41192711 (53.0%) r@Group pss=3286115 padding=3286115 count=2 + source_path= object_path= + flags={} name=** symbol gaps +> 0) 3 (0.0%) r@0x284e364 pss=3 padding=3 num_aliases=1 + source_path= object_path= + flags={} name=** symbol gap 0 +> 1) 3286115 (100.0%) r@0x2c158e4 pss=3286112 padding=3286112 num_aliases=1 + source_path= object_path= + flags={} name=** symbol gap 1 (end of section) +22) 41192719 (53.0%) r@0x284e364 pss=8 padding=0 num_aliases=1 + source_path=base/page_allocator.cc object_path=base/base/page_allocator.o +23) 41192763 (53.0%) r@0x284e370 pss=44 padding=4 num_aliases=1 + source_path=base/page_allocator.cc object_path=base/base/page_allocator.o + flags={} name=Name +24) 41192795 (53.0%) r@0x284e398 pss=32 padding=0 num_aliases=1 + source_path=third_party/container.c object_path=third_party/WebKit.a/ContiguousContainer.o + flags={} name=chrome::mojom::FilePatcher::Name_ +25) 41868835 (53.8%) r@0x28f3450 pss=676040 padding=675992 num_aliases=1 + source_path=third_party/paint.cc object_path=third_party/WebKit.a/PaintChunker.o + flags={anon} name=kAnimationFrameTimeHistogramClassPath +26) 41868839 (53.8%) r@0x28f3480 pss=4 padding=0 num_aliases=1 + source_path=third_party/paint.cc object_path=third_party/WebKit.a/PaintChunker.o + flags={anon} name=blink::CSSValueKeywordsHash::findValueImpl::value_word_list + full_name=blink::CSSValueKeywordsHash::findValueImpl(char const*, unsigned int)::value_word_list +27) 41868855 (53.8%) t@0x28d900 pss=16 padding=0 num_aliases=1 + source_path=base/page_allocator.cc object_path=base/base/page_allocator.o + flags={startup} name=_GLOBAL__sub_I_page_allocator.cc +28) 41868911 (53.8%) t@0x28d910 pss=56 padding=0 num_aliases=1 + source_path=base/page_allocator.cc object_path=base/base/page_allocator.o + flags={startup} name=_GLOBAL__sub_I_bbr_sender.cc +29) 41868939 (53.8%) t@0x28d948 pss=28 padding=0 num_aliases=1 + source_path=base/page_allocator.cc object_path=base/base/page_allocator.o + flags={startup} name=_GLOBAL__sub_I_pacing_sender.cc +30) 41868977 (53.8%) t@0x28d964 pss=38 padding=0 num_aliases=1 + source_path=base/page_allocator.cc object_path=base/base/page_allocator.o + flags={} name=extFromUUseMapping + full_name=extFromUUseMapping(signed char, unsigned int, int) +31) 41869009 (53.8%) t@0x28d98a pss=32 padding=0 num_aliases=1 + source_path=base/page_allocator.cc object_path=base/base/page_allocator.o + flags={} name=extFromUUseMapping + full_name=extFromUUseMapping(aj, int) +32) 77699769 (99.9%) t@Group pss=35830760 padding=35830760 count=3 source_path= object_path= flags={} name=** symbol gaps > 0) 5718 (0.0%) t@0x28f000 pss=5718 padding=5718 num_aliases=1 @@ -262,141 +380,64 @@ > 2) 35830760 (100.0%) t@0x24ca628 pss=35821002 padding=35821002 num_aliases=1 source_path= object_path= flags={} name=** symbol gap 2 (end of section) -6) 35831378 (81.8%) t@0x28f000 pss=448 padding=0 num_aliases=1 +33) 77700217 (99.9%) t@0x28f000 pss=448 padding=0 num_aliases=1 source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o flags={gen} name=ucnv_extMatchFromU full_name=ucnv_extMatchFromU(int const*, int, unsigned short const*, int, unsigned short const*, int, unsigned int*, signed char, signed char) -7) 35831406 (81.8%) t@0x28f1c8 pss=28 padding=8 num_aliases=1 +34) 77700245 (99.9%) t@0x28f1c8 pss=28 padding=8 num_aliases=1 source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o flags={startup,gen} name=_GLOBAL__sub_I_SkDeviceProfile.cpp -8) 35900530 (82.0%) t@0x28f1e0 pss=69124 padding=4 num_aliases=1 +35) 77769369 (100.0%) t@0x28f1e0 pss=69124 padding=4 num_aliases=1 source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o flags={unlikely,gen} name=foo_bar -9) 35900554 (82.0%) t@0x2a0000 pss=24 (size=48) padding=32 num_aliases=2 +36) 77769393 (100.0%) t@0x2a0000 pss=24 (size=48) padding=32 num_aliases=2 source_path= object_path= flags={} name=blink::ContiguousContainerBase::shrinkToFit full_name=blink::ContiguousContainerBase::shrinkToFit() -10) 35900578 (82.0%) t@0x2a0000 pss=24 (size=48) padding=32 num_aliases=2 +37) 77769417 (100.0%) t@0x2a0000 pss=24 (size=48) padding=32 num_aliases=2 source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o flags={gen} name=BazAlias full_name=BazAlias(bool) -11) 35900582 (82.0%) t@0x2a0010 pss=4 (size=12) padding=0 num_aliases=3 - source_path=third_party/{shared}/2 object_path=third_party/{shared}/2 +38) 77769420 (100.0%) t@0x2a0010 pss=3 (size=12) padding=0 num_aliases=4 + source_path=third_party/paint.cc object_path=third_party/WebKit.a/PaintChunker.o flags={clone} name=blink::ContiguousContainerBase::shrinkToFit full_name=blink::ContiguousContainerBase::shrinkToFit() -12) 35900586 (82.0%) t@0x2a0010 pss=4 (size=12) padding=0 num_aliases=3 +39) 77769423 (100.0%) t@0x2a0010 pss=3 (size=12) padding=0 num_aliases=4 + source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o + flags={gen,clone} name=blink::ContiguousContainerBase::shrinkToFit + full_name=blink::ContiguousContainerBase::shrinkToFit() +40) 77769426 (100.0%) t@0x2a0010 pss=3 (size=12) padding=0 num_aliases=4 source_path=third_party/fft_float.cc object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o flags={} name=FooAlias full_name=FooAlias() -13) 35900590 (82.0%) t@0x2a0010 pss=4 (size=12) padding=0 num_aliases=3 +41) 77769429 (100.0%) t@0x2a0010 pss=3 (size=12) padding=0 num_aliases=4 source_path=third_party/fft_float.cc object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o flags={} name=BarAlias full_name=BarAlias() -14) 35900618 (82.0%) t@0x2a0020 pss=28 padding=4 num_aliases=1 +42) 77769457 (100.0%) t@0x2a0020 pss=28 padding=4 num_aliases=1 source_path=third_party/container.c object_path=third_party/WebKit.a/ContiguousContainer.o flags={} name=blink::ContiguousContainerBase::ContiguousContainerBase full_name=blink::ContiguousContainerBase::ContiguousContainerBase(blink::ContiguousContainerBase&&) -15) 35900712 (82.0%) t@0x2a1000 pss=94 padding=0 num_aliases=1 +43) 77769551 (100.0%) t@0x2a1000 pss=94 padding=0 num_aliases=1 source_path=third_party/container.c object_path=third_party/WebKit.a/ContiguousContainer.o flags={anon,clone} name=blink::PaintChunker::releasePaintChunks full_name=blink::PaintChunker::releasePaintChunks() -16) 38538681 (88.0%) r@Group pss=2637969 padding=352 count=2 - source_path= object_path= - flags={} name=** merge strings -> 0) 1961984 (74.4%) r@0x266e600 pss=1961984 padding=0 num_aliases=1 - source_path= object_path= - flags={} name=** merge strings -> 1) 2637969 (100.0%) r@0x284e518 pss=675985 padding=352 num_aliases=1 - source_path= object_path= - flags={} name=** merge strings -17) 38542106 (88.0%) r@0x284d600 pss=3425 padding=0 num_aliases=1 - source_path= object_path= - flags={} name=** merge constants -18) 41828221 (95.5%) r@Group pss=3286115 padding=3286115 count=2 - source_path= object_path= - flags={} name=** symbol gaps -> 0) 3 (0.0%) r@0x284e364 pss=3 padding=3 num_aliases=1 - source_path= object_path= - flags={} name=** symbol gap 0 -> 1) 3286115 (100.0%) r@0x2c158e4 pss=3286112 padding=3286112 num_aliases=1 - source_path= object_path= - flags={} name=** symbol gap 1 (end of section) -19) 41828229 (95.5%) r@0x284e364 pss=8 padding=0 num_aliases=1 - source_path=base/page_allocator.cc object_path=base/base/page_allocator.o -20) 41828273 (95.5%) r@0x284e370 pss=44 padding=4 num_aliases=1 - source_path=base/page_allocator.cc object_path=base/base/page_allocator.o - flags={} name=Name -21) 41828305 (95.5%) r@0x284e398 pss=32 padding=0 num_aliases=1 - source_path=third_party/container.c object_path=third_party/WebKit.a/ContiguousContainer.o - flags={} name=chrome::mojom::FilePatcher::Name_ -22) 41828360 (95.5%) r@0x28f3450 pss=55 padding=7 num_aliases=1 - source_path=third_party/paint.cc object_path=third_party/WebKit.a/PaintChunker.o - flags={anon} name=kAnimationFrameTimeHistogramClassPath -23) 41828364 (95.5%) r@0x28f3480 pss=4 padding=0 num_aliases=1 - source_path=third_party/paint.cc object_path=third_party/WebKit.a/PaintChunker.o - flags={anon} name=blink::CSSValueKeywordsHash::findValueImpl::value_word_list - full_name=blink::CSSValueKeywordsHash::findValueImpl(char const*, unsigned int)::value_word_list -24) 41828420 (95.5%) R@0x2c176f0 pss=56 padding=0 num_aliases=1 - source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o - flags={gen} name=ChromeMainDelegate [vtable] -25) 41828444 (95.5%) R@0x2c17728 pss=24 padding=0 num_aliases=1 - source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o - flags={gen} name=chrome::mojom::FieldTrialRecorder [vtable] -26) 42618348 (97.3%) R@0x2c17740 pss=789904 padding=0 num_aliases=1 - source_path=third_party/container.c object_path=third_party/WebKit.a/ContiguousContainer.o - flags={} name=chrome::mojom::FieldTrialRecorderProxy [vtable] -27) 42618380 (97.3%) R@0x2cd84e0 pss=32 padding=16 num_aliases=1 - source_path= object_path=third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libcontroller_api_impl.a_controller_api_impl.o - flags={} name=.Lswitch.table.45 -28) 42618388 (97.3%) R@0x2cd84f0 pss=8 padding=0 num_aliases=1 - source_path= object_path=third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libport_android_jni.a_jni_utils.o - flags={anon} name=kSystemClassPrefixes -29) 42618444 (97.3%) R@0x2cd8500 pss=56 padding=0 num_aliases=1 - source_path=third_party/paint.cc object_path=third_party/WebKit.a/PaintChunker.o - flags={} name=ChromeMainDelegateAndroid [vtable] -30) 42618468 (97.3%) R@0x2cd8538 pss=24 padding=0 num_aliases=1 - source_path=base/page_allocator.cc object_path=base/base/page_allocator.o - flags={} name=mojo::MessageReceiver [vtable] -31) 42618480 (97.3%) R@0x2cd8550 pss=12 padding=0 num_aliases=1 - source_path=base/page_allocator.cc object_path=base/base/page_allocator.o - flags={} name=kMethodsAnimationFrameTimeHistogram -32) 43683612 (99.8%) R@0x2ddc608 pss=1065132 padding=1065132 num_aliases=1 - source_path= object_path= - flags={} name=** symbol gap 0 (end of section) -33) 43683616 (99.8%) d@0x2de7000 pss=4 padding=0 num_aliases=1 - source_path=base/page_allocator.cc object_path=base/base/page_allocator.o - flags={} name=google::protobuf::internal::pLinuxKernelCmpxchg -34) 43683620 (99.8%) d@0x2de7004 pss=4 padding=0 num_aliases=1 - source_path=third_party/container.c object_path=third_party/WebKit.a/ContiguousContainer.o - flags={} name=google::protobuf::internal::pLinuxKernelMemoryBarrier -35) 43683772 (99.8%) d@0x2de7008 pss=152 padding=0 num_aliases=1 - source_path=third_party/container.c object_path=third_party/WebKit.a/ContiguousContainer.o - flags={rel} name=base::android::kBaseRegisteredMethods -36) 43683776 (99.8%) d@0x2de70a0 pss=4 padding=0 num_aliases=1 - source_path=third_party/container.c object_path=third_party/WebKit.a/ContiguousContainer.o - flags={anon} name=base::android::g_renderer_histogram_code -37) 43683780 (99.8%) d@0x2de70a4 pss=4 padding=0 num_aliases=1 - source_path=third_party/container.c object_path=third_party/WebKit.a/ContiguousContainer.o - flags={anon,rel.loc} name=base::android::g_library_version_number -38) 43785380 (100.0%) d@0x2dffd88 pss=101600 padding=101600 num_aliases=1 - source_path= object_path= - flags={} name=** symbol gap 0 (end of section) -39) 43785380 (100.0%) b@0x0 pss=262144 padding=0 num_aliases=1 +44) 77769551 (100.0%) b@0x0 pss=262144 padding=0 num_aliases=1 source_path=third_party/fft_float.cc object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o flags={} name=ff_cos_131072 -40) 43785380 (100.0%) b@0x0 pss=131072 padding=0 num_aliases=1 +45) 77769551 (100.0%) b@0x0 pss=131072 padding=0 num_aliases=1 source_path=third_party/fft_fixed.cc object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_fixed.o flags={} name=ff_cos_131072_fixed -41) 43785380 (100.0%) b@0x0 pss=131072 padding=0 num_aliases=1 +46) 77769551 (100.0%) b@0x0 pss=131072 padding=0 num_aliases=1 source_path=third_party/fft_float.cc object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o flags={} name=ff_cos_65536 -42) 43785380 (100.0%) b@0x2dffda0 pss=28 padding=0 num_aliases=1 +47) 77769551 (100.0%) b@0x2dffda0 pss=28 padding=0 num_aliases=1 source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o flags={gen} name=g_chrome_content_browser_client -43) 43785380 (100.0%) b@0x2dffe80 pss=200 padding=196 num_aliases=1 +48) 77769551 (100.0%) b@0x2dffe80 pss=200 padding=196 num_aliases=1 source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o flags={gen} name=SaveHistogram::atomic_histogram_pointer full_name=SaveHistogram(_JNIEnv*, base::android::JavaParamRef<_jobject*> const&, base::android::JavaParamRef<_jstring*> const&, base::android::JavaParamRef<_jlongArray*> const&, int)::atomic_histogram_pointer -44) 43785380 (100.0%) b@0x2dffe84 pss=4 padding=0 num_aliases=1 +49) 77769551 (100.0%) b@0x2dffe84 pss=4 padding=0 num_aliases=1 source_path=third_party/icu/ucnv_ext.c object_path=third_party/icu/icuuc/ucnv_ext.o flags={anon,gen} name=g_AnimationFrameTimeHistogram_clazz
diff --git a/tools/binary_size/libsupersize/testdata/SymbolGroupMethods.golden b/tools/binary_size/libsupersize/testdata/SymbolGroupMethods.golden index f1c472b..c9abbf0 100644 --- a/tools/binary_size/libsupersize/testdata/SymbolGroupMethods.golden +++ b/tools/binary_size/libsupersize/testdata/SymbolGroupMethods.golden
@@ -1,207 +1,232 @@ GroupedByName() -Showing 41 symbols (41 unique) with total pss: 43785380 bytes -.text=34.2mb .rodata=5.65mb .data.rel.ro=1.02mb .data=99.4kb .bss=512kb total=41.8mb +Showing 43 symbols (43 unique) with total pss: 77769551 bytes +Histogram of symbols based on PSS: + {0}: 6 [8,16): 3 [64,128): 2 [65536,131072): 1 [33554432,67108864): 2 + [2,4): 2 [16,32): 9 [128,256): 1 [524288,1048576): 2 + [4,8): 5 [32,64): 7 [256,512): 1 [1048576,2097152): 2 +.text=34.2mb .rodata=5.65mb .data.rel.ro=1.02mb .data=99.4kb .bss=512kb .other=32.4mb total=74.2mb Number of unique paths: 9 -Section Legend: t=.text, r=.rodata, R=.data.rel.ro, d=.data, b=.bss +Section Legend: t=.text, r=.rodata, R=.data.rel.ro, d=.data, b=.bss, o=.other Index | Running Total | Section@Address | PSS | Path ------------------------------------------------------------ -0) 16 (0.0%) *@Group 16 _GLOBAL__sub_I_page_allocator.cc (count=1) -1) 72 (0.0%) *@Group 56 _GLOBAL__sub_I_bbr_sender.cc (count=1) -2) 100 (0.0%) *@Group 28 _GLOBAL__sub_I_pacing_sender.cc (count=1) -3) 170 (0.0%) *@Group 70 extFromUUseMapping (count=2) -4) 39117045 (89.3%) *@Group 39116875 ** symbol gaps (count=2) -5) 39117493 (89.3%) *@Group 448 ucnv_extMatchFromU (count=1) -6) 39117521 (89.3%) *@Group 28 _GLOBAL__sub_I_SkDeviceProfile.cpp (count=1) -7) 39186645 (89.5%) *@Group 69124 foo_bar (count=1) -8) 39186673 (89.5%) *@Group 28 blink::ContiguousContainerBase::shrinkToFit (count=2) -9) 39186697 (89.5%) *@Group 24 BazAlias (count=1) -10) 39186701 (89.5%) *@Group 4 FooAlias (count=1) -11) 39186705 (89.5%) *@Group 4 BarAlias (count=1) -12) 39186733 (89.5%) *@Group 28 blink::ContiguousContainerBase::ContiguousContainerBase (count=1) -13) 39186827 (89.5%) *@Group 94 blink::PaintChunker::releasePaintChunks (count=1) -14) 41824796 (95.5%) *@Group 2637969 ** merge strings (count=1) -15) 41828221 (95.5%) *@Group 3425 ** merge constants (count=1) -16) 41828229 (95.5%) *@Group 8 (count=1) -17) 41828273 (95.5%) *@Group 44 Name (count=1) -18) 41828305 (95.5%) *@Group 32 chrome::mojom::FilePatcher::Name_ (count=1) -19) 41828360 (95.5%) *@Group 55 kAnimationFrameTimeHistogramClassPath (count=1) -20) 41828364 (95.5%) *@Group 4 blink::CSSValueKeywordsHash::findValueImpl::value_word_list (count=1) -21) 41828420 (95.5%) *@Group 56 ChromeMainDelegate [vtable] (count=1) -22) 41828444 (95.5%) *@Group 24 chrome::mojom::FieldTrialRecorder [vtable] (count=1) -23) 42618348 (97.3%) *@Group 789904 chrome::mojom::FieldTrialRecorderProxy [vtable] (count=1) -24) 42618380 (97.3%) *@Group 32 .Lswitch.table.45 (count=1) -25) 42618388 (97.3%) *@Group 8 kSystemClassPrefixes (count=1) -26) 42618444 (97.3%) *@Group 56 ChromeMainDelegateAndroid [vtable] (count=1) -27) 42618468 (97.3%) *@Group 24 mojo::MessageReceiver [vtable] (count=1) -28) 42618480 (97.3%) *@Group 12 kMethodsAnimationFrameTimeHistogram (count=1) -29) 43785212 (100.0%) *@Group 1166732 ** symbol gap 0 (end of section) (count=2) -30) 43785216 (100.0%) *@Group 4 google::protobuf::internal::pLinuxKernelCmpxchg (count=1) -31) 43785220 (100.0%) *@Group 4 google::protobuf::internal::pLinuxKernelMemoryBarrier (count=1) -32) 43785372 (100.0%) *@Group 152 base::android::kBaseRegisteredMethods (count=1) -33) 43785376 (100.0%) *@Group 4 base::android::g_renderer_histogram_code (count=1) -34) 43785380 (100.0%) *@Group 4 base::android::g_library_version_number (count=1) -35) 43785380 (100.0%) *@Group 0 ff_cos_131072 (count=1) -36) 43785380 (100.0%) *@Group 0 ff_cos_131072_fixed (count=1) -37) 43785380 (100.0%) *@Group 0 ff_cos_65536 (count=1) -38) 43785380 (100.0%) *@Group 0 g_chrome_content_browser_client (count=1) -39) 43785380 (100.0%) *@Group 0 SaveHistogram::atomic_histogram_pointer (count=1) -40) 43785380 (100.0%) *@Group 0 g_AnimationFrameTimeHistogram_clazz (count=1) +0) 4 (0.0%) *@Group 4 google::protobuf::internal::pLinuxKernelCmpxchg (count=1) +1) 8 (0.0%) *@Group 4 google::protobuf::internal::pLinuxKernelMemoryBarrier (count=1) +2) 160 (0.0%) *@Group 152 base::android::kBaseRegisteredMethods (count=1) +3) 164 (0.0%) *@Group 4 base::android::g_renderer_histogram_code (count=1) +4) 168 (0.0%) *@Group 4 base::android::g_library_version_number (count=1) +5) 1166900 (1.5%) *@Group 1166732 ** symbol gap 0 (end of section) (count=2) +6) 1166956 (1.5%) *@Group 56 ChromeMainDelegateAndroid [vtable] (count=1) +7) 1166980 (1.5%) *@Group 24 mojo::MessageReceiver [vtable] (count=1) +8) 1166992 (1.5%) *@Group 12 kMethodsAnimationFrameTimeHistogram (count=1) +9) 1167048 (1.5%) *@Group 56 ChromeMainDelegate [vtable] (count=1) +10) 1167072 (1.5%) *@Group 24 chrome::mojom::FieldTrialRecorder [vtable] (count=1) +11) 1956976 (2.5%) *@Group 789904 chrome::mojom::FieldTrialRecorderProxy [vtable] (count=1) +12) 1957008 (2.5%) *@Group 32 .Lswitch.table.45 (count=1) +13) 1957016 (2.5%) *@Group 8 kSystemClassPrefixes (count=1) +14) 35941187 (46.2%) *@Group 33984171 ELF file overhead (count=1) +15) 35941208 (46.2%) *@Group 21 string literal (count=3) +16) 35941251 (46.2%) *@Group 43 ** merge strings (count=1) +17) 37906596 (48.7%) *@Group 1965345 ** merge constants (count=1) +18) 77023471 (99.0%) *@Group 39116875 ** symbol gaps (count=2) +19) 77023479 (99.0%) *@Group 8 (count=1) +20) 77023523 (99.0%) *@Group 44 Name (count=1) +21) 77023555 (99.0%) *@Group 32 chrome::mojom::FilePatcher::Name_ (count=1) +22) 77699595 (99.9%) *@Group 676040 kAnimationFrameTimeHistogramClassPath (count=1) +23) 77699599 (99.9%) *@Group 4 blink::CSSValueKeywordsHash::findValueImpl::value_word_list (count=1) +24) 77699615 (99.9%) *@Group 16 _GLOBAL__sub_I_page_allocator.cc (count=1) +25) 77699671 (99.9%) *@Group 56 _GLOBAL__sub_I_bbr_sender.cc (count=1) +26) 77699699 (99.9%) *@Group 28 _GLOBAL__sub_I_pacing_sender.cc (count=1) +27) 77699769 (99.9%) *@Group 70 extFromUUseMapping (count=2) +28) 77700217 (99.9%) *@Group 448 ucnv_extMatchFromU (count=1) +29) 77700245 (99.9%) *@Group 28 _GLOBAL__sub_I_SkDeviceProfile.cpp (count=1) +30) 77769369 (100.0%) *@Group 69124 foo_bar (count=1) +31) 77769399 (100.0%) *@Group 30 blink::ContiguousContainerBase::shrinkToFit (count=3) +32) 77769423 (100.0%) *@Group 24 BazAlias (count=1) +33) 77769426 (100.0%) *@Group 3 FooAlias (count=1) +34) 77769429 (100.0%) *@Group 3 BarAlias (count=1) +35) 77769457 (100.0%) *@Group 28 blink::ContiguousContainerBase::ContiguousContainerBase (count=1) +36) 77769551 (100.0%) *@Group 94 blink::PaintChunker::releasePaintChunks (count=1) +37) 77769551 (100.0%) *@Group 0 ff_cos_131072 (count=1) +38) 77769551 (100.0%) *@Group 0 ff_cos_131072_fixed (count=1) +39) 77769551 (100.0%) *@Group 0 ff_cos_65536 (count=1) +40) 77769551 (100.0%) *@Group 0 g_chrome_content_browser_client (count=1) +41) 77769551 (100.0%) *@Group 0 SaveHistogram::atomic_histogram_pointer (count=1) +42) 77769551 (100.0%) *@Group 0 g_AnimationFrameTimeHistogram_clazz (count=1) GroupedByName(depth=1) -Showing 33 symbols (33 unique) with total pss: 43785380 bytes -.text=34.2mb .rodata=5.65mb .data.rel.ro=1.02mb .data=99.4kb .bss=512kb total=41.8mb +Showing 35 symbols (35 unique) with total pss: 77769551 bytes +Histogram of symbols based on PSS: + {0}: 6 [8,16): 4 [32,64): 6 [128,256): 2 [65536,131072): 1 [1048576,2097152): 2 + [2,4): 2 [16,32): 6 [64,128): 1 [256,512): 1 [524288,1048576): 2 [33554432,67108864): 2 +.text=34.2mb .rodata=5.65mb .data.rel.ro=1.02mb .data=99.4kb .bss=512kb .other=32.4mb total=74.2mb Number of unique paths: 9 -Section Legend: t=.text, r=.rodata, R=.data.rel.ro, d=.data, b=.bss +Section Legend: t=.text, r=.rodata, R=.data.rel.ro, d=.data, b=.bss, o=.other Index | Running Total | Section@Address | PSS | Path ------------------------------------------------------------ -0) 16 (0.0%) *@Group 16 _GLOBAL__sub_I_page_allocator.cc (count=1) -1) 72 (0.0%) *@Group 56 _GLOBAL__sub_I_bbr_sender.cc (count=1) -2) 100 (0.0%) *@Group 28 _GLOBAL__sub_I_pacing_sender.cc (count=1) -3) 170 (0.0%) *@Group 70 extFromUUseMapping (count=2) -4) 39117045 (89.3%) *@Group 39116875 ** symbol gaps (count=2) -5) 39117493 (89.3%) *@Group 448 ucnv_extMatchFromU (count=1) -6) 39117521 (89.3%) *@Group 28 _GLOBAL__sub_I_SkDeviceProfile.cpp (count=1) -7) 39186645 (89.5%) *@Group 69124 foo_bar (count=1) -8) 39186799 (89.5%) *@Group 154 blink (count=5) -9) 39186823 (89.5%) *@Group 24 BazAlias (count=1) -10) 39186827 (89.5%) *@Group 4 FooAlias (count=1) -11) 39186831 (89.5%) *@Group 4 BarAlias (count=1) -12) 41824800 (95.5%) *@Group 2637969 ** merge strings (count=1) -13) 41828225 (95.5%) *@Group 3425 ** merge constants (count=1) -14) 41828233 (95.5%) *@Group 8 (count=1) -15) 41828277 (95.5%) *@Group 44 Name (count=1) -16) 42618237 (97.3%) *@Group 789960 chrome (count=3) -17) 42618292 (97.3%) *@Group 55 kAnimationFrameTimeHistogramClassPath (count=1) -18) 42618348 (97.3%) *@Group 56 ChromeMainDelegate [vtable] (count=1) -19) 42618380 (97.3%) *@Group 32 .Lswitch.table.45 (count=1) -20) 42618388 (97.3%) *@Group 8 kSystemClassPrefixes (count=1) -21) 42618444 (97.3%) *@Group 56 ChromeMainDelegateAndroid [vtable] (count=1) -22) 42618468 (97.3%) *@Group 24 mojo (count=1) -23) 42618480 (97.3%) *@Group 12 kMethodsAnimationFrameTimeHistogram (count=1) -24) 43785212 (100.0%) *@Group 1166732 ** symbol gap 0 (end of section) (count=2) -25) 43785220 (100.0%) *@Group 8 google (count=2) -26) 43785380 (100.0%) *@Group 160 base (count=3) -27) 43785380 (100.0%) *@Group 0 ff_cos_131072 (count=1) -28) 43785380 (100.0%) *@Group 0 ff_cos_131072_fixed (count=1) -29) 43785380 (100.0%) *@Group 0 ff_cos_65536 (count=1) -30) 43785380 (100.0%) *@Group 0 g_chrome_content_browser_client (count=1) -31) 43785380 (100.0%) *@Group 0 SaveHistogram (count=1) -32) 43785380 (100.0%) *@Group 0 g_AnimationFrameTimeHistogram_clazz (count=1) +0) 8 (0.0%) *@Group 8 google (count=2) +1) 168 (0.0%) *@Group 160 base (count=3) +2) 1166900 (1.5%) *@Group 1166732 ** symbol gap 0 (end of section) (count=2) +3) 1166956 (1.5%) *@Group 56 ChromeMainDelegateAndroid [vtable] (count=1) +4) 1166980 (1.5%) *@Group 24 mojo (count=1) +5) 1166992 (1.5%) *@Group 12 kMethodsAnimationFrameTimeHistogram (count=1) +6) 1167048 (1.5%) *@Group 56 ChromeMainDelegate [vtable] (count=1) +7) 1957008 (2.5%) *@Group 789960 chrome (count=3) +8) 1957040 (2.5%) *@Group 32 .Lswitch.table.45 (count=1) +9) 1957048 (2.5%) *@Group 8 kSystemClassPrefixes (count=1) +10) 35941219 (46.2%) *@Group 33984171 ELF file overhead (count=1) +11) 35941240 (46.2%) *@Group 21 string literal (count=3) +12) 35941283 (46.2%) *@Group 43 ** merge strings (count=1) +13) 37906628 (48.7%) *@Group 1965345 ** merge constants (count=1) +14) 77023503 (99.0%) *@Group 39116875 ** symbol gaps (count=2) +15) 77023511 (99.0%) *@Group 8 (count=1) +16) 77023555 (99.0%) *@Group 44 Name (count=1) +17) 77699595 (99.9%) *@Group 676040 kAnimationFrameTimeHistogramClassPath (count=1) +18) 77699751 (99.9%) *@Group 156 blink (count=6) +19) 77699767 (99.9%) *@Group 16 _GLOBAL__sub_I_page_allocator.cc (count=1) +20) 77699823 (99.9%) *@Group 56 _GLOBAL__sub_I_bbr_sender.cc (count=1) +21) 77699851 (99.9%) *@Group 28 _GLOBAL__sub_I_pacing_sender.cc (count=1) +22) 77699921 (99.9%) *@Group 70 extFromUUseMapping (count=2) +23) 77700369 (99.9%) *@Group 448 ucnv_extMatchFromU (count=1) +24) 77700397 (99.9%) *@Group 28 _GLOBAL__sub_I_SkDeviceProfile.cpp (count=1) +25) 77769521 (100.0%) *@Group 69124 foo_bar (count=1) +26) 77769545 (100.0%) *@Group 24 BazAlias (count=1) +27) 77769548 (100.0%) *@Group 3 FooAlias (count=1) +28) 77769551 (100.0%) *@Group 3 BarAlias (count=1) +29) 77769551 (100.0%) *@Group 0 ff_cos_131072 (count=1) +30) 77769551 (100.0%) *@Group 0 ff_cos_131072_fixed (count=1) +31) 77769551 (100.0%) *@Group 0 ff_cos_65536 (count=1) +32) 77769551 (100.0%) *@Group 0 g_chrome_content_browser_client (count=1) +33) 77769551 (100.0%) *@Group 0 SaveHistogram (count=1) +34) 77769551 (100.0%) *@Group 0 g_AnimationFrameTimeHistogram_clazz (count=1) GroupedByName(depth=-1) -Showing 36 symbols (36 unique) with total pss: 43785380 bytes -.text=34.2mb .rodata=5.65mb .data.rel.ro=1.02mb .data=99.4kb .bss=512kb total=41.8mb +Showing 38 symbols (38 unique) with total pss: 77769551 bytes +Histogram of symbols based on PSS: + {0}: 6 [8,16): 4 [64,128): 2 [65536,131072): 1 [33554432,67108864): 2 + [2,4): 2 [16,32): 6 [128,256): 1 [524288,1048576): 2 + [4,8): 1 [32,64): 8 [256,512): 1 [1048576,2097152): 2 +.text=34.2mb .rodata=5.65mb .data.rel.ro=1.02mb .data=99.4kb .bss=512kb .other=32.4mb total=74.2mb Number of unique paths: 9 -Section Legend: t=.text, r=.rodata, R=.data.rel.ro, d=.data, b=.bss +Section Legend: t=.text, r=.rodata, R=.data.rel.ro, d=.data, b=.bss, o=.other Index | Running Total | Section@Address | PSS | Path ------------------------------------------------------------ -0) 16 (0.0%) *@Group 16 _GLOBAL__sub_I_page_allocator.cc (count=1) -1) 72 (0.0%) *@Group 56 _GLOBAL__sub_I_bbr_sender.cc (count=1) -2) 100 (0.0%) *@Group 28 _GLOBAL__sub_I_pacing_sender.cc (count=1) -3) 170 (0.0%) *@Group 70 extFromUUseMapping (count=2) -4) 39117045 (89.3%) *@Group 39116875 ** symbol gaps (count=2) -5) 39117493 (89.3%) *@Group 448 ucnv_extMatchFromU (count=1) -6) 39117521 (89.3%) *@Group 28 _GLOBAL__sub_I_SkDeviceProfile.cpp (count=1) -7) 39186645 (89.5%) *@Group 69124 foo_bar (count=1) -8) 39186701 (89.5%) *@Group 56 blink::ContiguousContainerBase (count=3) -9) 39186725 (89.5%) *@Group 24 BazAlias (count=1) -10) 39186729 (89.5%) *@Group 4 FooAlias (count=1) -11) 39186733 (89.5%) *@Group 4 BarAlias (count=1) -12) 39186827 (89.5%) *@Group 94 blink::PaintChunker (count=1) -13) 41824796 (95.5%) *@Group 2637969 ** merge strings (count=1) -14) 41828221 (95.5%) *@Group 3425 ** merge constants (count=1) -15) 41828229 (95.5%) *@Group 8 (count=1) -16) 41828273 (95.5%) *@Group 44 Name (count=1) -17) 41828305 (95.5%) *@Group 32 chrome::mojom::FilePatcher (count=1) -18) 41828360 (95.5%) *@Group 55 kAnimationFrameTimeHistogramClassPath (count=1) -19) 41828364 (95.5%) *@Group 4 blink::CSSValueKeywordsHash::findValueImpl (count=1) -20) 41828420 (95.5%) *@Group 56 ChromeMainDelegate [vtable] (count=1) -21) 42618348 (97.3%) *@Group 789928 chrome::mojom (count=2) -22) 42618380 (97.3%) *@Group 32 .Lswitch.table.45 (count=1) -23) 42618388 (97.3%) *@Group 8 kSystemClassPrefixes (count=1) -24) 42618444 (97.3%) *@Group 56 ChromeMainDelegateAndroid [vtable] (count=1) -25) 42618468 (97.3%) *@Group 24 mojo (count=1) -26) 42618480 (97.3%) *@Group 12 kMethodsAnimationFrameTimeHistogram (count=1) -27) 43785212 (100.0%) *@Group 1166732 ** symbol gap 0 (end of section) (count=2) -28) 43785220 (100.0%) *@Group 8 google::protobuf::internal (count=2) -29) 43785380 (100.0%) *@Group 160 base::android (count=3) -30) 43785380 (100.0%) *@Group 0 ff_cos_131072 (count=1) -31) 43785380 (100.0%) *@Group 0 ff_cos_131072_fixed (count=1) -32) 43785380 (100.0%) *@Group 0 ff_cos_65536 (count=1) -33) 43785380 (100.0%) *@Group 0 g_chrome_content_browser_client (count=1) -34) 43785380 (100.0%) *@Group 0 SaveHistogram (count=1) -35) 43785380 (100.0%) *@Group 0 g_AnimationFrameTimeHistogram_clazz (count=1) +0) 8 (0.0%) *@Group 8 google::protobuf::internal (count=2) +1) 168 (0.0%) *@Group 160 base::android (count=3) +2) 1166900 (1.5%) *@Group 1166732 ** symbol gap 0 (end of section) (count=2) +3) 1166956 (1.5%) *@Group 56 ChromeMainDelegateAndroid [vtable] (count=1) +4) 1166980 (1.5%) *@Group 24 mojo (count=1) +5) 1166992 (1.5%) *@Group 12 kMethodsAnimationFrameTimeHistogram (count=1) +6) 1167048 (1.5%) *@Group 56 ChromeMainDelegate [vtable] (count=1) +7) 1956976 (2.5%) *@Group 789928 chrome::mojom (count=2) +8) 1957008 (2.5%) *@Group 32 .Lswitch.table.45 (count=1) +9) 1957016 (2.5%) *@Group 8 kSystemClassPrefixes (count=1) +10) 35941187 (46.2%) *@Group 33984171 ELF file overhead (count=1) +11) 35941208 (46.2%) *@Group 21 string literal (count=3) +12) 35941251 (46.2%) *@Group 43 ** merge strings (count=1) +13) 37906596 (48.7%) *@Group 1965345 ** merge constants (count=1) +14) 77023471 (99.0%) *@Group 39116875 ** symbol gaps (count=2) +15) 77023479 (99.0%) *@Group 8 (count=1) +16) 77023523 (99.0%) *@Group 44 Name (count=1) +17) 77023555 (99.0%) *@Group 32 chrome::mojom::FilePatcher (count=1) +18) 77699595 (99.9%) *@Group 676040 kAnimationFrameTimeHistogramClassPath (count=1) +19) 77699599 (99.9%) *@Group 4 blink::CSSValueKeywordsHash::findValueImpl (count=1) +20) 77699615 (99.9%) *@Group 16 _GLOBAL__sub_I_page_allocator.cc (count=1) +21) 77699671 (99.9%) *@Group 56 _GLOBAL__sub_I_bbr_sender.cc (count=1) +22) 77699699 (99.9%) *@Group 28 _GLOBAL__sub_I_pacing_sender.cc (count=1) +23) 77699769 (99.9%) *@Group 70 extFromUUseMapping (count=2) +24) 77700217 (99.9%) *@Group 448 ucnv_extMatchFromU (count=1) +25) 77700245 (99.9%) *@Group 28 _GLOBAL__sub_I_SkDeviceProfile.cpp (count=1) +26) 77769369 (100.0%) *@Group 69124 foo_bar (count=1) +27) 77769427 (100.0%) *@Group 58 blink::ContiguousContainerBase (count=4) +28) 77769451 (100.0%) *@Group 24 BazAlias (count=1) +29) 77769454 (100.0%) *@Group 3 FooAlias (count=1) +30) 77769457 (100.0%) *@Group 3 BarAlias (count=1) +31) 77769551 (100.0%) *@Group 94 blink::PaintChunker (count=1) +32) 77769551 (100.0%) *@Group 0 ff_cos_131072 (count=1) +33) 77769551 (100.0%) *@Group 0 ff_cos_131072_fixed (count=1) +34) 77769551 (100.0%) *@Group 0 ff_cos_65536 (count=1) +35) 77769551 (100.0%) *@Group 0 g_chrome_content_browser_client (count=1) +36) 77769551 (100.0%) *@Group 0 SaveHistogram (count=1) +37) 77769551 (100.0%) *@Group 0 g_AnimationFrameTimeHistogram_clazz (count=1) GroupedByName(depth=1, min_count=2) -Showing 33 symbols (32 unique) with total pss: 43785380 bytes -.text=34.2mb .rodata=5.65mb .data.rel.ro=1.02mb .data=99.4kb .bss=512kb total=41.8mb +Showing 35 symbols (34 unique) with total pss: 77769551 bytes +Histogram of symbols based on PSS: + [2,4): 2 [16,32): 7 [128,256): 3 [131072,262144): 2 [1048576,2097152): 2 + [4,8): 1 [32,64): 6 [256,512): 1 [262144,524288): 1 [33554432,67108864): 2 + [8,16): 4 [64,128): 1 [65536,131072): 1 [524288,1048576): 2 +.text=34.2mb .rodata=5.65mb .data.rel.ro=1.02mb .data=99.4kb .bss=512kb .other=32.4mb total=74.2mb Number of unique paths: 9 -Section Legend: t=.text, r=.rodata, R=.data.rel.ro, d=.data, b=.bss +Section Legend: t=.text, r=.rodata, R=.data.rel.ro, d=.data, b=.bss, o=.other Index | Running Total | Section@Address | PSS | Path ------------------------------------------------------------ -0) 16 (0.0%) t@0x28d900 16 base/page_allocator.cc - _GLOBAL__sub_I_page_allocator.cc -1) 72 (0.0%) t@0x28d910 56 base/page_allocator.cc - _GLOBAL__sub_I_bbr_sender.cc -2) 100 (0.0%) t@0x28d948 28 base/page_allocator.cc - _GLOBAL__sub_I_pacing_sender.cc -3) 170 (0.0%) *@Group 70 base/page_allocator.cc - extFromUUseMapping (count=2) -4) 39117045 (89.3%) *@Group 39116875 {no path} - ** symbol gaps (count=2) -5) 39117493 (89.3%) t@0x28f000 448 third_party/icu/ucnv_ext.c - ucnv_extMatchFromU -6) 39117521 (89.3%) t@0x28f1c8 28 third_party/icu/ucnv_ext.c - _GLOBAL__sub_I_SkDeviceProfile.cpp -7) 39186645 (89.5%) t@0x28f1e0 69124 third_party/icu/ucnv_ext.c - foo_bar -8) 39186799 (89.5%) *@Group 154 {no path} - blink (count=5) -9) 39186823 (89.5%) t@0x2a0000 24 (size=48) third_party/icu/ucnv_ext.c - BazAlias (num_aliases=2) -10) 39186827 (89.5%) t@0x2a0010 4 (size=12) third_party/fft_float.cc - FooAlias (num_aliases=3) -11) 39186831 (89.5%) t@0x2a0010 4 (size=12) third_party/fft_float.cc - BarAlias (num_aliases=3) -12) 41824800 (95.5%) r@Group 2637969 {no path} - ** merge strings (count=2) -13) 41828225 (95.5%) r@0x284d600 3425 {no path} - ** merge constants -14) 41828233 (95.5%) r@0x284e364 8 base/page_allocator.cc -15) 41828277 (95.5%) r@0x284e370 44 base/page_allocator.cc - Name -16) 42618237 (97.3%) *@Group 789960 {no path} - chrome (count=3) -17) 42618292 (97.3%) r@0x28f3450 55 third_party/paint.cc - kAnimationFrameTimeHistogramClassPath -18) 42618348 (97.3%) R@0x2c176f0 56 third_party/icu/ucnv_ext.c - ChromeMainDelegate [vtable] -19) 42618380 (97.3%) R@0x2cd84e0 32 third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libcontroller_api_impl.a_controller_api_impl.o - .Lswitch.table.45 -20) 42618388 (97.3%) R@0x2cd84f0 8 third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libport_android_jni.a_jni_utils.o - kSystemClassPrefixes -21) 42618444 (97.3%) R@0x2cd8500 56 third_party/paint.cc - ChromeMainDelegateAndroid [vtable] -22) 42618468 (97.3%) R@0x2cd8538 24 base/page_allocator.cc - mojo::MessageReceiver [vtable] -23) 42618480 (97.3%) R@0x2cd8550 12 base/page_allocator.cc - kMethodsAnimationFrameTimeHistogram -24) 43785212 (100.0%) *@Group 1166732 {no path} - ** symbol gap 0 (end of section) (count=2) -25) 43785220 (100.0%) *@Group 8 {no path} +0) 8 (0.0%) *@Group 8 {no path} google (count=2) -26) 43785380 (100.0%) *@Group 160 third_party/container.c +1) 168 (0.0%) *@Group 160 third_party/container.c base (count=3) -27) 43785380 (100.0%) b@0x0 262144 third_party/fft_float.cc +2) 1166900 (1.5%) *@Group 1166732 {no path} + ** symbol gap 0 (end of section) (count=2) +3) 1166956 (1.5%) R@0x2cd8500 56 third_party/paint.cc + ChromeMainDelegateAndroid [vtable] +4) 1166980 (1.5%) R@0x2cd8538 24 base/page_allocator.cc + mojo::MessageReceiver [vtable] +5) 1166992 (1.5%) R@0x2cd8550 12 base/page_allocator.cc + kMethodsAnimationFrameTimeHistogram +6) 1167048 (1.5%) R@0x2c176f0 56 third_party/icu/ucnv_ext.c + ChromeMainDelegate [vtable] +7) 1957008 (2.5%) *@Group 789960 {no path} + chrome (count=3) +8) 1957040 (2.5%) R@0x2cd84e0 32 third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libcontroller_api_impl.a_controller_api_impl.o + .Lswitch.table.45 +9) 1957048 (2.5%) R@0x2cd84f0 8 third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libport_android_jni.a_jni_utils.o + kSystemClassPrefixes +10) 35941219 (46.2%) o@0x0 33984171 {no path} + ELF file overhead +11) 35941240 (46.2%) *@Group 21 {no path} + string literal (count=3) +12) 35941283 (46.2%) r@0x266e630 43 {no path} + ** merge strings +13) 37906628 (48.7%) r@0x284d600 1965345 {no path} + ** merge constants +14) 77023503 (99.0%) *@Group 39116875 {no path} + ** symbol gaps (count=2) +15) 77023511 (99.0%) r@0x284e364 8 base/page_allocator.cc +16) 77023555 (99.0%) r@0x284e370 44 base/page_allocator.cc + Name +17) 77699595 (99.9%) r@0x28f3450 676040 third_party/paint.cc + kAnimationFrameTimeHistogramClassPath +18) 77699751 (99.9%) *@Group 156 {no path} + blink (count=6) +19) 77699767 (99.9%) t@0x28d900 16 base/page_allocator.cc + _GLOBAL__sub_I_page_allocator.cc +20) 77699823 (99.9%) t@0x28d910 56 base/page_allocator.cc + _GLOBAL__sub_I_bbr_sender.cc +21) 77699851 (99.9%) t@0x28d948 28 base/page_allocator.cc + _GLOBAL__sub_I_pacing_sender.cc +22) 77699921 (99.9%) *@Group 70 base/page_allocator.cc + extFromUUseMapping (count=2) +23) 77700369 (99.9%) t@0x28f000 448 third_party/icu/ucnv_ext.c + ucnv_extMatchFromU +24) 77700397 (99.9%) t@0x28f1c8 28 third_party/icu/ucnv_ext.c + _GLOBAL__sub_I_SkDeviceProfile.cpp +25) 77769521 (100.0%) t@0x28f1e0 69124 third_party/icu/ucnv_ext.c + foo_bar +26) 77769545 (100.0%) t@0x2a0000 24 (size=48) third_party/icu/ucnv_ext.c + BazAlias (num_aliases=2) +27) 77769548 (100.0%) t@0x2a0010 3 (size=12) third_party/fft_float.cc + FooAlias (num_aliases=4) +28) 77769551 (100.0%) t@0x2a0010 3 (size=12) third_party/fft_float.cc + BarAlias (num_aliases=4) +29) 77769551 (100.0%) b@0x0 262144 third_party/fft_float.cc ff_cos_131072 -28) 43785380 (100.0%) b@0x0 131072 third_party/fft_fixed.cc +30) 77769551 (100.0%) b@0x0 131072 third_party/fft_fixed.cc ff_cos_131072_fixed -29) 43785380 (100.0%) b@0x0 131072 third_party/fft_float.cc +31) 77769551 (100.0%) b@0x0 131072 third_party/fft_float.cc ff_cos_65536 -30) 43785380 (100.0%) b@0x2dffda0 28 third_party/icu/ucnv_ext.c +32) 77769551 (100.0%) b@0x2dffda0 28 third_party/icu/ucnv_ext.c g_chrome_content_browser_client -31) 43785380 (100.0%) b@0x2dffe80 200 third_party/icu/ucnv_ext.c +33) 77769551 (100.0%) b@0x2dffe80 200 third_party/icu/ucnv_ext.c SaveHistogram::atomic_histogram_pointer -32) 43785380 (100.0%) b@0x2dffe84 4 third_party/icu/ucnv_ext.c +34) 77769551 (100.0%) b@0x2dffe84 4 third_party/icu/ucnv_ext.c g_AnimationFrameTimeHistogram_clazz
diff --git a/tools/binary_size/libsupersize/testdata/mock_output_directory/elf b/tools/binary_size/libsupersize/testdata/mock_output_directory/elf deleted file mode 100644 index cd45dd7..0000000 --- a/tools/binary_size/libsupersize/testdata/mock_output_directory/elf +++ /dev/null
@@ -1,3 +0,0 @@ -Placeholder for an ELF file. -Its mtime is queried, and its output-relative path is used. -But what you read here is completely superfluous.
diff --git a/tools/binary_size/libsupersize/testdata/mock_output_directory/elf.begin b/tools/binary_size/libsupersize/testdata/mock_output_directory/elf.begin new file mode 100644 index 0000000..dcec5d37 --- /dev/null +++ b/tools/binary_size/libsupersize/testdata/mock_output_directory/elf.begin Binary files differ
diff --git a/tools/binary_size/libsupersize/testdata/mock_output_directory/en-US.pak b/tools/binary_size/libsupersize/testdata/mock_output_directory/en-US.pak new file mode 100644 index 0000000..06b0605a --- /dev/null +++ b/tools/binary_size/libsupersize/testdata/mock_output_directory/en-US.pak Binary files differ
diff --git a/tools/binary_size/libsupersize/testdata/mock_output_directory/en-US.pak.info b/tools/binary_size/libsupersize/testdata/mock_output_directory/en-US.pak.info new file mode 100644 index 0000000..eba2e12 --- /dev/null +++ b/tools/binary_size/libsupersize/testdata/mock_output_directory/en-US.pak.info
@@ -0,0 +1,222 @@ +IDS_BEFOREUNLOAD_MESSAGEBOX_MESSAGE,15046,../../components/app_modal_strings.grdp +IDS_POLICY_TYPE_ERROR,15740,../../components/policy_strings.grdp +IDS_POLICY_LIST_ENTRY_ERROR,15746,../../components/policy_strings.grdp +IDS_POLICY_SCHEMA_VALIDATION_ERROR,15747,../../components/policy_strings.grdp +IDS_SB_UNDER_CONSTRUCTION,15826,../../components/safe_browsing_strings.grdp +IDS_SAFEBROWSING_V3_TITLE,15864,../../components/security_interstitials_strings.grdp +IDS_SAFEBROWSING_V3_OPEN_DETAILS_BUTTON,15865,../../components/security_interstitials_strings.grdp +IDS_SAFEBROWSING_V3_CLOSE_DETAILS_BUTTON,15866,../../components/security_interstitials_strings.grdp +IDS_SAFEBROWSING_OVERRIDABLE_SAFETY_BUTTON,15867,../../components/security_interstitials_strings.grdp +IDS_MALWARE_V3_HEADING,15868,../../components/security_interstitials_strings.grdp +IDS_MALWARE_V3_PRIMARY_PARAGRAPH,15869,../../components/security_interstitials_strings.grdp +IDS_MALWARE_V3_EXPLANATION_PARAGRAPH,15870,../../components/security_interstitials_strings.grdp +IDS_MALWARE_V3_EXPLANATION_PARAGRAPH_SUBRESOURCE,15871,../../components/security_interstitials_strings.grdp +IDS_MALWARE_V3_PROCEED_PARAGRAPH,15872,../../components/security_interstitials_strings.grdp +IDS_SAFE_BROWSING_PRIVACY_POLICY_PAGE,15873,../../components/security_interstitials_strings.grdp +IDS_SAFE_BROWSING_MALWARE_REPORTING_AGREE,15874,../../components/security_interstitials_strings.grdp +IDS_SAFE_BROWSING_SCOUT_REPORTING_AGREE,15875,../../components/security_interstitials_strings.grdp +IDS_PHISHING_V4_HEADING,15880,../../components/security_interstitials_strings.grdp +IDS_PHISHING_V4_PRIMARY_PARAGRAPH,15881,../../components/security_interstitials_strings.grdp +IDS_PHISHING_V4_EXPLANATION_PARAGRAPH,15882,../../components/security_interstitials_strings.grdp +IDS_PHISHING_V4_PROCEED_AND_REPORT_PARAGRAPH,15883,../../components/security_interstitials_strings.grdp +IDS_MALWARE_WEBVIEW_HEADING,15884,../../components/security_interstitials_strings.grdp +IDS_MALWARE_WEBVIEW_EXPLANATION_PARAGRAPH,15885,../../components/security_interstitials_strings.grdp +IDS_PHISHING_WEBVIEW_HEADING,15886,../../components/security_interstitials_strings.grdp +IDS_PHISHING_WEBVIEW_EXPLANATION_PARAGRAPH,15887,../../components/security_interstitials_strings.grdp +IDS_DETAILS_WITHOUT_SUMMARY_LABEL,20100,../../content/app/strings/content_strings.grd +IDS_FORM_CALENDAR_CLEAR,20101,../../content/app/strings/content_strings.grd +IDS_FORM_CALENDAR_TODAY,20102,../../content/app/strings/content_strings.grd +IDS_FORM_SUBMIT_LABEL,20103,../../content/app/strings/content_strings.grd +IDS_FORM_INPUT_ALT,20104,../../content/app/strings/content_strings.grd +IDS_FORM_RESET_LABEL,20105,../../content/app/strings/content_strings.grd +IDS_FORM_FILE_BUTTON_LABEL,20106,../../content/app/strings/content_strings.grd +IDS_FORM_MULTIPLE_FILES_BUTTON_LABEL,20107,../../content/app/strings/content_strings.grd +IDS_FORM_FILE_NO_FILE_LABEL,20108,../../content/app/strings/content_strings.grd +IDS_FORM_FILE_MULTIPLE_UPLOAD,20109,../../content/app/strings/content_strings.grd +IDS_FORM_OTHER_COLOR_LABEL,20110,../../content/app/strings/content_strings.grd +IDS_FORM_OTHER_DATE_LABEL,20111,../../content/app/strings/content_strings.grd +IDS_FORM_OTHER_MONTH_LABEL,20112,../../content/app/strings/content_strings.grd +IDS_FORM_OTHER_WEEK_LABEL,20113,../../content/app/strings/content_strings.grd +IDS_FORM_PLACEHOLDER_FOR_DAY_OF_MONTH_FIELD,20114,../../content/app/strings/content_strings.grd +IDS_FORM_PLACEHOLDER_FOR_MONTH_FIELD,20115,../../content/app/strings/content_strings.grd +IDS_FORM_PLACEHOLDER_FOR_YEAR_FIELD,20116,../../content/app/strings/content_strings.grd +IDS_FORM_SELECT_MENU_LIST_TEXT,20117,../../content/app/strings/content_strings.grd +IDS_FORM_THIS_MONTH_LABEL,20118,../../content/app/strings/content_strings.grd +IDS_FORM_THIS_WEEK_LABEL,20119,../../content/app/strings/content_strings.grd +IDS_FORM_WEEK_NUMBER_LABEL,20120,../../content/app/strings/content_strings.grd +IDS_AX_CALENDAR_SHOW_MONTH_SELECTOR,20121,../../content/app/strings/content_strings.grd +IDS_AX_CALENDAR_SHOW_NEXT_MONTH,20122,../../content/app/strings/content_strings.grd +IDS_AX_CALENDAR_SHOW_PREVIOUS_MONTH,20123,../../content/app/strings/content_strings.grd +IDS_AX_CALENDAR_WEEK_DESCRIPTION,20124,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_ARTICLE,20125,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_BANNER,20126,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_COMPLEMENTARY,20127,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_CHECK_BOX,20128,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_CONTENT_INFO,20129,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_DEFINITION,20130,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_DESCRIPTION_LIST,20131,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_DESCRIPTION_TERM,20132,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_DISCLOSURE_TRIANGLE,20133,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_FEED,20134,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_FIGURE,20135,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_FORM,20136,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_FOOTER,20137,../../content/app/strings/content_strings.grd +IDS_AX_AUTOFILL_POPUP_ACCESSIBLE_NODE_DATA,20138,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_TOGGLE_BUTTON,20140,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_HEADING,20141,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_LINK,20142,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_MAIN_CONTENT,20143,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_MARK,20144,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_MATH,20145,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_NAVIGATIONAL_LINK,20146,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_REGION,20147,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_SEARCH_BOX,20148,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_STATUS,20149,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_SWITCH,20150,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_WEB_AREA,20151,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_ALERT,20152,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_ALERT_DIALOG,20153,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_APPLICATION,20154,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_BLOCKQUOTE,20155,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_BUTTON,20156,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_BUTTON_DROP_DOWN,20157,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_CELL,20158,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_COLOR_WELL,20159,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_COLUMN_HEADER,20160,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_COMBO_BOX,20161,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_DATE,20162,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_DATE_TIME,20163,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_DIALOG,20164,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_DIRECTORY,20165,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_DOCUMENT,20166,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_EMBEDDED_OBJECT,20167,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_GRAPHIC,20168,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_HEADING_WITH_LEVEL,20169,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_INPUT_TIME,20170,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_LIST_BOX,20171,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_LOG,20172,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_MARQUEE,20173,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_MENU,20174,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_MENU_BAR,20175,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_MENU_BUTTON,20176,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_MENU_ITEM,20177,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_METER,20178,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_NOTE,20179,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_POP_UP_BUTTON,20180,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_PROGRESS_INDICATOR,20181,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_RADIO,20182,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_RADIO_GROUP,20183,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_ROW_HEADER,20184,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_SCROLL_BAR,20185,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_SEARCH,20186,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_SLIDER,20187,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_SPIN_BUTTON,20188,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_SPLITTER,20189,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_TAB,20190,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_TABLE,20191,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_TAB_LIST,20192,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_TAB_PANEL,20193,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_TIME,20194,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_TIMER,20195,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_TOOLBAR,20196,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_TOOLTIP,20197,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_TREE,20198,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_TREE_GRID,20199,../../content/app/strings/content_strings.grd +IDS_AX_ROLE_TREE_ITEM,20200,../../content/app/strings/content_strings.grd +IDS_AX_AM_PM_FIELD_TEXT,20201,../../content/app/strings/content_strings.grd +IDS_AX_DAY_OF_MONTH_FIELD_TEXT,20202,../../content/app/strings/content_strings.grd +IDS_AX_HOUR_FIELD_TEXT,20203,../../content/app/strings/content_strings.grd +IDS_AX_MEDIA_DEFAULT,20204,../../content/app/strings/content_strings.grd +IDS_AX_MEDIA_AUDIO_ELEMENT,20205,../../content/app/strings/content_strings.grd +IDS_AX_MEDIA_VIDEO_ELEMENT,20206,../../content/app/strings/content_strings.grd +IDS_AX_MEDIA_MUTE_BUTTON,20207,../../content/app/strings/content_strings.grd +IDS_AX_MEDIA_UNMUTE_BUTTON,20208,../../content/app/strings/content_strings.grd +IDS_AX_MEDIA_PLAY_BUTTON,20209,../../content/app/strings/content_strings.grd +IDS_AX_MEDIA_PAUSE_BUTTON,20210,../../content/app/strings/content_strings.grd +IDS_AX_MEDIA_CURRENT_TIME_DISPLAY,20211,../../content/app/strings/content_strings.grd +IDS_AX_MEDIA_TIME_REMAINING_DISPLAY,20212,../../content/app/strings/content_strings.grd +IDS_AX_MEDIA_ENTER_FULL_SCREEN_BUTTON,20213,../../content/app/strings/content_strings.grd +IDS_AX_MEDIA_EXIT_FULL_SCREEN_BUTTON,20214,../../content/app/strings/content_strings.grd +IDS_AX_MEDIA_SHOW_CLOSED_CAPTIONS_BUTTON,20215,../../content/app/strings/content_strings.grd +IDS_AX_MEDIA_HIDE_CLOSED_CAPTIONS_BUTTON,20216,../../content/app/strings/content_strings.grd +IDS_AX_MEDIA_CAST_OFF_BUTTON,20217,../../content/app/strings/content_strings.grd +IDS_AX_MEDIA_CAST_ON_BUTTON,20218,../../content/app/strings/content_strings.grd +IDS_AX_MEDIA_DOWNLOAD_BUTTON,20219,../../content/app/strings/content_strings.grd +IDS_AX_MEDIA_OVERFLOW_BUTTON,20220,../../content/app/strings/content_strings.grd +IDS_AX_MEDIA_AUDIO_ELEMENT_HELP,20221,../../content/app/strings/content_strings.grd +IDS_AX_MEDIA_VIDEO_ELEMENT_HELP,20222,../../content/app/strings/content_strings.grd +IDS_AX_MEDIA_MUTE_BUTTON_HELP,20223,../../content/app/strings/content_strings.grd +IDS_AX_MEDIA_UNMUTE_BUTTON_HELP,20224,../../content/app/strings/content_strings.grd +IDS_AX_MEDIA_PLAY_BUTTON_HELP,20225,../../content/app/strings/content_strings.grd +IDS_AX_MEDIA_PAUSE_BUTTON_HELP,20226,../../content/app/strings/content_strings.grd +IDS_AX_MEDIA_AUDIO_SLIDER_HELP,20227,../../content/app/strings/content_strings.grd +IDS_AX_MEDIA_VIDEO_SLIDER_HELP,20228,../../content/app/strings/content_strings.grd +IDS_AX_MEDIA_CURRENT_TIME_DISPLAY_HELP,20229,../../content/app/strings/content_strings.grd +IDS_AX_MEDIA_TIME_REMAINING_DISPLAY_HELP,20230,../../content/app/strings/content_strings.grd +IDS_AX_MEDIA_ENTER_FULL_SCREEN_BUTTON_HELP,20231,../../content/app/strings/content_strings.grd +IDS_AX_MEDIA_EXIT_FULL_SCREEN_BUTTON_HELP,20232,../../content/app/strings/content_strings.grd +IDS_AX_MEDIA_SHOW_CLOSED_CAPTIONS_BUTTON_HELP,20233,../../content/app/strings/content_strings.grd +IDS_AX_MEDIA_HIDE_CLOSED_CAPTIONS_BUTTON_HELP,20234,../../content/app/strings/content_strings.grd +IDS_AX_MEDIA_CAST_OFF_BUTTON_HELP,20235,../../content/app/strings/content_strings.grd +IDS_AX_MEDIA_CAST_ON_BUTTON_HELP,20236,../../content/app/strings/content_strings.grd +IDS_AX_MEDIA_OVERFLOW_BUTTON_HELP,20237,../../content/app/strings/content_strings.grd +IDS_AX_MILLISECOND_FIELD_TEXT,20238,../../content/app/strings/content_strings.grd +IDS_AX_MINUTE_FIELD_TEXT,20239,../../content/app/strings/content_strings.grd +IDS_AX_MONTH_FIELD_TEXT,20240,../../content/app/strings/content_strings.grd +IDS_AX_SECOND_FIELD_TEXT,20241,../../content/app/strings/content_strings.grd +IDS_AX_WEEK_OF_YEAR_FIELD_TEXT,20242,../../content/app/strings/content_strings.grd +IDS_AX_YEAR_FIELD_TEXT,20243,../../content/app/strings/content_strings.grd +IDS_FORM_INPUT_WEEK_TEMPLATE,20244,../../content/app/strings/content_strings.grd +IDS_FORM_VALIDATION_VALUE_MISSING_MULTIPLE_FILE,20245,../../content/app/strings/content_strings.grd +IDS_FORM_VALIDATION_TYPE_MISMATCH,20246,../../content/app/strings/content_strings.grd +IDS_FORM_VALIDATION_TYPE_MISMATCH_EMAIL_EMPTY,20247,../../content/app/strings/content_strings.grd +IDS_FORM_VALIDATION_TYPE_MISMATCH_EMAIL_EMPTY_DOMAIN,20248,../../content/app/strings/content_strings.grd +IDS_FORM_VALIDATION_TYPE_MISMATCH_EMAIL_EMPTY_LOCAL,20249,../../content/app/strings/content_strings.grd +IDS_FORM_VALIDATION_TYPE_MISMATCH_EMAIL_INVALID_DOMAIN,20250,../../content/app/strings/content_strings.grd +IDS_FORM_VALIDATION_TYPE_MISMATCH_EMAIL_INVALID_DOTS,20251,../../content/app/strings/content_strings.grd +IDS_FORM_VALIDATION_TYPE_MISMATCH_EMAIL_INVALID_LOCAL,20252,../../content/app/strings/content_strings.grd +IDS_FORM_VALIDATION_TYPE_MISMATCH_EMAIL_NO_AT_SIGN,20253,../../content/app/strings/content_strings.grd +IDS_FORM_VALIDATION_TYPE_MISMATCH_MULTIPLE_EMAIL,20254,../../content/app/strings/content_strings.grd +IDS_FORM_VALIDATION_RANGE_UNDERFLOW,20255,../../content/app/strings/content_strings.grd +IDS_FORM_VALIDATION_RANGE_UNDERFLOW_DATETIME,20256,../../content/app/strings/content_strings.grd +IDS_FORM_VALIDATION_RANGE_OVERFLOW,20257,../../content/app/strings/content_strings.grd +IDS_FORM_VALIDATION_RANGE_OVERFLOW_DATETIME,20258,../../content/app/strings/content_strings.grd +IDS_FORM_VALIDATION_BAD_INPUT_DATETIME,20259,../../content/app/strings/content_strings.grd +IDS_FORM_VALIDATION_BAD_INPUT_NUMBER,20260,../../content/app/strings/content_strings.grd +IDS_FORM_VALIDATION_VALUE_MISSING,20261,../../content/app/strings/content_strings.grd +IDS_FORM_VALIDATION_VALUE_MISSING_CHECKBOX,20262,../../content/app/strings/content_strings.grd +IDS_FORM_VALIDATION_VALUE_MISSING_FILE,20263,../../content/app/strings/content_strings.grd +IDS_FORM_VALIDATION_VALUE_MISSING_RADIO,20264,../../content/app/strings/content_strings.grd +IDS_FORM_VALIDATION_VALUE_MISSING_SELECT,20265,../../content/app/strings/content_strings.grd +IDS_FORM_VALIDATION_TYPE_MISMATCH_EMAIL,20266,../../content/app/strings/content_strings.grd +IDS_FORM_VALIDATION_TYPE_MISMATCH_URL,20267,../../content/app/strings/content_strings.grd +IDS_FORM_VALIDATION_PATTERN_MISMATCH,20268,../../content/app/strings/content_strings.grd +IDS_FORM_VALIDATION_STEP_MISMATCH,20269,../../content/app/strings/content_strings.grd +IDS_FORM_VALIDATION_STEP_MISMATCH_CLOSE_TO_LIMIT,20270,../../content/app/strings/content_strings.grd +IDS_FORM_VALIDATION_TOO_LONG,20271,../../content/app/strings/content_strings.grd +IDS_FORM_VALIDATION_TOO_SHORT,20272,../../content/app/strings/content_strings.grd +IDS_FORM_VALIDATION_TOO_SHORT_PLURAL,20273,../../content/app/strings/content_strings.grd +IDS_MEDIA_OVERFLOW_MENU_CLOSED_CAPTIONS,20274,../../content/app/strings/content_strings.grd +IDS_MEDIA_OVERFLOW_MENU_CLOSED_CAPTIONS_SUBMENU_TITLE,20275,../../content/app/strings/content_strings.grd +IDS_MEDIA_OVERFLOW_MENU_CAST,20276,../../content/app/strings/content_strings.grd +IDS_MEDIA_OVERFLOW_MENU_ENTER_FULLSCREEN,20277,../../content/app/strings/content_strings.grd +IDS_MEDIA_OVERFLOW_MENU_EXIT_FULLSCREEN,20278,../../content/app/strings/content_strings.grd +IDS_MEDIA_OVERFLOW_MENU_STOP_CAST,20279,../../content/app/strings/content_strings.grd +IDS_MEDIA_OVERFLOW_MENU_MUTE,20280,../../content/app/strings/content_strings.grd +IDS_MEDIA_OVERFLOW_MENU_UNMUTE,20281,../../content/app/strings/content_strings.grd +IDS_MEDIA_OVERFLOW_MENU_PLAY,20282,../../content/app/strings/content_strings.grd +IDS_MEDIA_OVERFLOW_MENU_PAUSE,20283,../../content/app/strings/content_strings.grd +IDS_MEDIA_OVERFLOW_MENU_DOWNLOAD,20284,../../content/app/strings/content_strings.grd +IDS_MEDIA_REMOTING_DISABLE_TEXT,20285,../../content/app/strings/content_strings.grd +IDS_MEDIA_REMOTING_CAST_TEXT,20286,../../content/app/strings/content_strings.grd +IDS_MEDIA_REMOTING_CAST_TO_UNKNOWN_DEVICE_TEXT,20287,../../content/app/strings/content_strings.grd +IDS_MEDIA_TRACKS_NO_LABEL,20288,../../content/app/strings/content_strings.grd +IDS_MEDIA_TRACKS_OFF,20289,../../content/app/strings/content_strings.grd +IDS_PLUGIN_INITIALIZATION_ERROR,20290,../../content/app/strings/content_strings.grd +IDS_WEB_FONT_FAMILY,26903,../../ui/strings/app_locale_settings.grd +IDS_WEB_FONT_SIZE,26904,../../ui/strings/app_locale_settings.grd +IDS_AW_WEBPAGE_NOT_AVAILABLE,23510,../../android_webview/ui/aw_strings.grd +IDS_AW_WEBPAGE_CAN_NOT_BE_LOADED,23511,../../android_webview/ui/aw_strings.grd +IDS_AW_WEBPAGE_TEMPORARILY_DOWN,23512,../../android_webview/ui/aw_strings.grd +IDS_AW_WEBPAGE_TEMPORARILY_DOWN_SUGGESTIONS,23513,../../android_webview/ui/aw_strings.grd +IDS_AW_WEBPAGE_PARENTAL_PERMISSION_NEEDED,23514,../../android_webview/ui/aw_strings.grd
diff --git a/tools/binary_size/libsupersize/testdata/mock_output_directory/obj/base/base/page_allocator.o b/tools/binary_size/libsupersize/testdata/mock_output_directory/obj/base/base/page_allocator.o new file mode 100644 index 0000000..e7daba46 --- /dev/null +++ b/tools/binary_size/libsupersize/testdata/mock_output_directory/obj/base/base/page_allocator.o Binary files differ
diff --git a/tools/binary_size/libsupersize/testdata/mock_output_directory/obj/third_party/icu/icuuc/ucnv_ext.o b/tools/binary_size/libsupersize/testdata/mock_output_directory/obj/third_party/icu/icuuc/ucnv_ext.o new file mode 100644 index 0000000..47406ec --- /dev/null +++ b/tools/binary_size/libsupersize/testdata/mock_output_directory/obj/third_party/icu/icuuc/ucnv_ext.o Binary files differ
diff --git a/tools/binary_size/libsupersize/testdata/mock_toolchain/mock_cppfilt.py b/tools/binary_size/libsupersize/testdata/mock_toolchain/mock_cppfilt.py index e7448a9..0d903a0a 100644 --- a/tools/binary_size/libsupersize/testdata/mock_toolchain/mock_cppfilt.py +++ b/tools/binary_size/libsupersize/testdata/mock_toolchain/mock_cppfilt.py
@@ -31,6 +31,34 @@ 'aramRef<_jlongArray*> const&, int)::atomic_histogram_pointer'), '_ZN12_GLOBAL__N_135g_AnimationFrameTimeHistogram_clazzE': ( '(anonymous namespace)::g_AnimationFrameTimeHistogram_clazz'), + '_ZN5blink23ContiguousContainerBase11shrinkToFitEv': ( + 'blink::ContiguousContainerBase::shrinkToFit()'), + '_ZN5blink23ContiguousContainerBase11shrinkToFitEv2.part.1234.isra.2': ( + 'blink::ContiguousContainerBase::shrinkToFit() [clone .part.1234] ' + '[clone .isra.2]'), + '_ZN5blink23ContiguousContainerBaseC2EOS0_': ( + 'blink::ContiguousContainerBase::ContiguousContainerBase(' + 'blink::ContiguousContainerBase&&)'), + '_ZN5blink12PaintChunker18releasePaintChunksEv': ( + 'blink::PaintChunker::releasePaintChunks()'), + '_ZN10_GLOBAL__N5blink12PaintChunker18releasePaintChunksEv.part.1': ( + '(anonymous namespace)::blink::PaintChunker::releasePaintChunks() ' + '[clone .part.1]'), + '_ZN6chrome5mojom11FilePatcher5Name_E': 'chrome::mojom::FilePatcher::Name_', + '_ZTV18ChromeMainDelegate': 'vtable for ChromeMainDelegate', + '_ZTVN6chrome5mojom34FieldTrialRecorderRequestValidatorE': ( + 'vtable for chrome::mojom::FieldTrialRecorder'), + '_ZTVN6chrome5mojom23FieldTrialRecorderProxyE': ( + 'vtable for chrome::mojom::FieldTrialRecorderProxy'), + ('_ZZN10_GLOBAL__N5blink20CSSValueKeywordsHash13findValueImplEPKcjE15value_' + 'word_list'): ('(anonymous namespace)::blink::CSSValueKeywordsHash::' + 'findValueImpl(char const*, unsigned int)::value_word_list'), + '_ZTV25ChromeMainDelegateAndroid': 'vtable for ChromeMainDelegateAndroid', + '_ZTVN4mojo15MessageReceiverE': 'vtable for mojo::MessageReceiver', + '_ZN6google8protobuf8internal19pLinuxKernelCmpxchgE': ( + 'google::protobuf::internal::pLinuxKernelCmpxchg'), + '_ZN6google8protobuf8internal25pLinuxKernelMemoryBarrierE': ( + 'google::protobuf::internal::pLinuxKernelMemoryBarrier'), }
diff --git a/tools/binary_size/libsupersize/testdata/mock_toolchain/mock_nm.py b/tools/binary_size/libsupersize/testdata/mock_toolchain/mock_nm.py index 9472569..6b805b1 100644 --- a/tools/binary_size/libsupersize/testdata/mock_toolchain/mock_nm.py +++ b/tools/binary_size/libsupersize/testdata/mock_toolchain/mock_nm.py
@@ -14,11 +14,11 @@ 002a0010 t {} 0028d900 t startup._GLOBAL__sub_I_page_allocator.cc 002a0010 t FooAlias() -002b6bb8 t $t +002b6bb8 t $t.23 002a0010 t BarAlias() 002a0000 t blink::ContiguousContainerBase::shrinkToFit() 002a0000 t BazAlias(bool) -002b6bb8 t $t +002b6bb8 t $t.22 """.format(_SHRINK_TO_FIT_CLONE) _SHRINK_TO_FIT = ('blink::ContiguousContainerBase::shrinkToFit() ' @@ -29,6 +29,9 @@ '01010101 t _GLOBAL__sub_I_SkDeviceProfile.cpp', '01010101 t foo_bar', '002a0000 t BazAlias(bool)', + '00000000 r .L.str', + '00000005 r .L.str.1', + '01010101 r vtable for ChromeMainDelegate', '01010101 r vtable for ChromeMainDelegate', '01010101 r vtable for chrome::mojom::FieldTrialRecorder', ('01010101 t ucnv_extMatchFromU(int const*, int, unsigned short const*,' @@ -62,7 +65,7 @@ '01010101 t _GLOBAL__sub_I_page_allocator.cc', '01010101 t _GLOBAL__sub_I_bbr_sender.cc', '01010101 t _GLOBAL__sub_I_pacing_sender.cc', - '01010101 t _GLOBAL__sub_I_bbr_sender.cc', + '00000000 r .L.str', '01010101 t extFromUUseMapping(aj, int)', '01010101 t extFromUUseMapping(signed char, unsigned int, int)', '01010101 t Name', @@ -101,7 +104,7 @@ if path.endswith(os.path.join('mock_output_directory', 'elf')): sys.stdout.write(_ELF_OUTPUT) else: - lines = _OBJECT_OUTPUTS.get(path) + lines = _OBJECT_OUTPUTS.get(os.path.normpath(path)) assert lines, 'No mock_nm.py entry for: ' + path sys.stdout.write('\n'.join(lines)) sys.stdout.write('\n')
diff --git a/tools/binary_size/libsupersize/testdata/mock_toolchain/mock_readelf.py b/tools/binary_size/libsupersize/testdata/mock_toolchain/mock_readelf.py index ccfa532f..e770cf78 100644 --- a/tools/binary_size/libsupersize/testdata/mock_toolchain/mock_readelf.py +++ b/tools/binary_size/libsupersize/testdata/mock_toolchain/mock_readelf.py
@@ -2,6 +2,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import os import sys @@ -44,7 +45,7 @@ [10] .rel.plt REL 0029fbec 29fbec 000b00 08 A 3 0 4 [11] .plt PROGBITS 002a06ec 2a06ec 001094 00 AX 0 0 4 [12] .text PROGBITS 002a1780 2a1780 223cd28 00 AX 0 0 64 - [13] .rodata PROGBITS 02605000 2605000 5a72e4 00 A 0 0 256 + [13] .rodata PROGBITS 0266e5f0 000084 5a72e4 00 A 0 0 256 [14] .ARM.exidx ARM_EXIDX 02bd3d10 2bd3d10 1771c8 08 AL 12 0 4 [15] .ARM.extab PROGBITS 02bd5858 2bd5858 02cd50 00 A 0 0 4 [16] .data.rel.ro.local PROGBITS 02bdac40 2bd9c40 0c0e08 00 WA 0 0 16 @@ -77,9 +78,146 @@ GNU 0x00000009\tNT_GNU_GOLD_VERSION (gold version) """ +_OBJECT_OUTPUTS = { + 'obj/third_party/icu/icuuc/ucnv_ext.o': """\ +There are 71 section headers, starting at offset 0x3114: + +Section Headers: + [Nr] Name Type Addr Off Size ES Flg Lk Inf Al + [ 0] NULL 00000000 000000 000000 00 0 0 0 + [ 1] .strtab STRTAB 00000000 0029ac 000765 00 0 0 1 + [ 2] .text PROGBITS 00000000 000034 000000 00 AX 0 0 4 + [ 3] .text.ucnv_extIni PROGBITS 00000000 000034 0000c6 00 AX 0 0 2 + [ 4] .rel.text.ucnv_ex REL 00000000 0023f4 000010 08 70 3 4 + [ 5] .ARM.exidx.text.u ARM_EXIDX 00000000 0000fc 000008 00 AL 3 0 4 + [60] .rodata.str1.1 PROGBITS 00000000 000015 000015 01 AMS 0 0 1 + [56] .debug_str PROGBITS 00000000 000c50 0003c5 01 MS 0 0 1 + [57] .debug_abbrev PROGBITS 00000000 001015 0000a1 00 0 0 1 + [58] .debug_info PROGBITS 00000000 0010b6 000151 00 0 0 1 + [59] .rel.debug_info REL 00000000 002544 0001e8 08 70 58 4 + [60] .debug_ranges PROGBITS 00000000 001207 0000b0 00 0 0 1 + [61] .rel.debug_ranges REL 00000000 00272c 000130 08 70 60 4 + [62] .debug_macinfo PROGBITS 00000000 0012b7 000001 00 0 0 1 + [63] .comment PROGBITS 00000000 0012b8 000024 01 MS 0 0 1 + [64] .note.GNU-stack PROGBITS 00000000 0012dc 000000 00 0 0 1 + [65] .ARM.attributes ARM_ATTRIBUTES 00000000 0012dc 00003c 00 0 0 1 + [66] .debug_frame PROGBITS 00000000 001318 0001e4 00 0 0 4 + [67] .rel.debug_frame REL 00000000 00285c 0000e0 08 70 66 4 + [68] .debug_line PROGBITS 00000000 0014fc 000965 00 0 0 1 + [69] .rel.debug_line REL 00000000 00293c 000070 08 70 68 4 + [70] .symtab SYMTAB 00000000 001e64 000590 10 1 74 4 +Key to Flags: + W (write), A (alloc), X (execute), M (merge), S (strings) + I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown) + O (extra OS processing required) o (OS specific), p (processor specific) +""", + 'obj/third_party/WebKit.a': """\ + +File: obj/third_party/WebKit.a(PaintChunker.o) +There are 68 section headers, starting at offset 0x5650: + +Section Headers: + [Nr] Name Type Addr Off Size ES Flg Lk Inf Al + [ 0] NULL 00000000 000000 000000 00 0 0 0 +Key to Flags: + W (write), A (alloc), X (execute), M (merge), S (strings) + I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown) + O (extra OS processing required) o (OS specific), p (processor specific) + +File: obj/third_party/WebKit.a(ContiguousContainer.o) +There are 68 section headers, starting at offset 0x5650: + +Section Headers: + [Nr] Name Type Addr Off Size ES Flg Lk Inf Al + [ 0] NULL 00000000 000000 000000 00 0 0 0 +Key to Flags: + W (write), A (alloc), X (execute), M (merge), S (strings) + I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown) + O (extra OS processing required) o (OS specific), p (processor specific) +""", + 'obj/base/base/page_allocator.o': """\ +There are 68 section headers, starting at offset 0x5650: + +Section Headers: + [Nr] Name Type Addr Off Size ES Flg Lk Inf Al + [ 0] NULL 00000000 000000 000000 00 0 0 0 + [ 1] .rodata.str1.1 PROGBITS 00000000 000015 000005 01 AMS 0 0 1 +""", + 'obj/third_party/ffmpeg/libffmpeg_internal.a': """\ + +File: obj/third_party/ffmpeg/libffmpeg_internal.a(fft_float.o) +There are 68 section headers, starting at offset 0x5650: + +Section Headers: + [Nr] Name Type Addr Off Size ES Flg Lk Inf Al + [ 0] NULL 00000000 000000 000000 00 0 0 0 + [ 1] .rodata.str1.1 PROGBITS 00000000 000015 000005 01 AMS 0 0 1 +Key to Flags: + W (write), A (alloc), X (execute), M (merge), S (strings) + I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown) + O (extra OS processing required) o (OS specific), p (processor specific) + +File: obj/third_party/ffmpeg/libffmpeg_internal.a(fft_fixed.o) +There are 68 section headers, starting at offset 0x5650: + +Section Headers: + [Nr] Name Type Addr Off Size ES Flg Lk Inf Al + [ 0] NULL 00000000 000000 000000 00 0 0 0 +Key to Flags: + W (write), A (alloc), X (execute), M (merge), S (strings) + I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown) + O (extra OS processing required) o (OS specific), p (processor specific) +""", + '../../third_party/gvr-android-sdk/libgvr_shim_static_arm.a': """\ + +File: ../../third_party/gvr-android-sdk/libgvr_shim_static_arm.a(\ +libcontroller_api_impl.a_controller_api_impl.o) +There are 68 section headers, starting at offset 0x5650: + +Section Headers: + [Nr] Name Type Addr Off Size ES Flg Lk Inf Al + [ 0] NULL 00000000 000000 000000 00 0 0 0 +Key to Flags: + W (write), A (alloc), X (execute), M (merge), S (strings) + I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown) + O (extra OS processing required) o (OS specific), p (processor specific) + +File: ../../third_party/gvr-android-sdk/libgvr_shim_static_arm.a(\ +libport_android_jni.a_jni_utils.o) +There are 68 section headers, starting at offset 0x5650: + +Section Headers: + [Nr] Name Type Addr Off Size ES Flg Lk Inf Al + [ 0] NULL 00000000 000000 000000 00 0 0 0 +Key to Flags: + W (write), A (alloc), X (execute), M (merge), S (strings) + I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown) + O (extra OS processing required) o (OS specific), p (processor specific) +""", +} + +def _PrintHeader(path): + sys.stdout.write('\n') + sys.stdout.write('File: ' + path + '\n') + + +def _PrintOutput(path): + payload = _OBJECT_OUTPUTS.get(os.path.normpath(path)) + assert payload, 'No mock_nm.py entry for: ' + path + sys.stdout.write(payload) + sys.stdout.write('\n') + def main(): - if sys.argv[1] == '-h': + paths = [p for p in sys.argv[1:] if not p.startswith('-')] + if paths[0].endswith('.o') or paths[0].endswith('.a'): + if len(paths) > 1: + for path in paths: + _PrintHeader(path) + _PrintOutput(path) + else: + _PrintOutput(paths[0]) + elif sys.argv[1] == '-h': sys.stdout.write(_HEADERS) elif sys.argv[1] == '-S': sys.stdout.write(_SECTIONS)
diff --git a/tools/binary_size/libsupersize/testdata/test.map b/tools/binary_size/libsupersize/testdata/test.map index 890e80e5..a855747 100644 --- a/tools/binary_size/libsupersize/testdata/test.map +++ b/tools/binary_size/libsupersize/testdata/test.map
@@ -84,22 +84,22 @@ .text._ZL18extFromUUseMapping2aji 0xffffffffffffffff 0x20 obj/base/base/page_allocator.o .text._ZL18ucnv_extMatchFromUPKiiPKtiS2_iPjaa - 0x0028f000 0x1c0 obj/third_party/icu/icuuc/ucnv_ext.o + 0x0028f000 0x1c0 ./obj/third_party/icu/../icu/icuuc/ucnv_ext.o .text.startup._GLOBAL__sub_I_SkDeviceProfile.cpp - 0x0028f1c8 0x14 obj/third_party/icu/icuuc/ucnv_ext.o + 0x0028f1c8 0x14 ./obj/third_party/icu/../icu/icuuc/ucnv_ext.o .text.unlikely.foo_bar - 0x0028f1e0 0x10e00 obj/third_party/icu/icuuc/ucnv_ext.o + 0x0028f1e0 0x10e00 ./obj/third_party/icu/../icu/icuuc/ucnv_ext.o .text._ZN5blink23ContiguousContainerBase11shrinkToFitEv 0x002a0000 0x10 obj/third_party/WebKit.a(PaintChunker.o) 0x002a0001 blink::ContiguousContainerBase::shrinkToFit() - .text._ZN5blink23ContiguousContainerBase11shrinkToFitEv2 + .text.hot._ZN5blink23ContiguousContainerBase11shrinkToFitEv2.part.1234.isra.2 0x002a0010 0xc obj/third_party/WebKit.a(PaintChunker.o) - 0x002a0011 blink::ContiguousContainerBase::shrinkToFit() [clone .part.1234] [clone .isra.2] + 0x002a0011 blink::ContiguousContainerBase::shrinkToFit() .text._ZN5blink23ContiguousContainerBaseC2EOS0_ 0xffffffffffffffff 0x18 obj/third_party/WebKit.a(ContiguousContainer.o) 0x002a0021 blink::ContiguousContainerBase::ContiguousContainerBase(blink::ContiguousContainerBase&&) 0x002a0021 blink::ContiguousContainerBase::ContiguousContainerBase(blink::ContiguousContainerBase&&) - .text._ZN5blink12PaintChunker18releasePaintChunksEv + .text._ZN10_GLOBAL__N5blink12PaintChunker18releasePaintChunksEv.part.1 0x002a1000 0x5e obj/third_party/WebKit.a(ContiguousContainer.o) 0x002a1001 (anonymous namespace)::blink::PaintChunker::releasePaintChunks() [clone .part.1] @@ -113,7 +113,9 @@ .rodata 0x0266e600 0x5a72e4 ** merge strings - 0x0266e600 0x1df000 + 0x0266e600 0x20 + ** merge strings + 0x0266e630 0x10 ** merge constants 0x0284d600 0xd61 .rodata 0x0284e364 0x8 obj/base/base/page_allocator.o @@ -123,21 +125,19 @@ .rodata._ZN6chrome5mojom11FilePatcher5Name_E 0x0284e398 0x20 obj/third_party/WebKit.a(ContiguousContainer.o) 0x0284e398 chrome::mojom::FilePatcher::Name_ - ** merge strings - 0x0284e518 0xa4f31 .rodata._ZN12_GLOBAL__N_1L37kAnimationFrameTimeHistogramClassPathE 0x028f3450 0x30 obj/third_party/WebKit.a(PaintChunker.o) - .rodata._ZZN5blink20CSSValueKeywordsHash13findValueImplEPKcjE15value_word_list + .rodata._ZZN10_GLOBAL__N5blink20CSSValueKeywordsHash13findValueImplEPKcjE15value_word_list 0x028f3480 0x4 obj/third_party/WebKit.a(PaintChunker.o) 0x028f3480 blink::(anonymous namespace)::CSSValueKeywordsHash::findValueImpl(char const*, unsigned int)::value_word_list .data.rel.ro.local 0x02c176f0 0xc0e08 .data.rel.ro.local._ZTV18ChromeMainDelegate - 0x02c176f0 0x38 obj/third_party/icu/icuuc/ucnv_ext.o + 0x02c176f0 0x38 ./obj/third_party/icu/../icu/icuuc/ucnv_ext.o 0x02c176f0 vtable for ChromeMainDelegate .data.rel.ro.local._ZTVN6chrome5mojom34FieldTrialRecorderRequestValidatorE - 0x02c17728 0x18 obj/third_party/icu/icuuc/ucnv_ext.o + 0x02c17728 0x18 ./obj/third_party/icu/../icu/icuuc/ucnv_ext.o 0x02c17728 vtable for chrome::mojom::FieldTrialRecorder .data.rel.ro.local._ZTVN6chrome5mojom23FieldTrialRecorderProxyE 0x02c17740 0xc0d90 obj/third_party/WebKit.a(ContiguousContainer.o) @@ -162,8 +162,8 @@ .init_array 0x02ddc60c 0x4 obj/base/base/page_allocator.o .fini_array 0x02ddc6f4 0x8 - .fini_array 0x02ddc6f4 0x4 ../../third_party/android_tools/ndk/platforms/android-16/arch-arm/usr/lib/crtbegin_so.o - .fini_array 0x02ddc6f8 0x4 ../../third_party/android_tools/ndk/platforms/android-16/arch-arm/usr/lib/crtend_so.o + .fini_array 0x02ddc6f4 0x4 ../../third_party/android_ndk/platforms/android-16/arch-arm/usr/lib/crtbegin_so.o + .fini_array 0x02ddc6f8 0x4 ../../third_party/android_ndk/platforms/android-16/arch-arm/usr/lib/crtend_so.o .dynamic 0x02ddc6fc 0x130 ** dynamic 0x02ddc6fc 0x130 @@ -190,12 +190,12 @@ .bss 0x02dffda0 0x13d7e8 .bss.g_chrome_content_browser_client - 0x02dffda0 0x1c obj/third_party/icu/icuuc/ucnv_ext.o + 0x02dffda0 0x1c ./obj/third_party/icu/../icu/icuuc/ucnv_ext.o 0x02dffda0 g_chrome_content_browser_client .bss._ZZL13SaveHistogramP7_JNIEnvRKN4base7android12JavaParamRefIP8_jobjectEERKNS3_IP8_jstringEERKNS3_IP11_jlongArrayEEiE24atomic_histogram_pointer - 0x02dffe80 0x4 obj/third_party/icu/icuuc/ucnv_ext.o + 0x02dffe80 0x4 ./obj/third_party/icu/../icu/icuuc/ucnv_ext.o .bss._ZN12_GLOBAL__N_135g_AnimationFrameTimeHistogram_clazzE - 0x02dffe84 0x4 obj/third_party/icu/icuuc/ucnv_ext.o + 0x02dffe84 0x4 ./obj/third_party/icu/../icu/icuuc/ucnv_ext.o ** common 0x02e2fca0 0x10d8e8 .note.gnu.gold-version
diff --git a/tools/bisect-builds.py b/tools/bisect-builds.py index 588c811e3..b3feeb1 100755 --- a/tools/bisect-builds.py +++ b/tools/bisect-builds.py
@@ -72,6 +72,7 @@ ############################################################################### +import glob import httplib import json import optparse @@ -531,6 +532,24 @@ pass +def CopyMissingFileFromCurrentSource(src_glob, dst): + """Work around missing files in archives. + This happens when archives of Chrome don't contain all of the files + needed to build it. In many cases we can work around this using + files from the current checkout. The source is in the form of a glob + so that it can try to look for possible sources of the file in + multiple locations, but we just arbitrarily try the first match. + + Silently fail if this doesn't work because we don't yet have clear + markers for builds that require certain files or a way to test + whether or not launching Chrome succeeded. + """ + if not os.path.exists(dst): + matches = glob.glob(src_glob) + if matches: + shutil.copy2(matches[0], dst) + + def RunRevision(context, revision, zip_file, profile, num_runs, command, args): """Given a zipped revision, unzip it and run the test.""" print 'Trying revision %s...' % str(revision) @@ -540,17 +559,13 @@ tempdir = tempfile.mkdtemp(prefix='bisect_tmp') UnzipFilenameToDir(zip_file, tempdir) - # Hack: Chrome OS archives are missing icudtl.dat; try to copy it from - # the local directory. + # Hack: Some Chrome OS archives are missing some files; try to copy them + # from the local directory. if context.platform == 'chromeos': - if not os.access('%s/chrome-linux/icudtl.dat' % tempdir, os.F_OK): - icudtl_path = 'third_party/icu/common/icudtl.dat' - if not os.access(icudtl_path, os.F_OK): - print 'Couldn\'t find: ' + icudtl_path - print ('The path might have changed. Please look for the data under ' - 'third_party/icu and update bisect-build.py') - sys.exit() - os.system('cp %s %s/chrome-linux/' % (icudtl_path, tempdir)) + CopyMissingFileFromCurrentSource('third_party/icu/common/icudtl.dat', + '%s/chrome-linux/icudtl.dat' % tempdir) + CopyMissingFileFromCurrentSource('*out*/*/libminigbm.so', + '%s/chrome-linux/libminigbm.so' % tempdir) os.chdir(tempdir)
diff --git a/tools/bisect-manual-test.py b/tools/bisect-manual-test.py deleted file mode 100755 index c1b6329..0000000 --- a/tools/bisect-manual-test.py +++ /dev/null
@@ -1,53 +0,0 @@ -#!/usr/bin/env python -# 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. - -"""Simple script which asks user to manually check result of bisection. - -Typically used as by the run-bisect-manual-test.py script. -""" - -import os -import sys - -sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), - 'perf')) -from chrome_telemetry_build import chromium_config -sys.path.append(chromium_config.GetTelemetryDir()) - -from telemetry.internal.browser import browser_finder -from telemetry.internal.browser import browser_options - - -def _StartManualTest(options): - """Start browser then ask the user whether build is good or bad.""" - browser_to_create = browser_finder.FindBrowser(options) - print 'Starting browser: %s.' % options.browser_type - with browser_to_create.Create(options) as _: - # Loop until we get a response that we can parse. - while True: - sys.stderr.write('Revision is [(g)ood/(b)ad]: ') - response = raw_input() - if response and response in ('g', 'b'): - if response in ('g'): - print 'RESULT manual_test: manual_test= 1' - else: - print 'RESULT manual_test: manual_test= 0' - break - - -def main(): - usage = ('%prog [options]\n' - 'Starts browser with an optional url and asks user whether ' - 'revision is good or bad.\n') - - options = browser_options.BrowserFinderOptions() - parser = options.CreateParser(usage) - options, _ = parser.parse_args() - - _StartManualTest(options) - - -if __name__ == '__main__': - sys.exit(main())
diff --git a/tools/cfi/OWNERS b/tools/cfi/OWNERS index ba0dc32..aaa8fa9c6 100644 --- a/tools/cfi/OWNERS +++ b/tools/cfi/OWNERS
@@ -1,2 +1,2 @@ -krasin@chromium.org +eugenis@chromium.org pcc@chromium.org
diff --git a/tools/cfi/blacklist.txt b/tools/cfi/blacklist.txt index 8241a054..4f6fa1f 100644 --- a/tools/cfi/blacklist.txt +++ b/tools/cfi/blacklist.txt
@@ -1,5 +1,4 @@ -# TODO(thakis): Remove clang is past r310132, works around r309617. -type:std::* +[cfi-unrelated-cast|cfi-derived-cast] # e.g. RolloverProtectedTickClock fun:*MutableInstance* @@ -13,11 +12,16 @@ # Mesa contains several bad casts. src:*third_party/mesa* +# LLVM's allocator +src:*llvm/Support/Allocator.h + # Deliberate bad cast to derived class to hide functions. type:*BlockIUnknownMethods* type:*BlockRefType* type:*SkAutoTUnref* type:*SkBlockComRef* +type:*RemoveIUnknown* +src:*atlcomcli.h # invalid downcasts for IPC messages # https://crbug.com/520760 @@ -26,15 +30,11 @@ # src/base/win/event_trace_provider_unittest.cc type:*EtwTraceProvider* -# These classes are used to communicate between chrome.exe and -# chrome_child.dll (see src/sandbox/win/src/sandbox.h, -# src/chrome/app/chrome_main.cc). -type:sandbox::BrokerServices -type:sandbox::TargetPolicy -type:sandbox::TargetServices +# b/64003142 +fun:*internal_default_instance* -# Likewise (base/win/scoped_handle.cc). -type:*ActiveVerifier* +# CAtlArray<T> casts to uninitialized T*. +src:*atlcoll.h ############################################################################# # Base class's constructor accesses a derived class. @@ -59,14 +59,11 @@ # so exclude source file for now. src:*LifecycleObserver.h* -# Blink wtf::Vector cast on non-initialized data -# https://crbug.com/568891 -src:*wtf/Vector.h* -src:*wtf/PartitionAllocator.h* - ############################################################################# # Methods disabled due to perf considerations. +[cfi-vcall] + # Skia # https://crbug.com/638056#c1 @@ -111,5 +108,94 @@ fun:*supportsCachedOffsets* fun:*traceImpl* -# b/64003142 -fun:*internal_default_instance* +############################################################################# +# Cross-DSO vcalls + +[cfi-vcall|cfi-unrelated-cast|cfi-derived-cast] + +# These classes are used to communicate between chrome.exe and +# chrome_child.dll (see src/sandbox/win/src/sandbox.h, +# src/chrome/app/chrome_main.cc). +type:sandbox::BrokerServices +type:sandbox::TargetPolicy +type:sandbox::TargetServices + +############################################################################# +# Disabled indirect calls + +[cfi-icall] + +######### Cross-DSO icalls using dynamically resolved symbols + +# ANGLE +src:*third_party/angle/src/libANGLE/* +src:*third_party/angle/src/third_party/libXNVCtrl/NVCtrl.c +# third_party/angle/src/gpu_info_util/SystemInfo_libpci.cpp +fun:*GetPCIDevicesWithLibPCI* +# third_party/angle/src/common/event_tracer.cpp +fun:*GetTraceCategoryEnabledFlag* +fun:*AddTraceEvent* + +# PPAPI +src:*ppapi/* +src:*content/renderer/pepper* +fun:*PpapiThread* +fun:*BrokerProcessDispatcher* +# ppapi code uses base::Callback to call into libppappi_test.so. +# base/bind_internal.h +fun:*FunctorTraits* + +# Calls to auto-generated stubs by generate_stubs.py +src:*audio/pulse/pulse_stubs.cc + +# Calls to auto-generated stubs by generate_library_loader.py +src:*device/udev_linux/udev1_loader.cc +src:*net/proxy_resolution/proxy_config_service_linux.cc + +# Calls to auto-generated stubs by ui/gl/generate_bindings.py +src:*ui/gl/gl_bindings_autogen_* + +src:*components/os_crypt/* +src:*chrome/browser/password_manager/native_backend_libsecret* + +src:*content/browser/accessibility/browser_accessibility_auralinux.cc +src:*ui/accessibility/platform/ax_platform_node_auralinux.cc +src:*ui/accessibility/platform/ax_platform_atk_hyperlink.cc + +src:*chrome/browser/ui/zoom/chrome_zoom_level_prefs.cc +src:*third_party/webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.cc +src:*media/cdm/* +src:*third_party/swiftshader/* +src:*base/native_library_unittest.cc + +# chrome/browser/ui/views/frame/global_menu_bar_x11.cc +fun:*GlobalMenuBarX11* + +# third_party/skia/include/gpu/gl/GrGLFunctions.h +fun:*GrGLFunction* + +######### Function pointers cast to incorrect type signatures + +# libicu is currently compiled such that in libicu the 'UChar' type is a +# defined as a char16_t internally, but for the rest of chromium it's an +# unsigned short, causing mismatched type signatures for icalls to/from icu +src:*third_party/icu/source/common/* +src:*third_party/WebKit/Source/platform/wtf/* +# v8/src/intl.cc +fun:*LocaleConvertCase* + +# Casts away const qualifier +# third_party/boringssl/src/crypto/pem/pem_lib.c +fun:*PEM_ASN1_write* + +src:*third_party/sqlite/* + +# PropertyCallbackArguments::Call methods cast function pointers +src:*v8/src/api-arguments-inl.h + +# v8 callback that casts argument template parameters +fun:*PendingPhantomCallback*Invoke* + +######### Uncategorized + +src:*native_client/*
diff --git a/tools/cfi/blacklist_android.txt b/tools/cfi/blacklist_android.txt new file mode 100644 index 0000000..0f0e4ff --- /dev/null +++ b/tools/cfi/blacklist_android.txt
@@ -0,0 +1,4 @@ +# The Android port links against a prebuilt libc++.a from the NDK, and also +# links a prebuilt .a from third_party/gvr-android-sdk that uses libc++, so we +# cannot apply CFI to the standard library yet. +type:std::*
diff --git a/tools/check_grd_for_unused_strings.py b/tools/check_grd_for_unused_strings.py index 21afc8a..7e5e919 100755 --- a/tools/check_grd_for_unused_strings.py +++ b/tools/check_grd_for_unused_strings.py
@@ -119,7 +119,7 @@ src_dirs = [] grd_files = [] for arg in sys.argv[1:]: - if arg.lower().endswith('.grd'): + if arg.lower().endswith('.grd') or arg.lower().endswith('.grdp'): grd_files.append(arg) else: src_dirs.append(arg)
diff --git a/tools/checkbins/checkbins.py b/tools/checkbins/checkbins.py index 98eef13..767f2350 100755 --- a/tools/checkbins/checkbins.py +++ b/tools/checkbins/checkbins.py
@@ -29,8 +29,10 @@ # Please do not add your file here without confirming that it indeed doesn't # require /NXCOMPAT and /DYNAMICBASE. Contact cpu@chromium.org or your local # Windows guru for advice. -EXCLUDED_FILES = ['mini_installer.exe', - 'next_version_mini_installer.exe' +EXCLUDED_FILES = [ + 'crashpad_util_test_process_info_test_child.exe', + 'mini_installer.exe', + 'next_version_mini_installer.exe', ] def IsPEFile(path):
diff --git a/tools/checklicenses/OWNERS b/tools/checklicenses/OWNERS index 2abfa66e..1967bf5 100644 --- a/tools/checklicenses/OWNERS +++ b/tools/checklicenses/OWNERS
@@ -1,3 +1 @@ -set noparent -phajdan.jr@chromium.org thestig@chromium.org
diff --git a/tools/checklicenses/checklicenses.py b/tools/checklicenses/checklicenses.py index ecd2a15..d804303 100755 --- a/tools/checklicenses/checklicenses.py +++ b/tools/checklicenses/checklicenses.py
@@ -9,6 +9,7 @@ import json import optparse import os.path +import re import subprocess import sys @@ -119,11 +120,6 @@ 'UNKNOWN', ], - # http://code.google.com/p/google-breakpad/issues/detail?id=450 - 'breakpad/src': [ - 'UNKNOWN', - ], - 'buildtools/third_party/libc++/trunk/test': [ # http://llvm.org/bugs/show_bug.cgi?id=25980 'UNKNOWN', @@ -186,6 +182,11 @@ 'UNKNOWN', ], + # https://crbug.com/google-breakpad/450 + 'third_party/breakpad/breakpad': [ + 'UNKNOWN', + ], + # http://crbug.com/603946 # https://github.com/google/oauth2client/issues/331 # Just imports googleapiclient. Chromite is not shipped. @@ -426,14 +427,16 @@ 'UNKNOWN', ], + # The following files have a special license. + 'third_party/libovr/src': [ + 'UNKNOWN', + ], + # The following files lack license headers, but are trivial. 'third_party/libusb/src/libusb/os/poll_posix.h': [ 'UNKNOWN', ], - 'third_party/libvpx/source': [ # http://crbug.com/98319 - 'UNKNOWN', - ], 'third_party/libxml': [ 'UNKNOWN', ], @@ -602,6 +605,10 @@ 'tools/gyp/test': [ 'UNKNOWN', ], + # Perf test data from Google Maps team. Not shipped. + 'tools/perf/page_sets/maps_perf_test': [ + 'UNKNOWN', + ], 'tools/python/google/__init__.py': [ 'UNKNOWN', ], @@ -646,17 +653,13 @@ EXCLUDED_PATHS = [ # Don't check generated files - 'out/', + re.compile('^out/'), # Don't check downloaded goma client binaries - 'build/goma/client/', + re.compile('^build/goma/client/'), # Don't check sysroot directories - 'build/linux/debian_jessie_arm64-sysroot/', - 'build/linux/debian_jessie_amd64-sysroot/', - 'build/linux/debian_jessie_arm-sysroot/', - 'build/linux/debian_jessie_i386-sysroot/', - 'build/linux/debian_jessie_mips-sysroot/', + re.compile('^build/linux/.+-sysroot/'), ] @@ -708,7 +711,7 @@ filename = os.path.relpath(filename.strip(), options.base_directory) # Check if the file belongs to one of the excluded paths. - if any((filename.startswith(path) for path in EXCLUDED_PATHS)): + if any((pattern.match(filename) for pattern in EXCLUDED_PATHS)): continue # For now we're just interested in the license.
diff --git a/tools/checkperms/checkperms.py b/tools/checkperms/checkperms.py index 81c2cf5..f1b44b71 100755 --- a/tools/checkperms/checkperms.py +++ b/tools/checkperms/checkperms.py
@@ -440,6 +440,10 @@ '--file', action='append', dest='files', help='Specifics a list of files to check the permissions of. Only these ' 'files will be checked') + parser.add_option( + '--file-list', + help='Specifies a file with a list of files (one per line) to check the ' + 'permissions of. Only these files will be checked') parser.add_option('--json', help='Path to JSON output file') options, args = parser.parse_args() @@ -449,11 +453,18 @@ if len(args) > 1: parser.error('Too many arguments used') + if options.files and options.file_list: + parser.error('--file and --file-list are mutually exclusive options') + if options.root: options.root = os.path.abspath(options.root) if options.files: errors = check_files(options.root, options.files) + elif options.file_list: + with open(options.file_list) as file_list: + files = file_list.read().splitlines() + errors = check_files(options.root, files) else: api = get_scm(options.root, options.bare) start_dir = args[0] if args else api.root_dir
diff --git a/tools/chrome_extensions/chromium_code_coverage/js/app.js b/tools/chrome_extensions/chromium_code_coverage/js/app.js deleted file mode 100644 index 322c3098..0000000 --- a/tools/chrome_extensions/chromium_code_coverage/js/app.js +++ /dev/null
@@ -1,420 +0,0 @@ -// Copyright 2015 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. - -/** - * @fileoverview Main module for the Chromium Code Coverage extension. This - * extension adds incremental and absolute code coverage stats - * to the deprecated Rietveld UI. Stats are added inline with - * file names as percentage of lines covered. - */ - - var coverage = coverage || {}; - -/** - * Contains all required configuration information. - * - * @type {Object} - * @const - */ -coverage.CONFIG = {}; - -/** - * URLs necessary for each project. These are necessary because the Rietveld - * sites are used by other projects as well, and is is only possible to find - * coverage stats for the projects registered here. - * - * @type {Object} - * @const - */ -coverage.CONFIG.COVERAGE_REPORT_URLS = { - 'Android': { - prefix: 'https://build.chromium.org/p/tryserver.chromium.linux/builders/' + - 'android_coverage/builds/', - suffix: '/steps/Incremental%20coverage%20report/logs/json.output', - botUrl: 'http://build.chromium.org/p/tryserver.chromium.linux/builders/' + - 'android_coverage' - }, - 'iOS': { - prefix: 'https://uberchromegw.corp.google.com/i/internal.bling.tryserver/' + - 'builders/coverage/builds/', - suffix: '/steps/coverage/logs/json.output', - botUrl: 'https://uberchromegw.corp.google.com/i/internal.bling.tryserver/' + - 'builders/coverage' - } -}; - -/** - * URLs where Rietveld apps are served. URLs should be escaped properly so that - * they are ready to be used in regular expressions. - * - * @type {Array.<string>} - */ -coverage.CONFIG.CODE_REVIEW_URLS = [ - 'https:\\/\\/codereview\\.chromium\\.org', - 'https:\\/\\/chromereviews\\.googleplex\\.com' -]; - -/** - * String representing absolute coverage. - * - * @type {string} - * @const -*/ -coverage.ABSOLUTE_COVERAGE = 'absolute'; - -/** - * String representing incremental coverage. - * - * @type {string} - * @const -*/ -coverage.INCREMENTAL_COVERAGE = 'incremental'; - -/** - * String representing patch incremental coverage. - * - * @type {string} - * @const - */ -coverage.PATCH_COVERAGE = 'patch'; - -/** - * Fetches detailed coverage stats for a given patch set and injects them into - * the code review page. - * - * @param {Element} patchElement Div containing a single patch set. - * @param {string} botUrl Location of the detailed coverage bot results. - * @param {string} projectName The name of project to which code was submitted. - */ -coverage.injectCoverageStats = function(patchElement, botUrl, projectName) { - var buildNumber = botUrl.split('/').pop(); - var patch = new coverage.PatchSet(projectName, buildNumber); - patch.getCoverageData(function(patchStats) { - coverage.updateUi(patchStats, patchElement, patch.getCoverageReportUrl()); - }); -}; - -/** - * Adds coverage stats to the table containing files changed for a given patch. - * - * @param {Object} patchStats Object containing stats for a given patch set. - * @param {Element} patchElement Div containing a patch single set. - * @param {string} reportUrl Location of the detailed coverage stats for this - * patch. - */ -coverage.updateUi = function(patchStats, patchElement, reportUrl) { - // Add absolute and incremental coverage column headers. - var patchSetTableBody = patchElement.getElementsByTagName('tbody')[0]; - var headerRow = patchSetTableBody.firstElementChild; - coverage.appendElementBeforeChild(headerRow, 'th', 'ΔCov.', 1); - coverage.appendElementBeforeChild(headerRow, 'th', '|Cov.|', 1); - - // Add absolute and incremental coverage stats for each file. - var fileRows = patchElement.querySelectorAll('[name=patch]'); - for (var i = 0; i < fileRows.length; i++) { - var sourceFileRow = fileRows[i]; - var fileName = sourceFileRow.children[2].textContent.trim(); - - var incrementalPercent = null; - var absolutePercent = null; - if (patchStats[fileName]) { - incrementalPercent = patchStats[fileName][coverage.INCREMENTAL_COVERAGE]; - absolutePercent = patchStats[fileName][coverage.ABSOLUTE_COVERAGE]; - } - - coverage.appendElementBeforeChild( - sourceFileRow, 'td', coverage.formatPercent(incrementalPercent), 2); - - coverage.appendElementBeforeChild( - sourceFileRow, 'td', coverage.formatPercent(absolutePercent), 2); - } - // Add the overall coverage stats for the patch. - coverage.addPatchSummaryStats( - patchElement, patchStats[coverage.PATCH_COVERAGE], reportUrl); -}; - -/** - * Formats percent for presentation on the page. - * - * @param {number} coveragePercent - * @return {string} Formatted string ready to be added to the the DOM. - */ -coverage.formatPercent = function(coveragePercent) { - if (!coveragePercent) { - return '-'; - } else { - return coveragePercent + '%'; - } -}; - -/** - * Adds summary line to a patch element: "Cov. for this patch: 45%. Details". - * - * @param {Element} patchElement Div containing a patch single patch set. - * @param {number} coveragePercent Incremental coverage for entire patch. - * @param {string} coverageReportUrl Location of detailed coverage report. - */ -coverage.addPatchSummaryStats = function( - patchElement, coveragePercent, coverageReportUrl) { - var summaryElement = document.createElement('div'); - var patchSummaryHtml = 'ΔCov. for this patch: ' + - coverage.formatPercent(coveragePercent) + '. '; - var detailsHtml = '<a href="' + coverageReportUrl + '">Details</a>'; - summaryElement.innerHTML = patchSummaryHtml + ' ' + detailsHtml; - - // Insert the summary line immediately after the table containing the changed - // files for the patch. - var tableElement = patchElement.getElementsByTagName('table')[0]; - tableElement.parentNode.insertBefore( - summaryElement, tableElement.nextSibling); -}; - -/** - * Creates and prepends an element before another. - * - * @param {Element} parentElement The parent of the element to prepend a new - * element to. - * @param {string} elementType The tag name for the new element. - * @param {string} innerHtml The value to set as the new element's innerHTML - * @param {number} childNumber The index of the child to prepend to. - */ -coverage.appendElementBeforeChild = function( - parentElement, elementType, innerHtml, childNumber) { - var newElement = document.createElement(elementType); - newElement.innerHTML = innerHtml; - parentElement.insertBefore(newElement, parentElement.children[childNumber]); -}; - -/** - * Checks if the given URL has been registered or not. - * - * @param {string} botUrl The URL to be verified. - * @return {boolean} Whether or not the provided URL was valid. - */ -coverage.isValidBotUrl = function(botUrl) { - if (!botUrl) { - return false; - } - for (var project in coverage.CONFIG.COVERAGE_REPORT_URLS) { - var candidateUrl = coverage.CONFIG.COVERAGE_REPORT_URLS[project]['botUrl']; - if (botUrl.indexOf(candidateUrl) > - 1) { - return true; - } - } - return false; -}; - -/** - * Returns the project name for the given bot URL. This function expects the bot - * URL to be valid. - * - * @param {botUrl} botUrl - * @return {string} The project name for the given bot URL. - * @throws {Error} If an invalid bot URL is supplied. - */ -coverage.getProjectNameFromBotUrl = function(botUrl) { - if (!botUrl) { - throw Error(botUrl + ' is an invalid bot url.'); - } - for (var project in coverage.CONFIG.COVERAGE_REPORT_URLS) { - var candidateUrl = coverage.CONFIG.COVERAGE_REPORT_URLS[project]['botUrl']; - if (botUrl.indexOf(candidateUrl) > - 1) { - return project; - } - } - throw Error(botUrl + ' is not registered.'); -}; - - -/** - * Finds the coverage bot URL. - * - * @param {Element} patchElement Div to search for bot URL. - * @return {string} Returns the URL to the bot details page. - */ -coverage.getValidBotUrl = function(patchElement) { - var bots = patchElement.getElementsByClassName('build-result'); - for (var i = 0; i < bots.length; i++) { - if (bots[i].getAttribute('status') === 'success' && - coverage.isValidBotUrl(bots[i].href)) { - return bots[i].href; - } - } - return null; -}; - -/** - * Checks to see if the URL points to a CL review and not another page on the - * code review site (i.e. settings). - * - * @param {string} url The URL to verify. - * @return {boolean} Whether or not the URL points to a CL review. - */ -coverage.isValidReviewUrl = function(url) { - baseUrls = coverage.CONFIG.CODE_REVIEW_URLS.join('|'); - // Matches baseurl.com/numeric-digits and baseurl.com/numeric-digits/anything - var re = new RegExp('(' + baseUrls + ')/[\\d]+(\\/|$)', 'i'); - return !!url.match(re); -}; - -/** - * Verifies that the user is using the deprecated UI. - * - * @return {boolean} Whether or not the deprecated UI is being used. - */ -coverage.isDeprecatedUi = function() { - // The tag is present in the new UI only. - return document.getElementsByTagName('cr-app').length == 0; -}; - -/** - * Returns the newest patch set element. - * - * @return {Element} The main div for the last patch set. - */ -coverage.getLastPatchElement = function() { - var patchElement = document.querySelectorAll('div[id^="ps-"'); - return patchElement[patchElement.length - 1]; -}; - -/** - * Model that describes a patch set. - * - * @param {string} projectName The name of the project. - * @param {string} buildNumber The build number for the bot run corresponding to - * this patch set. - * @constructor - */ -coverage.PatchSet = function(projectName, buildNumber) { - /** - * Location of the detailed coverage JSON report. - * @type {string} - * @private - */ - this.coverageReportUrl_ = this.getCoverageReportUrl(projectName, buildNumber); -}; - -/** - * Returns the coverage report URL. - * - * @param {string} projectName The name of the project. - * @param {string} buildNumber The build number for the bot run corresponding - * to this patch set. - * @return {string} The URL to the detailed coverage report. - */ -coverage.PatchSet.prototype.getCoverageReportUrl = function( - projectName, buildNumber) { - if (!this.coverageReportUrl_) { - var reportUrl = coverage.CONFIG.COVERAGE_REPORT_URLS[projectName]; - this.coverageReportUrl_ = reportUrl['prefix'] + buildNumber + - reportUrl['suffix']; - } - return this.coverageReportUrl_; -}; - -/** - * Returns the detailed coverage report. Caller must handle what happens - * when the report is received. No side effects if report isn't sent. - * - * @param {function} success The callback to be invoked when the report is - * received. Invoked with an object mapping file names to - * coverage stats as the only argument. - */ -coverage.PatchSet.prototype.getCoverageData = function(success) { - var client = new coverage.HttpClient(); - client.get(this.coverageReportUrl_, (function(data) { - var resultDict = JSON.parse(data); - var coveragePercentages = this.getCoveragePercentForFiles(resultDict); - success(coveragePercentages); - }).bind(this)); -}; - -/** - * Extracts the coverage percent for each file from the coverage report. - * - * @param {Object} reportDict The detailed coverage report. - * @return {Object} An object containing the coverage percent for each file and - * the patch coverage percent. - */ -coverage.PatchSet.prototype.getCoveragePercentForFiles = function(reportDict) { - var fileDict = reportDict['files']; - var coveragePercentages = {}; - - for (var fileName in fileDict) { - if (fileDict.hasOwnProperty(fileName)) { - coveragePercentages[fileName] = {}; - var coverageDict = fileDict[fileName]; - - coveragePercentages[fileName][coverage.ABSOLUTE_COVERAGE] = - this.getCoveragePercent(coverageDict, coverage.ABSOLUTE_COVERAGE); - - coveragePercentages[fileName][coverage.INCREMENTAL_COVERAGE] = - this.getCoveragePercent(coverageDict, coverage.INCREMENTAL_COVERAGE); - } - } - coveragePercentages[coverage.PATCH_COVERAGE] = - this.getCoveragePercent(reportDict[coverage.PATCH_COVERAGE], - coverage.INCREMENTAL_COVERAGE); - return coveragePercentages; -}; - -/** - * Returns the coverage percent given the number of total and covered lines. - * - * @param {Object} coverageDict Object containing absolute and incremental - * number of lines covered. - * @param {string} coverageType Either 'incremental' or 'absolute'. - * @return {number} The coverage percent. - */ -coverage.PatchSet.prototype.getCoveragePercent = function( - coverageDict, coverageType) { - if (!coverageDict || - (coverageType !== coverage.INCREMENTAL_COVERAGE && - coverageType !== coverage.ABSOLUTE_COVERAGE) || - parseFloat(total) === 0) { - return null; - } - var covered = coverageDict[coverageType]['covered']; - var total = coverageDict[coverageType]['total']; - return Math.round( - (parseFloat(covered) / parseFloat(total)) * 100); -}; - -/** - * Model describing a simple HTTP client. Only supports GET requests. - */ -coverage.HttpClient = function() { -}; - -/** - * HTTP GET that only handles successful requests. - * - * @param {string} url The URL to make a GET request to. - * @param {function} success The callback invoked when the request is finished - * successfully. Callback is invoked with response text as - * the only argument. - */ -coverage.HttpClient.prototype.get = function(url, success) { - // TODO(estevenson): Handle failure when user isn't authenticated. - var http = new XMLHttpRequest(); - http.onreadystatechange = function() { - if (http.readyState === 4 && http.status === 200) { - success(http.responseText); - } - }; - - http.open('GET', url + '/text', true); - http.send(null); -}; - -// Verifies that page might contain a patch set with a valid coverage bot. -if (coverage.isDeprecatedUi() && - coverage.isValidReviewUrl(window.location.href)) { - var patchElement = coverage.getLastPatchElement(); - var botUrl = coverage.getValidBotUrl(patchElement); - if (botUrl) { - var projectName = coverage.getProjectNameFromBotUrl(botUrl); - coverage.injectCoverageStats(patchElement, botUrl, projectName); - } -}
diff --git a/tools/chrome_extensions/chromium_code_coverage/manifest.json b/tools/chrome_extensions/chromium_code_coverage/manifest.json deleted file mode 100644 index b8eb440..0000000 --- a/tools/chrome_extensions/chromium_code_coverage/manifest.json +++ /dev/null
@@ -1,18 +0,0 @@ -{ - "manifest_version": 2, - "name": "Chromium code coverage: deprecated UI", - "description": "Adds coverage stats to Rietveld.", - "version": "1.0.0", - "permissions": [ - "https://uberchromegw.corp.google.com/", - "https://build.chromium.org/" - ], - "content_scripts": [{ - "matches": ["https://codereview.chromium.org/*", - "https://chromereviews.googleplex.com/*"], - "js": [ - "js/app.js" - ], - "run_at": "document_end" - }] -}
diff --git a/tools/chrome_proxy/live_tests/pagesets/data/chrome_proxy_top_20.json b/tools/chrome_proxy/live_tests/pagesets/data/chrome_proxy_top_20.json index 7fdb557..85c2217 100644 --- a/tools/chrome_proxy/live_tests/pagesets/data/chrome_proxy_top_20.json +++ b/tools/chrome_proxy/live_tests/pagesets/data/chrome_proxy_top_20.json
@@ -1,27 +1,27 @@ { - "description": "Describes the Web Page Replay archives for a page set. Don't edit by hand! Use record_wpr for updating.", + "description": "Describes the Web Page Replay archives for a page set. Don't edit by hand! Use record_wpr for updating.", "archives": { "chrome_proxy_top_20_000.wpr": [ - "https://www.google.com/#hl=en&q=barack+obama", - "http://www.youtube.com", - "Wordpress", - "Facebook", - "LinkedIn", - "Wikipedia (1 tab)", - "Twitter", - "Pinterest", - "ESPN", - "http://news.yahoo.com", - "http://www.cnn.com", - "Weather.com", - "http://www.amazon.com", - "http://www.ebay.com", - "http://games.yahoo.com", - "http://booking.com", - "http://answers.yahoo.com", - "http://sports.yahoo.com/", - "http://techcrunch.com", + "https://www.google.com/#hl=en&q=barack+obama", + "http://www.youtube.com", + "Wordpress", + "Facebook", + "LinkedIn", + "Wikipedia_(1_tab)", + "Twitter", + "Pinterest", + "ESPN", + "http://news.yahoo.com", + "http://www.cnn.com", + "Weather.com", + "http://www.amazon.com", + "http://www.ebay.com", + "http://games.yahoo.com", + "http://booking.com", + "http://answers.yahoo.com", + "http://sports.yahoo.com/", + "http://techcrunch.com", "http://www.nytimes.com" ] } -} \ No newline at end of file +}
diff --git a/tools/chrome_proxy/live_tests/pagesets/top_20.py b/tools/chrome_proxy/live_tests/pagesets/top_20.py index 3e5897dd..0845c998 100644 --- a/tools/chrome_proxy/live_tests/pagesets/top_20.py +++ b/tools/chrome_proxy/live_tests/pagesets/top_20.py
@@ -43,7 +43,7 @@ # Why: #6 (Alexa) most visited worldwide,Picked an interesting page self.AddStory(Top20Page('http://en.wikipedia.org/wiki/Wikipedia', self, - 'Wikipedia (1 tab)')) + 'Wikipedia_(1_tab)')) # Why: #8 (Alexa global),Picked an interesting page self.AddStory(Top20Page('https://twitter.com/katyperry', self,
diff --git a/tools/chrome_proxy/webdriver/client_config.py b/tools/chrome_proxy/webdriver/client_config.py index f8835fb..cfe485a 100644 --- a/tools/chrome_proxy/webdriver/client_config.py +++ b/tools/chrome_proxy/webdriver/client_config.py
@@ -51,7 +51,8 @@ data = t.StopAndGetNetLog() for i in data["events"]: dumped_event = json.dumps(i) - if dumped_event.find("datasaver.googleapis.com") !=-1 and\ + if dumped_event.find("datasaver.") !=-1 and\ + dumped_event.find(".googleapis.com") !=-1 and\ dumped_event.find("clientConfigs") != -1 and\ dumped_event.find("headers") != -1 and\ dumped_event.find("accept-encoding") != -1 and\ @@ -79,7 +80,8 @@ data = t.StopAndGetNetLog() for i in data["events"]: dumped_event = json.dumps(i) - if dumped_event.find("datasaver.googleapis.com") !=-1 and\ + if dumped_event.find("datasaver.") !=-1 and\ + dumped_event.find(".googleapis.com") !=-1 and\ dumped_event.find("clientConfigs") != -1 and\ dumped_event.find("headers") != -1 and\ dumped_event.find("accept-encoding") != -1 and\
diff --git a/tools/chrome_proxy/webdriver/common.py b/tools/chrome_proxy/webdriver/common.py index 85600ccd..59be489 100644 --- a/tools/chrome_proxy/webdriver/common.py +++ b/tools/chrome_proxy/webdriver/common.py
@@ -18,6 +18,8 @@ import unittest import urlparse +from emulation_server import LocalEmulationServer + sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, os.pardir, 'third_party', 'webdriver', 'pylib')) from selenium import webdriver @@ -163,6 +165,16 @@ if proc.returncode: raise Exception("ADB command failed. Output: %s" % (stdout + stderr)) +def GetOpenPort(): + """Returns an open port on the host machine. + + Return: + an open port number as an int + """ + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.bind(('', 0)) + return int(sock.getsockname()[1]) + class TestDriver: """The main driver for an integration test. @@ -182,6 +194,9 @@ was meant to support network connection control, and thus had to enable mobile emulation _network_connection: The connection type to use on start up + _emulation_server: A reference to the emulation server being used + _emulation_server_port: If this is not set to -1, the emulation server is + being used for the test and is available on this port """ def __init__(self, control_network_connection=False): @@ -194,6 +209,8 @@ self._control_network_connection = control_network_connection self._net_log = None self._network_connection = None + self._emulation_server = None + self._emulation_server_port = -1 def __enter__(self): return self @@ -201,6 +218,14 @@ def __exit__(self, exc_type, exc_value, tb): if self._driver: self._StopDriver() + if self._emulation_server: + self._emulation_server.Shutdown() + if self._flags.android: + # Remove the Android port forwarding to the host machine. + _RunAdbCmd(['reverse', '--remove', + 'tcp:%d' % self._emulation_server_port]) + self._emulation_server = None + self._emulation_server_port = -1 if self._net_log and self._flags.android: try: _RunAdbCmd('shell', 'rm', '-f', self._net_log) @@ -247,6 +272,13 @@ If running Android, the Android package name is passed to ChromeDriver here. """ self._OverrideChromeArgs() + if self._emulation_server: + self.AddChromeArg('--ignore-certificate-errors') + self._emulation_server.StartAndReturn() + if self._flags.android: + # Forward the Android port to the host machine. + address = 'tcp:%d' % self._emulation_server_port + _RunAdbCmd(['reverse', address, address]) capabilities = { 'loggingPrefs': {'performance': 'INFO'}, } @@ -367,6 +399,18 @@ self.AddChromeArg('--log-net-log=%s' % temp_file) self._net_log = temp_file + def UseEmulationServer(self, handler, port=None): + """Requests the test driver to use the emulation server. + + Args: + port: The port to run the server on. + handler: The handler to use, subclassed from BaseRequestHandler. + """ + if not port: + port = GetOpenPort() + self._emulation_server = LocalEmulationServer(port, handler) + self._emulation_server_port = port + def SetNetworkConnection(self, connection_type): """Changes the emulated connection type.
diff --git a/tools/chrome_proxy/webdriver/cross_origin_push.py b/tools/chrome_proxy/webdriver/cross_origin_push.py deleted file mode 100644 index 8ac614d2..0000000 --- a/tools/chrome_proxy/webdriver/cross_origin_push.py +++ /dev/null
@@ -1,58 +0,0 @@ -# Copyright 2017 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 common -from common import TestDriver -from common import IntegrationTest -from decorators import ChromeVersionEqualOrAfterM -import json - - -class CrossOriginPush(IntegrationTest): - # Ensure cross origin push from trusted proxy server is adopted by Chromium. - # Disabled on android because the net log is not copied yet. crbug.com/761507 - @ChromeVersionEqualOrAfterM(62) - def testClientConfigVariationsHeader(self): - with TestDriver() as t: - t.UseNetLog() - t.AddChromeArg('--enable-spdy-proxy-auth') - t.AddChromeArg( - '--force-fieldtrial-params=DataReductionProxyServerExperiments' - '.TestNanoRedirectPush:exp/test_nano_redirect_push') - t.AddChromeArg( - '--force-fieldtrials=DataReductionProxyServerExperiments' - '/TestNanoRedirectPush') - - t.LoadURL('http://googleweblight.com/i?u=' - 'http://check.googlezip.net/test.html') - - promised_stream_count = 0 - adopted_stream_count = 0 - - # Look for the request made to data saver client config server. - data = t.StopAndGetNetLog() - - mapped_const = data["constants"]["logEventTypes"]\ - ["HTTP2_STREAM_ADOPTED_PUSH_STREAM"] - self.assertLess(0, mapped_const) - - for i in data["events"]: - dumped_event = json.dumps(i) - if dumped_event.find("chrome-proxy") != -1 and\ - dumped_event.find("check.googlezip.net/test.html") != -1 and\ - dumped_event.find("promised_stream_id") !=-1: - promised_stream_count = promised_stream_count + 1 - - if dumped_event.find(str(mapped_const)) != -1 and\ - dumped_event.find("check.googlezip.net/test.html") != -1 and\ - dumped_event.find("stream_id") !=-1: - adopted_stream_count = adopted_stream_count + 1 - - # Verify that the stream was pushed and adopted. - self.assertEqual(1, promised_stream_count) - self.assertEqual(1, adopted_stream_count) - - -if __name__ == '__main__': - IntegrationTest.RunAllTests() \ No newline at end of file
diff --git a/tools/chrome_proxy/webdriver/emulation_server.py b/tools/chrome_proxy/webdriver/emulation_server.py new file mode 100644 index 0000000..06b647d --- /dev/null +++ b/tools/chrome_proxy/webdriver/emulation_server.py
@@ -0,0 +1,149 @@ +# Copyright 2017 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 SocketServer +import os +import socket +import ssl +import struct +import tempfile +import threading + +from OpenSSL import crypto + +class BlackHoleHandler(SocketServer.BaseRequestHandler): + """This handler consumes all request input and makes no responses. + """ + def handle(self): + """Consume the request and then do nothing. + """ + data = self.request.recv(4096) + while len(data) > 0: + data = self.request.recv(4096) + +class InvalidTLSHandler(SocketServer.BaseRequestHandler): + """This handler injects unencrypted TCP after a TLS handshake. + """ + def handle(self): + """Do a TLS handshake on the new connection then inject unencrypted bytes. + """ + # ssl.wrap_socket will automatically do a TLS handshake before returning. + ssl_conn = ssl.wrap_socket(self.request, server_side=True, + **_CreateSelfSignedCert()) + self.request.sendall('this is unencrypted. oops') + + +class TCPResetHandler(SocketServer.BaseRequestHandler): + """This handler sends TCP RST immediately after the connection is established. + """ + def handle(self): + """Reset the socket once connected. + """ + # Setting these socket options tells Python to TCP RST the connection when + # socket.close() is called instead of the default TCP FIN. + self.request.recv(4096) + self.request.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, + struct.pack('ii', 1, 0)) + self.request.close() + + +class TLSResetHandler(SocketServer.BaseRequestHandler): + """This handler sends TCP RST immediately after the TLS handshake. + """ + def handle(self): + """Reset the socket after TLS handshake. + """ + # ssl.wrap_socket will automatically do a TLS handshake before returning. + ssl_conn = ssl.wrap_socket(self.request, server_side=True, + **_CreateSelfSignedCert()) + # Allow the request to be sent. + ssl_conn.recv(4096) + # Setting these socket options tells the OS to TCP RST the connection when + # socket.close() is called instead of the default TCP FIN. + self.request.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, + struct.pack('ii', 1, 0)) + self.request.close() + + +class LocalEmulationServer: + """This server is a simple wrapper for building servers with request handlers. + + This class wraps Python's basic network server stack, providing a simple API + for Chrome-Proxy tests to use. + Attributes: + _port: the port to bind and listen to + _handler_class: the handler class to handle new connections with + _server: a reference to the underlying server + """ + def __init__(self, port, handler_class, server_class=SocketServer.TCPServer): + self._port = port + self._handler_class = handler_class + self._server_class = server_class + self._server = None + + def StartAndReturn(self): + """Start the server in a new thread and return once the server is running. + + A new server of the given server_class at init is started with the given + handler. The server will listen forever in a new thread unless Shutdown() is + called. + """ + self._server = self._server_class(("0.0.0.0", self._port), + self._handler_class) + event = threading.Event() + def WaitForRunning(event): + event.set() + self._server.serve_forever() + thread = threading.Thread(target=WaitForRunning, args=[event]) + thread.daemon = True + thread.start() + event.wait() + + def Shutdown(self): + """Shutdown a running server. + + Calls shutdown() on the underlying server instance, closing the spawned + thread. + """ + if self._server: + self._server.shutdown() + self._server.server_close() + +def _CreateSelfSignedCert(): + """Creates a self-signed certificate and key in the machine's temp directory. + + Returns: + a dict suitable for expansion to many ssl functions + """ + temp_dir = tempfile.gettempdir() + cert_path = os.path.join(temp_dir, "selfsigned.crt") + pkey_path = os.path.join(temp_dir, "private.key") + + # Create a private key pair. + pk = crypto.PKey() + pk.generate_key(crypto.TYPE_RSA, 1024) + + # Create a certificate and sign it. + cert = crypto.X509() + cert.get_subject().C = "US" + cert.get_subject().ST = "California" + cert.get_subject().L = "Mountain View" + cert.get_subject().O = "Fake Company Name" + cert.get_subject().OU = "Fake Company Org Name" + cert.get_subject().CN = "localhost" + cert.set_serial_number(1337) + cert.gmtime_adj_notBefore(0) + cert.gmtime_adj_notAfter(60*60*24*365) # 1 year + cert.set_issuer(cert.get_subject()) + cert.set_pubkey(pk) + cert.sign(pk, 'sha1') + + # Dump to files. + with open(cert_path, "wt") as cert_f: + cert_f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert)) + with open(pkey_path, "wt") as pkey_f: + pkey_f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, pk)) + + # Return the filenames in a dict that can be expanded into ssl function args. + return {"certfile": cert_path, "keyfile": pkey_path}
diff --git a/tools/chrome_proxy/webdriver/lite_page.py b/tools/chrome_proxy/webdriver/lite_page.py index b76979e3..01ac41c7 100644 --- a/tools/chrome_proxy/webdriver/lite_page.py +++ b/tools/chrome_proxy/webdriver/lite_page.py
@@ -3,13 +3,17 @@ # found in the LICENSE file. import common +from common import ParseFlags from common import TestDriver from common import IntegrationTest +from decorators import AndroidOnly from decorators import ChromeVersionBeforeM from decorators import ChromeVersionEqualOrAfterM import time +# These are integration tests for server provided previews and the +# protocol that supports them. class LitePage(IntegrationTest): # Verifies that a Lite Page is served for slow connection if any copyright @@ -24,7 +28,7 @@ with TestDriver() as test_driver: test_driver.AddChromeArg('--enable-spdy-proxy-auth') test_driver.AddChromeArg('--enable-features=' - 'DataReductionProxyDecidesTransform') + 'Previews,DataReductionProxyDecidesTransform') test_driver.AddChromeArg( '--force-fieldtrial-params=NetworkQualityEstimator.Enabled:' 'force_effective_connection_type/2G,' @@ -57,10 +61,15 @@ # Verify that a Lite Page response for the main frame was seen. self.assertEqual(1, lite_page_responses) + # Verify previews info bar recorded + histogram = test_driver.GetHistogram('Previews.InfoBarAction.LitePage', 5) + self.assertEqual(1, histogram['count']) + # Checks that a Lite Page is served and the force_lite_page experiment # directive is provided when always-on. # Note: this test is only on M-60+ which supports exp=force_lite_page @ChromeVersionEqualOrAfterM(60) + @ChromeVersionBeforeM(65) def testLitePageForcedExperiment(self): # If it was attempted to run with another experiment, skip this test. if common.ParseFlags().browser_args and ('--data-reduction-proxy-experiment' @@ -68,6 +77,8 @@ self.skipTest('This test cannot be run with other experiments.') with TestDriver() as test_driver: test_driver.AddChromeArg('--enable-spdy-proxy-auth') + test_driver.AddChromeArg('--enable-features=' + 'Previews,DataReductionProxyDecidesTransform') test_driver.AddChromeArg('--data-reduction-proxy-lo-fi=always-on') test_driver.AddChromeArg('--enable-data-reduction-proxy-lite-page') @@ -102,6 +113,7 @@ # Checks that a Lite Page is not served for the Cellular-Only option but # not on cellular connection. @ChromeVersionEqualOrAfterM(61) + @ChromeVersionBeforeM(65) def testLitePageNotAcceptedForCellularOnlyFlag(self): with TestDriver() as test_driver: test_driver.AddChromeArg('--enable-spdy-proxy-auth') @@ -131,8 +143,11 @@ self.assertEqual(1, non_lite_page_responses) # Checks that a Lite Page does not have an error when scrolling to the bottom - # of the page and is able to load all resources. - def testLitePageBTF(self): + # of the page and is able to load all resources. This test is only run on + # Android because it depends on window size of the browser. + @AndroidOnly + @ChromeVersionBeforeM(65) + def testLitePageBTFOldFlags(self): # If it was attempted to run with another experiment, skip this test. if common.ParseFlags().browser_args and ('--data-reduction-proxy-experiment' in common.ParseFlags().browser_args): @@ -177,6 +192,108 @@ self.assertHasChromeProxyViaHeader(response) self.assertIn(response.status, [200, 204]) + # Checks that a Lite Page does not have an error when scrolling to the bottom + # of the page and is able to load all resources. This test is only run on + # Android because it depends on window size of the browser. + @AndroidOnly + @ChromeVersionEqualOrAfterM(65) + def testLitePageBTFWithoutFallback(self): + # If it was attempted to run with another experiment, skip this test. + if common.ParseFlags().browser_args and ('--data-reduction-proxy-experiment' + in common.ParseFlags().browser_args): + self.skipTest('This test cannot be run with other experiments.') + with TestDriver() as test_driver: + test_driver.AddChromeArg('--enable-spdy-proxy-auth') + # Need to force 2G speed to get lite-page response. + test_driver.AddChromeArg('--force-effective-connection-type=2G') + + # Need to force lite page so target page doesn't fallback to Lo-Fi + # Set exp=alt1 to force Lite-page response. + test_driver.AddChromeArg('--data-reduction-proxy-experiment=alt1') + + # This page is long and has many media resources. + test_driver.LoadURL('http://check.googlezip.net/metrics/index.html') + + # Verify that a Lite Page response for the main frame was seen. + lite_page_responses = 0 + for response in test_driver.GetHTTPResponses(): + # Skip CSI requests when validating Lite Page headers. CSI requests + # aren't expected to have LoFi headers. + if '/csi?' in response.url: + continue + if response.url.startswith('data:'): + continue + if (self.checkLitePageResponse(response)): + lite_page_responses = lite_page_responses + 1 + self.assertEqual(1, lite_page_responses) + + # Scroll to the bottom of the window and ensure scrollHeight increases. + original_scroll_height = test_driver.ExecuteJavascriptStatement( + 'document.body.scrollHeight') + test_driver.ExecuteJavascriptStatement( + 'window.scrollTo(0,Math.max(document.body.scrollHeight));') + # Give some time for loading after scrolling. + time.sleep(2) + new_scroll_height = test_driver.ExecuteJavascriptStatement( + 'document.body.scrollHeight') + self.assertGreater(new_scroll_height, original_scroll_height) + + # Make sure there were more requests that were proxied. + responses = test_driver.GetHTTPResponses(override_has_logs=True) + self.assertNotEqual(0, len(responses)) + for response in responses: + self.assertHasChromeProxyViaHeader(response) + self.assertIn(response.status, [200, 204]) + + # Checks that a Nano Lite Page does not have an error when scrolling to the + # bottom of the page and is able to load all resources. Nano pages don't + # request additional resources when scrolling. This test is only run on + # Android because it depends on window size of the browser. + @AndroidOnly + @ChromeVersionEqualOrAfterM(65) + def testLitePageNano(self): + # If it was attempted to run with another experiment, skip this test. + if common.ParseFlags().browser_args and ('--data-reduction-proxy-experiment' + in common.ParseFlags().browser_args): + self.skipTest('This test cannot be run with other experiments.') + with TestDriver() as test_driver: + test_driver.AddChromeArg('--enable-spdy-proxy-auth') + # Need to force 2G speed to get lite-page response. + test_driver.AddChromeArg('--force-effective-connection-type=2G') + # Set exp=alt2 to force Nano response. + test_driver.AddChromeArg('--data-reduction-proxy-experiment=alt2') + + # This page is long and has many media resources. + test_driver.LoadURL('http://check.googlezip.net/metrics/index.html') + time.sleep(2) + + lite_page_responses = 0 + btf_response = 0 + image_responses = 0 + for response in test_driver.GetHTTPResponses(): + # Verify that a Lite Page response for the main frame was seen. + if response.url.endswith('html'): + if (self.checkLitePageResponse(response)): + lite_page_responses = lite_page_responses + 1 + # Keep track of BTF responses. + if response.url.startswith("http://googleweblight.com/b"): + btf_response = btf_response + 1 + # Keep track of image responses. + if response.url.startswith("data:image"): + image_responses = image_responses + 1 + # Some video requests don't go through Flywheel. + if 'content-type' in response.response_headers and ('video/mp4' + in response.response_headers['content-type']): + continue + # Make sure non-video requests are proxied. + self.assertHasChromeProxyViaHeader(response) + # Make sure there are no 4XX or 5xx status codes. + self.assertLess(response.status, 400) + + self.assertEqual(1, lite_page_responses) + self.assertEqual(1, btf_response) + self.assertGreater(1, image_responses) + # Lo-Fi fallback is not supported without the # DataReductionProxyDecidesTransform feature. Check that no Lo-Fi response # is received if a Lite Page is not served. @@ -223,7 +340,7 @@ with TestDriver() as test_driver: test_driver.AddChromeArg('--enable-spdy-proxy-auth') test_driver.AddChromeArg('--enable-features=' - 'DataReductionProxyDecidesTransform') + 'Previews,DataReductionProxyDecidesTransform') test_driver.AddChromeArg('--force-fieldtrial-params=' 'NetworkQualityEstimator.Enabled:' 'force_effective_connection_type/Slow2G') @@ -251,7 +368,6 @@ self.assertEqual(0, lite_page_responses) self.assertNotEqual(0, lofi_resource) - self.assertNotEqual(0, lofi_resource) # Checks that the server provides a preview (either Lite Page or fallback # to LoFi) for a 2G connection. @@ -261,7 +377,7 @@ with TestDriver() as test_driver: test_driver.AddChromeArg('--enable-spdy-proxy-auth') test_driver.AddChromeArg('--enable-features=' - 'DataReductionProxyDecidesTransform') + 'Previews,DataReductionProxyDecidesTransform') test_driver.AddChromeArg('--force-fieldtrial-params=' 'NetworkQualityEstimator.Enabled:' 'force_effective_connection_type/2G') @@ -286,6 +402,14 @@ self.assertTrue(lite_page_responses == 1 or page_policies_responses == 1) + # Verify a previews info bar recorded + if (lite_page_responses == 1): + histogram = test_driver.GetHistogram( + 'Previews.InfoBarAction.LitePage', 5) + else: + histogram = test_driver.GetHistogram('Previews.InfoBarAction.LoFi', 5) + self.assertEqual(1, histogram['count']) + # Checks that the server does not provide a preview (neither Lite Page nor # fallback to LoFi) for a fast connection. # Note: this test is for the CPAT protocol change in M-61. @@ -294,7 +418,7 @@ with TestDriver() as test_driver: test_driver.AddChromeArg('--enable-spdy-proxy-auth') test_driver.AddChromeArg('--enable-features=' - 'DataReductionProxyDecidesTransform') + 'Previews,DataReductionProxyDecidesTransform') test_driver.AddChromeArg('--force-fieldtrial-params=' 'NetworkQualityEstimator.Enabled:' 'force_effective_connection_type/4G') @@ -322,41 +446,44 @@ self.assertNotIn('chrome-proxy-accept-transform', response.request_headers) - # Checks that the server provides a preview (either Lite Page or fallback - # to LoFi) for a "heavy" page over a 3G connection. - @ChromeVersionEqualOrAfterM(61) - def testPreviewProvidedForHeavyPage(self): + # Verify no previews info bar recorded + histogram = test_driver.GetHistogram('Previews.InfoBarAction.LitePage', 5) + self.assertEqual(histogram, {}) + histogram = test_driver.GetHistogram('Previews.InfoBarAction.LoFi', 5) + self.assertEqual(histogram, {}) + + # Checks the default of whether server previews are enabled or not + # based on whether running on Android (enabled) or not (disabled). + # This is a regression test that the DataReductionProxyDecidesTransform + # Feature is not enabled by default for non-Android platforms. + @ChromeVersionEqualOrAfterM(64) + def testDataReductionProxyDecidesTransformDefault(self): with TestDriver() as test_driver: test_driver.AddChromeArg('--enable-spdy-proxy-auth') + test_driver.AddChromeArg('--force-fieldtrial-params=' + 'NetworkQualityEstimator.Enabled:' + 'force_effective_connection_type/2G') test_driver.AddChromeArg( - '--force-fieldtrial-params=NetworkQualityEstimator.Enabled:' - 'force_effective_connection_type/3G,' - 'DataReductionProxyServerExperiments.Enabled:' - 'exp/integration_test_policy') - test_driver.AddChromeArg( - '--force-fieldtrials=NetworkQualityEstimator/Enabled/' - 'DataReductionProxyServerExperiments/Enabled') + '--force-fieldtrials=' + 'NetworkQualityEstimator/Enabled/' + 'DataReductionProxyPreviewsBlackListTransition/Enabled/') - # Open a URL that is specially marked as a heavy page for integration - # test purposes (requires using the "exp=integration_test_policy" value - # in chrome-proxy header). - test_driver.LoadURL('http://check.googlezip.net/previews/heavy_page.html') + test_driver.LoadURL('http://check.googlezip.net/test.html') - lite_page_responses = 0 - page_policies_responses = 0 for response in test_driver.GetHTTPResponses(): - self.assertEqual('3G', response.request_headers['chrome-proxy-ect']) - self.assertIn('exp=integration_test_policy', - response.request_headers['chrome-proxy']) + self.assertEqual('2G', response.request_headers['chrome-proxy-ect']) if response.url.endswith('html'): - if self.checkLitePageResponse(response): - lite_page_responses = lite_page_responses + 1 - elif 'chrome-proxy' in response.response_headers: - self.assertIn('page-policies', - response.response_headers['chrome-proxy']) - page_policies_responses = page_policies_responses + 1 - - self.assertTrue(lite_page_responses == 1 or page_policies_responses == 1) + if ParseFlags().android: + # CPAT provided on Android + self.assertIn('chrome-proxy-accept-transform', + response.request_headers) + else: + # CPAT NOT provided on Desktop + self.assertNotIn('chrome-proxy-accept-transform', + response.request_headers) + self.assertNotIn('chrome-proxy-content-transform', + response.response_headers) + continue if __name__ == '__main__': IntegrationTest.RunAllTests()
diff --git a/tools/chrome_proxy/webdriver/lofi.py b/tools/chrome_proxy/webdriver/lofi.py index 96574ac..8c707ee6 100644 --- a/tools/chrome_proxy/webdriver/lofi.py +++ b/tools/chrome_proxy/webdriver/lofi.py
@@ -13,9 +13,12 @@ # Checks that the compressed image is below a certain threshold. # The test page is uncacheable otherwise a cached page may be served that # doesn't have the correct via headers. - def testLoFi(self): + @ChromeVersionBeforeM(65) + def testLoFiOldFlags(self): with TestDriver() as test_driver: test_driver.AddChromeArg('--enable-spdy-proxy-auth') + test_driver.AddChromeArg('--enable-features=' + 'Previews,DataReductionProxyDecidesTransform') test_driver.AddChromeArg('--data-reduction-proxy-lo-fi=always-on') # Disable server experiments such as tamper detection. test_driver.AddChromeArg('--data-reduction-proxy-server-experiments-' @@ -35,17 +38,23 @@ # Verify that Lo-Fi responses were seen. self.assertNotEqual(0, lofi_responses) + # Verify Lo-Fi previews info bar recorded + histogram = test_driver.GetHistogram('Previews.InfoBarAction.LoFi', 5) + self.assertEqual(1, histogram['count']) + # Checks that LoFi images are served when LoFi slow connections are used and # the network quality estimator returns Slow2G. - def testLoFiSlowConnection(self): + @ChromeVersionBeforeM(65) + def testLoFiSlowConnectionOldFlags(self): with TestDriver() as test_driver: test_driver.AddChromeArg('--enable-spdy-proxy-auth') + test_driver.AddChromeArg('--enable-features=' + 'Previews,DataReductionProxyDecidesTransform') test_driver.AddChromeArg('--data-reduction-proxy-lo-fi=slow-connections-' 'only') # Disable server experiments such as tamper detection. test_driver.AddChromeArg('--data-reduction-proxy-server-experiments-' 'disabled') - test_driver.AddChromeArg('--force-fieldtrial-params=' 'NetworkQualityEstimator.Enabled:' 'force_effective_connection_type/Slow2G') @@ -66,6 +75,125 @@ # Verify that Lo-Fi responses were seen. self.assertNotEqual(0, lofi_responses) + # Verify Lo-Fi previews info bar recorded + histogram = test_driver.GetHistogram('Previews.InfoBarAction.LoFi', 5) + self.assertEqual(1, histogram['count']) + + # Checks that LoFi images are served when LoFi slow connections are used and + # the network quality estimator returns Slow2G. + @ChromeVersionEqualOrAfterM(65) + def testLoFiOnSlowConnection(self): + with TestDriver() as test_driver: + test_driver.AddChromeArg('--enable-spdy-proxy-auth') + test_driver.AddChromeArg('--enable-features=' + 'Previews,DataReductionProxyDecidesTransform') + # Disable server experiments such as tamper detection. + test_driver.AddChromeArg('--data-reduction-proxy-server-experiments-' + 'disabled') + test_driver.AddChromeArg('--force-fieldtrial-params=' + 'NetworkQualityEstimator.Enabled:' + 'force_effective_connection_type/Slow2G') + test_driver.AddChromeArg('--force-fieldtrials=NetworkQualityEstimator/' + 'Enabled') + + test_driver.LoadURL('http://check.googlezip.net/static/index.html') + + lofi_responses = 0 + for response in test_driver.GetHTTPResponses(): + if not response.url.endswith('png'): + continue + if not response.request_headers: + continue + if (self.checkLoFiResponse(response, True)): + lofi_responses = lofi_responses + 1 + + # Verify that Lo-Fi responses were seen. + self.assertNotEqual(0, lofi_responses) + + # Verify Lo-Fi previews info bar recorded + histogram = test_driver.GetHistogram('Previews.InfoBarAction.LoFi', 5) + self.assertEqual(1, histogram['count']) + + # Checks that LoFi images are NOT served when the network quality estimator + # returns fast connection type. + @ChromeVersionBeforeM(65) + def testLoFiFastConnectionOldFlags(self): + with TestDriver() as test_driver: + test_driver.AddChromeArg('--enable-spdy-proxy-auth') + test_driver.AddChromeArg('--enable-features=' + 'Previews,DataReductionProxyDecidesTransform') + test_driver.AddChromeArg('--data-reduction-proxy-lo-fi=slow-connections-' + 'only') + # Disable server experiments such as tamper detection. + test_driver.AddChromeArg('--data-reduction-proxy-server-experiments-' + 'disabled') + test_driver.AddChromeArg('--force-fieldtrial-params=' + 'NetworkQualityEstimator.Enabled:' + 'force_effective_connection_type/4G') + test_driver.AddChromeArg('--force-fieldtrials=NetworkQualityEstimator/' + 'Enabled') + + test_driver.LoadURL('http://check.googlezip.net/static/index.html') + + lofi_responses = 0 + for response in test_driver.GetHTTPResponses(): + if response.url.endswith('html'): + # Main resource should accept transforms but not be transformed. + self.assertEqual('lite-page', + response.request_headers['chrome-proxy-accept-transform']) + self.assertNotIn('chrome-proxy-content-transform', + response.response_headers) + if 'chrome-proxy' in response.response_headers: + self.assertNotIn('page-policies', + response.response_headers['chrome-proxy']) + else: + # No subresources should accept transforms. + self.assertNotIn('chrome-proxy-accept-transform', + response.request_headers) + + # Verify no Lo-Fi previews info bar recorded + histogram = test_driver.GetHistogram('Previews.InfoBarAction.LoFi', 5) + self.assertEqual(histogram, {}) + + # Checks that LoFi images are NOT served when the network quality estimator + # returns fast connection. + @ChromeVersionEqualOrAfterM(65) + def testLoFiFastConnection(self): + with TestDriver() as test_driver: + test_driver.AddChromeArg('--enable-spdy-proxy-auth') + test_driver.AddChromeArg('--enable-features=' + 'Previews,DataReductionProxyDecidesTransform') + # Disable server experiments such as tamper detection. + test_driver.AddChromeArg('--data-reduction-proxy-server-experiments-' + 'disabled') + test_driver.AddChromeArg('--force-fieldtrial-params=' + 'NetworkQualityEstimator.Enabled:' + 'force_effective_connection_type/4G') + test_driver.AddChromeArg('--force-fieldtrials=NetworkQualityEstimator/' + 'Enabled') + + test_driver.LoadURL('http://check.googlezip.net/static/index.html') + + lofi_responses = 0 + for response in test_driver.GetHTTPResponses(): + if response.url.endswith('html'): + # Main resource should accept transforms but not be transformed. + self.assertEqual('lite-page', + response.request_headers['chrome-proxy-accept-transform']) + self.assertNotIn('chrome-proxy-content-transform', + response.response_headers) + if 'chrome-proxy' in response.response_headers: + self.assertNotIn('page-policies', + response.response_headers['chrome-proxy']) + else: + # No subresources should accept transforms. + self.assertNotIn('chrome-proxy-accept-transform', + response.request_headers) + + # Verify no Lo-Fi previews info bar recorded + histogram = test_driver.GetHistogram('Previews.InfoBarAction.LoFi', 5) + self.assertEqual(histogram, {}) + # Checks that LoFi images are not served, but the if-heavy CPAT header is # added when LoFi slow connections are used and the network quality estimator # returns 4G. @@ -115,7 +243,8 @@ # enabled and Lo-Fi disabled and the same test page is loaded. This third page # load should not pick the Lo-Fi placeholder from cache and original image # should be loaded. - def testLoFiCacheBypass(self): + @ChromeVersionBeforeM(65) + def testLoFiCacheBypassOldFlags(self): # If it was attempted to run with another experiment, skip this test. if common.ParseFlags().browser_args and ('--data-reduction-proxy-experiment' in common.ParseFlags().browser_args): @@ -126,6 +255,8 @@ # --profile-type=default command line for the same user profile and cache # to be used across the two page loads. test_driver.AddChromeArg('--enable-spdy-proxy-auth') + test_driver.AddChromeArg('--enable-features=' + 'Previews,DataReductionProxyDecidesTransform') test_driver.AddChromeArg('--data-reduction-proxy-lo-fi=always-on') test_driver.AddChromeArg('--profile-type=default') test_driver.AddChromeArg('--data-reduction-proxy-server-experiments-' @@ -183,19 +314,107 @@ # Verify that responses were seen. self.assertNotEqual(0, responses) + # Checks that Lo-Fi placeholder images are not loaded from cache on page + # reloads when Lo-Fi mode is disabled or data reduction proxy is disabled. + # First a test page is opened with Lo-Fi and chrome proxy enabled. This allows + # Chrome to cache the Lo-Fi placeholder image. The browser is restarted with + # chrome proxy disabled and the same test page is loaded. This second page + # load should not pick the Lo-Fi placeholder from cache and original image + # should be loaded. Finally, the browser is restarted with chrome proxy + # enabled and Lo-Fi disabled and the same test page is loaded. This third page + # load should not pick the Lo-Fi placeholder from cache and original image + # should be loaded. + @ChromeVersionEqualOrAfterM(65) + def testLoFiCacheBypass(self): + # If it was attempted to run with another experiment, skip this test. + if common.ParseFlags().browser_args and ('--data-reduction-proxy-experiment' + in common.ParseFlags().browser_args): + self.skipTest('This test cannot be run with other experiments.') + with TestDriver() as test_driver: + # First page load, enable Lo-Fi and chrome proxy. Disable server + # experiments such as tamper detection. This test should be run with + # --profile-type=default command line for the same user profile and cache + # to be used across the two page loads. + test_driver.AddChromeArg('--enable-spdy-proxy-auth') + test_driver.AddChromeArg('--enable-features=' + 'Previews,DataReductionProxyDecidesTransform') + test_driver.AddChromeArg('--profile-type=default') + test_driver.AddChromeArg('--data-reduction-proxy-server-experiments-' + 'disabled') + test_driver.AddChromeArg('--force-fieldtrial-params=' + 'NetworkQualityEstimator.Enabled:' + 'force_effective_connection_type/Slow2G') + test_driver.AddChromeArg('--force-fieldtrials=NetworkQualityEstimator/' + 'Enabled') + + test_driver.LoadURL('http://check.googlezip.net/cacheable/test.html') + + lofi_responses = 0 + for response in test_driver.GetHTTPResponses(): + if not response.url.endswith('png'): + continue + if not response.request_headers: + continue + if (self.checkLoFiResponse(response, True)): + lofi_responses = lofi_responses + 1 + + # Verify that Lo-Fi responses were seen. + self.assertNotEqual(0, lofi_responses) + + # Second page load with the chrome proxy off. + test_driver._StopDriver() + test_driver.RemoveChromeArg('--enable-spdy-proxy-auth') + test_driver.LoadURL('http://check.googlezip.net/cacheable/test.html') + + responses = 0 + for response in test_driver.GetHTTPResponses(): + if not response.url.endswith('png'): + continue + if not response.request_headers: + continue + responses = responses + 1 + self.assertNotHasChromeProxyViaHeader(response) + self.checkLoFiResponse(response, False) + + # Verify that responses were seen. + self.assertNotEqual(0, responses) + + # Third page load with the chrome proxy on and Lo-Fi off. + test_driver._StopDriver() + test_driver.AddChromeArg('--enable-spdy-proxy-auth') + test_driver.RemoveChromeArg('--enable-features=' + 'DataReductionProxyDecidesTransform') + test_driver.AddChromeArg('--disable-features=' + 'DataReductionProxyDecidesTransform') + test_driver.LoadURL('http://check.googlezip.net/cacheable/test.html') + + responses = 0 + for response in test_driver.GetHTTPResponses(): + if not response.url.endswith('png'): + continue + if not response.request_headers: + continue + responses = responses + 1 + self.assertHasChromeProxyViaHeader(response) + self.checkLoFiResponse(response, False) + + # Verify that responses were seen. + self.assertNotEqual(0, responses) + # Checks that LoFi images are served and the force empty image experiment # directive is provided when LoFi is always-on without Lite Pages enabled. @ChromeVersionEqualOrAfterM(61) - def testLoFiForcedExperiment(self): + @ChromeVersionBeforeM(65) + def testLoFiForcedExperimentOldFlags(self): # If it was attempted to run with another experiment, skip this test. if common.ParseFlags().browser_args and ('--data-reduction-proxy-experiment' in common.ParseFlags().browser_args): self.skipTest('This test cannot be run with other experiments.') with TestDriver() as test_driver: test_driver.AddChromeArg('--enable-spdy-proxy-auth') - test_driver.AddChromeArg('--data-reduction-proxy-lo-fi=always-on') test_driver.AddChromeArg('--enable-features=' - 'DataReductionProxyDecidesTransform') + 'Previews,DataReductionProxyDecidesTransform') + test_driver.AddChromeArg('--data-reduction-proxy-lo-fi=always-on') # Ensure fast network (4G) to ensure force flag ignores ECT. test_driver.AddChromeArg('--force-fieldtrial-params=' @@ -223,14 +442,13 @@ # Verify that Lo-Fi responses were seen. self.assertNotEqual(0, lofi_responses) - # Checks that Client LoFi resource requests have the Intervention header - # (in case page has https images that may not be fully loaded). + # Checks that Client LoFi resource requests have the Intervention header. @ChromeVersionEqualOrAfterM(61) def testClientLoFiInterventionHeader(self): with TestDriver() as test_driver: test_driver.AddChromeArg('--enable-spdy-proxy-auth') test_driver.AddChromeArg('--enable-features=' - 'DataReductionProxyDecidesTransform') + 'Previews,DataReductionProxyDecidesTransform') test_driver.AddChromeArg( '--force-fieldtrial-params=NetworkQualityEstimator.Enabled:' 'force_effective_connection_type/2G,' @@ -240,7 +458,7 @@ '--force-fieldtrials=NetworkQualityEstimator/Enabled/' 'PreviewsClientLoFi/Enabled') - test_driver.LoadURL('http://check.googlezip.net/static/index.html') + test_driver.LoadURL('https://check.googlezip.net/static/index.html') intervention_headers = 0 for response in test_driver.GetHTTPResponses():
diff --git a/tools/chrome_proxy/webdriver/proxy_connection.py b/tools/chrome_proxy/webdriver/proxy_connection.py new file mode 100644 index 0000000..03932ad1 --- /dev/null +++ b/tools/chrome_proxy/webdriver/proxy_connection.py
@@ -0,0 +1,129 @@ + # Copyright 2017 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 common +from common import TestDriver +from common import IntegrationTest +from decorators import ChromeVersionEqualOrAfterM +from emulation_server import BlackHoleHandler +from emulation_server import InvalidTLSHandler +from emulation_server import TCPResetHandler +from emulation_server import TLSResetHandler + +class ProxyConnection(IntegrationTest): + + @ChromeVersionEqualOrAfterM(63) + def testTLSInjectionAfterHandshake(self): + port = common.GetOpenPort() + with TestDriver() as t: + t.AddChromeArg('--enable-spdy-proxy-auth') + # The server should be 127.0.0.1, not localhost because the two are + # treated differently in Chrome internals. Using localhost invalidates the + # test. + t.AddChromeArg( + '--data-reduction-proxy-http-proxies=https://127.0.0.1:%d' % port) + t.AddChromeArg( + '--force-fieldtrials=DataReductionProxyConfigService/Disabled') + t.UseEmulationServer(InvalidTLSHandler, port=port) + + t.LoadURL('http://check.googlezip.net/test.html') + responses = t.GetHTTPResponses() + # Expect responses with a bypass on a bad proxy. If the test failed, the + # next assertion will fail because there will be no responses. + self.assertEqual(2, len(responses)) + for response in responses: + self.assertNotHasChromeProxyViaHeader(response) + self.assertTrue(t.SleepUntilHistogramHasEntry('DataReductionProxy.' + 'InvalidResponseHeadersReceived.NetError')) + + @ChromeVersionEqualOrAfterM(63) + def testTCPReset(self): + port = common.GetOpenPort() + with TestDriver() as t: + t.AddChromeArg('--enable-spdy-proxy-auth') + # The server should be 127.0.0.1, not localhost because the two are + # treated differently in Chrome internals. Using localhost invalidates the + # test. + t.UseNetLog() + t.AddChromeArg( + '--data-reduction-proxy-http-proxies=http://127.0.0.1:%d' % port) + t.AddChromeArg( + '--force-fieldtrials=DataReductionProxyConfigService/Disabled') + t.UseEmulationServer(TCPResetHandler, port=port) + + t.LoadURL('http://check.googlezip.net/test.html') + responses = t.GetHTTPResponses() + # Expect responses with a bypass on a bad proxy. If the test failed, the + # next assertion will fail because there will be no responses. + self.assertEqual(2, len(responses)) + for response in responses: + self.assertNotHasChromeProxyViaHeader(response) + self.assertTrue(t.SleepUntilHistogramHasEntry('DataReductionProxy.' + 'InvalidResponseHeadersReceived.NetError')) + + @ChromeVersionEqualOrAfterM(63) + def testTLSReset(self): + port = common.GetOpenPort() + with TestDriver() as t: + t.AddChromeArg('--enable-spdy-proxy-auth') + t.AddChromeArg('--allow-insecure-localhost') + # The server should be 127.0.0.1, not localhost because the two are + # treated differently in Chrome internals. Using localhost invalidates the + # test. + t.AddChromeArg( + '--data-reduction-proxy-http-proxies=https://127.0.0.1:%d' % port) + t.AddChromeArg( + '--force-fieldtrials=DataReductionProxyConfigService/Disabled') + t.UseEmulationServer(TLSResetHandler, port=port) + + t.LoadURL('http://check.googlezip.net/test.html') + responses = t.GetHTTPResponses() + # Expect responses with a bypass on a bad proxy. If the test failed, the + # next assertion will fail because there will be no responses. + self.assertEqual(2, len(responses)) + for response in responses: + self.assertNotHasChromeProxyViaHeader(response) + + @ChromeVersionEqualOrAfterM(66) + def testTCPBlackhole(self): + port = common.GetOpenPort() + with TestDriver() as t: + t.UseNetLog() + t.AddChromeArg('--enable-spdy-proxy-auth') + t.AddChromeArg('--enable-features=' + 'DataReductionProxyRobustConnection<DataReductionProxyRobustConnection') + t.AddChromeArg('--force-fieldtrials=' + 'DataReductionProxyRobustConnection/Enabled') + t.AddChromeArg('--force-fieldtrial-params=' + 'DataReductionProxyRobustConnection.Enabled:' + 'warmup_fetch_callback_enabled/true') + t.AddChromeArg('--force-effective-connection-type=4G') + # The server should be 127.0.0.1, not localhost because the two are + # treated differently in Chrome internals. Using localhost invalidates the + # test. + t.AddChromeArg( + '--data-reduction-proxy-http-proxies=http://127.0.0.1:%d' % port) + + t.UseEmulationServer(BlackHoleHandler, port=port) + # Start Chrome and wait for the proxy timeout to fail. At ECT=4G, this + # will take about 8 seconds. + t.LoadURL('data:,') + self.assertTrue( + t.SleepUntilHistogramHasEntry('DataReductionProxy.WarmupURL.NetError', + sleep_intervals=10)) + + # Check the WarmupURL Callback was called. + histogram = t.GetHistogram('DataReductionProxy.WarmupURLFetcherCallback.' + 'SuccessfulFetch.InsecureProxy.NonCore') + self.assertEqual(1, histogram['count']) + + # Verify DRP was not used. + t.LoadURL('http://check.googlezip.net/test.html') + responses = t.GetHTTPResponses() + self.assertEqual(2, len(responses)) + for response in responses: + self.assertNotHasChromeProxyViaHeader(response) + +if __name__ == '__main__': + IntegrationTest.RunAllTests()
diff --git a/tools/chrome_proxy/webdriver/run_all_tests.py b/tools/chrome_proxy/webdriver/run_all_tests.py index 604b4764..8ed1c2c1 100644 --- a/tools/chrome_proxy/webdriver/run_all_tests.py +++ b/tools/chrome_proxy/webdriver/run_all_tests.py
@@ -3,6 +3,9 @@ # found in the LICENSE file. import common +import sys if __name__ == "__main__": - common.IntegrationTest.RunAllTests(run_all_tests=True) + results = common.IntegrationTest.RunAllTests(run_all_tests=True) + if results.errors or results.failures: + sys.exit(2)
diff --git a/tools/chrome_proxy/webdriver/safebrowsing.py b/tools/chrome_proxy/webdriver/safebrowsing.py index 1560bb0..f55fb58 100644 --- a/tools/chrome_proxy/webdriver/safebrowsing.py +++ b/tools/chrome_proxy/webdriver/safebrowsing.py
@@ -8,6 +8,7 @@ from decorators import AndroidOnly from decorators import NotAndroid +from selenium.common.exceptions import TimeoutException class SafeBrowsing(IntegrationTest): @@ -15,9 +16,15 @@ def testSafeBrowsingOn(self): with TestDriver() as t: t.AddChromeArg('--enable-spdy-proxy-auth') - t.LoadURL('http://testsafebrowsing.appspot.com/s/malware.html') - responses = t.GetHTTPResponses() - self.assertEqual(0, len(responses)) + + # Starting in M63 LoadURL will timeout when the safebrowsing + # interstitial appears. + try: + t.LoadURL('http://testsafebrowsing.appspot.com/s/malware.html') + responses = t.GetHTTPResponses() + self.assertEqual(0, len(responses)) + except TimeoutException: + pass @NotAndroid def testSafeBrowsingOff(self):
diff --git a/tools/chrome_proxy/webdriver/video.py b/tools/chrome_proxy/webdriver/video.py index 4c552029..4fe83f2 100644 --- a/tools/chrome_proxy/webdriver/video.py +++ b/tools/chrome_proxy/webdriver/video.py
@@ -9,11 +9,19 @@ from common import IntegrationTest from common import ParseFlags from decorators import Slow +from decorators import ChromeVersionEqualOrAfterM from selenium.webdriver.common.by import By class Video(IntegrationTest): + # Returns the ofcl value in chrome-proxy header. + def getChromeProxyOFCL(self, response): + self.assertIn('chrome-proxy', response.response_headers) + chrome_proxy_header = response.response_headers['chrome-proxy'] + self.assertIn('ofcl=', chrome_proxy_header) + return chrome_proxy_header.split('ofcl=', 1)[1].split(',', 1)[0] + # Check videos are proxied. def testCheckVideoHasViaHeader(self): with TestDriver() as t: @@ -47,13 +55,76 @@ self.assertHasChromeProxyViaHeader(response) self.assertTrue(saw_video_response, 'No video request seen in test!') + @ChromeVersionEqualOrAfterM(64) + def testRangeRequest(self): + with TestDriver() as t: + t.AddChromeArg('--enable-spdy-proxy-auth') + t.LoadURL('http://check.googlezip.net/connect') + time.sleep(2) # wait for page load + initial_ocl_histogram_count = t.GetHistogram( + 'Net.HttpOriginalContentLengthWithValidOCL')['count'] + initial_ocl_histogram_sum = t.GetHistogram( + 'Net.HttpOriginalContentLengthWithValidOCL')['sum'] + t.ExecuteJavascript( + 'var xhr = new XMLHttpRequest();' + 'xhr.open("GET", "/metrics/local.png", false);' + 'xhr.setRequestHeader("Range", "bytes=0-200");' + 'xhr.send();' + 'return;' + ) + saw_range_response = False + for response in t.GetHTTPResponses(): + self.assertHasChromeProxyViaHeader(response) + if response.response_headers['status']=='206': + saw_range_response = True + content_range = response.response_headers['content-range'] + self.assertTrue(content_range.startswith('bytes 0-200/')) + compressed_full_content_length = int(content_range.split('/')[1]) + ofcl = int(self.getChromeProxyOFCL(response)) + # ofcl should be same as compressed full content length, since no + # compression for XHR. + self.assertEqual(ofcl, compressed_full_content_length) + # One new entry should be added to HttpOriginalContentLengthWithValidOCL + # histogram and that should match expected OCL which is + # compression_ratio * 201 bytes. + self.assertEqual(1, t.GetHistogram( + 'Net.HttpOriginalContentLengthWithValidOCL')['count'] + - initial_ocl_histogram_count) + self.assertEqual(t.GetHistogram( + 'Net.HttpOriginalContentLengthWithValidOCL')['sum'] + - initial_ocl_histogram_sum, + ofcl/compressed_full_content_length*201) + self.assertTrue(saw_range_response, 'No range request was seen in test!') + + @ChromeVersionEqualOrAfterM(64) + def testRangeRequestInVideo(self): + with TestDriver() as t: + t.AddChromeArg('--enable-spdy-proxy-auth') + t.LoadURL( + 'http://check.googlezip.net/cacheable/video/buck_bunny_tiny.html') + # Wait for the video to finish playing, plus some headroom. + time.sleep(5) + responses = t.GetHTTPResponses() + self.assertEquals(2, len(responses)) + saw_range_response = False + for response in responses: + self.assertHasChromeProxyViaHeader(response) + if response.response_headers['status']=='206': + saw_range_response = True + content_range = response.response_headers['content-range'] + compressed_full_content_length = int(content_range.split('/')[1]) + ofcl = int(self.getChromeProxyOFCL(response)) + # ofcl should be greater than the compressed full content length. + self.assertTrue(ofcl > compressed_full_content_length) + self.assertTrue(saw_range_response, 'No range request was seen in test!') + # Check the compressed video has the same frame count, width, height, and # duration as uncompressed. @Slow def testVideoMetrics(self): expected = { - 'duration': 3.128, - 'webkitDecodedFrameCount': 54.0, + 'duration': 3.068, + 'webkitDecodedFrameCount': 53.0, 'videoWidth': 1280.0, 'videoHeight': 720.0 } @@ -161,9 +232,9 @@ if is_android: alt_data = 'data/buck_bunny_640x360_24fps.mp4.expected_volume_alt.json' self.instrumentedVideoTest('http://check.googlezip.net/cacheable/video/buck_bunny_640x360_24fps_audio.html', - alt_data=alt_data, needs_click=is_android) + alt_data=alt_data) - def instrumentedVideoTest(self, url, alt_data=None, needs_click=False): + def instrumentedVideoTest(self, url, alt_data=None): """Run an instrumented video test. The given page is reloaded up to some maximum number of times until a compressed video is seen by ChromeDriver by inspecting the network logs. Once that happens, test.ready is set and that @@ -175,6 +246,7 @@ max_attempts = 10 with TestDriver() as t: t.AddChromeArg('--enable-spdy-proxy-auth') + t.AddChromeArg('--autoplay-policy=no-user-gesture-required') loaded_compressed_video = False attempts = 0 while not loaded_compressed_video and attempts < max_attempts: @@ -193,8 +265,12 @@ if alt_data != None: t.ExecuteJavascriptStatement('test.expectedVolumeSrc = "%s"' % alt_data) t.ExecuteJavascriptStatement('test.ready = true') - if needs_click: + t.WaitForJavascriptExpression('test.video_ != undefined', 5) + # Click the video to start if Android. + if ParseFlags().android: t.FindElement(By.ID, 'video').click() + else: + t.ExecuteJavascriptStatement('test.video_.play()') waitTimeQuery = 'test.waitTime' if ParseFlags().android: waitTimeQuery = 'test.androidWaitTime'
diff --git a/tools/clang/OWNERS b/tools/clang/OWNERS index 4c7cbe4..0dfd9ae 100644 --- a/tools/clang/OWNERS +++ b/tools/clang/OWNERS
@@ -1,4 +1,5 @@ hans@chromium.org +pcc@chromium.org thakis@chromium.org # Only for clang tooling.
diff --git a/tools/clang/blink_gc_plugin/BadPatternFinder.cpp b/tools/clang/blink_gc_plugin/BadPatternFinder.cpp new file mode 100644 index 0000000..4b8152b --- /dev/null +++ b/tools/clang/blink_gc_plugin/BadPatternFinder.cpp
@@ -0,0 +1,100 @@ +// Copyright 2017 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 "BadPatternFinder.h" +#include "DiagnosticsReporter.h" + +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" + +using namespace clang::ast_matchers; + +namespace { + +TypeMatcher GarbageCollectedType() { + auto has_gc_base = hasCanonicalType(hasDeclaration( + cxxRecordDecl(isDerivedFrom(hasAnyName("::blink::GarbageCollected", + "::blink::GarbageCollectedMixin"))) + .bind("gctype"))); + return anyOf(has_gc_base, + hasCanonicalType(arrayType(hasElementType(has_gc_base)))); +} + +class UniquePtrGarbageCollectedMatcher : public MatchFinder::MatchCallback { + public: + explicit UniquePtrGarbageCollectedMatcher(DiagnosticsReporter& diagnostics) + : diagnostics_(diagnostics) {} + + void Register(MatchFinder& match_finder) { + // Matches any application of make_unique where the template argument is + // known to refer to a garbage-collected type. + auto make_unique_matcher = + callExpr(callee(functionDecl( + hasAnyName( + "::std::make_unique", "::base::MakeUnique", + "::WTF::MakeUnique", "::base::WrapUnique", + "::WTF::WrapUnique", "::WTF::WrapArrayUnique"), + hasTemplateArgument( + 0, refersToType(GarbageCollectedType()))) + .bind("badfunc"))) + .bind("bad"); + match_finder.addDynamicMatcher(make_unique_matcher, this); + } + + void run(const MatchFinder::MatchResult& result) { + auto* bad_use = result.Nodes.getNodeAs<clang::Expr>("bad"); + auto* bad_function = result.Nodes.getNodeAs<clang::FunctionDecl>("badfunc"); + auto* gc_type = result.Nodes.getNodeAs<clang::CXXRecordDecl>("gctype"); + diagnostics_.UniquePtrUsedWithGC(bad_use, bad_function, gc_type); + } + + private: + DiagnosticsReporter& diagnostics_; +}; + +class OptionalGarbageCollectedMatcher : public MatchFinder::MatchCallback { + public: + explicit OptionalGarbageCollectedMatcher(DiagnosticsReporter& diagnostics) + : diagnostics_(diagnostics) {} + + void Register(MatchFinder& match_finder) { + // Matches any application of make_unique where the template argument is + // known to refer to a garbage-collected type. + auto optional_construction = + cxxConstructExpr(hasDeclaration(cxxConstructorDecl(ofClass( + classTemplateSpecializationDecl( + hasName("::base::Optional"), + hasTemplateArgument( + 0, refersToType(GarbageCollectedType()))) + .bind("optional"))))) + .bind("bad"); + match_finder.addDynamicMatcher(optional_construction, this); + } + + void run(const MatchFinder::MatchResult& result) { + auto* bad_use = result.Nodes.getNodeAs<clang::Expr>("bad"); + auto* optional = result.Nodes.getNodeAs<clang::CXXRecordDecl>("optional"); + auto* gc_type = result.Nodes.getNodeAs<clang::CXXRecordDecl>("gctype"); + diagnostics_.OptionalUsedWithGC(bad_use, optional, gc_type); + } + + private: + DiagnosticsReporter& diagnostics_; +}; + +} // namespace + +void FindBadPatterns(clang::ASTContext& ast_context, + DiagnosticsReporter& diagnostics) { + MatchFinder match_finder; + + UniquePtrGarbageCollectedMatcher unique_ptr_gc(diagnostics); + unique_ptr_gc.Register(match_finder); + + OptionalGarbageCollectedMatcher optional_gc(diagnostics); + optional_gc.Register(match_finder); + + match_finder.matchAST(ast_context); +}
diff --git a/tools/clang/blink_gc_plugin/BadPatternFinder.h b/tools/clang/blink_gc_plugin/BadPatternFinder.h new file mode 100644 index 0000000..1220b0b --- /dev/null +++ b/tools/clang/blink_gc_plugin/BadPatternFinder.h
@@ -0,0 +1,13 @@ +// Copyright 2017 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 DiagnosticsReporter; + +namespace clang { +class ASTContext; +} // namespace clang + +// Detects and reports use of banned patterns, such as applying +// std::make_unique to a garbage-collected type. +void FindBadPatterns(clang::ASTContext& ast_context, DiagnosticsReporter&);
diff --git a/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp b/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp index 36db12ab..ff6af46 100644 --- a/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp +++ b/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp
@@ -37,6 +37,8 @@ options_.warn_unneeded_finalizer = true; } else if (arg == "enable-weak-members-in-unmanaged-classes") { options_.enable_weak_members_in_unmanaged_classes = true; + } else if (arg == "warn-trace-wrappers-missing-base-dispatch") { + options_.warn_trace_wrappers_missing_base_dispatch = true; } else { llvm::errs() << "Unknown blink-gc-plugin argument: " << arg << "\n"; return false;
diff --git a/tools/clang/blink_gc_plugin/BlinkGCPluginConsumer.cpp b/tools/clang/blink_gc_plugin/BlinkGCPluginConsumer.cpp index e45ccf8..7ec37b3c 100644 --- a/tools/clang/blink_gc_plugin/BlinkGCPluginConsumer.cpp +++ b/tools/clang/blink_gc_plugin/BlinkGCPluginConsumer.cpp
@@ -7,11 +7,13 @@ #include <algorithm> #include <set> +#include "BadPatternFinder.h" #include "CheckDispatchVisitor.h" #include "CheckFieldsVisitor.h" #include "CheckFinalizerVisitor.h" #include "CheckGCRootsVisitor.h" #include "CheckTraceVisitor.h" +#include "CheckTraceWrappersVisitor.h" #include "CollectVisitor.h" #include "JsonWriter.h" #include "RecordInfo.h" @@ -117,11 +119,18 @@ for (const auto& method : visitor.trace_decls()) CheckTracingMethod(method); + if (options_.warn_trace_wrappers_missing_base_dispatch) { + for (const auto& method : visitor.trace_wrapper_decls()) + CheckWrapperTracingMethod(method); + } + if (json_) { json_->CloseList(); delete json_; json_ = 0; } + + FindBadPatterns(context, reporter_); } void BlinkGCPluginConsumer::ParseFunctionTemplates(TranslationUnitDecl* decl) { @@ -360,7 +369,7 @@ CXXRecordDecl* left_most = GetLeftMostBase(info->record()); if (!left_most) return; - if (!Config::IsGCBase(left_most->getName())) + if (!Config::IsGCBase(left_most->getName()) || Config::IsGCMixinBase(left_most->getName())) reporter_.ClassMustLeftMostlyDeriveGC(info); } @@ -522,6 +531,16 @@ CheckTraceOrDispatchMethod(parent, method); } +void BlinkGCPluginConsumer::CheckWrapperTracingMethod(CXXMethodDecl* method) { + RecordInfo* parent = cache_.Lookup(method->getParent()); + if (IsIgnored(parent)) + return; + + Config::TraceWrappersMethodType trace_wrappers_type = + Config::GetTraceWrappersMethodType(method); + CheckTraceWrappersMethod(parent, method, trace_wrappers_type); +} + void BlinkGCPluginConsumer::CheckTraceOrDispatchMethod( RecordInfo* parent, CXXMethodDecl* method) { @@ -561,6 +580,18 @@ } } +void BlinkGCPluginConsumer::CheckTraceWrappersMethod( + RecordInfo* parent, + clang::CXXMethodDecl* trace_wrappers, + Config::TraceWrappersMethodType trace_wrappers_type) { + CheckTraceWrappersVisitor visitor(trace_wrappers, parent, &cache_); + visitor.TraverseCXXMethodDecl(trace_wrappers); + + for (auto& base : parent->GetBases()) + if (!base.second.IsProperlyWrapperTraced()) + reporter_.BaseRequiresWrapperTracing(parent, trace_wrappers, base.first); +} + void BlinkGCPluginConsumer::DumpClass(RecordInfo* info) { if (!json_) return; @@ -590,7 +621,6 @@ (static_cast<RawPtr*>(Parent())->HasReferenceType() ? "reference" : "raw") : Parent()->IsRefPtr() ? "ref" : - Parent()->IsOwnPtr() ? "own" : Parent()->IsUniquePtr() ? "unique" : (Parent()->IsMember() || Parent()->IsWeakMember()) ? "mem" : "val");
diff --git a/tools/clang/blink_gc_plugin/BlinkGCPluginConsumer.h b/tools/clang/blink_gc_plugin/BlinkGCPluginConsumer.h index bcfb3af..d76ccf2 100644 --- a/tools/clang/blink_gc_plugin/BlinkGCPluginConsumer.h +++ b/tools/clang/blink_gc_plugin/BlinkGCPluginConsumer.h
@@ -57,6 +57,8 @@ // This is the main entry for tracing method definitions. void CheckTracingMethod(clang::CXXMethodDecl* method); + void CheckWrapperTracingMethod(clang::CXXMethodDecl* method); + // Determine what type of tracing method this is (dispatch or trace). void CheckTraceOrDispatchMethod(RecordInfo* parent, clang::CXXMethodDecl* method); @@ -66,6 +68,11 @@ clang::CXXMethodDecl* trace, Config::TraceMethodType trace_type); + void CheckTraceWrappersMethod( + RecordInfo* parent, + clang::CXXMethodDecl* trace_wrappers, + Config::TraceWrappersMethodType trace_wrappers_type); + void DumpClass(RecordInfo* info); // Adds either a warning or error, based on the current handling of -Werror.
diff --git a/tools/clang/blink_gc_plugin/BlinkGCPluginOptions.h b/tools/clang/blink_gc_plugin/BlinkGCPluginOptions.h index 4af8950..f69976d 100644 --- a/tools/clang/blink_gc_plugin/BlinkGCPluginOptions.h +++ b/tools/clang/blink_gc_plugin/BlinkGCPluginOptions.h
@@ -30,6 +30,9 @@ // TODO(sof): remove this option once safely rolled out. bool enable_weak_members_in_unmanaged_classes = false; + // Warn on missing dispatches to base class TraceWrappers. + bool warn_trace_wrappers_missing_base_dispatch = false; + std::set<std::string> ignored_classes; std::set<std::string> checked_namespaces; std::vector<std::string> ignored_directories;
diff --git a/tools/clang/blink_gc_plugin/CMakeLists.txt b/tools/clang/blink_gc_plugin/CMakeLists.txt index 009807b..5188def 100644 --- a/tools/clang/blink_gc_plugin/CMakeLists.txt +++ b/tools/clang/blink_gc_plugin/CMakeLists.txt
@@ -1,6 +1,7 @@ set(LIBRARYNAME BlinkGCPlugin) set(plugin_sources + BadPatternFinder.cpp BlinkGCPlugin.cpp BlinkGCPluginConsumer.cpp CheckDispatchVisitor.cpp @@ -8,6 +9,7 @@ CheckFinalizerVisitor.cpp CheckGCRootsVisitor.cpp CheckTraceVisitor.cpp + CheckTraceWrappersVisitor.cpp CollectVisitor.cpp Config.cpp DiagnosticsReporter.cpp
diff --git a/tools/clang/blink_gc_plugin/CheckFieldsVisitor.cpp b/tools/clang/blink_gc_plugin/CheckFieldsVisitor.cpp index 735ec0e8..9f783f9 100644 --- a/tools/clang/blink_gc_plugin/CheckFieldsVisitor.cpp +++ b/tools/clang/blink_gc_plugin/CheckFieldsVisitor.cpp
@@ -97,9 +97,8 @@ if (!Parent() || !edge->value()->IsGCAllocated()) return; - // Disallow OwnPtr<T>, RefPtr<T> and T* to stack-allocated types. - if (Parent()->IsOwnPtr() || - Parent()->IsUniquePtr() || + // Disallow unique_ptr<T>, RefPtr<T> and T* to stack-allocated types. + if (Parent()->IsUniquePtr() || Parent()->IsRefPtr() || (stack_allocated_host_ && Parent()->IsRawPtr())) { invalid_fields_.push_back(std::make_pair( @@ -115,8 +114,6 @@ } void CheckFieldsVisitor::AtCollection(Collection* edge) { - if (edge->on_heap() && Parent() && Parent()->IsOwnPtr()) - invalid_fields_.push_back(std::make_pair(current_, kOwnPtrToGCManaged)); if (edge->on_heap() && Parent() && Parent()->IsUniquePtr()) invalid_fields_.push_back(std::make_pair(current_, kUniquePtrToGCManaged)); } @@ -130,8 +127,6 @@ } if (ptr->IsRefPtr()) return kRefPtrToGCManaged; - if (ptr->IsOwnPtr()) - return kOwnPtrToGCManaged; if (ptr->IsUniquePtr()) return kUniquePtrToGCManaged; assert(false && "Unknown smart pointer kind");
diff --git a/tools/clang/blink_gc_plugin/CheckFieldsVisitor.h b/tools/clang/blink_gc_plugin/CheckFieldsVisitor.h index c47f1d4..b7b68c2f 100644 --- a/tools/clang/blink_gc_plugin/CheckFieldsVisitor.h +++ b/tools/clang/blink_gc_plugin/CheckFieldsVisitor.h
@@ -13,7 +13,7 @@ class FieldPoint; // This visitor checks that the fields of a class are "well formed". -// - OwnPtr and RefPtr must not point to a GC derived type. +// - unique_ptr and RefPtr must not point to a GC derived type. // - Part objects must not be a GC derived type. // - An on-heap class must never contain GC roots. // - Only stack-allocated types may point to stack-allocated types. @@ -24,7 +24,6 @@ kRawPtrToGCManaged, kRefPtrToGCManaged, kReferencePtrToGCManaged, - kOwnPtrToGCManaged, kUniquePtrToGCManaged, kMemberToGCUnmanaged, kMemberInUnmanaged,
diff --git a/tools/clang/blink_gc_plugin/CheckTraceWrappersVisitor.cpp b/tools/clang/blink_gc_plugin/CheckTraceWrappersVisitor.cpp new file mode 100644 index 0000000..106f983 --- /dev/null +++ b/tools/clang/blink_gc_plugin/CheckTraceWrappersVisitor.cpp
@@ -0,0 +1,103 @@ +// Copyright 2018 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 "CheckTraceWrappersVisitor.h" + +#include <vector> + +#include "Config.h" + +using namespace clang; + +CheckTraceWrappersVisitor::CheckTraceWrappersVisitor(CXXMethodDecl* trace, + RecordInfo* info, + RecordCache* cache) + : trace_wrappers_(trace), info_(info), cache_(cache) {} + +bool CheckTraceWrappersVisitor::VisitCallExpr(CallExpr* call) { + CheckTraceBaseCall(call); + return true; +} + +bool CheckTraceWrappersVisitor::IsTraceWrappersCallName( + const std::string& name) { + // See CheckTraceVisitor::IsTraceCallName. + return name == trace_wrappers_->getName(); +} + +bool CheckTraceWrappersVisitor::CheckTraceBaseCall(CallExpr* call) { + // Checks for "Base::TraceWrappers(visitor)"-like calls. + + // For example, if we've got "Base::TraceWrappers(visitor)" as |call|, + // callee_record will be "Base", and func_name will be "TraceWrappers". + CXXRecordDecl* callee_record = nullptr; + std::string func_name; + + if (MemberExpr* callee = dyn_cast<MemberExpr>(call->getCallee())) { + if (!callee->hasQualifier()) + return false; + + FunctionDecl* trace_decl = dyn_cast<FunctionDecl>(callee->getMemberDecl()); + if (!trace_decl || !Config::IsTraceWrappersMethod(trace_decl)) + return false; + + const Type* type = callee->getQualifier()->getAsType(); + if (!type) + return false; + + callee_record = type->getAsCXXRecordDecl(); + func_name = trace_decl->getName(); + } + + if (!callee_record) + return false; + + if (!IsTraceWrappersCallName(func_name)) + return false; + + for (auto& base : info_->GetBases()) { + // We want to deal with omitted TraceWrappers() function in an intermediary + // class in the class hierarchy, e.g.: + // class A : public TraceWrapperBase<A> { TraceWrappers() { ... } }; + // class B : public A { + // /* No TraceWrappers(); have nothing to trace. */ + // }; + // class C : public B { TraceWrappers() { B::TraceWrappers(visitor); } } + // where, B::TraceWrappers() is actually A::TraceWrappers(), and in some + // cases we get A as |callee_record| instead of B. We somehow need to mark B + // as wrapper traced if we find A::TraceWrappers() call. + // + // To solve this, here we keep going up the class hierarchy as long as + // they are not required to have a trace method. The implementation is + // a simple DFS, where |base_records| represents the set of base classes + // we need to visit. + + std::vector<CXXRecordDecl*> base_records; + base_records.push_back(base.first); + + while (!base_records.empty()) { + CXXRecordDecl* base_record = base_records.back(); + base_records.pop_back(); + + if (base_record == callee_record) { + // If we find a matching trace method, pretend the user has written + // a correct trace() method of the base; in the example above, we + // find A::trace() here and mark B as correctly traced. + base.second.MarkWrapperTraced(); + return true; + } + + if (RecordInfo* base_info = cache_->Lookup(base_record)) { + if (!base_info->RequiresTraceWrappersMethod()) { + // If this base class is not required to have a trace method, then + // the actual trace method may be defined in an ancestor. + for (auto& inner_base : base_info->GetBases()) + base_records.push_back(inner_base.first); + } + } + } + } + + return false; +}
diff --git a/tools/clang/blink_gc_plugin/CheckTraceWrappersVisitor.h b/tools/clang/blink_gc_plugin/CheckTraceWrappersVisitor.h new file mode 100644 index 0000000..6190465 --- /dev/null +++ b/tools/clang/blink_gc_plugin/CheckTraceWrappersVisitor.h
@@ -0,0 +1,39 @@ +// Copyright 2018 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. + +#ifndef TOOLS_BLINK_GC_PLUGIN_CHECK_TRACE_WRAPPERS_VISITOR_H_ +#define TOOLS_BLINK_GC_PLUGIN_CHECK_TRACE_WRAPPERS_VISITOR_H_ + +#include <string> + +#include "RecordInfo.h" +#include "clang/AST/AST.h" +#include "clang/AST/RecursiveASTVisitor.h" + +class RecordCache; +class RecordInfo; + +// This visitor checks a wrapper tracing method by traversing its body. +// - A base is wrapper traced if a base-qualified call to a trace method is +// found. +class CheckTraceWrappersVisitor + : public clang::RecursiveASTVisitor<CheckTraceWrappersVisitor> { + public: + CheckTraceWrappersVisitor(clang::CXXMethodDecl* trace, + RecordInfo* info, + RecordCache* cache); + + bool VisitCallExpr(clang::CallExpr* call); + + private: + bool IsTraceWrappersCallName(const std::string& name); + + bool CheckTraceBaseCall(clang::CallExpr* call); + + clang::CXXMethodDecl* trace_wrappers_; + RecordInfo* info_; + RecordCache* cache_; +}; + +#endif // TOOLS_BLINK_GC_PLUGIN_CHECK_TRACE_WRAPPERS_VISITOR_H_
diff --git a/tools/clang/blink_gc_plugin/CollectVisitor.cpp b/tools/clang/blink_gc_plugin/CollectVisitor.cpp index 203e8adf..0f999a4 100644 --- a/tools/clang/blink_gc_plugin/CollectVisitor.cpp +++ b/tools/clang/blink_gc_plugin/CollectVisitor.cpp
@@ -19,6 +19,10 @@ return trace_decls_; } +CollectVisitor::MethodVector& CollectVisitor::trace_wrapper_decls() { + return trace_wrapper_decls_; +} + bool CollectVisitor::VisitCXXRecordDecl(CXXRecordDecl* record) { if (record->hasDefinition() && record->isCompleteDefinition()) record_decls_.push_back(record); @@ -26,7 +30,12 @@ } bool CollectVisitor::VisitCXXMethodDecl(CXXMethodDecl* method) { - if (method->isThisDeclarationADefinition() && Config::IsTraceMethod(method)) - trace_decls_.push_back(method); + if (method->isThisDeclarationADefinition()) { + if (Config::IsTraceMethod(method)) { + trace_decls_.push_back(method); + } + if (Config::IsTraceWrappersMethod(method)) + trace_wrapper_decls_.push_back(method); + } return true; }
diff --git a/tools/clang/blink_gc_plugin/CollectVisitor.h b/tools/clang/blink_gc_plugin/CollectVisitor.h index a3ccdd8..4adf819 100644 --- a/tools/clang/blink_gc_plugin/CollectVisitor.h +++ b/tools/clang/blink_gc_plugin/CollectVisitor.h
@@ -20,6 +20,7 @@ RecordVector& record_decls(); MethodVector& trace_decls(); + MethodVector& trace_wrapper_decls(); // Collect record declarations, including nested declarations. bool VisitCXXRecordDecl(clang::CXXRecordDecl* record); @@ -30,6 +31,7 @@ private: RecordVector record_decls_; MethodVector trace_decls_; + MethodVector trace_wrapper_decls_; }; #endif // TOOLS_BLINK_GC_PLUGIN_COLLECT_VISITOR_H_
diff --git a/tools/clang/blink_gc_plugin/Config.cpp b/tools/clang/blink_gc_plugin/Config.cpp index df8867a9..4b3a1a3 100644 --- a/tools/clang/blink_gc_plugin/Config.cpp +++ b/tools/clang/blink_gc_plugin/Config.cpp
@@ -13,6 +13,7 @@ const char kNewOperatorName[] = "operator new"; const char kCreateName[] = "Create"; const char kTraceName[] = "Trace"; +const char kTraceWrappersName[] = "TraceWrappers"; const char kFinalizeName[] = "FinalizeGarbageCollectedObject"; const char kTraceAfterDispatchName[] = "TraceAfterDispatch"; const char kRegisterWeakMembersName[] = "RegisterWeakMembers"; @@ -28,6 +29,10 @@ const char kConstReverseIteratorName[] = "const_reverse_iterator"; const char kReverseIteratorName[] = "reverse_iterator"; +const char* kIgnoredTraceWrapperNames[] = { + "blink::ScriptWrappableVisitor::TraceWrappers", + "blink::WrapperMarkingData::TraceWrappers"}; + bool Config::IsTemplateInstantiation(CXXRecordDecl* record) { ClassTemplateSpecializationDecl* spec = dyn_cast<clang::ClassTemplateSpecializationDecl>(record); @@ -47,3 +52,29 @@ assert(false && "Unknown template specialization kind"); return false; } + +// static +Config::TraceWrappersMethodType Config::GetTraceWrappersMethodType( + const clang::FunctionDecl* method) { + if (method->getNumParams() != 1) + return NOT_TRACE_WRAPPERS_METHOD; + + const std::string& name = method->getNameAsString(); + const std::string& full_name = method->getQualifiedNameAsString(); + for (size_t i = 0; i < (sizeof(kIgnoredTraceWrapperNames) / + sizeof(kIgnoredTraceWrapperNames[0])); + i++) { + if (full_name == kIgnoredTraceWrapperNames[i]) + return NOT_TRACE_WRAPPERS_METHOD; + } + + if (name == kTraceWrappersName) + return TRACE_WRAPPERS_METHOD; + + return NOT_TRACE_WRAPPERS_METHOD; +} + +// static +bool Config::IsTraceWrappersMethod(const clang::FunctionDecl* method) { + return GetTraceWrappersMethodType(method) != NOT_TRACE_WRAPPERS_METHOD; +}
diff --git a/tools/clang/blink_gc_plugin/Config.h b/tools/clang/blink_gc_plugin/Config.h index 13d38e8..527fe1c3 100644 --- a/tools/clang/blink_gc_plugin/Config.h +++ b/tools/clang/blink_gc_plugin/Config.h
@@ -20,6 +20,7 @@ extern const char kNewOperatorName[]; extern const char kCreateName[]; extern const char kTraceName[]; +extern const char kTraceWrappersName[]; extern const char kFinalizeName[]; extern const char kTraceAfterDispatchName[]; extern const char kRegisterWeakMembersName[]; @@ -35,6 +36,8 @@ extern const char kConstReverseIteratorName[]; extern const char kReverseIteratorName[]; +extern const char* kIgnoredTraceWrapperNames[]; + class Config { public: static bool IsMember(const std::string& name) { @@ -64,10 +67,6 @@ return name == "RefPtr"; } - static bool IsOwnPtr(const std::string& name) { - return name == "OwnPtr"; - } - static bool IsUniquePtr(const std::string& name) { return name == "unique_ptr"; } @@ -143,6 +142,10 @@ IsGCMixinBase(name); } + static bool IsTraceWrapperBase(const std::string& name) { + return name == "TraceWrapperBase"; + } + static bool IsIterator(const std::string& name) { return name == kIteratorName || name == kConstIteratorName || name == kReverseIteratorName || name == kConstReverseIteratorName; @@ -243,6 +246,17 @@ return GetTraceMethodType(method) != NOT_TRACE_METHOD; } + enum TraceWrappersMethodType { + NOT_TRACE_WRAPPERS_METHOD, + TRACE_WRAPPERS_METHOD, + // TODO(mlippautz): TRACE_WRAPPERS_AFTER_DISPATCH_METHOD + }; + + static TraceWrappersMethodType GetTraceWrappersMethodType( + const clang::FunctionDecl* method); + + static bool IsTraceWrappersMethod(const clang::FunctionDecl* method); + static bool StartsWith(const std::string& str, const std::string& prefix) { if (prefix.size() > str.size()) return false;
diff --git a/tools/clang/blink_gc_plugin/DiagnosticsReporter.cpp b/tools/clang/blink_gc_plugin/DiagnosticsReporter.cpp index 95d5595..6e704f2 100644 --- a/tools/clang/blink_gc_plugin/DiagnosticsReporter.cpp +++ b/tools/clang/blink_gc_plugin/DiagnosticsReporter.cpp
@@ -9,7 +9,7 @@ namespace { const char kClassMustLeftMostlyDeriveGC[] = - "[blink-gc] Class %0 must derive its GC base in the left-most position."; + "[blink-gc] Class %0 must derive from GarbageCollected in the left-most position."; const char kClassRequiresTraceMethod[] = "[blink-gc] Class %0 requires a trace method."; @@ -17,6 +17,9 @@ const char kBaseRequiresTracing[] = "[blink-gc] Base class %0 of derived class %1 requires tracing."; +const char kBaseRequiresWrapperTracing[] = + "[blink-gc] Base class %0 of derived class %1 requires wrapper tracing."; + const char kBaseRequiresTracingNote[] = "[blink-gc] Untraced base class %0 declared here:"; @@ -60,9 +63,6 @@ "[blink-gc] Reference pointer field %0 to a GC managed class" " declared here:"; -const char kOwnPtrToGCManagedClassNote[] = - "[blink-gc] OwnPtr field %0 to a GC managed class declared here:"; - const char kUniquePtrToGCManagedClassNote[] = "[blink-gc] std::unique_ptr field %0 to a GC managed class declared here:"; @@ -154,6 +154,14 @@ "[blink-gc] The stack allocated class %0 provides an unnecessary " "trace method:"; +const char kUniquePtrUsedWithGC[] = + "[blink-gc] Disallowed use of %0 found; %1 is a garbage-collected type. " + "std::unique_ptr cannot hold garbage-collected objects."; + +const char kOptionalUsedWithGC[] = + "[blink-gc] Disallowed construction of %0 found; %1 is a garbage-collected " + "type. optional cannot hold garbage-collected objects."; + } // namespace DiagnosticBuilder DiagnosticsReporter::ReportDiagnostic( @@ -176,6 +184,8 @@ diagnostic_.getCustomDiagID(getErrorLevel(), kClassRequiresTraceMethod); diag_base_requires_tracing_ = diagnostic_.getCustomDiagID(getErrorLevel(), kBaseRequiresTracing); + diag_base_requires_wrapper_tracing_ = + diagnostic_.getCustomDiagID(getErrorLevel(), kBaseRequiresWrapperTracing); diag_fields_require_tracing_ = diagnostic_.getCustomDiagID(getErrorLevel(), kFieldsRequireTracing); diag_fields_improperly_traced_ = @@ -232,8 +242,6 @@ DiagnosticsEngine::Note, kRefPtrToGCManagedClassNote); diag_reference_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID( DiagnosticsEngine::Note, kReferencePtrToGCManagedClassNote); - diag_own_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID( - DiagnosticsEngine::Note, kOwnPtrToGCManagedClassNote); diag_unique_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID( DiagnosticsEngine::Note, kUniquePtrToGCManagedClassNote); diag_member_to_gc_unmanaged_class_note_ = diagnostic_.getCustomDiagID( @@ -264,6 +272,11 @@ DiagnosticsEngine::Note, kOverriddenNonVirtualTraceNote); diag_manual_dispatch_method_note_ = diagnostic_.getCustomDiagID( DiagnosticsEngine::Note, kManualDispatchMethodNote); + + diag_unique_ptr_used_with_gc_ = + diagnostic_.getCustomDiagID(getErrorLevel(), kUniquePtrUsedWithGC); + diag_optional_used_with_gc_ = + diagnostic_.getCustomDiagID(getErrorLevel(), kOptionalUsedWithGC); } bool DiagnosticsReporter::hasErrorOccurred() const @@ -305,6 +318,13 @@ << base << derived->record(); } +void DiagnosticsReporter::BaseRequiresWrapperTracing(RecordInfo* derived, + CXXMethodDecl* trace, + CXXRecordDecl* base) { + ReportDiagnostic(trace->getLocStart(), diag_base_requires_wrapper_tracing_) + << base << derived->record(); +} + void DiagnosticsReporter::FieldsImproperlyTraced( RecordInfo* info, CXXMethodDecl* trace) { @@ -342,8 +362,6 @@ note = diag_ref_ptr_to_gc_managed_class_note_; } else if (error.second == CheckFieldsVisitor::kReferencePtrToGCManaged) { note = diag_reference_ptr_to_gc_managed_class_note_; - } else if (error.second == CheckFieldsVisitor::kOwnPtrToGCManaged) { - note = diag_own_ptr_to_gc_managed_class_note_; } else if (error.second == CheckFieldsVisitor::kUniquePtrToGCManaged) { note = diag_unique_ptr_to_gc_managed_class_note_; } else if (error.second == CheckFieldsVisitor::kMemberToGCUnmanaged) { @@ -580,3 +598,19 @@ diag_overridden_non_virtual_trace_note_) << overridden; } + +void DiagnosticsReporter::UniquePtrUsedWithGC( + const clang::Expr* expr, + const clang::FunctionDecl* bad_function, + const clang::CXXRecordDecl* gc_type) { + ReportDiagnostic(expr->getLocStart(), diag_unique_ptr_used_with_gc_) + << bad_function << gc_type << expr->getSourceRange(); +} + +void DiagnosticsReporter::OptionalUsedWithGC( + const clang::Expr* expr, + const clang::CXXRecordDecl* optional, + const clang::CXXRecordDecl* gc_type) { + ReportDiagnostic(expr->getLocStart(), diag_optional_used_with_gc_) + << optional << gc_type << expr->getSourceRange(); +}
diff --git a/tools/clang/blink_gc_plugin/DiagnosticsReporter.h b/tools/clang/blink_gc_plugin/DiagnosticsReporter.h index 6a32f70..784e4d8 100644 --- a/tools/clang/blink_gc_plugin/DiagnosticsReporter.h +++ b/tools/clang/blink_gc_plugin/DiagnosticsReporter.h
@@ -30,6 +30,9 @@ void BaseRequiresTracing(RecordInfo* derived, clang::CXXMethodDecl* trace, clang::CXXRecordDecl* base); + void BaseRequiresWrapperTracing(RecordInfo* derived, + clang::CXXMethodDecl* trace, + clang::CXXRecordDecl* base); void FieldsImproperlyTraced(RecordInfo* info, clang::CXXMethodDecl* trace); void ClassContainsInvalidFields( @@ -79,6 +82,14 @@ void NoteField(clang::FieldDecl* field, unsigned note); void NoteOverriddenNonVirtualTrace(clang::CXXMethodDecl* overridden); + // Used by FindBadPatterns. + void UniquePtrUsedWithGC(const clang::Expr* expr, + const clang::FunctionDecl* bad_function, + const clang::CXXRecordDecl* gc_type); + void OptionalUsedWithGC(const clang::Expr* expr, + const clang::CXXRecordDecl* optional, + const clang::CXXRecordDecl* gc_type); + private: clang::DiagnosticBuilder ReportDiagnostic( clang::SourceLocation location, @@ -95,6 +106,7 @@ unsigned diag_class_must_left_mostly_derive_gc_; unsigned diag_class_requires_trace_method_; unsigned diag_base_requires_tracing_; + unsigned diag_base_requires_wrapper_tracing_; unsigned diag_fields_require_tracing_; unsigned diag_fields_improperly_traced_; unsigned diag_class_contains_invalid_fields_; @@ -139,6 +151,9 @@ unsigned diag_manual_dispatch_method_note_; unsigned diag_iterator_to_gc_managed_collection_note_; unsigned diag_trace_method_of_stack_allocated_parent_; + + unsigned diag_unique_ptr_used_with_gc_; + unsigned diag_optional_used_with_gc_; }; #endif // TOOLS_BLINK_GC_PLUGIN_DIAGNOSTICS_REPORTER_H_
diff --git a/tools/clang/blink_gc_plugin/Edge.cpp b/tools/clang/blink_gc_plugin/Edge.cpp index 428e747..9136bdf 100644 --- a/tools/clang/blink_gc_plugin/Edge.cpp +++ b/tools/clang/blink_gc_plugin/Edge.cpp
@@ -16,7 +16,6 @@ void RecursiveEdgeVisitor::AtValue(Value*) {} void RecursiveEdgeVisitor::AtRawPtr(RawPtr*) {} void RecursiveEdgeVisitor::AtRefPtr(RefPtr*) {} -void RecursiveEdgeVisitor::AtOwnPtr(OwnPtr*) {} void RecursiveEdgeVisitor::AtUniquePtr(UniquePtr*) {} void RecursiveEdgeVisitor::AtMember(Member*) {} void RecursiveEdgeVisitor::AtWeakMember(WeakMember*) {} @@ -42,12 +41,6 @@ e->ptr()->Accept(this); Leave(); } -void RecursiveEdgeVisitor::VisitOwnPtr(OwnPtr* e) { - AtOwnPtr(e); - Enter(e); - e->ptr()->Accept(this); - Leave(); -} void RecursiveEdgeVisitor::VisitUniquePtr(UniquePtr* e) { AtUniquePtr(e);
diff --git a/tools/clang/blink_gc_plugin/Edge.h b/tools/clang/blink_gc_plugin/Edge.h index 164112f..5549e6a7 100644 --- a/tools/clang/blink_gc_plugin/Edge.h +++ b/tools/clang/blink_gc_plugin/Edge.h
@@ -18,7 +18,6 @@ class CrossThreadPersistent; class Iterator; class Member; -class OwnPtr; class Persistent; class RawPtr; class RefPtr; @@ -33,7 +32,6 @@ virtual void VisitValue(Value*) {} virtual void VisitRawPtr(RawPtr*) {} virtual void VisitRefPtr(RefPtr*) {} - virtual void VisitOwnPtr(OwnPtr*) {} virtual void VisitUniquePtr(UniquePtr*) {} virtual void VisitMember(Member*) {} virtual void VisitWeakMember(WeakMember*) {} @@ -50,7 +48,6 @@ void VisitValue(Value*) override; void VisitRawPtr(RawPtr*) override; void VisitRefPtr(RefPtr*) override; - void VisitOwnPtr(OwnPtr*) override; void VisitUniquePtr(UniquePtr*) override; void VisitMember(Member*) override; void VisitWeakMember(WeakMember*) override; @@ -70,7 +67,6 @@ virtual void AtValue(Value*); virtual void AtRawPtr(RawPtr*); virtual void AtRefPtr(RefPtr*); - virtual void AtOwnPtr(OwnPtr*); virtual void AtUniquePtr(UniquePtr*); virtual void AtMember(Member*); virtual void AtWeakMember(WeakMember*); @@ -100,7 +96,6 @@ virtual bool IsValue() { return false; } virtual bool IsRawPtr() { return false; } virtual bool IsRefPtr() { return false; } - virtual bool IsOwnPtr() { return false; } virtual bool IsUniquePtr() { return false; } virtual bool IsMember() { return false; } virtual bool IsWeakMember() { return false; } @@ -168,18 +163,6 @@ void Accept(EdgeVisitor* visitor) override { visitor->VisitRefPtr(this); } }; -class OwnPtr : public PtrEdge { - public: - explicit OwnPtr(Edge* ptr) : PtrEdge(ptr) { } - bool IsOwnPtr() override { return true; } - LivenessKind Kind() override { return kStrong; } - bool NeedsFinalization() override { return true; } - TracingStatus NeedsTracing(NeedsTracingOption) override { - return TracingStatus::Illegal(); - } - void Accept(EdgeVisitor* visitor) override { visitor->VisitOwnPtr(this); } -}; - class UniquePtr : public PtrEdge { public: explicit UniquePtr(Edge* ptr) : PtrEdge(ptr) { }
diff --git a/tools/clang/blink_gc_plugin/RecordInfo.cpp b/tools/clang/blink_gc_plugin/RecordInfo.cpp index 419ed7a..5f4f7ca4 100644 --- a/tools/clang/blink_gc_plugin/RecordInfo.cpp +++ b/tools/clang/blink_gc_plugin/RecordInfo.cpp
@@ -24,7 +24,9 @@ is_declaring_local_trace_(kNotComputed), is_eagerly_finalized_(kNotComputed), determined_trace_methods_(false), + determined_wrapper_trace_methods_(false), trace_method_(0), + trace_wrappers_method_(0), trace_dispatch_method_(0), finalize_dispatch_method_(0), is_gc_derived_(false) {} @@ -170,6 +172,14 @@ return IsGCDerived() || IsHeapAllocatedCollection(); } +bool RecordInfo::IsTraceWrapperBase() { + for (const auto& gc_base : gc_base_names_) { + if (Config::IsTraceWrapperBase(gc_base)) + return true; + } + return false; +} + bool RecordInfo::IsEagerlyFinalized() { if (is_eagerly_finalized_ != kNotComputed) return is_eagerly_finalized_; @@ -292,6 +302,23 @@ return fields_need_tracing_.IsNeeded(); } +bool RecordInfo::RequiresTraceWrappersMethod() { + if (IsStackAllocated()) + return false; + + if (IsTraceWrapperBase()) + return true; + + unsigned bases_with_trace_wrappers = 0; + for (Bases::iterator it = GetBases().begin(); it != GetBases().end(); ++it) { + if (it->second.NeedsWrapperTracing().IsNeeded()) + ++bases_with_trace_wrappers; + } + if (bases_with_trace_wrappers > 1) + return true; + return false; +} + // Get the actual tracing method (ie, can be traceAfterDispatch if there is a // dispatch method). CXXMethodDecl* RecordInfo::GetTraceMethod() { @@ -299,6 +326,11 @@ return trace_method_; } +CXXMethodDecl* RecordInfo::GetTraceWrappersMethod() { + DetermineWrapperTracingMethods(); + return trace_wrappers_method_; +} + // Get the static trace dispatch method. CXXMethodDecl* RecordInfo::GetTraceDispatchMethod() { DetermineTracingMethods(); @@ -326,6 +358,16 @@ return false; } +bool RecordInfo::InheritsTraceWrappers() { + if (GetTraceWrappersMethod()) + return true; + for (Bases::iterator it = GetBases().begin(); it != GetBases().end(); ++it) { + if (it->second.info()->InheritsTraceWrappers()) + return true; + } + return false; +} + CXXMethodDecl* RecordInfo::InheritsNonVirtualTrace() { if (CXXMethodDecl* trace = GetTraceMethod()) return trace->isVirtual() ? 0 : trace; @@ -392,7 +434,11 @@ TracingStatus status = info->InheritsTrace() ? TracingStatus::Needed() : TracingStatus::Unneeded(); - bases->push_back(std::make_pair(base, BasePoint(spec, info, status))); + TracingStatus wrapper_status = info->InheritsTraceWrappers() + ? TracingStatus::Needed() + : TracingStatus::Unneeded(); + bases->push_back( + std::make_pair(base, BasePoint(spec, info, status, wrapper_status))); } return bases; } @@ -431,6 +477,36 @@ return fields; } +void RecordInfo::DetermineWrapperTracingMethods() { + if (determined_wrapper_trace_methods_) + return; + determined_wrapper_trace_methods_ = true; + + if (Config::IsTraceWrapperBase(name_)) + return; + + CXXMethodDecl* trace_wrappers = nullptr; + for (Decl* decl : record_->decls()) { + CXXMethodDecl* method = dyn_cast<CXXMethodDecl>(decl); + if (!method) { + if (FunctionTemplateDecl* func_template = + dyn_cast<FunctionTemplateDecl>(decl)) + method = dyn_cast<CXXMethodDecl>(func_template->getTemplatedDecl()); + } + if (!method) + continue; + + switch (Config::GetTraceWrappersMethodType(method)) { + case Config::TRACE_METHOD: + trace_wrappers = method; + break; + case Config::NOT_TRACE_METHOD: + break; + } + } + trace_wrappers_method_ = trace_wrappers; +} + void RecordInfo::DetermineTracingMethods() { if (determined_trace_methods_) return; @@ -559,6 +635,18 @@ return fields_need_tracing_; } +TracingStatus RecordInfo::NeedsWrapperTracing() { + if (IsStackAllocated()) + return TracingStatus::Unneeded(); + + for (Bases::iterator it = GetBases().begin(); it != GetBases().end(); ++it) { + if (it->second.info()->NeedsWrapperTracing().IsNeeded()) + return TracingStatus::Needed(); + } + + return TracingStatus::Unneeded(); +} + static bool isInStdNamespace(clang::Sema& sema, NamespaceDecl* ns) { while (ns) { @@ -625,12 +713,6 @@ return 0; } - if (Config::IsOwnPtr(info->name()) && info->GetTemplateArgs(1, &args)) { - if (Edge* ptr = CreateEdge(args[0])) - return new OwnPtr(ptr); - return 0; - } - if (Config::IsUniquePtr(info->name()) && info->GetTemplateArgs(1, &args)) { // Check that this is std::unique_ptr NamespaceDecl* ns =
diff --git a/tools/clang/blink_gc_plugin/RecordInfo.h b/tools/clang/blink_gc_plugin/RecordInfo.h index 220a6d3..8ec92ec 100644 --- a/tools/clang/blink_gc_plugin/RecordInfo.h +++ b/tools/clang/blink_gc_plugin/RecordInfo.h
@@ -23,24 +23,35 @@ // A potentially tracable and/or lifetime affecting point in the object graph. class GraphPoint { public: - GraphPoint() : traced_(false) {} + GraphPoint() : traced_(false), wrapper_traced_(false) {} virtual ~GraphPoint() {} void MarkTraced() { traced_ = true; } + void MarkWrapperTraced() { wrapper_traced_ = true; } bool IsProperlyTraced() { return traced_ || !NeedsTracing().IsNeeded(); } bool IsInproperlyTraced() { return traced_ && NeedsTracing().IsIllegal(); } + bool IsProperlyWrapperTraced() { + return wrapper_traced_ || !NeedsWrapperTracing().IsNeeded(); + } virtual const TracingStatus NeedsTracing() = 0; + virtual const TracingStatus NeedsWrapperTracing() = 0; private: bool traced_; + bool wrapper_traced_; }; class BasePoint : public GraphPoint { public: BasePoint(const clang::CXXBaseSpecifier& spec, RecordInfo* info, - const TracingStatus& status) - : spec_(spec), info_(info), status_(status) {} + const TracingStatus& status, + const TracingStatus& wrapper_status) + : spec_(spec), + info_(info), + status_(status), + wrapper_status_(wrapper_status) {} const TracingStatus NeedsTracing() { return status_; } + const TracingStatus NeedsWrapperTracing() { return wrapper_status_; } const clang::CXXBaseSpecifier& spec() { return spec_; } RecordInfo* info() { return info_; } @@ -48,6 +59,7 @@ const clang::CXXBaseSpecifier& spec_; RecordInfo* info_; TracingStatus status_; + TracingStatus wrapper_status_; }; class FieldPoint : public GraphPoint { @@ -57,6 +69,7 @@ const TracingStatus NeedsTracing() { return edge_->NeedsTracing(Edge::kRecursive); } + const TracingStatus NeedsWrapperTracing() { return TracingStatus::Illegal(); } clang::FieldDecl* field() { return field_; } Edge* edge() { return edge_; } @@ -89,6 +102,7 @@ Fields& GetFields(); Bases& GetBases(); clang::CXXMethodDecl* GetTraceMethod(); + clang::CXXMethodDecl* GetTraceWrappersMethod(); clang::CXXMethodDecl* GetTraceDispatchMethod(); clang::CXXMethodDecl* GetFinalizeDispatchMethod(); @@ -99,6 +113,7 @@ bool IsGCAllocated(); bool IsGCFinalized(); bool IsGCMixin(); + bool IsTraceWrapperBase(); bool IsStackAllocated(); bool IsNonNewable(); bool IsOnlyPlacementNewable(); @@ -110,9 +125,11 @@ bool RequiresTraceMethod(); bool NeedsFinalization(); + bool RequiresTraceWrappersMethod(); bool DeclaresGCMixinMethods(); bool DeclaresLocalTraceMethod(); TracingStatus NeedsTracing(Edge::NeedsTracingOption); + TracingStatus NeedsWrapperTracing(); clang::CXXMethodDecl* InheritsNonVirtualTrace(); bool IsConsideredAbstract(); @@ -126,7 +143,9 @@ Fields* CollectFields(); Bases* CollectBases(); void DetermineTracingMethods(); + void DetermineWrapperTracingMethods(); bool InheritsTrace(); + bool InheritsTraceWrappers(); Edge* CreateEdge(const clang::Type* type); Edge* CreateEdgeFromOriginalType(const clang::Type* type); @@ -148,7 +167,9 @@ CachedBool is_eagerly_finalized_; bool determined_trace_methods_; + bool determined_wrapper_trace_methods_; clang::CXXMethodDecl* trace_method_; + clang::CXXMethodDecl* trace_wrappers_method_; clang::CXXMethodDecl* trace_dispatch_method_; clang::CXXMethodDecl* finalize_dispatch_method_;
diff --git a/tools/clang/blink_gc_plugin/tests/class_trace_wrappers_bases.cpp b/tools/clang/blink_gc_plugin/tests/class_trace_wrappers_bases.cpp new file mode 100644 index 0000000..2c67451 --- /dev/null +++ b/tools/clang/blink_gc_plugin/tests/class_trace_wrappers_bases.cpp
@@ -0,0 +1,18 @@ +// Copyright 2018 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 "class_trace_wrappers_bases.h" + +namespace blink { + +void CustomScriptWrappable::TraceWrappers(const ScriptWrappableVisitor*) const { + // Missing ScriptWrappable::TraceWrappers(visitor). +} + +void MixinApplication::TraceWrappers(const ScriptWrappableVisitor*) const { + // Missing MixinClassWithTraceWrappers1::TraceWrappers(visitor). + // Missing MixinClassWithTraceWrappers2::TraceWrappers(visitor). +} + +} // namespace blink
diff --git a/tools/clang/blink_gc_plugin/tests/class_trace_wrappers_bases.flags b/tools/clang/blink_gc_plugin/tests/class_trace_wrappers_bases.flags new file mode 100644 index 0000000..ff86e66 --- /dev/null +++ b/tools/clang/blink_gc_plugin/tests/class_trace_wrappers_bases.flags
@@ -0,0 +1 @@ +-Xclang -plugin-arg-blink-gc-plugin -Xclang warn-trace-wrappers-missing-base-dispatch \ No newline at end of file
diff --git a/tools/clang/blink_gc_plugin/tests/class_trace_wrappers_bases.h b/tools/clang/blink_gc_plugin/tests/class_trace_wrappers_bases.h new file mode 100644 index 0000000..1e494e6 --- /dev/null +++ b/tools/clang/blink_gc_plugin/tests/class_trace_wrappers_bases.h
@@ -0,0 +1,40 @@ +// Copyright 2018 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. + +#ifndef CLASS_TRACE_WRAPPERS_BASES_H_ +#define CLASS_TRACE_WRAPPERS_BASES_H_ + +#include "heap/stubs.h" + +namespace blink { + +class EmptyScriptWrappable : public ScriptWrappable { + // No TraceWrappers required. +}; + +class CustomScriptWrappable : public ScriptWrappable { + public: + void TraceWrappers(const ScriptWrappableVisitor*) const override; +}; + +class MixinClassWithTraceWrappers1 { + public: + virtual void TraceWrappers(const ScriptWrappableVisitor*) const {} +}; + +class MixinClassWithTraceWrappers2 { + public: + virtual void TraceWrappers(const ScriptWrappableVisitor*) const {} +}; + +class MixinApplication : public TraceWrapperBase, + public MixinClassWithTraceWrappers1, + public MixinClassWithTraceWrappers2 { + public: + void TraceWrappers(const ScriptWrappableVisitor*) const override; +}; + +} // namespace blink + +#endif // CLASS_TRACE_WRAPPERS_BASES_H_
diff --git a/tools/clang/blink_gc_plugin/tests/class_trace_wrappers_bases.txt b/tools/clang/blink_gc_plugin/tests/class_trace_wrappers_bases.txt new file mode 100644 index 0000000..00b7e3a --- /dev/null +++ b/tools/clang/blink_gc_plugin/tests/class_trace_wrappers_bases.txt
@@ -0,0 +1,8 @@ +class_trace_wrappers_bases.cpp:9:1: warning: [blink-gc] Base class 'ScriptWrappable' of derived class 'CustomScriptWrappable' requires wrapper tracing. +void CustomScriptWrappable::TraceWrappers(const ScriptWrappableVisitor*) const { +^ +class_trace_wrappers_bases.cpp:13:1: warning: [blink-gc] Base class 'MixinClassWithTraceWrappers1' of derived class 'MixinApplication' requires wrapper tracing. +void MixinApplication::TraceWrappers(const ScriptWrappableVisitor*) const { +^ +class_trace_wrappers_bases.cpp:13:1: warning: [blink-gc] Base class 'MixinClassWithTraceWrappers2' of derived class 'MixinApplication' requires wrapper tracing. +3 warnings generated.
diff --git a/tools/clang/blink_gc_plugin/tests/cycle_ptrs.h b/tools/clang/blink_gc_plugin/tests/cycle_ptrs.h index cb404ef..242e97f 100644 --- a/tools/clang/blink_gc_plugin/tests/cycle_ptrs.h +++ b/tools/clang/blink_gc_plugin/tests/cycle_ptrs.h
@@ -36,12 +36,12 @@ class C : public RefCounted<C> { private: - OwnPtr<D> m_d; + std::unique_ptr<D> m_d; }; class D { private: - Vector<OwnPtr<E> > m_es; + Vector<std::unique_ptr<E> > m_es; }; class E {
diff --git a/tools/clang/blink_gc_plugin/tests/destructor_access_finalized_field.h b/tools/clang/blink_gc_plugin/tests/destructor_access_finalized_field.h index 074582f..0c1a916 100644 --- a/tools/clang/blink_gc_plugin/tests/destructor_access_finalized_field.h +++ b/tools/clang/blink_gc_plugin/tests/destructor_access_finalized_field.h
@@ -17,7 +17,7 @@ class HeapObject; class PartOther { - ALLOW_ONLY_INLINE_ALLOCATION(); + DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); public: void Trace(Visitor*);
diff --git a/tools/clang/blink_gc_plugin/tests/fields_illegal_tracing.cpp b/tools/clang/blink_gc_plugin/tests/fields_illegal_tracing.cpp index 15df8814..6628858 100644 --- a/tools/clang/blink_gc_plugin/tests/fields_illegal_tracing.cpp +++ b/tools/clang/blink_gc_plugin/tests/fields_illegal_tracing.cpp
@@ -7,14 +7,12 @@ namespace blink { void PartObject::Trace(Visitor* visitor) { - visitor->Trace(m_obj1); visitor->Trace(m_obj2); visitor->Trace(m_obj3); visitor->Trace(m_obj4); } void HeapObject::Trace(Visitor* visitor) { - visitor->Trace(m_obj1); visitor->Trace(m_obj2); visitor->Trace(m_obj3); visitor->Trace(m_obj4);
diff --git a/tools/clang/blink_gc_plugin/tests/fields_illegal_tracing.h b/tools/clang/blink_gc_plugin/tests/fields_illegal_tracing.h index 294629e..526b3bd 100644 --- a/tools/clang/blink_gc_plugin/tests/fields_illegal_tracing.h +++ b/tools/clang/blink_gc_plugin/tests/fields_illegal_tracing.h
@@ -34,7 +34,6 @@ public: void Trace(Visitor*); private: - OwnPtr<HeapObject> m_obj1; RefPtr<HeapObject> m_obj2; bar::unique_ptr<HeapObject> m_obj3; std::unique_ptr<HeapObject> m_obj4; @@ -48,7 +47,6 @@ void Trace(Visitor*); private: PartObject m_part; - OwnPtr<HeapObject> m_obj1; RefPtr<HeapObject> m_obj2; bar::unique_ptr<HeapObject> m_obj3; std::unique_ptr<HeapObject> m_obj4;
diff --git a/tools/clang/blink_gc_plugin/tests/fields_illegal_tracing.txt b/tools/clang/blink_gc_plugin/tests/fields_illegal_tracing.txt index dc7030b..72ffada 100644 --- a/tools/clang/blink_gc_plugin/tests/fields_illegal_tracing.txt +++ b/tools/clang/blink_gc_plugin/tests/fields_illegal_tracing.txt
@@ -2,67 +2,55 @@ ./fields_illegal_tracing.h:32:1: warning: [blink-gc] Class 'PartObject' contains invalid fields. class PartObject { ^ -./fields_illegal_tracing.h:37:5: note: [blink-gc] OwnPtr field 'm_obj1' to a GC managed class declared here: - OwnPtr<HeapObject> m_obj1; - ^ -./fields_illegal_tracing.h:38:5: note: [blink-gc] RefPtr field 'm_obj2' to a GC managed class declared here: +./fields_illegal_tracing.h:37:5: note: [blink-gc] RefPtr field 'm_obj2' to a GC managed class declared here: RefPtr<HeapObject> m_obj2; ^ -./fields_illegal_tracing.h:40:5: note: [blink-gc] std::unique_ptr field 'm_obj4' to a GC managed class declared here: +./fields_illegal_tracing.h:39:5: note: [blink-gc] std::unique_ptr field 'm_obj4' to a GC managed class declared here: std::unique_ptr<HeapObject> m_obj4; ^ -./fields_illegal_tracing.h:42:5: warning: [blink-gc] Iterator field 'm_iterator2' to a GC managed collection declared here: +./fields_illegal_tracing.h:41:5: warning: [blink-gc] Iterator field 'm_iterator2' to a GC managed collection declared here: HeapVector<Member<HeapObject>>::iterator m_iterator2; ^ -./fields_illegal_tracing.h:43:5: warning: [blink-gc] Iterator field 'm_iterator3' to a GC managed collection declared here: +./fields_illegal_tracing.h:42:5: warning: [blink-gc] Iterator field 'm_iterator3' to a GC managed collection declared here: HeapHashSet<PartObject>::const_iterator m_iterator3; ^ -./fields_illegal_tracing.h:46:1: warning: [blink-gc] Class 'HeapObject' contains invalid fields. +./fields_illegal_tracing.h:45:1: warning: [blink-gc] Class 'HeapObject' contains invalid fields. class HeapObject : public GarbageCollectedFinalized<HeapObject> { ^ -./fields_illegal_tracing.h:51:5: note: [blink-gc] OwnPtr field 'm_obj1' to a GC managed class declared here: - OwnPtr<HeapObject> m_obj1; - ^ -./fields_illegal_tracing.h:52:5: note: [blink-gc] RefPtr field 'm_obj2' to a GC managed class declared here: +./fields_illegal_tracing.h:50:5: note: [blink-gc] RefPtr field 'm_obj2' to a GC managed class declared here: RefPtr<HeapObject> m_obj2; ^ -./fields_illegal_tracing.h:54:5: note: [blink-gc] std::unique_ptr field 'm_obj4' to a GC managed class declared here: +./fields_illegal_tracing.h:52:5: note: [blink-gc] std::unique_ptr field 'm_obj4' to a GC managed class declared here: std::unique_ptr<HeapObject> m_obj4; ^ -./fields_illegal_tracing.h:55:5: warning: [blink-gc] Iterator field 'm_iterator3' to a GC managed collection declared here: +./fields_illegal_tracing.h:53:5: warning: [blink-gc] Iterator field 'm_iterator3' to a GC managed collection declared here: HeapHashMap<int, Member<HeapObject>>::reverse_iterator m_iterator3; ^ -./fields_illegal_tracing.h:56:5: warning: [blink-gc] Iterator field 'm_iterator4' to a GC managed collection declared here: +./fields_illegal_tracing.h:54:5: warning: [blink-gc] Iterator field 'm_iterator4' to a GC managed collection declared here: HeapDeque<Member<HeapObject>>::const_reverse_iterator m_iterator4; ^ -./fields_illegal_tracing.h:58:5: warning: [blink-gc] Iterator field 'm_iterator6' to a GC managed collection declared here: +./fields_illegal_tracing.h:56:5: warning: [blink-gc] Iterator field 'm_iterator6' to a GC managed collection declared here: HeapLinkedHashSet<Member<HeapObject>>::const_iterator m_iterator6; ^ fields_illegal_tracing.cpp:9:1: warning: [blink-gc] Class 'PartObject' has untraced or not traceable fields. void PartObject::Trace(Visitor* visitor) { ^ -./fields_illegal_tracing.h:37:5: note: [blink-gc] Untraceable field 'm_obj1' declared here: - OwnPtr<HeapObject> m_obj1; - ^ -./fields_illegal_tracing.h:38:5: note: [blink-gc] Untraceable field 'm_obj2' declared here: +./fields_illegal_tracing.h:37:5: note: [blink-gc] Untraceable field 'm_obj2' declared here: RefPtr<HeapObject> m_obj2; ^ -./fields_illegal_tracing.h:40:5: note: [blink-gc] Untraceable field 'm_obj4' declared here: +./fields_illegal_tracing.h:39:5: note: [blink-gc] Untraceable field 'm_obj4' declared here: std::unique_ptr<HeapObject> m_obj4; ^ -fields_illegal_tracing.cpp:16:1: warning: [blink-gc] Class 'HeapObject' has untraced or not traceable fields. +fields_illegal_tracing.cpp:15:1: warning: [blink-gc] Class 'HeapObject' has untraced or not traceable fields. void HeapObject::Trace(Visitor* visitor) { ^ -./fields_illegal_tracing.h:51:5: note: [blink-gc] Untraceable field 'm_obj1' declared here: - OwnPtr<HeapObject> m_obj1; - ^ -./fields_illegal_tracing.h:52:5: note: [blink-gc] Untraceable field 'm_obj2' declared here: +./fields_illegal_tracing.h:50:5: note: [blink-gc] Untraceable field 'm_obj2' declared here: RefPtr<HeapObject> m_obj2; ^ -./fields_illegal_tracing.h:54:5: note: [blink-gc] Untraceable field 'm_obj4' declared here: +./fields_illegal_tracing.h:52:5: note: [blink-gc] Untraceable field 'm_obj4' declared here: std::unique_ptr<HeapObject> m_obj4; ^ -./fields_illegal_tracing.h:57:5: note: [blink-gc] Untraced field 'm_iterator5' declared here: +./fields_illegal_tracing.h:55:5: note: [blink-gc] Untraced field 'm_iterator5' declared here: HeapListHashSet<Member<HeapObject>>::const_iterator m_iterator5; ^ 9 warnings generated.
diff --git a/tools/clang/blink_gc_plugin/tests/heap/stubs.h b/tools/clang/blink_gc_plugin/tests/heap/stubs.h index 4f17273..735af486 100644 --- a/tools/clang/blink_gc_plugin/tests/heap/stubs.h +++ b/tools/clang/blink_gc_plugin/tests/heap/stubs.h
@@ -32,13 +32,6 @@ T* operator->() { return 0; } }; -template<typename T> class OwnPtr { -public: - ~OwnPtr() { } - operator T*() const { return 0; } - T* operator->() { return 0; } -}; - class DefaultAllocator { public: static const bool isGarbageCollected = false; @@ -162,8 +155,25 @@ T* operator->() { return 0; } }; +template <typename T, typename... Args> +unique_ptr<T> make_unique(Args&&... args) { + return unique_ptr<T>(); } +} // namespace std + +namespace base { + +template <typename T> +std::unique_ptr<T> WrapUnique(T* ptr) { + return std::unique_ptr<T>(); +} + +template <typename T> +class Optional {}; + +} // namespace base + namespace blink { using namespace WTF; @@ -179,10 +189,10 @@ void* operator new(size_t) = delete; \ void* operator new(size_t, void*) = delete; -#define ALLOW_ONLY_INLINE_ALLOCATION() \ - public: \ - void* operator new(size_t, void*); \ - private: \ +#define DISALLOW_NEW_EXCEPT_PLACEMENT_NEW() \ + public: \ + void* operator new(size_t, void*); \ + private: \ void* operator new(size_t) = delete; #define GC_PLUGIN_IGNORE(bug) \ @@ -297,6 +307,17 @@ static void Trace(Visitor*, T*); }; +class ScriptWrappableVisitor {}; + +class TraceWrapperBase { + public: + virtual void TraceWrappers(const ScriptWrappableVisitor*) const = 0; +}; + +class ScriptWrappable : public TraceWrapperBase { + public: + void TraceWrappers(const ScriptWrappableVisitor*) const override {} +}; } namespace WTF {
diff --git a/tools/clang/blink_gc_plugin/tests/left_most_gc_base.h b/tools/clang/blink_gc_plugin/tests/left_most_gc_base.h index 96d01d3..49fc853 100644 --- a/tools/clang/blink_gc_plugin/tests/left_most_gc_base.h +++ b/tools/clang/blink_gc_plugin/tests/left_most_gc_base.h
@@ -25,6 +25,15 @@ class IllFormed : public A, public C { }; // Error +class LeftMixin : public GarbageCollectedMixin { +public: + virtual void Trace(Visitor*); +}; + +class DerivedLeftMixin : public LeftMixin, public GarbageCollected<DerivedLeftMixin> { + USING_GARBAGE_COLLECTED_MIXIN(DerivedLeftMixin); +}; + } #endif
diff --git a/tools/clang/blink_gc_plugin/tests/left_most_gc_base.txt b/tools/clang/blink_gc_plugin/tests/left_most_gc_base.txt index e2d04186..4865dcc 100644 --- a/tools/clang/blink_gc_plugin/tests/left_most_gc_base.txt +++ b/tools/clang/blink_gc_plugin/tests/left_most_gc_base.txt
@@ -1,14 +1,17 @@ In file included from left_most_gc_base.cpp:5: -./left_most_gc_base.h:15:1: warning: [blink-gc] Class 'Right' must derive its GC base in the left-most position. +./left_most_gc_base.h:15:1: warning: [blink-gc] Class 'Right' must derive from GarbageCollected in the left-most position. class Right : public A, public B, public GarbageCollected<Right> { }; // Error ^ -./left_most_gc_base.h:18:1: warning: [blink-gc] Class 'DerivedRight' must derive its GC base in the left-most position. +./left_most_gc_base.h:18:1: warning: [blink-gc] Class 'DerivedRight' must derive from GarbageCollected in the left-most position. class DerivedRight : public Right, public Left { }; // Error ^ ./left_most_gc_base.h:12:1: warning: [blink-gc] Left-most base class 'A' of derived class 'IllFormed' must be polymorphic. class A { }; ^ -./left_most_gc_base.h:26:1: warning: [blink-gc] Class 'IllFormed' must derive its GC base in the left-most position. +./left_most_gc_base.h:26:1: warning: [blink-gc] Class 'IllFormed' must derive from GarbageCollected in the left-most position. class IllFormed : public A, public C { }; // Error ^ -4 warnings generated. +./left_most_gc_base.h:33:1: warning: [blink-gc] Class 'DerivedLeftMixin' must derive from GarbageCollected in the left-most position. +class DerivedLeftMixin : public LeftMixin, public GarbageCollected<DerivedLeftMixin> { +^ +5 warnings generated.
diff --git a/tools/clang/blink_gc_plugin/tests/make_unique_gc_object.cpp b/tools/clang/blink_gc_plugin/tests/make_unique_gc_object.cpp new file mode 100644 index 0000000..ea76684 --- /dev/null +++ b/tools/clang/blink_gc_plugin/tests/make_unique_gc_object.cpp
@@ -0,0 +1,16 @@ +// Copyright 2017 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 "make_unique_gc_object.h" + +namespace blink { + +void DisallowedUseOfUniquePtr() { + auto owned_base = std::make_unique<Base>(); + auto owned_base_array = std::make_unique<Base[]>(1); + auto owned_derived = std::make_unique<Derived>(); + auto owned_mixin = base::WrapUnique(static_cast<Mixin*>(nullptr)); +} + +} // namespace blink
diff --git a/tools/clang/blink_gc_plugin/tests/make_unique_gc_object.h b/tools/clang/blink_gc_plugin/tests/make_unique_gc_object.h new file mode 100644 index 0000000..952e4d3 --- /dev/null +++ b/tools/clang/blink_gc_plugin/tests/make_unique_gc_object.h
@@ -0,0 +1,29 @@ +// Copyright 2017 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. + +#ifndef MAKE_UNIQUE_GC_OBJECT_H_ +#define MAKE_UNIQUE_GC_OBJECT_H_ + +#include "heap/stubs.h" + +namespace blink { + +class Base : public GarbageCollected<Base> { + public: + virtual void Trace(Visitor*) {} +}; + +class Derived : public Base { + public: + void Trace(Visitor* visitor) override { Base::Trace(visitor); } +}; + +class Mixin : public GarbageCollectedMixin { + public: + void Trace(Visitor*) {} +}; + +} // namespace blink + +#endif // MAKE_UNIQUE_GC_OBJECT_H_
diff --git a/tools/clang/blink_gc_plugin/tests/make_unique_gc_object.txt b/tools/clang/blink_gc_plugin/tests/make_unique_gc_object.txt new file mode 100644 index 0000000..9db21c5e --- /dev/null +++ b/tools/clang/blink_gc_plugin/tests/make_unique_gc_object.txt
@@ -0,0 +1,13 @@ +make_unique_gc_object.cpp:10:21: warning: [blink-gc] Disallowed use of 'make_unique<blink::Base>' found; 'Base' is a garbage-collected type. std::unique_ptr cannot hold garbage-collected objects. + auto owned_base = std::make_unique<Base>(); + ^~~~~~~~~~~~~~~~~~~~~~~~ +make_unique_gc_object.cpp:11:27: warning: [blink-gc] Disallowed use of 'make_unique<blink::Base [], int>' found; 'Base' is a garbage-collected type. std::unique_ptr cannot hold garbage-collected objects. + auto owned_base_array = std::make_unique<Base[]>(1); + ^~~~~~~~~~~~~~~~~~~~~~~~~~~ +make_unique_gc_object.cpp:12:24: warning: [blink-gc] Disallowed use of 'make_unique<blink::Derived>' found; 'Derived' is a garbage-collected type. std::unique_ptr cannot hold garbage-collected objects. + auto owned_derived = std::make_unique<Derived>(); + ^~~~~~~~~~~~~~~~~~~~~~~~~~~ +make_unique_gc_object.cpp:13:22: warning: [blink-gc] Disallowed use of 'WrapUnique<blink::Mixin>' found; 'Mixin' is a garbage-collected type. std::unique_ptr cannot hold garbage-collected objects. + auto owned_mixin = base::WrapUnique(static_cast<Mixin*>(nullptr)); + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +4 warnings generated.
diff --git a/tools/clang/blink_gc_plugin/tests/member_in_offheap_class.h b/tools/clang/blink_gc_plugin/tests/member_in_offheap_class.h index 170a8890..f311d0f 100644 --- a/tools/clang/blink_gc_plugin/tests/member_in_offheap_class.h +++ b/tools/clang/blink_gc_plugin/tests/member_in_offheap_class.h
@@ -37,7 +37,7 @@ }; class InlineObject { - ALLOW_ONLY_INLINE_ALLOCATION(); + DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); public: void Trace(Visitor*); private:
diff --git a/tools/clang/blink_gc_plugin/tests/optional_gc_object.cpp b/tools/clang/blink_gc_plugin/tests/optional_gc_object.cpp new file mode 100644 index 0000000..c044b9d --- /dev/null +++ b/tools/clang/blink_gc_plugin/tests/optional_gc_object.cpp
@@ -0,0 +1,19 @@ +// Copyright 2017 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 "optional_gc_object.h" + +namespace blink { + +void DisallowedUseOfUniquePtr() { + base::Optional<Base> optional_base; + (void)optional_base; + + base::Optional<Derived> optional_derived; + (void)optional_derived; + + new base::Optional<Base>; +} + +} // namespace blink
diff --git a/tools/clang/blink_gc_plugin/tests/optional_gc_object.h b/tools/clang/blink_gc_plugin/tests/optional_gc_object.h new file mode 100644 index 0000000..e46888e6 --- /dev/null +++ b/tools/clang/blink_gc_plugin/tests/optional_gc_object.h
@@ -0,0 +1,29 @@ +// Copyright 2017 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. + +#ifndef OPTIONAL_GC_OBJECT_H_ +#define OPTIONAL_GC_OBJECT_H_ + +#include "heap/stubs.h" + +namespace blink { + +class Base : public GarbageCollected<Base> { + public: + virtual void Trace(Visitor*) {} +}; + +class Derived : public Base { + public: + void Trace(Visitor* visitor) override { Base::Trace(visitor); } +}; + +class Mixin : public GarbageCollectedMixin { + public: + void Trace(Visitor*) {} +}; + +} // namespace blink + +#endif // OPTIONAL_GC_OBJECT_H_
diff --git a/tools/clang/blink_gc_plugin/tests/optional_gc_object.txt b/tools/clang/blink_gc_plugin/tests/optional_gc_object.txt new file mode 100644 index 0000000..9b78937 --- /dev/null +++ b/tools/clang/blink_gc_plugin/tests/optional_gc_object.txt
@@ -0,0 +1,10 @@ +optional_gc_object.cpp:10:24: warning: [blink-gc] Disallowed construction of 'Optional<blink::Base>' found; 'Base' is a garbage-collected type. optional cannot hold garbage-collected objects. + base::Optional<Base> optional_base; + ^~~~~~~~~~~~~ +optional_gc_object.cpp:13:27: warning: [blink-gc] Disallowed construction of 'Optional<blink::Derived>' found; 'Derived' is a garbage-collected type. optional cannot hold garbage-collected objects. + base::Optional<Derived> optional_derived; + ^~~~~~~~~~~~~~~~ +optional_gc_object.cpp:16:7: warning: [blink-gc] Disallowed construction of 'Optional<blink::Base>' found; 'Base' is a garbage-collected type. optional cannot hold garbage-collected objects. + new base::Optional<Base>; + ^~~~ +3 warnings generated.
diff --git a/tools/clang/blink_gc_plugin/tests/own_ptr_to_gc_managed_class.txt b/tools/clang/blink_gc_plugin/tests/own_ptr_to_gc_managed_class.txt deleted file mode 100644 index 4102e86..0000000 --- a/tools/clang/blink_gc_plugin/tests/own_ptr_to_gc_managed_class.txt +++ /dev/null
@@ -1,17 +0,0 @@ -In file included from own_ptr_to_gc_managed_class.cpp:5: -./own_ptr_to_gc_managed_class.h:14:1: warning: [blink-gc] Class 'PartObject' contains invalid fields. -class PartObject { -^ -./own_ptr_to_gc_managed_class.h:17:5: note: [blink-gc] OwnPtr field 'm_obj' to a GC managed class declared here: - OwnPtr<HeapObject> m_obj; - ^ -./own_ptr_to_gc_managed_class.h:20:1: warning: [blink-gc] Class 'HeapObject' contains invalid fields. -class HeapObject : public GarbageCollectedFinalized<HeapObject> { -^ -./own_ptr_to_gc_managed_class.h:24:5: note: [blink-gc] OwnPtr field 'm_objs' to a GC managed class declared here: - Vector<OwnPtr<HeapObject> > m_objs; - ^ -./own_ptr_to_gc_managed_class.h:25:5: note: [blink-gc] OwnPtr field 'm_objs2' to a GC managed class declared here: - OwnPtr<HeapVector<Member<HeapObject> > > m_objs2; - ^ -2 warnings generated.
diff --git a/tools/clang/blink_gc_plugin/tests/stack_allocated.txt b/tools/clang/blink_gc_plugin/tests/stack_allocated.txt index f9c7a15..0fbb42f 100644 --- a/tools/clang/blink_gc_plugin/tests/stack_allocated.txt +++ b/tools/clang/blink_gc_plugin/tests/stack_allocated.txt
@@ -23,7 +23,7 @@ ./stack_allocated.h:43:3: warning: [blink-gc] Garbage collected class 'DerivedHeapObject2' is not permitted to override its new operator. STACK_ALLOCATED(); ^ -./heap/stubs.h:178:5: note: expanded from macro 'STACK_ALLOCATED' +./heap/stubs.h:188:5: note: expanded from macro 'STACK_ALLOCATED' __attribute__((annotate("blink_stack_allocated"))) \ ^ stack_allocated.cpp:12:1: warning: [blink-gc] Class 'AnonStackObject' contains invalid fields.
diff --git a/tools/clang/blink_gc_plugin/tests/templated_class_with_local_class_requires_trace.h b/tools/clang/blink_gc_plugin/tests/templated_class_with_local_class_requires_trace.h index 6656120..4959cdc 100644 --- a/tools/clang/blink_gc_plugin/tests/templated_class_with_local_class_requires_trace.h +++ b/tools/clang/blink_gc_plugin/tests/templated_class_with_local_class_requires_trace.h
@@ -38,12 +38,12 @@ } private: Member<HeapObject> m_heapObject; - OwnPtr<HeapObject> m_object; + std::unique_ptr<HeapObject> m_object; }; Member<Local> m_local; Member<T> m_memberRef; - OwnPtr<T> m_ownRef; + std::unique_ptr<T> m_uniqueRef; }; } // namespace blink
diff --git a/tools/clang/blink_gc_plugin/tests/templated_class_with_local_class_requires_trace.txt b/tools/clang/blink_gc_plugin/tests/templated_class_with_local_class_requires_trace.txt index fa3e0edc4..37e7b8f 100644 --- a/tools/clang/blink_gc_plugin/tests/templated_class_with_local_class_requires_trace.txt +++ b/tools/clang/blink_gc_plugin/tests/templated_class_with_local_class_requires_trace.txt
@@ -2,25 +2,25 @@ ./templated_class_with_local_class_requires_trace.h:22:1: warning: [blink-gc] Class 'TemplatedObject<blink::HeapObject>' contains invalid fields. class TemplatedObject final ^ -./templated_class_with_local_class_requires_trace.h:46:5: note: [blink-gc] OwnPtr field 'm_ownRef' to a GC managed class declared here: - OwnPtr<T> m_ownRef; +./templated_class_with_local_class_requires_trace.h:46:5: note: [blink-gc] std::unique_ptr field 'm_uniqueRef' to a GC managed class declared here: + std::unique_ptr<T> m_uniqueRef; ^ ./templated_class_with_local_class_requires_trace.h:32:5: warning: [blink-gc] Class 'Local' contains invalid fields. class Local final : public GarbageCollected<Local> { ^ -./templated_class_with_local_class_requires_trace.h:41:9: note: [blink-gc] OwnPtr field 'm_object' to a GC managed class declared here: - OwnPtr<HeapObject> m_object; +./templated_class_with_local_class_requires_trace.h:41:9: note: [blink-gc] std::unique_ptr field 'm_object' to a GC managed class declared here: + std::unique_ptr<HeapObject> m_object; ^ ./templated_class_with_local_class_requires_trace.h:32:5: warning: [blink-gc] Class 'Local' requires finalization. class Local final : public GarbageCollected<Local> { ^ ./templated_class_with_local_class_requires_trace.h:41:9: note: [blink-gc] Field 'm_object' requiring finalization declared here: - OwnPtr<HeapObject> m_object; + std::unique_ptr<HeapObject> m_object; ^ ./templated_class_with_local_class_requires_trace.h:34:9: warning: [blink-gc] Class 'Local' has untraced or not traceable fields. void Trace(Visitor* visitor) ^ ./templated_class_with_local_class_requires_trace.h:41:9: note: [blink-gc] Untraceable field 'm_object' declared here: - OwnPtr<HeapObject> m_object; + std::unique_ptr<HeapObject> m_object; ^ 4 warnings generated.
diff --git a/tools/clang/blink_gc_plugin/tests/own_ptr_to_gc_managed_class.cpp b/tools/clang/blink_gc_plugin/tests/unique_ptr_to_gc_managed_class.cpp similarity index 84% rename from tools/clang/blink_gc_plugin/tests/own_ptr_to_gc_managed_class.cpp rename to tools/clang/blink_gc_plugin/tests/unique_ptr_to_gc_managed_class.cpp index 7621c148..af37672 100644 --- a/tools/clang/blink_gc_plugin/tests/own_ptr_to_gc_managed_class.cpp +++ b/tools/clang/blink_gc_plugin/tests/unique_ptr_to_gc_managed_class.cpp
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "own_ptr_to_gc_managed_class.h" +#include "unique_ptr_to_gc_managed_class.h" namespace blink {
diff --git a/tools/clang/blink_gc_plugin/tests/own_ptr_to_gc_managed_class.h b/tools/clang/blink_gc_plugin/tests/unique_ptr_to_gc_managed_class.h similarity index 76% rename from tools/clang/blink_gc_plugin/tests/own_ptr_to_gc_managed_class.h rename to tools/clang/blink_gc_plugin/tests/unique_ptr_to_gc_managed_class.h index 586716a3..6594289 100644 --- a/tools/clang/blink_gc_plugin/tests/own_ptr_to_gc_managed_class.h +++ b/tools/clang/blink_gc_plugin/tests/unique_ptr_to_gc_managed_class.h
@@ -14,15 +14,15 @@ class PartObject { DISALLOW_NEW(); private: - OwnPtr<HeapObject> m_obj; + std::unique_ptr<HeapObject> m_obj; }; class HeapObject : public GarbageCollectedFinalized<HeapObject> { public: void Trace(Visitor*); private: - Vector<OwnPtr<HeapObject> > m_objs; - OwnPtr<HeapVector<Member<HeapObject> > > m_objs2; + Vector<std::unique_ptr<HeapObject> > m_objs; + std::unique_ptr<HeapVector<Member<HeapObject> > > m_objs2; }; }
diff --git a/tools/clang/blink_gc_plugin/tests/unique_ptr_to_gc_managed_class.txt b/tools/clang/blink_gc_plugin/tests/unique_ptr_to_gc_managed_class.txt new file mode 100644 index 0000000..1b67883 --- /dev/null +++ b/tools/clang/blink_gc_plugin/tests/unique_ptr_to_gc_managed_class.txt
@@ -0,0 +1,17 @@ +In file included from unique_ptr_to_gc_managed_class.cpp:5: +./unique_ptr_to_gc_managed_class.h:14:1: warning: [blink-gc] Class 'PartObject' contains invalid fields. +class PartObject { +^ +./unique_ptr_to_gc_managed_class.h:17:5: note: [blink-gc] std::unique_ptr field 'm_obj' to a GC managed class declared here: + std::unique_ptr<HeapObject> m_obj; + ^ +./unique_ptr_to_gc_managed_class.h:20:1: warning: [blink-gc] Class 'HeapObject' contains invalid fields. +class HeapObject : public GarbageCollectedFinalized<HeapObject> { +^ +./unique_ptr_to_gc_managed_class.h:24:5: note: [blink-gc] std::unique_ptr field 'm_objs' to a GC managed class declared here: + Vector<std::unique_ptr<HeapObject> > m_objs; + ^ +./unique_ptr_to_gc_managed_class.h:25:5: note: [blink-gc] std::unique_ptr field 'm_objs2' to a GC managed class declared here: + std::unique_ptr<HeapVector<Member<HeapObject> > > m_objs2; + ^ +2 warnings generated.
diff --git a/tools/clang/move_raw/CMakeLists.txt b/tools/clang/move_raw/CMakeLists.txt deleted file mode 100644 index 3375a58..0000000 --- a/tools/clang/move_raw/CMakeLists.txt +++ /dev/null
@@ -1,28 +0,0 @@ -set(LLVM_LINK_COMPONENTS - BitReader - MCParser - Option - X86AsmParser - X86CodeGen - ) - -add_llvm_executable(move_raw - MoveRaw.cpp - ) - -target_link_libraries(move_raw - clangAST - clangASTMatchers - clangAnalysis - clangBasic - clangDriver - clangEdit - clangFrontend - clangLex - clangParse - clangSema - clangSerialization - clangTooling - ) - -cr_install(TARGETS move_raw RUNTIME DESTINATION bin)
diff --git a/tools/clang/move_raw/MoveRaw.cpp b/tools/clang/move_raw/MoveRaw.cpp deleted file mode 100644 index 516b5075..0000000 --- a/tools/clang/move_raw/MoveRaw.cpp +++ /dev/null
@@ -1,97 +0,0 @@ -// Copyright 2017 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. -// -// Clang tool to find where std::move is called on a raw pointer. -// Calling std::move on a raw pointer has no useful effect and is likely a -// sign of an error (e.g., mistaking a raw pointer for a smart pointer). -// TODO(crbug.com/731577): Make this a clang-tidy check instead. - -#include <memory> -#include <set> -#include <string> - -#include "clang/AST/ASTContext.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/ASTMatchers/ASTMatchers.h" -#include "clang/ASTMatchers/ASTMatchersMacros.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Frontend/FrontendActions.h" -#include "clang/Lex/Lexer.h" -#include "clang/Tooling/CommonOptionsParser.h" -#include "clang/Tooling/Refactoring.h" -#include "clang/Tooling/Tooling.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/TargetSelect.h" - -using namespace clang::ast_matchers; -using clang::tooling::CommonOptionsParser; - -namespace { - -class MoveCallCollector : public MatchFinder::MatchCallback { - public: - explicit MoveCallCollector( - std::set<clang::tooling::Replacement>* replacements) - : replacements_(replacements) {} - virtual void run(const MatchFinder::MatchResult& result) override; - - private: - std::set<clang::tooling::Replacement>* const replacements_; -}; - -void MoveCallCollector::run(const MatchFinder::MatchResult& result) { - const clang::Expr* callsite = - result.Nodes.getNodeAs<clang::Expr>("move_call"); - replacements_->insert(clang::tooling::Replacement( - *result.SourceManager, - result.SourceManager->getSpellingLoc(callsite->getLocStart()), 0, - "/*This tries to move a raw pointer!*/")); -} - -} // namespace - -static llvm::cl::extrahelp common_help(CommonOptionsParser::HelpMessage); - -int main(int argc, const char* argv[]) { - // TODO(dcheng): Clang tooling should do this itself. - // https://llvm.org/bugs/show_bug.cgi?id=21627 - llvm::InitializeNativeTarget(); - llvm::InitializeNativeTargetAsmParser(); - llvm::cl::OptionCategory category( - "Catching red flags: calling std::move on raw pointers"); - CommonOptionsParser options(argc, argv, category); - clang::tooling::ClangTool tool(options.getCompilations(), - options.getSourcePathList()); - - MatchFinder match_finder; - std::set<clang::tooling::Replacement> replacements; - - StatementMatcher move_on_raw_matcher = - callExpr(argumentCountIs(1), callee(functionDecl(hasName("::std::move"))), - hasArgument(0, hasType(pointerType()))) - .bind("move_call"); - MoveCallCollector callback(&replacements); - match_finder.addMatcher(move_on_raw_matcher, &callback); - - std::unique_ptr<clang::tooling::FrontendActionFactory> factory = - clang::tooling::newFrontendActionFactory(&match_finder); - int result = tool.run(factory.get()); - if (result != 0) - return result; - - if (replacements.empty()) - return 0; - - // Serialization format is documented in tools/clang/scripts/run_tool.py - llvm::outs() << "==== BEGIN EDITS ====\n"; - for (const auto& r : replacements) { - std::string replacement_text = r.getReplacementText().str(); - std::replace(replacement_text.begin(), replacement_text.end(), '\n', '\0'); - llvm::outs() << "r:::" << r.getFilePath() << ":::" << r.getOffset() - << ":::" << r.getLength() << ":::" << replacement_text << "\n"; - } - llvm::outs() << "==== END EDITS ====\n"; - - return 0; -}
diff --git a/tools/clang/move_raw/tests/test-expected.cc b/tools/clang/move_raw/tests/test-expected.cc deleted file mode 100644 index 1432d33a..0000000 --- a/tools/clang/move_raw/tests/test-expected.cc +++ /dev/null
@@ -1,40 +0,0 @@ -// Copyright 2017 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. - -namespace std { - -// This is the move that should be flagged. Representes the unary std::move. -template <typename T> -T move(T t) { - return t; -} - -// This represents the algorithm std::move, it should not be flagged. -template <class InputIt, class OutputIt> -OutputIt move(InputIt first, InputIt last, OutputIt d_first) { - return d_first; -} - -} // namespace std - -// This represents some non-std move. It should not be flagged. -template <typename T> -T move(T t) { - return t; -} - -void Test() { - int x = 3; - - // Should not be flagged: x is not a pointer. - int y = std::move(x); - - int* p = &x; - - // Calling std::move on a raw pointer should be flagged. - int* q = /*This tries to move a raw pointer!*/ std::move(p); - - // Calling non-std move should not be flagged. - q = move(p); -}
diff --git a/tools/clang/move_raw/tests/test-original.cc b/tools/clang/move_raw/tests/test-original.cc deleted file mode 100644 index 0b3b5a7..0000000 --- a/tools/clang/move_raw/tests/test-original.cc +++ /dev/null
@@ -1,40 +0,0 @@ -// Copyright 2017 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. - -namespace std { - -// This is the move that should be flagged. Representes the unary std::move. -template <typename T> -T move(T t) { - return t; -} - -// This represents the algorithm std::move, it should not be flagged. -template <class InputIt, class OutputIt> -OutputIt move(InputIt first, InputIt last, OutputIt d_first) { - return d_first; -} - -} // namespace std - -// This represents some non-std move. It should not be flagged. -template <typename T> -T move(T t) { - return t; -} - -void Test() { - int x = 3; - - // Should not be flagged: x is not a pointer. - int y = std::move(x); - - int* p = &x; - - // Calling std::move on a raw pointer should be flagged. - int* q = std::move(p); - - // Calling non-std move should not be flagged. - q = move(p); -}
diff --git a/tools/clang/plugins/ChromeClassTester.cpp b/tools/clang/plugins/ChromeClassTester.cpp index b0c9c32..594edde 100644 --- a/tools/clang/plugins/ChromeClassTester.cpp +++ b/tools/clang/plugins/ChromeClassTester.cpp
@@ -99,8 +99,7 @@ // Resolve the symlinktastic relative path and make it absolute. char resolvedPath[MAXPATHLEN]; if (options_.no_realpath) { - // Same reason as windows below, but we don't need to do - // the '\\' manipulation on linux. + // Same reason as windows below. filename.insert(filename.begin(), '/'); } else if (realpath(filename.c_str(), resolvedPath)) { filename = resolvedPath; @@ -131,10 +130,16 @@ WideCharToMultiByte(CP_UTF8, 0, full_utf16.data(), -1, &filename[0], size_needed, nullptr, nullptr); } - - std::replace(filename.begin(), filename.end(), '\\', '/'); #endif + // When using distributed cross compilation build tools, file paths can have + // separators which differ from ones at this platform. Make them consistent. + std::replace(filename.begin(), filename.end(), '\\', '/'); + + // Don't check autogenerated files. ninja puts them in $OUT_DIR/gen. + if (filename.find("/gen/") != std::string::npos) + return LocationType::kThirdParty; + // TODO(dcheng, tkent): The WebKit directory is being renamed to Blink. Clean // this up once the rename is done. if (filename.find("/third_party/WebKit/") != std::string::npos || @@ -208,14 +213,6 @@ banned_directories_.emplace("/v8/"); banned_directories_.emplace("/frameworks/"); - // Don't check autogenerated headers. - // Make puts them below $(builddir_name)/.../gen and geni. - // Ninja puts them below OUTPUT_DIR/.../gen - // Xcode has a fixed output directory for everything. - banned_directories_.emplace("/gen/"); - banned_directories_.emplace("/geni/"); - banned_directories_.emplace("/xcodebuild/"); - // Used in really low level threading code that probably shouldn't be out of // lined. ignored_record_names_.emplace("ThreadLocalBoolean");
diff --git a/tools/clang/plugins/FindBadConstructsAction.cpp b/tools/clang/plugins/FindBadConstructsAction.cpp index 56050b4..e1443f9 100644 --- a/tools/clang/plugins/FindBadConstructsAction.cpp +++ b/tools/clang/plugins/FindBadConstructsAction.cpp
@@ -57,9 +57,6 @@ options_.no_realpath = true; } else if (args[i] == "check-ipc") { options_.check_ipc = true; - } else if (args[i] == "check-auto-raw-pointer") { - // This flag is deprecated and will be removed once Chromium builds aren't - // using it. http://crbug.com/554600. } else { parsed = false; llvm::errs() << "Unknown clang plugin argument: " << args[i] << "\n";
diff --git a/tools/clang/plugins/FindBadConstructsConsumer.cpp b/tools/clang/plugins/FindBadConstructsConsumer.cpp index 215e69b..ab10066 100644 --- a/tools/clang/plugins/FindBadConstructsConsumer.cpp +++ b/tools/clang/plugins/FindBadConstructsConsumer.cpp
@@ -31,27 +31,6 @@ return decl->getQualifiedNameAsString() == "testing::Test"; } -// Generates a fixit hint to remove the 'virtual' keyword. -// Unfortunately, there doesn't seem to be a good way to determine the source -// location of the 'virtual' keyword. It's available in Declarator, but that -// isn't accessible from the AST. So instead, make an educated guess that the -// first token is probably the virtual keyword. Strictly speaking, this doesn't -// have to be true, but it probably will be. -// TODO(dcheng): Add a warning to force virtual to always appear first ;-) -FixItHint FixItRemovalForVirtual(const SourceManager& manager, - const LangOptions& lang_opts, - const CXXMethodDecl* method) { - SourceRange range(method->getLocStart()); - // Get the spelling loc just in case it was expanded from a macro. - SourceRange spelling_range(manager.getSpellingLoc(range.getBegin())); - // Sanity check that the text looks like virtual. - StringRef text = clang::Lexer::getSourceText( - CharSourceRange::getTokenRange(spelling_range), manager, lang_opts); - if (text.trim() != "virtual") - return FixItHint(); - return FixItHint::CreateRemoval(range); -} - bool IsPodOrTemplateType(const CXXRecordDecl& record) { return record.isPOD() || record.getDescribedClassTemplate() || @@ -85,11 +64,11 @@ std::string result = GetAutoReplacementTypeAsString( non_reference_type->getPointeeType(), storage_class); result += "*"; - if (non_reference_type.isLocalConstQualified()) + if (non_reference_type.isConstQualified()) result += " const"; - if (non_reference_type.isLocalVolatileQualified()) + if (non_reference_type.isVolatileQualified()) result += " volatile"; - if (type->isReferenceType() && !non_reference_type.isLocalConstQualified()) { + if (type->isReferenceType() && !non_reference_type.isConstQualified()) { if (type->isLValueReferenceType()) result += "&"; else if (type->isRValueReferenceType()) @@ -114,6 +93,8 @@ "'final'."); diag_redundant_virtual_specifier_ = diagnostic().getCustomDiagID( getErrorLevel(), "[chromium-style] %0 is redundant; %1 implies %0."); + diag_will_be_redundant_virtual_specifier_ = diagnostic().getCustomDiagID( + getErrorLevel(), "[chromium-style] %0 will be redundant; %1 implies %0."); // http://llvm.org/bugs/show_bug.cgi?id=21051 has been filed to make this a // Clang warning. diag_base_method_virtual_and_final_ = diagnostic().getCustomDiagID( @@ -233,13 +214,6 @@ void FindBadConstructsConsumer::CheckChromeClass(LocationType location_type, SourceLocation record_location, CXXRecordDecl* record) { - // TODO(dcheng): This is needed because some of the diagnostics for refcounted - // classes use DiagnosticsEngine::Report() directly, and there are existing - // violations in Blink. This should be removed once the checks are - // modularized. - if (location_type == LocationType::kBlink) - return; - bool implementation_file = InImplementationFile(record_location); if (!implementation_file) { @@ -262,7 +236,12 @@ if (!IsPodOrTemplateType(*record)) CheckVirtualMethods(record_location, record, warn_on_inline_bodies); - CheckRefCountedDtors(record_location, record); + // TODO(dcheng): This is needed because some of the diagnostics for refcounted + // classes use DiagnosticsEngine::Report() directly, and there are existing + // violations in Blink. This should be removed once the checks are + // modularized. + if (location_type != LocationType::kBlink) + CheckRefCountedDtors(record_location, record); CheckWeakPtrFactoryMembers(record_location, record); } @@ -473,8 +452,23 @@ unsigned diagnostic_id) { LocationType type = ClassifyLocation(instance().getSourceManager().getSpellingLoc(loc)); - bool ignored = - type == LocationType::kThirdParty || type == LocationType::kBlink; + bool ignored = type == LocationType::kThirdParty; + if (type == LocationType::kBlink) { + if (!options_.enforce_in_thirdparty_webkit) { + ignored = true; + } else if (diagnostic_id == diag_no_explicit_ctor_ || + diagnostic_id == diag_no_explicit_copy_ctor_ || + diagnostic_id == diag_inline_complex_ctor_ || + diagnostic_id == diag_no_explicit_dtor_ || + diagnostic_id == diag_inline_complex_dtor_ || + diagnostic_id == + diag_refcounted_with_protected_non_virtual_dtor_ || + diagnostic_id == diag_virtual_with_inline_body_) { + // Certain checks are ignored in Blink for historical reasons. + // TODO(dcheng): Make this list smaller. + ignored = true; + } + } return SuppressibleDiagnosticBuilder(&diagnostic(), loc, diagnostic_id, ignored); } @@ -538,69 +532,21 @@ SourceManager& manager = instance().getSourceManager(); const LangOptions& lang_opts = instance().getLangOpts(); + // Grab the stream of tokens from the beginning of the method + bool remove_virtual = false; + bool add_override = false; + // Complain if a method is annotated virtual && (override || final). - if (has_virtual && (override_attr || final_attr)) { - // ... but only if virtual does not originate in a macro from a banned file. - // Note this is just an educated guess: the assumption here is that any - // macro for declaring methods will probably be at the start of the method's - // source range. - ReportIfSpellingLocNotIgnored(method->getLocStart(), - diag_redundant_virtual_specifier_) - << "'virtual'" - << (override_attr ? static_cast<Attr*>(override_attr) : final_attr) - << FixItRemovalForVirtual(manager, lang_opts, method); - } + if (has_virtual && (override_attr || final_attr)) + remove_virtual = true; // Complain if a method is an override and is not annotated with override or // final. if (is_override && !override_attr && !final_attr) { - SourceRange range = method->getSourceRange(); - SourceLocation loc; - if (method->hasInlineBody()) { - loc = method->getBody()->getSourceRange().getBegin(); - } else { - loc = Lexer::getLocForEndOfToken(manager.getSpellingLoc(range.getEnd()), - 0, manager, lang_opts); - // The original code used the ending source loc of TypeSourceInfo's - // TypeLoc. Unfortunately, this breaks down in the presence of attributes. - // Attributes often appear at the end of a TypeLoc, e.g. - // virtual ULONG __stdcall AddRef() - // has a TypeSourceInfo that looks something like: - // ULONG AddRef() __attribute(stdcall) - // so a fix-it insertion would be generated to insert 'override' after - // __stdcall in the code as written. - // While using the spelling loc of the CXXMethodDecl fixes attribute - // handling, it breaks handling of "= 0" and similar constructs.. To work - // around this, scan backwards in the source text for a '=' or ')' token - // and adjust the location as needed... - for (SourceLocation l = loc.getLocWithOffset(-1); - l != manager.getLocForStartOfFile(manager.getFileID(loc)); - l = l.getLocWithOffset(-1)) { - l = Lexer::GetBeginningOfToken(l, manager, lang_opts); - Token token; - // getRawToken() returns *true* on failure. In that case, just give up - // and don't bother generating a possibly incorrect fix-it. - if (Lexer::getRawToken(l, token, manager, lang_opts, true)) { - loc = SourceLocation(); - break; - } - if (token.is(tok::r_paren)) { - break; - } else if (token.is(tok::equal)) { - loc = l; - break; - } - } - } - // Again, only emit the warning if it doesn't originate from a macro in - // a system header. - if (loc.isValid()) { - ReportIfSpellingLocNotIgnored(loc, diag_method_requires_override_) - << FixItHint::CreateInsertion(loc, " override"); - } else { - ReportIfSpellingLocNotIgnored(range.getBegin(), - diag_method_requires_override_); - } + add_override = true; + // Also remove the virtual in the same fixit if currently present. + if (has_virtual) + remove_virtual = true; } if (final_attr && override_attr) { @@ -610,11 +556,69 @@ << FixItHint::CreateRemoval(override_attr->getRange()); } - if (final_attr && !is_override) { - ReportIfSpellingLocNotIgnored(method->getLocStart(), - diag_base_method_virtual_and_final_) - << FixItRemovalForVirtual(manager, lang_opts, method) - << FixItHint::CreateRemoval(final_attr->getRange()); + if (!remove_virtual && !add_override) + return; + + // Deletion of virtual and insertion of override are tricky. The AST does not + // expose the location of `virtual` or `=`: the former is useful when trying + // to remove `virtual, while the latter is useful when trying to insert + // `override`. Iterate over the tokens from |method->getLocStart()| until: + // 1. A `{` not nested inside parentheses is found or + // 2. A `=` not nested inside parentheses is found or + // 3. A `;` not nested inside parentheses is found or + // 4. The end of the file is found. + SourceLocation virtual_loc; + SourceLocation override_insertion_loc; + // Attempt to set up the lexer in raw mode. + std::pair<FileID, unsigned> decomposed_start = + manager.getDecomposedLoc(method->getLocStart()); + bool invalid = false; + StringRef buffer = manager.getBufferData(decomposed_start.first, &invalid); + if (!invalid) { + int nested_parentheses = 0; + Lexer lexer(manager.getLocForStartOfFile(decomposed_start.first), lang_opts, + buffer.begin(), buffer.begin() + decomposed_start.second, + buffer.end()); + Token token; + while (!lexer.LexFromRawLexer(token)) { + // Found '=', ';', or '{'. No need to scan any further, since an override + // fixit hint won't be inserted after any of these tokens. + if ((token.is(tok::equal) || token.is(tok::semi) || + token.is(tok::l_brace)) && + nested_parentheses == 0) { + override_insertion_loc = token.getLocation(); + break; + } + if (token.is(tok::l_paren)) { + ++nested_parentheses; + } else if (token.is(tok::r_paren)) { + --nested_parentheses; + } else if (token.is(tok::raw_identifier)) { + // TODO(dcheng): Unclear if this needs to check for nested parentheses + // as well? + if (token.getRawIdentifier() == "virtual") + virtual_loc = token.getLocation(); + } + } + } + + if (add_override && override_insertion_loc.isValid()) { + ReportIfSpellingLocNotIgnored(override_insertion_loc, + diag_method_requires_override_) + << FixItHint::CreateInsertion(override_insertion_loc, " override"); + } + if (remove_virtual && virtual_loc.isValid()) { + ReportIfSpellingLocNotIgnored( + virtual_loc, add_override ? diag_will_be_redundant_virtual_specifier_ + : diag_redundant_virtual_specifier_) + << "'virtual'" + // Slightly subtle: the else case handles both the currently and the + // will be redundant case for override. Doing the check this way also + // lets the plugin prioritize keeping 'final' over 'override' when both + // are present. + << (final_attr ? "'final'" : "'override'") + << FixItHint::CreateRemoval( + CharSourceRange::getTokenRange(SourceRange(virtual_loc))); } } @@ -1006,6 +1010,10 @@ } void FindBadConstructsConsumer::CheckVarDecl(clang::VarDecl* var_decl) { + // Lambda init-captures should be ignored. + if (var_decl->isInitCapture()) + return; + // Check whether auto deduces to a raw pointer. QualType non_reference_type = var_decl->getType().getNonReferenceType(); // We might have a case where the type is written as auto*, but the actual
diff --git a/tools/clang/plugins/FindBadConstructsConsumer.h b/tools/clang/plugins/FindBadConstructsConsumer.h index 6e7930a4..928179f 100644 --- a/tools/clang/plugins/FindBadConstructsConsumer.h +++ b/tools/clang/plugins/FindBadConstructsConsumer.h
@@ -114,6 +114,7 @@ unsigned diag_method_requires_override_; unsigned diag_redundant_virtual_specifier_; + unsigned diag_will_be_redundant_virtual_specifier_; unsigned diag_base_method_virtual_and_final_; unsigned diag_virtual_with_inline_body_; unsigned diag_no_explicit_ctor_;
diff --git a/tools/clang/plugins/tests/auto_raw_pointer.cpp b/tools/clang/plugins/tests/auto_raw_pointer.cpp index 5ddb55f..2b0cc98f 100644 --- a/tools/clang/plugins/tests/auto_raw_pointer.cpp +++ b/tools/clang/plugins/tests/auto_raw_pointer.cpp
@@ -2,6 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +class Iteratable { + public: + using const_iterator = int* const*; + + const_iterator begin() { return nullptr; } + const_iterator end() { return nullptr; } +}; + class Foo { public: void foo() {} @@ -49,4 +57,12 @@ const auto&& const_int_ptr_rref = static_cast<int*&&>(int_ptr); static auto static_ptr = new int; + + Iteratable iteratable; + for (auto& it : iteratable) + (void)it; + + // This is a valid usecase of deducing a type to be a raw pointer and should + // not trigger a warning / error. + auto lambda = [foo_ptr = &foo] { return *foo_ptr; }; }
diff --git a/tools/clang/plugins/tests/auto_raw_pointer.txt b/tools/clang/plugins/tests/auto_raw_pointer.txt index 34f7bdbf..6683acdf 100644 --- a/tools/clang/plugins/tests/auto_raw_pointer.txt +++ b/tools/clang/plugins/tests/auto_raw_pointer.txt
@@ -1,57 +1,61 @@ -auto_raw_pointer.cpp:20:3: warning: [chromium-style] auto variable type must not deduce to a raw pointer type. +auto_raw_pointer.cpp:28:3: warning: [chromium-style] auto variable type must not deduce to a raw pointer type. auto raw_int_ptr = &integer; ^~~~ auto* -auto_raw_pointer.cpp:21:3: warning: [chromium-style] auto variable type must not deduce to a raw pointer type. +auto_raw_pointer.cpp:29:3: warning: [chromium-style] auto variable type must not deduce to a raw pointer type. const auto const_raw_int_ptr = &integer; ^~~~~~~~~~ auto* const -auto_raw_pointer.cpp:22:3: warning: [chromium-style] auto variable type must not deduce to a raw pointer type. +auto_raw_pointer.cpp:30:3: warning: [chromium-style] auto variable type must not deduce to a raw pointer type. const auto& const_raw_int_ptr_ref = &integer; ^~~~~~~~~~~ auto* const -auto_raw_pointer.cpp:27:3: warning: [chromium-style] auto variable type must not deduce to a raw pointer type. +auto_raw_pointer.cpp:35:3: warning: [chromium-style] auto variable type must not deduce to a raw pointer type. auto raw_foo_ptr = &foo; ^~~~ auto* -auto_raw_pointer.cpp:28:3: warning: [chromium-style] auto variable type must not deduce to a raw pointer type. +auto_raw_pointer.cpp:36:3: warning: [chromium-style] auto variable type must not deduce to a raw pointer type. const auto const_raw_foo_ptr = &foo; ^~~~~~~~~~ auto* const -auto_raw_pointer.cpp:29:3: warning: [chromium-style] auto variable type must not deduce to a raw pointer type. +auto_raw_pointer.cpp:37:3: warning: [chromium-style] auto variable type must not deduce to a raw pointer type. const auto& const_raw_foo_ptr_ref = &foo; ^~~~~~~~~~~ auto* const -auto_raw_pointer.cpp:36:3: warning: [chromium-style] auto variable type must not deduce to a raw pointer type. +auto_raw_pointer.cpp:44:3: warning: [chromium-style] auto variable type must not deduce to a raw pointer type. auto double_ptr_auto = &int_ptr; ^~~~ auto** -auto_raw_pointer.cpp:37:3: warning: [chromium-style] auto variable type must not deduce to a raw pointer type. +auto_raw_pointer.cpp:45:3: warning: [chromium-style] auto variable type must not deduce to a raw pointer type. auto* double_ptr_auto_ptr = &int_ptr; ^~~~~ auto** -auto_raw_pointer.cpp:44:3: warning: [chromium-style] auto variable type must not deduce to a raw pointer type. +auto_raw_pointer.cpp:52:3: warning: [chromium-style] auto variable type must not deduce to a raw pointer type. auto auto_awesome = pointer_awesomeness; ^~~~ auto* const* const volatile** const* -auto_raw_pointer.cpp:46:3: warning: [chromium-style] auto variable type must not deduce to a raw pointer type. +auto_raw_pointer.cpp:54:3: warning: [chromium-style] auto variable type must not deduce to a raw pointer type. auto& int_ptr_ref = int_ptr; ^~~~~ auto*& -auto_raw_pointer.cpp:47:3: warning: [chromium-style] auto variable type must not deduce to a raw pointer type. +auto_raw_pointer.cpp:55:3: warning: [chromium-style] auto variable type must not deduce to a raw pointer type. const auto& const_int_ptr_ref = int_ptr; ^~~~~~~~~~~ auto* const -auto_raw_pointer.cpp:48:3: warning: [chromium-style] auto variable type must not deduce to a raw pointer type. +auto_raw_pointer.cpp:56:3: warning: [chromium-style] auto variable type must not deduce to a raw pointer type. auto&& int_ptr_rref = static_cast<int*&&>(int_ptr); ^~~~~~ auto*&& -auto_raw_pointer.cpp:49:3: warning: [chromium-style] auto variable type must not deduce to a raw pointer type. +auto_raw_pointer.cpp:57:3: warning: [chromium-style] auto variable type must not deduce to a raw pointer type. const auto&& const_int_ptr_rref = static_cast<int*&&>(int_ptr); ^~~~~~~~~~~~ auto* const -auto_raw_pointer.cpp:51:3: warning: [chromium-style] auto variable type must not deduce to a raw pointer type. +auto_raw_pointer.cpp:59:3: warning: [chromium-style] auto variable type must not deduce to a raw pointer type. static auto static_ptr = new int; ^~~~~~~~~~~ static auto* -14 warnings generated. +auto_raw_pointer.cpp:62:8: warning: [chromium-style] auto variable type must not deduce to a raw pointer type. + for (auto& it : iteratable) + ^~~~~ + auto* const +15 warnings generated.
diff --git a/tools/clang/plugins/tests/blacklisted_dirs.txt b/tools/clang/plugins/tests/blacklisted_dirs.txt index 5df9e7c..9bef7f9 100644 --- a/tools/clang/plugins/tests/blacklisted_dirs.txt +++ b/tools/clang/plugins/tests/blacklisted_dirs.txt
@@ -2,8 +2,14 @@ virtual void foo(); // Should warn about missing 'override'. ^ override +/src/chromium/src/myheader.h:2:3: warning: [chromium-style] 'virtual' will be redundant; 'override' implies 'virtual'. + virtual void foo(); // Should warn about missing 'override'. + ^~~~~~~~ /src/chrome-breakpad/src/myheader.h:124:21: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'. virtual void foo(); // Should warn about missing 'override'. ^ override -2 warnings generated. +/src/chrome-breakpad/src/myheader.h:124:3: warning: [chromium-style] 'virtual' will be redundant; 'override' implies 'virtual'. + virtual void foo(); // Should warn about missing 'override'. + ^~~~~~~~ +4 warnings generated.
diff --git a/tools/clang/plugins/tests/overridden_methods.cpp b/tools/clang/plugins/tests/overridden_methods.cpp index e5ab0cab..97e9246 100644 --- a/tools/clang/plugins/tests/overridden_methods.cpp +++ b/tools/clang/plugins/tests/overridden_methods.cpp
@@ -9,6 +9,8 @@ void DerivedClass::SomeOtherMethod() {} void DerivedClass::WebKitModifiedSomething() {} +DerivedClassWithDefaultedDtor::DerivedClassWithDefaultedDtor() {} + class ImplementationInterimClass : public BaseClass { public: // Should warn about pure virtual methods. @@ -46,4 +48,5 @@ int main() { DerivedClass something; ImplementationDerivedClass something_else; + DerivedClassWithDefaultedDtor defaulted_dtor; }
diff --git a/tools/clang/plugins/tests/overridden_methods.h b/tools/clang/plugins/tests/overridden_methods.h index ed299334..5199181 100644 --- a/tools/clang/plugins/tests/overridden_methods.h +++ b/tools/clang/plugins/tests/overridden_methods.h
@@ -28,14 +28,14 @@ namespace blink { class WebKitObserver { public: - virtual void WebKitModifiedSomething() {}; + virtual void WebKitModifiedSomething() {} }; } // namespace blink namespace webkit_glue { class WebKitObserverImpl : blink::WebKitObserver { public: - virtual void WebKitModifiedSomething() {}; + virtual void WebKitModifiedSomething() {} }; } // namespace webkit_glue @@ -67,4 +67,15 @@ virtual void SomeMethodWithCommentAndBody() {} // This is a comment. }; +class BaseClassWithDefaultedVirtualDtor { + public: + virtual ~BaseClassWithDefaultedVirtualDtor() = default; +}; + +class DerivedClassWithDefaultedDtor : public BaseClassWithDefaultedVirtualDtor { + public: + DerivedClassWithDefaultedDtor(); + ~DerivedClassWithDefaultedDtor() = default; +}; + #endif // OVERRIDDEN_METHODS_H_
diff --git a/tools/clang/plugins/tests/overridden_methods.txt b/tools/clang/plugins/tests/overridden_methods.txt index 037d4348..5a70c3a 100644 --- a/tools/clang/plugins/tests/overridden_methods.txt +++ b/tools/clang/plugins/tests/overridden_methods.txt
@@ -3,92 +3,165 @@ virtual void SomeMethod() = 0; ^ override +./overridden_methods.h:25:3: warning: [chromium-style] 'virtual' will be redundant; 'override' implies 'virtual'. + virtual void SomeMethod() = 0; + ^~~~~~~~ ./overridden_methods.h:38:42: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'. - virtual void WebKitModifiedSomething() {}; + virtual void WebKitModifiedSomething() {} ^ override +./overridden_methods.h:38:3: warning: [chromium-style] 'virtual' will be redundant; 'override' implies 'virtual'. + virtual void WebKitModifiedSomething() {} + ^~~~~~~~ ./overridden_methods.h:46:27: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'. virtual ~DerivedClass() {} ^ override +./overridden_methods.h:46:3: warning: [chromium-style] 'virtual' will be redundant; 'override' implies 'virtual'. + virtual ~DerivedClass() {} + ^~~~~~~~ ./overridden_methods.h:48:28: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'. virtual void SomeMethod(); ^ override +./overridden_methods.h:48:3: warning: [chromium-style] 'virtual' will be redundant; 'override' implies 'virtual'. + virtual void SomeMethod(); + ^~~~~~~~ ./overridden_methods.h:52:35: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'. virtual void SomeInlineMethod() {} ^ override +./overridden_methods.h:52:3: warning: [chromium-style] 'virtual' will be redundant; 'override' implies 'virtual'. + virtual void SomeInlineMethod() {} + ^~~~~~~~ ./overridden_methods.h:54:41: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'. virtual void WebKitModifiedSomething(); ^ override +./overridden_methods.h:54:3: warning: [chromium-style] 'virtual' will be redundant; 'override' implies 'virtual'. + virtual void WebKitModifiedSomething(); + ^~~~~~~~ ./overridden_methods.h:56:40: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'. virtual void SomeConstMethod() const {} ^ override +./overridden_methods.h:56:3: warning: [chromium-style] 'virtual' will be redundant; 'override' implies 'virtual'. + virtual void SomeConstMethod() const {} + ^~~~~~~~ ./overridden_methods.h:58:54: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'. virtual void SomeMethodWithExceptionSpec() throw() {} ^ override +./overridden_methods.h:58:3: warning: [chromium-style] 'virtual' will be redundant; 'override' implies 'virtual'. + virtual void SomeMethodWithExceptionSpec() throw() {} + ^~~~~~~~ ./overridden_methods.h:61:68: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'. virtual void SomeConstMethodWithExceptionSpec() const throw(int) {} ^ override +./overridden_methods.h:61:3: warning: [chromium-style] 'virtual' will be redundant; 'override' implies 'virtual'. + virtual void SomeConstMethodWithExceptionSpec() const throw(int) {} + ^~~~~~~~ ./overridden_methods.h:63:40: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'. virtual void SomeNonPureBaseMethod() {} ^ override +./overridden_methods.h:63:3: warning: [chromium-style] 'virtual' will be redundant; 'override' implies 'virtual'. + virtual void SomeNonPureBaseMethod() {} + ^~~~~~~~ ./overridden_methods.h:65:39: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'. virtual void SomeMethodWithComment(); // This is a comment. ^ override +./overridden_methods.h:65:3: warning: [chromium-style] 'virtual' will be redundant; 'override' implies 'virtual'. + virtual void SomeMethodWithComment(); // This is a comment. + ^~~~~~~~ ./overridden_methods.h:67:47: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'. virtual void SomeMethodWithCommentAndBody() {} // This is a comment. ^ override -overridden_methods.cpp:15:29: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'. +./overridden_methods.h:67:3: warning: [chromium-style] 'virtual' will be redundant; 'override' implies 'virtual'. + virtual void SomeMethodWithCommentAndBody() {} // This is a comment. + ^~~~~~~~ +./overridden_methods.h:78:36: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'. + ~DerivedClassWithDefaultedDtor() = default; + ^ + override +overridden_methods.cpp:17:29: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'. virtual void SomeMethod() = 0; ^ override -overridden_methods.cpp:22:41: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'. +overridden_methods.cpp:17:3: warning: [chromium-style] 'virtual' will be redundant; 'override' implies 'virtual'. + virtual void SomeMethod() = 0; + ^~~~~~~~ +overridden_methods.cpp:24:41: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'. virtual ~ImplementationDerivedClass() {} ^ override -overridden_methods.cpp:24:28: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'. +overridden_methods.cpp:24:3: warning: [chromium-style] 'virtual' will be redundant; 'override' implies 'virtual'. + virtual ~ImplementationDerivedClass() {} + ^~~~~~~~ +overridden_methods.cpp:26:28: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'. virtual void SomeMethod(); ^ override -overridden_methods.cpp:28:35: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'. +overridden_methods.cpp:26:3: warning: [chromium-style] 'virtual' will be redundant; 'override' implies 'virtual'. + virtual void SomeMethod(); + ^~~~~~~~ +overridden_methods.cpp:30:35: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'. virtual void SomeInlineMethod() {} ^ override -overridden_methods.cpp:30:41: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'. +overridden_methods.cpp:30:3: warning: [chromium-style] 'virtual' will be redundant; 'override' implies 'virtual'. + virtual void SomeInlineMethod() {} + ^~~~~~~~ +overridden_methods.cpp:32:41: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'. virtual void WebKitModifiedSomething(); ^ override -overridden_methods.cpp:32:40: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'. +overridden_methods.cpp:32:3: warning: [chromium-style] 'virtual' will be redundant; 'override' implies 'virtual'. + virtual void WebKitModifiedSomething(); + ^~~~~~~~ +overridden_methods.cpp:34:40: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'. virtual void SomeConstMethod() const {} ^ override -overridden_methods.cpp:34:54: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'. +overridden_methods.cpp:34:3: warning: [chromium-style] 'virtual' will be redundant; 'override' implies 'virtual'. + virtual void SomeConstMethod() const {} + ^~~~~~~~ +overridden_methods.cpp:36:54: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'. virtual void SomeMethodWithExceptionSpec() throw() {} ^ override -overridden_methods.cpp:37:68: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'. +overridden_methods.cpp:36:3: warning: [chromium-style] 'virtual' will be redundant; 'override' implies 'virtual'. + virtual void SomeMethodWithExceptionSpec() throw() {} + ^~~~~~~~ +overridden_methods.cpp:39:68: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'. virtual void SomeConstMethodWithExceptionSpec() const throw(int) {} ^ override -overridden_methods.cpp:39:40: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'. +overridden_methods.cpp:39:3: warning: [chromium-style] 'virtual' will be redundant; 'override' implies 'virtual'. + virtual void SomeConstMethodWithExceptionSpec() const throw(int) {} + ^~~~~~~~ +overridden_methods.cpp:41:40: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'. virtual void SomeNonPureBaseMethod() {} ^ override -overridden_methods.cpp:41:39: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'. +overridden_methods.cpp:41:3: warning: [chromium-style] 'virtual' will be redundant; 'override' implies 'virtual'. + virtual void SomeNonPureBaseMethod() {} + ^~~~~~~~ +overridden_methods.cpp:43:39: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'. virtual void SomeMethodWithComment(); // This is a comment. ^ override -overridden_methods.cpp:43:47: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'. +overridden_methods.cpp:43:3: warning: [chromium-style] 'virtual' will be redundant; 'override' implies 'virtual'. + virtual void SomeMethodWithComment(); // This is a comment. + ^~~~~~~~ +overridden_methods.cpp:45:47: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'. virtual void SomeMethodWithCommentAndBody() {} // This is a comment. ^ override -23 warnings generated. +overridden_methods.cpp:45:3: warning: [chromium-style] 'virtual' will be redundant; 'override' implies 'virtual'. + virtual void SomeMethodWithCommentAndBody() {} // This is a comment. + ^~~~~~~~ +47 warnings generated.
diff --git a/tools/clang/plugins/tests/virtual_base_method_also_final.cpp b/tools/clang/plugins/tests/virtual_base_method_also_final.cpp index 93723f5..161b5787 100644 --- a/tools/clang/plugins/tests/virtual_base_method_also_final.cpp +++ b/tools/clang/plugins/tests/virtual_base_method_also_final.cpp
@@ -7,11 +7,12 @@ class A { public: - VIRTUAL void F() final {} + virtual void F() final {} // Make sure an out-of-place virtual doesn't cause an incorrect fixit removal // to be emitted. - void VIRTUAL G() final {} - // Make sure a fixit removal isn't generated for macros that expand to more - // than just 'virtual'. - VIRTUAL_VOID H() final {} + void virtual G() final {} + // Don't emit any fixits for virtual from macros. + VIRTUAL void H() final {} + void VIRTUAL I() final {} + VIRTUAL_VOID J() final {} };
diff --git a/tools/clang/plugins/tests/virtual_base_method_also_final.txt b/tools/clang/plugins/tests/virtual_base_method_also_final.txt index 80208dcd..2670ad28 100644 --- a/tools/clang/plugins/tests/virtual_base_method_also_final.txt +++ b/tools/clang/plugins/tests/virtual_base_method_also_final.txt
@@ -1,29 +1,7 @@ virtual_base_method_also_final.cpp:10:3: warning: [chromium-style] 'virtual' is redundant; 'final' implies 'virtual'. - VIRTUAL void F() final {} + virtual void F() final {} ^~~~~~~~ -virtual_base_method_also_final.cpp:5:17: note: expanded from macro 'VIRTUAL' -#define VIRTUAL virtual - ^ -virtual_base_method_also_final.cpp:10:3: warning: [chromium-style] The virtual method does not override anything and is final; consider making it non-virtual. - VIRTUAL void F() final {} - ^~~~~~~~ ~~~~~~ -virtual_base_method_also_final.cpp:5:17: note: expanded from macro 'VIRTUAL' -#define VIRTUAL virtual - ^ -virtual_base_method_also_final.cpp:13:3: warning: [chromium-style] 'virtual' is redundant; 'final' implies 'virtual'. - void VIRTUAL G() final {} - ^ -virtual_base_method_also_final.cpp:13:3: warning: [chromium-style] The virtual method does not override anything and is final; consider making it non-virtual. - void VIRTUAL G() final {} - ^ ~~~~~~ -virtual_base_method_also_final.cpp:16:3: warning: [chromium-style] 'virtual' is redundant; 'final' implies 'virtual'. - VIRTUAL_VOID H() final {} - ^ -virtual_base_method_also_final.cpp:6:22: note: expanded from macro 'VIRTUAL_VOID' -#define VIRTUAL_VOID virtual void - ^ -virtual_base_method_also_final.cpp:16:3: warning: [chromium-style] The virtual method does not override anything and is final; consider making it non-virtual. -virtual_base_method_also_final.cpp:6:22: note: expanded from macro 'VIRTUAL_VOID' -#define VIRTUAL_VOID virtual void - ^ -6 warnings generated. +virtual_base_method_also_final.cpp:13:8: warning: [chromium-style] 'virtual' is redundant; 'final' implies 'virtual'. + void virtual G() final {} + ^~~~~~~~ +2 warnings generated.
diff --git a/tools/clang/plugins/tests/virtual_specifiers.txt b/tools/clang/plugins/tests/virtual_specifiers.txt index 7b36d23..1d92c0c6 100644 --- a/tools/clang/plugins/tests/virtual_specifiers.txt +++ b/tools/clang/plugins/tests/virtual_specifiers.txt
@@ -18,17 +18,14 @@ virtual_specifiers.cpp:53:3: warning: [chromium-style] 'virtual' is redundant; 'final' implies 'virtual'. virtual void F() FINAL {} ^~~~~~~~ -virtual_specifiers.cpp:58:3: warning: [chromium-style] 'virtual' is redundant; 'override' implies 'virtual'. - virtual ~VirtualAndOverrideFinal() OVERRIDE FINAL {} - ^~~~~~~~ virtual_specifiers.cpp:58:38: warning: [chromium-style] 'override' is redundant; 'final' implies 'override'. virtual ~VirtualAndOverrideFinal() OVERRIDE FINAL {} ^~~~~~~~~ virtual_specifiers.cpp:13:18: note: expanded from macro 'OVERRIDE' #define OVERRIDE override ^ -virtual_specifiers.cpp:59:3: warning: [chromium-style] 'virtual' is redundant; 'override' implies 'virtual'. - virtual void F() OVERRIDE FINAL {} +virtual_specifiers.cpp:58:3: warning: [chromium-style] 'virtual' is redundant; 'final' implies 'virtual'. + virtual ~VirtualAndOverrideFinal() OVERRIDE FINAL {} ^~~~~~~~ virtual_specifiers.cpp:59:20: warning: [chromium-style] 'override' is redundant; 'final' implies 'override'. virtual void F() OVERRIDE FINAL {} @@ -36,6 +33,9 @@ virtual_specifiers.cpp:13:18: note: expanded from macro 'OVERRIDE' #define OVERRIDE override ^ +virtual_specifiers.cpp:59:3: warning: [chromium-style] 'virtual' is redundant; 'final' implies 'virtual'. + virtual void F() OVERRIDE FINAL {} + ^~~~~~~~ virtual_specifiers.cpp:64:23: warning: [chromium-style] 'override' is redundant; 'final' implies 'override'. ~OverrideAndFinal() OVERRIDE FINAL {} ^~~~~~~~~ @@ -52,6 +52,9 @@ virtual void F() = 0; ^ override +virtual_specifiers.cpp:70:3: warning: [chromium-style] 'virtual' will be redundant; 'override' implies 'virtual'. + virtual void F() = 0; + ^~~~~~~~ virtual_specifiers.cpp:74:12: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'. void F() = 0; ^ @@ -63,7 +66,10 @@ virtual ~MyTest(); ^ override +virtual_specifiers.cpp:111:3: warning: [chromium-style] 'virtual' will be redundant; 'override' implies 'virtual'. + virtual ~MyTest(); + ^~~~~~~~ virtual_specifiers.cpp:112:3: warning: [chromium-style] 'virtual' is redundant; 'override' implies 'virtual'. virtual void SetUp() override; ^~~~~~~~ -17 warnings generated. +19 warnings generated.
diff --git a/tools/clang/pylib/clang/compile_db.py b/tools/clang/pylib/clang/compile_db.py index 0706b42..a78ab5e 100755 --- a/tools/clang/pylib/clang/compile_db.py +++ b/tools/clang/pylib/clang/compile_db.py
@@ -71,6 +71,14 @@ return compile_db +def GetNinjaPath(): + ninja_executable = 'ninja.exe' if sys.platform == 'win32' else 'ninja' + return os.path.join( + os.path.dirname(os.path.realpath(__file__)), + '..', '..', '..', '..', 'third_party', 'depot_tools', ninja_executable) + + +# FIXME: This really should be a build target, rather than generated at runtime. def GenerateWithNinja(path): """Generates a compile database using ninja. @@ -84,7 +92,8 @@ # First, generate the compile database. json_compile_db = subprocess.check_output([ - 'ninja', '-C', path, '-t', 'compdb', 'cc', 'cxx', 'objc', 'objcxx']) + GetNinjaPath(), '-C', path, '-t', 'compdb', 'cc', 'cxx', 'objc', + 'objcxx']) compile_db = json.loads(json_compile_db) # TODO(dcheng): Ideally this would check target_os... but not sure there's an
diff --git a/tools/clang/pylib/clang/plugin_testing.py b/tools/clang/pylib/clang/plugin_testing.py index bede36e..028bb18 100755 --- a/tools/clang/pylib/clang/plugin_testing.py +++ b/tools/clang/pylib/clang/plugin_testing.py
@@ -53,7 +53,7 @@ os.chdir(self._test_base) - clang_cmd = [self._clang_path, '-c', '-std=c++11'] + clang_cmd = [self._clang_path, '-c', '-std=c++14'] if self._plugin_path: clang_cmd.extend(['-Xclang', '-load', '-Xclang', self._plugin_path]) clang_cmd.extend(['-Xclang', '-add-plugin', '-Xclang', self._plugin_name])
diff --git a/tools/clang/scripts/download_lld_mac.py b/tools/clang/scripts/download_lld_mac.py new file mode 100755 index 0000000..50c0e81 --- /dev/null +++ b/tools/clang/scripts/download_lld_mac.py
@@ -0,0 +1,36 @@ +#!/usr/bin/env python +# Copyright 2017 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. + +"""Script to download lld/mac from google storage.""" + +import os +import re +import subprocess +import sys + +import update + +LLVM_BUILD_DIR = update.LLVM_BUILD_DIR +LLD_LINK_PATH = os.path.join(LLVM_BUILD_DIR, 'bin', 'lld-link') + + +def AlreadyUpToDate(): + if not os.path.exists(LLD_LINK_PATH): + return False + lld_rev = subprocess.check_output([LLD_LINK_PATH, '--version']) + return (re.match(r'LLD.*\(trunk (\d+)\)', lld_rev).group(1) == + update.CLANG_REVISION) + + +def main(): + if AlreadyUpToDate(): + return 0 + remote_path = '%s/Mac/lld-%s.tgz' % (update.CDS_URL, update.PACKAGE_VERSION) + update.DownloadAndUnpack(remote_path, update.LLVM_BUILD_DIR) + return 0 + + +if __name__ == '__main__': + sys.exit(main())
diff --git a/tools/clang/scripts/download_objdump.py b/tools/clang/scripts/download_objdump.py new file mode 100755 index 0000000..6025f7d --- /dev/null +++ b/tools/clang/scripts/download_objdump.py
@@ -0,0 +1,47 @@ +#!/usr/bin/env python +# Copyright 2017 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. + +"""Script to download llvm-objdump and related utils from google storage.""" + +import os +import re +import subprocess +import sys +import urllib2 + +import update + +LLVM_BUILD_DIR = update.LLVM_BUILD_DIR +OBJDUMP_PATH = os.path.join(LLVM_BUILD_DIR, 'bin', 'llvm-objdump') +STAMP_FILE = os.path.normpath( + os.path.join(LLVM_BUILD_DIR, 'llvmobjdump_build_revision')) + + +def AlreadyUpToDate(): + if not os.path.exists(OBJDUMP_PATH) or not os.path.exists(STAMP_FILE): + return False + stamp = update.ReadStampFile(STAMP_FILE) + return stamp.rstrip() == update.PACKAGE_VERSION + + +def DownloadAndUnpackLlvmObjDumpPackage(platform): + cds_file = 'llvmobjdump-%s.tgz' % update.PACKAGE_VERSION + cds_full_url = update.GetPlatformUrlPrefix(platform) + cds_file + try: + update.DownloadAndUnpack(cds_full_url, update.LLVM_BUILD_DIR) + except urllib2.URLError: + print 'Failed to download prebuilt utils %s' % cds_file + print 'Use --force-local-build if you want to build locally.' + print 'Exiting.' + sys.exit(1) + + +def main(): + if not AlreadyUpToDate(): + DownloadAndUnpackLlvmObjDumpPackage(sys.platform) + return 0 + +if __name__ == '__main__': + sys.exit(main())
diff --git a/tools/clang/scripts/package.py b/tools/clang/scripts/package.py index 2699d06..93be613 100755 --- a/tools/clang/scripts/package.py +++ b/tools/clang/scripts/package.py
@@ -25,7 +25,7 @@ 'llvm-bootstrap-install') LLVM_BUILD_DIR = os.path.join(THIRD_PARTY_DIR, 'llvm-build') LLVM_RELEASE_DIR = os.path.join(LLVM_BUILD_DIR, 'Release+Asserts') -LLVM_LTO_LLD_DIR = os.path.join(THIRD_PARTY_DIR, 'llvm-lto-lld') +EU_STRIP = os.path.join(THIRD_PARTY_DIR, 'eu-strip', 'bin', 'eu-strip') STAMP_FILE = os.path.join(LLVM_BUILD_DIR, 'cr_build_revision') @@ -93,9 +93,7 @@ def MaybeUpload(args, archive_name, platform): - # We don't want to rewrite the file, if it already exists on the server, - # so -n option to gsutil is used. It will warn, if the upload was aborted. - gsutil_args = ['cp', '-n', '-a', 'public-read', + gsutil_args = ['cp', '-a', 'public-read', '%s.tgz' % archive_name, 'gs://chromium-browser-clang-staging/%s/%s.tgz' % (platform, archive_name)] @@ -166,7 +164,7 @@ args = parser.parse_args() # Check that the script is not going to upload a toolchain built from HEAD. - use_head_revision = 'LLVM_FORCE_HEAD_REVISION' in os.environ + use_head_revision = bool(int(os.environ.get('LLVM_FORCE_HEAD_REVISION', '0'))) if args.upload and use_head_revision: print ("--upload and LLVM_FORCE_HEAD_REVISION could not be used " "at the same time.") @@ -183,13 +181,6 @@ else: platform = 'Linux_x64' - # Check if Google Cloud Storage already has the artifacts we want to build. - if args.upload and GsutilArchiveExists(pdir, platform): - print ('Desired toolchain revision %s is already available ' - 'in Google Cloud Storage:') % expected_stamp - print 'gs://chromium-browser-clang-staging/%s/%s.tgz' % (platform, pdir) - return 0 - with open('buildlog.txt', 'w') as log: Tee('Diff in llvm:\n', log) TeeCmd(['svn', 'stat', LLVM_DIR], log, fail_hard=False) @@ -255,10 +246,11 @@ 'lib/libBlinkGCPlugin.' + so_ext, ]) if sys.platform == 'darwin': - want.extend([# Copy only the OSX and iossim (ASan and profile) runtime - # libraries: + want.extend([# Copy only the OSX and iossim (ASan, fuzzer and profile) + # runtime libraries: 'lib/clang/*/lib/darwin/*asan_osx*', 'lib/clang/*/lib/darwin/*asan_iossim*', + 'lib/clang/*/lib/darwin/*fuzzer*', 'lib/clang/*/lib/darwin/*profile_osx*', 'lib/clang/*/lib/darwin/*profile_iossim*', # And the OSX and ios builtin libraries (iossim is lipo'd into @@ -271,10 +263,11 @@ want.append('bin/llvm-ar') want.append('bin/lld') # Copy only - # lib/clang/*/lib/linux/libclang_rt.{[atm]san,san,ubsan,profile}-*.a , + # lib/clang/*/lib/linux/libclang_rt.{[atm]san,san,ubsan,fuzzer,profile}-*.a, # but not dfsan. want.extend(['lib/clang/*/lib/linux/*[atm]san*', 'lib/clang/*/lib/linux/*ubsan*', + 'lib/clang/*/lib/linux/*libclang_rt.fuzzer*', 'lib/clang/*/lib/linux/*libclang_rt.san*', 'lib/clang/*/lib/linux/*profile*', 'lib/clang/*/msan_blacklist.txt', @@ -282,6 +275,7 @@ elif sys.platform == 'win32': want.extend(['lib/clang/*/lib/windows/clang_rt.asan*.dll', 'lib/clang/*/lib/windows/clang_rt.asan*.lib', + 'lib/clang/*/lib/windows/clang_rt.ubsan*.lib', ]) for root, dirs, files in os.walk(LLVM_RELEASE_DIR): @@ -302,7 +296,18 @@ subprocess.call(['strip', '-x', dest]) elif (sys.platform.startswith('linux') and os.path.splitext(f)[1] in ['.so', '.a']): - subprocess.call(['strip', '-g', dest]) + subprocess.call([EU_STRIP, '-g', dest]) + + stripped_binaries = ['clang', 'llvm-symbolizer', 'sancov'] + if sys.platform.startswith('linux'): + stripped_binaries.append('lld') + stripped_binaries.append('llvm-ar') + for f in stripped_binaries: + if sys.platform == 'darwin': + # See http://crbug.com/256342 + subprocess.call(['strip', '-x', os.path.join(pdir, 'bin', f)]) + elif sys.platform.startswith('linux'): + subprocess.call(['strip', os.path.join(pdir, 'bin', f)]) # Set up symlinks. if sys.platform != 'win32': @@ -343,17 +348,53 @@ filter=PrintTarProgress) MaybeUpload(args, code_coverage_dir, platform) - # Zip up llvm-objdump for sanitizer coverage. + # Zip up llvm-objdump and related tools for sanitizer coverage and Supersize. objdumpdir = 'llvmobjdump-' + stamp shutil.rmtree(objdumpdir, ignore_errors=True) os.makedirs(os.path.join(objdumpdir, 'bin')) - shutil.copy(os.path.join(LLVM_RELEASE_DIR, 'bin', 'llvm-objdump' + exe_ext), - os.path.join(objdumpdir, 'bin')) + for filename in ['llvm-cxxfilt', 'llvm-nm', 'llvm-objdump', 'llvm-readobj']: + shutil.copy(os.path.join(LLVM_RELEASE_DIR, 'bin', filename + exe_ext), + os.path.join(objdumpdir, 'bin')) + llvmobjdump_stamp_file_base = 'llvmobjdump_build_revision' + llvmobjdump_stamp_file = os.path.join(objdumpdir, llvmobjdump_stamp_file_base) + with open(llvmobjdump_stamp_file, 'w') as f: + f.write(expected_stamp) + f.write('\n') + if sys.platform != 'win32': + os.symlink('llvm-readobj', os.path.join(objdumpdir, 'bin', 'llvm-readelf')) with tarfile.open(objdumpdir + '.tgz', 'w:gz') as tar: tar.add(os.path.join(objdumpdir, 'bin'), arcname='bin', filter=PrintTarProgress) + tar.add(llvmobjdump_stamp_file, arcname=llvmobjdump_stamp_file_base, + filter=PrintTarProgress) MaybeUpload(args, objdumpdir, platform) + # Zip up llvm-cfi-verify for CFI coverage. + cfiverifydir = 'llvmcfiverify-' + stamp + shutil.rmtree(cfiverifydir, ignore_errors=True) + os.makedirs(os.path.join(cfiverifydir, 'bin')) + shutil.copy(os.path.join(LLVM_RELEASE_DIR, 'bin', 'llvm-cfi-verify' + + exe_ext), + os.path.join(cfiverifydir, 'bin')) + with tarfile.open(cfiverifydir + '.tgz', 'w:gz') as tar: + tar.add(os.path.join(cfiverifydir, 'bin'), arcname='bin', + filter=PrintTarProgress) + MaybeUpload(args, cfiverifydir, platform) + + # On Mac, lld isn't part of the main zip. Upload it in a separate zip. + if sys.platform == 'darwin': + llddir = 'lld-' + stamp + shutil.rmtree(llddir, ignore_errors=True) + os.makedirs(os.path.join(llddir, 'bin')) + shutil.copy(os.path.join(LLVM_RELEASE_DIR, 'bin', 'lld'), + os.path.join(llddir, 'bin')) + os.symlink('lld', os.path.join(llddir, 'bin', 'lld-link')) + os.symlink('lld', os.path.join(llddir, 'bin', 'ld.lld')) + with tarfile.open(llddir + '.tgz', 'w:gz') as tar: + tar.add(os.path.join(llddir, 'bin'), arcname='bin', + filter=PrintTarProgress) + MaybeUpload(args, llddir, platform) + # Zip up the translation_unit tool. translation_unit_dir = 'translation_unit-' + stamp shutil.rmtree(translation_unit_dir, ignore_errors=True)
diff --git a/tools/clang/scripts/run_tool.py b/tools/clang/scripts/run_tool.py index e6a88937..ef887e8 100755 --- a/tools/clang/scripts/run_tool.py +++ b/tools/clang/scripts/run_tool.py
@@ -75,6 +75,8 @@ Returns: Pruned list of files. """ + if not git_files: + return [] pruned_list = [] git_index = 0 for path in sorted(paths): @@ -260,7 +262,7 @@ nargs='*', help='optional paths to filter what files the tool is run on') parser.add_argument( - '--tool-args', nargs='*', + '--tool-arg', nargs='?', action='append', help='optional arguments passed to the tool') parser.add_argument( '--tool-path', nargs='?', @@ -302,7 +304,7 @@ shard_number, shard_count, len(source_filenames), total_length) dispatcher = _CompilerDispatcher(os.path.join(tool_path, args.tool), - args.tool_args, + args.tool_arg, args.p, source_filenames) dispatcher.Run()
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py index 1b9fdeb..de21496 100755 --- a/tools/clang/scripts/update.py +++ b/tools/clang/scripts/update.py
@@ -27,9 +27,10 @@ # Do NOT CHANGE this if you don't know what you're doing -- see # https://chromium.googlesource.com/chromium/src/+/master/docs/updating_clang.md # Reverting problematic clang rolls is safe, though. -CLANG_REVISION = '313786' +CLANG_REVISION = '324578' -use_head_revision = 'LLVM_FORCE_HEAD_REVISION' in os.environ +use_head_revision = bool(os.environ.get('LLVM_FORCE_HEAD_REVISION', '0') + in ('1', 'YES')) if use_head_revision: CLANG_REVISION = 'HEAD' @@ -41,15 +42,16 @@ # Path constants. (All of these should be absolute paths.) THIS_DIR = os.path.abspath(os.path.dirname(__file__)) CHROMIUM_DIR = os.path.abspath(os.path.join(THIS_DIR, '..', '..', '..')) +GCLIENT_CONFIG = os.path.join(os.path.dirname(CHROMIUM_DIR), '.gclient') THIRD_PARTY_DIR = os.path.join(CHROMIUM_DIR, 'third_party') LLVM_DIR = os.path.join(THIRD_PARTY_DIR, 'llvm') LLVM_BOOTSTRAP_DIR = os.path.join(THIRD_PARTY_DIR, 'llvm-bootstrap') LLVM_BOOTSTRAP_INSTALL_DIR = os.path.join(THIRD_PARTY_DIR, 'llvm-bootstrap-install') -LLVM_LTO_LLD_DIR = os.path.join(THIRD_PARTY_DIR, 'llvm-lto-lld') CHROME_TOOLS_SHIM_DIR = os.path.join(LLVM_DIR, 'tools', 'chrometools') LLVM_BUILD_DIR = os.path.join(CHROMIUM_DIR, 'third_party', 'llvm-build', 'Release+Asserts') +THREADS_ENABLED_BUILD_DIR = os.path.join(LLVM_BUILD_DIR, 'threads_enabled') COMPILER_RT_BUILD_DIR = os.path.join(LLVM_BUILD_DIR, 'compiler-rt') CLANG_DIR = os.path.join(LLVM_DIR, 'tools', 'clang') LLD_DIR = os.path.join(LLVM_DIR, 'tools', 'lld') @@ -66,9 +68,9 @@ os.path.join(LLVM_DIR, '..', 'llvm-build-tools')) STAMP_FILE = os.path.normpath( os.path.join(LLVM_DIR, '..', 'llvm-build', 'cr_build_revision')) -VERSION = '6.0.0' +VERSION = '7.0.0' ANDROID_NDK_DIR = os.path.join( - CHROMIUM_DIR, 'third_party', 'android_tools', 'ndk') + CHROMIUM_DIR, 'third_party', 'android_ndk') # URL for pre-built binaries. CDS_URL = os.environ.get('CDS_CLANG_BUCKET_OVERRIDE', @@ -129,19 +131,26 @@ def EnsureDirExists(path): if not os.path.exists(path): - print "Creating directory %s" % path os.makedirs(path) -def DownloadAndUnpack(url, output_dir): +def DownloadAndUnpack(url, output_dir, path_prefix=None): + """Download an archive from url and extract into output_dir. If path_prefix is + not None, only extract files whose paths within the archive start with + path_prefix.""" with tempfile.TemporaryFile() as f: DownloadUrl(url, f) f.seek(0) EnsureDirExists(output_dir) if url.endswith('.zip'): + assert path_prefix is None zipfile.ZipFile(f).extractall(path=output_dir) else: - tarfile.open(mode='r:gz', fileobj=f).extractall(path=output_dir) + t = tarfile.open(mode='r:gz', fileobj=f) + members = None + if path_prefix is not None: + members = [m for m in t.getmembers() if m.name.startswith(path_prefix)] + t.extractall(path=output_dir, members=members) def ReadStampFile(path=STAMP_FILE): @@ -255,6 +264,28 @@ RunCommand(command) +def CheckoutRepos(args): + if args.skip_checkout: + return + + Checkout('LLVM', LLVM_REPO_URL + '/llvm/trunk', LLVM_DIR) + Checkout('Clang', LLVM_REPO_URL + '/cfe/trunk', CLANG_DIR) + if True: + Checkout('LLD', LLVM_REPO_URL + '/lld/trunk', LLD_DIR) + elif os.path.exists(LLD_DIR): + # In case someone sends a tryjob that temporary adds lld to the checkout, + # make sure it's not around on future builds. + RmTree(LLD_DIR) + Checkout('compiler-rt', LLVM_REPO_URL + '/compiler-rt/trunk', COMPILER_RT_DIR) + if sys.platform == 'darwin': + # clang needs a libc++ checkout, else -stdlib=libc++ won't find includes + # (i.e. this is needed for bootstrap builds). + Checkout('libcxx', LLVM_REPO_URL + '/libcxx/trunk', LIBCXX_DIR) + # We used to check out libcxxabi on OS X; we no longer need that. + if os.path.exists(LIBCXXABI_DIR): + RmTree(LIBCXXABI_DIR) + + def DeleteChromeToolsShim(): OLD_SHIM_DIR = os.path.join(LLVM_DIR, 'tools', 'zzz-chrometools') shutil.rmtree(OLD_SHIM_DIR, ignore_errors=True) @@ -308,8 +339,10 @@ os.environ['PATH'] = svn_dir + os.pathsep + os.environ.get('PATH', '') -def AddCMakeToPath(): +def AddCMakeToPath(args): """Download CMake and add it to PATH.""" + if args.use_system_cmake: + return if sys.platform == 'win32': zip_name = 'cmake-3.4.3-win32-x86.zip' cmake_dir = os.path.join(LLVM_BUILD_TOOLS_DIR, @@ -387,41 +420,60 @@ sys.exit(1) -def UpdateClang(args): - print 'Updating Clang to %s...' % PACKAGE_VERSION +def GetPlatformUrlPrefix(platform): + if platform == 'win32' or platform == 'cygwin': + return CDS_URL + '/Win/' + if platform == 'darwin': + return CDS_URL + '/Mac/' + assert platform.startswith('linux') + return CDS_URL + '/Linux_x64/' - if ReadStampFile() == PACKAGE_VERSION and not args.force_local_build: - print 'Clang is already up to date.' + +def DownloadAndUnpackClangPackage(platform, runtimes_only=False): + cds_file = "clang-%s.tgz" % PACKAGE_VERSION + cds_full_url = GetPlatformUrlPrefix(platform) + cds_file + try: + path_prefix = None + if runtimes_only: + path_prefix = 'lib/clang/' + VERSION + '/lib/' + DownloadAndUnpack(cds_full_url, LLVM_BUILD_DIR, path_prefix) + except urllib2.URLError: + print 'Failed to download prebuilt clang %s' % cds_file + print 'Use --force-local-build if you want to build locally.' + print 'Exiting.' + sys.exit(1) + + +def UpdateClang(args): + # Read target_os from .gclient so we know which non-native runtimes we need. + # TODO(pcc): See if we can download just the runtimes instead of the entire + # clang package, and do that from DEPS instead of here. + target_os = [] + try: + env = {} + execfile(GCLIENT_CONFIG, env, env) + target_os = env.get('target_os', target_os) + except: + pass + + expected_stamp = ','.join([PACKAGE_VERSION] + target_os) + if ReadStampFile() == expected_stamp and not args.force_local_build: return 0 # Reset the stamp file in case the build is unsuccessful. WriteStampFile('') if not args.force_local_build: - cds_file = "clang-%s.tgz" % PACKAGE_VERSION - if sys.platform == 'win32' or sys.platform == 'cygwin': - cds_full_url = CDS_URL + '/Win/' + cds_file - elif sys.platform == 'darwin': - cds_full_url = CDS_URL + '/Mac/' + cds_file - else: - assert sys.platform.startswith('linux') - cds_full_url = CDS_URL + '/Linux_x64/' + cds_file - - print 'Downloading prebuilt clang' if os.path.exists(LLVM_BUILD_DIR): RmTree(LLVM_BUILD_DIR) - try: - DownloadAndUnpack(cds_full_url, LLVM_BUILD_DIR) - print 'clang %s unpacked' % PACKAGE_VERSION - if sys.platform == 'win32': - CopyDiaDllTo(os.path.join(LLVM_BUILD_DIR, 'bin')) - WriteStampFile(PACKAGE_VERSION) - return 0 - except urllib2.URLError: - print 'Failed to download prebuilt clang %s' % cds_file - print 'Use --force-local-build if you want to build locally.' - print 'Exiting.' - return 1 + + DownloadAndUnpackClangPackage(sys.platform) + if 'win' in target_os: + DownloadAndUnpackClangPackage('win32', runtimes_only=True) + if sys.platform == 'win32': + CopyDiaDllTo(os.path.join(LLVM_BUILD_DIR, 'bin')) + WriteStampFile(expected_stamp) + return 0 if args.with_android and not os.path.exists(ANDROID_NDK_DIR): print 'Android NDK not found at ' + ANDROID_NDK_DIR @@ -431,42 +483,18 @@ print 'for how to install the NDK, or pass --without-android.' return 1 + print 'Locally building Clang %s...' % PACKAGE_VERSION + DownloadHostGcc(args) - AddCMakeToPath() + AddCMakeToPath(args) AddGnuWinToPath() DeleteChromeToolsShim() - Checkout('LLVM', LLVM_REPO_URL + '/llvm/trunk', LLVM_DIR) + CheckoutRepos(args) - # Back out previous local patches. This needs to be kept around a bit - # until all bots have cycled. See https://crbug.com/755777. - files = [ - 'lib/Transforms/InstCombine/InstructionCombining.cpp', - 'test/DebugInfo/X86/formal_parameter.ll', - 'test/DebugInfo/X86/instcombine-instrinsics.ll', - 'test/Transforms/InstCombine/debuginfo-skip.ll', - 'test/Transforms/InstCombine/debuginfo.ll', - 'test/Transforms/Util/simplify-dbg-declare-load.ll', - ] - for f in [os.path.join(LLVM_DIR, f) for f in files]: - RunCommand(['svn', 'revert', f]) - - Checkout('Clang', LLVM_REPO_URL + '/cfe/trunk', CLANG_DIR) - if sys.platform != 'darwin': - Checkout('LLD', LLVM_REPO_URL + '/lld/trunk', LLD_DIR) - elif os.path.exists(LLD_DIR): - # In case someone sends a tryjob that temporary adds lld to the checkout, - # make sure it's not around on future builds. - RmTree(LLD_DIR) - Checkout('compiler-rt', LLVM_REPO_URL + '/compiler-rt/trunk', COMPILER_RT_DIR) - if sys.platform == 'darwin': - # clang needs a libc++ checkout, else -stdlib=libc++ won't find includes - # (i.e. this is needed for bootstrap builds). - Checkout('libcxx', LLVM_REPO_URL + '/libcxx/trunk', LIBCXX_DIR) - # We used to check out libcxxabi on OS X; we no longer need that. - if os.path.exists(LIBCXXABI_DIR): - RmTree(LIBCXXABI_DIR) + if args.skip_build: + return cc, cxx = None, None libstdcpp = None @@ -497,6 +525,10 @@ '-DLLVM_USE_CRT_RELEASE=MT', ] + if sys.platform != 'win32': + # libxml2 is required by the Win manifest merging tool used in cross-builds. + base_cmake_args.append('-DLLVM_ENABLE_LIBXML2=FORCE_ON') + if args.bootstrap: print 'Building bootstrap compiler' EnsureDirExists(LLVM_BOOTSTRAP_DIR) @@ -536,37 +568,6 @@ cxxflags = ['--gcc-toolchain=' + args.gcc_toolchain] print 'Building final compiler' - # Build lld with LTO. That speeds up the linker by ~10%. - # We only use LTO for Linux now. - if args.bootstrap and args.lto_lld: - print 'Building LTO lld' - if os.path.exists(LLVM_LTO_LLD_DIR): - RmTree(LLVM_LTO_LLD_DIR) - EnsureDirExists(LLVM_LTO_LLD_DIR) - os.chdir(LLVM_LTO_LLD_DIR) - - # The linker expects all archive members to have symbol tables, so the - # archiver needs to be able to create symbol tables for bitcode files. - # GNU ar and ranlib don't understand bitcode files, but llvm-ar and - # llvm-ranlib do, so use them. - ar = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'llvm-ar') - ranlib = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'llvm-ranlib') - - lto_cmake_args = base_cmake_args + [ - '-DCMAKE_C_COMPILER=' + cc, - '-DCMAKE_CXX_COMPILER=' + cxx, - '-DCMAKE_AR=' + ar, - '-DCMAKE_RANLIB=' + ranlib, - '-DLLVM_ENABLE_LTO=thin', - '-DLLVM_USE_LINKER=lld', - '-DCMAKE_C_FLAGS=' + ' '.join(cflags), - '-DCMAKE_CXX_FLAGS=' + ' '.join(cxxflags)] - - RmCmakeCache('.') - RunCommand(['cmake'] + lto_cmake_args + [LLVM_DIR]) - RunCommand(['ninja', 'lld']) - - # LLVM uses C++11 starting in llvm 3.5. On Linux, this means libstdc++4.7+ is # needed, on OS X it requires libc++. clang only automatically links to libc++ # when targeting OS X 10.9+, so add stdlib=libc++ explicitly so clang can run @@ -586,7 +587,6 @@ # This makes running package.py over 10% faster (30 min instead of 34 min) RmTree(LIBCXX_DIR) - # Build clang. # If building at head, define a macro that plugins can use for #ifdefing # out code that builds at head, but not at CLANG_REVISION or vice versa. @@ -602,13 +602,57 @@ cxxflags += ['/Zi', '/GS-'] ldflags += ['/DEBUG', '/OPT:REF', '/OPT:ICF'] - CreateChromeToolsShim() - deployment_env = None if deployment_target: deployment_env = os.environ.copy() deployment_env['MACOSX_DEPLOYMENT_TARGET'] = deployment_target + # Build lld and code coverage tools. This is done separately from the rest of + # the build because these tools require threading support. + tools_with_threading = [ 'lld', 'llvm-cov', 'llvm-profdata' ] + print 'Building the following tools with threading support: %s' % ( + str(tools_with_threading)) + + if os.path.exists(THREADS_ENABLED_BUILD_DIR): + RmTree(THREADS_ENABLED_BUILD_DIR) + EnsureDirExists(THREADS_ENABLED_BUILD_DIR) + os.chdir(THREADS_ENABLED_BUILD_DIR) + + threads_enabled_cmake_args = base_cmake_args + [ + '-DCMAKE_C_FLAGS=' + ' '.join(cflags), + '-DCMAKE_CXX_FLAGS=' + ' '.join(cxxflags), + '-DCMAKE_EXE_LINKER_FLAGS=' + ' '.join(ldflags), + '-DCMAKE_SHARED_LINKER_FLAGS=' + ' '.join(ldflags), + '-DCMAKE_MODULE_LINKER_FLAGS=' + ' '.join(ldflags)] + if cc is not None: + threads_enabled_cmake_args.append('-DCMAKE_C_COMPILER=' + cc) + if cxx is not None: + threads_enabled_cmake_args.append('-DCMAKE_CXX_COMPILER=' + cxx) + + if args.lto_lld: + # Build lld with LTO. That speeds up the linker by ~10%. + # We only use LTO for Linux now. + # + # The linker expects all archive members to have symbol tables, so the + # archiver needs to be able to create symbol tables for bitcode files. + # GNU ar and ranlib don't understand bitcode files, but llvm-ar and + # llvm-ranlib do, so use them. + ar = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'llvm-ar') + ranlib = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'llvm-ranlib') + threads_enabled_cmake_args += [ + '-DCMAKE_AR=' + ar, + '-DCMAKE_RANLIB=' + ranlib, + '-DLLVM_ENABLE_LTO=thin', + '-DLLVM_USE_LINKER=lld'] + + RmCmakeCache('.') + RunCommand(['cmake'] + threads_enabled_cmake_args + [LLVM_DIR], + msvc_arch='x64', env=deployment_env) + RunCommand(['ninja'] + tools_with_threading, msvc_arch='x64') + + # Build clang and other tools. + CreateChromeToolsShim() + cmake_args = [] # TODO(thakis): Unconditionally append this to base_cmake_args instead once # compiler-rt can build with clang-cl on Windows (http://llvm.org/PR23698) @@ -635,21 +679,21 @@ msvc_arch='x64', env=deployment_env) RunCommand(['ninja'], msvc_arch='x64') - # Copy LTO-optimized lld, if any. - if args.bootstrap and args.lto_lld: - CopyFile(os.path.join(LLVM_LTO_LLD_DIR, 'bin', 'lld'), + # Copy in the threaded versions of lld and other tools. + if sys.platform == 'win32': + CopyFile(os.path.join(THREADS_ENABLED_BUILD_DIR, 'bin', 'lld-link.exe'), os.path.join(LLVM_BUILD_DIR, 'bin')) + CopyFile(os.path.join(THREADS_ENABLED_BUILD_DIR, 'bin', 'lld.pdb'), + os.path.join(LLVM_BUILD_DIR, 'bin')) + else: + for tool in tools_with_threading: + CopyFile(os.path.join(THREADS_ENABLED_BUILD_DIR, 'bin', tool), + os.path.join(LLVM_BUILD_DIR, 'bin')) if chrome_tools: # If any Chromium tools were built, install those now. RunCommand(['ninja', 'cr-install'], msvc_arch='x64') - if sys.platform == 'darwin': - # See http://crbug.com/256342 - RunCommand(['strip', '-x', os.path.join(LLVM_BUILD_DIR, 'bin', 'clang')]) - elif sys.platform.startswith('linux'): - RunCommand(['strip', os.path.join(LLVM_BUILD_DIR, 'bin', 'clang')]) - VeryifyVersionOfBuiltClangMatchesVERSION() # Do an out-of-tree build of compiler-rt. @@ -684,6 +728,8 @@ [LLVM_DIR if sys.platform == 'win32' else COMPILER_RT_DIR], msvc_arch='x86', env=deployment_env) RunCommand(['ninja', 'compiler-rt'], msvc_arch='x86') + if sys.platform != 'win32': + RunCommand(['ninja', 'fuzzer']) # Copy select output to the main tree. # TODO(hans): Make this (and the .gypi and .isolate files) version number @@ -731,28 +777,31 @@ # Make standalone Android toolchain for target_arch. toolchain_dir = os.path.join( LLVM_BUILD_DIR, 'android-toolchain-' + target_arch) + api_level = '21' if target_arch == 'aarch64' else '19' RunCommand([ make_toolchain, - '--api=' + ('21' if target_arch == 'aarch64' else '19'), + '--api=' + api_level, '--force', '--install-dir=%s' % toolchain_dir, - '--stl=stlport', + '--stl=libc++', '--arch=' + { 'aarch64': 'arm64', 'arm': 'arm', 'i686': 'x86', }[target_arch]]) - # Android NDK r9d copies a broken unwind.h into the toolchain, see - # http://crbug.com/357890 - for f in glob.glob(os.path.join(toolchain_dir, 'include/c++/*/unwind.h')): - os.remove(f) - # Build ASan runtime for Android in a separate build tree. + # Build sanitizer runtimes for Android in a separate build tree. build_dir = os.path.join(LLVM_BUILD_DIR, 'android-' + target_arch) if not os.path.exists(build_dir): os.mkdir(os.path.join(build_dir)) os.chdir(build_dir) - cflags = ['--target=%s-linux-androideabi' % target_arch, + target_triple = target_arch + abi_libs = 'c++abi' + if target_arch == 'arm': + target_triple = 'armv7' + abi_libs += ';unwind' + target_triple += '-linux-android' + api_level + cflags = ['--target=%s' % target_triple, '--sysroot=%s/sysroot' % toolchain_dir, '-B%s' % toolchain_dir] android_args = base_cmake_args + [ @@ -762,16 +811,17 @@ '-DLLVM_CONFIG_PATH=' + os.path.join(LLVM_BUILD_DIR, 'bin/llvm-config'), '-DCMAKE_C_FLAGS=' + ' '.join(cflags), '-DCMAKE_CXX_FLAGS=' + ' '.join(cflags), + '-DSANITIZER_CXX_ABI=none', + '-DSANITIZER_CXX_ABI_LIBRARY=' + abi_libs, + '-DCMAKE_SHARED_LINKER_FLAGS=-Wl,-u__cxa_demangle', '-DANDROID=1'] RmCmakeCache('.') RunCommand(['cmake'] + android_args + [COMPILER_RT_DIR]) - RunCommand(['ninja', 'libclang_rt.asan-%s-android.so' % target_arch]) + RunCommand(['ninja', 'asan', 'ubsan']) - # And copy it into the main build tree. - runtime = 'libclang_rt.asan-%s-android.so' % target_arch - for root, _, files in os.walk(build_dir): - if runtime in files: - shutil.copy(os.path.join(root, runtime), asan_rt_lib_dst_dir) + # And copy them into the main build tree. + for f in glob.glob(os.path.join(build_dir, 'lib/linux/*.so')): + shutil.copy(f, asan_rt_lib_dst_dir) # Run tests. if args.run_tests or use_head_revision: @@ -811,8 +861,15 @@ help='print current clang version (e.g. x.y.z) and exit.') parser.add_argument('--run-tests', action='store_true', help='run tests after building; only for local builds') + parser.add_argument('--skip-build', action='store_true', + help='do not build anything') + parser.add_argument('--skip-checkout', action='store_true', + help='do not create or update any checkouts') parser.add_argument('--extra-tools', nargs='*', default=[], help='select additional chrome tools to build') + parser.add_argument('--use-system-cmake', action='store_true', + help='use the cmake from PATH instead of downloading ' + 'and using prebuilt cmake binaries') parser.add_argument('--without-android', action='store_false', help='don\'t build Android ASan runtime (linux only)', dest='with_android',
diff --git a/tools/clang/traffic_annotation_extractor/CMakeLists.txt b/tools/clang/traffic_annotation_extractor/CMakeLists.txt index f33d3ae7..32b154d 100644 --- a/tools/clang/traffic_annotation_extractor/CMakeLists.txt +++ b/tools/clang/traffic_annotation_extractor/CMakeLists.txt
@@ -2,6 +2,8 @@ BitReader MCParser Option + X86AsmParser + X86CodeGen ) add_llvm_executable(traffic_annotation_extractor
diff --git a/tools/clang/traffic_annotation_extractor/traffic_annotation_extractor.cpp b/tools/clang/traffic_annotation_extractor/traffic_annotation_extractor.cpp index 5015932..eed654a7 100644 --- a/tools/clang/traffic_annotation_extractor/traffic_annotation_extractor.cpp +++ b/tools/clang/traffic_annotation_extractor/traffic_annotation_extractor.cpp
@@ -42,6 +42,7 @@ #include "clang/Tooling/Refactoring.h" #include "clang/Tooling/Tooling.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/TargetSelect.h" using namespace clang::ast_matchers; @@ -414,6 +415,8 @@ options.getSourcePathList()); Collector collector; + llvm::InitializeNativeTarget(); + llvm::InitializeNativeTargetAsmParser(); int result = RunMatchers(&tool, &collector); if (result != 0)
diff --git a/tools/clang/value_cleanup/CMakeLists.txt b/tools/clang/value_cleanup/CMakeLists.txt index 3804117e..006db9c 100644 --- a/tools/clang/value_cleanup/CMakeLists.txt +++ b/tools/clang/value_cleanup/CMakeLists.txt
@@ -7,8 +7,8 @@ ) add_llvm_executable(value_cleanup - ListValueRewriter.cpp ValueCleanup.cpp + ValueRewriter.cpp ) target_link_libraries(value_cleanup
diff --git a/tools/clang/value_cleanup/ListValueRewriter.cpp b/tools/clang/value_cleanup/ListValueRewriter.cpp deleted file mode 100644 index 67988b5..0000000 --- a/tools/clang/value_cleanup/ListValueRewriter.cpp +++ /dev/null
@@ -1,482 +0,0 @@ -// Copyright 2016 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 "ListValueRewriter.h" - -#include <assert.h> -#include <algorithm> - -#include "clang/AST/ASTContext.h" -#include "clang/AST/ParentMap.h" -#include "clang/AST/RecursiveASTVisitor.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/ASTMatchers/ASTMatchers.h" -#include "clang/ASTMatchers/ASTMatchersMacros.h" -#include "clang/Basic/CharInfo.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Frontend/FrontendActions.h" -#include "clang/Lex/Lexer.h" -#include "clang/Tooling/Refactoring.h" -#include "llvm/ADT/STLExtras.h" - -using namespace clang::ast_matchers; -using clang::tooling::Replacement; -using llvm::StringRef; - -namespace { - -// Helper class for AppendRawCallback to visit each DeclRefExpr for a given -// VarDecl. If it finds a DeclRefExpr it can't figure out how to rewrite, the -// traversal will be terminated early. -class CollectDeclRefExprVisitor - : public clang::RecursiveASTVisitor<CollectDeclRefExprVisitor> { - public: - CollectDeclRefExprVisitor(clang::SourceManager* source_manager, - clang::ASTContext* ast_context, - const clang::VarDecl* decl, - const clang::FunctionDecl* containing_function) - : source_manager_(source_manager), - ast_context_(ast_context), - decl_(decl), - is_valid_(decl->hasInit()), - map_(containing_function->getBody()) {} - - // RecursiveASTVisitor: - bool VisitDeclRefExpr(const clang::DeclRefExpr* expr) { - if (expr->getDecl() != decl_) - return true; - - const clang::Stmt* stmt = expr; - while (stmt) { - // TODO(dcheng): Add a const version of getParentIgnoreParenImpCasts. - stmt = map_.getParentIgnoreParenImpCasts(const_cast<clang::Stmt*>(stmt)); - - if (clang::isa<clang::MemberExpr>(stmt)) { - // Member expressions need no special rewriting since std::unique_ptr - // overloads `.' and `->'. - return is_valid_; - } else if (auto* member_call_expr = - clang::dyn_cast<clang::CXXMemberCallExpr>(stmt)) { - return HandleMemberCallExpr(member_call_expr, expr); - } else if (auto* binary_op = - clang::dyn_cast<clang::BinaryOperator>(stmt)) { - return HandleBinaryOp(binary_op); - } else { - // Can't handle this so cancel the rewrite. - stmt->dump(); - return false; - } - } - - assert(false); - return false; - } - - const std::set<clang::tooling::Replacement>& replacements() const { - return replacements_; - } - - private: - bool HandleMemberCallExpr(const clang::CXXMemberCallExpr* member_call_expr, - const clang::DeclRefExpr* decl_ref_expr) { - // If this isn't a ListValue::Append() call, cancel the rewrite: it - // will require manual inspection to determine if it's an ownership - // transferring call or not. - auto* method_decl = member_call_expr->getMethodDecl(); - if (method_decl->getQualifiedNameAsString() != "base::ListValue::Append") - return false; - // Use-after-move is also a fatal error. - if (!is_valid_) - return false; - - is_valid_ = false; - - // Surround the DeclRefExpr with std::move(). - replacements_.emplace(*source_manager_, decl_ref_expr->getLocStart(), 0, - "std::move("); - - clang::SourceLocation end = clang::Lexer::getLocForEndOfToken( - decl_ref_expr->getLocEnd(), 0, *source_manager_, - ast_context_->getLangOpts()); - replacements_.emplace(*source_manager_, end, 0, ")"); - return true; - } - - bool HandleBinaryOp(const clang::BinaryOperator* op) { - if (op->isRelationalOp() || op->isEqualityOp() || op->isLogicalOp()) { - // Supported binary operations for which no rewrites need to be done. - return is_valid_; - } - if (!op->isAssignmentOp()) { - // Pointer arithmetic or something else clever. Just cancel the rewrite. - return false; - } - if (op->isCompoundAssignmentOp()) { - // +=, -=, etc. Give up and cancel the rewrite. - return false; - } - - const clang::Expr* rhs = op->getRHS()->IgnoreParenImpCasts(); - const clang::CXXNewExpr* new_expr = clang::dyn_cast<clang::CXXNewExpr>(rhs); - if (!new_expr) { - // The variable isn't being assigned the result of a new operation. Just - // cancel the rewrite. - return false; - } - - is_valid_ = true; - - // Rewrite the assignment operation to use std::unique_ptr::reset(). - clang::CharSourceRange range = clang::CharSourceRange::getCharRange( - op->getOperatorLoc(), op->getRHS()->getLocStart()); - replacements_.emplace(*source_manager_, range, ".reset("); - - clang::SourceLocation expr_end = clang::Lexer::getLocForEndOfToken( - op->getLocEnd(), 0, *source_manager_, ast_context_->getLangOpts()); - replacements_.emplace(*source_manager_, expr_end, 0, ")"); - return true; - } - - clang::SourceManager* const source_manager_; - clang::ASTContext* const ast_context_; - const clang::VarDecl* const decl_; - // Tracks the state of |decl_| during the traversal. |decl_| becomes valid - // upon initialization/assignment and becomes invalid when passed as an - // argument to base::ListValue::Append(base::Value*). - bool is_valid_; - clang::ParentMap map_; - std::set<clang::tooling::Replacement> replacements_; -}; - -} // namespace - -ListValueRewriter::AppendCallback::AppendCallback( - std::set<clang::tooling::Replacement>* replacements) - : replacements_(replacements) {} - -void ListValueRewriter::AppendCallback::run( - const MatchFinder::MatchResult& result) { - // Delete `new base::*Value(' and `)'. - auto* newExpr = result.Nodes.getNodeAs<clang::CXXNewExpr>("newExpr"); - auto* argExpr = result.Nodes.getNodeAs<clang::Expr>("argExpr"); - - // Note that for the end loc, we use the expansion loc: the argument might be - // a macro like true and false. - clang::CharSourceRange pre_arg_range = clang::CharSourceRange::getCharRange( - newExpr->getLocStart(), - result.SourceManager->getExpansionLoc(argExpr->getLocStart())); - replacements_->emplace(*result.SourceManager, pre_arg_range, ""); - - clang::CharSourceRange post_arg_range = - clang::CharSourceRange::getTokenRange(newExpr->getLocEnd()); - replacements_->emplace(*result.SourceManager, post_arg_range, ""); -} - -ListValueRewriter::AppendBooleanCallback::AppendBooleanCallback( - std::set<clang::tooling::Replacement>* replacements) - : AppendCallback(replacements) {} - -void ListValueRewriter::AppendBooleanCallback::run( - const MatchFinder::MatchResult& result) { - // Replace 'Append' with 'AppendBoolean'. - auto* callExpr = result.Nodes.getNodeAs<clang::CXXMemberCallExpr>("callExpr"); - - clang::CharSourceRange call_range = - clang::CharSourceRange::getTokenRange(callExpr->getExprLoc()); - replacements_->emplace(*result.SourceManager, call_range, "AppendBoolean"); - - AppendCallback::run(result); -} - -ListValueRewriter::AppendIntegerCallback::AppendIntegerCallback( - std::set<clang::tooling::Replacement>* replacements) - : AppendCallback(replacements) {} - -void ListValueRewriter::AppendIntegerCallback::run( - const MatchFinder::MatchResult& result) { - // Replace 'Append' with 'AppendInteger'. - auto* callExpr = result.Nodes.getNodeAs<clang::CXXMemberCallExpr>("callExpr"); - - clang::CharSourceRange call_range = - clang::CharSourceRange::getTokenRange(callExpr->getExprLoc()); - replacements_->emplace(*result.SourceManager, call_range, "AppendInteger"); - - AppendCallback::run(result); -} - -ListValueRewriter::AppendDoubleCallback::AppendDoubleCallback( - std::set<clang::tooling::Replacement>* replacements) - : AppendCallback(replacements) {} - -void ListValueRewriter::AppendDoubleCallback::run( - const MatchFinder::MatchResult& result) { - // Replace 'Append' with 'AppendDouble'. - auto* callExpr = result.Nodes.getNodeAs<clang::CXXMemberCallExpr>("callExpr"); - - clang::CharSourceRange call_range = - clang::CharSourceRange::getTokenRange(callExpr->getExprLoc()); - replacements_->emplace(*result.SourceManager, call_range, "AppendDouble"); - - AppendCallback::run(result); -} - -ListValueRewriter::AppendStringCallback::AppendStringCallback( - std::set<clang::tooling::Replacement>* replacements) - : AppendCallback(replacements) {} - -void ListValueRewriter::AppendStringCallback::run( - const MatchFinder::MatchResult& result) { - // Replace 'Append' with 'AppendString'. - auto* callExpr = result.Nodes.getNodeAs<clang::CXXMemberCallExpr>("callExpr"); - - clang::CharSourceRange call_range = - clang::CharSourceRange::getTokenRange(callExpr->getExprLoc()); - replacements_->emplace(*result.SourceManager, call_range, "AppendString"); - - AppendCallback::run(result); -} - -ListValueRewriter::AppendReleasedUniquePtrCallback:: - AppendReleasedUniquePtrCallback( - std::set<clang::tooling::Replacement>* replacements) - : replacements_(replacements) {} - -void ListValueRewriter::AppendReleasedUniquePtrCallback::run( - const MatchFinder::MatchResult& result) { - auto* object_expr = result.Nodes.getNodeAs<clang::Expr>("objectExpr"); - bool arg_is_rvalue = object_expr->Classify(*result.Context).isRValue(); - - // Remove .release() - auto* member_call = - result.Nodes.getNodeAs<clang::CXXMemberCallExpr>("memberCall"); - auto* member_expr = result.Nodes.getNodeAs<clang::MemberExpr>("memberExpr"); - clang::CharSourceRange release_range = clang::CharSourceRange::getTokenRange( - member_expr->getOperatorLoc(), member_call->getLocEnd()); - replacements_->emplace(*result.SourceManager, release_range, - arg_is_rvalue ? "" : ")"); - - if (arg_is_rvalue) - return; - - // Insert `std::move(' for non-rvalue expressions. - clang::CharSourceRange insertion_range = clang::CharSourceRange::getCharRange( - object_expr->getLocStart(), object_expr->getLocStart()); - replacements_->emplace(*result.SourceManager, insertion_range, "std::move("); -} - -ListValueRewriter::AppendRawPtrCallback::AppendRawPtrCallback( - std::set<clang::tooling::Replacement>* replacements) - : replacements_(replacements) {} - -void ListValueRewriter::AppendRawPtrCallback::run( - const MatchFinder::MatchResult& result) { - auto* var_decl = result.Nodes.getNodeAs<clang::VarDecl>("varDecl"); - // As an optimization, skip processing if it's already been visited, since - // this match callback walks the entire function body. - if (visited_.find(var_decl) != visited_.end()) - return; - visited_.insert(var_decl); - auto* function_context = var_decl->getParentFunctionOrMethod(); - assert(function_context && "local var not in function context?!"); - auto* function_decl = clang::cast<clang::FunctionDecl>(function_context); - - auto* type_source_info = var_decl->getTypeSourceInfo(); - assert(type_source_info && "no type source info for VarDecl?!"); - // Don't bother trying to handle qualifiers. - clang::QualType qual_type = var_decl->getType(); - if (qual_type.hasQualifiers()) { - return; - } - - CollectDeclRefExprVisitor visitor(result.SourceManager, result.Context, - var_decl, function_decl); - if (!visitor.TraverseStmt(function_decl->getBody())) - return; - - // Rewrite the variable type to use std::unique_ptr. - clang::CharSourceRange type_range = clang::CharSourceRange::getTokenRange( - type_source_info->getTypeLoc().getSourceRange()); - std::string replacement_type = "std::unique_ptr<"; - while (true) { - const clang::Type* type = qual_type.getTypePtr(); - if (auto* auto_type = type->getAs<clang::AutoType>()) { - if (!auto_type->isDeduced()) { - // If an AutoType isn't deduced, the rewriter can't do anything. - return; - } - qual_type = auto_type->getDeducedType(); - } else if (auto* pointer_type = type->getAs<clang::PointerType>()) { - qual_type = pointer_type->getPointeeType(); - } else { - break; - } - } - replacement_type += qual_type.getAsString(); - replacement_type += ">"; - replacements_->emplace(*result.SourceManager, type_range, replacement_type); - - // Initialized with `=' - if (var_decl->hasInit() && - var_decl->getInitStyle() == clang::VarDecl::CInit) { - clang::SourceLocation name_end = clang::Lexer::getLocForEndOfToken( - var_decl->getLocation(), 0, *result.SourceManager, - result.Context->getLangOpts()); - clang::CharSourceRange range = clang::CharSourceRange::getCharRange( - name_end, var_decl->getInit()->getLocStart()); - replacements_->emplace(*result.SourceManager, range, "("); - - clang::SourceLocation init_end = clang::Lexer::getLocForEndOfToken( - var_decl->getInit()->getLocEnd(), 0, *result.SourceManager, - result.Context->getLangOpts()); - replacements_->emplace(*result.SourceManager, init_end, 0, ")"); - } - - // Also append the collected replacements from visiting the DeclRefExprs. - replacements_->insert(visitor.replacements().begin(), - visitor.replacements().end()); -} - -ListValueRewriter::ListValueRewriter( - std::set<clang::tooling::Replacement>* replacements) - : append_boolean_callback_(replacements), - append_integer_callback_(replacements), - append_double_callback_(replacements), - append_string_callback_(replacements), - append_released_unique_ptr_callback_(replacements), - append_raw_ptr_callback_(replacements) {} - -void ListValueRewriter::RegisterMatchers(MatchFinder* match_finder) { - auto is_list_append = cxxMemberCallExpr( - callee(cxxMethodDecl(hasName("::base::ListValue::Append"))), - argumentCountIs(1)); - - // base::ListValue::Append(new base::Value(bool)) - // => base::ListValue::AppendBoolean() - match_finder->addMatcher( - id("callExpr", - cxxMemberCallExpr( - is_list_append, - hasArgument( - 0, ignoringParenImpCasts( - id("newExpr", - cxxNewExpr(has(cxxConstructExpr( - hasDeclaration(cxxMethodDecl( - hasName("::base::Value::FundamentalValue"))), - argumentCountIs(1), - hasArgument( - 0, id("argExpr", - expr(hasType(booleanType())))))))))))), - &append_boolean_callback_); - - // base::ListValue::Append(new base::Value(int)) - // => base::ListValue::AppendInteger() - match_finder->addMatcher( - id("callExpr", - cxxMemberCallExpr( - is_list_append, - hasArgument( - 0, - ignoringParenImpCasts(id( - "newExpr", - cxxNewExpr(has(cxxConstructExpr( - hasDeclaration(cxxMethodDecl( - hasName("::base::Value::FundamentalValue"))), - argumentCountIs(1), - hasArgument(0, id("argExpr", - expr(hasType(isInteger()), - unless(hasType( - booleanType()))))))))))))), - &append_integer_callback_); - - // base::ListValue::Append(new base::Value(double)) - // => base::ListValue::AppendDouble() - match_finder->addMatcher( - id("callExpr", - cxxMemberCallExpr( - is_list_append, - hasArgument( - 0, ignoringParenImpCasts(id( - "newExpr", - cxxNewExpr(has(cxxConstructExpr( - hasDeclaration(cxxMethodDecl( - hasName("::base::Value::FundamentalValue"))), - argumentCountIs(1), - hasArgument( - 0, id("argExpr", - expr(hasType( - realFloatingPointType())))))))))))), - &append_double_callback_); - - // base::ListValue::Append(new base::Value(...)) - // => base::ListValue::AppendString() - match_finder->addMatcher( - id("callExpr", - cxxMemberCallExpr( - is_list_append, - hasArgument( - 0, ignoringParenImpCasts( - id("newExpr", - cxxNewExpr(has(cxxConstructExpr( - hasDeclaration(cxxMethodDecl( - hasName("::base::Value::StringValue"))), - argumentCountIs(1), - hasArgument(0, id("argExpr", expr())))))))))), - &append_string_callback_); - - auto is_unique_ptr_release = - allOf(callee(cxxMethodDecl( - hasName("release"), - ofClass(cxxRecordDecl(hasName("::std::unique_ptr"))))), - argumentCountIs(0)); - - // base::ListValue::Append(ReturnsUniquePtr().release()) - // => base::ListValue::Append(ReturnsUniquePtr()) - // or - // base::ListValue::Append(unique_ptr_var.release()) - // => base::ListValue::Append(std::move(unique_ptr_var)) - match_finder->addMatcher( - cxxMemberCallExpr( - is_list_append, - hasArgument( - 0, ignoringParenImpCasts( - id("memberCall", - cxxMemberCallExpr(has(id("memberExpr", memberExpr())), - is_unique_ptr_release, - on(id("objectExpr", expr()))))))), - &append_released_unique_ptr_callback_); - - // Simple versions of the following pattern. Note the callback itself does - // much of the filtering (to detect use-after-move, things that aren't - // assigned the result of a new expression, etc). - // - // base::ListValue* this_list = new base::ListValue; - // this_list->AppendInteger(1); - // that_list->Append(this_list); - // - // will be rewritten to - // - // std::unique_ptr<base::ListValue> this_list(new base::ListValue); - // this_list->AppendInteger(1); - // that_list->Append(std::move(this_list); - match_finder->addMatcher( - cxxMemberCallExpr( - is_list_append, - hasArgument( - 0, - ignoringParenImpCasts(id( - "declRefExpr", - declRefExpr(to(id( - "varDecl", - varDecl( - hasLocalStorage(), - anyOf(hasInitializer( - // Note this won't match C++11 uniform - // initialization syntax, since the - // CXXNewExpr is wrapped in an - // InitListExpr in that case. - ignoringParenImpCasts(cxxNewExpr())), - unless(hasInitializer(expr()))), - unless(parmVarDecl()))))))))), - &append_raw_ptr_callback_); -}
diff --git a/tools/clang/value_cleanup/ListValueRewriter.h b/tools/clang/value_cleanup/ListValueRewriter.h deleted file mode 100644 index 25032b12..0000000 --- a/tools/clang/value_cleanup/ListValueRewriter.h +++ /dev/null
@@ -1,109 +0,0 @@ -// Copyright 2016 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. -// -// Handles various rewrites for base::ListValue::Append(). - -#ifndef TOOLS_CLANG_VALUE_CLEANUP_LIST_VALUE_REWRITER_H_ -#define TOOLS_CLANG_VALUE_CLEANUP_LIST_VALUE_REWRITER_H_ - -#include <memory> -#include <set> -#include <unordered_set> - -#include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/Tooling/Refactoring.h" - -class ListValueRewriter { - public: - explicit ListValueRewriter( - std::set<clang::tooling::Replacement>* replacements); - - void RegisterMatchers(clang::ast_matchers::MatchFinder* match_finder); - - private: - class AppendCallback - : public clang::ast_matchers::MatchFinder::MatchCallback { - public: - explicit AppendCallback( - std::set<clang::tooling::Replacement>* replacements); - - void run( - const clang::ast_matchers::MatchFinder::MatchResult& result) override; - - protected: - std::set<clang::tooling::Replacement>* const replacements_; - }; - - class AppendBooleanCallback : public AppendCallback { - public: - explicit AppendBooleanCallback( - std::set<clang::tooling::Replacement>* replacements); - - void run( - const clang::ast_matchers::MatchFinder::MatchResult& result) override; - }; - - class AppendIntegerCallback : public AppendCallback { - public: - explicit AppendIntegerCallback( - std::set<clang::tooling::Replacement>* replacements); - - void run( - const clang::ast_matchers::MatchFinder::MatchResult& result) override; - }; - - class AppendDoubleCallback : public AppendCallback { - public: - explicit AppendDoubleCallback( - std::set<clang::tooling::Replacement>* replacements); - - void run( - const clang::ast_matchers::MatchFinder::MatchResult& result) override; - }; - - class AppendStringCallback : public AppendCallback { - public: - explicit AppendStringCallback( - std::set<clang::tooling::Replacement>* replacements); - - void run( - const clang::ast_matchers::MatchFinder::MatchResult& result) override; - }; - - class AppendReleasedUniquePtrCallback - : public clang::ast_matchers::MatchFinder::MatchCallback { - public: - explicit AppendReleasedUniquePtrCallback( - std::set<clang::tooling::Replacement>* replacements); - - void run( - const clang::ast_matchers::MatchFinder::MatchResult& result) override; - - private: - std::set<clang::tooling::Replacement>* const replacements_; - }; - - class AppendRawPtrCallback - : public clang::ast_matchers::MatchFinder::MatchCallback { - public: - explicit AppendRawPtrCallback( - std::set<clang::tooling::Replacement>* replacements); - - void run( - const clang::ast_matchers::MatchFinder::MatchResult& result) override; - - private: - std::set<clang::tooling::Replacement>* const replacements_; - std::unordered_set<const clang::VarDecl*> visited_; - }; - - AppendBooleanCallback append_boolean_callback_; - AppendIntegerCallback append_integer_callback_; - AppendDoubleCallback append_double_callback_; - AppendStringCallback append_string_callback_; - AppendReleasedUniquePtrCallback append_released_unique_ptr_callback_; - AppendRawPtrCallback append_raw_ptr_callback_; -}; - -#endif // TOOLS_CLANG_VALUE_CLEANUP_LIST_VALUE_REWRITER_H_
diff --git a/tools/clang/value_cleanup/ValueCleanup.cpp b/tools/clang/value_cleanup/ValueCleanup.cpp index 0d2ebe7..cd9d860 100644 --- a/tools/clang/value_cleanup/ValueCleanup.cpp +++ b/tools/clang/value_cleanup/ValueCleanup.cpp
@@ -20,7 +20,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/TargetSelect.h" -#include "ListValueRewriter.h" +#include "ValueRewriter.h" using namespace clang::ast_matchers; using clang::tooling::CommonOptionsParser; @@ -43,8 +43,8 @@ MatchFinder match_finder; std::set<Replacement> replacements; - ListValueRewriter list_value_rewriter(&replacements); - list_value_rewriter.RegisterMatchers(&match_finder); + ValueRewriter value_rewriter(&replacements); + value_rewriter.RegisterMatchers(&match_finder); std::unique_ptr<clang::tooling::FrontendActionFactory> factory = clang::tooling::newFrontendActionFactory(&match_finder); @@ -52,6 +52,9 @@ if (result != 0) return result; + if (replacements.empty()) + return 0; + // Serialization format is documented in tools/clang/scripts/run_tool.py llvm::outs() << "==== BEGIN EDITS ====\n"; for (const auto& r : replacements) {
diff --git a/tools/clang/value_cleanup/ValueRewriter.cpp b/tools/clang/value_cleanup/ValueRewriter.cpp new file mode 100644 index 0000000..647eb78 --- /dev/null +++ b/tools/clang/value_cleanup/ValueRewriter.cpp
@@ -0,0 +1,52 @@ +// Copyright 2017 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 "ValueRewriter.h" + +#include <utility> + +using namespace clang::ast_matchers; + +ValueRewriter::ListValueCallback::ListValueCallback( + std::string method, + std::string replacement, + std::set<clang::tooling::Replacement>* replacements) + : method_(std::move(method)), + replacement_(std::move(replacement)), + replacements_(replacements) {} + +void ValueRewriter::ListValueCallback::run( + const MatchFinder::MatchResult& result) { + auto* callExpr = result.Nodes.getNodeAs<clang::CXXMemberCallExpr>(method()); + + clang::CharSourceRange call_range = + clang::CharSourceRange::getTokenRange(callExpr->getExprLoc()); + replacements_->emplace(*result.SourceManager, call_range, replacement()); +} + +ValueRewriter::ValueRewriter( + std::set<clang::tooling::Replacement>* replacements) + : list_value_callbacks_({ + {"::base::ListValue::Clear", "GetList().clear", replacements}, + {"::base::ListValue::GetSize", "GetList().size", replacements}, + {"::base::ListValue::empty", "GetList().empty", replacements}, + {"::base::ListValue::Reserve", "GetList().reserve", replacements}, + {"::base::ListValue::AppendBoolean", "GetList().emplace_back", + replacements}, + {"::base::ListValue::AppendInteger", "GetList().emplace_back", + replacements}, + {"::base::ListValue::AppendDouble", "GetList().emplace_back", + replacements}, + {"::base::ListValue::AppendString", "GetList().emplace_back", + replacements}, + }) {} + +void ValueRewriter::RegisterMatchers(MatchFinder* match_finder) { + for (auto& callback : list_value_callbacks_) { + match_finder->addMatcher( + callExpr(callee(functionDecl(hasName(callback.method())))) + .bind(callback.method()), + &callback); + } +}
diff --git a/tools/clang/value_cleanup/ValueRewriter.h b/tools/clang/value_cleanup/ValueRewriter.h new file mode 100644 index 0000000..8924c42 --- /dev/null +++ b/tools/clang/value_cleanup/ValueRewriter.h
@@ -0,0 +1,47 @@ +// Copyright 2017 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. +// +// Handles the rewriting of base::Value::GetType() to base::Value::type(). + +#ifndef TOOLS_CLANG_VALUE_CLEANUP_VALUE_REWRITER_H_ +#define TOOLS_CLANG_VALUE_CLEANUP_VALUE_REWRITER_H_ + +#include <set> +#include <string> +#include <utility> +#include <vector> + +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Tooling/Refactoring.h" + +class ValueRewriter { + public: + explicit ValueRewriter(std::set<clang::tooling::Replacement>* replacements); + + void RegisterMatchers(clang::ast_matchers::MatchFinder* match_finder); + + private: + class ListValueCallback + : public clang::ast_matchers::MatchFinder::MatchCallback { + public: + ListValueCallback(std::string method, + std::string replacement, + std::set<clang::tooling::Replacement>* replacements); + + void run( + const clang::ast_matchers::MatchFinder::MatchResult& result) override; + + const std::string& method() const { return method_; } + const std::string& replacement() const { return replacement_; } + + private: + const std::string method_; + const std::string replacement_; + std::set<clang::tooling::Replacement>* const replacements_; + }; + + std::vector<ListValueCallback> list_value_callbacks_; +}; + +#endif // TOOLS_CLANG_VALUE_CLEANUP_VALUE_REWRITER_H_
diff --git a/tools/clang/value_cleanup/tests/list-value-append-expected.cc b/tools/clang/value_cleanup/tests/list-value-append-expected.cc deleted file mode 100644 index 8d7a57a..0000000 --- a/tools/clang/value_cleanup/tests/list-value-append-expected.cc +++ /dev/null
@@ -1,109 +0,0 @@ -// Copyright 2016 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 <memory> - -#include "values.h" - -#define true true - -base::ListValue* ReturnsRawPtr() { - return nullptr; -} - -std::unique_ptr<base::Value> ReturnsUniquePtr() { - return nullptr; -} - -// The joy of raw pointers. -void DoesItTakeOwnership(base::Value*) {} - -struct Thing { - std::unique_ptr<base::Value> ToValue() { return nullptr; } -}; - -void F() { - base::ListValue list; - list.AppendBoolean(1 == 0); - list.AppendBoolean(true); - list.AppendInteger(static_cast<unsigned char>(1.0)); - list.AppendDouble(double{3}); - list.AppendString("abc"); - - list.Append(ReturnsUniquePtr()); - Thing thing; - list.Append(thing.ToValue()); - std::unique_ptr<base::Value> unique_ptr_var; - list.Append(std::move(unique_ptr_var)); -} - -void G(base::Value* input) { - base::ListValue list; - - std::unique_ptr<base::ListValue> local(new base::ListValue()); - // Not rewritten, since it often makes more sense to change the function - // prototype. - local->Append(input); - // Should be rewritten: it will only be moved after it's no longer referenced. - list.Append(std::move(local)); - - // Not rewritten, since it would be used after it's moved. In theory, we could - // automatically handle this too, but the risk of accidentally breaking - // something is much higher. - base::ListValue* clever_list = new base::ListValue; - list.Append(clever_list); - clever_list->AppendInteger(2); - - // Not rewritten, since it often makes more sense to change the function - // prototype. - base::Value* returned_value = ReturnsRawPtr(); - list.Append(returned_value); - - // Should be rewritten. The reassignment should be transformed into - // .reset(). - std::unique_ptr<base::ListValue> reused_list(new base::ListValue); - reused_list->AppendInteger(1); - list.Append(std::move(reused_list)); - reused_list.reset(new base::ListValue); - reused_list->AppendInteger(3); - list.Append(std::move(reused_list)); - - // This shouldn't be rewritten, since the reassignment is the return - // value of a function. - base::ListValue* reused_list_2 = new base::ListValue; - reused_list_2->AppendInteger(4); - list.Append(reused_list_2); - reused_list_2 = ReturnsRawPtr(); - reused_list_2->AppendInteger(5); - list.Append(reused_list_2); - - // auto should be expanded to a std::unique_ptr containing the deduced type. - std::unique_ptr<class base::ListValue> auto_list(new base::ListValue); - auto_list->AppendInteger(6); - list.Append(std::move(auto_list)); - - std::unique_ptr<class base::ListValue> auto_list_2(new base::ListValue); - auto_list_2->AppendInteger(7); - list.Append(std::move(auto_list_2)); - - // Shouldn't be rewritten: a raw pointer is passed to a function which may or - // may not take ownership. - base::ListValue* maybe_owned_list = new base::ListValue; - DoesItTakeOwnership(maybe_owned_list); - list.Append(maybe_owned_list); - - // Should be rewritten, even though it doesn't have an initializer. - std::unique_ptr<base::ListValue> list_with_no_initializer; - list_with_no_initializer.reset(new base::ListValue); - list.Append(std::move(list_with_no_initializer)); - - // Make sure C++98 style initialization is correctly handled. - std::unique_ptr<base::ListValue> cxx98_list(new base::ListValue); - list.Append(std::move(cxx98_list)); - - // C++11 style syntax currently causes the tool to bail out: this is banned in - // Chromium style anyway. - base::ListValue* cxx11_list{new base::ListValue}; - list.Append(cxx11_list); -}
diff --git a/tools/clang/value_cleanup/tests/list-value-append-original.cc b/tools/clang/value_cleanup/tests/list-value-append-original.cc deleted file mode 100644 index adebcf4..0000000 --- a/tools/clang/value_cleanup/tests/list-value-append-original.cc +++ /dev/null
@@ -1,109 +0,0 @@ -// Copyright 2016 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 <memory> - -#include "values.h" - -#define true true - -base::ListValue* ReturnsRawPtr() { - return nullptr; -} - -std::unique_ptr<base::Value> ReturnsUniquePtr() { - return nullptr; -} - -// The joy of raw pointers. -void DoesItTakeOwnership(base::Value*) {} - -struct Thing { - std::unique_ptr<base::Value> ToValue() { return nullptr; } -}; - -void F() { - base::ListValue list; - list.Append(new base::Value(1 == 0)); - list.Append(new base::Value(true)); - list.Append(new base::Value(static_cast<unsigned char>(1.0))); - list.Append(new base::Value(double{3})); - list.Append(new base::Value("abc")); - - list.Append(ReturnsUniquePtr().release()); - Thing thing; - list.Append(thing.ToValue().release()); - std::unique_ptr<base::Value> unique_ptr_var; - list.Append(unique_ptr_var.release()); -} - -void G(base::Value* input) { - base::ListValue list; - - base::ListValue* local = new base::ListValue(); - // Not rewritten, since it often makes more sense to change the function - // prototype. - local->Append(input); - // Should be rewritten: it will only be moved after it's no longer referenced. - list.Append(local); - - // Not rewritten, since it would be used after it's moved. In theory, we could - // automatically handle this too, but the risk of accidentally breaking - // something is much higher. - base::ListValue* clever_list = new base::ListValue; - list.Append(clever_list); - clever_list->AppendInteger(2); - - // Not rewritten, since it often makes more sense to change the function - // prototype. - base::Value* returned_value = ReturnsRawPtr(); - list.Append(returned_value); - - // Should be rewritten. The reassignment should be transformed into - // .reset(). - base::ListValue* reused_list = new base::ListValue; - reused_list->AppendInteger(1); - list.Append(reused_list); - reused_list = new base::ListValue; - reused_list->AppendInteger(3); - list.Append(reused_list); - - // This shouldn't be rewritten, since the reassignment is the return - // value of a function. - base::ListValue* reused_list_2 = new base::ListValue; - reused_list_2->AppendInteger(4); - list.Append(reused_list_2); - reused_list_2 = ReturnsRawPtr(); - reused_list_2->AppendInteger(5); - list.Append(reused_list_2); - - // auto should be expanded to a std::unique_ptr containing the deduced type. - auto* auto_list = new base::ListValue; - auto_list->AppendInteger(6); - list.Append(auto_list); - - auto auto_list_2 = new base::ListValue; - auto_list_2->AppendInteger(7); - list.Append(auto_list_2); - - // Shouldn't be rewritten: a raw pointer is passed to a function which may or - // may not take ownership. - base::ListValue* maybe_owned_list = new base::ListValue; - DoesItTakeOwnership(maybe_owned_list); - list.Append(maybe_owned_list); - - // Should be rewritten, even though it doesn't have an initializer. - base::ListValue* list_with_no_initializer; - list_with_no_initializer = new base::ListValue; - list.Append(list_with_no_initializer); - - // Make sure C++98 style initialization is correctly handled. - base::ListValue* cxx98_list(new base::ListValue); - list.Append(cxx98_list); - - // C++11 style syntax currently causes the tool to bail out: this is banned in - // Chromium style anyway. - base::ListValue* cxx11_list{new base::ListValue}; - list.Append(cxx11_list); -}
diff --git a/tools/clang/value_cleanup/tests/listvalue-expected.cc b/tools/clang/value_cleanup/tests/listvalue-expected.cc new file mode 100644 index 0000000..765713f9 --- /dev/null +++ b/tools/clang/value_cleanup/tests/listvalue-expected.cc
@@ -0,0 +1,31 @@ +// Copyright 2017 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 "values.h" + +// All of these should be renamed to |GetList().emplace_back()|. +void F() { + base::ListValue value; + value.GetList().emplace_back(false); + value.GetList().emplace_back(0); + value.GetList().emplace_back(0.0); + value.GetList().emplace_back(""); +} + +// All of these should be renamed to GetList() + their std::vector equivalent. +void G() { + base::ListValue value; + value.GetList().clear(); + value.GetList().size(); + value.GetList().empty(); + value.GetList().reserve(0); +} + +// None of these should be renamed, as these methods require different handling. +void H() { + base::ListValue value; + value.Append(std::unique_ptr<base::Value>(new base::Value())); + value.AppendStrings({"foo", "bar"}); + value.AppendIfNotPresent(std::unique_ptr<base::Value>(new base::Value())); +}
diff --git a/tools/clang/value_cleanup/tests/listvalue-original.cc b/tools/clang/value_cleanup/tests/listvalue-original.cc new file mode 100644 index 0000000..7cb3138 --- /dev/null +++ b/tools/clang/value_cleanup/tests/listvalue-original.cc
@@ -0,0 +1,31 @@ +// Copyright 2017 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 "values.h" + +// All of these should be renamed to |GetList().emplace_back()|. +void F() { + base::ListValue value; + value.AppendBoolean(false); + value.AppendInteger(0); + value.AppendDouble(0.0); + value.AppendString(""); +} + +// All of these should be renamed to GetList() + their std::vector equivalent. +void G() { + base::ListValue value; + value.Clear(); + value.GetSize(); + value.empty(); + value.Reserve(0); +} + +// None of these should be renamed, as these methods require different handling. +void H() { + base::ListValue value; + value.Append(std::unique_ptr<base::Value>(new base::Value())); + value.AppendStrings({"foo", "bar"}); + value.AppendIfNotPresent(std::unique_ptr<base::Value>(new base::Value())); +}
diff --git a/tools/clang/value_cleanup/tests/values.h b/tools/clang/value_cleanup/tests/values.h index e3c63a0..5548dbde 100644 --- a/tools/clang/value_cleanup/tests/values.h +++ b/tools/clang/value_cleanup/tests/values.h
@@ -5,53 +5,40 @@ #ifndef VALUES_H_ #define VALUES_H_ +#include <memory> +#include <string> #include <vector> -#include "base/strings/string16.h" -#include "base/strings/string_piece.h" - namespace base { -class Value {}; - -// FundamentalValue represents the simple fundamental types of values. -class FundamentalValue : public Value { +class Value { public: - explicit FundamentalValue(bool in_value); - explicit FundamentalValue(int in_value); - explicit FundamentalValue(double in_value); + using ListStorage = std::vector<Value>; + + ListStorage& GetList(); + const ListStorage& GetList() const; + + protected: + ListStorage list_; }; -class StringValue : public Value { - public: - // Initializes a StringValue with a UTF-8 narrow character string. - explicit StringValue(StringPiece in_value); - - // Initializes a StringValue with a string16. - explicit StringValue(const string16& in_value); -}; - -// Stub base::ListValue class that supports Append(Value*). class ListValue : public Value { public: - ListValue(); + void Clear(); + size_t GetSize() const; + bool empty() const; + void Reserve(size_t); - // Appends a Value to the end of the list. + void AppendBoolean(bool); + void AppendInteger(int); + void AppendDouble(double); + void AppendString(std::string); + void Append(std::unique_ptr<Value> in_value); - - // Deprecated version of the above. - void Append(Value* in_value); - - // Convenience forms of Append. - void AppendBoolean(bool in_value); - void AppendInteger(int in_value); - void AppendDouble(double in_value); - void AppendString(StringPiece in_value); - void AppendString(const string16& in_value); void AppendStrings(const std::vector<std::string>& in_values); - void AppendStrings(const std::vector<string16>& in_values); + bool AppendIfNotPresent(std::unique_ptr<Value> in_value); }; } // namespace base -#endif // VALUES_H_ \ No newline at end of file +#endif // VALUES_H_
diff --git a/tools/code_coverage/OWNERS b/tools/code_coverage/OWNERS new file mode 100644 index 0000000..9fd85c05 --- /dev/null +++ b/tools/code_coverage/OWNERS
@@ -0,0 +1,3 @@ +liaoyuke@chromium.org +mmoroz@chromium.org +inferno@chromum.org
diff --git a/tools/code_coverage/coverage.py b/tools/code_coverage/coverage.py new file mode 100755 index 0000000..c6de664 --- /dev/null +++ b/tools/code_coverage/coverage.py
@@ -0,0 +1,1103 @@ +#!/usr/bin/python +# Copyright 2017 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. +"""This script helps to generate code coverage report. + + It uses Clang Source-based Code Coverage - + https://clang.llvm.org/docs/SourceBasedCodeCoverage.html + + In order to generate code coverage report, you need to first add + "use_clang_coverage=true" GN flag to args.gn file in your build + output directory (e.g. out/coverage). + + It is recommended to add "is_component_build=false" flag as well because: + 1. It is incompatible with other sanitizer flags (like "is_asan", "is_msan") + and others like "optimize_for_fuzzing". + 2. If it is not set explicitly, "is_debug" overrides it to true. + + Example usage: + + gn gen out/coverage --args='use_clang_coverage=true is_component_build=false' + gclient runhooks + python tools/code_coverage/coverage.py crypto_unittests url_unittests \\ + -b out/coverage -o out/report -c 'out/coverage/crypto_unittests' \\ + -c 'out/coverage/url_unittests --gtest_filter=URLParser.PathURL' \\ + -f url/ -f crypto/ + + The command above builds crypto_unittests and url_unittests targets and then + runs them with specified command line arguments. For url_unittests, it only + runs the test URLParser.PathURL. The coverage report is filtered to include + only files and sub-directories under url/ and crypto/ directories. + + If you are building a fuzz target, you need to add "use_libfuzzer=true" GN + flag as well. + + Sample workflow for a fuzz target (e.g. pdfium_fuzzer): + + python tools/code_coverage/coverage.py pdfium_fuzzer \\ + -b out/coverage -o out/report \\ + -c 'out/coverage/pdfium_fuzzer -runs=<runs> <corpus_dir>' \\ + -f third_party/pdfium + + where: + <corpus_dir> - directory containing samples files for this format. + <runs> - number of times to fuzz target function. Should be 0 when you just + want to see the coverage on corpus and don't want to fuzz at all. + + For more options, please refer to tools/code_coverage/coverage.py -h. +""" + +from __future__ import print_function + +import sys + +import argparse +import json +import logging +import os +import subprocess +import urllib2 + +sys.path.append( + os.path.join( + os.path.dirname(__file__), os.path.pardir, os.path.pardir, 'tools', + 'clang', 'scripts')) +import update as clang_update + +sys.path.append( + os.path.join( + os.path.dirname(__file__), os.path.pardir, os.path.pardir, + 'third_party')) +import jinja2 +from collections import defaultdict + +# Absolute path to the root of the checkout. +SRC_ROOT_PATH = os.path.abspath( + os.path.join(os.path.dirname(__file__), os.path.pardir, os.path.pardir)) + +# Absolute path to the code coverage tools binary. +LLVM_BUILD_DIR = clang_update.LLVM_BUILD_DIR +LLVM_COV_PATH = os.path.join(LLVM_BUILD_DIR, 'bin', 'llvm-cov') +LLVM_PROFDATA_PATH = os.path.join(LLVM_BUILD_DIR, 'bin', 'llvm-profdata') + +# Build directory, the value is parsed from command line arguments. +BUILD_DIR = None + +# Output directory for generated artifacts, the value is parsed from command +# line arguemnts. +OUTPUT_DIR = None + +# Default number of jobs used to build when goma is configured and enabled. +DEFAULT_GOMA_JOBS = 100 + +# Name of the file extension for profraw data files. +PROFRAW_FILE_EXTENSION = 'profraw' + +# Name of the final profdata file, and this file needs to be passed to +# "llvm-cov" command in order to call "llvm-cov show" to inspect the +# line-by-line coverage of specific files. +PROFDATA_FILE_NAME = 'coverage.profdata' + +# Build arg required for generating code coverage data. +CLANG_COVERAGE_BUILD_ARG = 'use_clang_coverage' + +# The default name of the html coverage report for a directory. +DIRECTORY_COVERAGE_HTML_REPORT_NAME = os.extsep.join(['report', 'html']) + +# Name of the html index files for different views. +DIRECTORY_VIEW_INDEX_FILE = os.extsep.join(['directory_view_index', 'html']) +COMPONENT_VIEW_INDEX_FILE = os.extsep.join(['component_view_index', 'html']) +FILE_VIEW_INDEX_FILE = os.extsep.join(['file_view_index', 'html']) + +# Used to extract a mapping between directories and components. +COMPONENT_MAPPING_URL = 'https://storage.googleapis.com/chromium-owners/component_map.json' + + +class _CoverageSummary(object): + """Encapsulates coverage summary representation.""" + + def __init__(self, + regions_total=0, + regions_covered=0, + functions_total=0, + functions_covered=0, + lines_total=0, + lines_covered=0): + """Initializes _CoverageSummary object.""" + self._summary = { + 'regions': { + 'total': regions_total, + 'covered': regions_covered + }, + 'functions': { + 'total': functions_total, + 'covered': functions_covered + }, + 'lines': { + 'total': lines_total, + 'covered': lines_covered + } + } + + def Get(self): + """Returns summary as a dictionary.""" + return self._summary + + def AddSummary(self, other_summary): + """Adds another summary to this one element-wise.""" + for feature in self._summary: + self._summary[feature]['total'] += other_summary.Get()[feature]['total'] + self._summary[feature]['covered'] += other_summary.Get()[feature][ + 'covered'] + + +class _CoverageReportHtmlGenerator(object): + """Encapsulates coverage html report generation. + + The generated html has a table that contains links to other coverage reports. + """ + + def __init__(self, output_path, table_entry_type): + """Initializes _CoverageReportHtmlGenerator object. + + Args: + output_path: Path to the html report that will be generated. + table_entry_type: Type of the table entries to be displayed in the table + header. For example: 'Path', 'Component'. + """ + css_file_name = os.extsep.join(['style', 'css']) + css_absolute_path = os.path.abspath(os.path.join(OUTPUT_DIR, css_file_name)) + assert os.path.exists(css_absolute_path), ( + 'css file doesn\'t exit. Please make sure "llvm-cov show -format=html" ' + 'is called first, and the css file is generated at: "%s"' % + css_absolute_path) + + self._css_absolute_path = css_absolute_path + self._output_path = output_path + self._table_entry_type = table_entry_type + + self._table_entries = [] + self._total_entry = {} + template_dir = os.path.join( + os.path.dirname(os.path.realpath(__file__)), 'html_templates') + + jinja_env = jinja2.Environment( + loader=jinja2.FileSystemLoader(template_dir), trim_blocks=True) + self._header_template = jinja_env.get_template('header.html') + self._table_template = jinja_env.get_template('table.html') + self._footer_template = jinja_env.get_template('footer.html') + + def AddLinkToAnotherReport(self, html_report_path, name, summary): + """Adds a link to another html report in this report. + + The link to be added is assumed to be an entry in this directory. + """ + # Use relative paths instead of absolute paths to make the generated reports + # portable. + html_report_relative_path = _GetRelativePathToDirectoryOfFile( + html_report_path, self._output_path) + + table_entry = self._CreateTableEntryFromCoverageSummary( + summary, html_report_relative_path, name, + os.path.basename(html_report_path) == + DIRECTORY_COVERAGE_HTML_REPORT_NAME) + self._table_entries.append(table_entry) + + def CreateTotalsEntry(self, summary): + """Creates an entry corresponds to the 'Totals' row in the html report.""" + self._total_entry = self._CreateTableEntryFromCoverageSummary(summary) + + def _CreateTableEntryFromCoverageSummary(self, + summary, + href=None, + name=None, + is_dir=None): + """Creates an entry to display in the html report.""" + assert (href is None and name is None and is_dir is None) or ( + href is not None and name is not None and is_dir is not None), ( + 'The only scenario when href or name or is_dir can be None is when ' + 'creating an entry for the Totals row, and in that case, all three ' + 'attributes must be None.') + + entry = {} + if href is not None: + entry['href'] = href + if name is not None: + entry['name'] = name + if is_dir is not None: + entry['is_dir'] = is_dir + + summary_dict = summary.Get() + for feature in summary_dict: + if summary_dict[feature]['total'] == 0: + percentage = 0.0 + else: + percentage = float(summary_dict[feature]['covered']) / summary_dict[ + feature]['total'] * 100 + + color_class = self._GetColorClass(percentage) + entry[feature] = { + 'total': summary_dict[feature]['total'], + 'covered': summary_dict[feature]['covered'], + 'percentage': '{:6.2f}'.format(percentage), + 'color_class': color_class + } + + return entry + + def _GetColorClass(self, percentage): + """Returns the css color class based on coverage percentage.""" + if percentage >= 0 and percentage < 80: + return 'red' + if percentage >= 80 and percentage < 100: + return 'yellow' + if percentage == 100: + return 'green' + + assert False, 'Invalid coverage percentage: "%d"' % percentage + + def WriteHtmlCoverageReport(self): + """Writes html coverage report. + + In the report, sub-directories are displayed before files and within each + category, entries are sorted alphabetically. + """ + + def EntryCmp(left, right): + """Compare function for table entries.""" + if left['is_dir'] != right['is_dir']: + return -1 if left['is_dir'] == True else 1 + + return -1 if left['name'] < right['name'] else 1 + + self._table_entries = sorted(self._table_entries, cmp=EntryCmp) + + css_path = os.path.join(OUTPUT_DIR, os.extsep.join(['style', 'css'])) + directory_view_path = os.path.join(OUTPUT_DIR, DIRECTORY_VIEW_INDEX_FILE) + component_view_path = os.path.join(OUTPUT_DIR, COMPONENT_VIEW_INDEX_FILE) + file_view_path = os.path.join(OUTPUT_DIR, FILE_VIEW_INDEX_FILE) + + html_header = self._header_template.render( + css_path=_GetRelativePathToDirectoryOfFile(css_path, self._output_path), + directory_view_href=_GetRelativePathToDirectoryOfFile( + directory_view_path, self._output_path), + component_view_href=_GetRelativePathToDirectoryOfFile( + component_view_path, self._output_path), + file_view_href=_GetRelativePathToDirectoryOfFile( + file_view_path, self._output_path)) + + html_table = self._table_template.render( + entries=self._table_entries, + total_entry=self._total_entry, + table_entry_type=self._table_entry_type) + html_footer = self._footer_template.render() + + with open(self._output_path, 'w') as html_file: + html_file.write(html_header + html_table + html_footer) + + +def _GetPlatform(): + """Returns current running platform.""" + if sys.platform == 'win32' or sys.platform == 'cygwin': + return 'win' + if sys.platform.startswith('linux'): + return 'linux' + else: + assert sys.platform == 'darwin' + return 'mac' + + +# TODO(crbug.com/759794): remove this function once tools get included to +# Clang bundle: +# https://chromium-review.googlesource.com/c/chromium/src/+/688221 +def DownloadCoverageToolsIfNeeded(): + """Temporary solution to download llvm-profdata and llvm-cov tools.""" + + def _GetRevisionFromStampFile(stamp_file_path, platform): + """Returns a pair of revision number by reading the build stamp file. + + Args: + stamp_file_path: A path the build stamp file created by + tools/clang/scripts/update.py. + Returns: + A pair of integers represeting the main and sub revision respectively. + """ + if not os.path.exists(stamp_file_path): + return 0, 0 + + with open(stamp_file_path) as stamp_file: + for stamp_file_line in stamp_file.readlines(): + if ',' in stamp_file_line: + package_version, target_os = stamp_file_line.rstrip().split(',') + else: + package_version = stamp_file_line.rstrip() + target_os = '' + + if target_os and platform != target_os: + continue + + clang_revision_str, clang_sub_revision_str = package_version.split('-') + return int(clang_revision_str), int(clang_sub_revision_str) + + assert False, 'Coverage is only supported on target_os - linux, mac.' + + platform = _GetPlatform() + clang_revision, clang_sub_revision = _GetRevisionFromStampFile( + clang_update.STAMP_FILE, platform) + + coverage_revision_stamp_file = os.path.join( + os.path.dirname(clang_update.STAMP_FILE), 'cr_coverage_revision') + coverage_revision, coverage_sub_revision = _GetRevisionFromStampFile( + coverage_revision_stamp_file, platform) + + has_coverage_tools = ( + os.path.exists(LLVM_COV_PATH) and os.path.exists(LLVM_PROFDATA_PATH)) + + if (has_coverage_tools and coverage_revision == clang_revision and + coverage_sub_revision == clang_sub_revision): + # LLVM coverage tools are up to date, bail out. + return clang_revision + + package_version = '%d-%d' % (clang_revision, clang_sub_revision) + coverage_tools_file = 'llvm-code-coverage-%s.tgz' % package_version + + # The code bellow follows the code from tools/clang/scripts/update.py. + if platform == 'mac': + coverage_tools_url = clang_update.CDS_URL + '/Mac/' + coverage_tools_file + else: + assert platform == 'linux' + coverage_tools_url = ( + clang_update.CDS_URL + '/Linux_x64/' + coverage_tools_file) + + try: + clang_update.DownloadAndUnpack(coverage_tools_url, + clang_update.LLVM_BUILD_DIR) + logging.info('Coverage tools %s unpacked', package_version) + with open(coverage_revision_stamp_file, 'w') as file_handle: + file_handle.write('%s,%s' % (package_version, platform)) + file_handle.write('\n') + except urllib2.URLError: + raise Exception( + 'Failed to download coverage tools: %s.' % coverage_tools_url) + + +def _GeneratePerFileLineByLineCoverageInHtml(binary_paths, profdata_file_path, + filters): + """Generates per file line-by-line coverage in html using 'llvm-cov show'. + + For a file with absolute path /a/b/x.cc, a html report is generated as: + OUTPUT_DIR/coverage/a/b/x.cc.html. An index html file is also generated as: + OUTPUT_DIR/index.html. + + Args: + binary_paths: A list of paths to the instrumented binaries. + profdata_file_path: A path to the profdata file. + filters: A list of directories and files to get coverage for. + """ + # llvm-cov show [options] -instr-profile PROFILE BIN [-object BIN,...] + # [[-object BIN]] [SOURCES] + # NOTE: For object files, the first one is specified as a positional argument, + # and the rest are specified as keyword argument. + logging.debug('Generating per file line by line coverage reports using ' + '"llvm-cov show" command') + subprocess_cmd = [ + LLVM_COV_PATH, 'show', '-format=html', + '-output-dir={}'.format(OUTPUT_DIR), + '-instr-profile={}'.format(profdata_file_path), binary_paths[0] + ] + subprocess_cmd.extend( + ['-object=' + binary_path for binary_path in binary_paths[1:]]) + subprocess_cmd.extend(filters) + subprocess.check_call(subprocess_cmd) + logging.debug('Finished running "llvm-cov show" command') + + +def _GenerateFileViewHtmlIndexFile(per_file_coverage_summary): + """Generates html index file for file view.""" + file_view_index_file_path = os.path.join(OUTPUT_DIR, FILE_VIEW_INDEX_FILE) + logging.debug('Generating file view html index file as: "%s".', + file_view_index_file_path) + html_generator = _CoverageReportHtmlGenerator(file_view_index_file_path, + 'Path') + totals_coverage_summary = _CoverageSummary() + + for file_path in per_file_coverage_summary: + totals_coverage_summary.AddSummary(per_file_coverage_summary[file_path]) + + html_generator.AddLinkToAnotherReport( + _GetCoverageHtmlReportPathForFile(file_path), + os.path.relpath(file_path, SRC_ROOT_PATH), + per_file_coverage_summary[file_path]) + + html_generator.CreateTotalsEntry(totals_coverage_summary) + html_generator.WriteHtmlCoverageReport() + logging.debug('Finished generating file view html index file.') + + +def _CalculatePerDirectoryCoverageSummary(per_file_coverage_summary): + """Calculates per directory coverage summary.""" + logging.debug('Calculating per-directory coverage summary') + per_directory_coverage_summary = defaultdict(lambda: _CoverageSummary()) + + for file_path in per_file_coverage_summary: + summary = per_file_coverage_summary[file_path] + parent_dir = os.path.dirname(file_path) + while True: + per_directory_coverage_summary[parent_dir].AddSummary(summary) + + if parent_dir == SRC_ROOT_PATH: + break + parent_dir = os.path.dirname(parent_dir) + + logging.debug('Finished calculating per-directory coverage summary') + return per_directory_coverage_summary + + +def _GeneratePerDirectoryCoverageInHtml(per_directory_coverage_summary, + per_file_coverage_summary): + """Generates per directory coverage breakdown in html.""" + logging.debug('Writing per-directory coverage html reports') + for dir_path in per_directory_coverage_summary: + _GenerateCoverageInHtmlForDirectory( + dir_path, per_directory_coverage_summary, per_file_coverage_summary) + + logging.debug('Finished writing per-directory coverage html reports') + + +def _GenerateCoverageInHtmlForDirectory( + dir_path, per_directory_coverage_summary, per_file_coverage_summary): + """Generates coverage html report for a single directory.""" + html_generator = _CoverageReportHtmlGenerator( + _GetCoverageHtmlReportPathForDirectory(dir_path), 'Path') + + for entry_name in os.listdir(dir_path): + entry_path = os.path.normpath(os.path.join(dir_path, entry_name)) + + if entry_path in per_file_coverage_summary: + entry_html_report_path = _GetCoverageHtmlReportPathForFile(entry_path) + entry_coverage_summary = per_file_coverage_summary[entry_path] + elif entry_path in per_directory_coverage_summary: + entry_html_report_path = _GetCoverageHtmlReportPathForDirectory( + entry_path) + entry_coverage_summary = per_directory_coverage_summary[entry_path] + else: + # Any file without executable lines shouldn't be included into the report. + # For example, OWNER and README.md files. + continue + + html_generator.AddLinkToAnotherReport(entry_html_report_path, + os.path.basename(entry_path), + entry_coverage_summary) + + html_generator.CreateTotalsEntry(per_directory_coverage_summary[dir_path]) + html_generator.WriteHtmlCoverageReport() + + +def _GenerateDirectoryViewHtmlIndexFile(): + """Generates the html index file for directory view. + + Note that the index file is already generated under SRC_ROOT_PATH, so this + file simply redirects to it, and the reason of this extra layer is for + structural consistency with other views. + """ + directory_view_index_file_path = os.path.join(OUTPUT_DIR, + DIRECTORY_VIEW_INDEX_FILE) + logging.debug('Generating directory view html index file as: "%s".', + directory_view_index_file_path) + src_root_html_report_path = _GetCoverageHtmlReportPathForDirectory( + SRC_ROOT_PATH) + _WriteRedirectHtmlFile(directory_view_index_file_path, + src_root_html_report_path) + logging.debug('Finished generating directory view html index file.') + + +def _CalculatePerComponentCoverageSummary(component_to_directories, + per_directory_coverage_summary): + """Calculates per component coverage summary.""" + logging.debug('Calculating per-component coverage summary') + per_component_coverage_summary = defaultdict(lambda: _CoverageSummary()) + + for component in component_to_directories: + for directory in component_to_directories[component]: + absolute_directory_path = os.path.abspath(directory) + if absolute_directory_path in per_directory_coverage_summary: + per_component_coverage_summary[component].AddSummary( + per_directory_coverage_summary[absolute_directory_path]) + + logging.debug('Finished calculating per-component coverage summary') + return per_component_coverage_summary + + +def _ExtractComponentToDirectoriesMapping(): + """Returns a mapping from components to directories.""" + component_mappings = json.load(urllib2.urlopen(COMPONENT_MAPPING_URL)) + directory_to_component = component_mappings['dir-to-component'] + + component_to_directories = defaultdict(list) + for directory in directory_to_component: + component = directory_to_component[directory] + component_to_directories[component].append(directory) + + return component_to_directories + + +def _GeneratePerComponentCoverageInHtml(per_component_coverage_summary, + component_to_directories, + per_directory_coverage_summary): + """Generates per-component coverage reports in html.""" + logging.debug('Writing per-component coverage html reports.') + for component in per_component_coverage_summary: + _GenerateCoverageInHtmlForComponent( + component, per_component_coverage_summary, component_to_directories, + per_directory_coverage_summary) + + logging.debug('Finished writing per-component coverage html reports.') + + +def _GenerateCoverageInHtmlForComponent( + component_name, per_component_coverage_summary, component_to_directories, + per_directory_coverage_summary): + """Generates coverage html report for a component.""" + component_html_report_path = _GetCoverageHtmlReportPathForComponent( + component_name) + component_html_report_dir = os.path.dirname(component_html_report_path) + if not os.path.exists(component_html_report_dir): + os.makedirs(component_html_report_dir) + + html_generator = _CoverageReportHtmlGenerator(component_html_report_path, + 'Path') + + for dir_path in component_to_directories[component_name]: + dir_absolute_path = os.path.abspath(dir_path) + if dir_absolute_path not in per_directory_coverage_summary: + # Any directory without an excercised file shouldn't be included into the + # report. + continue + + html_generator.AddLinkToAnotherReport( + _GetCoverageHtmlReportPathForDirectory(dir_path), + os.path.relpath(dir_path, SRC_ROOT_PATH), + per_directory_coverage_summary[dir_absolute_path]) + + html_generator.CreateTotalsEntry( + per_component_coverage_summary[component_name]) + html_generator.WriteHtmlCoverageReport() + + +def _GenerateComponentViewHtmlIndexFile(per_component_coverage_summary): + """Generates the html index file for component view.""" + component_view_index_file_path = os.path.join(OUTPUT_DIR, + COMPONENT_VIEW_INDEX_FILE) + logging.debug('Generating component view html index file as: "%s".', + component_view_index_file_path) + html_generator = _CoverageReportHtmlGenerator(component_view_index_file_path, + 'Component') + totals_coverage_summary = _CoverageSummary() + + for component in per_component_coverage_summary: + totals_coverage_summary.AddSummary( + per_component_coverage_summary[component]) + + html_generator.AddLinkToAnotherReport( + _GetCoverageHtmlReportPathForComponent(component), component, + per_component_coverage_summary[component]) + + html_generator.CreateTotalsEntry(totals_coverage_summary) + html_generator.WriteHtmlCoverageReport() + logging.debug('Finished generating component view html index file.') + + +def _OverwriteHtmlReportsIndexFile(): + """Overwrites the root index file to redirect to the default view.""" + html_index_file_path = os.path.join(OUTPUT_DIR, + os.extsep.join(['index', 'html'])) + directory_view_index_file_path = os.path.join(OUTPUT_DIR, + DIRECTORY_VIEW_INDEX_FILE) + _WriteRedirectHtmlFile(html_index_file_path, directory_view_index_file_path) + + +def _WriteRedirectHtmlFile(from_html_path, to_html_path): + """Writes a html file that redirects to another html file.""" + to_html_relative_path = _GetRelativePathToDirectoryOfFile( + to_html_path, from_html_path) + content = (""" + <!DOCTYPE html> + <html> + <head> + <!-- HTML meta refresh URL redirection --> + <meta http-equiv="refresh" content="0; url=%s"> + </head> + </html>""" % to_html_relative_path) + with open(from_html_path, 'w') as f: + f.write(content) + + +def _GetCoverageHtmlReportPathForFile(file_path): + """Given a file path, returns the corresponding html report path.""" + assert os.path.isfile(file_path), '"%s" is not a file' % file_path + html_report_path = os.extsep.join([os.path.abspath(file_path), 'html']) + + # '+' is used instead of os.path.join because both of them are absolute paths + # and os.path.join ignores the first path. + # TODO(crbug.com/809150): Think of a generic cross platform fix (Windows). + return _GetCoverageReportRootDirPath() + html_report_path + + +def _GetCoverageHtmlReportPathForDirectory(dir_path): + """Given a directory path, returns the corresponding html report path.""" + assert os.path.isdir(dir_path), '"%s" is not a directory' % dir_path + html_report_path = os.path.join( + os.path.abspath(dir_path), DIRECTORY_COVERAGE_HTML_REPORT_NAME) + + # '+' is used instead of os.path.join because both of them are absolute paths + # and os.path.join ignores the first path. + # TODO(crbug.com/809150): Think of a generic cross platform fix (Windows). + return _GetCoverageReportRootDirPath() + html_report_path + + +def _GetCoverageHtmlReportPathForComponent(component_name): + """Given a component, returns the corresponding html report path.""" + component_file_name = component_name.lower().replace('>', '-') + html_report_name = os.extsep.join([component_file_name, 'html']) + return os.path.join(_GetCoverageReportRootDirPath(), 'components', + html_report_name) + + +def _GetCoverageReportRootDirPath(): + """The root directory that contains all generated coverage html reports.""" + return os.path.join(os.path.abspath(OUTPUT_DIR), 'coverage') + + +def _CreateCoverageProfileDataForTargets(targets, commands, jobs_count=None): + """Builds and runs target to generate the coverage profile data. + + Args: + targets: A list of targets to build with coverage instrumentation. + commands: A list of commands used to run the targets. + jobs_count: Number of jobs to run in parallel for building. If None, a + default value is derived based on CPUs availability. + + Returns: + A relative path to the generated profdata file. + """ + _BuildTargets(targets, jobs_count) + profraw_file_paths = _GetProfileRawDataPathsByExecutingCommands( + targets, commands) + profdata_file_path = _CreateCoverageProfileDataFromProfRawData( + profraw_file_paths) + + for profraw_file_path in profraw_file_paths: + os.remove(profraw_file_path) + + return profdata_file_path + + +def _BuildTargets(targets, jobs_count): + """Builds target with Clang coverage instrumentation. + + This function requires current working directory to be the root of checkout. + + Args: + targets: A list of targets to build with coverage instrumentation. + jobs_count: Number of jobs to run in parallel for compilation. If None, a + default value is derived based on CPUs availability. + """ + + def _IsGomaConfigured(): + """Returns True if goma is enabled in the gn build args. + + Returns: + A boolean indicates whether goma is configured for building or not. + """ + build_args = _ParseArgsGnFile() + return 'use_goma' in build_args and build_args['use_goma'] == 'true' + + logging.info('Building %s', str(targets)) + if jobs_count is None and _IsGomaConfigured(): + jobs_count = DEFAULT_GOMA_JOBS + + subprocess_cmd = ['ninja', '-C', BUILD_DIR] + if jobs_count is not None: + subprocess_cmd.append('-j' + str(jobs_count)) + + subprocess_cmd.extend(targets) + subprocess.check_call(subprocess_cmd) + logging.debug('Finished building %s', str(targets)) + + +def _GetProfileRawDataPathsByExecutingCommands(targets, commands): + """Runs commands and returns the relative paths to the profraw data files. + + Args: + targets: A list of targets built with coverage instrumentation. + commands: A list of commands used to run the targets. + + Returns: + A list of relative paths to the generated profraw data files. + """ + logging.debug('Executing the test commands') + + # Remove existing profraw data files. + for file_or_dir in os.listdir(OUTPUT_DIR): + if file_or_dir.endswith(PROFRAW_FILE_EXTENSION): + os.remove(os.path.join(OUTPUT_DIR, file_or_dir)) + + # Run all test targets to generate profraw data files. + for target, command in zip(targets, commands): + _ExecuteCommand(target, command) + + logging.debug('Finished executing the test commands') + + profraw_file_paths = [] + for file_or_dir in os.listdir(OUTPUT_DIR): + if file_or_dir.endswith(PROFRAW_FILE_EXTENSION): + profraw_file_paths.append(os.path.join(OUTPUT_DIR, file_or_dir)) + + # Assert one target/command generates at least one profraw data file. + for target in targets: + assert any( + os.path.basename(profraw_file).startswith(target) + for profraw_file in profraw_file_paths), ( + 'Running target: %s failed to generate any profraw data file, ' + 'please make sure the binary exists and is properly instrumented.' % + target) + + return profraw_file_paths + + +def _ExecuteCommand(target, command): + """Runs a single command and generates a profraw data file. + + Args: + target: A target built with coverage instrumentation. + command: A command used to run the target. + """ + # Per Clang "Source-based Code Coverage" doc: + # "%Nm" expands out to the instrumented binary's signature. When this pattern + # is specified, the runtime creates a pool of N raw profiles which are used + # for on-line profile merging. The runtime takes care of selecting a raw + # profile from the pool, locking it, and updating it before the program exits. + # If N is not specified (i.e the pattern is "%m"), it's assumed that N = 1. + # N must be between 1 and 9. The merge pool specifier can only occur once per + # filename pattern. + # + # 4 is chosen because it creates some level of parallelism, but it's not too + # big to consume too much computing resource or disk space. + expected_profraw_file_name = os.extsep.join( + [target, '%4m', PROFRAW_FILE_EXTENSION]) + expected_profraw_file_path = os.path.join(OUTPUT_DIR, + expected_profraw_file_name) + output_file_name = os.extsep.join([target + '_output', 'txt']) + output_file_path = os.path.join(OUTPUT_DIR, output_file_name) + + logging.info('Running command: "%s", the output is redirected to "%s"', + command, output_file_path) + output = subprocess.check_output( + command.split(), env={'LLVM_PROFILE_FILE': expected_profraw_file_path}) + with open(output_file_path, 'w') as output_file: + output_file.write(output) + + +def _CreateCoverageProfileDataFromProfRawData(profraw_file_paths): + """Returns a relative path to the profdata file by merging profraw data files. + + Args: + profraw_file_paths: A list of relative paths to the profraw data files that + are to be merged. + + Returns: + A relative path to the generated profdata file. + + Raises: + CalledProcessError: An error occurred merging profraw data files. + """ + logging.info('Creating the coverage profile data file') + logging.debug('Merging profraw files to create profdata file') + profdata_file_path = os.path.join(OUTPUT_DIR, PROFDATA_FILE_NAME) + try: + subprocess_cmd = [ + LLVM_PROFDATA_PATH, 'merge', '-o', profdata_file_path, '-sparse=true' + ] + subprocess_cmd.extend(profraw_file_paths) + subprocess.check_call(subprocess_cmd) + except subprocess.CalledProcessError as error: + print('Failed to merge profraw files to create profdata file') + raise error + + logging.debug('Finished merging profraw files') + logging.info('Code coverage profile data is created as: %s', + profdata_file_path) + return profdata_file_path + + +def _GeneratePerFileCoverageSummary(binary_paths, profdata_file_path, filters): + """Generates per file coverage summary using "llvm-cov export" command.""" + # llvm-cov export [options] -instr-profile PROFILE BIN [-object BIN,...] + # [[-object BIN]] [SOURCES]. + # NOTE: For object files, the first one is specified as a positional argument, + # and the rest are specified as keyword argument. + logging.debug('Generating per-file code coverage summary using "llvm-cov ' + 'export -summary-only" command') + subprocess_cmd = [ + LLVM_COV_PATH, 'export', '-summary-only', + '-instr-profile=' + profdata_file_path, binary_paths[0] + ] + subprocess_cmd.extend( + ['-object=' + binary_path for binary_path in binary_paths[1:]]) + subprocess_cmd.extend(filters) + + json_output = json.loads(subprocess.check_output(subprocess_cmd)) + assert len(json_output['data']) == 1 + files_coverage_data = json_output['data'][0]['files'] + + per_file_coverage_summary = {} + for file_coverage_data in files_coverage_data: + file_path = file_coverage_data['filename'] + summary = file_coverage_data['summary'] + + if summary['lines']['count'] == 0: + continue + + per_file_coverage_summary[file_path] = _CoverageSummary( + regions_total=summary['regions']['count'], + regions_covered=summary['regions']['covered'], + functions_total=summary['functions']['count'], + functions_covered=summary['functions']['covered'], + lines_total=summary['lines']['count'], + lines_covered=summary['lines']['covered']) + + logging.debug('Finished generating per-file code coverage summary') + return per_file_coverage_summary + + +def _GetBinaryPath(command): + """Returns a relative path to the binary to be run by the command. + + Args: + command: A command used to run a target. + + Returns: + A relative path to the binary. + """ + return command.split()[0] + + +def _VerifyTargetExecutablesAreInBuildDirectory(commands): + """Verifies that the target executables specified in the commands are inside + the given build directory.""" + for command in commands: + binary_path = _GetBinaryPath(command) + binary_absolute_path = os.path.abspath(os.path.normpath(binary_path)) + assert binary_absolute_path.startswith(os.path.abspath(BUILD_DIR)), ( + 'Target executable "%s" in command: "%s" is outside of ' + 'the given build directory: "%s".' % (binary_path, command, BUILD_DIR)) + + +def _ValidateBuildingWithClangCoverage(): + """Asserts that targets are built with Clang coverage enabled.""" + build_args = _ParseArgsGnFile() + + if (CLANG_COVERAGE_BUILD_ARG not in build_args or + build_args[CLANG_COVERAGE_BUILD_ARG] != 'true'): + assert False, ('\'{} = true\' is required in args.gn.' + ).format(CLANG_COVERAGE_BUILD_ARG) + + +def _ParseArgsGnFile(): + """Parses args.gn file and returns results as a dictionary. + + Returns: + A dictionary representing the build args. + """ + build_args_path = os.path.join(BUILD_DIR, 'args.gn') + assert os.path.exists(build_args_path), ('"%s" is not a build directory, ' + 'missing args.gn file.' % BUILD_DIR) + with open(build_args_path) as build_args_file: + build_args_lines = build_args_file.readlines() + + build_args = {} + for build_arg_line in build_args_lines: + build_arg_without_comments = build_arg_line.split('#')[0] + key_value_pair = build_arg_without_comments.split('=') + if len(key_value_pair) != 2: + continue + + key = key_value_pair[0].strip() + value = key_value_pair[1].strip() + build_args[key] = value + + return build_args + + +def _VerifyPathsAndReturnAbsolutes(paths): + """Verifies that the paths specified in |paths| exist and returns absolute + versions. + + Args: + paths: A list of files or directories. + """ + absolute_paths = [] + for path in paths: + absolute_path = os.path.join(SRC_ROOT_PATH, path) + assert os.path.exists(absolute_path), ('Path: "%s" doesn\'t exist.' % path) + + absolute_paths.append(absolute_path) + + return absolute_paths + + +def _GetRelativePathToDirectoryOfFile(target_path, base_path): + """Returns a target path relative to the directory of base_path. + + This method requires base_path to be a file, otherwise, one should call + os.path.relpath directly. + """ + assert os.path.dirname(base_path) != base_path, ( + 'Base path: "%s" is a directory, please call os.path.relpath directly.' % + base_path) + base_dir = os.path.dirname(base_path) + return os.path.relpath(target_path, base_dir) + + +def _ParseCommandArguments(): + """Adds and parses relevant arguments for tool comands. + + Returns: + A dictionary representing the arguments. + """ + arg_parser = argparse.ArgumentParser() + arg_parser.usage = __doc__ + + arg_parser.add_argument( + '-b', + '--build-dir', + type=str, + required=True, + help='The build directory, the path needs to be relative to the root of ' + 'the checkout.') + + arg_parser.add_argument( + '-o', + '--output-dir', + type=str, + required=True, + help='Output directory for generated artifacts.') + + arg_parser.add_argument( + '-c', + '--command', + action='append', + required=True, + help='Commands used to run test targets, one test target needs one and ' + 'only one command, when specifying commands, one should assume the ' + 'current working directory is the root of the checkout.') + + arg_parser.add_argument( + '-f', + '--filters', + action='append', + required=False, + help='Directories or files to get code coverage for, and all files under ' + 'the directories are included recursively.') + + arg_parser.add_argument( + '-j', + '--jobs', + type=int, + default=None, + help='Run N jobs to build in parallel. If not specified, a default value ' + 'will be derived based on CPUs availability. Please refer to ' + '\'ninja -h\' for more details.') + + arg_parser.add_argument( + '-v', + '--verbose', + action='store_true', + help='Prints additional output for diagnostics.') + + arg_parser.add_argument( + '-l', '--log_file', type=str, help='Redirects logs to a file.') + + arg_parser.add_argument( + 'targets', nargs='+', help='The names of the test targets to run.') + + args = arg_parser.parse_args() + return args + + +def Main(): + """Execute tool commands.""" + assert _GetPlatform() in [ + 'linux', 'mac' + ], ('Coverage is only supported on linux and mac platforms.') + assert os.path.abspath(os.getcwd()) == SRC_ROOT_PATH, ('This script must be ' + 'called from the root ' + 'of checkout.') + DownloadCoverageToolsIfNeeded() + + args = _ParseCommandArguments() + global BUILD_DIR + BUILD_DIR = args.build_dir + global OUTPUT_DIR + OUTPUT_DIR = args.output_dir + + log_level = logging.DEBUG if args.verbose else logging.INFO + log_format = '[%(asctime)s] %(message)s' + log_file = args.log_file if args.log_file else None + logging.basicConfig(filename=log_file, level=log_level, format=log_format) + + assert len(args.targets) == len(args.command), ('Number of targets must be ' + 'equal to the number of test ' + 'commands.') + assert os.path.exists(BUILD_DIR), ( + 'Build directory: {} doesn\'t exist. ' + 'Please run "gn gen" to generate.').format(BUILD_DIR) + _ValidateBuildingWithClangCoverage() + _VerifyTargetExecutablesAreInBuildDirectory(args.command) + + absolute_filter_paths = [] + if args.filters: + absolute_filter_paths = _VerifyPathsAndReturnAbsolutes(args.filters) + + if not os.path.exists(OUTPUT_DIR): + os.makedirs(OUTPUT_DIR) + + profdata_file_path = _CreateCoverageProfileDataForTargets( + args.targets, args.command, args.jobs) + binary_paths = [_GetBinaryPath(command) for command in args.command] + + logging.info('Generating code coverage report in html (this can take a while ' + 'depending on size of target!)') + per_file_coverage_summary = _GeneratePerFileCoverageSummary( + binary_paths, profdata_file_path, absolute_filter_paths) + _GeneratePerFileLineByLineCoverageInHtml(binary_paths, profdata_file_path, + absolute_filter_paths) + _GenerateFileViewHtmlIndexFile(per_file_coverage_summary) + + per_directory_coverage_summary = _CalculatePerDirectoryCoverageSummary( + per_file_coverage_summary) + _GeneratePerDirectoryCoverageInHtml(per_directory_coverage_summary, + per_file_coverage_summary) + _GenerateDirectoryViewHtmlIndexFile() + + component_to_directories = _ExtractComponentToDirectoriesMapping() + per_component_coverage_summary = _CalculatePerComponentCoverageSummary( + component_to_directories, per_directory_coverage_summary) + _GeneratePerComponentCoverageInHtml(per_component_coverage_summary, + component_to_directories, + per_directory_coverage_summary) + _GenerateComponentViewHtmlIndexFile(per_component_coverage_summary) + + # The default index file is generated only for the list of source files, needs + # to overwrite it to display per directory coverage view by default. + _OverwriteHtmlReportsIndexFile() + + html_index_file_path = 'file://' + os.path.abspath( + os.path.join(OUTPUT_DIR, 'index.html')) + logging.info('Index file for html report is generated as: %s', + html_index_file_path) + + +if __name__ == '__main__': + sys.exit(Main())
diff --git a/tools/code_coverage/croc.css b/tools/code_coverage/croc.css deleted file mode 100644 index 071822d..0000000 --- a/tools/code_coverage/croc.css +++ /dev/null
@@ -1,102 +0,0 @@ -/* - * 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. - */ - -/* - * croc.css - styles for croc HTML output - */ - -body { - font-family:arial; -} - -table { - border-collapse:collapse; - border-width:0px; - border-style:solid; -} - -thead { - background-color:#C0C0E0; - text-align:center; -} - -td { - padding-right:10px; - padding-left:10px; - font-size:small; - border-width:1px; - border-style:solid; - border-color:black; -} - -td.secdesc { - text-align:center; - font-size:medium; - font-weight:bold; - border-width:0px; - border-style:none; - padding-top:10px; - padding-bottom:5px; -} - -td.section { - background-color:#D0D0F0; - text-align:center; -} - -td.stat { - text-align:center; -} - -td.number { - text-align:right; -} - -td.graph { - /* Hide the dummy character */ - color:#FFFFFF; - padding-left:6px; -} - -td.high_pct { - text-align:right; - background-color:#B0FFB0; -} -td.mid_pct { - text-align:right; - background-color:#FFFF90; -} -td.low_pct { - text-align:right; - background-color:#FFB0B0; -} - - -span.missing { - background-color:#FFB0B0; -} -span.instr { - background-color:#FFFF90; -} -span.covered { - background-color:#B0FFB0; -} - -span.g_missing { - background-color:#FF4040; -} -span.g_instr { - background-color:#FFFF00; -} -span.g_covered { - background-color:#40FF40; -} - -p.time { - padding-top:10px; - font-size:small; - font-style:italic; -}
diff --git a/tools/code_coverage/croc.py b/tools/code_coverage/croc.py deleted file mode 100755 index 1b9908a5..0000000 --- a/tools/code_coverage/croc.py +++ /dev/null
@@ -1,722 +0,0 @@ -#!/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. - -"""Crocodile - compute coverage numbers for Chrome coverage dashboard.""" - -import optparse -import os -import platform -import re -import sys -import croc_html -import croc_scan - - -class CrocError(Exception): - """Coverage error.""" - - -class CrocStatError(CrocError): - """Error evaluating coverage stat.""" - -#------------------------------------------------------------------------------ - - -class CoverageStats(dict): - """Coverage statistics.""" - - # Default dictionary values for this stat. - DEFAULTS = { 'files_covered': 0, - 'files_instrumented': 0, - 'files_executable': 0, - 'lines_covered': 0, - 'lines_instrumented': 0, - 'lines_executable': 0 } - - def Add(self, coverage_stats): - """Adds a contribution from another coverage stats dict. - - Args: - coverage_stats: Statistics to add to this one. - """ - for k, v in coverage_stats.iteritems(): - if k in self: - self[k] += v - else: - self[k] = v - - def AddDefaults(self): - """Add some default stats which might be assumed present. - - Do not clobber if already present. Adds resilience when evaling a - croc file which expects certain stats to exist.""" - for k, v in self.DEFAULTS.iteritems(): - if not k in self: - self[k] = v - -#------------------------------------------------------------------------------ - - -class CoveredFile(object): - """Information about a single covered file.""" - - def __init__(self, filename, **kwargs): - """Constructor. - - Args: - filename: Full path to file, '/'-delimited. - kwargs: Keyword args are attributes for file. - """ - self.filename = filename - self.attrs = dict(kwargs) - - # Move these to attrs? - self.local_path = None # Local path to file - self.in_lcov = False # Is file instrumented? - - # No coverage data for file yet - self.lines = {} # line_no -> None=executable, 0=instrumented, 1=covered - self.stats = CoverageStats() - - def UpdateCoverage(self): - """Updates the coverage summary based on covered lines.""" - exe = instr = cov = 0 - for l in self.lines.itervalues(): - exe += 1 - if l is not None: - instr += 1 - if l == 1: - cov += 1 - - # Add stats that always exist - self.stats = CoverageStats(lines_executable=exe, - lines_instrumented=instr, - lines_covered=cov, - files_executable=1) - - # Add conditional stats - if cov: - self.stats['files_covered'] = 1 - if instr or self.in_lcov: - self.stats['files_instrumented'] = 1 - -#------------------------------------------------------------------------------ - - -class CoveredDir(object): - """Information about a directory containing covered files.""" - - def __init__(self, dirpath): - """Constructor. - - Args: - dirpath: Full path of directory, '/'-delimited. - """ - self.dirpath = dirpath - - # List of covered files directly in this dir, indexed by filename (not - # full path) - self.files = {} - - # List of subdirs, indexed by filename (not full path) - self.subdirs = {} - - # Dict of CoverageStats objects summarizing all children, indexed by group - self.stats_by_group = {'all': CoverageStats()} - # TODO: by language - - def GetTree(self, indent=''): - """Recursively gets stats for the directory and its children. - - Args: - indent: indent prefix string. - - Returns: - The tree as a string. - """ - dest = [] - - # Compile all groupstats - groupstats = [] - for group in sorted(self.stats_by_group): - s = self.stats_by_group[group] - if not s.get('lines_executable'): - continue # Skip groups with no executable lines - groupstats.append('%s:%d/%d/%d' % ( - group, s.get('lines_covered', 0), - s.get('lines_instrumented', 0), - s.get('lines_executable', 0))) - - outline = '%s%-30s %s' % (indent, - os.path.split(self.dirpath)[1] + '/', - ' '.join(groupstats)) - dest.append(outline.rstrip()) - - for d in sorted(self.subdirs): - dest.append(self.subdirs[d].GetTree(indent=indent + ' ')) - - return '\n'.join(dest) - -#------------------------------------------------------------------------------ - - -class Coverage(object): - """Code coverage for a group of files.""" - - def __init__(self): - """Constructor.""" - self.files = {} # Map filename --> CoverageFile - self.root_dirs = [] # (root, altname) - self.rules = [] # (regexp, dict of RHS attrs) - self.tree = CoveredDir('') - self.print_stats = [] # Dicts of args to PrintStat() - - # Functions which need to be replaced for unit testing - self.add_files_walk = os.walk # Walk function for AddFiles() - self.scan_file = croc_scan.ScanFile # Source scanner for AddFiles() - - def CleanupFilename(self, filename): - """Cleans up a filename. - - Args: - filename: Input filename. - - Returns: - The cleaned up filename. - - Changes all path separators to '/'. - Makes relative paths (those starting with '../' or './' absolute. - Replaces all instances of root dirs with alternate names. - """ - # Change path separators - filename = filename.replace('\\', '/') - - # Windows doesn't care about case sensitivity. - if platform.system() in ['Windows', 'Microsoft']: - filename = filename.lower() - - # If path is relative, make it absolute - # TODO: Perhaps we should default to relative instead, and only understand - # absolute to be files starting with '\', '/', or '[A-Za-z]:'? - if filename.split('/')[0] in ('.', '..'): - filename = os.path.abspath(filename).replace('\\', '/') - - # Replace alternate roots - for root, alt_name in self.root_dirs: - # Windows doesn't care about case sensitivity. - if platform.system() in ['Windows', 'Microsoft']: - root = root.lower() - filename = re.sub('^' + re.escape(root) + '(?=(/|$))', - alt_name, filename) - return filename - - def ClassifyFile(self, filename): - """Applies rules to a filename, to see if we care about it. - - Args: - filename: Input filename. - - Returns: - A dict of attributes for the file, accumulated from the right hand sides - of rules which fired. - """ - attrs = {} - - # Process all rules - for regexp, rhs_dict in self.rules: - if regexp.match(filename): - attrs.update(rhs_dict) - - return attrs - # TODO: Files can belong to multiple groups? - # (test/source) - # (mac/pc/win) - # (media_test/all_tests) - # (small/med/large) - # How to handle that? - - def AddRoot(self, root_path, alt_name='_'): - """Adds a root directory. - - Args: - root_path: Root directory to add. - alt_name: If specified, name of root dir. Otherwise, defaults to '_'. - - Raises: - ValueError: alt_name was blank. - """ - # Alt name must not be blank. If it were, there wouldn't be a way to - # reverse-resolve from a root-replaced path back to the local path, since - # '' would always match the beginning of the candidate filename, resulting - # in an infinite loop. - if not alt_name: - raise ValueError('AddRoot alt_name must not be blank.') - - # Clean up root path based on existing rules - self.root_dirs.append([self.CleanupFilename(root_path), alt_name]) - - def AddRule(self, path_regexp, **kwargs): - """Adds a rule. - - Args: - path_regexp: Regular expression to match for filenames. These are - matched after root directory replacement. - kwargs: Keyword arguments are attributes to set if the rule applies. - - Keyword arguments currently supported: - include: If True, includes matches; if False, excludes matches. Ignored - if None. - group: If not None, sets group to apply to matches. - language: If not None, sets file language to apply to matches. - """ - - # Compile regexp ahead of time - self.rules.append([re.compile(path_regexp), dict(kwargs)]) - - def GetCoveredFile(self, filename, add=False): - """Gets the CoveredFile object for the filename. - - Args: - filename: Name of file to find. - add: If True, will add the file if it's not present. This applies the - transformations from AddRoot() and AddRule(), and only adds the file - if a rule includes it, and it has a group and language. - - Returns: - The matching CoveredFile object, or None if not present. - """ - # Clean filename - filename = self.CleanupFilename(filename) - - # Check for existing match - if filename in self.files: - return self.files[filename] - - # File isn't one we know about. If we can't add it, give up. - if not add: - return None - - # Check rules to see if file can be added. Files must be included and - # have a group and language. - attrs = self.ClassifyFile(filename) - if not (attrs.get('include') - and attrs.get('group') - and attrs.get('language')): - return None - - # Add the file - f = CoveredFile(filename, **attrs) - self.files[filename] = f - - # Return the newly covered file - return f - - def RemoveCoveredFile(self, cov_file): - """Removes the file from the covered file list. - - Args: - cov_file: A file object returned by GetCoveredFile(). - """ - self.files.pop(cov_file.filename) - - def ParseLcovData(self, lcov_data): - """Adds coverage from LCOV-formatted data. - - Args: - lcov_data: An iterable returning lines of data in LCOV format. For - example, a file or list of strings. - """ - cov_file = None - cov_lines = None - for line in lcov_data: - line = line.strip() - if line.startswith('SF:'): - # Start of data for a new file; payload is filename - cov_file = self.GetCoveredFile(line[3:], add=True) - if cov_file: - cov_lines = cov_file.lines - cov_file.in_lcov = True # File was instrumented - elif not cov_file: - # Inside data for a file we don't care about - so skip it - pass - elif line.startswith('DA:'): - # Data point - that is, an executable line in current file - line_no, is_covered = map(int, line[3:].split(',')) - if is_covered: - # Line is covered - cov_lines[line_no] = 1 - elif cov_lines.get(line_no) != 1: - # Line is not covered, so track it as uncovered - cov_lines[line_no] = 0 - elif line == 'end_of_record': - cov_file.UpdateCoverage() - cov_file = None - # (else ignore other line types) - - def ParseLcovFile(self, input_filename): - """Adds coverage data from a .lcov file. - - Args: - input_filename: Input filename. - """ - # TODO: All manner of error checking - lcov_file = None - try: - lcov_file = open(input_filename, 'rt') - self.ParseLcovData(lcov_file) - finally: - if lcov_file: - lcov_file.close() - - def GetStat(self, stat, group='all', default=None): - """Gets a statistic from the coverage object. - - Args: - stat: Statistic to get. May also be an evaluatable python expression, - using the stats. For example, 'stat1 - stat2'. - group: File group to match; if 'all', matches all groups. - default: Value to return if there was an error evaluating the stat. For - example, if the stat does not exist. If None, raises - CrocStatError. - - Returns: - The evaluated stat, or None if error. - - Raises: - CrocStatError: Error evaluating stat. - """ - # TODO: specify a subdir to get the stat from, then walk the tree to - # print the stats from just that subdir - - # Make sure the group exists - if group not in self.tree.stats_by_group: - if default is None: - raise CrocStatError('Group %r not found.' % group) - else: - return default - - stats = self.tree.stats_by_group[group] - # Unit tests use real dicts, not CoverageStats objects, - # so we can't AddDefaults() on them. - if group == 'all' and hasattr(stats, 'AddDefaults'): - stats.AddDefaults() - try: - return eval(stat, {'__builtins__': {'S': self.GetStat}}, stats) - except Exception, e: - if default is None: - raise CrocStatError('Error evaluating stat %r: %s' % (stat, e)) - else: - return default - - def PrintStat(self, stat, format=None, outfile=sys.stdout, **kwargs): - """Prints a statistic from the coverage object. - - Args: - stat: Statistic to get. May also be an evaluatable python expression, - using the stats. For example, 'stat1 - stat2'. - format: Format string to use when printing stat. If None, prints the - stat and its evaluation. - outfile: File stream to output stat to; defaults to stdout. - kwargs: Additional args to pass to GetStat(). - """ - s = self.GetStat(stat, **kwargs) - if format is None: - outfile.write('GetStat(%r) = %s\n' % (stat, s)) - else: - outfile.write(format % s + '\n') - - def AddFiles(self, src_dir): - """Adds files to coverage information. - - LCOV files only contains files which are compiled and instrumented as part - of running coverage. This function finds missing files and adds them. - - Args: - src_dir: Directory on disk at which to start search. May be a relative - path on disk starting with '.' or '..', or an absolute path, or a - path relative to an alt_name for one of the roots - (for example, '_/src'). If the alt_name matches more than one root, - all matches will be attempted. - - Note that dirs not underneath one of the root dirs and covered by an - inclusion rule will be ignored. - """ - # Check for root dir alt_names in the path and replace with the actual - # root dirs, then recurse. - found_root = False - for root, alt_name in self.root_dirs: - replaced_root = re.sub('^' + re.escape(alt_name) + '(?=(/|$))', root, - src_dir) - if replaced_root != src_dir: - found_root = True - self.AddFiles(replaced_root) - if found_root: - return # Replaced an alt_name with a root_dir, so already recursed. - - for (dirpath, dirnames, filenames) in self.add_files_walk(src_dir): - # Make a copy of the dirnames list so we can modify the original to - # prune subdirs we don't need to walk. - for d in list(dirnames): - # Add trailing '/' to directory names so dir-based regexps can match - # '/' instead of needing to specify '(/|$)'. - dpath = self.CleanupFilename(dirpath + '/' + d) + '/' - attrs = self.ClassifyFile(dpath) - if not attrs.get('include'): - # Directory has been excluded, so don't traverse it - # TODO: Document the slight weirdness caused by this: If you - # AddFiles('./A'), and the rules include 'A/B/C/D' but not 'A/B', - # then it won't recurse into './A/B' so won't find './A/B/C/D'. - # Workarounds are to AddFiles('./A/B/C/D') or AddFiles('./A/B/C'). - # The latter works because it explicitly walks the contents of the - # path passed to AddFiles(), so it finds './A/B/C/D'. - dirnames.remove(d) - - for f in filenames: - local_path = dirpath + '/' + f - - covf = self.GetCoveredFile(local_path, add=True) - if not covf: - continue - - # Save where we found the file, for generating line-by-line HTML output - covf.local_path = local_path - - if covf.in_lcov: - # File already instrumented and doesn't need to be scanned - continue - - if not covf.attrs.get('add_if_missing', 1): - # Not allowed to add the file - self.RemoveCoveredFile(covf) - continue - - # Scan file to find potentially-executable lines - lines = self.scan_file(covf.local_path, covf.attrs.get('language')) - if lines: - for l in lines: - covf.lines[l] = None - covf.UpdateCoverage() - else: - # File has no executable lines, so don't count it - self.RemoveCoveredFile(covf) - - def AddConfig(self, config_data, lcov_queue=None, addfiles_queue=None): - """Adds JSON-ish config data. - - Args: - config_data: Config data string. - lcov_queue: If not None, object to append lcov_files to instead of - parsing them immediately. - addfiles_queue: If not None, object to append add_files to instead of - processing them immediately. - """ - # TODO: All manner of error checking - cfg = eval(config_data, {'__builtins__': {}}, {}) - - for rootdict in cfg.get('roots', []): - self.AddRoot(rootdict['root'], alt_name=rootdict.get('altname', '_')) - - for ruledict in cfg.get('rules', []): - regexp = ruledict.pop('regexp') - self.AddRule(regexp, **ruledict) - - for add_lcov in cfg.get('lcov_files', []): - if lcov_queue is not None: - lcov_queue.append(add_lcov) - else: - self.ParseLcovFile(add_lcov) - - for add_path in cfg.get('add_files', []): - if addfiles_queue is not None: - addfiles_queue.append(add_path) - else: - self.AddFiles(add_path) - - self.print_stats += cfg.get('print_stats', []) - - def ParseConfig(self, filename, **kwargs): - """Parses a configuration file. - - Args: - filename: Config filename. - kwargs: Additional parameters to pass to AddConfig(). - """ - # TODO: All manner of error checking - f = None - try: - f = open(filename, 'rt') - # Need to strip CR's from CRLF-terminated lines or posix systems can't - # eval the data. - config_data = f.read().replace('\r\n', '\n') - # TODO: some sort of include syntax. - # - # Needs to be done at string-time rather than at eval()-time, so that - # it's possible to include parts of dicts. Path from a file to its - # include should be relative to the dir containing the file. - # - # Or perhaps it could be done after eval. In that case, there'd be an - # 'include' section with a list of files to include. Those would be - # eval()'d and recursively pre- or post-merged with the including file. - # - # Or maybe just don't worry about it, since multiple configs can be - # specified on the command line. - self.AddConfig(config_data, **kwargs) - finally: - if f: - f.close() - - def UpdateTreeStats(self): - """Recalculates the tree stats from the currently covered files. - - Also calculates coverage summary for files. - """ - self.tree = CoveredDir('') - for cov_file in self.files.itervalues(): - # Add the file to the tree - fdirs = cov_file.filename.split('/') - parent = self.tree - ancestors = [parent] - for d in fdirs[:-1]: - if d not in parent.subdirs: - if parent.dirpath: - parent.subdirs[d] = CoveredDir(parent.dirpath + '/' + d) - else: - parent.subdirs[d] = CoveredDir(d) - parent = parent.subdirs[d] - ancestors.append(parent) - # Final subdir actually contains the file - parent.files[fdirs[-1]] = cov_file - - # Now add file's contribution to coverage by dir - for a in ancestors: - # Add to 'all' group - a.stats_by_group['all'].Add(cov_file.stats) - - # Add to group file belongs to - group = cov_file.attrs.get('group') - if group not in a.stats_by_group: - a.stats_by_group[group] = CoverageStats() - cbyg = a.stats_by_group[group] - cbyg.Add(cov_file.stats) - - def PrintTree(self): - """Prints the tree stats.""" - # Print the tree - print 'Lines of code coverage by directory:' - print self.tree.GetTree() - -#------------------------------------------------------------------------------ - - -def Main(argv): - """Main routine. - - Args: - argv: list of arguments - - Returns: - exit code, 0 for normal exit. - """ - # Parse args - parser = optparse.OptionParser() - parser.add_option( - '-i', '--input', dest='inputs', type='string', action='append', - metavar='FILE', - help='read LCOV input from FILE') - parser.add_option( - '-r', '--root', dest='roots', type='string', action='append', - metavar='ROOT[=ALTNAME]', - help='add ROOT directory, optionally map in coverage results as ALTNAME') - parser.add_option( - '-c', '--config', dest='configs', type='string', action='append', - metavar='FILE', - help='read settings from configuration FILE') - parser.add_option( - '-a', '--addfiles', dest='addfiles', type='string', action='append', - metavar='PATH', - help='add files from PATH to coverage data') - parser.add_option( - '-t', '--tree', dest='tree', action='store_true', - help='print tree of code coverage by group') - parser.add_option( - '-u', '--uninstrumented', dest='uninstrumented', action='store_true', - help='list uninstrumented files') - parser.add_option( - '-m', '--html', dest='html_out', type='string', metavar='PATH', - help='write HTML output to PATH') - parser.add_option( - '-b', '--base_url', dest='base_url', type='string', metavar='URL', - help='include URL in base tag of HTML output') - - parser.set_defaults( - inputs=[], - roots=[], - configs=[], - addfiles=[], - tree=False, - html_out=None, - ) - - options = parser.parse_args(args=argv)[0] - - cov = Coverage() - - # Set root directories for coverage - for root_opt in options.roots: - if '=' in root_opt: - cov.AddRoot(*root_opt.split('=')) - else: - cov.AddRoot(root_opt) - - # Read config files - for config_file in options.configs: - cov.ParseConfig(config_file, lcov_queue=options.inputs, - addfiles_queue=options.addfiles) - - # Parse lcov files - for input_filename in options.inputs: - cov.ParseLcovFile(input_filename) - - # Add missing files - for add_path in options.addfiles: - cov.AddFiles(add_path) - - # Print help if no files specified - if not cov.files: - print 'No covered files found.' - parser.print_help() - return 1 - - # Update tree stats - cov.UpdateTreeStats() - - # Print uninstrumented filenames - if options.uninstrumented: - print 'Uninstrumented files:' - for f in sorted(cov.files): - covf = cov.files[f] - if not covf.in_lcov: - print ' %-6s %-6s %s' % (covf.attrs.get('group'), - covf.attrs.get('language'), f) - - # Print tree stats - if options.tree: - cov.PrintTree() - - # Print stats - for ps_args in cov.print_stats: - cov.PrintStat(**ps_args) - - # Generate HTML - if options.html_out: - html = croc_html.CrocHtml(cov, options.html_out, options.base_url) - html.Write() - - # Normal exit - return 0 - - -if __name__ == '__main__': - sys.exit(Main(sys.argv))
diff --git a/tools/code_coverage/croc_html.py b/tools/code_coverage/croc_html.py deleted file mode 100644 index 7866f472..0000000 --- a/tools/code_coverage/croc_html.py +++ /dev/null
@@ -1,451 +0,0 @@ -# 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. - -"""Crocodile HTML output.""" - -import os -import shutil -import time -import xml.dom - - -class CrocHtmlError(Exception): - """Coverage HTML error.""" - - -class HtmlElement(object): - """Node in a HTML file.""" - - def __init__(self, doc, element): - """Constructor. - - Args: - doc: XML document object. - element: XML element. - """ - self.doc = doc - self.element = element - - def E(self, name, **kwargs): - """Adds a child element. - - Args: - name: Name of element. - kwargs: Attributes for element. To use an attribute which is a python - reserved word (i.e. 'class'), prefix the attribute name with 'e_'. - - Returns: - The child element. - """ - he = HtmlElement(self.doc, self.doc.createElement(name)) - element = he.element - self.element.appendChild(element) - - for k, v in kwargs.iteritems(): - if k.startswith('e_'): - # Remove prefix - element.setAttribute(k[2:], str(v)) - else: - element.setAttribute(k, str(v)) - - return he - - def Text(self, text): - """Adds a text node. - - Args: - text: Text to add. - - Returns: - self. - """ - t = self.doc.createTextNode(str(text)) - self.element.appendChild(t) - return self - - -class HtmlFile(object): - """HTML file.""" - - def __init__(self, xml_impl, filename): - """Constructor. - - Args: - xml_impl: DOMImplementation to use to create document. - filename: Path to file. - """ - self.xml_impl = xml_impl - doctype = xml_impl.createDocumentType( - 'HTML', '-//W3C//DTD HTML 4.01//EN', - 'http://www.w3.org/TR/html4/strict.dtd') - self.doc = xml_impl.createDocument(None, 'html', doctype) - self.filename = filename - - # Create head and body elements - root = HtmlElement(self.doc, self.doc.documentElement) - self.head = root.E('head') - self.body = root.E('body') - - def Write(self, cleanup=True): - """Writes the file. - - Args: - cleanup: If True, calls unlink() on the internal xml document. This - frees up memory, but means that you can't use this file for anything - else. - """ - f = open(self.filename, 'wt') - self.doc.writexml(f, encoding='UTF-8') - f.close() - - if cleanup: - self.doc.unlink() - # Prevent future uses of the doc now that we've unlinked it - self.doc = None - -#------------------------------------------------------------------------------ - -COV_TYPE_STRING = {None: 'm', 0: 'i', 1: 'E', 2: ' '} -COV_TYPE_CLASS = {None: 'missing', 0: 'instr', 1: 'covered', 2: ''} - - -class CrocHtml(object): - """Crocodile HTML output class.""" - - def __init__(self, cov, output_root, base_url=None): - """Constructor.""" - self.cov = cov - self.output_root = output_root - self.base_url = base_url - self.xml_impl = xml.dom.getDOMImplementation() - self.time_string = 'Coverage information generated %s.' % time.asctime() - - def CreateHtmlDoc(self, filename, title): - """Creates a new HTML document. - - Args: - filename: Filename to write to, relative to self.output_root. - title: Title of page - - Returns: - The document. - """ - f = HtmlFile(self.xml_impl, self.output_root + '/' + filename) - - f.head.E('title').Text(title) - - if self.base_url: - css_href = self.base_url + 'croc.css' - base_href = self.base_url + os.path.dirname(filename) - if not base_href.endswith('/'): - base_href += '/' - f.head.E('base', href=base_href) - else: - css_href = '../' * (len(filename.split('/')) - 1) + 'croc.css' - - f.head.E('link', rel='stylesheet', type='text/css', href=css_href) - - return f - - def AddCaptionForFile(self, body, path): - """Adds a caption for the file, with links to each parent dir. - - Args: - body: Body elemement. - path: Path to file. - """ - # This is slightly different that for subdir, because it needs to have a - # link to the current directory's index.html. - hdr = body.E('h2') - hdr.Text('Coverage for ') - dirs = [''] + path.split('/') - num_dirs = len(dirs) - for i in range(num_dirs - 1): - hdr.E('a', href=( - '../' * (num_dirs - i - 2) + 'index.html')).Text(dirs[i] + '/') - hdr.Text(dirs[-1]) - - def AddCaptionForSubdir(self, body, path): - """Adds a caption for the subdir, with links to each parent dir. - - Args: - body: Body elemement. - path: Path to subdir. - """ - # Link to parent dirs - hdr = body.E('h2') - hdr.Text('Coverage for ') - dirs = [''] + path.split('/') - num_dirs = len(dirs) - for i in range(num_dirs - 1): - hdr.E('a', href=( - '../' * (num_dirs - i - 1) + 'index.html')).Text(dirs[i] + '/') - hdr.Text(dirs[-1] + '/') - - def AddSectionHeader(self, table, caption, itemtype, is_file=False): - """Adds a section header to the coverage table. - - Args: - table: Table to add rows to. - caption: Caption for section, if not None. - itemtype: Type of items in this section, if not None. - is_file: Are items in this section files? - """ - - if caption is not None: - table.E('tr').E('th', e_class='secdesc', colspan=8).Text(caption) - - sec_hdr = table.E('tr') - - if itemtype is not None: - sec_hdr.E('th', e_class='section').Text(itemtype) - - sec_hdr.E('th', e_class='section').Text('Coverage') - sec_hdr.E('th', e_class='section', colspan=3).Text( - 'Lines executed / instrumented / missing') - - graph = sec_hdr.E('th', e_class='section') - graph.E('span', style='color:#00FF00').Text('exe') - graph.Text(' / ') - graph.E('span', style='color:#FFFF00').Text('inst') - graph.Text(' / ') - graph.E('span', style='color:#FF0000').Text('miss') - - if is_file: - sec_hdr.E('th', e_class='section').Text('Language') - sec_hdr.E('th', e_class='section').Text('Group') - else: - sec_hdr.E('th', e_class='section', colspan=2) - - def AddItem(self, table, itemname, stats, attrs, link=None): - """Adds a bar graph to the element. This is a series of <td> elements. - - Args: - table: Table to add item to. - itemname: Name of item. - stats: Stats object. - attrs: Attributes dictionary; if None, no attributes will be printed. - link: Destination for itemname hyperlink, if not None. - """ - row = table.E('tr') - - # Add item name - if itemname is not None: - item_elem = row.E('td') - if link is not None: - item_elem = item_elem.E('a', href=link) - item_elem.Text(itemname) - - # Get stats - stat_exe = stats.get('lines_executable', 0) - stat_ins = stats.get('lines_instrumented', 0) - stat_cov = stats.get('lines_covered', 0) - - percent = row.E('td') - - # Add text - row.E('td', e_class='number').Text(stat_cov) - row.E('td', e_class='number').Text(stat_ins) - row.E('td', e_class='number').Text(stat_exe - stat_ins) - - # Add percent and graph; only fill in if there's something in there - graph = row.E('td', e_class='graph', width=100) - if stat_exe: - percent_cov = 100.0 * stat_cov / stat_exe - percent_ins = 100.0 * stat_ins / stat_exe - - # Color percent based on thresholds - percent.Text('%.1f%%' % percent_cov) - if percent_cov >= 80: - percent.element.setAttribute('class', 'high_pct') - elif percent_cov >= 60: - percent.element.setAttribute('class', 'mid_pct') - else: - percent.element.setAttribute('class', 'low_pct') - - # Graphs use integer values - percent_cov = int(percent_cov) - percent_ins = int(percent_ins) - - graph.Text('.') - graph.E('span', style='padding-left:%dpx' % percent_cov, - e_class='g_covered') - graph.E('span', style='padding-left:%dpx' % (percent_ins - percent_cov), - e_class='g_instr') - graph.E('span', style='padding-left:%dpx' % (100 - percent_ins), - e_class='g_missing') - - if attrs: - row.E('td', e_class='stat').Text(attrs.get('language')) - row.E('td', e_class='stat').Text(attrs.get('group')) - else: - row.E('td', colspan=2) - - def WriteFile(self, cov_file): - """Writes the HTML for a file. - - Args: - cov_file: croc.CoveredFile to write. - """ - print ' ' + cov_file.filename - title = 'Coverage for ' + cov_file.filename - - f = self.CreateHtmlDoc(cov_file.filename + '.html', title) - body = f.body - - # Write header section - self.AddCaptionForFile(body, cov_file.filename) - - # Summary for this file - table = body.E('table') - self.AddSectionHeader(table, None, None, is_file=True) - self.AddItem(table, None, cov_file.stats, cov_file.attrs) - - body.E('h2').Text('Line-by-line coverage:') - - # Print line-by-line coverage - if cov_file.local_path: - code_table = body.E('table').E('tr').E('td').E('pre') - - flines = open(cov_file.local_path, 'rt') - lineno = 0 - - for line in flines: - lineno += 1 - line_cov = cov_file.lines.get(lineno, 2) - e_class = COV_TYPE_CLASS.get(line_cov) - - code_table.E('span', e_class=e_class).Text('%4d %s : %s\n' % ( - lineno, - COV_TYPE_STRING.get(line_cov), - line.rstrip() - )) - - else: - body.Text('Line-by-line coverage not available. Make sure the directory' - ' containing this file has been scanned via ') - body.E('B').Text('add_files') - body.Text(' in a configuration file, or the ') - body.E('B').Text('--addfiles') - body.Text(' command line option.') - - # TODO: if file doesn't have a local path, try to find it by - # reverse-mapping roots and searching for the file. - - body.E('p', e_class='time').Text(self.time_string) - f.Write() - - def WriteSubdir(self, cov_dir): - """Writes the index.html for a subdirectory. - - Args: - cov_dir: croc.CoveredDir to write. - """ - print ' ' + cov_dir.dirpath + '/' - - # Create the subdir if it doesn't already exist - subdir = self.output_root + '/' + cov_dir.dirpath - if not os.path.exists(subdir): - os.mkdir(subdir) - - if cov_dir.dirpath: - title = 'Coverage for ' + cov_dir.dirpath + '/' - f = self.CreateHtmlDoc(cov_dir.dirpath + '/index.html', title) - else: - title = 'Coverage summary' - f = self.CreateHtmlDoc('index.html', title) - - body = f.body - - dirs = [''] + cov_dir.dirpath.split('/') - num_dirs = len(dirs) - sort_jsfile = '../' * (num_dirs - 1) + 'sorttable.js' - script = body.E('script', src=sort_jsfile) - body.E('/script') - - # Write header section - if cov_dir.dirpath: - self.AddCaptionForSubdir(body, cov_dir.dirpath) - else: - body.E('h2').Text(title) - - table = body.E('table', e_class='sortable') - table.E('h3').Text('Coverage by Group') - # Coverage by group - self.AddSectionHeader(table, None, 'Group') - - for group in sorted(cov_dir.stats_by_group): - self.AddItem(table, group, cov_dir.stats_by_group[group], None) - - # List subdirs - if cov_dir.subdirs: - table = body.E('table', e_class='sortable') - table.E('h3').Text('Subdirectories') - self.AddSectionHeader(table, None, 'Subdirectory') - - for d in sorted(cov_dir.subdirs): - self.AddItem(table, d + '/', cov_dir.subdirs[d].stats_by_group['all'], - None, link=d + '/index.html') - - # List files - if cov_dir.files: - table = body.E('table', e_class='sortable') - table.E('h3').Text('Files in This Directory') - self.AddSectionHeader(table, None, 'Filename', - is_file=True) - - for filename in sorted(cov_dir.files): - cov_file = cov_dir.files[filename] - self.AddItem(table, filename, cov_file.stats, cov_file.attrs, - link=filename + '.html') - - body.E('p', e_class='time').Text(self.time_string) - f.Write() - - def WriteRoot(self): - """Writes the files in the output root.""" - # Find ourselves - src_dir = os.path.split(self.WriteRoot.func_code.co_filename)[0] - - # Files to copy into output root - copy_files = ['croc.css'] - # Third_party files to copy into output root - third_party_files = ['sorttable.js'] - - # Copy files from our directory into the output directory - for copy_file in copy_files: - print ' Copying %s' % copy_file - shutil.copyfile(os.path.join(src_dir, copy_file), - os.path.join(self.output_root, copy_file)) - # Copy third party files from third_party directory into - # the output directory - src_dir = os.path.join(src_dir, 'third_party') - for third_party_file in third_party_files: - print ' Copying %s' % third_party_file - shutil.copyfile(os.path.join(src_dir, third_party_file), - os.path.join(self.output_root, third_party_file)) - - def Write(self): - """Writes HTML output.""" - - print 'Writing HTML to %s...' % self.output_root - - # Loop through the tree and write subdirs, breadth-first - # TODO: switch to depth-first and sort values - makes nicer output? - todo = [self.cov.tree] - while todo: - cov_dir = todo.pop(0) - - # Append subdirs to todo list - todo += cov_dir.subdirs.values() - - # Write this subdir - self.WriteSubdir(cov_dir) - - # Write files in this subdir - for cov_file in cov_dir.files.itervalues(): - self.WriteFile(cov_file) - - # Write files in root directory - self.WriteRoot()
diff --git a/tools/code_coverage/croc_scan.py b/tools/code_coverage/croc_scan.py deleted file mode 100644 index 8d0e2e8d..0000000 --- a/tools/code_coverage/croc_scan.py +++ /dev/null
@@ -1,164 +0,0 @@ -# Copyright (c) 2011 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. - -"""Crocodile source scanners.""" - - -import re - - -class Scanner(object): - """Generic source scanner.""" - - def __init__(self): - """Constructor.""" - - self.re_token = re.compile('#') - self.comment_to_eol = ['#'] - self.comment_start = None - self.comment_end = None - - def ScanLines(self, lines): - """Scans the lines for executable statements. - - Args: - lines: Iterator returning source lines. - - Returns: - An array of line numbers which are executable. - """ - exe_lines = [] - lineno = 0 - - in_string = None - in_comment = None - comment_index = None - - for line in lines: - lineno += 1 - in_string_at_start = in_string - - for t in self.re_token.finditer(line): - tokenstr = t.groups()[0] - - if in_comment: - # Inside a multi-line comment, so look for end token - if tokenstr == in_comment: - in_comment = None - # Replace comment with spaces - line = (line[:comment_index] - + ' ' * (t.end(0) - comment_index) - + line[t.end(0):]) - - elif in_string: - # Inside a string, so look for end token - if tokenstr == in_string: - in_string = None - - elif tokenstr in self.comment_to_eol: - # Single-line comment, so truncate line at start of token - line = line[:t.start(0)] - break - - elif tokenstr == self.comment_start: - # Multi-line comment start - end token is comment_end - in_comment = self.comment_end - comment_index = t.start(0) - - else: - # Starting a string - end token is same as start - in_string = tokenstr - - # If still in comment at end of line, remove comment - if in_comment: - line = line[:comment_index] - # Next line, delete from the beginnine - comment_index = 0 - - # If line-sans-comments is not empty, claim it may be executable - if line.strip() or in_string_at_start: - exe_lines.append(lineno) - - # Return executable lines - return exe_lines - - def Scan(self, filename): - """Reads the file and scans its lines. - - Args: - filename: Path to file to scan. - - Returns: - An array of line numbers which are executable. - """ - - # TODO: All manner of error checking - f = None - try: - f = open(filename, 'rt') - return self.ScanLines(f) - finally: - if f: - f.close() - - -class PythonScanner(Scanner): - """Python source scanner.""" - - def __init__(self): - """Constructor.""" - Scanner.__init__(self) - - # TODO: This breaks for strings ending in more than 2 backslashes. Need - # a pattern which counts only an odd number of backslashes, so the last - # one thus escapes the quote. - self.re_token = re.compile(r'(#|\'\'\'|"""|(?<!(?<!\\)\\)["\'])') - self.comment_to_eol = ['#'] - self.comment_start = None - self.comment_end = None - - -class CppScanner(Scanner): - """C / C++ / ObjC / ObjC++ source scanner.""" - - def __init__(self): - """Constructor.""" - Scanner.__init__(self) - - # TODO: This breaks for strings ending in more than 2 backslashes. Need - # a pattern which counts only an odd number of backslashes, so the last - # one thus escapes the quote. - self.re_token = re.compile(r'(^\s*#|//|/\*|\*/|(?<!(?<!\\)\\)["\'])') - - # TODO: Treat '\' at EOL as a token, and handle it as continuing the - # previous line. That is, if in a comment-to-eol, this line is a comment - # too. - - # Note that we treat # at beginning of line as a comment, so that we ignore - # preprocessor definitions - self.comment_to_eol = ['//', '#'] - - self.comment_start = '/*' - self.comment_end = '*/' - - -def ScanFile(filename, language): - """Scans a file for executable lines. - - Args: - filename: Path to file to scan. - language: Language for file ('C', 'C++', 'python', 'ObjC', 'ObjC++') - - Returns: - A list of executable lines, or an empty list if the file was not a handled - language. - """ - - if language == 'python': - return PythonScanner().Scan(filename) - elif language in ['C', 'C++', 'ObjC', 'ObjC++']: - return CppScanner().Scan(filename) - - # Something we don't handle - return []
diff --git a/tools/code_coverage/croc_scan_test.py b/tools/code_coverage/croc_scan_test.py deleted file mode 100755 index a69b28a..0000000 --- a/tools/code_coverage/croc_scan_test.py +++ /dev/null
@@ -1,187 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2011 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. - -"""Unit tests for croc_scan.py.""" - -import re -import unittest -import croc_scan - - -class TestScanner(unittest.TestCase): - """Tests for croc_scan.Scanner.""" - - def testInit(self): - """Test __init()__.""" - s = croc_scan.Scanner() - - self.assertEqual(s.re_token.pattern, '#') - self.assertEqual(s.comment_to_eol, ['#']) - self.assertEqual(s.comment_start, None) - self.assertEqual(s.comment_end, None) - - def testScanLines(self): - """Test ScanLines().""" - s = croc_scan.Scanner() - # Set up imaginary language: - # ':' = comment to EOL - # '"' = string start/end - # '(' = comment start - # ')' = comment end - s.re_token = re.compile(r'([\:\"\(\)])') - s.comment_to_eol = [':'] - s.comment_start = '(' - s.comment_end = ')' - - # No input file = no output lines - self.assertEqual(s.ScanLines([]), []) - - # Empty lines and lines with only whitespace are ignored - self.assertEqual(s.ScanLines([ - '', # 1 - 'line', # 2 exe - ' \t ', # 3 - ]), [2]) - - # Comments to EOL are stripped, but not inside strings - self.assertEqual(s.ScanLines([ - 'test', # 1 exe - ' : A comment', # 2 - '"a : in a string"', # 3 exe - 'test2 : with comment to EOL', # 4 exe - 'foo = "a multiline string with an empty line', # 5 exe - '', # 6 exe - ': and a comment-to-EOL character"', # 7 exe - ': done', # 8 - ]), [1, 3, 4, 5, 6, 7]) - - # Test Comment start/stop detection - self.assertEqual(s.ScanLines([ - '( a comment on one line)', # 1 - 'text (with a comment)', # 2 exe - '( a comment with a : in the middle)', # 3 - '( a multi-line', # 4 - ' comment)', # 5 - 'a string "with a ( in it"', # 6 exe - 'not in a multi-line comment', # 7 exe - '(a comment with a " in it)', # 8 - ': not in a string, so this gets stripped', # 9 - 'more text "with an uninteresting string"', # 10 exe - ]), [2, 6, 7, 10]) - - # TODO: Test Scan(). Low priority, since it just wraps ScanLines(). - - -class TestPythonScanner(unittest.TestCase): - """Tests for croc_scan.PythonScanner.""" - - def testScanLines(self): - """Test ScanLines().""" - s = croc_scan.PythonScanner() - - # No input file = no output lines - self.assertEqual(s.ScanLines([]), []) - - self.assertEqual(s.ScanLines([ - '# a comment', # 1 - '', # 2 - '"""multi-line string', # 3 exe - '# not a comment', # 4 exe - 'end of multi-line string"""', # 5 exe - ' ', # 6 - '"single string with #comment"', # 7 exe - '', # 8 - '\'\'\'multi-line string, single-quote', # 9 exe - '# not a comment', # 10 exe - 'end of multi-line string\'\'\'', # 11 exe - '', # 12 - '"string with embedded \\" is handled"', # 13 exe - '# quoted "', # 14 - '"\\""', # 15 exe - '# quoted backslash', # 16 - '"\\\\"', # 17 exe - 'main()', # 18 exe - '# end', # 19 - ]), [3, 4, 5, 7, 9, 10, 11, 13, 15, 17, 18]) - - -class TestCppScanner(unittest.TestCase): - """Tests for croc_scan.CppScanner.""" - - def testScanLines(self): - """Test ScanLines().""" - s = croc_scan.CppScanner() - - # No input file = no output lines - self.assertEqual(s.ScanLines([]), []) - - self.assertEqual(s.ScanLines([ - '// a comment', # 1 - '# a preprocessor define', # 2 - '', # 3 - '\'#\', \'"\'', # 4 exe - '', # 5 - '/* a multi-line comment', # 6 - 'with a " in it', # 7 - '*/', # 8 - '', # 9 - '"a string with /* and \' in it"', # 10 exe - '', # 11 - '"a multi-line string\\', # 12 exe - '// not a comment\\', # 13 exe - 'ending here"', # 14 exe - '', # 15 - '"string with embedded \\" is handled"', # 16 exe - '', # 17 - 'main()', # 18 exe - '// end', # 19 - ]), [4, 10, 12, 13, 14, 16, 18]) - - -class TestScanFile(unittest.TestCase): - """Tests for croc_scan.ScanFile().""" - - class MockScanner(object): - """Mock scanner.""" - - def __init__(self, language): - """Constructor.""" - self.language = language - - def Scan(self, filename): - """Mock Scan() method.""" - return 'scan %s %s' % (self.language, filename) - - def MockPythonScanner(self): - return self.MockScanner('py') - - def MockCppScanner(self): - return self.MockScanner('cpp') - - def setUp(self): - """Per-test setup.""" - # Hook scanners - self.old_python_scanner = croc_scan.PythonScanner - self.old_cpp_scanner = croc_scan.CppScanner - croc_scan.PythonScanner = self.MockPythonScanner - croc_scan.CppScanner = self.MockCppScanner - - def tearDown(self): - """Per-test cleanup.""" - croc_scan.PythonScanner = self.old_python_scanner - croc_scan.CppScanner = self.old_cpp_scanner - - def testScanFile(self): - """Test ScanFile().""" - self.assertEqual(croc_scan.ScanFile('foo', 'python'), 'scan py foo') - self.assertEqual(croc_scan.ScanFile('bar1', 'C'), 'scan cpp bar1') - self.assertEqual(croc_scan.ScanFile('bar2', 'C++'), 'scan cpp bar2') - self.assertEqual(croc_scan.ScanFile('bar3', 'ObjC'), 'scan cpp bar3') - self.assertEqual(croc_scan.ScanFile('bar4', 'ObjC++'), 'scan cpp bar4') - self.assertEqual(croc_scan.ScanFile('bar', 'fortran'), []) - - -if __name__ == '__main__': - unittest.main()
diff --git a/tools/code_coverage/croc_test.py b/tools/code_coverage/croc_test.py deleted file mode 100755 index 7c2521c..0000000 --- a/tools/code_coverage/croc_test.py +++ /dev/null
@@ -1,758 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2011 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. - -"""Unit tests for Crocodile.""" - -import os -import StringIO -import unittest -import croc - - -class TestCoverageStats(unittest.TestCase): - """Tests for croc.CoverageStats.""" - - def testAdd(self): - """Test Add().""" - c = croc.CoverageStats() - - # Initially empty - self.assertEqual(c, {}) - - # Add items - c['a'] = 1 - c['b'] = 0 - self.assertEqual(c, {'a': 1, 'b': 0}) - - # Add dict with non-overlapping items - c.Add({'c': 5}) - self.assertEqual(c, {'a': 1, 'b': 0, 'c': 5}) - - # Add dict with overlapping items - c.Add({'a': 4, 'd': 3}) - self.assertEqual(c, {'a': 5, 'b': 0, 'c': 5, 'd': 3}) - - -class TestCoveredFile(unittest.TestCase): - """Tests for croc.CoveredFile.""" - - def setUp(self): - self.cov_file = croc.CoveredFile('bob.cc', group='source', language='C++') - - def testInit(self): - """Test init.""" - f = self.cov_file - - # Check initial values - self.assertEqual(f.filename, 'bob.cc') - self.assertEqual(f.attrs, {'group': 'source', 'language': 'C++'}) - self.assertEqual(f.lines, {}) - self.assertEqual(f.stats, {}) - self.assertEqual(f.local_path, None) - self.assertEqual(f.in_lcov, False) - - def testUpdateCoverageEmpty(self): - """Test updating coverage when empty.""" - f = self.cov_file - f.UpdateCoverage() - self.assertEqual(f.stats, { - 'lines_executable': 0, - 'lines_instrumented': 0, - 'lines_covered': 0, - 'files_executable': 1, - }) - - def testUpdateCoverageExeOnly(self): - """Test updating coverage when no lines are instrumented.""" - f = self.cov_file - f.lines = {1: None, 2: None, 4: None} - f.UpdateCoverage() - self.assertEqual(f.stats, { - 'lines_executable': 3, - 'lines_instrumented': 0, - 'lines_covered': 0, - 'files_executable': 1, - }) - - # Now mark the file instrumented via in_lcov - f.in_lcov = True - f.UpdateCoverage() - self.assertEqual(f.stats, { - 'lines_executable': 3, - 'lines_instrumented': 0, - 'lines_covered': 0, - 'files_executable': 1, - 'files_instrumented': 1, - }) - - def testUpdateCoverageExeAndInstr(self): - """Test updating coverage when no lines are covered.""" - f = self.cov_file - f.lines = {1: None, 2: None, 4: 0, 5: 0, 7: None} - f.UpdateCoverage() - self.assertEqual(f.stats, { - 'lines_executable': 5, - 'lines_instrumented': 2, - 'lines_covered': 0, - 'files_executable': 1, - 'files_instrumented': 1, - }) - - def testUpdateCoverageWhenCovered(self): - """Test updating coverage when lines are covered.""" - f = self.cov_file - f.lines = {1: None, 2: None, 3: 1, 4: 0, 5: 0, 6: 1, 7: None} - f.UpdateCoverage() - self.assertEqual(f.stats, { - 'lines_executable': 7, - 'lines_instrumented': 4, - 'lines_covered': 2, - 'files_executable': 1, - 'files_instrumented': 1, - 'files_covered': 1, - }) - - -class TestCoveredDir(unittest.TestCase): - """Tests for croc.CoveredDir.""" - - def setUp(self): - self.cov_dir = croc.CoveredDir('/a/b/c') - - def testInit(self): - """Test init.""" - d = self.cov_dir - - # Check initial values - self.assertEqual(d.dirpath, '/a/b/c') - self.assertEqual(d.files, {}) - self.assertEqual(d.subdirs, {}) - self.assertEqual(d.stats_by_group, {'all': {}}) - - def testGetTreeEmpty(self): - """Test getting empty tree.""" - d = self.cov_dir - self.assertEqual(d.GetTree(), 'c/') - - def testGetTreeStats(self): - """Test getting tree with stats.""" - d = self.cov_dir - d.stats_by_group['all'] = croc.CoverageStats( - lines_executable=50, lines_instrumented=30, lines_covered=20) - d.stats_by_group['bar'] = croc.CoverageStats( - lines_executable=0, lines_instrumented=0, lines_covered=0) - d.stats_by_group['foo'] = croc.CoverageStats( - lines_executable=33, lines_instrumented=22, lines_covered=11) - # 'bar' group is skipped because it has no executable lines - self.assertEqual( - d.GetTree(), - 'c/ all:20/30/50 foo:11/22/33') - - def testGetTreeSubdir(self): - """Test getting tree with subdirs.""" - d1 = self.cov_dir = croc.CoveredDir('/a') - d2 = self.cov_dir = croc.CoveredDir('/a/b') - d3 = self.cov_dir = croc.CoveredDir('/a/c') - d4 = self.cov_dir = croc.CoveredDir('/a/b/d') - d5 = self.cov_dir = croc.CoveredDir('/a/b/e') - d1.subdirs = {'/a/b': d2, '/a/c': d3} - d2.subdirs = {'/a/b/d': d4, '/a/b/e': d5} - self.assertEqual(d1.GetTree(), 'a/\n b/\n d/\n e/\n c/') - - -class TestCoverage(unittest.TestCase): - """Tests for croc.Coverage.""" - - def MockWalk(self, src_dir): - """Mock for os.walk(). - - Args: - src_dir: Source directory to walk. - - Returns: - A list of (dirpath, dirnames, filenames) tuples. - """ - self.mock_walk_calls.append(src_dir) - return self.mock_walk_return - - def MockScanFile(self, filename, language): - """Mock for croc_scan.ScanFile(). - - Args: - filename: Path to file to scan. - language: Language for file. - - Returns: - A list of executable lines. - """ - self.mock_scan_calls.append([filename, language]) - if filename in self.mock_scan_return: - return self.mock_scan_return[filename] - else: - return self.mock_scan_return['default'] - - def setUp(self): - """Per-test setup.""" - - # Empty coverage object - self.cov = croc.Coverage() - - # Coverage object with minimal setup - self.cov_minimal = croc.Coverage() - self.cov_minimal.AddRoot('/src') - self.cov_minimal.AddRoot('c:\\source') - self.cov_minimal.AddRule('^_/', include=1, group='my') - self.cov_minimal.AddRule('.*\\.c$', language='C') - self.cov_minimal.AddRule('.*\\.c##$', language='C##') # sharper than thou - - # Data for MockWalk() - self.mock_walk_calls = [] - self.mock_walk_return = [] - - # Data for MockScanFile() - self.mock_scan_calls = [] - self.mock_scan_return = {'default': [1]} - - def testInit(self): - """Test init.""" - c = self.cov - self.assertEqual(c.files, {}) - self.assertEqual(c.root_dirs, []) - self.assertEqual(c.print_stats, []) - self.assertEqual(c.rules, []) - - def testAddRoot(self): - """Test AddRoot() and CleanupFilename().""" - c = self.cov - - # Check for identity on already-clean filenames - self.assertEqual(c.CleanupFilename(''), '') - self.assertEqual(c.CleanupFilename('a'), 'a') - self.assertEqual(c.CleanupFilename('.a'), '.a') - self.assertEqual(c.CleanupFilename('..a'), '..a') - self.assertEqual(c.CleanupFilename('a.b'), 'a.b') - self.assertEqual(c.CleanupFilename('a/b/c'), 'a/b/c') - self.assertEqual(c.CleanupFilename('a/b/c/'), 'a/b/c/') - - # Backslash to forward slash - self.assertEqual(c.CleanupFilename('a\\b\\c'), 'a/b/c') - - # Handle relative paths - self.assertEqual(c.CleanupFilename('.'), - c.CleanupFilename(os.path.abspath('.'))) - self.assertEqual(c.CleanupFilename('..'), - c.CleanupFilename(os.path.abspath('..'))) - self.assertEqual(c.CleanupFilename('./foo/bar'), - c.CleanupFilename(os.path.abspath('./foo/bar'))) - self.assertEqual(c.CleanupFilename('../../a/b/c'), - c.CleanupFilename(os.path.abspath('../../a/b/c'))) - - # Replace alt roots - c.AddRoot('foo') - self.assertEqual(c.CleanupFilename('foo'), '_') - self.assertEqual(c.CleanupFilename('foo/bar/baz'), '_/bar/baz') - self.assertEqual(c.CleanupFilename('aaa/foo'), 'aaa/foo') - - # Alt root replacement is applied for all roots - c.AddRoot('foo/bar', '_B') - self.assertEqual(c.CleanupFilename('foo/bar/baz'), '_B/baz') - - # Can use previously defined roots in cleanup - c.AddRoot('_/nom/nom/nom', '_CANHAS') - self.assertEqual(c.CleanupFilename('foo/nom/nom/nom/cheezburger'), - '_CANHAS/cheezburger') - - # Verify roots starting with UNC paths or drive letters work, and that - # more than one root can point to the same alt_name - c.AddRoot('/usr/local/foo', '_FOO') - c.AddRoot('D:\\my\\foo', '_FOO') - self.assertEqual(c.CleanupFilename('/usr/local/foo/a/b'), '_FOO/a/b') - self.assertEqual(c.CleanupFilename('D:\\my\\foo\\c\\d'), '_FOO/c/d') - - # Cannot specify a blank alt_name - self.assertRaises(ValueError, c.AddRoot, 'some_dir', '') - - def testAddRule(self): - """Test AddRule() and ClassifyFile().""" - c = self.cov - - # With only the default rule, nothing gets kept - self.assertEqual(c.ClassifyFile('_/src/'), {}) - self.assertEqual(c.ClassifyFile('_/src/a.c'), {}) - - # Add rules to include a tree and set a default group - c.AddRule('^_/src/', include=1, group='source') - self.assertEqual(c.ClassifyFile('_/src/'), - {'include': 1, 'group': 'source'}) - self.assertEqual(c.ClassifyFile('_/notsrc/'), {}) - self.assertEqual(c.ClassifyFile('_/src/a.c'), - {'include': 1, 'group': 'source'}) - - # Define some languages and groups - c.AddRule('.*\\.(c|h)$', language='C') - c.AddRule('.*\\.py$', language='Python') - c.AddRule('.*_test\\.', group='test') - self.assertEqual(c.ClassifyFile('_/src/a.c'), - {'include': 1, 'group': 'source', 'language': 'C'}) - self.assertEqual(c.ClassifyFile('_/src/a.h'), - {'include': 1, 'group': 'source', 'language': 'C'}) - self.assertEqual(c.ClassifyFile('_/src/a.cpp'), - {'include': 1, 'group': 'source'}) - self.assertEqual(c.ClassifyFile('_/src/a_test.c'), - {'include': 1, 'group': 'test', 'language': 'C'}) - self.assertEqual(c.ClassifyFile('_/src/test_a.c'), - {'include': 1, 'group': 'source', 'language': 'C'}) - self.assertEqual(c.ClassifyFile('_/src/foo/bar.py'), - {'include': 1, 'group': 'source', 'language': 'Python'}) - self.assertEqual(c.ClassifyFile('_/src/test.py'), - {'include': 1, 'group': 'source', 'language': 'Python'}) - - # Exclude a path (for example, anything in a build output dir) - c.AddRule('.*/build/', include=0) - # But add back in a dir which matched the above rule but isn't a build - # output dir - c.AddRule('_/src/tools/build/', include=1) - self.assertEqual(c.ClassifyFile('_/src/build.c').get('include'), 1) - self.assertEqual(c.ClassifyFile('_/src/build/').get('include'), 0) - self.assertEqual(c.ClassifyFile('_/src/build/a.c').get('include'), 0) - self.assertEqual(c.ClassifyFile('_/src/tools/build/').get('include'), 1) - self.assertEqual(c.ClassifyFile('_/src/tools/build/t.c').get('include'), 1) - - def testGetCoveredFile(self): - """Test GetCoveredFile().""" - c = self.cov_minimal - - # Not currently any covered files - self.assertEqual(c.GetCoveredFile('_/a.c'), None) - - # Add some files - a_c = c.GetCoveredFile('_/a.c', add=True) - b_c = c.GetCoveredFile('_/b.c##', add=True) - self.assertEqual(a_c.filename, '_/a.c') - self.assertEqual(a_c.attrs, {'include': 1, 'group': 'my', 'language': 'C'}) - self.assertEqual(b_c.filename, '_/b.c##') - self.assertEqual(b_c.attrs, - {'include': 1, 'group': 'my', 'language': 'C##'}) - - # Specifying the same filename should return the existing object - self.assertEqual(c.GetCoveredFile('_/a.c'), a_c) - self.assertEqual(c.GetCoveredFile('_/a.c', add=True), a_c) - - # Filenames get cleaned on the way in, as do root paths - self.assertEqual(c.GetCoveredFile('/src/a.c'), a_c) - self.assertEqual(c.GetCoveredFile('c:\\source\\a.c'), a_c) - - # TODO: Make sure that covered files require language, group, and include - # (since that checking is now done in GetCoveredFile() rather than - # ClassifyFile()) - - def testRemoveCoveredFile(self): - """Test RemoveCoveredFile().""" - # TODO: TEST ME! - - def testParseLcov(self): - """Test ParseLcovData().""" - c = self.cov_minimal - - c.ParseLcovData([ - '# Ignore unknown lines', - # File we should include' - 'SF:/src/a.c', - 'DA:10,1', - 'DA:11,0', - 'DA:12,1 \n', # Trailing whitespace should get stripped - 'end_of_record', - # File we should ignore - 'SF:/not_src/a.c', - 'DA:20,1', - 'end_of_record', - # Same as first source file, but alternate root - 'SF:c:\\source\\a.c', - 'DA:30,1', - 'end_of_record', - # Ignore extra end of record - 'end_of_record', - # Ignore data points after end of record - 'DA:40,1', - # Instrumented but uncovered file - 'SF:/src/b.c', - 'DA:50,0', - 'end_of_record', - # Empty file (instrumented but no executable lines) - 'SF:c:\\source\\c.c', - 'end_of_record', - ]) - - # We should know about three files - self.assertEqual(sorted(c.files), ['_/a.c', '_/b.c', '_/c.c']) - - # Check expected contents - a_c = c.GetCoveredFile('_/a.c') - self.assertEqual(a_c.lines, {10: 1, 11: 0, 12: 1, 30: 1}) - self.assertEqual(a_c.stats, { - 'files_executable': 1, - 'files_instrumented': 1, - 'files_covered': 1, - 'lines_instrumented': 4, - 'lines_executable': 4, - 'lines_covered': 3, - }) - self.assertEqual(a_c.in_lcov, True) - - b_c = c.GetCoveredFile('_/b.c') - self.assertEqual(b_c.lines, {50: 0}) - self.assertEqual(b_c.stats, { - 'files_executable': 1, - 'files_instrumented': 1, - 'lines_instrumented': 1, - 'lines_executable': 1, - 'lines_covered': 0, - }) - self.assertEqual(b_c.in_lcov, True) - - c_c = c.GetCoveredFile('_/c.c') - self.assertEqual(c_c.lines, {}) - self.assertEqual(c_c.stats, { - 'files_executable': 1, - 'files_instrumented': 1, - 'lines_instrumented': 0, - 'lines_executable': 0, - 'lines_covered': 0, - }) - self.assertEqual(c_c.in_lcov, True) - - # TODO: Test that files are marked as instrumented if they come from lcov, - # even if they don't have any instrumented lines. (and that in_lcov is set - # for those files - probably should set that via some method rather than - # directly...) - - def testGetStat(self): - """Test GetStat() and PrintStat().""" - c = self.cov - - # Add some stats, so there's something to report - c.tree.stats_by_group = { - 'all': { - 'count_a': 10, - 'count_b': 4, - 'foo': 'bar', - }, - 'tests': { - 'count_a': 2, - 'count_b': 5, - 'baz': 'bob', - }, - } - - # Test missing stats and groups - self.assertRaises(croc.CrocStatError, c.GetStat, 'nosuch') - self.assertRaises(croc.CrocStatError, c.GetStat, 'baz') - self.assertRaises(croc.CrocStatError, c.GetStat, 'foo', group='tests') - self.assertRaises(croc.CrocStatError, c.GetStat, 'foo', group='nosuch') - - # Test returning defaults - self.assertEqual(c.GetStat('nosuch', default=13), 13) - self.assertEqual(c.GetStat('baz', default='aaa'), 'aaa') - self.assertEqual(c.GetStat('foo', group='tests', default=0), 0) - self.assertEqual(c.GetStat('foo', group='nosuch', default=''), '') - - # Test getting stats - self.assertEqual(c.GetStat('count_a'), 10) - self.assertEqual(c.GetStat('count_a', group='tests'), 2) - self.assertEqual(c.GetStat('foo', default='baz'), 'bar') - - # Test stat math (eval) - self.assertEqual(c.GetStat('count_a - count_b'), 6) - self.assertEqual(c.GetStat('100.0 * count_a / count_b', group='tests'), - 40.0) - # Should catch eval errors - self.assertRaises(croc.CrocStatError, c.GetStat, '100 / 0') - self.assertRaises(croc.CrocStatError, c.GetStat, 'count_a -') - - # Test nested stats via S() - self.assertEqual(c.GetStat('count_a - S("count_a", group="tests")'), 8) - self.assertRaises(croc.CrocStatError, c.GetStat, 'S()') - self.assertRaises(croc.CrocStatError, c.GetStat, 'S("nosuch")') - - # Test PrintStat() - # We won't see the first print, but at least verify it doesn't assert - c.PrintStat('count_a', format='(test to stdout: %s)') - # Send subsequent prints to a file - f = StringIO.StringIO() - c.PrintStat('count_b', outfile=f) - # Test specifying output format - c.PrintStat('count_a', format='Count A = %05d', outfile=f) - # Test specifing additional keyword args - c.PrintStat('count_a', group='tests', outfile=f) - c.PrintStat('nosuch', default=42, outfile=f) - self.assertEqual(f.getvalue(), ("""\ -GetStat('count_b') = 4 -Count A = 00010 -GetStat('count_a') = 2 -GetStat('nosuch') = 42 -""")) - f.close() - - def testAddConfigEmpty(self): - """Test AddConfig() with empty config.""" - c = self.cov - # Most minimal config is an empty dict; should do nothing - c.AddConfig('{} # And we ignore comments') - - def testAddConfig(self): - """Test AddConfig().""" - c = self.cov - lcov_queue = [] - addfiles_queue = [] - - c.AddConfig("""{ - 'roots' : [ - {'root' : '/foo'}, - {'root' : '/bar', 'altname' : 'BAR'}, - ], - 'rules' : [ - {'regexp' : '^_/', 'group' : 'apple'}, - {'regexp' : 're2', 'include' : 1, 'language' : 'elvish'}, - ], - 'lcov_files' : ['a.lcov', 'b.lcov'], - 'add_files' : ['/src', 'BAR/doo'], - 'print_stats' : [ - {'stat' : 'count_a'}, - {'stat' : 'count_b', 'group' : 'tests'}, - ], - 'extra_key' : 'is ignored', - }""", lcov_queue=lcov_queue, addfiles_queue=addfiles_queue) - - self.assertEqual(lcov_queue, ['a.lcov', 'b.lcov']) - self.assertEqual(addfiles_queue, ['/src', 'BAR/doo']) - self.assertEqual(c.root_dirs, [['/foo', '_'], ['/bar', 'BAR']]) - self.assertEqual(c.print_stats, [ - {'stat': 'count_a'}, - {'stat': 'count_b', 'group': 'tests'}, - ]) - # Convert compiled re's back to patterns for comparison - rules = [[r[0].pattern] + r[1:] for r in c.rules] - self.assertEqual(rules, [ - ['^_/', {'group': 'apple'}], - ['re2', {'include': 1, 'language': 'elvish'}], - ]) - - def testAddFilesSimple(self): - """Test AddFiles() simple call.""" - c = self.cov_minimal - c.add_files_walk = self.MockWalk - c.scan_file = self.MockScanFile - - c.AddFiles('/a/b/c') - self.assertEqual(self.mock_walk_calls, ['/a/b/c']) - self.assertEqual(self.mock_scan_calls, []) - self.assertEqual(c.files, {}) - - def testAddFilesRootMap(self): - """Test AddFiles() with root mappings.""" - c = self.cov_minimal - c.add_files_walk = self.MockWalk - c.scan_file = self.MockScanFile - - c.AddRoot('_/subdir', 'SUBDIR') - - # AddFiles() should replace the 'SUBDIR' alt_name, then match both - # possible roots for the '_' alt_name. - c.AddFiles('SUBDIR/foo') - self.assertEqual(self.mock_walk_calls, - ['/src/subdir/foo', 'c:/source/subdir/foo']) - self.assertEqual(self.mock_scan_calls, []) - self.assertEqual(c.files, {}) - - def testAddFilesNonEmpty(self): - """Test AddFiles() where files are returned.""" - - c = self.cov_minimal - c.add_files_walk = self.MockWalk - c.scan_file = self.MockScanFile - - # Add a rule to exclude a subdir - c.AddRule('^_/proj1/excluded/', include=0) - - # Add a rule to exclude adding some fiels - c.AddRule('.*noscan.c$', add_if_missing=0) - - # Set data for mock walk and scan - self.mock_walk_return = [ - [ - '/src/proj1', - ['excluded', 'subdir'], - ['a.c', 'no.f', 'yes.c', 'noexe.c', 'bob_noscan.c'], - ], - [ - '/src/proj1/subdir', - [], - ['cherry.c'], - ], - ] - - # Add a file with no executable lines; it should be scanned but not added - self.mock_scan_return['/src/proj1/noexe.c'] = [] - - c.AddFiles('/src/proj1') - - self.assertEqual(self.mock_walk_calls, ['/src/proj1']) - self.assertEqual(self.mock_scan_calls, [ - ['/src/proj1/a.c', 'C'], - ['/src/proj1/yes.c', 'C'], - ['/src/proj1/noexe.c', 'C'], - ['/src/proj1/subdir/cherry.c', 'C'], - ]) - - # Include files from the main dir and subdir - self.assertEqual(sorted(c.files), [ - '_/proj1/a.c', - '_/proj1/subdir/cherry.c', - '_/proj1/yes.c']) - - # Excluded dir should have been pruned from the mock walk data dirnames. - # In the real os.walk() call this prunes the walk. - self.assertEqual(self.mock_walk_return[0][1], ['subdir']) - - - def testEmptyTreeStats(self): - """Make sure we don't choke when absolutely nothing happened. - - How we might hit this: bot compile error.""" - c = self.cov_minimal - t = c.tree - t.stats_by_group['all'].AddDefaults() - self.assertEqual(t.stats_by_group, { - 'all': { 'files_covered': 0, - 'files_instrumented': 0, - 'files_executable': 0, - 'lines_covered': 0, - 'lines_instrumented': 0, - 'lines_executable': 0 }}) - - def testUpdateTreeStats(self): - """Test UpdateTreeStats().""" - - c = self.cov_minimal - c.AddRule('.*_test', group='test') - - # Fill the files list - c.ParseLcovData([ - 'SF:/src/a.c', - 'DA:10,1', 'DA:11,1', 'DA:20,0', - 'end_of_record', - 'SF:/src/a_test.c', - 'DA:10,1', 'DA:11,1', 'DA:12,1', - 'end_of_record', - 'SF:/src/foo/b.c', - 'DA:10,1', 'DA:11,1', 'DA:20,0', 'DA:21,0', 'DA:30,0', - 'end_of_record', - 'SF:/src/foo/b_test.c', - 'DA:20,0', 'DA:21,0', 'DA:22,0', - 'end_of_record', - ]) - c.UpdateTreeStats() - - t = c.tree - self.assertEqual(t.dirpath, '') - self.assertEqual(sorted(t.files), []) - self.assertEqual(sorted(t.subdirs), ['_']) - self.assertEqual(t.stats_by_group, { - 'all': { - 'files_covered': 3, - 'files_executable': 4, - 'lines_executable': 14, - 'lines_covered': 7, - 'lines_instrumented': 14, - 'files_instrumented': 4, - }, - 'my': { - 'files_covered': 2, - 'files_executable': 2, - 'lines_executable': 8, - 'lines_covered': 4, - 'lines_instrumented': 8, - 'files_instrumented': 2, - }, - 'test': { - 'files_covered': 1, - 'files_executable': 2, - 'lines_executable': 6, - 'lines_covered': 3, - 'lines_instrumented': 6, - 'files_instrumented': 2, - }, - }) - - t = t.subdirs['_'] - self.assertEqual(t.dirpath, '_') - self.assertEqual(sorted(t.files), ['a.c', 'a_test.c']) - self.assertEqual(sorted(t.subdirs), ['foo']) - self.assertEqual(t.stats_by_group, { - 'all': { - 'files_covered': 3, - 'files_executable': 4, - 'lines_executable': 14, - 'lines_covered': 7, - 'lines_instrumented': 14, - 'files_instrumented': 4, - }, - 'my': { - 'files_covered': 2, - 'files_executable': 2, - 'lines_executable': 8, - 'lines_covered': 4, - 'lines_instrumented': 8, - 'files_instrumented': 2, - }, - 'test': { - 'files_covered': 1, - 'files_executable': 2, - 'lines_executable': 6, - 'lines_covered': 3, - 'lines_instrumented': 6, - 'files_instrumented': 2, - }, - }) - - t = t.subdirs['foo'] - self.assertEqual(t.dirpath, '_/foo') - self.assertEqual(sorted(t.files), ['b.c', 'b_test.c']) - self.assertEqual(sorted(t.subdirs), []) - self.assertEqual(t.stats_by_group, { - 'test': { - 'files_executable': 1, - 'files_instrumented': 1, - 'lines_executable': 3, - 'lines_instrumented': 3, - 'lines_covered': 0, - }, - 'all': { - 'files_covered': 1, - 'files_executable': 2, - 'lines_executable': 8, - 'lines_covered': 2, - 'lines_instrumented': 8, - 'files_instrumented': 2, - }, - 'my': { - 'files_covered': 1, - 'files_executable': 1, - 'lines_executable': 5, - 'lines_covered': 2, - 'lines_instrumented': 5, - 'files_instrumented': 1, - } - }) - - # TODO: test: less important, since these are thin wrappers around other - # tested methods. - # ParseConfig() - # ParseLcovFile() - # PrintTree() - - -if __name__ == '__main__': - unittest.main()
diff --git a/tools/code_coverage/example.croc b/tools/code_coverage/example.croc deleted file mode 100644 index 4e8ca2b..0000000 --- a/tools/code_coverage/example.croc +++ /dev/null
@@ -1,197 +0,0 @@ -# -*- 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. - -# Example configuration file for Croc - -# Basic formatting rules: -# * It looks like JSON. -# * It's really python. -# * Dictionaries are wrapped in {}. Order does not matter. Entries are of -# the form: -# 'key':value, -# Note the trailing comma, which will help save you from python's built-in -# string concatenation. -# * Lists are wrapped in []. Order does matter. Entries should be followed -# with a trailing comma, which will help save you from python's built-in -# string concatenation. -# * Comments start with # and extend to end of line. -# * Strings are wrapped in ''. Backslashes must be escaped ('foo\\bar', not -# 'foo\bar') - this is particularly important in rule regular expressions. - - -# What follows is the main configuration dictionary. -{ - # List of root directories, applied in order. - # - # Typically, coverage data files contain absolute paths to the sources. - # What you care about is usually a relative path from the top of your source - # tree (referred to here as a 'source root') to the sources. - # - # Roots may also be specified on the command line via the --root option. - # Roots specified by --root are applied before those specified in config - # files. - 'roots' : [ - # Each entry is a dict. - # * It must contain a 'root' entry, which is the start of a path. - # * Root entries may be absolute paths - # * Root entries starting with './' or '../' are relative paths, and - # are taken relative to the current directory where you run croc. - # * Root entries may start with previously defined altnames. - # * Use '/' as a path separator, even on Windows. - # * It may contain a 'altname' entry. If the root matches the start of - # a filename, that start is replaced with the 'altname', or with '_' - # if no default is specified. - # * Multiple root entries may share the same altname. This is commonly - # used when combining LCOV files from different platforms into one - # coverage report, when each platform checks out source code into a - # different source tree. - {'root' : 'c:/P4/EarthHammer'}, - {'root' : 'd:/pulse/recipes/330137642/base'}, - {'root' : '/Volumes/BuildData/PulseData/data/recipes/330137640/base'}, - {'root' : '/usr/local/google/builder/.pulse-agent/data/recipes/330137641/base'}, - - # Sub-paths we specifically care about and want to call out. Note that - # these are relative to the default '_' altname. - { - 'root' : '_/googleclient/third_party/software_construction_toolkit/files', - 'altname' : 'SCT', - }, - { - 'root' : '_/googleclient/tools/hammer', - 'altname' : 'HAMMER', - }, - ], - - # List of rules, applied in order. - 'rules' : [ - # Each rule is a dict. - # * It must contaihn a 'regexp' entry. Filenames which match this - # regular expression (after applying mappings from 'roots') are - # affected by the rule. - # - # * Other entries in the dict are attributes to apply to matching files. - # - # Allowed attributes: - # - # 'include' : If 1, the file will be included in coverage reports. If 0, - # it won't be included in coverage reports. - # - # 'group' : Name of the group the file belongs to. The most common - # group names are 'source' and 'test'. Files must belong to - # a group to be included in coverage reports. - # - # 'language' : Programming language for the file. The most common - # languages are 'C', 'C++', 'python', 'ObjC', 'ObjC++'. - # Files must have a language to be included in coverage - # reports. - # - # 'add_if_missing' : If 1, and the file was not referenced by any LCOV - # files, it will be be scanned for executable lines - # and added to the coverage report. If 0, if the - # file is not referenced by any LCOV files, it will - # simply be ignored and not present in coverage - # reports. - - # Files/paths to include - { - 'regexp' : '^(SCT|HAMMER)/', - 'include' : 1, - 'add_if_missing': 1, - }, - { - 'regexp' : '.*/(\\.svn|\\.hg)/', - 'include' : 0, - }, - - # Groups - { - 'regexp' : '', - 'group' : 'source', - }, - { - 'regexp' : '.*_(test|test_mac|unittest)\\.', - 'group' : 'test', - }, - - # Languages - { - 'regexp' : '.*\\.py$', - 'language' : 'python', - }, - ], - - # List of paths to add source from. - # - # Each entry is a path. It may be a local path, or one relative to a root - # altname (see 'roots' above). - # - # If more than one root's altname matches the start of this path, all matches - # will be attempted; matches where the candidate directory doesn't exist will - # be ignored. For example, if you're combining data from multiple platforms' - # LCOV files, you probably defined at least one root per LCOV, but only have - # one copy of the source on your local platform. That's fine; Croc will use - # the source it can find and not worry about the source it can't. - # - # Source files must be added via 'add_files' to generate line-by-line HTML - # output (via the --html option) and/or to scan for missing executable lines - # (if 'add_if_missing' is 1). - 'add_files' : [ - 'SCT', - 'HAMMER', - ], - - # Statistics to print. - # - 'print_stats' : [ - # Each entry is a dict. - # - # It must have a 'stat' entry, which is the statistic to print. This may - # be one of the following stats: - # - # * files_executable - # * files_instrumented - # * files_covered - # * lines_executable - # * lines_instrumented - # * lines_covered - # - # or an expression using those stats. - # - # It may have a 'format' entry, which is a python formatting string (very - # printf-like) for the statistic. - # - # It may have a 'group' entry. If this is specified, only files from the - # matching group will be included in the statistic. If not specified, the - # group defaults to 'all', which means all groups. - { - 'stat' : 'files_executable', - 'format' : '*RESULT FilesKnown: files_executable= %d files', - }, - { - 'stat' : 'files_instrumented', - 'format' : '*RESULT FilesInstrumented: files_instrumented= %d files', - }, - { - 'stat' : '100.0 * files_instrumented / files_executable', - 'format' : '*RESULT FilesInstrumentedPercent: files_instrumented_percent= %g', - }, - { - 'stat' : 'lines_instrumented', - 'format' : '*RESULT LinesInstrumented: lines_instrumented= %d lines', - }, - { - 'stat' : 'lines_covered', - 'format' : '*RESULT LinesCoveredSource: lines_covered_source= %d lines', - 'group' : 'source', - }, - { - 'stat' : 'lines_covered', - 'format' : '*RESULT LinesCoveredTest: lines_covered_test= %d lines', - 'group' : 'test', - }, - ], - -}
diff --git a/tools/code_coverage/html_templates/footer.html b/tools/code_coverage/html_templates/footer.html new file mode 100644 index 0000000..afb7967 --- /dev/null +++ b/tools/code_coverage/html_templates/footer.html
@@ -0,0 +1,3 @@ + </div> + </body> +</html> \ No newline at end of file
diff --git a/tools/code_coverage/html_templates/header.html b/tools/code_coverage/html_templates/header.html new file mode 100644 index 0000000..b8bb6f7 --- /dev/null +++ b/tools/code_coverage/html_templates/header.html
@@ -0,0 +1,12 @@ +<!doctype html> +<html> + <head> + <meta name='viewport' content='width=device-width,initial-scale=1'> + <meta charset='UTF-8'> + <link rel='stylesheet' type='text/css' href='{{ css_path }}'> + </head> + <body> + <h2>Coverage Report</h2> + <p>Click <a href='http://clang.llvm.org/docs/SourceBasedCodeCoverage.html#interpreting-reports'>here</a> for information about interpreting this report.</p> + <p>View results by: <a href='{{ directory_view_href }}'>Directories</a> <a href='{{ component_view_href }}'>Components</a> <a href='{{ file_view_href }}'>Files</a></p> + <div class='centered'> \ No newline at end of file
diff --git a/tools/code_coverage/html_templates/table.html b/tools/code_coverage/html_templates/table.html new file mode 100644 index 0000000..226b29d --- /dev/null +++ b/tools/code_coverage/html_templates/table.html
@@ -0,0 +1,34 @@ +<table> + <tr> + <td class="column-entry-bold">{{ table_entry_type }}</td> + <td class="column-entry-bold">Line Coverage</td> + <td class="column-entry-bold">Function Coverage</td> + <td class="column-entry-bold">Region Coverage</td> + </tr> + {% for entry in entries %} + <tr class="light-row"> + <td> + {% if entry["is_dir"] == True %} + <pre><a href='{{ entry["href"] }}'>{{ entry["name"] }}/</a></pre> + {% else %} + <pre><a href='{{ entry["href"] }}'>{{ entry["name"] }}</a></pre> + {% endif %} + </td> + {% for feature in ("lines", "functions", "regions") %} + <td class='column-entry-{{ entry[feature]["color_class"] }}'> + <pre>{{ entry[feature]["percentage"] }}% ({{ entry[feature]["covered"] }}/{{ entry[feature]["total"] }})</pre> + </td> + {% endfor %} + </tr> + {% endfor %} + <tr class="light-row-bold"> + <td> + <pre>Totals</pre> + </td> + {% for feature in ("lines", "functions", "regions") %} + <td class='column-entry-{{ total_entry[feature]["color_class"] }}'> + <pre>{{ total_entry[feature]["percentage"] }}% ({{ total_entry[feature]["covered"] }}/{{ total_entry[feature]["total"] }})</pre> + </td> + {% endfor %} + </tr> +</table> \ No newline at end of file
diff --git a/tools/code_coverage/third_party/README.chromium b/tools/code_coverage/third_party/README.chromium deleted file mode 100644 index a492552..0000000 --- a/tools/code_coverage/third_party/README.chromium +++ /dev/null
@@ -1,11 +0,0 @@ -Name: SortTable -Short Name: sorttable.js -URL: http://www.kryogenix.org/code/browser/sorttable/ -Version: 2 -Date: 7th April 2007 -License: Licenced as X11: http://www.kryogenix.org/code/browser/licence.html - -Description: -Add <script src="sorttable.js"></script> to your HTML -Add class="sortable" to any table you'd like to make sortable -Click on the headers to sort
diff --git a/tools/code_coverage/third_party/sorttable.js b/tools/code_coverage/third_party/sorttable.js deleted file mode 100644 index 16ef551..0000000 --- a/tools/code_coverage/third_party/sorttable.js +++ /dev/null
@@ -1,494 +0,0 @@ -/* - SortTable - version 2 - 7th April 2007 - Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/ - - Instructions: - Download this file - Add <script src="sorttable.js"></script> to your HTML - Add class="sortable" to any table you'd like to make sortable - Click on the headers to sort - - Thanks to many, many people for contributions and suggestions. - Licenced as X11: http://www.kryogenix.org/code/browser/licence.html - This basically means: do what you want with it. -*/ - - -var stIsIE = /*@cc_on!@*/false; - -sorttable = { - init: function() { - // quit if this function has already been called - if (arguments.callee.done) return; - // flag this function so we don't do the same thing twice - arguments.callee.done = true; - // kill the timer - if (_timer) clearInterval(_timer); - - if (!document.createElement || !document.getElementsByTagName) return; - - sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/; - - forEach(document.getElementsByTagName('table'), function(table) { - if (table.className.search(/\bsortable\b/) != -1) { - sorttable.makeSortable(table); - } - }); - - }, - - makeSortable: function(table) { - if (table.getElementsByTagName('thead').length == 0) { - // table doesn't have a tHead. Since it should have, create one and - // put the first table row in it. - the = document.createElement('thead'); - the.appendChild(table.rows[0]); - table.insertBefore(the,table.firstChild); - } - // Safari doesn't support table.tHead, sigh - if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0]; - - if (table.tHead.rows.length != 1) return; // can't cope with two header rows - - // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as - // "total" rows, for example). This is B&R, since what you're supposed - // to do is put them in a tfoot. So, if there are sortbottom rows, - // for backwards compatibility, move them to tfoot (creating it if needed). - sortbottomrows = []; - for (var i=0; i<table.rows.length; i++) { - if (table.rows[i].className.search(/\bsortbottom\b/) != -1) { - sortbottomrows[sortbottomrows.length] = table.rows[i]; - } - } - if (sortbottomrows) { - if (table.tFoot == null) { - // table doesn't have a tfoot. Create one. - tfo = document.createElement('tfoot'); - table.appendChild(tfo); - } - for (var i=0; i<sortbottomrows.length; i++) { - tfo.appendChild(sortbottomrows[i]); - } - delete sortbottomrows; - } - - // work through each column and calculate its type - headrow = table.tHead.rows[0].cells; - for (var i=0; i<headrow.length; i++) { - // manually override the type with a sorttable_type attribute - if (!headrow[i].className.match(/\bsorttable_nosort\b/)) { // skip this col - mtch = headrow[i].className.match(/\bsorttable_([a-z0-9]+)\b/); - if (mtch) { override = mtch[1]; } - if (mtch && typeof sorttable["sort_"+override] == 'function') { - headrow[i].sorttable_sortfunction = sorttable["sort_"+override]; - } else { - headrow[i].sorttable_sortfunction = sorttable.guessType(table,i); - } - // make it clickable to sort - headrow[i].sorttable_columnindex = i; - headrow[i].sorttable_tbody = table.tBodies[0]; - dean_addEvent(headrow[i],"click", function(e) { - - if (this.className.search(/\bsorttable_sorted\b/) != -1) { - // if we're already sorted by this column, just - // reverse the table, which is quicker - sorttable.reverse(this.sorttable_tbody); - this.className = this.className.replace('sorttable_sorted', - 'sorttable_sorted_reverse'); - this.removeChild(document.getElementById('sorttable_sortfwdind')); - sortrevind = document.createElement('span'); - sortrevind.id = "sorttable_sortrevind"; - sortrevind.innerHTML = stIsIE ? ' <font face="webdings">5</font>' : ' ▴'; - this.appendChild(sortrevind); - return; - } - if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) { - // if we're already sorted by this column in reverse, just - // re-reverse the table, which is quicker - sorttable.reverse(this.sorttable_tbody); - this.className = this.className.replace('sorttable_sorted_reverse', - 'sorttable_sorted'); - this.removeChild(document.getElementById('sorttable_sortrevind')); - sortfwdind = document.createElement('span'); - sortfwdind.id = "sorttable_sortfwdind"; - sortfwdind.innerHTML = stIsIE ? ' <font face="webdings">6</font>' : ' ▾'; - this.appendChild(sortfwdind); - return; - } - - // remove sorttable_sorted classes - theadrow = this.parentNode; - forEach(theadrow.childNodes, function(cell) { - if (cell.nodeType == 1) { // an element - cell.className = cell.className.replace('sorttable_sorted_reverse',''); - cell.className = cell.className.replace('sorttable_sorted',''); - } - }); - sortfwdind = document.getElementById('sorttable_sortfwdind'); - if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); } - sortrevind = document.getElementById('sorttable_sortrevind'); - if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); } - - this.className += ' sorttable_sorted'; - sortfwdind = document.createElement('span'); - sortfwdind.id = "sorttable_sortfwdind"; - sortfwdind.innerHTML = stIsIE ? ' <font face="webdings">6</font>' : ' ▾'; - this.appendChild(sortfwdind); - - // build an array to sort. This is a Schwartzian transform thing, - // i.e., we "decorate" each row with the actual sort key, - // sort based on the sort keys, and then put the rows back in order - // which is a lot faster because you only do getInnerText once per row - row_array = []; - col = this.sorttable_columnindex; - rows = this.sorttable_tbody.rows; - for (var j=0; j<rows.length; j++) { - row_array[row_array.length] = [sorttable.getInnerText(rows[j].cells[col]), rows[j]]; - } - /* If you want a stable sort, uncomment the following line */ - //sorttable.shaker_sort(row_array, this.sorttable_sortfunction); - /* and comment out this one */ - row_array.sort(this.sorttable_sortfunction); - - tb = this.sorttable_tbody; - for (var j=0; j<row_array.length; j++) { - tb.appendChild(row_array[j][1]); - } - - delete row_array; - }); - } - } - }, - - guessType: function(table, column) { - // guess the type of a column based on its first non-blank row - sortfn = sorttable.sort_alpha; - for (var i=0; i<table.tBodies[0].rows.length; i++) { - text = sorttable.getInnerText(table.tBodies[0].rows[i].cells[column]); - if (text != '') { - if (text.match(/^-?[£$¤]?[\d,.]+%?$/)) { - return sorttable.sort_numeric; - } - // check for a date: dd/mm/yyyy or dd/mm/yy - // can have / or . or - as separator - // can be mm/dd as well - possdate = text.match(sorttable.DATE_RE) - if (possdate) { - // looks like a date - first = parseInt(possdate[1]); - second = parseInt(possdate[2]); - if (first > 12) { - // definitely dd/mm - return sorttable.sort_ddmm; - } else if (second > 12) { - return sorttable.sort_mmdd; - } else { - // looks like a date, but we can't tell which, so assume - // that it's dd/mm (English imperialism!) and keep looking - sortfn = sorttable.sort_ddmm; - } - } - } - } - return sortfn; - }, - - getInnerText: function(node) { - // gets the text we want to use for sorting for a cell. - // strips leading and trailing whitespace. - // this is *not* a generic getInnerText function; it's special to sorttable. - // for example, you can override the cell text with a customkey attribute. - // it also gets .value for <input> fields. - - if (!node) return ""; - - hasInputs = (typeof node.getElementsByTagName == 'function') && - node.getElementsByTagName('input').length; - - if (node.getAttribute("sorttable_customkey") != null) { - return node.getAttribute("sorttable_customkey"); - } - else if (typeof node.textContent != 'undefined' && !hasInputs) { - return node.textContent.replace(/^\s+|\s+$/g, ''); - } - else if (typeof node.innerText != 'undefined' && !hasInputs) { - return node.innerText.replace(/^\s+|\s+$/g, ''); - } - else if (typeof node.text != 'undefined' && !hasInputs) { - return node.text.replace(/^\s+|\s+$/g, ''); - } - else { - switch (node.nodeType) { - case 3: - if (node.nodeName.toLowerCase() == 'input') { - return node.value.replace(/^\s+|\s+$/g, ''); - } - case 4: - return node.nodeValue.replace(/^\s+|\s+$/g, ''); - break; - case 1: - case 11: - var innerText = ''; - for (var i = 0; i < node.childNodes.length; i++) { - innerText += sorttable.getInnerText(node.childNodes[i]); - } - return innerText.replace(/^\s+|\s+$/g, ''); - break; - default: - return ''; - } - } - }, - - reverse: function(tbody) { - // reverse the rows in a tbody - newrows = []; - for (var i=0; i<tbody.rows.length; i++) { - newrows[newrows.length] = tbody.rows[i]; - } - for (var i=newrows.length-1; i>=0; i--) { - tbody.appendChild(newrows[i]); - } - delete newrows; - }, - - /* sort functions - each sort function takes two parameters, a and b - you are comparing a[0] and b[0] */ - sort_numeric: function(a,b) { - aa = parseFloat(a[0].replace(/[^0-9.-]/g,'')); - if (isNaN(aa)) aa = 0; - bb = parseFloat(b[0].replace(/[^0-9.-]/g,'')); - if (isNaN(bb)) bb = 0; - return aa-bb; - }, - sort_alpha: function(a,b) { - if (a[0]==b[0]) return 0; - if (a[0]<b[0]) return -1; - return 1; - }, - sort_ddmm: function(a,b) { - mtch = a[0].match(sorttable.DATE_RE); - y = mtch[3]; m = mtch[2]; d = mtch[1]; - if (m.length == 1) m = '0'+m; - if (d.length == 1) d = '0'+d; - dt1 = y+m+d; - mtch = b[0].match(sorttable.DATE_RE); - y = mtch[3]; m = mtch[2]; d = mtch[1]; - if (m.length == 1) m = '0'+m; - if (d.length == 1) d = '0'+d; - dt2 = y+m+d; - if (dt1==dt2) return 0; - if (dt1<dt2) return -1; - return 1; - }, - sort_mmdd: function(a,b) { - mtch = a[0].match(sorttable.DATE_RE); - y = mtch[3]; d = mtch[2]; m = mtch[1]; - if (m.length == 1) m = '0'+m; - if (d.length == 1) d = '0'+d; - dt1 = y+m+d; - mtch = b[0].match(sorttable.DATE_RE); - y = mtch[3]; d = mtch[2]; m = mtch[1]; - if (m.length == 1) m = '0'+m; - if (d.length == 1) d = '0'+d; - dt2 = y+m+d; - if (dt1==dt2) return 0; - if (dt1<dt2) return -1; - return 1; - }, - - shaker_sort: function(list, comp_func) { - // A stable sort function to allow multi-level sorting of data - // see: http://en.wikipedia.org/wiki/Cocktail_sort - // thanks to Joseph Nahmias - var b = 0; - var t = list.length - 1; - var swap = true; - - while(swap) { - swap = false; - for(var i = b; i < t; ++i) { - if ( comp_func(list[i], list[i+1]) > 0 ) { - var q = list[i]; list[i] = list[i+1]; list[i+1] = q; - swap = true; - } - } // for - t--; - - if (!swap) break; - - for(var i = t; i > b; --i) { - if ( comp_func(list[i], list[i-1]) < 0 ) { - var q = list[i]; list[i] = list[i-1]; list[i-1] = q; - swap = true; - } - } // for - b++; - - } // while(swap) - } -} - -/* ****************************************************************** - Supporting functions: bundled here to avoid depending on a library - ****************************************************************** */ - -// Dean Edwards/Matthias Miller/John Resig - -/* for Mozilla/Opera9 */ -if (document.addEventListener) { - document.addEventListener("DOMContentLoaded", sorttable.init, false); -} - -/* for Internet Explorer */ -/*@cc_on @*/ -/*@if (@_win32) - document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>"); - var script = document.getElementById("__ie_onload"); - script.onreadystatechange = function() { - if (this.readyState == "complete") { - sorttable.init(); // call the onload handler - } - }; -/*@end @*/ - -/* for Safari */ -if (/WebKit/i.test(navigator.userAgent)) { // sniff - var _timer = setInterval(function() { - if (/loaded|complete/.test(document.readyState)) { - sorttable.init(); // call the onload handler - } - }, 10); -} - -/* for other browsers */ -window.onload = sorttable.init; - -// written by Dean Edwards, 2005 -// with input from Tino Zijdel, Matthias Miller, Diego Perini - -// http://dean.edwards.name/weblog/2005/10/add-event/ - -function dean_addEvent(element, type, handler) { - if (element.addEventListener) { - element.addEventListener(type, handler, false); - } else { - // assign each event handler a unique ID - if (!handler.$$guid) handler.$$guid = dean_addEvent.guid++; - // create a hash table of event types for the element - if (!element.events) element.events = {}; - // create a hash table of event handlers for each element/event pair - var handlers = element.events[type]; - if (!handlers) { - handlers = element.events[type] = {}; - // store the existing event handler (if there is one) - if (element["on" + type]) { - handlers[0] = element["on" + type]; - } - } - // store the event handler in the hash table - handlers[handler.$$guid] = handler; - // assign a global event handler to do all the work - element["on" + type] = handleEvent; - } -}; -// a counter used to create unique IDs -dean_addEvent.guid = 1; - -function removeEvent(element, type, handler) { - if (element.removeEventListener) { - element.removeEventListener(type, handler, false); - } else { - // delete the event handler from the hash table - if (element.events && element.events[type]) { - delete element.events[type][handler.$$guid]; - } - } -}; - -function handleEvent(event) { - var returnValue = true; - // grab the event object (IE uses a global event object) - event = event || fixEvent(((this.ownerDocument || this.document || this).parentWindow || window).event); - // get a reference to the hash table of event handlers - var handlers = this.events[event.type]; - // execute each event handler - for (var i in handlers) { - this.$$handleEvent = handlers[i]; - if (this.$$handleEvent(event) === false) { - returnValue = false; - } - } - return returnValue; -}; - -function fixEvent(event) { - // add W3C standard event methods - event.preventDefault = fixEvent.preventDefault; - event.stopPropagation = fixEvent.stopPropagation; - return event; -}; -fixEvent.preventDefault = function() { - this.returnValue = false; -}; -fixEvent.stopPropagation = function() { - this.cancelBubble = true; -} - -// Dean's forEach: http://dean.edwards.name/base/forEach.js -/* - forEach, version 1.0 - Copyright 2006, Dean Edwards - License: http://www.opensource.org/licenses/mit-license.php -*/ - -// array-like enumeration -if (!Array.forEach) { // mozilla already supports this - Array.forEach = function(array, block, context) { - for (var i = 0; i < array.length; i++) { - block.call(context, array[i], i, array); - } - }; -} - -// generic enumeration -Function.prototype.forEach = function(object, block, context) { - for (var key in object) { - if (typeof this.prototype[key] == "undefined") { - block.call(context, object[key], key, object); - } - } -}; - -// character enumeration -String.forEach = function(string, block, context) { - Array.forEach(string.split(""), function(chr, index) { - block.call(context, chr, index, string); - }); -}; - -// globally resolve forEach enumeration -var forEach = function(object, block, context) { - if (object) { - var resolve = Object; // default - if (object instanceof Function) { - // functions have a "length" property - resolve = Function; - } else if (object.forEach instanceof Function) { - // the object implements a custom forEach method so use that - object.forEach(block, context); - return; - } else if (typeof object == "string") { - // the object is a string - resolve = String; - } else if (typeof object.length == "number") { - // the object is array-like - resolve = Array; - } - resolve.forEach(object, block, context); - } -};
diff --git a/tools/cygprofile/BUILD.gn b/tools/cygprofile/BUILD.gn index fc4015a..f5f9016 100644 --- a/tools/cygprofile/BUILD.gn +++ b/tools/cygprofile/BUILD.gn
@@ -2,21 +2,47 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/config/android/config.gni") + +if (target_cpu == "arm") { + static_library("lightweight_cygprofile") { + sources = [ + "lightweight_cygprofile.cc", + "lightweight_cygprofile.h", + ] + deps = [ + "//base", + ] + + configs -= [ "//build/config/android:default_cygprofile_instrumentation" ] + configs += [ "//build/config/android:no_cygprofile_instrumentation" ] + } +} + static_library("cygprofile") { - sources = [ - "cygprofile.cc", - "cygprofile.h", - ] - - configs -= [ "//build/config/android:default_cygprofile_instrumentation" ] - configs += [ "//build/config/android:no_cygprofile_instrumentation" ] - deps = [ # This adds uninstrumented symbols to the static library from base. # These symbols are likely *not* to be used because there are many other # duplicates in other objects/libraries. "//base", ] + + if (use_lightweight_order_profiling) { + assert(use_order_profiling) + assert(target_cpu == "arm") + sources = [ + "delayed_dumper.cc", + ] + deps += [ ":lightweight_cygprofile" ] + } else { + sources = [ + "cygprofile.cc", + "cygprofile.h", + ] + } + + configs -= [ "//build/config/android:default_cygprofile_instrumentation" ] + configs += [ "//build/config/android:no_cygprofile_instrumentation" ] } executable("cygprofile_unittests") { @@ -53,3 +79,23 @@ "//testing/perf", ] } + +if (target_cpu == "arm") { + executable("lightweight_cygprofile_perftests") { + testonly = true + + sources = [ + "lightweight_cygprofile_perftest.cc", + ] + + configs -= [ "//build/config/android:default_cygprofile_instrumentation" ] + configs += [ "//build/config/android:no_cygprofile_instrumentation" ] + + deps = [ + ":lightweight_cygprofile", + "//base", + "//testing/gtest", + "//testing/perf", + ] + } +}
diff --git a/tools/cygprofile/check_orderfile.py b/tools/cygprofile/check_orderfile.py index 0b72bf7..f17e32a 100755 --- a/tools/cygprofile/check_orderfile.py +++ b/tools/cygprofile/check_orderfile.py
@@ -86,8 +86,8 @@ symbol_extractor.SetArchitecture(options.arch) obj_dir = cygprofile_utils.GetObjDir(binary_filename) - symbol_to_sections_map = \ - cyglog_to_orderfile.GetSymbolToSectionsMapFromObjectFiles(obj_dir) + symbol_to_sections_map = cyglog_to_orderfile.ObjectFileProcessor( + obj_dir).GetSymbolToSectionsMap() section_to_symbols_map = cygprofile_utils.InvertMapping( symbol_to_sections_map) symbols = patch_orderfile.GetSymbolsFromOrderfile(orderfile_filename,
diff --git a/tools/cygprofile/compare_orderfiles.py b/tools/cygprofile/compare_orderfiles.py new file mode 100755 index 0000000..3cf2934 --- /dev/null +++ b/tools/cygprofile/compare_orderfiles.py
@@ -0,0 +1,156 @@ +#!/usr/bin/python +# Copyright 2017 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. + +"""Compares two orderfiles, from filenames or a commit. + +This shows some statistics about two orderfiles, possibly extracted from an +updating commit made by the orderfile bot. +""" + +import argparse +import logging +import os +import subprocess +import sys + + +def ParseOrderfile(filename): + """Parses an orderfile into a list of symbols. + + Args: + filename: (str) Path to the orderfile. + + Returns: + [str] List of symbols. + """ + symbols = [] + lines = [] + already_seen = set() + with open(filename, 'r') as f: + lines = [line.strip() for line in f] + + for entry in lines: + # Example: .text.startup.BLA + symbol_name = entry[entry.rindex('.'):] + if symbol_name in already_seen or symbol_name == '*' or entry == '.text': + continue + already_seen.add(symbol_name) + symbols.append(symbol_name) + return symbols + + +def Compare(first_filename, second_filename): + """Outputs a comparison of two orderfiles to stdout. + + Args: + first_filename: (str) First orderfile. + second_filename: (str) Second orderfile. + """ + first_symbols = ParseOrderfile(first_filename) + second_symbols = ParseOrderfile(second_filename) + print 'Symbols count:\n\tfirst:\t%d\n\tsecond:\t%d' % ( + len(first_symbols), len(second_symbols)) + first_symbols = set(first_symbols) + second_symbols = set(second_symbols) + new_symbols = second_symbols - first_symbols + removed_symbols = first_symbols - second_symbols + print 'New symbols = %d' % len(new_symbols) + print 'Removed symbols = %d' % len(removed_symbols) + + +def CheckOrderfileCommit(commit_hash, clank_path): + """Asserts that a commit is an orderfile update from the bot. + + Args: + commit_hash: (str) Git hash of the orderfile roll commit. + clank_path: (str) Path to the clank repository. + """ + output = subprocess.check_output( + ['git', 'show', r'--format=%an %s', commit_hash], cwd=clank_path) + first_line = output.split('\n')[0] + assert first_line == 'clank-autoroller Update Orderfile.', ( + 'Not an orderfile commit') + + +def GetBeforeAfterOrderfileHashes(commit_hash, clank_path): + """Downloads the orderfiles before and afer an orderfile roll. + + Args: + commit_hash: (str) Git hash of the orderfile roll commit. + clank_path: (str) Path to the clank repository. + + Returns: + (str, str) Path to the before and after commit orderfiles. + """ + orderfile_hash_relative_path = 'orderfiles/orderfile.arm.out.sha1' + before_output = subprocess.check_output( + ['git', 'show', '%s^:%s' % (commit_hash, orderfile_hash_relative_path)], + cwd=clank_path) + before_hash = before_output.split('\n')[0] + after_output = subprocess.check_output( + ['git', 'show', '%s:%s' % (commit_hash, orderfile_hash_relative_path)], + cwd=clank_path) + after_hash = after_output.split('\n')[0] + assert before_hash != after_hash + return (before_hash, after_hash) + + +def DownloadOrderfile(orderfile_hash, output_filename): + """Downloads an orderfile with a given hash to a given destination.""" + cloud_storage_path = ( + 'gs://clank-archive/orderfile-clankium/%s' % orderfile_hash) + subprocess.check_call( + ['gsutil.py', 'cp', cloud_storage_path, output_filename]) + + +def GetOrderfilesFromCommit(commit_hash): + """Returns paths to the before and after orderfiles for a commit.""" + clank_path = os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, + 'clank') + logging.info('Checking that the commit is an orderfile') + CheckOrderfileCommit(commit_hash, clank_path) + (before_hash, after_hash) = GetBeforeAfterOrderfileHashes( + commit_hash, clank_path) + logging.info('Before / after hashes: %s %s', before_hash, after_hash) + before_filename = os.path.join('/tmp/', before_hash) + after_filename = os.path.join('/tmp/', after_hash) + logging.info('Downloading files') + DownloadOrderfile(before_hash, before_filename) + DownloadOrderfile(after_hash, after_filename) + return (before_filename, after_filename) + + +def CreateArgumentParser(): + """Returns the argumeng parser.""" + parser = argparse.ArgumentParser() + parser.add_argument('--first', help='First orderfile') + parser.add_argument('--second', help='Second orderfile') + parser.add_argument('--from-commit', help='Analyze the difference in the ' + 'orderfile from an orderfile bot commit.') + return parser + + +def main(): + logging.basicConfig(level=logging.INFO) + parser = CreateArgumentParser() + args = parser.parse_args() + if args.first or args.second: + assert args.first and args.second, 'Need both files.' + Compare(args.first, args.second) + elif args.from_commit: + first, second = GetOrderfilesFromCommit(args.from_commit) + try: + logging.info('Comparing the orderfiles') + Compare(first, second) + finally: + os.remove(first) + os.remove(second) + else: + return False + return True + + +if __name__ == '__main__': + sys.exit(0 if main() else 1)
diff --git a/tools/cygprofile/cyglog_to_orderfile.py b/tools/cygprofile/cyglog_to_orderfile.py index bc382f6..0fb2e90 100755 --- a/tools/cygprofile/cyglog_to_orderfile.py +++ b/tools/cygprofile/cyglog_to_orderfile.py
@@ -8,9 +8,9 @@ Given a log file and the binary being profiled, creates an orderfile. """ +import argparse import logging import multiprocessing -import optparse import os import re import string @@ -18,9 +18,189 @@ import tempfile import cygprofile_utils +import process_profiles import symbol_extractor +class _SymbolNotFoundException(Exception): + """Exception used during internal processing.""" + def __init__(self, value): + super(_SymbolNotFoundException, self).__init__(value) + self.value = value + + def __str__(self): + return repr(self.value) + + +class ObjectFileProcessor(object): + """Processes symbols found in the object file tree. + + This notably includes the section names of each symbol, as well as component + information that can be taken from the directory (not yet implemented). + """ + def __init__(self, obj_dir): + """Initialize. + + Args: + obj_dir (str) The root of the object directory. + """ + self._obj_dir = obj_dir + self._symbol_to_sections_map = None + + def GetSymbolToSectionsMap(self): + """Scans object files to find symbol section names. + + Returns: + {symbol: linker section(s)} + """ + if self._symbol_to_sections_map is not None: + return self._symbol_to_sections_map + + symbol_infos = self._GetAllSymbolInfos() + self._symbol_to_sections_map = {} + symbol_warnings = cygprofile_utils.WarningCollector(300) + for symbol_info in symbol_infos: + symbol = symbol_info.name + if symbol.startswith('.LTHUNK'): + continue + section = symbol_info.section + if ((symbol in self._symbol_to_sections_map) and + (symbol_info.section not in self._symbol_to_sections_map[symbol])): + self._symbol_to_sections_map[symbol].append(section) + + if not self._SameCtorOrDtorNames( + symbol, self._symbol_to_sections_map[symbol][0].lstrip('.text.')): + symbol_warnings.Write('Symbol ' + symbol + + ' unexpectedly in more than one section: ' + + ', '.join(self._symbol_to_sections_map[symbol])) + elif not section.startswith('.text.'): + # Assembly functions have section ".text". These are all grouped + # together near the end of the orderfile via an explicit ".text" entry. + if section != '.text': + symbol_warnings.Write('Symbol ' + symbol + + ' in incorrect section ' + section) + else: + # In most cases we expect just one item in this list, and maybe 4 or so + # in the worst case. + self._symbol_to_sections_map[symbol] = [section] + symbol_warnings.WriteEnd('bad sections') + return self._symbol_to_sections_map + + @classmethod + def _SameCtorOrDtorNames(cls, symbol1, symbol2): + """Returns True if two symbols refer to the same constructor or destructor. + + The Itanium C++ ABI specifies dual constructor and destructor emmission + (section 5.1.4.3): + https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-special-ctor-dtor + To avoid fully parsing all mangled symbols, a heuristic is used with + c++filt. + + Note: some compilers may name generated copies differently. If this becomes + an issue this heuristic will need to be updated. + """ + # Check if this is the understood case of constructor/destructor + # signatures. GCC emits up to three types of constructor/destructors: + # complete, base, and allocating. If they're all the same they'll + # get folded together. + return (re.search('(C[123]|D[012])E', symbol1) and + symbol_extractor.DemangleSymbol(symbol1) == + symbol_extractor.DemangleSymbol(symbol2)) + + def _GetAllSymbolInfos(self): + obj_files = [] + # Scan _obj_dir recursively for .o files. + for (dirpath, _, filenames) in os.walk(self._obj_dir): + for file_name in filenames: + if file_name.endswith('.o'): + obj_files.append(os.path.join(dirpath, file_name)) + + pool = multiprocessing.Pool() + # Hopefully the object files are in the page cache at this point as + # typically the library has just been built before the object files are + # scanned. Hence IO should not be a problem, and there is no need for a + # concurrency limit on the pool. + symbol_infos_nested = pool.map( + symbol_extractor.SymbolInfosFromBinary, obj_files) + pool.close() + result = [] + for symbol_infos in symbol_infos_nested: + result += symbol_infos + return result + + +class OffsetOrderfileGenerator(object): + """Generates an orderfile from instrumented build offsets. + + The object directory, SymbolOffsetProcessor and dump offsets must all be from + the same build. + """ + def __init__(self, symbol_offset_processor, obj_processor): + """Initialize the generator. + + Args: + symbol_offset_processor (process_profiles.SymbolOffsetProcessor). + obj_processor (ObjectFileProcessor). + """ + self._offset_to_symbols = symbol_offset_processor.OffsetToSymbolsMap() + self._obj_processor = obj_processor + + def GetOrderedSections(self, offsets): + """Get ordered list of sections corresponding to offsets. + + Args: + offsets ([int]) dump offsets, from same build as parameters to __init__. + + Returns: + [str] ordered list of sections suitable for use as an orderfile, or + None if failure. + """ + symbol_to_sections = self._obj_processor.GetSymbolToSectionsMap() + if not symbol_to_sections: + logging.error('No symbol section names found') + return None + unknown_symbol_warnings = cygprofile_utils.WarningCollector(300) + symbol_not_found_errors = cygprofile_utils.WarningCollector( + 300, level=logging.ERROR) + seen_sections = set() + ordered_sections = [] + success = True + for offset in offsets: + try: + symbol_infos = self._SymbolsAtOffset(offset) + for symbol_info in symbol_infos: + if symbol_info.name in symbol_to_sections: + sections = symbol_to_sections[symbol_info.name] + for section in sections: + if not section in seen_sections: + ordered_sections.append(section) + seen_sections.add(section) + else: + unknown_symbol_warnings.Write( + 'No known section for symbol ' + symbol_info.name) + except _SymbolNotFoundException: + symbol_not_found_errors.Write( + 'Did not find function in binary. offset: ' + hex(offset)) + success = False + unknown_symbol_warnings.WriteEnd('no known section for symbol.') + symbol_not_found_errors.WriteEnd('symbol not found in the binary.') + if not success: + return None + return ordered_sections + + def _SymbolsAtOffset(self, offset): + if offset in self._offset_to_symbols: + return self._offset_to_symbols[offset] + elif offset % 2 and (offset - 1) in self._offset_to_symbols: + # On ARM, odd addresses are used to signal thumb instruction. They are + # generated by setting the LSB to 1 (see + # http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0471e/Babfjhia.html). + # TODO(lizeb): Make sure this hack doesn't propagate to other archs. + return self._offset_to_symbols[offset - 1] + else: + raise _SymbolNotFoundException(offset) + + def _ParseLogLines(log_file_lines): """Parses a merged cyglog produced by mergetraces.py. @@ -62,128 +242,6 @@ return call_info -def _GroupLibrarySymbolInfosByOffset(lib_filename): - """Returns a dict {offset: [SymbolInfo]} from a library.""" - symbol_infos = symbol_extractor.SymbolInfosFromBinary(lib_filename) - return symbol_extractor.GroupSymbolInfosByOffset(symbol_infos) - - -class SymbolNotFoundException(Exception): - def __init__(self, value): - super(SymbolNotFoundException, self).__init__(value) - self.value = value - - def __str__(self): - return repr(self.value) - - -def _FindSymbolInfosAtOffset(offset_to_symbol_infos, offset): - """Finds all SymbolInfo at a given offset. - - Args: - offset_to_symbol_infos: {offset: [SymbolInfo]} - offset: offset to look the symbols at - - Returns: - The list of SymbolInfo at the given offset - - Raises: - SymbolNotFoundException if the offset doesn't match any symbol. - """ - if offset in offset_to_symbol_infos: - return offset_to_symbol_infos[offset] - elif offset % 2 and (offset - 1) in offset_to_symbol_infos: - # On ARM, odd addresses are used to signal thumb instruction. They are - # generated by setting the LSB to 1 (see - # http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0471e/Babfjhia.html). - # TODO(lizeb): Make sure this hack doesn't propagate to other archs. - return offset_to_symbol_infos[offset - 1] - else: - raise SymbolNotFoundException(offset) - - -def _GetObjectFileNames(obj_dir): - """Returns the list of object files in a directory.""" - obj_files = [] - for (dirpath, _, filenames) in os.walk(obj_dir): - for file_name in filenames: - if file_name.endswith('.o'): - obj_files.append(os.path.join(dirpath, file_name)) - return obj_files - - -def _AllSymbolInfos(object_filenames): - """Returns a list of SymbolInfo from an iterable of filenames.""" - pool = multiprocessing.Pool() - # Hopefully the object files are in the page cache at this step, so IO should - # not be a problem (hence no concurrency limit on the pool). - symbol_infos_nested = pool.map( - symbol_extractor.SymbolInfosFromBinary, object_filenames) - result = [] - for symbol_infos in symbol_infos_nested: - result += symbol_infos - return result - - -def _SameCtorOrDtorNames(symbol1, symbol2): - """Returns True if two symbols refer to the same constructor or destructor. - - The Itanium C++ ABI specifies dual constructor and destructor - emmission (section 5.1.4.3): - https://refspecs.linuxbase.org/cxxabi-1.83.html#mangling-special - To avoid fully parsing all mangled symbols, a heuristic is used with c++filt. - - Note: some compilers may name generated copies differently. If this becomes - an issue this heuristic will need to be updated. - """ - # Check if this is the understood case of constructor/destructor - # signatures. GCC emits up to three types of constructor/destructors: - # complete, base, and allocating. If they're all the same they'll - # get folded together. - return (re.search('(C[123]|D[012])E', symbol1) and - symbol_extractor.DemangleSymbol(symbol1) == - symbol_extractor.DemangleSymbol(symbol2)) - - -def GetSymbolToSectionsMapFromObjectFiles(obj_dir): - """Scans object files to create a {symbol: linker section(s)} map. - - Args: - obj_dir: The root of the output object file directory, which will be - scanned for .o files to form the mapping. - - Returns: - A map {symbol_name: [section_name1, section_name2...]} - """ - object_files = _GetObjectFileNames(obj_dir) - symbol_to_sections_map = {} - symbol_warnings = cygprofile_utils.WarningCollector(300) - symbol_infos = _AllSymbolInfos(object_files) - for symbol_info in symbol_infos: - symbol = symbol_info.name - if symbol.startswith('.LTHUNK'): - continue - section = symbol_info.section - if ((symbol in symbol_to_sections_map) and - (symbol_info.section not in symbol_to_sections_map[symbol])): - symbol_to_sections_map[symbol].append(section) - - if not _SameCtorOrDtorNames( - symbol, symbol_to_sections_map[symbol][0].lstrip('.text.')): - symbol_warnings.Write('Symbol ' + symbol + - ' unexpectedly in more than one section: ' + - ', '.join(symbol_to_sections_map[symbol])) - elif not section.startswith('.text.'): - symbol_warnings.Write('Symbol ' + symbol + - ' in incorrect section ' + section) - else: - # In most cases we expect just one item in this list, and maybe 4 or so in - # the worst case. - symbol_to_sections_map[symbol] = [section] - symbol_warnings.WriteEnd('bad sections') - return symbol_to_sections_map - - def _WarnAboutDuplicates(offsets): """Warns about duplicate offsets. @@ -204,82 +262,70 @@ return ok -def _OutputOrderfile(offsets, offset_to_symbol_infos, symbol_to_sections_map, - output_file): - """Outputs the orderfile to output_file. +def _ReadReachedOffsets(filename): + """Reads and returns a list of reached offsets.""" + with open(filename, 'r') as f: + offsets = [int(x.rstrip('\n')) for x in f.xreadlines()] + return offsets - Args: - offsets: Iterable of offsets to match to section names - offset_to_symbol_infos: {offset: [SymbolInfo]} - symbol_to_sections_map: {name: [section1, section2]} - output_file: file-like object to write the results to - Returns: - True if all symbols were found in the library. - """ - success = True - unknown_symbol_warnings = cygprofile_utils.WarningCollector(300) - symbol_not_found_errors = cygprofile_utils.WarningCollector( - 300, level=logging.ERROR) - output_sections = set() - for offset in offsets: - try: - symbol_infos = _FindSymbolInfosAtOffset(offset_to_symbol_infos, offset) - for symbol_info in symbol_infos: - if symbol_info.name in symbol_to_sections_map: - sections = symbol_to_sections_map[symbol_info.name] - for section in sections: - if not section in output_sections: - output_file.write(section + '\n') - output_sections.add(section) - else: - unknown_symbol_warnings.Write( - 'No known section for symbol ' + symbol_info.name) - except SymbolNotFoundException: - symbol_not_found_errors.Write( - 'Did not find function in binary. offset: ' + hex(offset)) - success = False - unknown_symbol_warnings.WriteEnd('no known section for symbol.') - symbol_not_found_errors.WriteEnd('symbol not found in the binary.') - return success +def _CreateArgumentParser(): + parser = argparse.ArgumentParser( + description='Creates an orderfile from profiles.') + parser.add_argument('--target-arch', required=False, + choices=['arm', 'arm64', 'x86', 'x86_64', 'x64', 'mips'], + help='The target architecture for libchrome.so') + parser.add_argument('--merged-cyglog', type=str, required=False, + help='Path to the merged cyglog') + parser.add_argument('--reached-offsets', type=str, required=False, + help='Path to the reached offsets') + parser.add_argument('--native-library', type=str, required=True, + help='Path to the unstripped instrumented library') + parser.add_argument('--output', type=str, required=True, + help='Output filename') + return parser def main(): - parser = optparse.OptionParser(usage= - 'usage: %prog [options] <merged_cyglog> <library> <output_filename>') - parser.add_option('--target-arch', action='store', dest='arch', - choices=['arm', 'arm64', 'x86', 'x86_64', 'x64', 'mips'], - help='The target architecture for libchrome.so') - options, argv = parser.parse_args(sys.argv) - if not options.arch: - options.arch = cygprofile_utils.DetectArchitecture() - if len(argv) != 4: - parser.print_help() - return 1 - (log_filename, lib_filename, output_filename) = argv[1:] - symbol_extractor.SetArchitecture(options.arch) + parser = _CreateArgumentParser() + args = parser.parse_args() - obj_dir = cygprofile_utils.GetObjDir(lib_filename) + assert bool(args.merged_cyglog) ^ bool(args.reached_offsets) - log_file_lines = map(string.rstrip, open(log_filename).readlines()) - offsets = _ParseLogLines(log_file_lines) + if not args.target_arch: + args.arch = cygprofile_utils.DetectArchitecture() + symbol_extractor.SetArchitecture(args.target_arch) + + obj_dir = cygprofile_utils.GetObjDir(args.native_library) + + offsets = [] + if args.merged_cyglog: + log_file_lines = map(string.rstrip, open(args.merged_cyglog).readlines()) + offsets = _ParseLogLines(log_file_lines) + else: + offsets = _ReadReachedOffsets(args.reached_offsets) + assert offsets _WarnAboutDuplicates(offsets) - offset_to_symbol_infos = _GroupLibrarySymbolInfosByOffset(lib_filename) - symbol_to_sections_map = GetSymbolToSectionsMapFromObjectFiles(obj_dir) + generator = OffsetOrderfileGenerator( + process_profiles.SymbolOffsetProcessor(args.native_library), + ObjectFileProcessor(obj_dir)) + + ordered_sections = generator.GetOrderedSections(offsets) + if ordered_sections is None: + return 1 success = False temp_filename = None output_file = None try: - (fd, temp_filename) = tempfile.mkstemp(dir=os.path.dirname(output_filename)) + (fd, temp_filename) = tempfile.mkstemp(dir=os.path.dirname(args.output)) output_file = os.fdopen(fd, 'w') - ok = _OutputOrderfile( - offsets, offset_to_symbol_infos, symbol_to_sections_map, output_file) + output_file.write('\n'.join(ordered_sections)) output_file.close() - os.rename(temp_filename, output_filename) + os.rename(temp_filename, args.output) temp_filename = None - success = ok + success = True finally: if output_file: output_file.close()
diff --git a/tools/cygprofile/cyglog_to_orderfile_unittest.py b/tools/cygprofile/cyglog_to_orderfile_unittest.py index 9ea0d18..37722570 100755 --- a/tools/cygprofile/cyglog_to_orderfile_unittest.py +++ b/tools/cygprofile/cyglog_to_orderfile_unittest.py
@@ -3,12 +3,19 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import collections +import os +import re +import sys import unittest import cyglog_to_orderfile -import os +import process_profiles import symbol_extractor -import sys + +import test_utils +from test_utils import SimpleTestSymbol + sys.path.insert( 0, os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, @@ -17,7 +24,58 @@ import symbol +# Used for fake demangling on bots where c++filt does not exist. +CTOR_PATTERN = re.compile(r'EEEC[12]Ev$') +CTOR_REPLACEMENT = 'EEECEv' +DTOR_PATTERN = re.compile(r'EEED[12]Ev$') +DTOR_REPLACEMENT = 'EEEDEv' + + +SectionTestSymbol = collections.namedtuple( + 'SectionTestSymbol', ['name', 'section']) + + +class TestObjectFileProcessor(cyglog_to_orderfile.ObjectFileProcessor): + def __init__(self, symbol_to_sections): + super(TestObjectFileProcessor, self).__init__(None) + self._symbol_to_sections_map = symbol_to_sections + + class TestCyglogToOrderfile(unittest.TestCase): + def setUp(self): + self._old_demangle = None + if not os.path.exists(symbol.ToolPath('c++filt')): + print 'Using fake demangling due to missing c++filt binary' + self._old_demangle = symbol_extractor.DemangleSymbol + symbol_extractor.DemangleSymbol = _FakeDemangle + + def tearDown(self): + if self._old_demangle is not None: + symbol_extractor.DemangleSymbol = self._old_demangle + + def assertDictWithUnorderedListEqual(self, expected, observed): + unexpected = set() + missing = set() + for i in expected: + if i not in observed: + missing.add(i) + else: + try: + self.assertListEqual(sorted(expected[i]), sorted(observed[i])) + except self.failureException, e: + raise self.failureException('For key {}: {}'.format(i, e)) + for i in observed: + # All i that are in expected have already been tested. + if i not in expected: + unexpected.add(i) + failure_items = [] + if unexpected: + failure_items.append('Unexpected keys: {}'.format(' '.join(unexpected))) + if missing: + failure_items.append('Missing keys: {}'.format(' '.join(missing))) + if failure_items: + raise self.failureException('\n'.join(failure_items)) + def testParseLogLines(self): lines = """5086e000-52e92000 r-xp 00000000 b3:02 51276 libchromeview.so secs usecs pid:threadid func @@ -29,84 +87,105 @@ self.assertListEqual( offsets, [0x509e105c - 0x5086e000, 0x509e0eb4 - 0x5086e000]) - def testFindSymbolInfosAtOffsetExactMatch(self): - offset_map = {0x10: [symbol_extractor.SymbolInfo( - name='Symbol', offset=0x10, size=0x13, section='.text')]} - functions = cyglog_to_orderfile._FindSymbolInfosAtOffset(offset_map, 0x10) - self.assertEquals(len(functions), 1) - self.assertEquals(functions[0], offset_map[0x10][0]) - - def testFindSymbolInfosAtOffsetInexactMatch(self): - offset_map = {0x10: [symbol_extractor.SymbolInfo( - name='Symbol', offset=0x10, size=0x13, section='.text')]} - functions = cyglog_to_orderfile._FindSymbolInfosAtOffset(offset_map, 0x11) - self.assertEquals(len(functions), 1) - self.assertEquals(functions[0], offset_map[0x10][0]) - - def testFindSymbolInfosAtOffsetNoMatch(self): - offset_map = {0x10: [symbol_extractor.SymbolInfo( - name='Symbol', offset=0x10, size=0x13, section='.text')]} - self.assertRaises( - cyglog_to_orderfile.SymbolNotFoundException, - cyglog_to_orderfile._FindSymbolInfosAtOffset, offset_map, 0x12) - def testWarnAboutDuplicates(self): offsets = [0x1, 0x2, 0x3] self.assertTrue(cyglog_to_orderfile._WarnAboutDuplicates(offsets)) offsets.append(0x1) self.assertFalse(cyglog_to_orderfile._WarnAboutDuplicates(offsets)) + def testSymbolsAtOffsetExactMatch(self): + symbol_infos = [SimpleTestSymbol('1', 0x10, 0x13)] + generator = cyglog_to_orderfile.OffsetOrderfileGenerator( + test_utils.TestSymbolOffsetProcessor(symbol_infos), None) + syms = generator._SymbolsAtOffset(0x10) + self.assertEquals(1, len(syms)) + self.assertEquals(symbol_infos[0], syms[0]) + + def testSymbolsAtOffsetInexectMatch(self): + symbol_infos = [SimpleTestSymbol('1', 0x10, 0x13)] + generator = cyglog_to_orderfile.OffsetOrderfileGenerator( + test_utils.TestSymbolOffsetProcessor(symbol_infos), None) + syms = generator._SymbolsAtOffset(0x11) + self.assertEquals(1, len(syms)) + self.assertEquals(symbol_infos[0], syms[0]) + def testSameCtorOrDtorNames(self): - if not os.path.exists(symbol.ToolPath('c++filt')): - print 'Skipping test dependent on missing c++filt binary.' - return - self.assertTrue(cyglog_to_orderfile._SameCtorOrDtorNames( + same_name = cyglog_to_orderfile.ObjectFileProcessor._SameCtorOrDtorNames + self.assertTrue(same_name( '_ZNSt3__119istreambuf_iteratorIcNS_11char_traitsIcEEEC1Ev', '_ZNSt3__119istreambuf_iteratorIcNS_11char_traitsIcEEEC2Ev')) - self.assertTrue(cyglog_to_orderfile._SameCtorOrDtorNames( + self.assertTrue(same_name( '_ZNSt3__119istreambuf_iteratorIcNS_11char_traitsIcEEED1Ev', '_ZNSt3__119istreambuf_iteratorIcNS_11char_traitsIcEEED2Ev')) - self.assertFalse(cyglog_to_orderfile._SameCtorOrDtorNames( + self.assertFalse(same_name( '_ZNSt3__119istreambuf_iteratorIcNS_11char_traitsIcEEEC1Ev', '_ZNSt3__119foo_iteratorIcNS_11char_traitsIcEEEC1Ev')) - self.assertFalse(cyglog_to_orderfile._SameCtorOrDtorNames( + self.assertFalse(same_name( '_ZNSt3__119istreambuf_iteratorIcNS_11char_traitsIcEEE', '_ZNSt3__119istreambuf_iteratorIcNS_11char_traitsIcEEE')) + def testGetSymbolToSectionsMap(self): + processor = cyglog_to_orderfile.ObjectFileProcessor(None) + processor._GetAllSymbolInfos = lambda: [ + SectionTestSymbol('.LTHUNK.foobar', 'unused'), + SectionTestSymbol('_Znwj', '.text._Znwj'), + SectionTestSymbol( # Ctor/Dtor same name. + '_ZNSt3__119istreambuf_iteratorIcNS_11char_traitsIcEEED1Ev', + '.text._ZNSt3__119istreambuf_iteratorIcNS_11char_traitsIcEEED1Ev'), + SectionTestSymbol( + '_ZNSt3__119istreambuf_iteratorIcNS_11char_traitsIcEEED1Ev', + '.text._ZNSt3__119istreambuf_iteratorIcNS_11char_traitsIcEEED2Ev'), + SectionTestSymbol( # Ctor/Dtor different name. + '_ZNSt3__119istreambuf2_iteratorIcNS_11char_traitsIcEEEC1Ev', + ('.text. _ZNSt3__119istreambuf2_iteratorIcNS_11char_' + 'traitsIcEEEC1Ev')), + SectionTestSymbol( + '_ZNSt3__119istreambuf2_iteratorIcNS_11char_traitsIcEEEC1Ev', + '.text._ZNSt3__119foo_iteratorIcNS_11char_traitsIcEEEC1Ev'), + SectionTestSymbol('_AssemblyFunction', '.text'), + SectionTestSymbol('_UnknownSection', '.surprise._UnknownSection'), + SectionTestSymbol('_Znwj', '.text._another_section_for_Znwj')] + self.assertDictWithUnorderedListEqual( + {'_Znwj': ['.text._Znwj', '.text._another_section_for_Znwj'], + # Ctor/Dtor same name. + '_ZNSt3__119istreambuf_iteratorIcNS_11char_traitsIcEEED1Ev': + ['.text._ZNSt3__119istreambuf_iteratorIcNS_11char_traitsIcEEED1Ev', + '.text._ZNSt3__119istreambuf_iteratorIcNS_11char_traitsIcEEED2Ev'], + # Ctor/Dtor different name; a warning is emitted but the sections are + # still added to the map. + '_ZNSt3__119istreambuf2_iteratorIcNS_11char_traitsIcEEEC1Ev': + ['.text. _ZNSt3__119istreambuf2_iteratorIcNS_11char_traitsIcEEEC1Ev', + '.text._ZNSt3__119foo_iteratorIcNS_11char_traitsIcEEEC1Ev'], + }, + processor.GetSymbolToSectionsMap()) + def testOutputOrderfile(self): - class FakeOutputFile(object): - def __init__(self): - self.writes = [] - - def write(self, data): - self.writes.append(data) - # One symbol not matched, one with an odd address, one regularly matched # And two symbols aliased to the same address - offsets = [0x12, 0x17] - offset_to_symbol_infos = { - 0x10: [symbol_extractor.SymbolInfo( - name='Symbol', offset=0x10, size=0x13, section='dummy')], - 0x12: [symbol_extractor.SymbolInfo( - name='Symbol2', offset=0x12, size=0x13, section='dummy')], - 0x16: [symbol_extractor.SymbolInfo( - name='Symbol3', offset=0x16, size=0x13, section='dummy'), - symbol_extractor.SymbolInfo( - name='Symbol32', offset=0x16, size=0x13, section='dummy'),]} - symbol_to_sections_map = { + symbols = [SimpleTestSymbol('Symbol', 0x10, 0x100), + SimpleTestSymbol('Symbol2', 0x12, 0x100), + SimpleTestSymbol('Symbol3', 0x16, 0x100), + SimpleTestSymbol('Symbol3.2', 0x16, 0x0)] + generator = cyglog_to_orderfile.OffsetOrderfileGenerator( + test_utils.TestSymbolOffsetProcessor(symbols), + TestObjectFileProcessor({ 'Symbol': ['.text.Symbol'], 'Symbol2': ['.text.Symbol2', '.text.hot.Symbol2'], 'Symbol3': ['.text.Symbol3'], - 'Symbol32': ['.text.Symbol32']} - fake_output = FakeOutputFile() - cyglog_to_orderfile._OutputOrderfile( - offsets, offset_to_symbol_infos, symbol_to_sections_map, fake_output) - expected = """.text.Symbol2 -.text.hot.Symbol2 -.text.Symbol3 -.text.Symbol32 -""" - self.assertEquals(expected, ''.join(fake_output.writes)) + 'Symbol3.2': ['.text.Symbol3.2']})) + ordered_sections = generator.GetOrderedSections([0x12, 0x17]) + self.assertListEqual( + ['.text.Symbol2', + '.text.hot.Symbol2', + '.text.Symbol3', + '.text.Symbol3.2'], + ordered_sections) + + +def _FakeDemangle(mangled): + unmangled = CTOR_PATTERN.sub(CTOR_REPLACEMENT, mangled) + unmangled = DTOR_PATTERN.sub(DTOR_REPLACEMENT, unmangled) + return unmangled if __name__ == '__main__':
diff --git a/tools/cygprofile/delayed_dumper.cc b/tools/cygprofile/delayed_dumper.cc new file mode 100644 index 0000000..513b6a5 --- /dev/null +++ b/tools/cygprofile/delayed_dumper.cc
@@ -0,0 +1,54 @@ +// Copyright 2017 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 <time.h> +#include <unistd.h> + +#include <thread> + +#include "base/android/library_loader/anchor_functions.h" +#include "base/logging.h" +#include "build/build_config.h" +#include "tools/cygprofile/lightweight_cygprofile.h" + +#if !defined(ARCH_CPU_ARMEL) +#error Only supported on ARM. +#endif // !defined(ARCH_CPU_ARMEL) + +namespace cygprofile { +namespace { + +// Disables the recording of addresses after |kDelayInSeconds| and dumps the +// result to a file. +class DelayedDumper { + public: + DelayedDumper() { + // Not using base::TimeTicks() to not call too many base:: symbol that would + // pollute the reached symbols dumps. + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts)) + PLOG(FATAL) << "clock_gettime."; + uint64_t start_ns_since_epoch = + static_cast<uint64_t>(ts.tv_sec) * 1000 * 1000 * 1000 + ts.tv_nsec; + int pid = getpid(); + + std::thread([pid, start_ns_since_epoch]() { + sleep(kInitialDelayInSeconds); + while (!SwitchToNextPhaseOrDump(pid, start_ns_since_epoch)) + sleep(kDelayInSeconds); + }) + .detach(); + } + + static constexpr int kDelayInSeconds = 30; + static constexpr int kInitialDelayInSeconds = + kPhases == 1 ? kDelayInSeconds : 5; +}; + +// Static initializer on purpose. Will disable instrumentation after +// |kDelayInSeconds|. +DelayedDumper g_dump_later; + +} // namespace +} // namespace cygprofile
diff --git a/tools/cygprofile/lightweight_cygprofile.cc b/tools/cygprofile/lightweight_cygprofile.cc new file mode 100644 index 0000000..7377260 --- /dev/null +++ b/tools/cygprofile/lightweight_cygprofile.cc
@@ -0,0 +1,228 @@ +// Copyright (c) 2017 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 "tools/cygprofile/lightweight_cygprofile.h" + +#include <atomic> +#include <cstdio> +#include <cstring> +#include <string> +#include <vector> + +#include "base/android/library_loader/anchor_functions.h" +#include "base/files/file.h" +#include "base/format_macros.h" +#include "base/logging.h" +#include "base/macros.h" +#include "base/strings/stringprintf.h" +#include "build/build_config.h" + +#if !defined(ARCH_CPU_ARMEL) +#error Only supported on ARM. +#endif // !defined(ARCH_CPU_ARMEL) + +namespace cygprofile { +namespace { + +// These are large overestimates, which is not an issue, as the data is +// allocated in .bss, and on linux doesn't take any actual memory when it's not +// touched. +constexpr size_t kBitfieldSize = 1 << 22; +constexpr size_t kMaxTextSizeInBytes = kBitfieldSize * (4 * 32); +constexpr size_t kMaxElements = 1 << 20; + +// Data required to log reached offsets. +struct LogData { + std::atomic<uint32_t> offsets[kBitfieldSize]; + std::atomic<size_t> ordered_offsets[kMaxElements]; + std::atomic<size_t> index; +}; + +LogData g_data[kPhases]; +std::atomic<int> g_data_index; + +// |RecordAddress()| adds an element to a concurrent bitset and to a concurrent +// append-only list of offsets. +// +// Ordering: +// Two consecutive calls to |RecordAddress()| from the same thread will be +// ordered in the same way in the result, as written by +// |StopAndDumpToFile()|. The result will contain exactly one instance of each +// unique offset relative to |kStartOfText| passed to |RecordAddress()|. +// +// Implementation: +// The "set" part is implemented with a bitfield, |g_offset|. The insertion +// order is recorded in |g_ordered_offsets|. +// This is not a class to make sure there isn't a static constructor, as it +// would cause issue with an instrumented static constructor calling this code. +// +// Limitations: +// - Only records offsets to addresses between |kStartOfText| and |kEndOfText|. +// - Capacity of the set is limited by |kMaxElements|. +// - Some insertions at the end of collection may be lost. + +// Records that |address| has been reached, if recording is enabled. +// To avoid any risk of infinite recursion, this *must* *never* call any +// instrumented function. +template <bool for_testing> +void RecordAddress(size_t address) { + int index = g_data_index.load(std::memory_order_relaxed); + if (index >= kPhases) + return; + + const size_t start = + for_testing ? kStartOfTextForTesting : base::android::kStartOfText; + const size_t end = + for_testing ? kEndOfTextForTesting : base::android::kEndOfText; + if (UNLIKELY(address < start || address > end)) { + Disable(); + // If the start and end addresses are set incorrectly, this code path is + // likely happening during a static initializer. Logging at this time is + // prone to deadlock. By crashing immediately we at least have a chance to + // get a stack trace from the system to give some clue about the nature of + // the problem. + IMMEDIATE_CRASH(); + } + + size_t offset = address - start; + static_assert(sizeof(int) == 4, + "Collection and processing code assumes that sizeof(int) == 4"); + size_t offset_index = offset / 4; + + auto* offsets = g_data[index].offsets; + // Atomically set the corresponding bit in the array. + std::atomic<uint32_t>* element = offsets + (offset_index / 32); + // First, a racy check. This saves a CAS if the bit is already set, and + // allows the cache line to remain shared acoss CPUs in this case. + uint32_t value = element->load(std::memory_order_relaxed); + uint32_t mask = 1 << (offset_index % 32); + if (value & mask) + return; + + auto before = element->fetch_or(mask, std::memory_order_relaxed); + if (before & mask) + return; + + // We were the first one to set the element, record it in the ordered + // elements list. + // Use relaxed ordering, as the value is not published, or used for + // synchronization. + auto* ordered_offsets = g_data[index].ordered_offsets; + auto& ordered_offsets_index = g_data[index].index; + size_t insertion_index = + ordered_offsets_index.fetch_add(1, std::memory_order_relaxed); + if (UNLIKELY(insertion_index >= kMaxElements)) { + Disable(); + LOG(FATAL) << "Too many reached offsets"; + } + ordered_offsets[insertion_index].store(offset, std::memory_order_relaxed); +} + +void DumpToFile(const base::FilePath& path, const LogData& data) { + auto file = + base::File(path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); + if (!file.IsValid()) { + PLOG(ERROR) << "Could not open " << path; + return; + } + + size_t count = data.index - 1; + for (size_t i = 0; i < count; i++) { + // |g_ordered_offsets| is initialized to 0, so a 0 in the middle of it + // indicates a case where the index was incremented, but the write is not + // visible in this thread yet. Safe to skip, also because the function at + // the start of text is never called. + auto offset = data.ordered_offsets[i].load(std::memory_order_relaxed); + if (!offset) + continue; + auto offset_str = base::StringPrintf("%" PRIuS "\n", offset); + file.WriteAtCurrentPos(offset_str.c_str(), + static_cast<int>(offset_str.size())); + } +} + +// Stops recording, and outputs the data to |path|. +void StopAndDumpToFile(int pid, uint64_t start_ns_since_epoch) { + Disable(); + + for (int phase = 0; phase < kPhases; phase++) { + auto path = base::StringPrintf( + "/data/local/tmp/chrome/cyglog/" + "cygprofile-instrumented-code-hitmap-%d-%" PRIu64 ".txt_%d", + pid, start_ns_since_epoch, phase); + DumpToFile(base::FilePath(path), g_data[phase]); + } +} + +} // namespace + +void Disable() { + g_data_index.store(kPhases, std::memory_order_relaxed); + std::atomic_thread_fence(std::memory_order_seq_cst); +} + +void SanityChecks() { + CHECK_LT(base::android::kEndOfText - base::android::kStartOfText, + kMaxTextSizeInBytes); + CHECK(base::android::IsOrderingSane()); +} + +bool SwitchToNextPhaseOrDump(int pid, uint64_t start_ns_since_epoch) { + int before = g_data_index.fetch_add(1, std::memory_order_relaxed); + if (before + 1 == kPhases) { + StopAndDumpToFile(pid, start_ns_since_epoch); + return true; + } + return false; +} + +void ResetForTesting() { + Disable(); + g_data_index = 0; + for (int i = 0; i < kPhases; i++) { + memset(reinterpret_cast<uint32_t*>(g_data[i].offsets), 0, + sizeof(uint32_t) * kBitfieldSize); + memset(reinterpret_cast<uint32_t*>(g_data[i].ordered_offsets), 0, + sizeof(uint32_t) * kMaxElements); + g_data[i].index.store(0); + } +} + +void RecordAddressForTesting(size_t address) { + return RecordAddress<true>(address); +} + +std::vector<size_t> GetOrderedOffsetsForTesting() { + std::vector<size_t> result; + size_t max_index = g_data[0].index.load(std::memory_order_relaxed); + for (size_t i = 0; i < max_index; ++i) { + auto value = g_data[0].ordered_offsets[i].load(std::memory_order_relaxed); + if (value) + result.push_back(value); + } + return result; +} + +} // namespace cygprofile + +extern "C" { + +// Since this function relies on the return address, if it's not inlined and +// __cyg_profile_func_enter() is called below, then the return address will +// be inside __cyg_profile_func_enter(). To prevent that, force inlining. +// We cannot use ALWAYS_INLINE from src/base/compiler_specific.h, as it doesn't +// always map to always_inline, for instance when NDEBUG is not defined. +__attribute__((__always_inline__)) void __cyg_profile_func_enter_bare() { + cygprofile::RecordAddress<false>( + reinterpret_cast<size_t>(__builtin_return_address(0))); +} + +void __cyg_profile_func_enter(void* unused1, void* unused2) { + // Requires __always_inline__ on __cyg_profile_func_enter_bare(), see above. + __cyg_profile_func_enter_bare(); +} + +void __cyg_profile_func_exit(void* unused1, void* unused2) {} + +} // extern "C"
diff --git a/tools/cygprofile/lightweight_cygprofile.h b/tools/cygprofile/lightweight_cygprofile.h new file mode 100644 index 0000000..2cabd2a --- /dev/null +++ b/tools/cygprofile/lightweight_cygprofile.h
@@ -0,0 +1,37 @@ +// Copyright 2017 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. + +#ifndef TOOLS_CYGPROFILE_LIGHTWEIGHT_CYGPROFILE_H_ +#define TOOLS_CYGPROFILE_LIGHTWEIGHT_CYGPROFILE_H_ + +#include <cstdint> +#include <vector> + +namespace cygprofile { +constexpr int kPhases = 1; +constexpr size_t kStartOfTextForTesting = 1000; +constexpr size_t kEndOfTextForTesting = kStartOfTextForTesting + 1000 * 1000; + +// Stop recording. +void Disable(); + +// CHECK()s that the offsets are correctly set up. +void SanityChecks(); + +// Switches to the next recording phase. If called from the last phase, dumps +// the data to disk, and returns |true|. |pid| is the current process pid, and +// |start_ns_since_epoch| the process start timestamp. +bool SwitchToNextPhaseOrDump(int pid, uint64_t start_ns_since_epoch); + +// Record an |address|, if recording is enabled. Only for testing. +void RecordAddressForTesting(size_t address); + +// Resets the state. Only for testing. +void ResetForTesting(); + +// Returns an ordered list of reached offsets. Only for testing. +std::vector<size_t> GetOrderedOffsetsForTesting(); +} // namespace cygprofile + +#endif // TOOLS_CYGPROFILE_LIGHTWEIGHT_CYGPROFILE_H_
diff --git a/tools/cygprofile/lightweight_cygprofile_perftest.cc b/tools/cygprofile/lightweight_cygprofile_perftest.cc new file mode 100644 index 0000000..689dd609 --- /dev/null +++ b/tools/cygprofile/lightweight_cygprofile_perftest.cc
@@ -0,0 +1,123 @@ +// Copyright 2017 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 "tools/cygprofile/lightweight_cygprofile.h" + +#include <thread> + +#include "base/android/library_loader/anchor_functions.h" +#include "base/strings/stringprintf.h" +#include "base/time/time.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/perf/perf_test.h" + +namespace cygprofile { + +namespace { + +// Records |addresses_count| distinct addresses |iterations| times, in +// |threads|. +void RunBenchmark(int iterations, int addresses_count, int threads) { + auto iterate = [iterations, addresses_count]() { + for (int i = 0; i < iterations; i++) { + for (size_t addr = kStartOfTextForTesting; + addr < static_cast<size_t>(addresses_count); addr += sizeof(int)) { + RecordAddressForTesting(addr); + } + } + }; + if (threads != 1) { + for (int i = 0; i < threads - 1; ++i) + std::thread(iterate).detach(); + } + auto tick = base::TimeTicks::Now(); + iterate(); + auto tock = base::TimeTicks::Now(); + double nanos = static_cast<double>((tock - tick).InNanoseconds()); + auto ns_per_call = + nanos / (iterations * static_cast<double>(addresses_count)); + auto modifier = + base::StringPrintf("_%d_%d_%d", iterations, addresses_count, threads); + perf_test::PrintResult("RecordAddressCostPerCall", modifier, "", ns_per_call, + "ns", true); +} + +} // namespace + +class LightweightCygprofileTest : public ::testing::Test { + protected: + void SetUp() override { ResetForTesting(); } +}; + +TEST_F(LightweightCygprofileTest, RecordOffset) { + size_t first = 1234, second = 1456; + RecordAddressForTesting(first); + RecordAddressForTesting(second); + RecordAddressForTesting(first); // No duplicates. + RecordAddressForTesting(first + 1); // 4 bytes granularity. + Disable(); + + auto reached = GetOrderedOffsetsForTesting(); + EXPECT_EQ(2UL, reached.size()); + EXPECT_EQ(first - kStartOfTextForTesting, reached[0]); + EXPECT_EQ(second - kStartOfTextForTesting, reached[1]); +} + +TEST_F(LightweightCygprofileTest, RecordingStops) { + size_t first = 1234, second = 1456, third = 1789; + RecordAddressForTesting(first); + RecordAddressForTesting(second); + Disable(); + RecordAddressForTesting(third); + + auto reached = GetOrderedOffsetsForTesting(); + ASSERT_EQ(2UL, reached.size()); + ASSERT_EQ(first - kStartOfTextForTesting, reached[0]); + ASSERT_EQ(second - kStartOfTextForTesting, reached[1]); +} + +TEST_F(LightweightCygprofileTest, OutOfBounds) { + EXPECT_DEATH(RecordAddressForTesting(kEndOfTextForTesting + 100), ""); + EXPECT_DEATH(RecordAddressForTesting(kStartOfTextForTesting - 100), ""); +} + +TEST(LightweightCygprofilePerfTest, RecordAddress_10_10000) { + RunBenchmark(10, 10000, 1); +} + +TEST(LightweightCygprofilePerfTest, RecordAddress_100_10000) { + RunBenchmark(100, 10000, 1); +} + +TEST(LightweightCygprofilePerfTest, RecordAddress_10_100000) { + RunBenchmark(10, 100000, 1); +} + +TEST(LightweightCygprofilePerfTest, RecordAddress_100_100000) { + RunBenchmark(100, 100000, 1); +} + +TEST(LightweightCygprofilePerfTest, RecordAddress_1000_100000_2) { + RunBenchmark(1000, 100000, 2); +} + +TEST(LightweightCygprofilePerfTest, RecordAddress_1000_100000_3) { + RunBenchmark(1000, 100000, 3); +} + +TEST(LightweightCygprofilePerfTest, RecordAddress_1000_100000_4) { + RunBenchmark(1000, 100000, 4); +} + +TEST(LightweightCygprofilePerfTest, RecordAddress_1000_100000_6) { + RunBenchmark(1000, 100000, 6); +} + +} // namespace cygprofile + +// Custom runner implementation since base's one requires JNI on Android. +int main(int argc, char** argv) { + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +}
diff --git a/tools/cygprofile/memory_top_10_mobile_000.wprgo.sha1 b/tools/cygprofile/memory_top_10_mobile_000.wprgo.sha1 new file mode 100644 index 0000000..f100338 --- /dev/null +++ b/tools/cygprofile/memory_top_10_mobile_000.wprgo.sha1
@@ -0,0 +1 @@ +254c66be2ae74962a2e4d6a813af6f43f86c708a \ No newline at end of file
diff --git a/tools/cygprofile/orderfile_generator_backend.py b/tools/cygprofile/orderfile_generator_backend.py new file mode 100755 index 0000000..147a067 --- /dev/null +++ b/tools/cygprofile/orderfile_generator_backend.py
@@ -0,0 +1,830 @@ +#!/usr/bin/env python +# Copyright (c) 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. + +""" A utility to generate an up-to-date orderfile. + +The orderfile is used by the linker to order text sections such that the +sections are placed consecutively in the order specified. This allows us +to page in less code during start-up. + +Example usage: + tools/cygprofile/orderfile_generator_backend.py -l 20 -j 1000 --use-goma \ + --target-arch=arm +""" + +import argparse +import hashlib +import json +import logging +import os +import re +import shutil +import subprocess +import sys +import tempfile +import time + +import cygprofile_utils +import patch_orderfile +import process_profiles +import profile_android_startup +import symbol_extractor + + +_SRC_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), + os.pardir, os.pardir) +sys.path.append(os.path.join(_SRC_PATH, 'build', 'android')) +import devil_chromium +from pylib import constants + + +# Needs to happen early for GetBuildType()/GetOutDirectory() to work correctly +constants.SetBuildType('Release') + + +class CommandError(Exception): + """Indicates that a dispatched shell command exited with a non-zero status.""" + + def __init__(self, value): + super(CommandError, self).__init__() + self.value = value + + def __str__(self): + return repr(self.value) + + +def _GenerateHash(file_path): + """Calculates and returns the hash of the file at file_path.""" + sha1 = hashlib.sha1() + with open(file_path, 'rb') as f: + while True: + # Read in 1mb chunks, so it doesn't all have to be loaded into memory. + chunk = f.read(1024 * 1024) + if not chunk: + break + sha1.update(chunk) + return sha1.hexdigest() + + +def _GetFileExtension(file_name): + """Calculates the file extension from a file name. + + Args: + file_name: The source file name. + Returns: + The part of file_name after the dot (.) or None if the file has no + extension. + Examples: /home/user/foo.bar -> bar + /home/user.name/foo -> None + /home/user/.foo -> None + /home/user/foo.bar.baz -> baz + """ + file_name_parts = os.path.basename(file_name).split('.') + if len(file_name_parts) > 1: + return file_name_parts[-1] + else: + return None + + +def _StashOutputDirectory(buildpath): + """Takes the output directory and stashes it in the default output directory. + + This allows it to be used for incremental builds next time (after unstashing) + by keeping it in a place that isn't deleted normally, while also ensuring + that it is properly clobbered when appropriate. + + This is a dirty hack to deal with the needs of clobbering while also handling + incremental builds and the hardcoded relative paths used in some of the + project files. + + Args: + buildpath: The path where the building happens. If this corresponds to the + default output directory, no action is taken. + """ + if os.path.abspath(buildpath) == os.path.abspath(os.path.dirname( + constants.GetOutDirectory())): + return + name = os.path.basename(buildpath) + stashpath = os.path.join(constants.GetOutDirectory(), name) + if not os.path.exists(buildpath): + return + if os.path.exists(stashpath): + shutil.rmtree(stashpath, ignore_errors=True) + shutil.move(buildpath, stashpath) + + +def _UnstashOutputDirectory(buildpath): + """Inverse of _StashOutputDirectory. + + Moves the output directory stashed within the default output directory + (out/Release) to the position where the builds can actually happen. + + This is a dirty hack to deal with the needs of clobbering while also handling + incremental builds and the hardcoded relative paths used in some of the + project files. + + Args: + buildpath: The path where the building happens. If this corresponds to the + default output directory, no action is taken. + """ + if os.path.abspath(buildpath) == os.path.abspath(os.path.dirname( + constants.GetOutDirectory())): + return + name = os.path.basename(buildpath) + stashpath = os.path.join(constants.GetOutDirectory(), name) + if not os.path.exists(stashpath): + return + if os.path.exists(buildpath): + shutil.rmtree(buildpath, ignore_errors=True) + shutil.move(stashpath, buildpath) + + +def _EnsureOrderfileStartsWithAnchorSection(filename): + """Ensures that the orderfile starts with the right anchor symbol. + + This changes the orderfile, if required. + + Args: + filename: (str) Path to the orderfile. + """ + anchor_section = '.text.dummy_function_to_anchor_text' + with open(filename, 'r') as f: + if f.readline().strip() == anchor_section: + return + try: + f = tempfile.NamedTemporaryFile(dir=os.path.dirname(filename), delete=False) + f.write(anchor_section + '\n') + with open(filename, 'r') as orderfile_file: + for line in orderfile_file: + f.write(line + '\n') + f.close() + os.rename(f.name, filename) + finally: + if os.path.exists(f.name): + os.remove(f.name) + + +class StepRecorder(object): + """Records steps and timings.""" + + def __init__(self, buildbot): + self.timings = [] + self._previous_step = ('', 0.0) + self._buildbot = buildbot + self._error_recorded = False + + def BeginStep(self, name): + """Marks a beginning of the next step in the script. + + On buildbot, this prints a specially formatted name that will show up + in the waterfall. Otherwise, just prints the step name. + + Args: + name: The name of the step. + """ + self.EndStep() + self._previous_step = (name, time.time()) + print 'Running step: ', name + + def EndStep(self): + """Records successful completion of the current step. + + This is optional if the step is immediately followed by another BeginStep. + """ + if self._previous_step[0]: + elapsed = time.time() - self._previous_step[1] + print 'Step %s took %f seconds' % (self._previous_step[0], elapsed) + self.timings.append((self._previous_step[0], elapsed)) + + self._previous_step = ('', 0.0) + + def FailStep(self, message=None): + """Marks that a particular step has failed. + + On buildbot, this will mark the current step as failed on the waterfall. + Otherwise we will just print an optional failure message. + + Args: + message: An optional explanation as to why the step failed. + """ + print 'STEP FAILED!!' + if message: + print message + self._error_recorded = True + self.EndStep() + + def ErrorRecorded(self): + """True if FailStep has been called.""" + return self._error_recorded + + def RunCommand(self, cmd, cwd=constants.DIR_SOURCE_ROOT, raise_on_error=True, + stdout=None): + """Execute a shell command. + + Args: + cmd: A list of command strings. + cwd: Directory in which the command should be executed, defaults to script + location if not specified. + raise_on_error: If true will raise a CommandError if the call doesn't + succeed and mark the step as failed. + stdout: A file to redirect stdout for the command to. + + Returns: + The process's return code. + + Raises: + CommandError: An error executing the specified command. + """ + print 'Executing %s in %s' % (' '.join(cmd), cwd) + process = subprocess.Popen(cmd, stdout=stdout, cwd=cwd, env=os.environ) + process.wait() + if raise_on_error and process.returncode != 0: + self.FailStep() + raise CommandError('Exception executing command %s' % ' '.join(cmd)) + return process.returncode + + +class ClankCompiler(object): + """Handles compilation of clank.""" + + def __init__(self, out_dir, step_recorder, arch, jobs, max_load, use_goma, + goma_dir, lightweight_instrumentation): + self._out_dir = out_dir + self._step_recorder = step_recorder + self._arch = arch + self._jobs = jobs + self._max_load = max_load + self._use_goma = use_goma + self._goma_dir = goma_dir + self._lightweight_instrumentation = lightweight_instrumentation + lib_chrome_so_dir = 'lib.unstripped' + self.lib_chrome_so = os.path.join( + self._out_dir, 'Release', lib_chrome_so_dir, 'libchrome.so') + self.chrome_apk = os.path.join( + self._out_dir, 'Release', 'apks', 'Chrome.apk') + + def Build(self, instrumented, target): + """Builds the provided ninja target with or without order_profiling on. + + Args: + instrumented: (bool) Whether we want to build an instrumented binary. + target: (str) The name of the ninja target to build. + """ + self._step_recorder.BeginStep('Compile %s' % target) + + # Set the "Release Official" flavor, the parts affecting performance. + args = [ + 'is_chrome_branded=true', + 'is_debug=false', + 'is_official_build=true', + # We have to build with no symbols if profiling and minimal symbols + # otherwise for libchrome.so to fit under the 4 GB limit. + # crbug.com/574476 + 'symbol_level=' + ('0' if instrumented else '1'), + 'target_cpu="' + self._arch + '"', + 'target_os="android"', + 'use_goma=' + str(self._use_goma).lower(), + 'use_order_profiling=' + str(instrumented).lower(), + ] + if instrumented and self._lightweight_instrumentation: + args.append('use_lightweight_order_profiling=true') + if self._goma_dir: + args += ['goma_dir="%s"' % self._goma_dir] + + self._step_recorder.RunCommand( + ['gn', 'gen', os.path.join(self._out_dir, 'Release'), + '--args=' + ' '.join(args)]) + + self._step_recorder.RunCommand( + ['ninja', '-C', os.path.join(self._out_dir, 'Release'), + '-j' + str(self._jobs), '-l' + str(self._max_load), target]) + + def CompileChromeApk(self, instrumented, force_relink=False): + """Builds a Chrome.apk either with or without order_profiling on. + + Args: + instrumented: (bool) Whether to build an instrumented apk. + force_relink: Whether libchromeview.so should be re-created. + """ + if force_relink: + self._step_recorder.RunCommand(['rm', '-rf', self.lib_chrome_so]) + self.Build(instrumented, 'chrome_apk') + + def CompileLibchrome(self, instrumented, force_relink=False): + """Builds a libchrome.so either with or without order_profiling on. + + Args: + instrumented: (bool) Whether to build an instrumented apk. + force_relink: (bool) Whether libchrome.so should be re-created. + """ + if force_relink: + self._step_recorder.RunCommand(['rm', '-rf', self.lib_chrome_so]) + self.Build(instrumented, 'libchrome') + + +class OrderfileUpdater(object): + """Handles uploading and committing a new orderfile in the repository. + + Only used for testing or on a bot. + """ + + _CLOUD_STORAGE_BUCKET_FOR_DEBUG = None + _CLOUD_STORAGE_BUCKET = None + _UPLOAD_TO_CLOUD_COMMAND = 'upload_to_google_storage.py' + + def __init__(self, repository_root, step_recorder, branch, netrc): + """Constructor. + + Args: + repository_root: (str) Root of the target repository. + step_recorder: (StepRecorder) Step recorder, for logging. + branch: (str) Branch to commit to. + netrc: (str) Path to the .netrc file to use. + """ + self._repository_root = repository_root + self._step_recorder = step_recorder + self._branch = branch + self._netrc = netrc + + def CommitFileHashes(self, unpatched_orderfile_filename, orderfile_filename): + """Commits unpatched and patched orderfiles hashes, if provided. + + Files must have been successfilly uploaded to cloud storage first. + + Args: + unpatched_orderfile_filename: (str or None) Unpatched orderfile path. + orderfile_filename: (str or None) Orderfile path. + + Raises: + NotImplementedError when the commit logic hasn't been overriden. + """ + files_to_commit = [] + commit_message_lines = ['Update Orderfile.'] + for filename in [unpatched_orderfile_filename, orderfile_filename]: + if not filename: + continue + (relative_path, sha1) = self._GetHashFilePathAndContents(filename) + commit_message_lines.append('Profile: %s: %s' % ( + os.path.basename(relative_path), sha1)) + files_to_commit.append(relative_path) + if files_to_commit: + self._CommitFiles(files_to_commit, commit_message_lines) + + def UploadToCloudStorage(self, filename, use_debug_location): + """Uploads a file to cloud storage. + + Args: + filename: (str) File to upload. + use_debug_location: (bool) Whether to use the debug location. + """ + bucket = (self._CLOUD_STORAGE_BUCKET_FOR_DEBUG if use_debug_location + else self._CLOUD_STORAGE_BUCKET) + extension = _GetFileExtension(filename) + cmd = [self._UPLOAD_TO_CLOUD_COMMAND, '--bucket', bucket] + if extension: + cmd.extend(['-z', extension]) + cmd.append(filename) + self._step_recorder.RunCommand(cmd) + print 'Download: https://sandbox.google.com/storage/%s/%s' % ( + bucket, _GenerateHash(filename)) + + def _GetHashFilePathAndContents(self, filename): + """Gets the name and content of the hash file created from uploading the + given file. + + Args: + filename: (str) The file that was uploaded to cloud storage. + + Returns: + A tuple of the hash file name, relative to the reository root, and the + content, which should be the sha1 hash of the file + ('base_file.sha1', hash) + """ + abs_hash_filename = filename + '.sha1' + rel_hash_filename = os.path.relpath( + abs_hash_filename, self._repository_root) + with open(abs_hash_filename, 'r') as f: + return (rel_hash_filename, f.read()) + + def _CommitFiles(self, files_to_commit, commit_message_lines): + """Commits a list of files, with a given message.""" + raise NotImplementedError + + +class OrderfileGenerator(object): + """A utility for generating a new orderfile for Clank. + + Builds an instrumented binary, profiles a run of the application, and + generates an updated orderfile. + """ + _CLANK_REPO = os.path.join(constants.DIR_SOURCE_ROOT, 'clank') + _MERGE_TRACES_SCRIPT = os.path.join( + constants.DIR_SOURCE_ROOT, 'tools', 'cygprofile', 'mergetraces.py') + _CYGLOG_TO_ORDERFILE_SCRIPT = os.path.join( + constants.DIR_SOURCE_ROOT, 'tools', 'cygprofile', + 'cyglog_to_orderfile.py') + _CHECK_ORDERFILE_SCRIPT = os.path.join( + constants.DIR_SOURCE_ROOT, 'tools', 'cygprofile', 'check_orderfile.py') + _BUILD_ROOT = os.path.abspath(os.path.dirname(os.path.dirname( + constants.GetOutDirectory()))) # Normally /path/to/src + + _UNPATCHED_ORDERFILE_FILENAME = os.path.join( + _CLANK_REPO, 'orderfiles', 'unpatched_orderfile.%s') + _MERGED_CYGLOG_FILENAME = os.path.join( + constants.GetOutDirectory(), 'merged_cyglog') + + _PATH_TO_ORDERFILE = os.path.join(_CLANK_REPO, 'orderfiles', + 'orderfile.%s.out') + + # Previous orderfile_generator debug files would be overwritten. + _DIRECTORY_FOR_DEBUG_FILES = '/tmp/orderfile_generator_debug_files' + + def _GetPathToOrderfile(self): + """Gets the path to the architecture-specific orderfile.""" + return self._PATH_TO_ORDERFILE % self._options.arch + + def _GetUnpatchedOrderfileFilename(self): + """Gets the path to the architecture-specific unpatched orderfile.""" + return self._UNPATCHED_ORDERFILE_FILENAME % self._options.arch + + def __init__(self, options, orderfile_updater_class): + self._options = options + + self._instrumented_out_dir = os.path.join( + self._BUILD_ROOT, self._options.arch + '_instrumented_out') + self._uninstrumented_out_dir = os.path.join( + self._BUILD_ROOT, self._options.arch + '_uninstrumented_out') + + if options.profile: + output_directory = os.path.join(self._instrumented_out_dir, 'Release') + host_cyglog_dir = os.path.join(output_directory, 'cyglog_data') + # Only override the defaults when using lightweight instrumentation, + # as the regular profiling code is likely too slow for these. + urls = [profile_android_startup.AndroidProfileTool.TEST_URL] + use_wpr = True + simulate_user = False + if options.simulate_user and not options.lightweight_instrumentation: + logging.error( + '--simulate-user required --lightweight-instrumentation, ignoring.') + if options.lightweight_instrumentation: + urls = options.urls + use_wpr = not options.no_wpr + simulate_user = options.simulate_user + self._profiler = profile_android_startup.AndroidProfileTool( + output_directory, host_cyglog_dir, use_wpr, urls, simulate_user) + + self._output_data = {} + self._step_recorder = StepRecorder(options.buildbot) + self._compiler = None + assert issubclass(orderfile_updater_class, OrderfileUpdater) + self._orderfile_updater = orderfile_updater_class(self._CLANK_REPO, + self._step_recorder, + options.branch, + options.netrc) + assert os.path.isdir(constants.DIR_SOURCE_ROOT), 'No src directory found' + symbol_extractor.SetArchitecture(options.arch) + + def _RunCygprofileUnitTests(self): + """Builds, deploys and runs cygprofile_unittests.""" + # There an no unittests (yet) for the lightweight instrumentation. + # TODO(lizeb): Fix this. + if self._options.lightweight_instrumentation: + return + tools_compiler = ClankCompiler( + os.path.dirname(constants.GetOutDirectory()), + self._step_recorder, self._options.arch, self._options.jobs, + self._options.max_load, self._options.use_goma, self._options.goma_dir, + self._options.lightweight_instrumentation) + tools_compiler.Build(instrumented=False, target='android_tools') + self._compiler.Build(instrumented=True, target='cygprofile_unittests') + + self._step_recorder.BeginStep('Deploy and run cygprofile_unittests') + exit_code = self._profiler.RunCygprofileTests() + + if exit_code != 0: + self._step_recorder.FailStep( + 'cygprofile_unittests exited with non-0 status: %d' % exit_code) + + @staticmethod + def _RemoveBlanks(src_file, dest_file): + """A utility to remove blank lines from a file. + + Args: + src_file: The name of the file to remove the blanks from. + dest_file: The name of the file to write the output without blanks. + """ + assert src_file != dest_file, 'Source and destination need to be distinct' + + try: + src = open(src_file, 'r') + dest = open(dest_file, 'w') + for line in src: + if line and not line.isspace(): + dest.write(line) + finally: + src.close() + dest.close() + + def _GenerateAndProcessProfile(self): + """Invokes a script to merge the per-thread traces into one file.""" + self._step_recorder.BeginStep('Generate Profile Data') + files = [] + try: + logging.getLogger().setLevel(logging.DEBUG) + files = self._profiler.CollectProfile( + self._compiler.chrome_apk, + constants.PACKAGE_INFO['chrome']) + self._step_recorder.BeginStep('Process cyglog') + if self._options.lightweight_instrumentation: + assert os.path.exists(self._compiler.lib_chrome_so) + offsets = process_profiles.GetReachedOffsetsFromDumpFiles( + files, self._compiler.lib_chrome_so) + if not offsets: + raise Exception('No profiler offsets found in {}'.format( + '\n'.join(files))) + with open(self._MERGED_CYGLOG_FILENAME, 'w') as f: + f.write('\n'.join(map(str, offsets))) + else: + with open(self._MERGED_CYGLOG_FILENAME, 'w') as merged_cyglog: + self._step_recorder.RunCommand([self._MERGE_TRACES_SCRIPT] + files, + constants.DIR_SOURCE_ROOT, + stdout=merged_cyglog) + except Exception: + for f in files: + self._SaveForDebugging(f) + raise + finally: + self._profiler.Cleanup() + logging.getLogger().setLevel(logging.INFO) + + try: + command_args = [ + '--target-arch=' + self._options.arch, + '--native-library=' + self._compiler.lib_chrome_so, + '--output=' + self._GetUnpatchedOrderfileFilename()] + if self._options.lightweight_instrumentation: + command_args.append('--reached-offsets=' + self._MERGED_CYGLOG_FILENAME) + else: + command_args.append('--merged-cyglog=' + self._MERGED_CYGLOG_FILENAME) + self._step_recorder.RunCommand( + [self._CYGLOG_TO_ORDERFILE_SCRIPT] + command_args) + except CommandError: + self._SaveForDebugging(self._MERGED_CYGLOG_FILENAME) + self._SaveForDebuggingWithOverwrite(self._compiler.lib_chrome_so) + raise + + def _DeleteTempFiles(self): + """Deletes intermediate step output files.""" + print 'Delete %s' % ( + self._MERGED_CYGLOG_FILENAME) + if os.path.isfile(self._MERGED_CYGLOG_FILENAME): + os.unlink(self._MERGED_CYGLOG_FILENAME) + + def _PatchOrderfile(self): + """Patches the orderfile using clean version of libchrome.so.""" + self._step_recorder.BeginStep('Patch Orderfile') + patch_orderfile.GeneratePatchedOrderfile( + self._GetUnpatchedOrderfileFilename(), self._compiler.lib_chrome_so, + self._GetPathToOrderfile()) + + def _VerifySymbolOrder(self): + self._step_recorder.BeginStep('Verify Symbol Order') + return_code = self._step_recorder.RunCommand( + [self._CHECK_ORDERFILE_SCRIPT, self._compiler.lib_chrome_so, + self._GetPathToOrderfile(), + '--target-arch=' + self._options.arch], + constants.DIR_SOURCE_ROOT, + raise_on_error=False) + if return_code: + self._step_recorder.FailStep('Orderfile check returned %d.' % return_code) + + def _RecordHash(self, file_name): + """Records the hash of the file into the output_data dictionary.""" + self._output_data[os.path.basename(file_name) + '.sha1'] = _GenerateHash( + file_name) + + def _SaveFileLocally(self, file_name, file_sha1): + """Saves the file to a temporary location and prints the sha1sum.""" + if not os.path.exists(self._DIRECTORY_FOR_DEBUG_FILES): + os.makedirs(self._DIRECTORY_FOR_DEBUG_FILES) + shutil.copy(file_name, self._DIRECTORY_FOR_DEBUG_FILES) + print 'File: %s, saved in: %s, sha1sum: %s' % ( + file_name, self._DIRECTORY_FOR_DEBUG_FILES, file_sha1) + + def _SaveForDebugging(self, filename): + """Uploads the file to cloud storage or saves to a temporary location.""" + file_sha1 = _GenerateHash(filename) + if not self._options.buildbot: + self._SaveFileLocally(filename, file_sha1) + else: + print 'Uploading file for debugging: ' + filename + self._orderfile_updater.UploadToCloudStorage( + filename, use_debug_location=True) + + def _SaveForDebuggingWithOverwrite(self, file_name): + """Uploads and overwrites the file in cloud storage or copies locally. + + Should be used for large binaries like lib_chrome_so. + + Args: + file_name: (str) File to upload. + """ + file_sha1 = _GenerateHash(file_name) + if not self._options.buildbot: + self._SaveFileLocally(file_name, file_sha1) + else: + print 'Uploading file for debugging: %s, sha1sum: %s' % ( + file_name, file_sha1) + upload_location = '%s/%s' % ( + self._CLOUD_STORAGE_BUCKET_FOR_DEBUG, os.path.basename(file_name)) + self._step_recorder.RunCommand([ + 'gsutil.py', 'cp', file_name, 'gs://' + upload_location]) + print ('Uploaded to: https://sandbox.google.com/storage/' + + upload_location) + + def _MaybeArchiveOrderfile(self, filename): + """In buildbot configuration, uploads the generated orderfile to + Google Cloud Storage. + + Args: + filename: (str) Orderfile to upload. + """ + # First compute hashes so that we can download them later if we need to + self._step_recorder.BeginStep('Compute hash for ' + filename) + self._RecordHash(filename) + if self._options.buildbot: + self._step_recorder.BeginStep('Archive ' + filename) + self._orderfile_updater.UploadToCloudStorage( + filename, use_debug_location=False) + + def _GetHashFilePathAndContents(self, base_file): + """Gets the name and content of the hash file created from uploading the + given file. + + Args: + base_file: The file that was uploaded to cloud storage. + + Returns: + A tuple of the hash file name, relative to the clank repo path, and the + content, which should be the sha1 hash of the file + ('base_file.sha1', hash) + """ + abs_file_name = base_file + '.sha1' + rel_file_name = os.path.relpath(abs_file_name, self._CLANK_REPO) + with open(abs_file_name, 'r') as f: + return (rel_file_name, f.read()) + + def Generate(self): + """Generates and maybe upload an order.""" + profile_uploaded = False + orderfile_uploaded = False + + if self._options.profile: + try: + _UnstashOutputDirectory(self._instrumented_out_dir) + self._compiler = ClankCompiler( + self._instrumented_out_dir, + self._step_recorder, self._options.arch, self._options.jobs, + self._options.max_load, self._options.use_goma, + self._options.goma_dir, + self._options.lightweight_instrumentation) + self._RunCygprofileUnitTests() + if self._options.lightweight_instrumentation: + _EnsureOrderfileStartsWithAnchorSection(self._GetPathToOrderfile()) + self._compiler.CompileChromeApk( + True, self._options.lightweight_instrumentation) + self._GenerateAndProcessProfile() + self._MaybeArchiveOrderfile(self._GetUnpatchedOrderfileFilename()) + profile_uploaded = True + finally: + self._DeleteTempFiles() + _StashOutputDirectory(self._instrumented_out_dir) + if self._options.patch: + if self._options.profile: + self._RemoveBlanks(self._GetUnpatchedOrderfileFilename(), + self._GetPathToOrderfile()) + try: + _UnstashOutputDirectory(self._uninstrumented_out_dir) + self._compiler = ClankCompiler( + self._uninstrumented_out_dir, self._step_recorder, + self._options.arch, self._options.jobs, self._options.max_load, + self._options.use_goma, self._options.goma_dir, + self._options.lightweight_instrumentation) + self._compiler.CompileLibchrome(False) + self._PatchOrderfile() + # Because identical code folding is a bit different with and without + # the orderfile build, we need to re-patch the orderfile with code + # folding as close to the final version as possible. + self._compiler.CompileLibchrome(False, force_relink=True) + self._PatchOrderfile() + self._compiler.CompileLibchrome(False, force_relink=True) + self._VerifySymbolOrder() + self._MaybeArchiveOrderfile(self._GetPathToOrderfile()) + finally: + _StashOutputDirectory(self._uninstrumented_out_dir) + orderfile_uploaded = True + + if (self._options.buildbot and self._options.netrc + and not self._step_recorder.ErrorRecorded()): + unpatched_orderfile_filename = ( + self._GetUnpatchedOrderfileFilename() if profile_uploaded else None) + orderfile_filename = ( + self._GetPathToOrderfile() if orderfile_uploaded else None) + self._orderfile_updater.CommitFileHashes( + unpatched_orderfile_filename, orderfile_filename) + + self._step_recorder.EndStep() + return not self._step_recorder.ErrorRecorded() + + def GetReportingData(self): + """Get a dictionary of reporting data (timings, output hashes)""" + self._output_data['timings'] = self._step_recorder.timings + return self._output_data + + +def CreateArgumentParser(): + """Creates and returns the argument parser.""" + parser = argparse.ArgumentParser() + parser.add_argument( + '--regular-instrumentation', action='store_false', + dest='lightweight_instrumentation', + help='Use the regular instrumentation path') + parser.add_argument( + '--buildbot', action='store_true', + help='If true, the script expects to be run on a buildbot') + parser.add_argument( + '--verify', action='store_true', + help='If true, the script only verifies the current orderfile') + parser.add_argument('--target-arch', action='store', dest='arch', + default=cygprofile_utils.DetectArchitecture(), + choices=['arm', 'arm64', 'x86', 'x86_64', 'x64', 'mips'], + help='The target architecture for which to build') + parser.add_argument('--output-json', action='store', dest='json_file', + help='Location to save stats in json format') + parser.add_argument( + '--skip-profile', action='store_false', dest='profile', default=True, + help='Don\'t generate a profile on the device. Only patch from the ' + 'existing profile.') + parser.add_argument( + '--skip-patch', action='store_false', dest='patch', default=True, + help='Only generate the raw (unpatched) orderfile, don\'t patch it.') + parser.add_argument( + '--netrc', action='store', + help='A custom .netrc file to use for git checkin. Only used on bots.') + parser.add_argument( + '--branch', action='store', default='master', + help='When running on buildbot with a netrc, the branch orderfile ' + 'hashes get checked into.') + # Note: -j50 was causing issues on the bot. + parser.add_argument( + '-j', '--jobs', action='store', default=20, + help='Number of jobs to use for compilation.') + parser.add_argument( + '-l', '--max-load', action='store', default=4, help='Max cpu load.') + parser.add_argument('--goma-dir', help='GOMA directory.') + parser.add_argument( + '--use-goma', action='store_true', help='Enable GOMA.', default=False) + parser.add_argument('--adb-path', help='Path to the adb binary.') + profile_android_startup.AddProfileCollectionArguments(parser) + return parser + + +def CreateOrderfile(options, orderfile_updater_class): + """Creates an oderfile. + + Args: + options: As returned from optparse.OptionParser.parse_args() + orderfile_updater_class: (OrderfileUpdater) subclass of OrderfileUpdater. + + Returns: + True iff success. + """ + logging.basicConfig(level=logging.INFO) + devil_chromium.Initialize(adb_path=options.adb_path) + + generator = OrderfileGenerator(options, orderfile_updater_class) + try: + if options.verify: + generator._VerifySymbolOrder() + else: + return generator.Generate() + finally: + json_output = json.dumps(generator.GetReportingData(), + indent=2) + '\n' + if options.json_file: + with open(options.json_file, 'w') as f: + f.write(json_output) + print json_output + return False + + +def main(): + parser = CreateArgumentParser() + options = parser.parse_args() + return 0 if CreateOrderfile(options, OrderfileUpdater) else 1 + + +if __name__ == '__main__': + sys.exit(main())
diff --git a/tools/cygprofile/orderfile_generator_backend_unittest.py b/tools/cygprofile/orderfile_generator_backend_unittest.py new file mode 100755 index 0000000..525b9bd --- /dev/null +++ b/tools/cygprofile/orderfile_generator_backend_unittest.py
@@ -0,0 +1,46 @@ +#!/usr/bin/python +# Copyright 2015 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 tempfile +import unittest + +import orderfile_generator_backend + +class TestOrderfileGenerator(unittest.TestCase): + def testStepRecorder(self): + """Checks that the step recorder records step timings correctly.""" + step_recorder = orderfile_generator_backend.StepRecorder(False) + self.assertFalse(step_recorder.ErrorRecorded()) + step_recorder.BeginStep('foo') + self.assertFalse(step_recorder.ErrorRecorded()) + step_recorder.BeginStep('bar') + self.assertFalse(step_recorder.ErrorRecorded()) + step_recorder.FailStep() + self.assertEqual(2, len(step_recorder.timings)) + self.assertEqual('foo', step_recorder.timings[0][0]) + self.assertEqual('bar', step_recorder.timings[1][0]) + self.assertLess(0, step_recorder.timings[0][1]) + self.assertLess(0, step_recorder.timings[1][1]) + self.assertTrue(step_recorder.ErrorRecorded()) + + def testGetFileExtension(self): + self.assertEqual('zip', + orderfile_generator_backend._GetFileExtension('/foo/bar/baz.blub.zip')) + + def testGenerateHash(self): + try: + with tempfile.NamedTemporaryFile(mode='w', delete=False) as handle: + filename = handle.name + handle.write('foo') + self.assertEqual('0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33', + orderfile_generator_backend._GenerateHash(filename)) + finally: + if filename: + os.unlink(filename) + + +if __name__ == '__main__': + unittest.main()
diff --git a/tools/cygprofile/patch_native_library.py b/tools/cygprofile/patch_native_library.py new file mode 100755 index 0000000..7fa1885 --- /dev/null +++ b/tools/cygprofile/patch_native_library.py
@@ -0,0 +1,312 @@ +#!/usr/bin/python +# Copyright 2017 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. + +"""Patches redundant calls to function instrumentation with NOPs.""" + +import argparse +import copy +import logging +import os +import re +import struct +import subprocess +import sys + +# Python has a symbol builtin module, so the android one needs to be first in +# the import path. +_SRC_PATH = os.path.join(os.path.dirname(__file__), os.pardir, os.pardir) +sys.path.insert(0, os.path.join( + _SRC_PATH, 'third_party', 'android_platform', 'development', 'scripts')) +import symbol + +_OBJDUMP = symbol.ToolPath('objdump') +_STRIP = symbol.ToolPath('strip') + + +class SymbolData(object): + """Data about a symbol, extracted from objdump output.""" + + SYMBOL_RE = re.compile('^([0-9a-f]{8}) <(.*)>:$') + assert SYMBOL_RE.match('002dcc84 <_ZN3net8QuicTime5Delta11FromSecondsEx>:') + _BLX_RE = re.compile('^ {1,2}([0-9a-f]{6,7}):.*blx\t[0-9a-f]{6,7} <(.*)>') + assert _BLX_RE.match( + ' 2dd03e: f3f3 ee16 ' + 'blx\t6d0c6c <_ZN16content_settings14PolicyProvider27UpdateManaged' + 'DefaultSettingERKNS0_30PrefsForManagedDefaultMapEntryE+0x120>') + _BL_ENTER_RE = re.compile('^ {1,2}([0-9a-f]{6,7}):.*bl\t[0-9a-f]{6,7} ' + '<__cyg_profile_func_enter>') + _BL_EXIT_RE = re.compile('^ {1,2}([0-9a-f]{6,7}):.*bl\t[0-9a-f]{6,7} ' + '<__cyg_profile_func_exit>') + assert(_BL_ENTER_RE.match(' 1a66d84: f3ff d766 bl\t' + '2a66c54 <__cyg_profile_func_enter>')) + + def __init__(self, name, offset, bl_enter, bl_exit, blx): + """Constructor. + + Args: + name: (str) Mangled symbol name. + offset: (int) Offset into the native library + bl_enter: ([int]) List of offsets at which short jumps to the enter + instrumentation are found. + bl_exit: ([int]) List of offsets at which short jumps to the exit + instrumentation are found. + blx: ([(int, str)]) (instruction_offset, target_offset) for long jumps. + The target is encoded, for instance _ZNSt6__ndk14ceilEf+0x28. + """ + self.name = name + self.offset = offset + self.bl_enter = bl_enter + self.bl_exit = bl_exit + self.blx = blx + + @classmethod + def FromObjdumpLines(cls, lines): + """Returns an instance of SymbolData from objdump lines. + + Args: + lines: ([str]) Symbol disassembly. + """ + offset, name = cls.SYMBOL_RE.match(lines[0]).groups() + symbol_data = cls(name, int(offset, 16), [], [], []) + for line in lines[1:]: + if cls._BL_ENTER_RE.match(line): + offset = int(cls._BL_ENTER_RE.match(line).group(1), 16) + symbol_data.bl_enter.append(offset) + elif cls._BL_EXIT_RE.match(line): + offset = int(cls._BL_EXIT_RE.match(line).group(1), 16) + symbol_data.bl_exit.append(offset) + elif cls._BLX_RE.match(line): + offset, name = cls._BLX_RE.match(line).groups() + offset = int(offset, 16) + symbol_data.blx.append((offset, name)) + return symbol_data + + +def RunObjdumpAndParse(native_library_filename): + """Calls Objdump and parses its output. + + Args: + native_library_filename: (str) Path to the natve library. + + Returns: + [SymbolData] + """ + p = subprocess.Popen([_OBJDUMP, '-d', native_library_filename, '-j', '.text'], + stdout=subprocess.PIPE, bufsize=-1) + result = [] + # Skip initial blank lines. + while not p.stdout.readline().startswith('Disassembly of section .text'): + continue + + next_line = p.stdout.readline() + while True: + if not next_line: + break + # skip to new symbol + while not SymbolData.SYMBOL_RE.match(next_line): + next_line = p.stdout.readline() + + symbol_lines = [next_line] + next_line = p.stdout.readline() + while next_line.strip(): + symbol_lines.append(next_line) + next_line = p.stdout.readline() + result.append(SymbolData.FromObjdumpLines(symbol_lines)) + # EOF + p.wait() + return result + + +def ResolveBlxTargets(symbols_data, native_lib_filename): + """Parses the binary, and resolves all targets of long jumps. + + Args: + symbols_data: ([SymbolData]) As returned by RunObjdumpAndParse(). + native_lib_filename: (str) Path to the unstripped native library. + + Returns: + {"blx_target_name": "actual jump target symbol name"} + """ + blx_targets = set() + blx_target_to_offset = {} + for symbol_data in symbols_data: + for (_, target) in symbol_data.blx: + blx_targets.add(target) + logging.info('Found %d distinct BLX targets', len(blx_targets)) + name_to_offset = {s.name: s.offset for s in symbols_data} + offset_to_name = {s.offset: s.name for s in symbols_data} + unmatched_count = 0 + for target in blx_targets: + if '+' not in target: + continue + # FunkySymbolName+0x12bc + name, offset = target.split('+') + if name not in name_to_offset: + unmatched_count += 1 + continue + offset = int(offset, 16) + absolute_offset = name_to_offset[name] + offset + blx_target_to_offset[target] = absolute_offset + logging.info('Unmatched BLX offsets: %d', unmatched_count) + + logging.info('Reading the native library') + content = bytearray(open(native_lib_filename, 'rb').read()) + + # Expected instructions are: + # ldr r12, [pc, #4] # Here + 12 + # add r12, pc, r12 + # bx r12 + # Some offset. (4 bytes) + # Note that the first instructions loads from pc + 8 + 4, per ARM + # documentation. See + # http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0473e/Cacdbfji.html + # Reversed for little endian. + ldr_r12_constant = bytearray(b'\xe5\x9f\xc0\x04'[::-1]) + unmatched_loads_count = 0 + add_r12_pc_r12 = bytearray(b'\xe0\x8f\xc0\x0c'[::-1]) + unmatched_adds_count = 0 + bx_r12 = bytearray(b'\xe1\x2f\xff\x1c'[::-1]) + unmatched_bx_count = 0 + unmatched_targets_count = 0 + blx_target_name_to_symbol = {} + for (target_name, offset) in blx_target_to_offset.items(): + actual_bytes = content[offset:offset+4] + if actual_bytes != ldr_r12_constant: + unmatched_loads_count += 1 + continue + actual_bytes = content[offset+4:offset+8] + if actual_bytes != add_r12_pc_r12: + unmatched_adds_count += 1 + continue + actual_bytes = content[offset+8:offset+12] + if actual_bytes != bx_r12: + unmatched_bx_count += 1 + continue + # Congratulations, you've passed all the tests. The next value must be + # an offset. + offset_bytearray = content[offset+12:offset+16] + offset_from_pc = struct.unpack('<i', offset_bytearray)[0] + # Jumping to THUMB code, last bit is set to 1 to indicate the instruction + # set. The actual address is aligned on 4 bytes though. + assert offset_from_pc & 1 + offset_from_pc &= ~1 + if offset_from_pc % 4: + unmatched_targets_count += 1 + continue + # PC points 8 bytes ahead of the ADD instruction, which is itself 4 bytes + # ahead of the jump target. Add 8 + 4 bytes to the destination. + target_offset = offset + offset_from_pc + 8 + 4 + if target_offset not in offset_to_name: + unmatched_targets_count += 1 + continue + blx_target_name_to_symbol[target_name] = offset_to_name[target_offset] + logging.info('Unmatched instruction sequence = %d %d %d', + unmatched_loads_count, unmatched_adds_count, unmatched_bx_count) + logging.info('Unmatched targets = %d', unmatched_targets_count) + return blx_target_name_to_symbol + + +def FindDuplicatedInstrumentationCalls(symbols_data, blx_target_to_symbol_name): + """Finds the extra instrumentation calls. + + Besides not needing the exit instrumentation calls, each function should only + contain one instrumentation call. However since instrumentation calls are + inserted before inlining, some functions contain tens of them. This function + returns the location of the instrumentation calls except the first one, for + all functions. + + Args: + symbols_data: As returned by RunObjdumpAndParse(). + blx_target_to_symbol_name: ({str: str}) As returned by ResolveBlxTargets(). + + Returns: + [int] A list of offsets containing duplicated instrumentation calls. + """ + offsets_to_patch = [] + # Instrumentation calls can be short (bl) calls, or long calls. + # In the second case, the compiler inserts a call using blx to a location + # containing trampoline code. The disassembler doesn't know about that, so + # we use the resolved locations. + for symbol_data in symbols_data: + enter_call_offsets = copy.deepcopy(symbol_data.bl_enter) + exit_call_offsets = copy.deepcopy(symbol_data.bl_exit) + for (offset, target) in symbol_data.blx: + if target not in blx_target_to_symbol_name: + continue + final_target = blx_target_to_symbol_name[target] + if final_target == '__cyg_profile_func_enter': + enter_call_offsets.append(offset) + elif final_target == '__cyg_profile_func_exit': + exit_call_offsets.append(offset) + offsets_to_patch += exit_call_offsets + # Not the first one. + offsets_to_patch += sorted(enter_call_offsets)[1:] + return sorted(offsets_to_patch) + + +def PatchBinary(filename, output_filename, offsets): + """Inserts 4-byte NOPs inside the native library at a list of offsets. + + Args: + filename: (str) File to patch. + output_filename: (str) Path to the patched file. + offsets: ([int]) List of offsets to patch in the binary. + """ + # NOP.w is 0xf3 0xaf 0x80 0x00 for THUMB-2, but the CPU is little endian, + # so reverse bytes (but 2 bytes at a time). + _THUMB_2_NOP = bytearray('\xaf\xf3\x00\x80') + content = bytearray(open(filename, 'rb').read()) + for offset in offsets: + # TODO(lizeb): Assert that it's a BL or BLX + content[offset:offset+4] = _THUMB_2_NOP + open(output_filename, 'wb').write(content) + + +def StripLibrary(unstripped_library_filename): + """Strips a native library. + + Args: + unstripped_library_filename: (str) Path to the library to strip in place. + """ + subprocess.call([_STRIP, unstripped_library_filename]) + + +def Go(build_directory): + unstripped_library_filename = os.path.join(build_directory, 'lib.unstripped', + 'libchrome.so') + logging.info('Running objdump') + symbols_data = RunObjdumpAndParse(unstripped_library_filename) + logging.info('Symbols = %d', len(symbols_data)) + + blx_target_to_symbol_name = ResolveBlxTargets(symbols_data, + unstripped_library_filename) + offsets = FindDuplicatedInstrumentationCalls(symbols_data, + blx_target_to_symbol_name) + logging.info('%d offsets to patch', len(offsets)) + patched_library_filename = unstripped_library_filename + '.patched' + logging.info('Patching the library') + PatchBinary(unstripped_library_filename, patched_library_filename, offsets) + logging.info('Stripping the patched library') + StripLibrary(patched_library_filename) + stripped_library_filename = os.path.join(build_directory, 'libchrome.so') + os.rename(patched_library_filename, stripped_library_filename) + + +def CreateArgumentParser(): + parser = argparse.ArgumentParser(description='Patch the native library') + parser.add_argument('--build_directory', type=str, required=True) + return parser + + +def main(): + logging.basicConfig(level=logging.INFO, + format='%(asctime)s %(levelname)s:%(message)s') + parser = CreateArgumentParser() + args = parser.parse_args() + Go(args.build_directory) + + +if __name__ == '__main__': + main()
diff --git a/tools/cygprofile/patch_native_library_unittest.py b/tools/cygprofile/patch_native_library_unittest.py new file mode 100644 index 0000000..d9f4249 --- /dev/null +++ b/tools/cygprofile/patch_native_library_unittest.py
@@ -0,0 +1,57 @@ +# Copyright 2017 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. + +"""Unit tests for patch_native_library.py.""" + +import unittest + +import patch_native_library + + +class PatchNativeLibraryTestCase(unittest.TestCase): + _SYMBOL_LINES = """002f7ee0 <baz>: + 2f7ee0: b570 push {r4, r5, r6, lr} + 2f7ee2: 4e09 ldr r6, [pc, #36] ; (2f7f08 <baz+0x28>) + 2f7ee4: 4674 mov r4, lr + 2f7ee6: 4605 mov r5, r0 + 2f7ee8: 4621 mov r1, r4 + 2f7eea: 447e add r6, pc + 2f7eec: 4630 mov r0, r6 + 2f7eee: f7ff ffa9 bl\t2f7e44 <__cyg_profile_func_enter> + 2f7ef2: 4806 ldr r0, [pc, #24] ; (2f7f0c <baz+0x2c>) + 2f7ef4: 2101 movs r1, #1 + 2f7ef6: 4478 add r0, pc + 2f7ef8: 7001 strb r1, [r0, #0] + 2f7efa: 4630 mov r0, r6 + 2f7efc: 4621 mov r1, r4 + 2f7efe: f3f3 ef58 blx\t6ebdb0 <bar+0x5c> + 2f7f02: 4628 mov r0, r5 + 2f7f04: bd70 pop {r4, r5, r6, pc} + 2f7f06: bf00 nop + 2f7f08: fffffff3 .word 0xfffffff3 + 2f7f0c: 101bdfef .word 0x101bdfef +""" + def testSymbolDataParsing(self): + lines = self._SYMBOL_LINES.split('\n') + symbol_data = patch_native_library.SymbolData.FromObjdumpLines(lines) + self.assertEquals("baz", symbol_data.name) + self.assertEquals(int("002f7ee0", 16), symbol_data.offset) + self.assertEquals([int("2f7eee", 16)], symbol_data.bl_enter) + self.assertEquals([], symbol_data.bl_exit) + self.assertEquals([(int("2f7efe", 16), ("bar+0x5c"))], symbol_data.blx) + + def testFindDuplicatedInstrumentationCals(self): + symbols_data = [ + patch_native_library.SymbolData( + "foo", 1000, [123, 124], [125], [(126, "bar+0x12"), + (127, "foo+0x12")])] + blx_target_to_symbol_name = {"bar+0x12": "__cyg_profile_func_enter"} + offsets = patch_native_library.FindDuplicatedInstrumentationCalls( + symbols_data, blx_target_to_symbol_name) + # Not the first enter call, and not the unmatched blx. + self.assertSetEqual(set([124, 125, 126]), set(offsets)) + + +if __name__ == '__main__': + unittest.main()
diff --git a/tools/cygprofile/patch_orderfile.py b/tools/cygprofile/patch_orderfile.py index dbb344f..5171c0939 100755 --- a/tools/cygprofile/patch_orderfile.py +++ b/tools/cygprofile/patch_orderfile.py
@@ -8,9 +8,12 @@ Starting with a list of symbols in a binary and an orderfile (ordered list of sections), matches the symbols in the orderfile and augments each symbol with the symbols residing at the same address (due to having identical code). The -output is a list of section matching rules appropriate for the linker option --section-ordering-file. These section matching rules include both actual -section names and names with wildcard (*) suffixes. +output is a list of section or symbols matching rules appropriate for the linker +option -section-ordering-file for gold and --symbol-ordering-file for lld. Both +linkers are fine with extra directives that aren't matched in the binary, so we +construct a file suitable for both, concatenating sections and symbols. We +assume that the unpatched orderfile is built for gold, that is, it only contains +sections. Note: It is possible to have. - Several symbols mapping to the same offset in the binary. @@ -22,14 +25,15 @@ 2. Get the symbol names from the orderfile 3. Find the orderfile symbol names in the symbols coming from the binary 4. For each symbol found, get all the symbols at the same address -5. Output them to an updated orderfile, with several different prefixes - and suffixes -6. Output catch-all section matching rules for unprofiled methods. +5. Output them to an updated orderfile suitable for gold and lld +6. Output catch-all section matching rules for unprofiled methods. This is + ineffective for lld, as it doesn't handle wildcards, but puts unordered + symbols after the ordered ones. """ +import argparse import collections import logging -import optparse import sys import cyglog_to_orderfile @@ -38,7 +42,9 @@ # Prefixes for the symbols. We strip them from the incoming symbols, and add # them back in the output file. -_PREFIXES = ('.text.startup.', '.text.hot.', '.text.unlikely.', '.text.') +# Output sections are constructed as prefix + symbol_name, hence the empty +# prefix is used to generate the symbol entry for lld. +_PREFIXES = ('.text.hot.', '.text.unlikely.', '.text.', '') # Suffixes for the symbols. These are due to method splitting for inlining and # method cloning for various reasons including constant propagation and @@ -83,28 +89,6 @@ return _FilteringFunction -def _GroupSymbolInfos(symbol_infos): - """Groups the symbol infos by name and offset. - - Args: - symbol_infos: an iterable of SymbolInfo - - Returns: - The same output as _GroupSymbolInfosFromBinary. - """ - # Map the addresses to symbols. - offset_to_symbol_infos = collections.defaultdict(list) - name_to_symbol_infos = collections.defaultdict(list) - for symbol in symbol_infos: - symbol = symbol_extractor.SymbolInfo(name=RemoveSuffixes(symbol.name), - offset=symbol.offset, - size=symbol.size, - section=symbol.section) - offset_to_symbol_infos[symbol.offset].append(symbol) - name_to_symbol_infos[symbol.name].append(symbol) - return (dict(offset_to_symbol_infos), dict(name_to_symbol_infos)) - - def _GroupSymbolInfosFromBinary(binary_filename): """Group all the symbols from a binary by name and offset. @@ -118,7 +102,10 @@ - name_to_symbol_infos: {name: [symbol_info1, ...]} """ symbol_infos = symbol_extractor.SymbolInfosFromBinary(binary_filename) - return _GroupSymbolInfos(symbol_infos) + symbol_infos_no_suffixes = [ + s._replace(name=RemoveSuffixes(s.name)) for s in symbol_infos] + return (symbol_extractor.GroupSymbolInfosByOffset(symbol_infos_no_suffixes), + symbol_extractor.GroupSymbolInfosByName(symbol_infos_no_suffixes)) def _StripPrefix(line): @@ -131,8 +118,11 @@ Returns: The symbol, SymbolName in the example above. """ + # Went away with GCC, make sure it doesn't come back, as the orderfile + # no longer contains it. + assert not line.startswith('.text.startup.') for prefix in _PREFIXES: - if line.startswith(prefix): + if prefix and line.startswith(prefix): return line[len(prefix):] return line # Unprefixed case @@ -257,6 +247,7 @@ # problems with unexpected suffixes. yield name + '.*' + def _ExpandSection(section_name, name_to_symbol_infos, offset_to_symbol_infos, section_to_symbols_map, symbol_to_sections_map): """Yields the set of section names for section_name. @@ -364,44 +355,82 @@ return [RemoveSuffixes(section) for section in section_list] -def main(argv): - parser = optparse.OptionParser(usage= - 'usage: %prog [options] <unpatched_orderfile> <library>') - parser.add_option('--target-arch', action='store', dest='arch', - choices=['arm', 'arm64', 'x86', 'x86_64', 'x64', 'mips'], - help='The target architecture for the library.') - options, argv = parser.parse_args(argv) - if not options.arch: - options.arch = cygprofile_utils.DetectArchitecture() - if len(argv) != 3: - parser.print_help() - return 1 - orderfile_filename = argv[1] - binary_filename = argv[2] - symbol_extractor.SetArchitecture(options.arch) +def GeneratePatchedOrderfile(unpatched_orderfile, native_lib_filename, + output_filename): + """Writes a patched orderfile. + + Args: + unpatched_orderfile: (str) Path to the unpatched orderfile. + native_lib_filename: (str) Path to the native library. + output_filename: (str) Path to the patched orderfile. + """ (offset_to_symbol_infos, name_to_symbol_infos) = _GroupSymbolInfosFromBinary( - binary_filename) - obj_dir = cygprofile_utils.GetObjDir(binary_filename) - raw_symbol_map = cyglog_to_orderfile.GetSymbolToSectionsMapFromObjectFiles( - obj_dir) + native_lib_filename) + obj_dir = cygprofile_utils.GetObjDir(native_lib_filename) + raw_symbol_map = cyglog_to_orderfile.ObjectFileProcessor( + obj_dir).GetSymbolToSectionsMap() suffixed = _SectionsWithSuffixes(raw_symbol_map) symbol_to_sections_map = _CombineSectionListsByPrimaryName(raw_symbol_map) section_to_symbols_map = cygprofile_utils.InvertMapping( symbol_to_sections_map) profiled_sections = _StripSuffixes( - GetSectionsFromOrderfile(orderfile_filename)) + GetSectionsFromOrderfile(unpatched_orderfile)) expanded_sections = _ExpandSections( profiled_sections, name_to_symbol_infos, offset_to_symbol_infos, section_to_symbols_map, symbol_to_sections_map, suffixed) - for section in expanded_sections: - print section - # The following is needed otherwise Gold only applies a partial sort. - print '.text' # gets methods not in a section, such as assembly - for prefix in _PREFIXES: - print prefix + '*' # gets everything else + + with open(output_filename, 'w') as f: + # Make sure the anchor functions are located in the right place, here and + # after everything else. + # See the comment in //base/android/library_loader/anchor_functions.cc. + for prefix in _PREFIXES: + f.write(prefix + 'dummy_function_to_anchor_text\n') + for prefix in _PREFIXES: + f.write(prefix + 'dummy_function_start_of_ordered_text\n') + + for section in expanded_sections: + f.write(section + '\n') + + for prefix in _PREFIXES: + f.write(prefix + 'dummy_function_end_of_ordered_text\n') + + # The following is needed otherwise Gold only applies a partial sort. + f.write('.text\n') # gets methods not in a section, such as assembly + f.write('.text.*\n') # gets everything else + + # Since wildcards are not supported by lld, the "end of text" anchor symbol + # is not emitted, a different mechanism is used instead. See comments in the + # file above. + for prefix in _PREFIXES: + if prefix: + f.write(prefix + 'dummy_function_at_the_end_of_text\n') + + +def _CreateArgumentParser(): + """Creates and returns the argument parser.""" + parser = argparse.ArgumentParser() + parser.add_argument('--target-arch', action='store', + choices=['arm', 'arm64', 'x86', 'x86_64', 'x64', 'mips'], + help='The target architecture for the library.') + parser.add_argument('--unpatched-orderfile', required=True, + help='Path to the unpatched orderfile') + parser.add_argument('--native-library', required=True, + help='Path to the native library') + parser.add_argument('--output-file', required=True, help='Output filename') + return parser + + +def main(): + parser = _CreateArgumentParser() + options = parser.parse_args() + if not options.target_arch: + options.arch = cygprofile_utils.DetectArchitecture() + symbol_extractor.SetArchitecture(options.target_arch) + GeneratePatchedOrderfile(options.unpatched_orderfile, options.native_library, + options.output_file) return 0 if __name__ == '__main__': logging.basicConfig(level=logging.INFO) - sys.exit(main(sys.argv)) + sys.exit(main())
diff --git a/tools/cygprofile/patch_orderfile_unittest.py b/tools/cygprofile/patch_orderfile_unittest.py index 047d447..26b099fb 100755 --- a/tools/cygprofile/patch_orderfile_unittest.py +++ b/tools/cygprofile/patch_orderfile_unittest.py
@@ -20,34 +20,6 @@ self.assertEquals( 'this.is.a', patch_orderfile.RemoveSuffixes(with_part)) - def testAliasClonedSymbols(self): - symbol_infos = [ - symbol_extractor.SymbolInfo(name='aSymbol', offset=0x42, size=0x12, - section='.text'), - symbol_extractor.SymbolInfo(name='aSymbol.clone.', offset=8, size=1, - section='.text')] - (offset_to_symbol_infos, name_to_symbol_infos) = \ - patch_orderfile._GroupSymbolInfos(symbol_infos) - self.assertEquals(len(offset_to_symbol_infos), 2) - for i in range(2): - s = symbol_infos[i] - matching = offset_to_symbol_infos[s.offset][0] - self.assertEquals(matching.offset, s.offset) - self.assertEquals(matching.size, s.size) - self.assertEquals(len(name_to_symbol_infos), 1) - self.assertEquals(len(name_to_symbol_infos['aSymbol']), 2) - - def testGroupSymbolsByOffset(self): - symbol_infos = ( - symbol_extractor.SymbolInfo(name='aSymbol', offset=0x42, size=0x12, - section='.text'), - symbol_extractor.SymbolInfo(name='anotherSymbol', offset=0x42, size=1, - section='.text')) - (offset_to_symbol_infos, _) = \ - patch_orderfile._GroupSymbolInfos(symbol_infos) - self.assertEquals(len(offset_to_symbol_infos), 1) - self.assertEquals(tuple(offset_to_symbol_infos[0x42]), symbol_infos) - def testSymbolsWithSameOffset(self): symbol_name = "dummySymbol" symbol_name2 = "other" @@ -70,21 +42,21 @@ def testSectionNameToSymbols(self): mapping = {'.text.foo': ['foo'], - '.text.startup.bar': ['bar', 'bar1']} + '.text.hot.bar': ['bar', 'bar1']} self.assertEquals(list(patch_orderfile._SectionNameToSymbols( '.text.foo', mapping)), ['foo']) self.assertEquals(list(patch_orderfile._SectionNameToSymbols( - '.text.startup.bar', mapping)), + '.text.hot.bar', mapping)), ['bar', 'bar1']) self.assertEquals(list(patch_orderfile._SectionNameToSymbols( - '.text.startup.bar', mapping)), + '.text.hot.bar', mapping)), ['bar', 'bar1']) self.assertEquals(list(patch_orderfile._SectionNameToSymbols( '.text.hot.foobar', mapping)), ['foobar']) self.assertEquals(list(patch_orderfile._SectionNameToSymbols( - '.text.startup.*', mapping)), + '.text.unlikely.*', mapping)), []) def testSectionMatchingRules(self): @@ -111,13 +83,13 @@ section_name1, section_name3, section_name3 + '.*', - '.text.startup.' + symbol_name1, '.text.hot.' + symbol_name1, '.text.unlikely.' + symbol_name1, - '.text.startup.symbol2', + symbol_name1, '.text.hot.symbol2', '.text.unlikely.symbol2', - '.text.symbol2'] + '.text.symbol2', + 'symbol2'] self.assertEqual(expected, list(patch_orderfile._SectionMatchingRules( section_name1, name_to_symbol_infos, offset_to_symbol_infos, section_to_symbols_map, symbol_to_sections_map, suffixed)))
diff --git a/tools/cygprofile/phased_orderfile.py b/tools/cygprofile/phased_orderfile.py new file mode 100755 index 0000000..49469de --- /dev/null +++ b/tools/cygprofile/phased_orderfile.py
@@ -0,0 +1,199 @@ +#!/usr/bin/python +# Copyright 2018 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. + +"""Utilities for creating a phased orderfile. + +This kind of orderfile is based on cygprofile lightweight instrumentation. The +profile dump format is described in process_profiles.py. These tools assume +profiling has been done with two phases. + +The first phase, labeled 0 in the filename, is called "startup" and the second, +labeled 1, is called "interaction". These two phases are used to create an +orderfile with three parts: the code touched only in startup, the code +touched only during interaction, and code common to the two phases. We refer to +these parts as the orderfile phases. +""" + +import argparse +import collections +import glob +import itertools +import logging +import os.path + +import process_profiles + + +# Files matched when using this script to analyze directly (see main()). +PROFILE_GLOB = 'cygprofile-*.txt_*' + + +OrderfilePhaseOffsets = collections.namedtuple( + 'OrderfilePhaseOffsets', ('startup', 'common', 'interaction')) + + +class PhasedAnalyzer(object): + """A class which collects analysis around phased orderfiles. + + It maintains common data such as symbol table information to make analysis + more convenient. + """ + # These figures are taken from running memory and speedometer telemetry + # benchmarks, and are still subject to change as of 2018-01-24. + STARTUP_STABILITY_THRESHOLD = 1.5 + COMMON_STABILITY_THRESHOLD = 1.75 + INTERACTION_STABILITY_THRESHOLD = 2.5 + + def __init__(self, profiles, processor): + """Intialize. + + Args: + profiles (ProfileManager) Manager of the profile dump files. + processor (SymbolOffsetProcessor) Symbol table processor for the dumps. + """ + self._profiles = profiles + self._processor = processor + self._phase_offsets = None + + def IsStableProfile(self): + """Verify that the profiling has been stable. + + See ComputeStability for details. + + Returns: + True if the profile was stable as described above. + """ + (startup_stability, common_stability, + interaction_stability) = self.ComputeStability() + + stable = True + if startup_stability > self.STARTUP_STABILITY_THRESHOLD: + logging.error('Startup unstable: %.3f', startup_stability) + stable = False + if common_stability > self.COMMON_STABILITY_THRESHOLD: + logging.error('Common unstable: %.3f', common_stability) + stable = False + if interaction_stability > self.INTERACTION_STABILITY_THRESHOLD: + logging.error('Interaction unstable: %.3f', interaction_stability) + stable = False + + return stable + + def ComputeStability(self): + """Compute heuristic phase stability metrics. + + This computes the ratio in size of symbols between the union and + intersection of all orderfile phases. Intuitively if this ratio is not too + large it means that the profiling phases are stable with respect to the code + they cover. + + Returns: + (float, float, float) A heuristic stability metric for startup, common and + interaction orderfile phases, respectively. + """ + phase_offsets = self._GetOrderfilePhaseOffsets() + assert len(phase_offsets) > 1 # Otherwise the analysis is silly. + + startup_union = set(phase_offsets[0].startup) + startup_intersection = set(phase_offsets[0].startup) + common_union = set(phase_offsets[0].common) + common_intersection = set(phase_offsets[0].common) + interaction_union = set(phase_offsets[0].interaction) + interaction_intersection = set(phase_offsets[0].interaction) + for offsets in phase_offsets[1:]: + startup_union |= set(offsets.startup) + startup_intersection &= set(offsets.startup) + common_union |= set(offsets.common) + common_intersection &= set(offsets.common) + interaction_union |= set(offsets.interaction) + interaction_intersection &= set(offsets.interaction) + startup_stability = self._SafeDiv( + self._processor.OffsetsPrimarySize(startup_union), + self._processor.OffsetsPrimarySize(startup_intersection)) + common_stability = self._SafeDiv( + self._processor.OffsetsPrimarySize(common_union), + self._processor.OffsetsPrimarySize(common_intersection)) + interaction_stability = self._SafeDiv( + self._processor.OffsetsPrimarySize(interaction_union), + self._processor.OffsetsPrimarySize(interaction_intersection)) + return (startup_stability, common_stability, interaction_stability) + + def _GetOrderfilePhaseOffsets(self): + """Compute the phase offsets for each run. + + Returns: + [OrderfilePhaseOffsets] Each run corresponds to an OrderfilePhaseOffsets, + which groups the symbol offsets discovered in the runs. + """ + if self._phase_offsets is not None: + return self._phase_offsets + + assert self._profiles.GetPhases() == set([0, 1]), 'Unexpected phases' + self._phase_offsets = [] + for first, second in zip(self._profiles.GetRunGroupOffsets(phase=0), + self._profiles.GetRunGroupOffsets(phase=1)): + all_first_offsets = self._processor.GetReachedOffsetsFromDump(first) + all_second_offsets = self._processor.GetReachedOffsetsFromDump(second) + first_offsets_set = set(all_first_offsets) + second_offsets_set = set(all_second_offsets) + common_offsets_set = first_offsets_set & second_offsets_set + first_offsets_set -= common_offsets_set + second_offsets_set -= common_offsets_set + + startup = [x for x in all_first_offsets + if x in first_offsets_set] + + interaction = [x for x in all_second_offsets + if x in second_offsets_set] + + common_seen = set() + common = [] + for x in itertools.chain(all_first_offsets, all_second_offsets): + if x in common_offsets_set and x not in common_seen: + common_seen.add(x) + common.append(x) + + self._phase_offsets.append(OrderfilePhaseOffsets( + startup=startup, + interaction=interaction, + common=common)) + + return self._phase_offsets + + @classmethod + def _SafeDiv(cls, a, b): + if not b: + return None + return float(a) / b + + +def _CreateArgumentParser(): + parser = argparse.ArgumentParser( + description='Compute statistics on phased orderfiles') + parser.add_argument('--profile-directory', type=str, required=True, + help=('Directory containing profile runs. Files ' + 'matching {} are used.'.format(PROFILE_GLOB))) + parser.add_argument('--instrumented-build-dir', type=str, + help='Path to the instrumented build', required=True) + parser.add_argument('--library-name', default='libchrome.so', + help=('Chrome shared library name (usually libchrome.so ' + 'or libmonochrome.so')) + return parser + + +def main(): + logging.basicConfig(level=logging.INFO) + parser = _CreateArgumentParser() + args = parser.parse_args() + profiles = process_profiles.ProfileManager( + glob.glob(os.path.join(args.profile_directory, PROFILE_GLOB))) + processor = process_profiles.SymbolOffsetProcessor(os.path.join( + args.instrumented_build_dir, 'lib.unstripped', args.library_name)) + phaser = PhasedAnalyzer(profiles, processor) + print 'Stability: {:.2f} {:.2f} {:.2f}'.format(*phaser.ComputeStability()) + + +if __name__ == '__main__': + main()
diff --git a/tools/cygprofile/phased_orderfile_unittest.py b/tools/cygprofile/phased_orderfile_unittest.py new file mode 100644 index 0000000..eaaf8ed --- /dev/null +++ b/tools/cygprofile/phased_orderfile_unittest.py
@@ -0,0 +1,79 @@ +# Copyright 2018 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. + +"""Tests for phased_orderfile.py.""" + +import collections +import unittest + +import phased_orderfile +import process_profiles + +from test_utils import (SimpleTestSymbol, + TestSymbolOffsetProcessor, + TestProfileManager) + + +class Mod10Processor(object): + """A restricted mock for a SymbolOffsetProcessor. + + This only implements GetReachedOffsetsFromDump, and works by mapping a dump + offset to offset - (offset % 10). If the dump offset is negative, it is marked + as not found. + """ + def GetReachedOffsetsFromDump(self, dump): + return [x - (x % 10) for x in dump if x >= 0] + + +class PhasedOrderfileTestCase(unittest.TestCase): + + def setUp(self): + self._file_counter = 0 + + def File(self, timestamp_sec, phase): + self._file_counter += 1 + return 'file-{}-{}.txt_{}'.format( + self._file_counter, timestamp_sec * 1000 * 1000 * 1000, phase) + + def testProfileStability(self): + symbols = [SimpleTestSymbol(str(i), i, 10) + for i in xrange(20)] + phaser = phased_orderfile.PhasedAnalyzer( + None, TestSymbolOffsetProcessor(symbols)) + opo = lambda s, c, i: phased_orderfile.OrderfilePhaseOffsets( + startup=s, common=c, interaction=i) + phaser._phase_offsets = [opo(range(5), range(6, 10), range(11,15)), + opo(range(4), range(6, 10), range(18, 20))] + self.assertEquals((1.25, 1, None), phaser.ComputeStability()) + + def testIsStable(self): + symbols = [SimpleTestSymbol(str(i), i, 10) + for i in xrange(20)] + phaser = phased_orderfile.PhasedAnalyzer( + None, TestSymbolOffsetProcessor(symbols)) + opo = lambda s, c, i: phased_orderfile.OrderfilePhaseOffsets( + startup=s, common=c, interaction=i) + phaser._phase_offsets = [opo(range(5), range(6, 10), range(11,15)), + opo(range(4), range(6, 10), range(18, 20))] + phaser.STARTUP_STABILITY_THRESHOLD = 1.1 + self.assertFalse(phaser.IsStableProfile()) + phaser.STARTUP_STABILITY_THRESHOLD = 1.5 + self.assertTrue(phaser.IsStableProfile()) + + def testGetOrderfilePhaseOffsets(self): + mgr = TestProfileManager({ + self.File(0, 0): [12, 21, -1, 33], + self.File(0, 1): [31, 49, 52], + self.File(100, 0): [113, 128], + self.File(200, 1): [132, 146], + self.File(300, 0): [19, 20, 32], + self.File(300, 1): [24, 39]}) + phaser = phased_orderfile.PhasedAnalyzer(mgr, Mod10Processor()) + opo = lambda s, c, i: phased_orderfile.OrderfilePhaseOffsets( + startup=s, common=c, interaction=i) + self.assertListEqual([opo([10, 20], [30], [40, 50]), + opo([110, 120], [], []), + opo([], [], [130, 140]), + opo([10], [20, 30], [])], + phaser._GetOrderfilePhaseOffsets())
diff --git a/tools/cygprofile/process_profiles.py b/tools/cygprofile/process_profiles.py new file mode 100755 index 0000000..ba88534 --- /dev/null +++ b/tools/cygprofile/process_profiles.py
@@ -0,0 +1,436 @@ +#!/usr/bin/python +# Copyright 2017 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. + +"""Lists all the reached symbols from an instrumentation dump.""" + +import argparse +import logging +import operator +import os +import sys + +_SRC_PATH = os.path.abspath(os.path.join( + os.path.dirname(__file__), os.pardir, os.pardir)) +path = os.path.join(_SRC_PATH, 'tools', 'cygprofile') +sys.path.append(path) +import symbol_extractor + + +def _Median(items): + if not items: + return None + sorted_items = sorted(items) + if len(sorted_items) & 1: + return sorted_items[len(sorted_items)/2] + else: + return (sorted_items[len(sorted_items)/2 - 1] + + sorted_items[len(sorted_items)/2]) / 2 + + +class SymbolOffsetProcessor(object): + """Utility for processing symbols in binaries. + + This class is used to translate between general offsets into a binary and the + starting offset of symbols in the binary. Because later phases in orderfile + generation have complicated strategies for resolving multiple symbols that map + to the same binary offset, this class is concerned with locating a symbol + containing a binary offset. If such a symbol exists, the start offset will be + unique, even when there are multiple symbol names at the same location in the + binary. + + In the function names below, "dump" is used to refer to arbitrary offsets in a + binary (eg, from a profiling run), while "offset" refers to a symbol + offset. The dump offsets are relative to the start of text, as returned by + lightweight_cygprofile.cc. + + This class manages expensive operations like extracting symbols, so that + higher-level operations can be done in different orders without the caller + managing all the state. + """ + + def __init__(self, binary_filename): + self._binary_filename = binary_filename + self._symbol_infos = None + self._name_to_symbol = None + self._offset_to_primary = None + self._offset_to_symbols = None + + def SymbolInfos(self): + """The symbols associated with this processor's binary. + + The symbols are ordered by offset. + + Returns: + [symbol_extractor.SymbolInfo] + """ + if self._symbol_infos is None: + self._symbol_infos = symbol_extractor.SymbolInfosFromBinary( + self._binary_filename) + self._symbol_infos.sort(key=lambda s: s.offset) + logging.info('%d symbols from %s', + len(self._symbol_infos), self._binary_filename) + return self._symbol_infos + + def NameToSymbolMap(self): + """Map symbol names to their full information. + + Returns: + {symbol name (str): symbol_extractor.SymbolInfo} + """ + if self._name_to_symbol is None: + self._name_to_symbol = {s.name: s for s in self.SymbolInfos()} + return self._name_to_symbol + + def OffsetToPrimaryMap(self): + """The map of a symbol offset in this binary to its primary symbol. + + Several symbols can be aliased to the same address, through ICF. This + returns the first one. The order is consistent for a given binary, as it's + derived from the file layout. We assert that all aliased symbols are the + same size. + + Returns: + {offset (int): primary (symbol_extractor.SymbolInfo)} + """ + if self._offset_to_primary is None: + self._offset_to_primary = {} + for s in self.SymbolInfos(): + if s.offset not in self._offset_to_primary: + self._offset_to_primary[s.offset] = s + else: + curr = self._offset_to_primary[s.offset] + if curr.size != s.size: + assert curr.size == 0 or s.size == 0, ( + 'Nonzero size mismatch between {} and {}'.format( + curr.name, s.name)) + # Upgrade to a symbol with nonzero size, otherwise don't change + # anything so that we use the earliest nonzero-size symbol. + if curr.size == 0 and s.size != 0: + self._offset_to_primary[s.offset] = s + + return self._offset_to_primary + + def OffsetToSymbolsMap(self): + """Map offsets to the set of matching symbols. + + Unlike OffsetToPrimaryMap, this is a 1-to-many mapping. + + Returns; + {offset (int): [symbol_extractor.SymbolInfo]} + """ + if self._offset_to_symbols is None: + self._offset_to_symbols = symbol_extractor.GroupSymbolInfosByOffset( + self.SymbolInfos()) + return self._offset_to_symbols + + def OffsetsPrimarySize(self, offsets): + """Computes the total primary size of a set of offsets. + + Args: + offsets (int iterable) a set of offsets. + + Returns + int The sum of the primary size of the offsets. + """ + return sum(self.OffsetToPrimaryMap()[x].size for x in offsets) + + def GetReachedOffsetsFromDump(self, dump): + """Find the symbol offsets from a list of binary offsets. + + The dump is a list offsets into a .text section. This finds the symbols + which contain the dump offsets, and returns their offsets. Note that while + usually a symbol offset corresponds to a single symbol, in some cases + several symbols will map to the same offset. For that reason this function + returns only the offset list. See cyglog_to_orderfile.py for computing more + information about symbols. + + Args: + dump: (int iterable) Dump offsets, for example as returned by MergeDumps(). + + Returns: + [int] Reached symbol offsets. + """ + dump_offset_to_symbol_info = self._GetDumpOffsetToSymbolInfo() + logging.info('Offset to Symbol size = %d', len(dump_offset_to_symbol_info)) + assert max(dump) / 4 <= len(dump_offset_to_symbol_info) + already_seen = set() + reached_offsets = [] + reached_return_addresses_not_found = 0 + for dump_offset in dump: + symbol_info = dump_offset_to_symbol_info[dump_offset / 4] + if symbol_info is None: + reached_return_addresses_not_found += 1 + continue + if symbol_info.offset in already_seen: + continue + reached_offsets.append(symbol_info.offset) + already_seen.add(symbol_info.offset) + if reached_return_addresses_not_found: + logging.warning('%d return addresses don\'t map to any symbol', + reached_return_addresses_not_found) + return reached_offsets + + def MatchSymbolNames(self, symbol_names): + """Find the symbols in this binary which match a list of symbols. + + Args: + symbol_names (str iterable) List of symbol names. + + Returns: + [symbol_extractor.SymbolInfo] Symbols in this binary matching the names. + """ + our_symbol_names = set(s.name for s in self.SymbolInfos()) + matched_names = our_symbol_names.intersection(set(symbol_names)) + return [self.NameToSymbolMap()[n] for n in matched_names] + + def _GetDumpOffsetToSymbolInfo(self): + """Computes an array mapping each word in .text to a symbol. + + Returns: + [symbol_extractor.SymbolInfo or None] For every 4 bytes of the .text + section, maps it to a symbol, or None. + """ + min_offset = min(s.offset for s in self.SymbolInfos()) + max_offset = max(s.offset + s.size for s in self.SymbolInfos()) + text_length_words = (max_offset - min_offset) / 4 + offset_to_symbol_info = [None for _ in xrange(text_length_words)] + for s in self.SymbolInfos(): + offset = s.offset - min_offset + for i in range(offset / 4, (offset + s.size) / 4): + offset_to_symbol_info[i] = s + return offset_to_symbol_info + + +class ProfileManager(object): + """Manipulates sets of profiles. + + The manager supports only lightweight-style profiles (see + lightweight_cygprofile.cc) and not the older cygprofile offset lists. + + A "profile set" refers to a set of data from an instrumented version of chrome + that will be processed together, usually to produce a single orderfile. A + "run" refers to a session of chrome, visiting several pages and thus + comprising a browser process and at least one renderer process. A "dump" + refers to the instrumentation in chrome writing out offsets of instrumented + functions. There may be several dumps per run, for example one describing + chrome startup and a second describing steady-state page interaction. Each + process in a run produces one file per dump. + + These dump files have a timestamp of the dump time. Each process produces its + own timestamp, but the dumps from each process occur very near in time to each + other (< 1 second). If there are several dumps per run, each set of dumps is + marked by a "phase" in the filename which is consistent across processes. For + example the dump for the startup could be phase 0 and then the steady-state + would be labeled phase 1. + + We assume the files are named like *-TIMESTAMP.SUFFIX_PHASE, where TIMESTAMP + is in nanoseconds, SUFFIX is string without dashes, PHASE is an integer + numbering the phases as 0, 1, 2..., and the only dot is the one between + TIMESTAMP and SUFFIX. Note that the current dump filename also includes a + process id which is currently unused. + + This manager supports several configurations of dumps. + + * A single dump from a single run. These files are merged together to produce + a single dump without regard for browser versus renderer methods. + + * Several phases of dumps from a single run. Files are grouped by phase as + described above. + + * Several phases of dumps from multiple runs from a set of telemetry + benchmarks. The timestamp is used to distinguish each run because each + benchmark takes < 10 seconds to run but there are > 50 seconds of setup + time. This files can be grouped into run sets that are within 30 seconds of + each other. Each run set is then grouped into phases as before. + """ + class _RunGroup(object): + RUN_GROUP_THRESHOLD_NS = 30e9 + + def __init__(self): + self._filenames = [] + + def Filenames(self, phase=None): + if phase is None: + return self._filenames + return [f for f in self._filenames + if ProfileManager._Phase(f) == phase] + + def Add(self, filename): + self._filenames.append(filename) + + def IsCloseTo(self, filename): + run_group_ts = _Median( + [ProfileManager._Timestamp(f) for f in self._filenames]) + return abs(ProfileManager._Timestamp(filename) - + run_group_ts) < self.RUN_GROUP_THRESHOLD_NS + + def __init__(self, filenames): + """Initialize a ProfileManager. + + Args: + filenames ([str]): List of filenames describe the profile set. + """ + self._filenames = sorted(filenames, key=self._Timestamp) + self._run_groups = None + + def GetPhases(self): + """Return the set of phases of all orderfiles. + + Returns: + set(int) + """ + return set(self._Phase(f) for f in self._filenames) + + def GetMergedOffsets(self, phase=None): + """Merges files, as if from a single dump. + + Args: + phase (int, optional) If present, restrict to this phase. + + Returns: + [int] Ordered list of reached offsets. Each offset only appears + once in the output, in the order of the first dump that contains it. + """ + if phase is None: + return self._GetOffsetsForGroup(self._filenames) + return self._GetOffsetsForGroup(f for f in self._filenames + if self._Phase(f) == phase) + + def GetRunGroupOffsets(self, phase=None): + """Merges files from each run group and returns offset list for each. + + Args: + phase (int, optional) If present, restrict to this phase. + + Returns: + [ [int] ] List of offsets lists, each as from GetMergedOffsets. + """ + return [self._GetOffsetsForGroup(g) for g in self._GetRunGroups(phase)] + + def _GetOffsetsForGroup(self, filenames): + dumps = [self._ReadOffsets(f) for f in filenames] + seen_offsets = set() + result = [] + for dump in dumps: + for offset in dump: + if offset not in seen_offsets: + result.append(offset) + seen_offsets.add(offset) + return result + + def _GetRunGroups(self, phase=None): + if self._run_groups is None: + self._ComputeRunGroups() + return [g.Filenames(phase) for g in self._run_groups] + + @classmethod + def _Timestamp(cls, filename): + dash_index = filename.rindex('-') + dot_index = filename.rindex('.') + return int(filename[dash_index+1:dot_index]) + + @classmethod + def _Phase(cls, filename): + return int(filename.split('_')[-1]) + + def _ReadOffsets(self, filename): + return [int(x.strip()) for x in open(filename)] + + def _ComputeRunGroups(self): + self._run_groups = [] + for f in self._filenames: + for g in self._run_groups: + if g.IsCloseTo(f): + g.Add(f) + break + else: + g = self._RunGroup() + g.Add(f) + self._run_groups.append(g) + + +def GetReachedOffsetsFromDumpFiles(dump_filenames, library_filename): + """Produces a list of symbol offsets reached by the dumps. + + Args: + dump_filenames (str iterable) A list of dump filenames. + library_filename (str) The library file which the dumps refer to. + + Returns: + [int] A list of symbol offsets. This order of symbol offsets produced is + given by the deduplicated order of offsets found in dump_filenames (see + also MergeDumps(). + """ + dump = ProfileManager(dump_filenames).GetMergedOffsets() + if not dump: + logging.error('Empty dump, cannot continue: %s', '\n'.join(dump_filenames)) + return None + logging.info('Reached offsets = %d', len(dump)) + processor = SymbolOffsetProcessor(library_filename) + return processor.GetReachedOffsetsFromDump(dump) + + +def CreateArgumentParser(): + """Returns an ArgumentParser.""" + parser = argparse.ArgumentParser(description='Outputs reached symbols') + parser.add_argument('--instrumented-build-dir', type=str, + help='Path to the instrumented build', required=True) + parser.add_argument('--build-dir', type=str, help='Path to the build dir', + required=True) + parser.add_argument('--dumps', type=str, help='A comma-separated list of ' + 'files with instrumentation dumps', required=True) + parser.add_argument('--output', type=str, help='Output filename', + required=True) + parser.add_argument('--offsets-output', type=str, + help='Output filename for the symbol offsets', + required=False, default=None) + parser.add_argument('--library-name', default='libchrome.so', + help=('Chrome shared library name (usually libchrome.so ' + 'or libmonochrome.so')) + return parser + + +def main(): + logging.basicConfig(level=logging.INFO) + parser = CreateArgumentParser() + args = parser.parse_args() + logging.info('Merging dumps') + dump_files = args.dumps.split(',') + profile_manager = ProfileManager(dump_files) + profile_manager.SortByTimestamp() + dumps = profile_manager.GetMergedOffsets() + + instrumented_native_lib = os.path.join(args.instrumented_build_dir, + 'lib.unstripped', args.library_name) + regular_native_lib = os.path.join(args.build_dir, + 'lib.unstripped', args.library_name) + + instrumented_processor = SymbolOffsetProcessor(instrumented_native_lib) + + reached_offsets = instrumented_processor.GetReachedOffsetsFromDumps(dumps) + if args.offsets_output: + with file(args.offsets_output, 'w') as f: + f.write('\n'.join(map(str, reached_offsets))) + logging.info('Reached Offsets = %d', len(reached_offsets)) + + primary_map = instrumented_processor.OffsetToPrimaryMap() + reached_primary_symbols = set( + primary_map[offset] for offset in reached_offsets) + logging.info('Reached symbol names = %d', len(reached_primary_symbols)) + + regular_processor = SymbolOffsetProcessor(regular_native_lib) + matched_in_regular_build = regular_processor.MatchSymbolNames( + s.name for s in reached_primary_symbols) + logging.info('Matched symbols = %d', len(matched_in_regular_build)) + total_size = sum(s.size for s in matched_in_regular_build) + logging.info('Total reached size = %d', total_size) + + with open(args.output, 'w') as f: + for s in matched_in_regular_build: + f.write(s.name + '\n') + + +if __name__ == '__main__': + main()
diff --git a/tools/cygprofile/process_profiles_unittest.py b/tools/cygprofile/process_profiles_unittest.py new file mode 100644 index 0000000..7d0ead7 --- /dev/null +++ b/tools/cygprofile/process_profiles_unittest.py
@@ -0,0 +1,170 @@ +# Copyright 2017 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. + +"""Tests for process_profiles.py.""" + +import collections +import unittest + +import process_profiles + +from test_utils import (SimpleTestSymbol, + TestSymbolOffsetProcessor, + TestProfileManager) + +class ProcessProfilesTestCase(unittest.TestCase): + + def setUp(self): + self.symbol_0 = SimpleTestSymbol('0', 0, 0) + self.symbol_1 = SimpleTestSymbol('1', 8, 16) + self.symbol_2 = SimpleTestSymbol('2', 32, 8) + self.symbol_3 = SimpleTestSymbol('3', 40, 12) + self.offset_to_symbol_info = ( + [None, None] + [self.symbol_1] * 4 + [None] * 2 + [self.symbol_2] * 2 + + [self.symbol_3] * 3) + self.symbol_infos = [self.symbol_0, self.symbol_1, + self.symbol_2, self.symbol_3] + self._file_counter = 0 + + def File(self, timestamp_sec, phase): + self._file_counter += 1 + return 'file-{}-{}.txt_{}'.format( + self._file_counter, timestamp_sec * 1000 * 1000 * 1000, phase) + + def testGetOffsetToSymbolInfo(self): + processor = TestSymbolOffsetProcessor(self.symbol_infos) + offset_to_symbol_info = processor._GetDumpOffsetToSymbolInfo() + self.assertListEqual(self.offset_to_symbol_info, offset_to_symbol_info) + + def testGetReachedOffsetsFromDump(self): + processor = TestSymbolOffsetProcessor(self.symbol_infos) + # 2 hits for symbol_1, 0 for symbol_2, 1 for symbol_3 + dump = [8, 12, 48] + reached = processor.GetReachedOffsetsFromDump(dump) + self.assertListEqual([self.symbol_1.offset, self.symbol_3.offset], reached) + # Ordering matters, no repetitions + dump = [48, 12, 8, 12, 8, 16] + reached = processor.GetReachedOffsetsFromDump(dump) + self.assertListEqual([self.symbol_3.offset, self.symbol_1.offset], reached) + + def testSymbolNameToPrimary(self): + symbol_infos = [SimpleTestSymbol('1', 8, 16), + SimpleTestSymbol('AnAlias', 8, 16), + SimpleTestSymbol('Another', 40, 16)] + processor = TestSymbolOffsetProcessor(symbol_infos) + self.assertDictEqual({8: symbol_infos[0], + 40: symbol_infos[2]}, processor.OffsetToPrimaryMap()) + + def testOffsetToSymbolsMap(self): + symbol_infos = [SimpleTestSymbol('1', 8, 16), + SimpleTestSymbol('AnAlias', 8, 16), + SimpleTestSymbol('Another', 40, 16)] + processor = TestSymbolOffsetProcessor(symbol_infos) + self.assertDictEqual({8: [symbol_infos[0], symbol_infos[1]], + 40: [symbol_infos[2]]}, + processor.OffsetToSymbolsMap()) + + def testPrimarySizeMismatch(self): + symbol_infos = [SimpleTestSymbol('1', 8, 16), + SimpleTestSymbol('AnAlias', 8, 32)] + processor = TestSymbolOffsetProcessor(symbol_infos) + self.assertRaises(AssertionError, processor.OffsetToPrimaryMap) + symbol_infos = [SimpleTestSymbol('1', 8, 0), + SimpleTestSymbol('2', 8, 32), + SimpleTestSymbol('3', 8, 32), + SimpleTestSymbol('4', 8, 0),] + processor = TestSymbolOffsetProcessor(symbol_infos) + self.assertDictEqual({8: symbol_infos[1]}, processor.OffsetToPrimaryMap()) + + def testMatchSymbols(self): + symbols = [SimpleTestSymbol('W', 30, 10), + SimpleTestSymbol('Y', 60, 5), + SimpleTestSymbol('X', 100, 10)] + processor = TestSymbolOffsetProcessor(symbols) + self.assertListEqual(symbols[1:3], + processor.MatchSymbolNames(['Y', 'X'])) + + def testOffsetsPrimarySize(self): + symbols = [SimpleTestSymbol('W', 10, 1), + SimpleTestSymbol('X', 20, 2), + SimpleTestSymbol('Y', 30, 4), + SimpleTestSymbol('Z', 40, 8)] + processor = TestSymbolOffsetProcessor(symbols) + self.assertEqual(13, processor.OffsetsPrimarySize([10, 30, 40])) + + def testMedian(self): + self.assertEquals(None, process_profiles._Median([])) + self.assertEquals(5, process_profiles._Median([5])) + self.assertEquals(5, process_profiles._Median([1, 5, 20])) + self.assertEquals(5, process_profiles._Median([4, 6])) + self.assertEquals(5, process_profiles._Median([1, 4, 6, 100])) + self.assertEquals(5, process_profiles._Median([1, 4, 5, 6, 100])) + + def testRunGroups(self): + files = [self.File(40, 0), self.File(100, 0), self.File(200, 1), + self.File(35, 1), self.File(42, 0), self.File(95, 0)] + mgr = process_profiles.ProfileManager(files) + mgr._ComputeRunGroups() + self.assertEquals(3, len(mgr._run_groups)) + self.assertEquals(3, len(mgr._run_groups[0].Filenames())) + self.assertEquals(2, len(mgr._run_groups[1].Filenames())) + self.assertEquals(1, len(mgr._run_groups[2].Filenames())) + self.assertTrue(files[0] in mgr._run_groups[0].Filenames()) + self.assertTrue(files[3] in mgr._run_groups[0].Filenames()) + self.assertTrue(files[4] in mgr._run_groups[0].Filenames()) + self.assertTrue(files[1] in mgr._run_groups[1].Filenames()) + self.assertTrue(files[5] in mgr._run_groups[1].Filenames()) + self.assertTrue(files[2] in mgr._run_groups[2].Filenames()) + + def testReadOffsets(self): + mgr = TestProfileManager({ + self.File(30, 0): [1, 3, 5, 7], + self.File(40, 1): [8, 10], + self.File(50, 0): [13, 15]}) + self.assertListEqual([1, 3, 5, 7, 8, 10, 13, 15], + mgr.GetMergedOffsets()) + self.assertListEqual([8, 10], mgr.GetMergedOffsets(1)) + self.assertListEqual([], mgr.GetMergedOffsets(2)) + + def testRunGroupOffsets(self): + mgr = TestProfileManager({ + self.File(30, 0): [1, 2, 3, 4], + self.File(150, 0): [9, 11, 13], + self.File(40, 1): [5, 6, 7]}) + offsets_list = mgr.GetRunGroupOffsets() + self.assertEquals(2, len(offsets_list)) + self.assertListEqual([1, 2, 3, 4, 5, 6, 7], offsets_list[0]) + self.assertListEqual([9, 11, 13], offsets_list[1]) + offsets_list = mgr.GetRunGroupOffsets(0) + self.assertEquals(2, len(offsets_list)) + self.assertListEqual([1, 2, 3, 4], offsets_list[0]) + self.assertListEqual([9, 11, 13], offsets_list[1]) + offsets_list = mgr.GetRunGroupOffsets(1) + self.assertEquals(2, len(offsets_list)) + self.assertListEqual([5, 6, 7], offsets_list[0]) + self.assertListEqual([], offsets_list[1]) + + def testSorted(self): + # The fact that the ProfileManager sorts by filename is implicit in the + # other tests. It is tested explicitly here. + mgr = TestProfileManager({ + self.File(40, 0): [1, 2, 3, 4], + self.File(150, 0): [9, 11, 13], + self.File(30, 1): [5, 6, 7]}) + offsets_list = mgr.GetRunGroupOffsets() + self.assertEquals(2, len(offsets_list)) + self.assertListEqual([5, 6, 7, 1, 2, 3, 4], offsets_list[0]) + + def testPhases(self): + mgr = TestProfileManager({ + self.File(40, 0): [], + self.File(150, 0): [], + self.File(30, 1): [], + self.File(30, 2): [], + self.File(30, 0): []}) + self.assertEquals(set([0,1,2]), mgr.GetPhases()) + + +if __name__ == '__main__': + unittest.main()
diff --git a/tools/cygprofile/profile_android_startup.py b/tools/cygprofile/profile_android_startup.py index d906ad9..ba96bce8 100755 --- a/tools/cygprofile/profile_android_startup.py +++ b/tools/cygprofile/profile_android_startup.py
@@ -16,11 +16,10 @@ import shutil import subprocess import sys -import tempfile import time -sys.path.append(os.path.join(sys.path[0], '..', '..', - 'third_party', 'catapult', 'devil')) +_SRC_PATH = os.path.join(os.path.dirname(__file__), os.pardir, os.pardir) +sys.path.append(os.path.join(_SRC_PATH, 'third_party', 'catapult', 'devil')) from devil.android import apk_helper from devil.android import device_errors from devil.android import device_utils @@ -28,19 +27,15 @@ from devil.android import forwarder from devil.android.sdk import intent -sys.path.append(os.path.join(sys.path[0], '..', '..', 'build', 'android')) +sys.path.append(os.path.join(_SRC_PATH, 'build', 'android')) import devil_chromium from pylib import constants -sys.path.append(os.path.join(sys.path[0], '..', '..', 'tools', 'perf')) +sys.path.append(os.path.join(_SRC_PATH, 'tools', 'perf')) from core import path_util sys.path.append(path_util.GetTelemetryDir()) -from telemetry.internal.util import wpr_server - -sys.path.append(os.path.join(sys.path[0], '..', '..', - 'third_party', 'webpagereplay')) -import adb_install_cert -import certutils +from telemetry.internal.util import webpagereplay_go_server +from telemetry.internal.util import binary_manager class NoCyglogDataError(Exception): @@ -65,6 +60,21 @@ raise Exception('Exception executing command %s' % ' '.join(cmd)) +def _SimulateSwipe(device, x1, y1, x2, y2): + """Simulates a swipe on a device from (x1, y1) to (x2, y2). + + Coordinates are in (device dependent) pixels, and the origin is at the upper + left corner. + The simulated swipe will take 300ms. + + Args: + device: (device_utils.DeviceUtils) device to run the command on. + x1, y1, x2, y2: (int) Coordinates. + """ + args = [str(x) for x in (x1, y1, x2, y2)] + device.RunShellCommand(['input', 'swipe'] + args) + + class WprManager(object): """A utility to download a WPR archive, host it, and forward device ports to it. @@ -72,23 +82,20 @@ _WPR_BUCKET = 'chrome-partner-telemetry' - def __init__(self, wpr_archive, device, cmdline_file): + def __init__(self, wpr_archive, device, cmdline_file, package): self._device = device self._wpr_archive = wpr_archive self._wpr_archive_hash = wpr_archive + '.sha1' self._cmdline_file = cmdline_file self._wpr_server = None - self._wpr_ca_cert_path = None - self._device_cert_util = None self._host_http_port = None self._host_https_port = None - self._is_test_ca_installed = False self._flag_changer = None + self._package = package def Start(self): """Set up the device and host for WPR.""" self.Stop() - # TODO(lizeb,pasko): make self._InstallTestCa() work self._BringUpWpr() self._StartForwarder() @@ -96,7 +103,6 @@ """Clean up the device and host's WPR setup.""" self._StopForwarder() self._StopWpr() - # TODO(lizeb,pasko): make self._RemoveTestCa() work def __enter__(self): self.Start() @@ -104,57 +110,20 @@ def __exit__(self, unused_exc_type, unused_exc_val, unused_exc_tb): self.Stop() - def _InstallTestCa(self): - """Generates and deploys a test certificate authority.""" - print 'Installing test certificate authority on device: %s' % ( - self._device.adb.GetDeviceSerial()) - self._wpr_ca_cert_path = os.path.join(tempfile.mkdtemp(), 'testca.pem') - certutils.write_dummy_ca_cert(*certutils.generate_dummy_ca_cert(), - cert_path=self._wpr_ca_cert_path) - self._device_cert_util = adb_install_cert.AndroidCertInstaller( - self._device.adb.GetDeviceSerial(), None, self._wpr_ca_cert_path) - self._device_cert_util.install_cert(overwrite_cert=True) - self._is_test_ca_installed = True - - def _RemoveTestCa(self): - """Remove root CA generated by previous call to InstallTestCa(). - - Removes the test root certificate from both the device and host machine. - """ - print 'Cleaning up test CA...' - if not self._wpr_ca_cert_path: - return - - if self._is_test_ca_installed: - try: - self._device_cert_util.remove_cert() - except Exception: - # Best effort cleanup - show the error and continue. - logging.error( - 'Error while trying to remove certificate authority: %s. ' - % self._adb.device_serial()) - self._is_test_ca_installed = False - - shutil.rmtree(os.path.dirname(self._wpr_ca_cert_path), ignore_errors=True) - self._wpr_ca_cert_path = None - self._device_cert_util = None - def _BringUpWpr(self): """Start the WPR server on the host and the forwarder on the device.""" print 'Starting WPR on host...' _DownloadFromCloudStorage(self._WPR_BUCKET, self._wpr_archive_hash) - args = ['--use_closest_match'] - if self._is_test_ca_installed: - args.extend(['--should_generate_certs', - '--https_root_ca_cert_path=' + self._wpr_ca_cert_path]) - self._wpr_server = wpr_server.ReplayServer(self._wpr_archive, - '127.0.0.1', 0, 0, None, args) - ports = self._wpr_server.StartServer()[:-1] - self._host_http_port = ports[0] - self._host_https_port = ports[1] + if binary_manager.NeedsInit(): + binary_manager.InitDependencyManager([]) + self._wpr_server = webpagereplay_go_server.ReplayServer( + self._wpr_archive, '127.0.0.1', 0, 0, replay_options=[]) + ports = self._wpr_server.StartServer() + self._host_http_port = ports['http'] + self._host_https_port = ports['https'] def _StopWpr(self): - """ Stop the WPR and forwarder. """ + """ Stop the WPR and forwarder.""" print 'Stopping WPR on host...' if self._wpr_server: self._wpr_server.StopServer() @@ -180,14 +149,27 @@ self._flag_changer.AddFlags([ '--host-resolver-rules=MAP * 127.0.0.1,EXCLUDE localhost', '--testing-fixed-http-port=%s' % device_http, - '--testing-fixed-https-port=%s' % device_https]) + '--testing-fixed-https-port=%s' % device_https, + + # Allows to selectively avoid certificate errors in Chrome. Unlike + # --ignore-certificate-errors this allows exercising the HTTP disk cache + # and avoids re-establishing socket connections. The value is taken from + # the WprGo documentation at: + # https://github.com/catapult-project/catapult/blob/master/web_page_replay_go/README.md + '--ignore-certificate-errors-spki-list=' + + 'PhrPvGIaAMmd29hj8BCZOq096yj7uMpRNHpn5PDxI6I=', + + # The flag --ignore-certificate-errors-spki-list (above) requires + # specifying the profile directory, otherwise it is silently ignored. + '--user-data-dir=/data/data/{}'.format(self._package)]) def _StopForwarder(self): """Shuts down the port forwarding service.""" - print 'Stopping device forwarder...' if self._flag_changer: + print 'Restoring flags while stopping forwarder, but why?...' self._flag_changer.Restore() self._flag_changer = None + print 'Stopping device forwarder...' forwarder.Forwarder.UnmapAllDevicePorts(self._device) @@ -200,28 +182,35 @@ _DEVICE_CYGLOG_DIR = '/data/local/tmp/chrome/cyglog' - # TEST_URL must be a url in the WPR_ARCHIVE. - _TEST_URL = 'https://www.google.com/#hl=en&q=science' + TEST_URL = 'https://www.google.com/#hl=en&q=science' _WPR_ARCHIVE = os.path.join( - os.path.dirname(__file__), 'top_10_mobile_002.wpr') + os.path.dirname(__file__), 'memory_top_10_mobile_000.wprgo') - # TODO(jbudorick): Make host_cyglog_dir mandatory after updating - # downstream clients. See crbug.com/639831 for context. - def __init__(self, output_directory, host_cyglog_dir=None): + def __init__(self, output_directory, host_cyglog_dir, use_wpr, urls, + simulate_user): + """Constructor. + + Args: + output_directory: (str) Chrome build directory. + host_cyglog_dir: (str) Where to store the profiles. + use_wpr: (bool) Whether to use Web Page Replay. + urls: (str) URLs to load. Have to be contained in the WPR archive if + use_wpr is True. + simulate_user: (bool) Whether to simulate a user. + """ devices = device_utils.DeviceUtils.HealthyDevices() self._device = devices[0] self._cygprofile_tests = os.path.join( output_directory, 'cygprofile_unittests') - self._host_cyglog_dir = host_cyglog_dir or os.path.join( - output_directory, 'cyglog_data') + self._host_cyglog_dir = host_cyglog_dir + self._use_wpr = use_wpr + self._urls = urls + self._simulate_user = simulate_user self._SetUpDevice() def RunCygprofileTests(self): """Run the cygprofile unit tests suite on the device. - Args: - path_to_tests: The location on the host machine with the compiled - cygprofile test binary. Returns: The exit code for the tests. """ @@ -244,8 +233,10 @@ apk: The location of the chrome apk to profile. package_info: A PackageInfo structure describing the chrome apk, as from pylib/constants. + Returns: A list of cygprofile data files. + Raises: NoCyglogDataError: No data was found on the device. """ @@ -253,18 +244,12 @@ try: changer = self._SetChromeFlags(package_info) self._SetUpDeviceFolders() - # Start up chrome once with a blank page, just to get the one-off - # activities out of the way such as apk resource extraction and profile - # creation. - self._StartChrome(package_info, 'about:blank') - time.sleep(15) - self._KillChrome(package_info) - self._SetUpDeviceFolders() - with WprManager(self._WPR_ARCHIVE, self._device, - package_info.cmdline_file): - self._StartChrome(package_info, self._TEST_URL) - time.sleep(90) - self._KillChrome(package_info) + if self._use_wpr: + with WprManager(self._WPR_ARCHIVE, self._device, + package_info.cmdline_file, package_info.package): + self._RunProfileCollection(package_info, self._simulate_user) + else: + self._RunProfileCollection(package_info, self._simulate_user) finally: self._RestoreChromeFlags(changer) @@ -272,6 +257,39 @@ self._DeleteDeviceData() return data + def _RunProfileCollection(self, package_info, simulate_user): + """Runs the profile collection tasks. + + If |simulate_user| is True, then try to simulate a real user, with swiping. + Also do a first load of the page instead of about:blank, in order to + exercise the cache. This is not desirable with a page that only contains + cachable resources, as in this instance the network code will not be called. + + Args: + package_info: Which Chrome package to use. + simulate_user: (bool) Whether to try to simulate a user interacting with + the browser. + """ + initial_url = self._urls[0] if simulate_user else 'about:blank' + # Start up chrome once with a page, just to get the one-off + # activities out of the way such as apk resource extraction and profile + # creation. + self._StartChrome(package_info, initial_url) + time.sleep(15) + self._KillChrome(package_info) + self._SetUpDeviceFolders() + for url in self._urls: + self._StartChrome(package_info, url) + time.sleep(15) + if simulate_user: + # Down, down, up, up. + _SimulateSwipe(self._device, 200, 700, 200, 300) + _SimulateSwipe(self._device, 200, 700, 200, 300) + _SimulateSwipe(self._device, 200, 700, 200, 1000) + _SimulateSwipe(self._device, 200, 700, 200, 1000) + time.sleep(30) + self._KillChrome(package_info) + def Cleanup(self): """Delete all local and device files left over from profiling. """ self._DeleteDeviceData() @@ -279,10 +297,9 @@ def _Install(self, apk): """Installs Chrome.apk on the device. + Args: apk: The location of the chrome apk to profile. - package_info: A PackageInfo structure describing the chrome apk, - as from pylib/constants. """ print 'Installing apk...' self._device.Install(apk) @@ -317,7 +334,7 @@ changer.Restore() def _SetUpDeviceFolders(self): - """Creates folders on the device to store cyglog data. """ + """Creates folders on the device to store cyglog data.""" print 'Setting up device folders...' self._DeleteDeviceData() self._device.RunShellCommand( @@ -336,7 +353,7 @@ intent.Intent(package=package_info.package, activity=package_info.activity, data=url, - extras={'create_new_tab' : True}), + extras={'create_new_tab': True}), blocking=True, force_stop=True) def _KillChrome(self, package_info): @@ -351,10 +368,11 @@ os.mkdir(self._host_cyglog_dir) def _PullCyglogData(self): - """Pull the cyglog data off of the device. + """Pulls the cyglog data off of the device. Returns: A list of cyglog data files which were pulled. + Raises: NoCyglogDataError: No data was found on the device. """ @@ -378,7 +396,19 @@ return [os.path.join(cyglog_dir, x) for x in files] -def main(): +def AddProfileCollectionArguments(parser): + """Adds the profiling collection arguments to |parser|.""" + parser.add_argument( + '--no-wpr', action='store_true', help='Don\'t use WPR.') + parser.add_argument('--urls', type=str, help='URLs to load.', + default=[AndroidProfileTool.TEST_URL], + nargs='+') + parser.add_argument( + '--simulate-user', action='store_true', help='More realistic collection.') + + +def CreateArgumentParser(): + """Creates and return the argument parser.""" parser = argparse.ArgumentParser() parser.add_argument( '--adb-path', type=os.path.realpath, @@ -393,7 +423,12 @@ '--trace-directory', type=os.path.realpath, help='Directory in which cyglog traces will be stored. ' 'Defaults to <output-directory>/cyglog_data') + AddProfileCollectionArguments(parser) + return parser + +def main(): + parser = CreateArgumentParser() args = parser.parse_args() devil_chromium.Initialize( @@ -409,7 +444,8 @@ raise Exception('Unable to determine package info for %s' % args.apk_path) profiler = AndroidProfileTool( - args.output_directory, host_cyglog_dir=args.trace_directory) + args.output_directory, host_cyglog_dir=args.trace_directory, + use_wpr=not args.no_wpr, urls=args.urls, simulate_user=args.simulate_user) profiler.CollectProfile(args.apk_path, package_info) return 0
diff --git a/tools/cygprofile/test_utils.py b/tools/cygprofile/test_utils.py new file mode 100644 index 0000000..47043b15 --- /dev/null +++ b/tools/cygprofile/test_utils.py
@@ -0,0 +1,27 @@ +# Copyright 2017 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. + +"""Test utilities for cygprofile scripts.""" + +import collections + +import process_profiles + +SimpleTestSymbol = collections.namedtuple( + 'SimpleTestSymbol', ['name', 'offset', 'size']) + + +class TestSymbolOffsetProcessor(process_profiles.SymbolOffsetProcessor): + def __init__(self, symbol_infos): + super(TestSymbolOffsetProcessor, self).__init__(None) + self._symbol_infos = symbol_infos + + +class TestProfileManager(process_profiles.ProfileManager): + def __init__(self, filecontents_mapping): + super(TestProfileManager, self).__init__(filecontents_mapping.keys()) + self._filecontents_mapping = filecontents_mapping + + def _ReadOffsets(self, filename): + return self._filecontents_mapping[filename]
diff --git a/tools/cygprofile/top_10_mobile_002.wpr.sha1 b/tools/cygprofile/top_10_mobile_002.wpr.sha1 deleted file mode 100644 index caa6d52..0000000 --- a/tools/cygprofile/top_10_mobile_002.wpr.sha1 +++ /dev/null
@@ -1 +0,0 @@ -8bcbec66f88136691a49f02e15e7cf8ccf9a9d7c \ No newline at end of file
diff --git a/tools/cygprofile_win/BUILD.gn b/tools/cygprofile_win/BUILD.gn new file mode 100644 index 0000000..9694a3c --- /dev/null +++ b/tools/cygprofile_win/BUILD.gn
@@ -0,0 +1,12 @@ +# Copyright 2017 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. + +static_library("cygprofile_win") { + sources = [ + "cygprofile.cc", + ] + + # Don't instrument this library. + configs -= [ "//build/config/win:default_cygprofile_instrumentation" ] +}
diff --git a/tools/cygprofile_win/OWNERS b/tools/cygprofile_win/OWNERS new file mode 100644 index 0000000..8d8029ea --- /dev/null +++ b/tools/cygprofile_win/OWNERS
@@ -0,0 +1 @@ +hans@chromium.org
diff --git a/tools/cygprofile_win/cygprofile.cc b/tools/cygprofile_win/cygprofile.cc new file mode 100644 index 0000000..87045a75 --- /dev/null +++ b/tools/cygprofile_win/cygprofile.cc
@@ -0,0 +1,103 @@ +// Copyright (c) 2017 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 <stdio.h> +#include <atomic> +#include <string> +#include <unordered_set> + +#include <windows.h> // Needs to be included before the others. + +#include <dbghelp.h> +#include <process.h> + +namespace { + +// The main purpose of the order file is to optimize startup time, +// so capturing the first N function calls is enough. +static constexpr int kSamplesCapacity = 25 * 1024 * 1024; + +void* samples[kSamplesCapacity]; +std::atomic_int num_samples; +std::atomic_int done; + +// Path to the dump file. %lu will be substituted by the process id. +static const char kDumpFile[] = "/src/tmp/cygprofile_%lu.txt"; + +// Symbolize the samples and write them to disk. +void dump(void*) { + HMODULE dbghelp = LoadLibraryA("dbghelp.dll"); + auto sym_from_addr = reinterpret_cast<decltype(::SymFromAddr)*>( + ::GetProcAddress(dbghelp, "SymFromAddr")); + auto sym_initialize = reinterpret_cast<decltype(::SymInitialize)*>( + ::GetProcAddress(dbghelp, "SymInitialize")); + auto sym_set_options = reinterpret_cast<decltype(::SymSetOptions)*>( + ::GetProcAddress(dbghelp, "SymSetOptions")); + + char filename[MAX_PATH]; + snprintf(filename, sizeof(filename), kDumpFile, ::GetCurrentProcessId()); + FILE* f = fopen(filename, "w"); + if (!f) + return; + + sym_initialize(::GetCurrentProcess(), NULL, TRUE); + sym_set_options(SYMOPT_DEFERRED_LOADS | SYMOPT_PUBLICS_ONLY); + char sym_buf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)]; + + std::unordered_set<void*> seen; + std::unordered_set<std::string> seen_names; + + for (void* sample : samples) { + // Only print the first call of a function. + if (seen.count(sample)) + continue; + seen.insert(sample); + + SYMBOL_INFO* symbol = reinterpret_cast<SYMBOL_INFO*>(sym_buf); + symbol->SizeOfStruct = sizeof(SYMBOL_INFO); + symbol->MaxNameLen = MAX_SYM_NAME; + DWORD64 offset = 0; + + if (sym_from_addr(::GetCurrentProcess(), reinterpret_cast<DWORD64>(sample), + &offset, symbol)) { + const char* name = symbol->Name; + if (name[0] == '_') + name++; + if (seen_names.count(name)) + continue; + seen_names.insert(name); + + fprintf(f, "%s\n", name); + } + } + + fclose(f); +} + +} // namespace + +extern "C" { + +void __cyg_profile_func_enter(void* this_fn, void* call_site_unused) { + if (done) + return; + + // Get our index for the samples array atomically. + int n = num_samples++; + + if (n < kSamplesCapacity) { + samples[n] = this_fn; + + if (n + 1 == kSamplesCapacity) { + // This is the final sample; start dumping the samples to a file (on a + // separate thread so as not to disturb the main program). + done = 1; + _beginthread(dump, 0, nullptr); + } + } +} + +void __cyg_profile_func_exit(void* this_fn, void* call_site) {} + +} // extern "C"
diff --git a/tools/determinism/deterministic_build_whitelist.pyl b/tools/determinism/deterministic_build_whitelist.pyl index 8a4c4e3..dad8a92 100644 --- a/tools/determinism/deterministic_build_whitelist.pyl +++ b/tools/determinism/deterministic_build_whitelist.pyl
@@ -118,7 +118,6 @@ 'message_center_unittests', 'midi_unittests', 'mojo_common_unittests', - 'mojo_js_unittests', 'mojo_public_bindings_unittests', 'mojo_public_system_unittests', 'mojo_system_unittests', @@ -273,7 +272,6 @@ 'midi_unittests.exe', 'mini_installer.exe', 'mksnapshot.exe', - 'mojo_js_unittests.exe', 'mojo_message_pipe_perftests.exe', 'mojo_public_bindings_perftests.exe', 'mojo_public_bindings_unittests.exe',
diff --git a/tools/fuchsia/OWNERS b/tools/fuchsia/OWNERS new file mode 100644 index 0000000..e7034ea --- /dev/null +++ b/tools/fuchsia/OWNERS
@@ -0,0 +1 @@ +file://build/fuchsia/OWNERS
diff --git a/tools/fuchsia/local-sdk.py b/tools/fuchsia/local-sdk.py index b36238b..b99e786 100755 --- a/tools/fuchsia/local-sdk.py +++ b/tools/fuchsia/local-sdk.py
@@ -4,6 +4,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import hashlib import os import shutil import subprocess @@ -30,6 +31,14 @@ os.makedirs(path) +def BuildForArch(project, arch): + Run('scripts/build-zircon.sh', '-p', project) + Run('build/gn/gen.py', '--target_cpu=' + arch, + '--packages=garnet/packages/sdk', '--release', + '--args=bootfs_packages=true') + Run('buildtools/ninja', '-C', 'out/release-' + arch) + + def main(args): if len(args) != 1 or not os.path.isdir(args[0]): print 'usage: %s <path_to_fuchsia_tree>' % SELF_FILE @@ -41,11 +50,10 @@ # Switch to the Fuchsia tree and build an SDK. os.chdir(fuchsia_root) - Run('scripts/build-zircon.sh', '-t', 'x86_64') - Run('scripts/build-zircon.sh', '-t', 'aarch64') - Run('packages/gn/gen.py', '--target_cpu=x86-64', '--modules=sdk', - '--ignore-skia', '--release') - Run('packages/gn/build.py', '--release') + + BuildForArch('x86', 'x86-64') + BuildForArch('arm64', 'aarch64') + tempdir = tempfile.mkdtemp() sdk_tar = os.path.join(tempdir, 'fuchsia-sdk.tgz') Run('go', 'run', 'scripts/makesdk.go', '-output', sdk_tar, '.') @@ -56,9 +64,22 @@ output_dir = os.path.join(REPOSITORY_ROOT, 'third_party', 'fuchsia-sdk') EnsureEmptyDir(output_dir) tarfile.open(sdk_tar, mode='r:gz').extractall(path=output_dir) + + print 'Hashing sysroot...' + # Hash the sysroot to catch updates to the headers, but don't hash the whole + # tree, as we want to avoid rebuilding all of Chromium if it's only e.g. the + # kernel blob has changed. https://crbug.com/793956. + sysroot_hash_obj = hashlib.sha1() + for root, dirs, files in os.walk(os.path.join(output_dir, 'sysroot')): + for f in files: + path = os.path.join(root, f) + sysroot_hash_obj.update(path) + sysroot_hash_obj.update(open(path, 'rb').read()) + sysroot_hash = sysroot_hash_obj.hexdigest() + hash_filename = os.path.join(output_dir, '.hash') with open(hash_filename, 'w') as f: - f.write('locally-built-sdk') + f.write('locally-built-sdk-' + sysroot_hash) # Clean up. shutil.rmtree(tempdir)
diff --git a/tools/fuchsia/run-swarmed.py b/tools/fuchsia/run-swarmed.py new file mode 100755 index 0000000..d963abe3 --- /dev/null +++ b/tools/fuchsia/run-swarmed.py
@@ -0,0 +1,165 @@ +#!/usr/bin/env python + +# Copyright 2017 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. + +"""Runs a Fuchsia gtest-based test on Swarming, optionally many times, +collecting the output of the runs into a directory. Useful for flake checking, +and faster than using trybots by avoiding repeated bot_update, compile, archive, +etc. and allowing greater parallelism. + +To use, run in a new shell (it blocks until all Swarming jobs complete): + + tools/fuchsia/run-swarmed.py -t content_unittests --out-dir=out/fuch + +The logs of the runs will be stored in results/ (or specify a results directory +with --results=some_dir). You can then do something like `grep -L SUCCESS +results/*` to find the tests that failed or otherwise process the log files. +""" + +import argparse +import multiprocessing +import os +import shutil +import subprocess +import sys + + +INTERNAL_ERROR_EXIT_CODE = -1000 + + +def _Spawn(args): + """Triggers a swarming job. The arguments passed are: + - The index of the job; + - The command line arguments object; + - The hash of the isolate job used to trigger; + - Value of --gtest_filter arg, or empty if none. + + The return value is passed to a collect-style map() and consists of: + - The index of the job; + - The json file created by triggering and used to collect results; + - The command line arguments object. + """ + index, args, isolated_hash, gtest_filter = args + json_file = os.path.join(args.results, '%d.json' % index) + trigger_args = [ + 'tools/swarming_client/swarming.py', 'trigger', + '-S', 'https://chromium-swarm.appspot.com', + '-I', 'https://isolateserver.appspot.com', + '-d', 'os', 'Linux', + '-d', 'pool', 'Chrome', + '-d', 'kvm', '1', + '-d', 'gpu', 'none', + '-d', 'cpu', args.arch, + '-s', isolated_hash, + '--dump-json', json_file, + '--', + '--test-launcher-summary-output=${ISOLATED_OUTDIR}/output.json'] + if gtest_filter: + trigger_args.append('--gtest_filter=' + gtest_filter) + else: + filter_file = \ + 'testing/buildbot/filters/fuchsia.' + args.test_name + '.filter' + if os.path.isfile(filter_file): + trigger_args.append('--test-launcher-filter-file=../../' + filter_file) + with open(os.devnull, 'w') as nul: + subprocess.check_call(trigger_args, stdout=nul) + return (index, json_file, args) + + +def _Collect(spawn_result): + index, json_file, args = spawn_result + p = subprocess.Popen([ + 'tools/swarming_client/swarming.py', 'collect', + '-S', 'https://chromium-swarm.appspot.com', + '--json', json_file, + '--task-output-stdout=console'], + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + stdout = p.communicate()[0] + if p.returncode != 0 and len(stdout) < 2**10 and 'Internal error!' in stdout: + exit_code = INTERNAL_ERROR_EXIT_CODE + file_suffix = '.INTERNAL_ERROR' + else: + exit_code = p.returncode + file_suffix = '' if exit_code == 0 else '.FAILED' + filename = '%d%s.stdout.txt' % (index, file_suffix) + with open(os.path.join(args.results, filename), 'w') as f: + f.write(stdout) + return exit_code + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--out-dir', default='out/fuch', help='Build directory.') + parser.add_argument('--test-name', '-t', required=True, + help='Name of test to run.') + parser.add_argument('--arch', '-a', default='detect', + help='CPU architecture of the test binary.') + parser.add_argument('--copies', '-n', type=int, default=1, + help='Number of copies to spawn.') + parser.add_argument('--results', '-r', default='results', + help='Directory in which to store results.') + parser.add_argument('--gtest_filter', + help='Use the given gtest_filter, rather than the ' + 'default filter file, if any.') + + args = parser.parse_args() + + # Determine the CPU architecture of the test binary, if not specified. + if args.arch == 'detect': + executable_info = subprocess.check_output( + ['file', os.path.join(args.out_dir, args.test_name)]) + if 'ARM aarch64' in executable_info: + args.arch = 'arm64', + else: + args.arch = 'x86-64' + + subprocess.check_call( + ['tools/mb/mb.py', 'isolate', '//' + args.out_dir, args.test_name]) + + print 'If you get authentication errors, follow:' + print ' https://www.chromium.org/developers/testing/isolated-testing/for-swes#TOC-Login-on-the-services' + + print 'Uploading to isolate server, this can take a while...' + archive_output = subprocess.check_output( + ['tools/swarming_client/isolate.py', 'archive', + '-I', 'https://isolateserver.appspot.com', + '-i', os.path.join(args.out_dir, args.test_name + '.isolate'), + '-s', os.path.join(args.out_dir, args.test_name + '.isolated')]) + isolated_hash = archive_output.split()[0] + + if os.path.isdir(args.results): + shutil.rmtree(args.results) + os.makedirs(args.results) + + try: + print 'Triggering %d tasks...' % args.copies + pool = multiprocessing.Pool() + spawn_args = map(lambda i: (i, args, isolated_hash, args.gtest_filter), + range(args.copies)) + spawn_results = pool.imap_unordered(_Spawn, spawn_args) + + exit_codes = [] + collect_results = pool.imap_unordered(_Collect, spawn_results) + for result in collect_results: + exit_codes.append(result) + successes = sum(1 for x in exit_codes if x == 0) + errors = sum(1 for x in exit_codes if x == INTERNAL_ERROR_EXIT_CODE) + failures = len(exit_codes) - successes - errors + clear_to_eol = '\033[K' + print('\r[%d/%d] collected: ' + '%d successes, %d failures, %d bot errors...%s' % (len(exit_codes), + args.copies, successes, failures, errors, clear_to_eol)), + sys.stdout.flush() + + print + print 'Results logs collected into', os.path.abspath(args.results) + '.' + finally: + pool.close() + pool.join() + return 0 + + +if __name__ == '__main__': + sys.exit(main())
diff --git a/tools/gdb/gdb_chrome.py b/tools/gdb/gdb_chrome.py index ef42a2c..6b956ed 100644 --- a/tools/gdb/gdb_chrome.py +++ b/tools/gdb/gdb_chrome.py
@@ -217,15 +217,6 @@ pp_set.add_printer('base::Time', '^base::Time$', TimePrinter) -class ManualConstructorPrinter(object): - def __init__(self, val): - self.val = val - - def to_string(self): - return self.val['space_'].cast(self.val.type.template_argument(0)) -pp_set.add_printer('base::ManualConstructor', '^base::ManualConstructor<.*>$', ManualConstructorPrinter) - - class FlatTreePrinter(object): def __init__(self, val): self.val = val
diff --git a/tools/generate_library_loader/OWNERS b/tools/generate_library_loader/OWNERS index 508f05e8..35a2760 100644 --- a/tools/generate_library_loader/OWNERS +++ b/tools/generate_library_loader/OWNERS
@@ -1,2 +1 @@ -phajdan.jr@chromium.org spang@chromium.org
diff --git a/tools/gn/BUILD.gn b/tools/gn/BUILD.gn index ecd84ac..31e24936 100644 --- a/tools/gn/BUILD.gn +++ b/tools/gn/BUILD.gn
@@ -2,12 +2,13 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/config/jumbo.gni") import("//testing/test.gni") import("//testing/libfuzzer/fuzzer_test.gni") defines = [ "GN_BUILD" ] -static_library("gn_lib") { +jumbo_static_library("gn_lib") { configs += [ "//build/config:precompiled_headers" ] sources = [ @@ -276,6 +277,18 @@ } test("gn_unittests") { + deps = [ + ":gn_unittests_sources", + ] + + data = [ + "format_test_data/", + ] +} + +jumbo_source_set("gn_unittests_sources") { + testonly = true + sources = [ "action_target_generator_unittest.cc", "analyzer_unittest.cc", @@ -330,6 +343,8 @@ "substitution_writer_unittest.cc", "target_unittest.cc", "template_unittest.cc", + "test_with_scheduler.cc", + "test_with_scheduler.h", "test_with_scope.cc", "test_with_scope.h", "tokenizer_unittest.cc", @@ -342,11 +357,7 @@ "xml_element_writer_unittest.cc", ] - data = [ - "format_test_data/", - ] - - deps = [ + public_deps = [ ":gn_lib", "//base/test:run_all_unittests", "//base/test:test_support",
diff --git a/tools/gn/action_target_generator.cc b/tools/gn/action_target_generator.cc index 52d64ac9..ca3986eb 100644 --- a/tools/gn/action_target_generator.cc +++ b/tools/gn/action_target_generator.cc
@@ -25,8 +25,7 @@ output_type_(type) { } -ActionTargetGenerator::~ActionTargetGenerator() { -} +ActionTargetGenerator::~ActionTargetGenerator() = default; void ActionTargetGenerator::DoRun() { target_->set_output_type(output_type_); @@ -207,3 +206,16 @@ } return true; } + +bool ActionTargetGenerator::FillInputs() { + const Value* value = scope_->GetValue(variables::kInputs, true); + if (!value) + return true; + + Target::FileList dest_inputs; + if (!ExtractListOfRelativeFiles(scope_->settings()->build_settings(), *value, + scope_->GetSourceDir(), &dest_inputs, err_)) + return false; + target_->config_values().inputs().swap(dest_inputs); + return true; +}
diff --git a/tools/gn/action_target_generator.h b/tools/gn/action_target_generator.h index 3833b81f..0ea3cbb 100644 --- a/tools/gn/action_target_generator.h +++ b/tools/gn/action_target_generator.h
@@ -28,6 +28,7 @@ bool FillResponseFileContents(); bool FillDepfile(); bool FillPool(); + bool FillInputs(); // Checks for errors in the outputs variable. bool CheckOutputs();
diff --git a/tools/gn/action_target_generator_unittest.cc b/tools/gn/action_target_generator_unittest.cc index 5a45932e..254bc982 100644 --- a/tools/gn/action_target_generator_unittest.cc +++ b/tools/gn/action_target_generator_unittest.cc
@@ -4,11 +4,13 @@ #include "testing/gtest/include/gtest/gtest.h" #include "tools/gn/scheduler.h" +#include "tools/gn/test_with_scheduler.h" #include "tools/gn/test_with_scope.h" +using ActionTargetGenerator = TestWithScheduler; + // Tests that actions can't have output substitutions. -TEST(ActionTargetGenerator, ActionOutputSubstitutions) { - Scheduler scheduler; +TEST_F(ActionTargetGenerator, ActionOutputSubstitutions) { TestWithScope setup; Scope::ItemVector items_; setup.scope()->set_item_collector(&items_); @@ -43,8 +45,7 @@ // Tests that arg and response file substitutions are validated for // action_foreach targets. -TEST(ActionTargetGenerator, ActionForeachSubstitutions) { - Scheduler scheduler; +TEST_F(ActionTargetGenerator, ActionForeachSubstitutions) { TestWithScope setup; Scope::ItemVector items_; setup.scope()->set_item_collector(&items_);
diff --git a/tools/gn/action_values.cc b/tools/gn/action_values.cc index 0a0c552..3290da43 100644 --- a/tools/gn/action_values.cc +++ b/tools/gn/action_values.cc
@@ -8,9 +8,9 @@ #include "tools/gn/substitution_writer.h" #include "tools/gn/target.h" -ActionValues::ActionValues() {} +ActionValues::ActionValues() = default; -ActionValues::~ActionValues() {} +ActionValues::~ActionValues() = default; void ActionValues::GetOutputsAsSourceFiles( const Target* target,
diff --git a/tools/gn/analyzer.cc b/tools/gn/analyzer.cc index cc403c2..c5158c5 100644 --- a/tools/gn/analyzer.cc +++ b/tools/gn/analyzer.cc
@@ -6,27 +6,26 @@ #include <algorithm> #include <iterator> +#include <memory> #include <set> #include <vector> #include "base/json/json_reader.h" #include "base/json/json_writer.h" -#include "base/memory/ptr_util.h" #include "base/strings/string_util.h" #include "base/values.h" #include "tools/gn/builder.h" +#include "tools/gn/config.h" +#include "tools/gn/config_values_extractors.h" #include "tools/gn/deps_iterator.h" #include "tools/gn/err.h" #include "tools/gn/filesystem_utils.h" #include "tools/gn/loader.h" #include "tools/gn/location.h" +#include "tools/gn/pool.h" #include "tools/gn/source_file.h" #include "tools/gn/target.h" -using LabelSet = Analyzer::LabelSet; -using SourceFileSet = Analyzer::SourceFileSet; -using TargetSet = Analyzer::TargetSet; - namespace { struct Inputs { @@ -34,40 +33,30 @@ std::vector<Label> compile_vec; std::vector<Label> test_vec; bool compile_included_all = false; - SourceFileSet source_files; - LabelSet compile_labels; - LabelSet test_labels; + std::set<const SourceFile*> source_files; + std::set<Label> compile_labels; + std::set<Label> test_labels; }; struct Outputs { std::string status; std::string error; bool compile_includes_all = false; - LabelSet compile_labels; - LabelSet test_labels; - LabelSet invalid_labels; + std::set<Label> compile_labels; + std::set<Label> test_labels; + std::set<Label> invalid_labels; }; -LabelSet LabelsFor(const TargetSet& targets) { - LabelSet labels; +std::set<Label> LabelsFor(const std::set<const Target*>& targets) { + std::set<Label> labels; for (auto* target : targets) labels.insert(target->label()); return labels; } -bool AnyBuildFilesWereModified(const SourceFileSet& source_files) { - for (auto* file : source_files) { - if (base::EndsWith(file->value(), ".gn", base::CompareCase::SENSITIVE) || - base::EndsWith(file->value(), ".gni", base::CompareCase::SENSITIVE) || - base::EndsWith(file->value(), "build/vs_toolchain.py", - base::CompareCase::SENSITIVE)) - return true; - } - return false; -} - -TargetSet Intersect(const TargetSet& l, const TargetSet& r) { - TargetSet result; +std::set<const Target*> Intersect(const std::set<const Target*>& l, + const std::set<const Target*>& r) { + std::set<const Target*> result; std::set_intersection(l.begin(), l.end(), r.begin(), r.end(), std::inserter(result, result.begin())); return result; @@ -109,9 +98,9 @@ void WriteLabels(const Label& default_toolchain, base::DictionaryValue& dict, const std::string& key, - const LabelSet& labels) { + const std::set<Label>& labels) { std::vector<std::string> strings; - auto value = base::MakeUnique<base::ListValue>(); + auto value = std::make_unique<base::ListValue>(); for (const auto l : labels) strings.push_back(l.GetUserVisibleName(default_toolchain)); std::sort(strings.begin(), strings.end()); @@ -197,7 +186,7 @@ std::string OutputsToJSON(const Outputs& outputs, const Label& default_toolchain, Err *err) { std::string output; - auto value = base::MakeUnique<base::DictionaryValue>(); + auto value = std::make_unique<base::DictionaryValue>(); if (outputs.error.size()) { WriteString(*value, "error", outputs.error); @@ -206,7 +195,7 @@ } else { WriteString(*value, "status", outputs.status); if (outputs.compile_includes_all) { - auto compile_targets = base::MakeUnique<base::ListValue>(); + auto compile_targets = std::make_unique<base::ListValue>(); compile_targets->AppendString("all"); value->SetWithoutPathExpansion("compile_targets", std::move(compile_targets)); @@ -224,21 +213,49 @@ } // namespace -Analyzer::Analyzer(const Builder& builder) - : all_targets_(builder.GetAllResolvedTargets()), - default_toolchain_(builder.loader()->GetDefaultToolchain()) { - for (const auto* target : all_targets_) { - labels_to_targets_[target->label()] = target; - for (const auto& dep_pair : target->GetDeps(Target::DEPS_ALL)) - dep_map_.insert(std::make_pair(dep_pair.ptr, target)); - } - for (const auto* target : all_targets_) { - if (dep_map_.find(target) == dep_map_.end()) - roots_.insert(target); +Analyzer::Analyzer(const Builder& builder, + const SourceFile& build_config_file, + const SourceFile& dot_file, + const std::set<SourceFile>& build_args_dependency_files) + : all_items_(builder.GetAllResolvedItems()), + default_toolchain_(builder.loader()->GetDefaultToolchain()), + build_config_file_(build_config_file), + dot_file_(dot_file), + build_args_dependency_files_(build_args_dependency_files) { + for (const auto* item : all_items_) { + labels_to_items_[item->label()] = item; + + // Fill dep_map_. + if (item->AsTarget()) { + for (const auto& dep_target_pair : + item->AsTarget()->GetDeps(Target::DEPS_ALL)) + dep_map_.insert(std::make_pair(dep_target_pair.ptr, item)); + + for (const auto& dep_config_pair : item->AsTarget()->configs()) + dep_map_.insert(std::make_pair(dep_config_pair.ptr, item)); + + dep_map_.insert(std::make_pair(item->AsTarget()->toolchain(), item)); + + if (item->AsTarget()->output_type() == Target::ACTION || + item->AsTarget()->output_type() == Target::ACTION_FOREACH) { + const LabelPtrPair<Pool>& pool = + item->AsTarget()->action_values().pool(); + if (pool.ptr) + dep_map_.insert(std::make_pair(pool.ptr, item)); + } + } else if (item->AsConfig()) { + for (const auto& dep_config_pair : item->AsConfig()->configs()) + dep_map_.insert(std::make_pair(dep_config_pair.ptr, item)); + } else if (item->AsToolchain()) { + for (const auto& dep_pair : item->AsToolchain()->deps()) + dep_map_.insert(std::make_pair(dep_pair.ptr, item)); + } else { + DCHECK(item->AsPool()); + } } } -Analyzer::~Analyzer() {} +Analyzer::~Analyzer() = default; std::string Analyzer::Analyze(const std::string& input, Err* err) const { Inputs inputs; @@ -250,7 +267,7 @@ return OutputsToJSON(outputs, default_toolchain_, err); } - LabelSet invalid_labels; + std::set<Label> invalid_labels; for (const auto& label : InvalidLabels(inputs.compile_labels)) invalid_labels.insert(label); for (const auto& label : InvalidLabels(inputs.test_labels)) @@ -261,12 +278,7 @@ return OutputsToJSON(outputs, default_toolchain_, err); } - // TODO(crbug.com/555273): We can do smarter things when we detect changes - // to build files. For example, if all of the ninja files are unchanged, - // we know that we can ignore changes to .gn* files. Also, for most .gn - // files, we can treat a change as simply affecting every target, config, - // or toolchain defined in that file. - if (AnyBuildFilesWereModified(inputs.source_files)) { + if (WereMainGNFilesModified(inputs.source_files)) { outputs.status = "Found dependency (all)"; if (inputs.compile_included_all) { outputs.compile_includes_all = true; @@ -280,22 +292,45 @@ return OutputsToJSON(outputs, default_toolchain_, err); } - TargetSet affected_targets = AllAffectedTargets(inputs.source_files); + std::set<const Item*> affected_items = + GetAllAffectedItems(inputs.source_files); + std::set<const Target*> affected_targets; + for (const Item* affected_item : affected_items) { + // Only handles targets in the default toolchain. + // TODO(crbug.com/667989): Expand analyzer to non-default toolchains when + // the bug is fixed. + if (affected_item->AsTarget() && + affected_item->label().GetToolchainLabel() == default_toolchain_) + affected_targets.insert(affected_item->AsTarget()); + } + if (affected_targets.empty()) { outputs.status = "No dependency"; return OutputsToJSON(outputs, default_toolchain_, err); } - TargetSet compile_targets = TargetsFor(inputs.compile_labels); - if (inputs.compile_included_all) { - for (auto* root : roots_) - compile_targets.insert(root); + std::set<const Target*> root_targets; + for (const auto* item : all_items_) { + if (item->AsTarget() && dep_map_.find(item) == dep_map_.end()) + root_targets.insert(item->AsTarget()); } - TargetSet filtered_targets = Filter(compile_targets); + + std::set<const Target*> compile_targets = TargetsFor(inputs.compile_labels); + if (inputs.compile_included_all) { + for (auto* root_target : root_targets) + compile_targets.insert(root_target); + } + std::set<const Target*> filtered_targets = Filter(compile_targets); outputs.compile_labels = LabelsFor(Intersect(filtered_targets, affected_targets)); - TargetSet test_targets = TargetsFor(inputs.test_labels); + // If every target is affected, simply compile All instead of listing all + // the targets to make the output easier to read. + if (inputs.compile_included_all && + outputs.compile_labels.size() == filtered_targets.size()) + outputs.compile_includes_all = true; + + std::set<const Target*> test_targets = TargetsFor(inputs.test_labels); outputs.test_labels = LabelsFor(Intersect(test_targets, affected_targets)); if (outputs.compile_labels.empty() && outputs.test_labels.empty()) @@ -305,47 +340,53 @@ return OutputsToJSON(outputs, default_toolchain_, err); } -TargetSet Analyzer::AllAffectedTargets( - const SourceFileSet& source_files) const { - TargetSet direct_matches; +std::set<const Item*> Analyzer::GetAllAffectedItems( + const std::set<const SourceFile*>& source_files) const { + std::set<const Item*> directly_affected_items; for (auto* source_file : source_files) - AddTargetsDirectlyReferringToFileTo(source_file, &direct_matches); - TargetSet all_matches; - for (auto* match : direct_matches) - AddAllRefsTo(match, &all_matches); - return all_matches; + AddItemsDirectlyReferringToFile(source_file, &directly_affected_items); + + std::set<const Item*> all_affected_items; + for (auto* affected_item : directly_affected_items) + AddAllItemsReferringToItem(affected_item, &all_affected_items); + + return all_affected_items; } -LabelSet Analyzer::InvalidLabels(const LabelSet& labels) const { - LabelSet invalid_labels; +std::set<Label> Analyzer::InvalidLabels(const std::set<Label>& labels) const { + std::set<Label> invalid_labels; for (const Label& label : labels) { - if (labels_to_targets_.find(label) == labels_to_targets_.end()) + if (labels_to_items_.find(label) == labels_to_items_.end()) invalid_labels.insert(label); } return invalid_labels; } -TargetSet Analyzer::TargetsFor(const LabelSet& labels) const { - TargetSet targets; +std::set<const Target*> Analyzer::TargetsFor( + const std::set<Label>& labels) const { + std::set<const Target*> targets; for (const auto& label : labels) { - auto it = labels_to_targets_.find(label); - if (it != labels_to_targets_.end()) - targets.insert(it->second); + auto it = labels_to_items_.find(label); + if (it != labels_to_items_.end()) { + DCHECK(it->second->AsTarget()); + targets.insert(it->second->AsTarget()); + } } return targets; } -TargetSet Analyzer::Filter(const TargetSet& targets) const { - TargetSet seen; - TargetSet filtered; +std::set<const Target*> Analyzer::Filter( + const std::set<const Target*>& targets) const { + std::set<const Target*> seen; + std::set<const Target*> filtered; for (const auto* target : targets) FilterTarget(target, &seen, &filtered); return filtered; } void Analyzer::FilterTarget(const Target* target, - TargetSet* seen, - TargetSet* filtered) const { + std::set<const Target*>* seen, + std::set<const Target*>* filtered) const { if (seen->find(target) == seen->end()) { seen->insert(target); if (target->output_type() != Target::GROUP) { @@ -357,8 +398,17 @@ } } -bool Analyzer::TargetRefersToFile(const Target* target, - const SourceFile* file) const { +bool Analyzer::ItemRefersToFile(const Item* item, + const SourceFile* file) const { + for (const auto& cur_file : item->build_dependency_files()) { + if (cur_file == *file) + return true; + } + + if (!item->AsTarget()) + return false; + + const Target* target = item->AsTarget(); for (const auto& cur_file : target->sources()) { if (cur_file == *file) return true; @@ -367,9 +417,11 @@ if (cur_file == *file) return true; } - for (const auto& cur_file : target->inputs()) { - if (cur_file == *file) - return true; + for (ConfigValuesIterator iter(target); !iter.done(); iter.Next()) { + for (const auto& cur_file : iter.cur().inputs()) { + if (cur_file == *file) + return true; + } } for (const auto& cur_file : target->data()) { if (cur_file == file->value()) @@ -391,23 +443,44 @@ return false; } -void Analyzer::AddTargetsDirectlyReferringToFileTo(const SourceFile* file, - TargetSet* matches) const { - for (auto* target : all_targets_) { - // Only handles targets in the default toolchain. - if ((target->label().GetToolchainLabel() == default_toolchain_) && - TargetRefersToFile(target, file)) - matches->insert(target); +void Analyzer::AddItemsDirectlyReferringToFile( + const SourceFile* file, + std::set<const Item*>* directly_affected_items) const { + for (const auto* item : all_items_) { + if (ItemRefersToFile(item, file)) + directly_affected_items->insert(item); } } -void Analyzer::AddAllRefsTo(const Target* target, TargetSet* results) const { - if (results->find(target) != results->end()) - return; // Already found this target. - results->insert(target); +void Analyzer::AddAllItemsReferringToItem( + const Item* item, + std::set<const Item*>* all_affected_items) const { + if (all_affected_items->find(item) != all_affected_items->end()) + return; // Already found this item. - auto dep_begin = dep_map_.lower_bound(target); - auto dep_end = dep_map_.upper_bound(target); - for (auto cur_dep = dep_begin; cur_dep != dep_end; cur_dep++) - AddAllRefsTo(cur_dep->second, results); + all_affected_items->insert(item); + + auto dep_begin = dep_map_.lower_bound(item); + auto dep_end = dep_map_.upper_bound(item); + for (auto cur_dep = dep_begin; cur_dep != dep_end; ++cur_dep) + AddAllItemsReferringToItem(cur_dep->second, all_affected_items); +} + +bool Analyzer::WereMainGNFilesModified( + const std::set<const SourceFile*>& modified_files) const { + for (const auto* file : modified_files) { + if (*file == dot_file_) + return true; + + if (*file == build_config_file_) + return true; + + for (const auto& build_args_dependency_file : + build_args_dependency_files_) { + if (*file == build_args_dependency_file) + return true; + } + } + + return false; }
diff --git a/tools/gn/analyzer.h b/tools/gn/analyzer.h index 130ebe9..01be0e4 100644 --- a/tools/gn/analyzer.h +++ b/tools/gn/analyzer.h
@@ -10,9 +10,9 @@ #include <vector> #include "tools/gn/builder.h" +#include "tools/gn/item.h" #include "tools/gn/label.h" #include "tools/gn/source_file.h" -#include "tools/gn/target.h" // An Analyzer can answer questions about a build graph. It is used // to answer queries for the `refs` and `analyze` commands, where we @@ -20,11 +20,10 @@ // from just a single Target. class Analyzer { public: - using LabelSet = std::set<Label>; - using SourceFileSet = std::set<const SourceFile*>; - using TargetSet = std::set<const Target*>; - - explicit Analyzer(const Builder& builder); + Analyzer(const Builder& builder, + const SourceFile& build_config_file, + const SourceFile& dot_file, + const std::set<SourceFile>& build_args_dependency_files); ~Analyzer(); // Figures out from a Buider and a JSON-formatted string containing lists @@ -35,20 +34,17 @@ std::string Analyze(const std::string& input, Err* err) const; private: - // Returns the roots of the build graph: the set of targets that - // no other target depends on. - TargetSet& roots() { return roots_; }; - - // Returns the set of all targets that might be affected, directly or + // Returns the set of all items that might be affected, directly or // indirectly, by modifications to the given source files. - TargetSet AllAffectedTargets(const SourceFileSet& source_files) const; + std::set<const Item*> GetAllAffectedItems( + const std::set<const SourceFile*>& source_files) const; // Returns the set of labels that do not refer to objects in the graph. - LabelSet InvalidLabels(const LabelSet& labels) const; + std::set<Label> InvalidLabels(const std::set<Label>& labels) const; // Returns the set of all targets that have a label in the given set. // Invalid (or missing) labels will be ignored. - TargetSet TargetsFor(const LabelSet& labels) const; + std::set<const Target*> TargetsFor(const std::set<Label>& labels) const; // Returns a filtered set of the given targets, meaning that for each of the // given targets, @@ -70,26 +66,39 @@ // ones). // // This filtering behavior is also known as "pruning" the list of targets. - TargetSet Filter(const TargetSet& targets) const; + std::set<const Target*> Filter(const std::set<const Target*>& targets) const; // Filter an individual target and adds the results to filtered // (see Filter(), above). - void FilterTarget(const Target*, TargetSet* seen, TargetSet* filtered) const; + void FilterTarget(const Target*, + std::set<const Target*>* seen, + std::set<const Target*>* filtered) const; - bool TargetRefersToFile(const Target* target, const SourceFile* file) const; + bool ItemRefersToFile(const Item* item, const SourceFile* file) const; - void AddTargetsDirectlyReferringToFileTo(const SourceFile* file, - TargetSet* matches) const; + void AddItemsDirectlyReferringToFile( + const SourceFile* file, + std::set<const Item*>* affected_items) const; - void AddAllRefsTo(const Target* target, TargetSet* matches) const; + void AddAllItemsReferringToItem(const Item* item, + std::set<const Item*>* affected_items) const; - std::vector<const Target*> all_targets_; - std::map<const Label, const Target*> labels_to_targets_; + // Main GN files stand for files whose context are used globally to execute + // every other build files, this list includes dot file, build config file, + // build args files etc. + bool WereMainGNFilesModified( + const std::set<const SourceFile*>& modified_files) const; + + std::vector<const Item*> all_items_; + std::map<Label, const Item*> labels_to_items_; Label default_toolchain_; - std::set<const Target*> roots_; - // Maps targets to the list of targets that depend on them. - std::multimap<const Target*, const Target*> dep_map_; + // Maps items to the list of items that depend on them. + std::multimap<const Item*, const Item*> dep_map_; + + const SourceFile build_config_file_; + const SourceFile dot_file_; + const std::set<SourceFile> build_args_dependency_files_; }; #endif // TOOLS_GN_ANALYZER_H_
diff --git a/tools/gn/analyzer_unittest.cc b/tools/gn/analyzer_unittest.cc index abbb96e..b8188d8 100644 --- a/tools/gn/analyzer_unittest.cc +++ b/tools/gn/analyzer_unittest.cc
@@ -6,15 +6,21 @@ #include "testing/gtest/include/gtest/gtest.h" #include "tools/gn/build_settings.h" #include "tools/gn/builder.h" +#include "tools/gn/config.h" #include "tools/gn/loader.h" +#include "tools/gn/pool.h" #include "tools/gn/settings.h" #include "tools/gn/source_file.h" +#include "tools/gn/substitution_list.h" +#include "tools/gn/target.h" +#include "tools/gn/tool.h" +#include "tools/gn/toolchain.h" -namespace { +namespace gn_analyzer_unittest { class MockLoader : public Loader { public: - MockLoader() {} + MockLoader() = default; void Load(const SourceFile& file, const LocationRange& origin, @@ -28,7 +34,7 @@ } private: - ~MockLoader() override {} + ~MockLoader() override = default; }; class AnalyzerTest : public testing::Test { @@ -44,60 +50,38 @@ tc_name_ = settings_.toolchain_label().name(); } - Target* MakeTarget(const std::string dir, - const std::string name, - Target::OutputType type, - const std::vector<std::string>& sources, - const std::vector<Target*>& deps) { - Label lbl(SourceDir(dir), name, tc_dir_, tc_name_); - Target* target = new Target(&settings_, lbl); - target->set_output_type(type); - for (const auto& s : sources) - target->sources().push_back(SourceFile(s)); - for (const auto* d : deps) - target->public_deps().push_back(LabelTargetPair(d)); - builder_.ItemDefined(std::unique_ptr<Item>(target)); + // Ownership of the target will be transfered to the builder, so no leaks. + Target* MakeTarget(const std::string& dir, const std::string& name) { + Label label(SourceDir(dir), name, tc_dir_, tc_name_); + Target* target = new Target(&settings_, label); + return target; } - void AddSource(Target* a, std::string path) {} + // Ownership of the config will be transfered to the builder, so no leaks. + Config* MakeConfig(const std::string& dir, const std::string& name) { + Label label(SourceDir(dir), name, tc_dir_, tc_name_); + Config* config = new Config(&settings_, label); - void AddDep(Target* a, Target* b) {} - - void SetUpABasicBuildGraph() { - std::vector<std::string> no_sources; - std::vector<Target*> no_deps; - - // All of the targets below are owned by the builder, so none of them - // get leaked. - - // Ignore the returned target since nothing depends on it. - MakeTarget("//", "a", Target::EXECUTABLE, {"//a.cc"}, no_deps); - - Target* b = - MakeTarget("//d", "b", Target::SOURCE_SET, {"//d/b.cc"}, no_deps); - - Target* b_unittests = MakeTarget("//d", "b_unittests", Target::EXECUTABLE, - {"//d/b_unittest.cc"}, {b}); - - Target* c = MakeTarget("//d", "c", Target::EXECUTABLE, {"//d/c.cc"}, {b}); - - Target* b_unittests_and_c = - MakeTarget("//d", "b_unittests_and_c", Target::GROUP, no_sources, - {b_unittests, c}); - - Target* e = - MakeTarget("//d", "e", Target::EXECUTABLE, {"//d/e.cc"}, no_deps); - - // Also ignore this returned target since nothing depends on it. - MakeTarget("//d", "d", Target::GROUP, no_sources, {b_unittests_and_c, e}); + return config; } - void RunBasicTest(const std::string& input, - const std::string& expected_output) { - SetUpABasicBuildGraph(); + // Ownership of the pool will be transfered to the builder, so no leaks. + Pool* MakePool(const std::string& dir, const std::string& name) { + Label label(SourceDir(dir), name, tc_dir_, tc_name_); + Pool* pool = new Pool(&settings_, label); + + return pool; + } + + void RunAnalyzerTest(const std::string& input, + const std::string& expected_output) { + Analyzer analyzer(builder_, SourceFile("//build/config/BUILDCONFIG.gn"), + SourceFile("//.gn"), + {SourceFile("//out/debug/args.gn"), + SourceFile("//build/default_args.gn")}); Err err; - std::string actual_output = Analyzer(builder_).Analyze(input, &err); + std::string actual_output = analyzer.Analyze(input, &err); EXPECT_EQ(err.has_error(), false); EXPECT_EQ(expected_output, actual_output); } @@ -111,125 +95,500 @@ std::string tc_name_; }; -} // namespace - -// TODO: clean this up when raw string literals are allowed. - -TEST_F(AnalyzerTest, AllWasPruned) { - RunBasicTest( +// Tests that a target is marked as affected if its sources are modified. +TEST_F(AnalyzerTest, TargetRefersToSources) { + Target* t = MakeTarget("//dir", "target_name"); + builder_.ItemDefined(std::unique_ptr<Item>(t)); + RunAnalyzerTest( + R"({ + "files": [ "//dir/file_name.cc" ], + "additional_compile_targets": [ "all" ], + "test_targets": [ "//dir:target_name" ] + })", "{" - " \"files\": [ \"//d/b.cc\" ]," - " \"additional_compile_targets\": [ \"all\" ]," - " \"test_targets\": [ ]" - "}", + R"("compile_targets":[],)" + R"/("status":"No dependency",)/" + R"("test_targets":[])" + "}"); + + t->sources().push_back(SourceFile("//dir/file_name.cc")); + RunAnalyzerTest( + R"({ + "files": [ "//dir/file_name.cc" ], + "additional_compile_targets": [ "all" ], + "test_targets": [ "//dir:target_name" ] + })", "{" - "\"compile_targets\":[\"//d:b_unittests\",\"//d:c\"]," - "\"status\":\"Found dependency\"," - "\"test_targets\":[]" + R"("compile_targets":["all"],)" + R"/("status":"Found dependency",)/" + R"("test_targets":["//dir:target_name"])" "}"); } +// Tests that a target is marked as affected if its public headers are modified. +TEST_F(AnalyzerTest, TargetRefersToPublicHeaders) { + Target* t = MakeTarget("//dir", "target_name"); + builder_.ItemDefined(std::unique_ptr<Item>(t)); + RunAnalyzerTest( + R"({ + "files": [ "//dir/header_name.h" ], + "additional_compile_targets": [ "all" ], + "test_targets": [ "//dir:target_name" ] + })", + "{" + R"("compile_targets":[],)" + R"/("status":"No dependency",)/" + R"("test_targets":[])" + "}"); + + t->public_headers().push_back(SourceFile("//dir/header_name.h")); + RunAnalyzerTest( + R"({ + "files": [ "//dir/header_name.h" ], + "additional_compile_targets": [ "all" ], + "test_targets": [ "//dir:target_name" ] + })", + "{" + R"("compile_targets":["all"],)" + R"/("status":"Found dependency",)/" + R"("test_targets":["//dir:target_name"])" + "}"); +} + +// Tests that a target is marked as affected if its inputs are modified. +TEST_F(AnalyzerTest, TargetRefersToInputs) { + Target* t = MakeTarget("//dir", "target_name"); + builder_.ItemDefined(std::unique_ptr<Item>(t)); + RunAnalyzerTest( + R"({ + "files": [ "//dir/extra_input.cc" ], + "additional_compile_targets": [ "all" ], + "test_targets": [ "//dir:target_name" ] + })", + "{" + R"("compile_targets":[],)" + R"/("status":"No dependency",)/" + R"("test_targets":[])" + "}"); + + SourceFile extra_input(SourceFile("//dir/extra_input.cc")); + t->config_values().inputs().push_back(extra_input); + RunAnalyzerTest( + R"({ + "files": [ "//dir/extra_input.cc" ], + "additional_compile_targets": [ "all" ], + "test_targets": [ "//dir:target_name" ] + })", + "{" + R"("compile_targets":["all"],)" + R"/("status":"Found dependency",)/" + R"("test_targets":["//dir:target_name"])" + "}"); + + t->config_values().inputs().clear(); + Config* c = MakeConfig("//dir", "config_name"); + builder_.ItemDefined(std::unique_ptr<Item>(c)); + c->own_values().inputs().push_back(extra_input); + t->configs().push_back(LabelConfigPair(c)); + + RunAnalyzerTest( + R"({ + "files": [ "//dir/extra_input.cc" ], + "additional_compile_targets": [ "all" ], + "test_targets": [ "//dir:target_name" ] + })", + "{" + R"("compile_targets":["all"],)" + R"/("status":"Found dependency",)/" + R"("test_targets":["//dir:target_name"])" + "}"); +} + +// Tests that a target is marked as affected if its data are modified. +TEST_F(AnalyzerTest, TargetRefersToData) { + Target* t = MakeTarget("//dir", "target_name"); + builder_.ItemDefined(std::unique_ptr<Item>(t)); + RunAnalyzerTest( + R"({ + "files": [ "//dir/data.html" ], + "additional_compile_targets": [ "all" ], + "test_targets": [ "//dir:target_name" ] + })", + "{" + R"("compile_targets":[],)" + R"/("status":"No dependency",)/" + R"("test_targets":[])" + "}"); + + t->data().push_back("//dir/data.html"); + RunAnalyzerTest( + R"({ + "files": [ "//dir/data.html" ], + "additional_compile_targets": [ "all" ], + "test_targets": [ "//dir:target_name" ] + })", + "{" + R"("compile_targets":["all"],)" + R"/("status":"Found dependency",)/" + R"("test_targets":["//dir:target_name"])" + "}"); +} + +// Tests that a target is marked as affected if the target is an action and its +// action script is modified. +TEST_F(AnalyzerTest, TargetRefersToActionScript) { + Target* t = MakeTarget("//dir", "target_name"); + builder_.ItemDefined(std::unique_ptr<Item>(t)); + t->set_output_type(Target::ACTION); + RunAnalyzerTest( + R"({ + "files": [ "//dir/script.py" ], + "additional_compile_targets": [ "all" ], + "test_targets": [ "//dir:target_name" ] + })", + "{" + R"("compile_targets":[],)" + R"/("status":"No dependency",)/" + R"("test_targets":[])" + "}"); + + t->action_values().set_script(SourceFile("//dir/script.py")); + RunAnalyzerTest( + R"({ + "files": [ "//dir/script.py" ], + "additional_compile_targets": [ "all" ], + "test_targets": [ "//dir:target_name" ] + })", + "{" + R"("compile_targets":["all"],)" + R"/("status":"Found dependency",)/" + R"("test_targets":["//dir:target_name"])" + "}"); +} + +// Tests that a target is marked as affected if its build dependency files are +// modified. +TEST_F(AnalyzerTest, TargetRefersToBuildDependencyFiles) { + Target* t = MakeTarget("//dir", "target_name"); + builder_.ItemDefined(std::unique_ptr<Item>(t)); + RunAnalyzerTest( + R"({ + "files": [ "//dir/BUILD.gn" ], + "additional_compile_targets": [ "all" ], + "test_targets": [ "//dir:target_name" ] + })", + "{" + R"("compile_targets":[],)" + R"/("status":"No dependency",)/" + R"("test_targets":[])" + "}"); + + t->build_dependency_files().insert(SourceFile("//dir/BUILD.gn")); + RunAnalyzerTest( + R"({ + "files": [ "//dir/BUILD.gn" ], + "additional_compile_targets": [ "all" ], + "test_targets": [ "//dir:target_name" ] + })", + "{" + R"("compile_targets":["all"],)" + R"/("status":"Found dependency",)/" + R"("test_targets":["//dir:target_name"])" + "}"); +} + +// Tests that if a target is marked as affected, then it propagates to dependent +// test_targets. +TEST_F(AnalyzerTest, AffectedTargetpropagatesToDependentTargets) { + Target* t1 = MakeTarget("//dir", "target_name1"); + Target* t2 = MakeTarget("//dir", "target_name2"); + Target* t3 = MakeTarget("//dir", "target_name3"); + t1->private_deps().push_back(LabelTargetPair(t2)); + t2->private_deps().push_back(LabelTargetPair(t3)); + builder_.ItemDefined(std::unique_ptr<Item>(t1)); + builder_.ItemDefined(std::unique_ptr<Item>(t2)); + builder_.ItemDefined(std::unique_ptr<Item>(t3)); + + RunAnalyzerTest( + R"({ + "files": [ "//dir/BUILD.gn" ], + "additional_compile_targets": [ "all" ], + "test_targets": [ "//dir:target_name1", "//dir:target_name2" ] + })", + "{" + R"("compile_targets":[],)" + R"/("status":"No dependency",)/" + R"("test_targets":[])" + "}"); + + t3->build_dependency_files().insert(SourceFile("//dir/BUILD.gn")); + RunAnalyzerTest( + R"({ + "files": [ "//dir/BUILD.gn" ], + "additional_compile_targets": [ "all" ], + "test_targets": [ "//dir:target_name1", "//dir:target_name2" ] + })", + "{" + R"("compile_targets":["all"],)" + R"/("status":"Found dependency",)/" + R"("test_targets":["//dir:target_name1","//dir:target_name2"])" + "}"); +} + +// Tests that if a config is marked as affected, then it propagates to dependent +// test_targets. +TEST_F(AnalyzerTest, AffectedConfigpropagatesToDependentTargets) { + Config* c = MakeConfig("//dir", "config_name"); + Target* t = MakeTarget("//dir", "target_name"); + t->configs().push_back(LabelConfigPair(c)); + builder_.ItemDefined(std::unique_ptr<Item>(t)); + builder_.ItemDefined(std::unique_ptr<Item>(c)); + RunAnalyzerTest( + R"({ + "files": [ "//dir/BUILD.gn" ], + "additional_compile_targets": [ "all" ], + "test_targets": [ "//dir:target_name" ] + })", + "{" + R"("compile_targets":[],)" + R"/("status":"No dependency",)/" + R"("test_targets":[])" + "}"); + + c->build_dependency_files().insert(SourceFile("//dir/BUILD.gn")); + RunAnalyzerTest( + R"({ + "files": [ "//dir/BUILD.gn" ], + "additional_compile_targets": [ "all" ], + "test_targets": [ "//dir:target_name" ] + })", + "{" + R"("compile_targets":["all"],)" + R"/("status":"Found dependency",)/" + R"("test_targets":["//dir:target_name"])" + "}"); +} + +// Tests that if toolchain is marked as affected, then it propagates to +// dependent test_targets. +TEST_F(AnalyzerTest, AffectedToolchainpropagatesToDependentTargets) { + Target* target = MakeTarget("//dir", "target_name"); + target->set_output_type(Target::EXECUTABLE); + Toolchain* toolchain = new Toolchain(&settings_, settings_.toolchain_label()); + + // The tool is not used anywhere, but is required to construct the dependency + // between a target and the toolchain. + std::unique_ptr<Tool> fake_tool(new Tool()); + fake_tool->set_outputs( + SubstitutionList::MakeForTest("//out/debug/output.txt")); + toolchain->SetTool(Toolchain::TYPE_LINK, std::move(fake_tool)); + builder_.ItemDefined(std::unique_ptr<Item>(target)); + builder_.ItemDefined(std::unique_ptr<Item>(toolchain)); + + RunAnalyzerTest( + R"({ + "files": [ "//tc/BUILD.gn" ], + "additional_compile_targets": [ "all" ], + "test_targets": [ "//dir:target_name" ] + })", + "{" + R"("compile_targets":[],)" + R"/("status":"No dependency",)/" + R"("test_targets":[])" + "}"); + + toolchain->build_dependency_files().insert(SourceFile("//tc/BUILD.gn")); + RunAnalyzerTest( + R"({ + "files": [ "//tc/BUILD.gn" ], + "additional_compile_targets": [ "all" ], + "test_targets": [ "//dir:target_name" ] + })", + "{" + R"("compile_targets":["all"],)" + R"/("status":"Found dependency",)/" + R"("test_targets":["//dir:target_name"])" + "}"); +} + +// Tests that if a pool is marked as affected, then it propagates to dependent +// targets. +TEST_F(AnalyzerTest, AffectedPoolpropagatesToDependentTargets) { + Target* t = MakeTarget("//dir", "target_name"); + t->set_output_type(Target::ACTION); + Pool* p = MakePool("//dir", "pool_name"); + t->action_values().set_pool(LabelPtrPair<Pool>(p)); + + builder_.ItemDefined(std::unique_ptr<Item>(t)); + builder_.ItemDefined(std::unique_ptr<Item>(p)); + + RunAnalyzerTest( + R"({ + "files": [ "//dir/BUILD.gn" ], + "additional_compile_targets": [ "all" ], + "test_targets": [ "//dir:target_name" ] + })", + "{" + R"("compile_targets":[],)" + R"/("status":"No dependency",)/" + R"("test_targets":[])" + "}"); + + p->build_dependency_files().insert(SourceFile("//dir/BUILD.gn")); + RunAnalyzerTest( + R"({ + "files": [ "//dir/BUILD.gn" ], + "additional_compile_targets": [ "all" ], + "test_targets": [ "//dir:target_name" ] + })", + "{" + R"("compile_targets":["all"],)" + R"/("status":"Found dependency",)/" + R"("test_targets":["//dir:target_name"])" + "}"); +} + +// Tests that when dependency was found, the "compile_targets" in the output is +// not "all". +TEST_F(AnalyzerTest, CompileTargetsAllWasPruned) { + Target* t1 = MakeTarget("//dir", "target_name1"); + Target* t2 = MakeTarget("//dir", "target_name2"); + builder_.ItemDefined(std::unique_ptr<Item>(t1)); + builder_.ItemDefined(std::unique_ptr<Item>(t2)); + t2->build_dependency_files().insert(SourceFile("//dir/BUILD.gn")); + + RunAnalyzerTest( + R"({ + "files": [ "//dir/BUILD.gn" ], + "additional_compile_targets": [ "all" ], + "test_targets": [] + })", + "{" + R"("compile_targets":["//dir:target_name2"],)" + R"/("status":"Found dependency",)/" + R"("test_targets":[])" + "}"); +} + +// Tests that output is "No dependency" when no dependency is found. TEST_F(AnalyzerTest, NoDependency) { - RunBasicTest( + Target* t = MakeTarget("//dir", "target_name"); + builder_.ItemDefined(std::unique_ptr<Item>(t)); + + RunAnalyzerTest( + R"({ + "files": [ "//dir/BUILD.gn" ], + "additional_compile_targets": [ "all" ], + "test_targets": [] + })", "{" - " \"files\":[ \"//missing.cc\" ]," - " \"additional_compile_targets\": [ \"all\" ]," - " \"test_targets\": [ \"//:a\" ]" - "}", - "{" - "\"compile_targets\":[]," - "\"status\":\"No dependency\"," - "\"test_targets\":[]" + R"("compile_targets":[],)" + R"/("status":"No dependency",)/" + R"("test_targets":[])" "}"); } +// Tests that output is "No dependency" when no files or targets are provided. TEST_F(AnalyzerTest, NoFilesNoTargets) { - RunBasicTest( + RunAnalyzerTest( + R"({ + "files": [], + "additional_compile_targets": [], + "test_targets": [] + })", "{" - " \"files\": []," - " \"additional_compile_targets\": []," - " \"test_targets\": []" - "}", - "{" - "\"compile_targets\":[]," - "\"status\":\"No dependency\"," - "\"test_targets\":[]" + R"("compile_targets":[],)" + R"("status":"No dependency",)" + R"("test_targets":[])" "}"); } -TEST_F(AnalyzerTest, OneTestTargetModified) { - RunBasicTest( - "{" - " \"files\": [ \"//a.cc\" ]," - " \"additional_compile_targets\": []," - " \"test_targets\": [ \"//:a\" ]" - "}", - "{" - "\"compile_targets\":[]," - "\"status\":\"Found dependency\"," - "\"test_targets\":[\"//:a\"]" - "}"); -} - +// Tests that output displays proper error message when given files aren't +// source-absolute or absolute path. TEST_F(AnalyzerTest, FilesArentSourceAbsolute) { - RunBasicTest( + RunAnalyzerTest( + R"({ + "files": [ "a.cc" ], + "additional_compile_targets": [], + "test_targets": [ "//dir:target_name" ] + })", "{" - " \"files\": [ \"a.cc\" ]," - " \"additional_compile_targets\": []," - " \"test_targets\": [ \"//:a\" ]" - "}", - "{" - "\"error\":" - "\"\\\"a.cc\\\" is not a source-absolute or absolute path.\"," - "\"invalid_targets\":[]" + R"("error":)" + R"("\"a.cc\" is not a source-absolute or absolute path.",)" + R"("invalid_targets":[])" "}"); } +// Tests that output displays proper error message when input is illy-formed. TEST_F(AnalyzerTest, WrongInputFields) { - RunBasicTest( + RunAnalyzerTest( + R"({ + "files": [ "//a.cc" ], + "compile_targets": [], + "test_targets": [ "//dir:target_name" ] + })", "{" - " \"files\": [ \"//a.cc\" ]," - " \"compile_targets\": []," - " \"test_targets\": [ \"//:a\" ]" - "}", - "{" - "\"error\":" - "\"Input does not have a key named " - "\\\"additional_compile_targets\\\" with a list value.\"," - "\"invalid_targets\":[]" + R"("error":)" + R"("Input does not have a key named )" + R"(\"additional_compile_targets\" with a list value.",)" + R"("invalid_targets":[])" "}"); } -TEST_F(AnalyzerTest, BuildFilesWereModified) { - // This tests that if a build file is modified, we bail out early with - // "Found dependency (all)" error since we can't handle changes to - // build files yet (crbug.com/555273). - RunBasicTest( +// Bails out early with "Found dependency (all)" if dot file is modified. +TEST_F(AnalyzerTest, DotFileWasModified) { + Target* t = MakeTarget("//dir", "target_name"); + builder_.ItemDefined(std::unique_ptr<Item>(t)); + + RunAnalyzerTest( + R"({ + "files": [ "//.gn" ], + "additional_compile_targets": [], + "test_targets": [ "//dir:target_name" ] + })", "{" - " \"files\": [ \"//a.cc\", \"//BUILD.gn\" ]," - " \"additional_compile_targets\": []," - " \"test_targets\": [ \"//:a\" ]" - "}", - "{" - "\"compile_targets\":[\"//:a\"]," - "\"status\":\"Found dependency (all)\"," - "\"test_targets\":[\"//:a\"]" + R"("compile_targets":["//dir:target_name"],)" + R"/("status":"Found dependency (all)",)/" + R"("test_targets":["//dir:target_name"])" "}"); } -TEST_F(AnalyzerTest, BuildFilesWereModifiedAndCompilingAll) { - // This tests that if a build file is modified, we bail out early with - // "Found dependency (all)" error since we can't handle changes to - // build files yet (crbug.com/555273). - RunBasicTest( +// Bails out early with "Found dependency (all)" if master build config file is +// modified. +TEST_F(AnalyzerTest, BuildConfigFileWasModified) { + Target* t = MakeTarget("//dir", "target_name"); + builder_.ItemDefined(std::unique_ptr<Item>(t)); + + RunAnalyzerTest( + R"({ + "files": [ "//build/config/BUILDCONFIG.gn" ], + "additional_compile_targets": [], + "test_targets": [ "//dir:target_name" ] + })", "{" - " \"files\": [ \"//a.cc\", \"//BUILD.gn\" ]," - " \"additional_compile_targets\": [ \"all\" ]," - " \"test_targets\": [ \"//:a\" ]" - "}", - "{" - "\"compile_targets\":[\"all\"]," - "\"status\":\"Found dependency (all)\"," - "\"test_targets\":[\"//:a\"]" + R"("compile_targets":["//dir:target_name"],)" + R"/("status":"Found dependency (all)",)/" + R"("test_targets":["//dir:target_name"])" "}"); } + +// Bails out early with "Found dependency (all)" if a build args dependency file +// is modified. +TEST_F(AnalyzerTest, BuildArgsDependencyFileWasModified) { + Target* t = MakeTarget("//dir", "target_name"); + builder_.ItemDefined(std::unique_ptr<Item>(t)); + + RunAnalyzerTest( + R"({ + "files": [ "//build/default_args.gn" ], + "additional_compile_targets": [], + "test_targets": [ "//dir:target_name" ] + })", + "{" + R"("compile_targets":["//dir:target_name"],)" + R"/("status":"Found dependency (all)",)/" + R"("test_targets":["//dir:target_name"])" + "}"); +} + +} // namespace gn_analyzer_unittest
diff --git a/tools/gn/args.cc b/tools/gn/args.cc index 1a01a50c..a53eb490 100644 --- a/tools/gn/args.cc +++ b/tools/gn/args.cc
@@ -6,6 +6,7 @@ #include "base/sys_info.h" #include "build/build_config.h" +#include "tools/gn/source_file.h" #include "tools/gn/string_utils.h" #include "tools/gn/variables.h" @@ -96,11 +97,9 @@ override_value() { } -Args::ValueWithOverride::~ValueWithOverride() { -} +Args::ValueWithOverride::~ValueWithOverride() = default; -Args::Args() { -} +Args::Args() = default; Args::Args(const Args& other) : overrides_(other.overrides_), @@ -110,8 +109,7 @@ toolchain_overrides_(other.toolchain_overrides_) { } -Args::~Args() { -} +Args::~Args() = default; void Args::AddArgOverride(const char* name, const Value& value) { base::AutoLock lock(lock_); @@ -129,6 +127,12 @@ } } +void Args::AddDefaultArgOverrides(const Scope::KeyValueMap& overrides) { + base::AutoLock lock(lock_); + for (const auto& cur_override : overrides) + overrides_[cur_override.first] = cur_override.second; +} + const Value* Args::GetArgOverride(const char* name) const { base::AutoLock lock(lock_); @@ -248,7 +252,7 @@ std::string err_help( "The variable \"" + name + "\" was set as a build argument\n" "but never appeared in a declare_args() block in any buildfile.\n\n" - "To view all possible args, run \"gn args --list <builddir>\""); + "To view all possible args, run \"gn args --list <out_dir>\""); // Use all declare_args for a spelling suggestion. std::vector<base::StringPiece> candidates; @@ -304,6 +308,8 @@ os = "netbsd"; #elif defined(OS_AIX) os = "aix"; +#elif defined(OS_FUCHSIA) + os = "fuchsia"; #else #error Unknown OS type. #endif
diff --git a/tools/gn/args.h b/tools/gn/args.h index 79fe93f..ee45085e 100644 --- a/tools/gn/args.h +++ b/tools/gn/args.h
@@ -6,6 +6,7 @@ #define TOOLS_GN_ARGS_H_ #include <map> +#include <set> #include "base/containers/hash_tables.h" #include "base/macros.h" @@ -13,6 +14,7 @@ #include "tools/gn/scope.h" class Err; +class SourceFile; extern const char kBuildArgs_Help[]; @@ -46,6 +48,10 @@ void AddArgOverride(const char* name, const Value& value); void AddArgOverrides(const Scope::KeyValueMap& overrides); + // Specifies default overrides of the build arguments. These are normally + // specified in the .gn file. + void AddDefaultArgOverrides(const Scope::KeyValueMap& overrides); + // Returns the value corresponding to the given argument name, or NULL if no // argument is set. const Value* GetArgOverride(const char* name) const; @@ -73,11 +79,22 @@ // arguments. If there are, this returns false and sets the error. bool VerifyAllOverridesUsed(Err* err) const; - // Returns information about all arguements, both defaults and overrides. + // Returns information about all arguments, both defaults and overrides. // This is used for the help system which is not performance critical. Use a - // map instead of a hash map so the arguements are sorted alphabetically. + // map instead of a hash map so the arguments are sorted alphabetically. ValueWithOverrideMap GetAllArguments() const; + // Returns the set of build files that may affect the build arguments, please + // refer to Scope for how this is determined. + const std::set<SourceFile>& build_args_dependency_files() const { + return build_args_dependency_files_; + } + + void set_build_args_dependency_files( + const std::set<SourceFile>& build_args_dependency_files) { + build_args_dependency_files_ = build_args_dependency_files; + } + private: using ArgumentsPerToolchain = base::hash_map<const Settings*, Scope::KeyValueMap>; @@ -122,6 +139,8 @@ // we see an argument declaration. mutable ArgumentsPerToolchain toolchain_overrides_; + std::set<SourceFile> build_args_dependency_files_; + DISALLOW_ASSIGN(Args); };
diff --git a/tools/gn/bin/roll_gn.py b/tools/gn/bin/roll_gn.py index af336bd2..cf4c878c 100755 --- a/tools/gn/bin/roll_gn.py +++ b/tools/gn/bin/roll_gn.py
@@ -167,7 +167,7 @@ self.Call('git-cl try -m tryserver.chromium.mac ' '-b mac_chromium_gn_upload -r %s' % self.new_gn_commitish) self.Call('git-cl try -m tryserver.chromium.win ' - '-b win8_chromium_gn_upload -r %s' % self.new_gn_commitish) + '-b win_chromium_gn_upload -r %s' % self.new_gn_commitish) return 0 @@ -223,7 +223,7 @@ builders = { 'linux_chromium_gn_upload': 'linux64', 'mac_chromium_gn_upload': 'mac', - 'win8_chromium_gn_upload': 'win' + 'win_chromium_gn_upload': 'win' } results = {}
diff --git a/tools/gn/binary_target_generator.cc b/tools/gn/binary_target_generator.cc index 7828013..8659306 100644 --- a/tools/gn/binary_target_generator.cc +++ b/tools/gn/binary_target_generator.cc
@@ -24,8 +24,7 @@ output_type_(type) { } -BinaryTargetGenerator::~BinaryTargetGenerator() { -} +BinaryTargetGenerator::~BinaryTargetGenerator() = default; void BinaryTargetGenerator::DoRun() { target_->set_output_type(output_type_); @@ -51,9 +50,6 @@ if (!FillCheckIncludes()) return; - if (!FillInputs()) - return; - if (!FillConfigs()) return;
diff --git a/tools/gn/bootstrap/bootstrap.py b/tools/gn/bootstrap/bootstrap.py index b274fa86..35c0945 100755 --- a/tools/gn/bootstrap/bootstrap.py +++ b/tools/gn/bootstrap/bootstrap.py
@@ -63,7 +63,9 @@ def run_build(tempdir, options): - if options.debug: + if options.build_path: + build_rel = options.build_path + elif options.debug: build_rel = os.path.join('out', 'Debug') else: build_rel = os.path.join('out', 'Release') @@ -109,6 +111,8 @@ help='Re-used build directory instead of using new ' 'temporary location each time') parser.add_option('--gn-gen-args', help='Args to pass to gn gen --args') + parser.add_option('--build-path', help='The directory in which to build gn, ' + 'relative to the src directory. (eg. out/Release)') parser.add_option('-v', '--verbose', action='store_true', help='Log more details') options, args = parser.parse_args(argv) @@ -174,6 +178,11 @@ root_gen_dir = os.path.join(tempdir, 'gen') mkdir_p(root_gen_dir) + write_buildflag_header_manually( + root_gen_dir, + 'base/synchronization/synchronization_flags.h', + {'ENABLE_MUTEX_PRIORITY_INHERITANCE': 'false'}) + write_buildflag_header_manually(root_gen_dir, 'base/allocator/features.h', {'USE_ALLOCATOR_SHIM': 'true' if is_linux else 'false'}) @@ -181,7 +190,20 @@ { 'ENABLE_LOCATION_SOURCE': 'false', 'ENABLE_PROFILING': 'false', - 'CAN_UNWIND_WITH_FRAME_POINTERS': 'false' + 'CAN_UNWIND_WITH_FRAME_POINTERS': 'false', + 'UNSAFE_DEVELOPER_BUILD': 'false' + }) + + write_buildflag_header_manually(root_gen_dir, + 'base/memory/protected_memory_flags.h', + { 'USE_LLD': 'false' }) + + write_buildflag_header_manually(root_gen_dir, 'base/cfi_flags.h', + { + 'CFI_CAST_CHECK': 'false', + 'CFI_ICALL_CHECK': 'false', + 'CFI_ENFORCEMENT_TRAP': 'false', + 'CFI_ENFORCEMENT_DIAGNOSTIC': 'false' }) write_build_date_header(root_gen_dir) @@ -203,6 +225,10 @@ write_compiled_message(root_gen_dir, 'base/trace_event/etw_manifest/chrome_events_win.man') + write_buildflag_header_manually( + root_gen_dir, 'base/android/library_loader.h', + {'USE_LLD': 'false', 'SUPPORTS_CODE_ORDERING': 'false'}) + write_gn_ninja(os.path.join(tempdir, 'build.ninja'), root_gen_dir, options) cmd = ['ninja', '-C', tempdir, '-w', 'dupbuild=err'] @@ -397,6 +423,8 @@ continue if name == 'run_all_unittests.cc': continue + if name == 'test_with_scheduler.cc': + continue if name == 'gn_main.cc': continue full_path = os.path.join(GN_ROOT, name) @@ -441,13 +469,12 @@ 'base/json/json_string_value_serializer.cc', 'base/json/json_writer.cc', 'base/json/string_escape.cc', - 'base/lazy_instance.cc', + 'base/lazy_instance_helpers.cc', 'base/location.cc', 'base/logging.cc', 'base/md5.cc', 'base/memory/ref_counted.cc', 'base/memory/ref_counted_memory.cc', - 'base/memory/singleton.cc', 'base/memory/shared_memory_handle.cc', 'base/memory/shared_memory_tracker.cc', 'base/memory/weak_ptr.cc', @@ -473,6 +500,7 @@ 'base/metrics/sample_vector.cc', 'base/metrics/sparse_histogram.cc', 'base/metrics/statistics_recorder.cc', + 'base/observer_list_threadsafe.cc', 'base/path_service.cc', 'base/pending_task.cc', 'base/pickle.cc', @@ -536,7 +564,6 @@ 'base/threading/thread_local_storage.cc', 'base/threading/thread_restrictions.cc', 'base/threading/thread_task_runner_handle.cc', - 'base/threading/worker_pool.cc', 'base/time/clock.cc', 'base/time/default_clock.cc', 'base/time/default_tick_clock.cc', @@ -605,13 +632,11 @@ 'base/strings/string16.cc', 'base/synchronization/condition_variable_posix.cc', 'base/synchronization/lock_impl_posix.cc', - 'base/synchronization/read_write_lock_posix.cc', 'base/sys_info_posix.cc', 'base/task_scheduler/task_tracker_posix.cc', 'base/threading/platform_thread_internal_posix.cc', 'base/threading/platform_thread_posix.cc', 'base/threading/thread_local_storage_posix.cc', - 'base/threading/worker_pool_posix.cc', 'base/time/time_conversion_posix.cc', 'base/trace_event/heap_profiler_allocation_register_posix.cc', ]) @@ -637,8 +662,6 @@ } if is_linux or is_aix: - ldflags.extend(['-pthread']) - static_libraries['xdg_user_dirs'] = { 'sources': [ 'base/third_party/xdg_user_dirs/xdg_user_dir_lookup.cc', @@ -664,6 +687,85 @@ 'base/threading/platform_thread_linux.cc', ]) if is_linux: + libcxx_root = SRC_ROOT + '/buildtools/third_party/libc++/trunk' + libcxxabi_root = SRC_ROOT + '/buildtools/third_party/libc++abi/trunk' + cflags_cc.extend([ + '-nostdinc++', + '-isystem' + libcxx_root + '/include', + '-isystem' + libcxxabi_root + '/include', + ]) + ldflags.extend(['-nodefaultlibs']) + libs.extend([ + '-lc', + '-lgcc_s', + '-lm', + '-lpthread', + ]) + static_libraries['libc++'] = { + 'sources': [ + libcxx_root + '/src/algorithm.cpp', + libcxx_root + '/src/any.cpp', + libcxx_root + '/src/bind.cpp', + libcxx_root + '/src/chrono.cpp', + libcxx_root + '/src/condition_variable.cpp', + libcxx_root + '/src/debug.cpp', + libcxx_root + '/src/exception.cpp', + libcxx_root + '/src/functional.cpp', + libcxx_root + '/src/future.cpp', + libcxx_root + '/src/hash.cpp', + libcxx_root + '/src/ios.cpp', + libcxx_root + '/src/iostream.cpp', + libcxx_root + '/src/locale.cpp', + libcxx_root + '/src/memory.cpp', + libcxx_root + '/src/mutex.cpp', + libcxx_root + '/src/new.cpp', + libcxx_root + '/src/optional.cpp', + libcxx_root + '/src/random.cpp', + libcxx_root + '/src/regex.cpp', + libcxx_root + '/src/shared_mutex.cpp', + libcxx_root + '/src/stdexcept.cpp', + libcxx_root + '/src/string.cpp', + libcxx_root + '/src/strstream.cpp', + libcxx_root + '/src/system_error.cpp', + libcxx_root + '/src/thread.cpp', + libcxx_root + '/src/typeinfo.cpp', + libcxx_root + '/src/utility.cpp', + libcxx_root + '/src/valarray.cpp', + libcxx_root + '/src/variant.cpp', + libcxx_root + '/src/vector.cpp', + ], + 'tool': 'cxx', + 'cflags': cflags + [ + '-D_LIBCPP_NO_EXCEPTIONS', + '-D_LIBCPP_BUILDING_LIBRARY', + '-DLIBCXX_BUILDING_LIBCXXABI', + ] + } + static_libraries['libc++abi'] = { + 'sources': [ + libcxxabi_root + '/src/abort_message.cpp', + libcxxabi_root + '/src/cxa_aux_runtime.cpp', + libcxxabi_root + '/src/cxa_default_handlers.cpp', + libcxxabi_root + '/src/cxa_demangle.cpp', + libcxxabi_root + '/src/cxa_exception_storage.cpp', + libcxxabi_root + '/src/cxa_guard.cpp', + libcxxabi_root + '/src/cxa_handlers.cpp', + libcxxabi_root + '/src/cxa_noexception.cpp', + libcxxabi_root + '/src/cxa_unexpected.cpp', + libcxxabi_root + '/src/cxa_vector.cpp', + libcxxabi_root + '/src/cxa_virtual.cpp', + libcxxabi_root + '/src/fallback_malloc.cpp', + libcxxabi_root + '/src/private_typeinfo.cpp', + libcxxabi_root + '/src/stdlib_exception.cpp', + libcxxabi_root + '/src/stdlib_stdexcept.cpp', + libcxxabi_root + '/src/stdlib_typeinfo.cpp', + ], + 'tool': 'cxx', + 'cflags': cflags + [ + '-DLIBCXXABI_SILENT_TERMINATE', + '-D_LIBCXXABI_NO_EXCEPTIONS', + ] + } static_libraries['base']['sources'].extend([ 'base/allocator/allocator_shim.cc', 'base/allocator/allocator_shim_default_dispatch_to_glibc.cc', @@ -676,6 +778,7 @@ 'base/third_party/libevent/epoll.c', ]) else: + ldflags.extend(['-pthread']) libs.extend(['-lrt']) static_libraries['base']['sources'].extend([ 'base/process/internal_aix.cc' @@ -709,6 +812,7 @@ 'base/strings/sys_string_conversions_mac.mm', 'base/synchronization/waitable_event_mac.cc', 'base/sys_info_mac.mm', + 'base/time/time_exploded_posix.cc', 'base/time/time_mac.cc', 'base/threading/platform_thread_mac.mm', ]) @@ -832,6 +936,13 @@ cmd.append('gn') check_call(cmd) + # build.ninja currently refers back to gn from the temporary directory. + # Regenerate the build files using the gn we just built so that the reference + # gets updated to "./gn". + cmd = [os.path.join(build_dir, 'gn'), 'gen', build_dir, + '--args=%s' % gn_gen_args] + check_call(cmd) + if not options.debug and not is_win: check_call(['strip', os.path.join(build_dir, 'gn')])
diff --git a/tools/gn/build_settings.cc b/tools/gn/build_settings.cc index 4cf2b86..38b830f 100644 --- a/tools/gn/build_settings.cc +++ b/tools/gn/build_settings.cc
@@ -9,8 +9,7 @@ #include "base/files/file_util.h" #include "tools/gn/filesystem_utils.h" -BuildSettings::BuildSettings() { -} +BuildSettings::BuildSettings() = default; BuildSettings::BuildSettings(const BuildSettings& other) : root_path_(other.root_path_), @@ -22,8 +21,7 @@ build_dir_(other.build_dir_), build_args_(other.build_args_) {} -BuildSettings::~BuildSettings() { -} +BuildSettings::~BuildSettings() = default; void BuildSettings::SetRootTargetLabel(const Label& r) { root_target_label_ = r;
diff --git a/tools/gn/build_settings.h b/tools/gn/build_settings.h index 3f41ae3..670f996a 100644 --- a/tools/gn/build_settings.h +++ b/tools/gn/build_settings.h
@@ -125,7 +125,7 @@ std::unique_ptr<std::set<SourceFile>> exec_script_whitelist_; - BuildSettings& operator=(const BuildSettings& other); // Disallow. + DISALLOW_ASSIGN(BuildSettings); }; #endif // TOOLS_GN_BUILD_SETTINGS_H_
diff --git a/tools/gn/builder.cc b/tools/gn/builder.cc index 540d83d6..ec45e6c6 100644 --- a/tools/gn/builder.cc +++ b/tools/gn/builder.cc
@@ -57,8 +57,7 @@ Builder::Builder(Loader* loader) : loader_(loader) { } -Builder::~Builder() { -} +Builder::~Builder() = default; void Builder::ItemDefined(std::unique_ptr<Item> item) { ScopedTrace trace(TraceItem::TRACE_DEFINE_TARGET, item->label()); @@ -135,7 +134,20 @@ std::vector<const BuilderRecord*> result; result.reserve(records_.size()); for (const auto& record : records_) - result.push_back(record.second); + result.push_back(record.second.get()); + return result; +} + +std::vector<const Item*> Builder::GetAllResolvedItems() const { + std::vector<const Item*> result; + result.reserve(records_.size()); + for (const auto& record : records_) { + if (record.second->type() != BuilderRecord::ITEM_UNKNOWN && + record.second->should_generate() && record.second->item()) { + result.push_back(record.second->item()); + } + } + return result; } @@ -156,10 +168,8 @@ } BuilderRecord* Builder::GetRecord(const Label& label) { - RecordMap::iterator found = records_.find(label); - if (found == records_.end()) - return nullptr; - return found->second; + auto found = records_.find(label); + return (found != records_.end()) ? found->second.get() : nullptr; } bool Builder::CheckForBadItems(Err* err) const { @@ -175,7 +185,7 @@ std::vector<const BuilderRecord*> bad_records; std::string depstring; for (const auto& record_pair : records_) { - const BuilderRecord* src = record_pair.second; + const BuilderRecord* src = record_pair.second.get(); if (!src->should_generate()) continue; // Skip ungenerated nodes. @@ -296,9 +306,10 @@ BuilderRecord* record = GetRecord(label); if (!record) { // Not seen this record yet, create a new one. - record = new BuilderRecord(type, label); - record->set_originally_referenced_from(request_from); - records_[label] = record; + auto new_record = std::make_unique<BuilderRecord>(type, label); + new_record->set_originally_referenced_from(request_from); + record = new_record.get(); + records_[label] = std::move(new_record); return record; }
diff --git a/tools/gn/builder.h b/tools/gn/builder.h index d46bbd1..58ccbad 100644 --- a/tools/gn/builder.h +++ b/tools/gn/builder.h
@@ -6,6 +6,7 @@ #define TOOLS_GN_BUILDER_H_ #include <map> +#include <memory> #include "base/callback.h" #include "base/macros.h" @@ -45,6 +46,9 @@ std::vector<const BuilderRecord*> GetAllRecords() const; + // Returns items which should be generated and which are defined. + std::vector<const Item*> GetAllResolvedItems() const; + // Returns targets which should be generated and which are defined. std::vector<const Target*> GetAllResolvedTargets() const; @@ -134,9 +138,7 @@ // Non owning pointer. Loader* loader_; - // Owning pointers. - typedef std::map<Label, BuilderRecord*> RecordMap; - RecordMap records_; + std::map<Label, std::unique_ptr<BuilderRecord>> records_; ResolvedGeneratedCallback resolved_and_generated_callback_;
diff --git a/tools/gn/builder_record.cc b/tools/gn/builder_record.cc index 107e441..665baae9 100644 --- a/tools/gn/builder_record.cc +++ b/tools/gn/builder_record.cc
@@ -14,8 +14,7 @@ resolved_(false) { } -BuilderRecord::~BuilderRecord() { -} +BuilderRecord::~BuilderRecord() = default; // static const char* BuilderRecord::GetNameForType(ItemType type) {
diff --git a/tools/gn/builder_unittest.cc b/tools/gn/builder_unittest.cc index 616e76a..3053bca 100644 --- a/tools/gn/builder_unittest.cc +++ b/tools/gn/builder_unittest.cc
@@ -10,12 +10,11 @@ #include "tools/gn/test_with_scope.h" #include "tools/gn/toolchain.h" -namespace { +namespace gn_builder_unittest { class MockLoader : public Loader { public: - MockLoader() { - } + MockLoader() = default; // Loader implementation: void Load(const SourceFile& file, @@ -58,7 +57,7 @@ } private: - ~MockLoader() override {} + ~MockLoader() override = default; std::vector<SourceFile> files_; }; @@ -90,8 +89,6 @@ Scope scope_; }; -} // namespace - TEST_F(BuilderTest, BasicDeps) { SourceDir toolchain_dir = settings_.toolchain_label().dir(); std::string toolchain_name = settings_.toolchain_label().name(); @@ -247,3 +244,5 @@ // Should have requested that B is loaded. EXPECT_TRUE(loader_->HasLoadedOne(SourceFile("//b/BUILD.gn"))); } + +} // namespace gn_builder_unittest
diff --git a/tools/gn/bundle_data.cc b/tools/gn/bundle_data.cc index f117ec29..5027691 100644 --- a/tools/gn/bundle_data.cc +++ b/tools/gn/bundle_data.cc
@@ -47,9 +47,9 @@ } // namespace -BundleData::BundleData() {} +BundleData::BundleData() = default; -BundleData::~BundleData() {} +BundleData::~BundleData() = default; void BundleData::AddBundleData(const Target* target) { DCHECK_EQ(target->output_type(), Target::BUNDLE_DATA); @@ -156,46 +156,12 @@ } SourceFile BundleData::GetBundleRootDirOutput(const Settings* settings) const { - // TODO(crbug.com/764286): all bundles used to be created in $root_out_dir - // and the bundle main output was assumed to be the first path component - // relative to $root_out_dir. - // - // This broke when Chrome on iOS had to generate multiple bundles with the - // same names (variation of the same bundle with some assets swapped). To - // fix this, a new variable $bundle_contents_dir was added to support that - // macOS bundle files are not in the root of the bundle but in a subdirectory. - // - // To allow migration introducing this variable without breaking existing - // code, the function does the following heuristic: - // 1. if $bundle_contents_dir is defined, then returns $bundle_root_dir, - // 2. otherwise, returns the first component of $bundle_root_dir relative - // to $root_out_dir (this was the old code). - // - // Remove those heuristics when all the code has been fixed to use the new - // variable $bundle_contents_dir instead of $bundle_root_dir, and just return - // the value of $bundle_root_dir. + std::string root_dir_value = root_dir().value(); + size_t last_separator = root_dir_value.rfind('/'); + if (last_separator != std::string::npos) + root_dir_value = root_dir_value.substr(0, last_separator); - if (!contents_dir().is_null()) { - std::string root_dir_value = root_dir().value(); - size_t last_separator = root_dir_value.rfind('/'); - if (last_separator != std::string::npos) - root_dir_value = root_dir_value.substr(0, last_separator); - - return SourceFile(SourceFile::SWAP_IN, &root_dir_value); - } - - const SourceDir& build_dir = settings->toolchain_output_dir(); - std::string bundle_root_relative = RebasePath(root_dir().value(), build_dir); - - size_t first_component = bundle_root_relative.find('/'); - if (first_component != std::string::npos) { - base::StringPiece outermost_bundle_dir = - base::StringPiece(bundle_root_relative).substr(0, first_component); - std::string return_value(build_dir.value()); - outermost_bundle_dir.AppendToString(&return_value); - return SourceFile(SourceFile::SWAP_IN, &return_value); - } - return SourceFile(root_dir().value()); + return SourceFile(SourceFile::SWAP_IN, &root_dir_value); } SourceDir BundleData::GetBundleRootDirOutputAsDir(
diff --git a/tools/gn/bundle_data_target_generator.cc b/tools/gn/bundle_data_target_generator.cc index 81a9b959..32a421a 100644 --- a/tools/gn/bundle_data_target_generator.cc +++ b/tools/gn/bundle_data_target_generator.cc
@@ -17,7 +17,7 @@ const FunctionCallNode* function_call, Err* err) : TargetGenerator(target, scope, function_call, err) {} -BundleDataTargetGenerator::~BundleDataTargetGenerator() {} +BundleDataTargetGenerator::~BundleDataTargetGenerator() = default; void BundleDataTargetGenerator::DoRun() { target_->set_output_type(Target::BUNDLE_DATA);
diff --git a/tools/gn/bundle_file_rule.cc b/tools/gn/bundle_file_rule.cc index 6631a59..4d4ca3a 100644 --- a/tools/gn/bundle_file_rule.cc +++ b/tools/gn/bundle_file_rule.cc
@@ -20,7 +20,7 @@ BundleFileRule::BundleFileRule(const BundleFileRule& other) = default; -BundleFileRule::~BundleFileRule() {} +BundleFileRule::~BundleFileRule() = default; SourceFile BundleFileRule::ApplyPatternToSource( const Settings* settings,
diff --git a/tools/gn/c_include_iterator.cc b/tools/gn/c_include_iterator.cc index cc3cb35d..29ead0b4 100644 --- a/tools/gn/c_include_iterator.cc +++ b/tools/gn/c_include_iterator.cc
@@ -122,8 +122,7 @@ lines_since_last_include_(0) { } -CIncludeIterator::~CIncludeIterator() { -} +CIncludeIterator::~CIncludeIterator() = default; bool CIncludeIterator::GetNextIncludeString(base::StringPiece* out, LocationRange* location) {
diff --git a/tools/gn/command_analyze.cc b/tools/gn/command_analyze.cc index 6fd5823..9aa698b3c 100644 --- a/tools/gn/command_analyze.cc +++ b/tools/gn/command_analyze.cc
@@ -110,10 +110,12 @@ if (!setup->DoSetup(args[0], false) || !setup->Run()) return 1; - Analyzer analyzer(setup->builder()); - Err err; - std::string output = Analyzer(setup->builder()).Analyze(input, &err); + Analyzer analyzer( + setup->builder(), setup->build_settings().build_config_file(), + setup->GetDotFile(), + setup->build_settings().build_args().build_args_dependency_files()); + std::string output = analyzer.Analyze(input, &err); if (err.has_error()) { err.PrintToStdout(); return 1;
diff --git a/tools/gn/command_args.cc b/tools/gn/command_args.cc index 2a24510..bb40a6e 100644 --- a/tools/gn/command_args.cc +++ b/tools/gn/command_args.cc
@@ -56,7 +56,7 @@ size_t cur = offset; do { - cur --; + cur--; if (Tokenizer::IsNewline(data, cur)) return cur + 1; // Want the first character *after* the newline. } while (cur > 0); @@ -64,7 +64,7 @@ } // Assumes DoesLineBeginWithComment(), this strips the # character from the -// beginning and normalizes preceeding whitespace. +// beginning and normalizes preceding whitespace. std::string StripHashFromLine(const base::StringPiece& line) { // Replace the # sign and everything before it with 3 spaces, so that a // normal comment that has a space after the # will be indented 4 spaces @@ -328,10 +328,10 @@ } // namespace -extern const char kArgs[] = "args"; -extern const char kArgs_HelpShort[] = +const char kArgs[] = "args"; +const char kArgs_HelpShort[] = "args: Display or configure arguments declared by the build."; -extern const char kArgs_Help[] = +const char kArgs_Help[] = R"(gn args <out_dir> [--list] [--short] [--args] [--overrides-only] See also "gn help buildargs" for a more high-level overview of how @@ -361,7 +361,7 @@ The output will list the declaration location, current value for the build, default value (if different than the current value), and comment - preceeding the declaration. + preceding the declaration. If --short is specified, only the names and current values will be printed.
diff --git a/tools/gn/command_check.cc b/tools/gn/command_check.cc index 86caf85..4efcd45 100644 --- a/tools/gn/command_check.cc +++ b/tools/gn/command_check.cc
@@ -95,10 +95,8 @@ - Only includes using "quotes" are checked. <brackets> are assumed to be system includes. - - Include paths are assumed to be relative to either the source root or the - "root_gen_dir" and must include all the path components. (It might be - nice in the future to incorporate GN's knowledge of the include path to - handle other include styles.) + - Include paths are assumed to be relative to any of the "include_dirs" for + the target (including the implicit current dir). - GN does not run the preprocessor so will not understand conditional includes. @@ -122,7 +120,7 @@ included by other targets. Anything in the sources will be considered private and will not be includable regardless of dependency paths. - - Ouptuts from actions are treated like public sources on that target. + - Outputs from actions are treated like public sources on that target. - A target can include headers from a target that depends on it if the other target is annotated accordingly. See "gn help @@ -130,9 +128,9 @@ Advice on fixing problems - If you have a third party project that uses relative includes, it's generally - best to exclude that target from checking altogether via - "check_includes = false". + If you have a third party project that is difficult to fix or doesn't care + about include checks it's generally best to exclude that target from checking + altogether via "check_includes = false". If you have conditional includes, make sure the build conditions and the preprocessor conditions match, and annotate the line with "nogncheck" (see
diff --git a/tools/gn/command_clean.cc b/tools/gn/command_clean.cc index 70def6d..f4b64af 100644 --- a/tools/gn/command_clean.cc +++ b/tools/gn/command_clean.cc
@@ -105,7 +105,11 @@ if (!args_contents.empty()) { if (base::WriteFile(gn_args_file, args_contents.data(), static_cast<int>(args_contents.size())) == -1) { - Err(Location(), std::string("Failed to write args.gn.")).PrintToStdout(); + // Print the previous contents of args.gn since otherwise it is lost for + // good which can be quite frustrating. + Err(Location(), + "Failed to write args.gn. Old contents was:\n\n" + args_contents) + .PrintToStdout(); return 1; } }
diff --git a/tools/gn/command_desc.cc b/tools/gn/command_desc.cc index 8dbe6de..9a9b243 100644 --- a/tools/gn/command_desc.cc +++ b/tools/gn/command_desc.cc
@@ -5,12 +5,12 @@ #include <stddef.h> #include <algorithm> +#include <memory> #include <set> #include <sstream> #include "base/command_line.h" #include "base/json/json_writer.h" -#include "base/memory/ptr_util.h" #include "base/strings/string_util.h" #include "tools/gn/commands.h" #include "tools/gn/config.h" @@ -56,7 +56,7 @@ PrintValue(&iter.value(), indentLevel + 1); iter.Advance(); } - } else if (value->IsType(base::Value::Type::NONE)) { + } else if (value->is_none()) { OutputString(indent + "<null>\n"); } } @@ -272,6 +272,7 @@ HANDLER(variables::kCflagsObjCC, DefaultHandler); HANDLER(variables::kDefines, DefaultHandler); HANDLER(variables::kIncludeDirs, DefaultHandler); + HANDLER(variables::kInputs, DefaultHandler); HANDLER(variables::kLdflags, DefaultHandler); HANDLER(variables::kLibs, DefaultHandler); HANDLER(variables::kLibDirs, DefaultHandler); @@ -457,7 +458,7 @@ if (json) { // Convert all targets/configs to JSON, serialize and print them - auto res = base::MakeUnique<base::DictionaryValue>(); + auto res = std::make_unique<base::DictionaryValue>(); if (!target_matches.empty()) { for (const auto* target : target_matches) { res->SetWithoutPathExpansion(
diff --git a/tools/gn/command_format.cc b/tools/gn/command_format.cc index 0849762..c44f637c 100644 --- a/tools/gn/command_format.cc +++ b/tools/gn/command_format.cc
@@ -38,7 +38,7 @@ The contents of some lists ('sources', 'deps', etc.) will be sorted to a canonical order. To suppress this, you can add a comment of the form "# - NOSORT" immediately preceeding the assignment. e.g. + NOSORT" immediately preceding the assignment. e.g. # NOSORT sources = [ @@ -252,8 +252,7 @@ stack_.push_back(IndentState()); } -Printer::~Printer() { -} +Printer::~Printer() = default; void Printer::Print(base::StringPiece str) { str.AppendToString(&output_); @@ -336,7 +335,7 @@ binop->op().value() == "-=") && ident && list) { const base::StringPiece lhs = ident->value().value(); - if (lhs == "sources") + if (lhs == "public" || lhs == "sources") const_cast<ListNode*>(list)->SortAsStringsList(); else if (lhs == "deps" || lhs == "public_deps") const_cast<ListNode*>(list)->SortAsDepsList(); @@ -406,6 +405,12 @@ } if (block->comments()) { + if (!block->statements().empty() && + block->statements().back()->AsBlockComment()) { + // If the block ends in a comment, and there's a comment following it, + // then the two comments were originally separate, so keep them that way. + Newline(); + } for (const auto& c : block->comments()->after()) { TrimAndPrintToken(c); Newline(); @@ -571,18 +576,45 @@ sub2.Print(suffix); penalty_next_line += AssessPenalty(sub2.String()); - // If in both cases it was forced past 80col, then we don't break to avoid + // Force a list on the RHS that would normally be a single line into + // multiline. + bool tried_rhs_multiline = false; + Printer sub3; + InitializeSub(&sub3); + int penalty_multiline_rhs_list = std::numeric_limits<int>::max(); + const ListNode* rhs_list = binop->right()->AsList(); + if (is_assignment && rhs_list && + !ListWillBeMultiline(rhs_list->contents(), rhs_list->End())) { + sub3.Print(" "); + sub3.stack_.push_back(IndentState(start_column, false, false)); + sub3.Sequence(kSequenceStyleList, rhs_list->contents(), rhs_list->End(), + true); + sub3.stack_.pop_back(); + penalty_multiline_rhs_list = AssessPenalty(sub3.String()); + tried_rhs_multiline = true; + } + + // If in all cases it was forced past 80col, then we don't break to avoid // breaking after '=' in the case of: // variable = "... very long string ..." // as breaking and indenting doesn't make things much more readable, even - // though there's less characters past the maximum width. - bool exceeds_maximum_either_way = ExceedsMaximumWidth(sub1.String()) && - ExceedsMaximumWidth(sub2.String()); + // though there's fewer characters past the maximum width. + bool exceeds_maximum_all_ways = + ExceedsMaximumWidth(sub1.String()) && + ExceedsMaximumWidth(sub2.String()) && + (!tried_rhs_multiline || ExceedsMaximumWidth(sub3.String())); if (penalty_current_line < penalty_next_line || - exceeds_maximum_either_way) { + exceeds_maximum_all_ways) { Print(" "); Expr(binop->right(), prec_right, std::string()); + } else if (tried_rhs_multiline && + penalty_multiline_rhs_list < penalty_next_line) { + // Force a multiline list on the right. + Print(" "); + stack_.push_back(IndentState(start_column, false, false)); + Sequence(kSequenceStyleList, rhs_list->contents(), rhs_list->End(), true); + stack_.pop_back(); } else { // Otherwise, put first argument and op, and indent next. Newline(); @@ -927,6 +959,11 @@ return true; } + // When a scope is used as a list entry, it's too complicated to go one a + // single line (the block will always be formatted multiline itself). + if (list.size() >= 1 && list[0]->AsBlock()) + return true; + return false; } @@ -934,7 +971,7 @@ if (dump_tree) { std::ostringstream os; root->Print(os, 0); - printf("%s", os.str().c_str()); + fprintf(stderr, "%s", os.str().c_str()); } Printer pr; pr.Block(root); @@ -1024,8 +1061,7 @@ std::string output; if (!FormatStringToString(input, dump_tree, &output)) return 1; - if (!dump_tree) - printf("%s", output.c_str()); + printf("%s", output.c_str()); return 0; }
diff --git a/tools/gn/command_format_unittest.cc b/tools/gn/command_format_unittest.cc index 802dfbd..c351df04 100644 --- a/tools/gn/command_format_unittest.cc +++ b/tools/gn/command_format_unittest.cc
@@ -2,16 +2,20 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "tools/gn/command_format.h" + #include "base/files/file_util.h" #include "base/path_service.h" #include "base/strings/string_util.h" #include "testing/gtest/include/gtest/gtest.h" -#include "tools/gn/command_format.h" #include "tools/gn/commands.h" #include "tools/gn/setup.h" +#include "tools/gn/test_with_scheduler.h" + +using FormatTest = TestWithScheduler; #define FORMAT_TEST(n) \ - TEST(Format, n) { \ + TEST_F(FormatTest, n) { \ ::Setup setup; \ std::string out; \ std::string expected; \ @@ -99,3 +103,6 @@ FORMAT_TEST(065) FORMAT_TEST(066) FORMAT_TEST(067) +FORMAT_TEST(068) +FORMAT_TEST(069) +FORMAT_TEST(070)
diff --git a/tools/gn/command_gen.cc b/tools/gn/command_gen.cc index ce3fa28..ca65877 100644 --- a/tools/gn/command_gen.cc +++ b/tools/gn/command_gen.cc
@@ -196,11 +196,11 @@ return res; } else if (ide == kSwitchIdeValueVs || ide == kSwitchIdeValueVs2013 || ide == kSwitchIdeValueVs2015 || ide == kSwitchIdeValueVs2017) { - VisualStudioWriter::Version version = VisualStudioWriter::Version::Vs2015; + VisualStudioWriter::Version version = VisualStudioWriter::Version::Vs2017; if (ide == kSwitchIdeValueVs2013) version = VisualStudioWriter::Version::Vs2013; - else if (ide == kSwitchIdeValueVs2017) - version = VisualStudioWriter::Version::Vs2017; + else if (ide == kSwitchIdeValueVs2015) + version = VisualStudioWriter::Version::Vs2015; std::string sln_name; if (command_line->HasSwitch(kSwitchSln)) @@ -211,10 +211,14 @@ std::string win_kit; if (command_line->HasSwitch(kSwitchIdeValueWinSdk)) win_kit = command_line->GetSwitchValueASCII(kSwitchIdeValueWinSdk); + std::string ninja_extra_args; + if (command_line->HasSwitch(kSwitchNinjaExtraArgs)) + ninja_extra_args = + command_line->GetSwitchValueASCII(kSwitchNinjaExtraArgs); bool no_deps = command_line->HasSwitch(kSwitchNoDeps); - bool res = VisualStudioWriter::RunAndWriteFiles(build_settings, builder, - version, sln_name, filters, - win_kit, no_deps, err); + bool res = VisualStudioWriter::RunAndWriteFiles( + build_settings, builder, version, sln_name, filters, win_kit, + ninja_extra_args, no_deps, err); if (res && !quiet) { OutputString("Generating Visual Studio projects took " + base::Int64ToString(timer.Elapsed().InMilliseconds()) + @@ -300,7 +304,7 @@ Generate files for an IDE. Currently supported values: "eclipse" - Eclipse CDT settings file. "vs" - Visual Studio project/solution files. - (default Visual Studio version: 2015) + (default Visual Studio version: 2017) "vs2013" - Visual Studio 2013 project/solution files. "vs2015" - Visual Studio 2015 project/solution files. "vs2017" - Visual Studio 2017 project/solution files. @@ -329,6 +333,10 @@ As an example, "10.0.15063.0" can be specified to use Creators Update SDK instead of the default one. + --ninja-extra-args=<string> + This string is passed without any quoting to the ninja invocation + command-line. Can be used to configure ninja flags, like "-j". + Xcode Flags --workspace=<file_name> @@ -337,8 +345,7 @@ --ninja-extra-args=<string> This string is passed without any quoting to the ninja invocation - command-line. Can be used to configure ninja flags, like "-j" if using - goma for example. + command-line. Can be used to configure ninja flags, like "-j". --root-target=<target_name> Name of the target corresponding to "All" target in Xcode. If unset, @@ -455,12 +462,12 @@ for (const auto& rules : write_info.rules) targets_collected += rules.second.size(); - std::string stats = "Made " + base::SizeTToString(targets_collected) + - " targets from " + + std::string stats = + "Made " + base::NumberToString(targets_collected) + " targets from " + base::IntToString( setup->scheduler().input_file_manager()->GetInputFileCount()) + - " files in " + - base::Int64ToString(elapsed_time.InMilliseconds()) + "ms\n"; + " files in " + base::Int64ToString(elapsed_time.InMilliseconds()) + + "ms\n"; OutputString(stats); }
diff --git a/tools/gn/command_refs.cc b/tools/gn/command_refs.cc index 4d7ad7b5..ee0a40f 100644 --- a/tools/gn/command_refs.cc +++ b/tools/gn/command_refs.cc
@@ -12,6 +12,7 @@ #include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "tools/gn/commands.h" +#include "tools/gn/config_values_extractors.h" #include "tools/gn/deps_iterator.h" #include "tools/gn/filesystem_utils.h" #include "tools/gn/input_file.h" @@ -137,9 +138,11 @@ if (cur_file == file) return true; } - for (const auto& cur_file : target->inputs()) { - if (cur_file == file) - return true; + for (ConfigValuesIterator iter(target); !iter.done(); iter.Next()) { + for (const auto& cur_file : iter.cur().inputs()) { + if (cur_file == file) + return true; + } } for (const auto& cur_file : target->data()) { if (cur_file == file.value())
diff --git a/tools/gn/config.cc b/tools/gn/config.cc index fcc5fa6..e021fe4 100644 --- a/tools/gn/config.cc +++ b/tools/gn/config.cc
@@ -8,11 +8,12 @@ #include "tools/gn/input_file_manager.h" #include "tools/gn/scheduler.h" -Config::Config(const Settings* settings, const Label& label) - : Item(settings, label), resolved_(false) {} +Config::Config(const Settings* settings, + const Label& label, + const std::set<SourceFile>& build_dependency_files) + : Item(settings, label, build_dependency_files), resolved_(false) {} -Config::~Config() { -} +Config::~Config() = default; Config* Config::AsConfig() { return this;
diff --git a/tools/gn/config.h b/tools/gn/config.h index 20cfe7e4..ad049737 100644 --- a/tools/gn/config.h +++ b/tools/gn/config.h
@@ -5,6 +5,8 @@ #ifndef TOOLS_GN_CONFIG_H_ #define TOOLS_GN_CONFIG_H_ +#include <set> + #include "base/logging.h" #include "base/macros.h" #include "tools/gn/config_values.h" @@ -21,7 +23,11 @@ // flags. class Config : public Item { public: - Config(const Settings* settings, const Label& label); + // We track the set of build files that may affect this config, please refer + // to Scope for how this is determined. + Config(const Settings* settings, + const Label& label, + const std::set<SourceFile>& build_dependency_files = {}); ~Config() override; // Item implementation.
diff --git a/tools/gn/config_values.cc b/tools/gn/config_values.cc index cfcb9e4..b3e9f6f 100644 --- a/tools/gn/config_values.cc +++ b/tools/gn/config_values.cc
@@ -16,11 +16,9 @@ } // namespace -ConfigValues::ConfigValues() { -} +ConfigValues::ConfigValues() = default; -ConfigValues::~ConfigValues() { -} +ConfigValues::~ConfigValues() = default; void ConfigValues::AppendValues(const ConfigValues& append) { VectorAppend(&asmflags_, append.asmflags_); @@ -32,6 +30,7 @@ VectorAppend(&cflags_objcc_, append.cflags_objcc_); VectorAppend(&defines_, append.defines_); VectorAppend(&include_dirs_, append.include_dirs_); + VectorAppend(&inputs_, append.inputs_); VectorAppend(&ldflags_, append.ldflags_); VectorAppend(&lib_dirs_, append.lib_dirs_); VectorAppend(&libs_, append.libs_);
diff --git a/tools/gn/config_values.h b/tools/gn/config_values.h index af97c2b..0099e81 100644 --- a/tools/gn/config_values.h +++ b/tools/gn/config_values.h
@@ -53,6 +53,9 @@ #undef STRING_VALUES_ACCESSOR #undef DIR_VALUES_ACCESSOR + const std::vector<SourceFile>& inputs() const { return inputs_; } + std::vector<SourceFile>& inputs() { return inputs_; } + const std::vector<LibFile>& libs() const { return libs_; } std::vector<LibFile>& libs() { return libs_; } @@ -82,6 +85,7 @@ std::vector<std::string> cflags_objcc_; std::vector<std::string> defines_; std::vector<SourceDir> include_dirs_; + std::vector<SourceFile> inputs_; std::vector<std::string> ldflags_; std::vector<SourceDir> lib_dirs_; std::vector<LibFile> libs_;
diff --git a/tools/gn/config_values_generator.cc b/tools/gn/config_values_generator.cc index e92f091..97888ac 100644 --- a/tools/gn/config_values_generator.cc +++ b/tools/gn/config_values_generator.cc
@@ -57,8 +57,7 @@ err_(err) { } -ConfigValuesGenerator::~ConfigValuesGenerator() { -} +ConfigValuesGenerator::~ConfigValuesGenerator() = default; void ConfigValuesGenerator::Run() { #define FILL_STRING_CONFIG_VALUE(name) \ @@ -82,6 +81,14 @@ #undef FILL_STRING_CONFIG_VALUE #undef FILL_DIR_CONFIG_VALUE + // Inputs + const Value* inputs_value = scope_->GetValue(variables::kInputs, true); + if (inputs_value) { + ExtractListOfRelativeFiles(scope_->settings()->build_settings(), + *inputs_value, input_dir_, + &config_values_->inputs(), err_); + } + // Libs const Value* libs_value = scope_->GetValue("libs", true); if (libs_value) {
diff --git a/tools/gn/config_values_generator.h b/tools/gn/config_values_generator.h index 7fd803c..165f41a 100644 --- a/tools/gn/config_values_generator.h +++ b/tools/gn/config_values_generator.h
@@ -37,9 +37,9 @@ }; // For using in documentation for functions which use this. -#define CONFIG_VALUES_VARS_HELP \ - " Flags: cflags, cflags_c, cflags_cc, cflags_objc, cflags_objcc,\n" \ - " asmflags, defines, include_dirs, ldflags, lib_dirs, libs,\n" \ - " precompiled_header, precompiled_source\n" +#define CONFIG_VALUES_VARS_HELP \ + " Flags: cflags, cflags_c, cflags_cc, cflags_objc, cflags_objcc,\n" \ + " asmflags, defines, include_dirs, inputs, ldflags, lib_dirs,\n" \ + " libs, precompiled_header, precompiled_source\n" #endif // TOOLS_GN_CONFIG_VALUES_GENERATOR_H_
diff --git a/tools/gn/copy_target_generator.cc b/tools/gn/copy_target_generator.cc index 994011e..a86f820 100644 --- a/tools/gn/copy_target_generator.cc +++ b/tools/gn/copy_target_generator.cc
@@ -17,8 +17,7 @@ : TargetGenerator(target, scope, function_call, err) { } -CopyTargetGenerator::~CopyTargetGenerator() { -} +CopyTargetGenerator::~CopyTargetGenerator() = default; void CopyTargetGenerator::DoRun() { target_->set_output_type(Target::COPY_FILES);
diff --git a/tools/gn/create_bundle_target_generator.cc b/tools/gn/create_bundle_target_generator.cc index 9797321..d4b8f555 100644 --- a/tools/gn/create_bundle_target_generator.cc +++ b/tools/gn/create_bundle_target_generator.cc
@@ -24,7 +24,7 @@ Err* err) : TargetGenerator(target, scope, function_call, err) {} -CreateBundleTargetGenerator::~CreateBundleTargetGenerator() {} +CreateBundleTargetGenerator::~CreateBundleTargetGenerator() = default; void CreateBundleTargetGenerator::DoRun() { target_->set_output_type(Target::CREATE_BUNDLE);
diff --git a/tools/gn/deps_iterator.cc b/tools/gn/deps_iterator.cc index 8bbb760..92e892e2 100644 --- a/tools/gn/deps_iterator.cc +++ b/tools/gn/deps_iterator.cc
@@ -52,5 +52,4 @@ end_() { } -DepsIteratorRange::~DepsIteratorRange() { -} +DepsIteratorRange::~DepsIteratorRange() = default;
diff --git a/tools/gn/desc_builder.cc b/tools/gn/desc_builder.cc index 38b78e8..b2fd716 100644 --- a/tools/gn/desc_builder.cc +++ b/tools/gn/desc_builder.cc
@@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <memory> #include <set> -#include "base/memory/ptr_util.h" #include "base/strings/string_number_conversions.h" #include "tools/gn/commands.h" #include "tools/gn/config.h" @@ -114,7 +114,7 @@ template <typename T> ValuePtr RenderValue(const std::vector<T>& vector) { - auto res = base::MakeUnique<base::ListValue>(); + auto res = std::make_unique<base::ListValue>(); for (const auto& v : vector) res->Append(RenderValue(v)); @@ -122,20 +122,22 @@ } ValuePtr RenderValue(const std::string& s, bool optional = false) { - return (s.empty() && optional) ? base::MakeUnique<base::Value>() + return (s.empty() && optional) ? std::make_unique<base::Value>() : ValuePtr(new base::Value(s)); } ValuePtr RenderValue(const SourceDir& d) { - return d.is_null() ? base::MakeUnique<base::Value>() + return d.is_null() ? std::make_unique<base::Value>() : ValuePtr(new base::Value(FormatSourceDir(d))); } ValuePtr RenderValue(const SourceFile& f) { - return f.is_null() ? base::MakeUnique<base::Value>() + return f.is_null() ? std::make_unique<base::Value>() : ValuePtr(new base::Value(f.value())); } + ValuePtr RenderValue(const SourceFile* f) { return RenderValue(*f); } + ValuePtr RenderValue(const LibFile& lib) { if (lib.is_source_file()) return RenderValue(lib.source_file()); @@ -182,7 +184,7 @@ : BaseDescBuilder(what, false, false, false), config_(config) {} std::unique_ptr<base::DictionaryValue> BuildDescription() { - auto res = base::MakeUnique<base::DictionaryValue>(); + auto res = std::make_unique<base::DictionaryValue>(); const ConfigValues& values = config_->resolved_values(); if (what_.empty()) @@ -192,7 +194,7 @@ config_->label().GetToolchainLabel().GetUserVisibleName(false))); if (what(variables::kConfigs) && !config_->configs().empty()) { - auto configs = base::MakeUnique<base::ListValue>(); + auto configs = std::make_unique<base::ListValue>(); FillInConfigVector(configs.get(), config_->configs().vector()); res->SetWithoutPathExpansion(variables::kConfigs, std::move(configs)); } @@ -214,6 +216,7 @@ CONFIG_VALUE_ARRAY_HANDLER(cflags_objcc, std::string) CONFIG_VALUE_ARRAY_HANDLER(defines, std::string) CONFIG_VALUE_ARRAY_HANDLER(include_dirs, SourceDir) + CONFIG_VALUE_ARRAY_HANDLER(inputs, SourceFile) CONFIG_VALUE_ARRAY_HANDLER(ldflags, std::string) CONFIG_VALUE_ARRAY_HANDLER(lib_dirs, SourceDir) CONFIG_VALUE_ARRAY_HANDLER(libs, LibFile) @@ -235,7 +238,7 @@ ValuePtr render_config_value_array( const ConfigValues& values, const std::vector<T>& (ConfigValues::*getter)() const) { - auto res = base::MakeUnique<base::ListValue>(); + auto res = std::make_unique<base::ListValue>(); for (const T& cur : (values.*getter)()) res->Append(RenderValue(cur)); @@ -256,7 +259,7 @@ : BaseDescBuilder(what, all, tree, blame), target_(target) {} std::unique_ptr<base::DictionaryValue> BuildDescription() { - auto res = base::MakeUnique<base::DictionaryValue>(); + auto res = std::make_unique<base::DictionaryValue>(); bool is_binary_output = target_->IsBinary(); if (what_.empty()) { @@ -283,7 +286,7 @@ base::Value(target_->check_includes())); if (what(variables::kAllowCircularIncludesFrom)) { - auto labels = base::MakeUnique<base::ListValue>(); + auto labels = std::make_unique<base::ListValue>(); for (const auto& cur : target_->allow_circular_includes_from()) labels->AppendString(cur.GetUserVisibleName(GetToolchainLabel())); @@ -315,19 +318,25 @@ RenderValue(target_->public_headers())); } - if (what(variables::kInputs) && !target_->inputs().empty()) - res->SetWithoutPathExpansion(variables::kInputs, - RenderValue(target_->inputs())); + if (what(variables::kInputs)) { + std::vector<const SourceFile*> inputs; + for (ConfigValuesIterator iter(target_); !iter.done(); iter.Next()) { + for (const auto& input : iter.cur().inputs()) + inputs.push_back(&input); + } + if (!inputs.empty()) + res->SetWithoutPathExpansion(variables::kInputs, RenderValue(inputs)); + } if (is_binary_output && what(variables::kConfigs) && !target_->configs().empty()) { - auto configs = base::MakeUnique<base::ListValue>(); + auto configs = std::make_unique<base::ListValue>(); FillInConfigVector(configs.get(), target_->configs().vector()); res->SetWithoutPathExpansion(variables::kConfigs, std::move(configs)); } if (what(variables::kPublicConfigs) && !target_->public_configs().empty()) { - auto configs = base::MakeUnique<base::ListValue>(); + auto configs = std::make_unique<base::ListValue>(); FillInConfigVector(configs.get(), target_->public_configs()); res->SetWithoutPathExpansion(variables::kPublicConfigs, std::move(configs)); @@ -335,7 +344,7 @@ if (what(variables::kAllDependentConfigs) && !target_->all_dependent_configs().empty()) { - auto configs = base::MakeUnique<base::ListValue>(); + auto configs = std::make_unique<base::ListValue>(); FillInConfigVector(configs.get(), target_->all_dependent_configs()); res->SetWithoutPathExpansion(variables::kAllDependentConfigs, std::move(configs)); @@ -349,7 +358,7 @@ base::Value(target_->action_values().script().value())); if (what(variables::kArgs)) { - auto args = base::MakeUnique<base::ListValue>(); + auto args = std::make_unique<base::ListValue>(); for (const auto& elem : target_->action_values().args().list()) args->AppendString(elem.AsString()); @@ -393,6 +402,7 @@ CONFIG_VALUE_ARRAY_HANDLER(cflags_objcc, std::string) CONFIG_VALUE_ARRAY_HANDLER(defines, std::string) CONFIG_VALUE_ARRAY_HANDLER(include_dirs, SourceDir) + CONFIG_VALUE_ARRAY_HANDLER(inputs, SourceFile) CONFIG_VALUE_ARRAY_HANDLER(ldflags, std::string) #undef CONFIG_VALUE_ARRAY_HANDLER @@ -419,7 +429,7 @@ if (what(variables::kLibs)) { const OrderedSet<LibFile>& all_libs = target_->all_libs(); if (!all_libs.empty()) { - auto libs = base::MakeUnique<base::ListValue>(); + auto libs = std::make_unique<base::ListValue>(); for (size_t i = 0; i < all_libs.size(); i++) libs->AppendString(all_libs[i].value()); res->SetWithoutPathExpansion(variables::kLibs, std::move(libs)); @@ -429,7 +439,7 @@ if (what(variables::kLibDirs)) { const OrderedSet<SourceDir>& all_lib_dirs = target_->all_lib_dirs(); if (!all_lib_dirs.empty()) { - auto lib_dirs = base::MakeUnique<base::ListValue>(); + auto lib_dirs = std::make_unique<base::ListValue>(); for (size_t i = 0; i < all_lib_dirs.size(); i++) lib_dirs->AppendString(FormatSourceDir(all_lib_dirs[i])); res->SetWithoutPathExpansion(variables::kLibDirs, std::move(lib_dirs)); @@ -486,7 +496,7 @@ } ValuePtr RenderDeps() { - auto res = base::MakeUnique<base::ListValue>(); + auto res = std::make_unique<base::ListValue>(); // Tree mode is separate. if (tree_) { @@ -520,7 +530,7 @@ } ValuePtr RenderRuntimeDeps() { - auto res = base::MakeUnique<base::ListValue>(); + auto res = std::make_unique<base::ListValue>(); const Target* previous_from = NULL; for (const auto& pair : ComputeRuntimeDeps(target_)) { @@ -546,12 +556,12 @@ } void FillInSourceOutputs(base::DictionaryValue* res) { - auto dict = base::MakeUnique<base::DictionaryValue>(); + auto dict = std::make_unique<base::DictionaryValue>(); for (const auto& source : target_->sources()) { std::vector<OutputFile> outputs; Toolchain::ToolType tool_type = Toolchain::TYPE_NONE; if (target_->GetOutputFilesForSource(source, &tool_type, &outputs)) { - auto list = base::MakeUnique<base::ListValue>(); + auto list = std::make_unique<base::ListValue>(); for (const auto& output : outputs) list->AppendString(output.value()); @@ -562,7 +572,7 @@ } void FillInBundle(base::DictionaryValue* res) { - auto data = base::MakeUnique<base::DictionaryValue>(); + auto data = std::make_unique<base::DictionaryValue>(); const BundleData& bundle_data = target_->bundle_data(); const Settings* settings = target_->settings(); BundleData::SourceFiles sources; @@ -583,7 +593,7 @@ data->SetWithoutPathExpansion( "partial_info_plist", RenderValue(bundle_data.partial_info_plist())); - auto deps = base::MakeUnique<base::ListValue>(); + auto deps = std::make_unique<base::ListValue>(); for (const auto* dep : bundle_data.bundle_deps()) deps->AppendString(dep->label().GetUserVisibleName(GetToolchainLabel())); @@ -593,7 +603,7 @@ void FillInOutputs(base::DictionaryValue* res) { if (target_->output_type() == Target::ACTION) { - auto list = base::MakeUnique<base::ListValue>(); + auto list = std::make_unique<base::ListValue>(); for (const auto& elem : target_->action_values().outputs().list()) list->AppendString(elem.AsString()); @@ -608,7 +618,7 @@ target_->output_type() == Target::COPY_FILES) { const SubstitutionList& outputs = target_->action_values().outputs(); if (!outputs.required_types().empty()) { - auto patterns = base::MakeUnique<base::ListValue>(); + auto patterns = std::make_unique<base::ListValue>(); for (const auto& elem : outputs.list()) patterns->AppendString(elem.AsString()); @@ -644,7 +654,7 @@ template <class T> ValuePtr RenderConfigValues(const std::vector<T>& (ConfigValues::*getter)() const) { - auto res = base::MakeUnique<base::ListValue>(); + auto res = std::make_unique<base::ListValue>(); for (ConfigValuesIterator iter(target_); !iter.done(); iter.Next()) { const std::vector<T>& vec = (iter.cur().*getter)(); @@ -678,7 +688,7 @@ // Indent string values in blame mode if (blame_ && rendered->GetAsString(&str)) { str = " " + str; - rendered = base::MakeUnique<base::Value>(str); + rendered = std::make_unique<base::Value>(str); } res->Append(std::move(rendered)); }
diff --git a/tools/gn/docs/reference.md b/tools/gn/docs/reference.md index 037214dc..b6857e8 100644 --- a/tools/gn/docs/reference.md +++ b/tools/gn/docs/reference.md
@@ -19,9 +19,9 @@ * [Target declarations](#targets) * [action: Declare a target that runs a script a single time.](#action) * [action_foreach: Declare a target that runs a script over a set of files.](#action_foreach) - * [bundle_data: [iOS/OS X] Declare a target without output.](#bundle_data) + * [bundle_data: [iOS/macOS] Declare a target without output.](#bundle_data) * [copy: Declare a target that copies files.](#copy) - * [create_bundle: [iOS/OS X] Build an OS X / iOS bundle.](#create_bundle) + * [create_bundle: [iOS/macOS] Build an iOS or macOS bundle.](#create_bundle) * [executable: Declare an executable target.](#executable) * [group: Declare a named group of targets.](#group) * [loadable_module: Declare a loadable module target.](#loadable_module) @@ -249,7 +249,7 @@ The output will list the declaration location, current value for the build, default value (if different than the current value), and comment - preceeding the declaration. + preceding the declaration. If --short is specified, only the names and current values will be printed. @@ -353,7 +353,7 @@ included by other targets. Anything in the sources will be considered private and will not be includable regardless of dependency paths. - - Ouptuts from actions are treated like public sources on that target. + - Outputs from actions are treated like public sources on that target. - A target can include headers from a target that depends on it if the other target is annotated accordingly. See "gn help @@ -571,7 +571,7 @@ The contents of some lists ('sources', 'deps', etc.) will be sorted to a canonical order. To suppress this, you can add a comment of the form "# - NOSORT" immediately preceeding the assignment. e.g. + NOSORT" immediately preceding the assignment. e.g. # NOSORT sources = [ @@ -633,7 +633,7 @@ Generate files for an IDE. Currently supported values: "eclipse" - Eclipse CDT settings file. "vs" - Visual Studio project/solution files. - (default Visual Studio version: 2015) + (default Visual Studio version: 2017) "vs2013" - Visual Studio 2013 project/solution files. "vs2015" - Visual Studio 2015 project/solution files. "vs2017" - Visual Studio 2017 project/solution files. @@ -663,6 +663,10 @@ Use the specified Windows 10 SDK version to generate project files. As an example, "10.0.15063.0" can be specified to use Creators Update SDK instead of the default one. + + --ninja-extra-args=<string> + This string is passed without any quoting to the ninja invocation + command-line. Can be used to configure ninja flags, like "-j". ``` #### **Xcode Flags** @@ -674,8 +678,7 @@ --ninja-extra-args=<string> This string is passed without any quoting to the ninja invocation - command-line. Can be used to configure ninja flags, like "-j" if using - goma for example. + command-line. Can be used to configure ninja flags, like "-j". --root-target=<target_name> Name of the target corresponding to "All" target in Xcode. If unset, @@ -1159,7 +1162,7 @@ "/{{source_name_part}}.h" ] } ``` -### <a name="bundle_data"></a>**bundle_data**: [iOS/OS X] Declare a target without output. +### <a name="bundle_data"></a>**bundle_data**: [iOS/macOS] Declare a target without output. ``` This target type allows to declare data that is required at runtime. It is @@ -1171,8 +1174,8 @@ output. The output must reference a file inside of {{bundle_root_dir}}. This target can be used on all platforms though it is designed only to - generate iOS/OS X bundle. In cross-platform projects, it is advised to put it - behind iOS/Mac conditionals. + generate iOS/macOS bundle. In cross-platform projects, it is advised to put it + behind iOS/macOS conditionals. See "gn help create_bundle" for more information. ``` @@ -1250,10 +1253,10 @@ outputs = [ "$target_gen_dir/{{source_file_part}}" ] } ``` -### <a name="create_bundle"></a>**create_bundle**: [iOS/OS X] Build an OS X / iOS bundle. +### <a name="create_bundle"></a>**create_bundle**: [ios/macOS] Build an iOS or macOS bundle. ``` - This target generates an iOS/OS X bundle (which is a directory with a + This target generates an iOS or macOS bundle (which is a directory with a well-know structure). This target does not define any sources, instead they are computed from all "bundle_data" target this one depends on transitively (the recursion stops at "create_bundle" targets). @@ -1262,8 +1265,8 @@ expansion of {{bundle_*_dir}} rules in "bundle_data" outputs. This target can be used on all platforms though it is designed only to - generate iOS/OS X bundle. In cross-platform projects, it is advised to put it - behind iOS/Mac conditionals. + generate iOS or macOS bundle. In cross-platform projects, it is advised to put + it behind iOS/macOS conditionals. If a create_bundle is specified as a data_deps for another target, the bundle is considered a leaf, and its public and private dependencies will not @@ -1305,7 +1308,7 @@ ``` # Defines a template to create an application. On most platform, this is just - # an alias for an "executable" target, but on iOS/OS X, it builds an + # an alias for an "executable" target, but on iOS/macOS, it builds an # application bundle. template("app") { if (!is_ios && !is_mac) { @@ -2105,7 +2108,7 @@ ``` value = getenv(env_var_name) - Returns the value of the given enironment variable. If the value is not + Returns the value of the given environment variable. If the value is not found, it will try to look up the variable with the "opposite" case (based on the case of the first letter of the variable), but is otherwise case-sensitive. @@ -2754,8 +2757,8 @@ "action": Defaults for actions Platform specific tools: - "copy_bundle_data": [iOS, OS X] Tool to copy files in a bundle. - "compile_xcassets": [iOS, OS X] Tool to compile asset catalogs. + "copy_bundle_data": [iOS, macOS] Tool to copy files in a bundle. + "compile_xcassets": [iOS, macOS] Tool to compile asset catalogs. ``` #### **Tool variables** @@ -3061,10 +3064,10 @@ {{libs}} Expands to the list of system libraries to link to. Each will be - prefixed by the "lib_prefix". + prefixed by the "lib_switch". As a special case to support Mac, libraries with names ending in - ".framework" will be added to the {{libs}} with "-framework" preceeding + ".framework" will be added to the {{libs}} with "-framework" preceding it, and the lib prefix will be ignored. Example: "-lfoo -lbar" @@ -3091,7 +3094,7 @@ Example: ".so" {{solibs}} - Extra libraries from shared library dependencide not specified in the + Extra libraries from shared library dependencies not specified in the {{inputs}}. This is the list of link_output files from shared libraries (if the solink tool specifies a "link_output" variable separate from the "depend_output"). @@ -3108,7 +3111,7 @@ common tool substitutions. The copy_bundle_data and compile_xcassets tools only allows the common tool - substitutions. Both tools are required to create iOS/OS X bundles and need + substitutions. Both tools are required to create iOS/macOS bundles and need only be defined on those platforms. The copy_bundle_data tool will be called with one source and needs to copy @@ -3117,7 +3120,7 @@ The compile_xcassets tool will be called with one or more source (each an asset catalog) that needs to be compiled to a single output. The following - substitutions are avaiable: + substitutions are available: {{inputs}} Expands to the list of .xcassets to use as input to compile the asset @@ -3174,8 +3177,8 @@ ``` toolchain("my_toolchain") { # Put these at the top to apply to all tools below. - lib_prefix = "-l" - lib_dir_prefix = "-L" + lib_switch = "-l" + lib_dir_switch = "-L" tool("cc") { command = "gcc {{source}} -o {{output}}" @@ -3213,7 +3216,7 @@ When a target has a dependency on a target using different toolchain (see "gn help labels" for how to specify this), GN will start a build using that secondary toolchain to resolve the target. GN will load the build config file - with the build arguements overridden as specified in the toolchain_args. + with the build arguments overridden as specified in the toolchain_args. Because the default toolchain is already known, calls to set_default_toolchain() are ignored. @@ -3338,7 +3341,7 @@ that depend on this file. One use for write_file is to write a list of inputs to an script that might - be too long for the command line. However, it is preferrable to use response + be too long for the command line. However, it is preferable to use response files for this purpose. See "gn help response_file_contents". TODO(brettw) we probably need an optional third argument to control list @@ -3718,7 +3721,7 @@ those configs appear in the list. 5. all_dependent_configs pulled from dependencies, in the order of the "deps" list. This is done recursively. If a config appears - more than once, only the first occurance will be used. + more than once, only the first occurence will be used. 6. public_configs pulled from dependencies, in the order of the "deps" list. If a dependency is public, they will be applied recursively. @@ -3824,7 +3827,7 @@ those configs appear in the list. 5. all_dependent_configs pulled from dependencies, in the order of the "deps" list. This is done recursively. If a config appears - more than once, only the first occurance will be used. + more than once, only the first occurence will be used. 6. public_configs pulled from dependencies, in the order of the "deps" list. If a dependency is public, they will be applied recursively. @@ -3859,7 +3862,7 @@ those configs appear in the list. 5. all_dependent_configs pulled from dependencies, in the order of the "deps" list. This is done recursively. If a config appears - more than once, only the first occurance will be used. + more than once, only the first occurence will be used. 6. public_configs pulled from dependencies, in the order of the "deps" list. If a dependency is public, they will be applied recursively. @@ -4037,7 +4040,7 @@ those configs appear in the list. 5. all_dependent_configs pulled from dependencies, in the order of the "deps" list. This is done recursively. If a config appears - more than once, only the first occurance will be used. + more than once, only the first occurence will be used. 6. public_configs pulled from dependencies, in the order of the "deps" list. If a dependency is public, they will be applied recursively. @@ -4070,7 +4073,7 @@ those configs appear in the list. 5. all_dependent_configs pulled from dependencies, in the order of the "deps" list. This is done recursively. If a config appears - more than once, only the first occurance will be used. + more than once, only the first occurence will be used. 6. public_configs pulled from dependencies, in the order of the "deps" list. If a dependency is public, they will be applied recursively. @@ -4103,7 +4106,7 @@ those configs appear in the list. 5. all_dependent_configs pulled from dependencies, in the order of the "deps" list. This is done recursively. If a config appears - more than once, only the first occurance will be used. + more than once, only the first occurence will be used. 6. public_configs pulled from dependencies, in the order of the "deps" list. If a dependency is public, they will be applied recursively. @@ -4136,7 +4139,7 @@ those configs appear in the list. 5. all_dependent_configs pulled from dependencies, in the order of the "deps" list. This is done recursively. If a config appears - more than once, only the first occurance will be used. + more than once, only the first occurence will be used. 6. public_configs pulled from dependencies, in the order of the "deps" list. If a dependency is public, they will be applied recursively. @@ -4169,7 +4172,7 @@ those configs appear in the list. 5. all_dependent_configs pulled from dependencies, in the order of the "deps" list. This is done recursively. If a config appears - more than once, only the first occurance will be used. + more than once, only the first occurence will be used. 6. public_configs pulled from dependencies, in the order of the "deps" list. If a dependency is public, they will be applied recursively. @@ -4331,7 +4334,7 @@ those configs appear in the list. 5. all_dependent_configs pulled from dependencies, in the order of the "deps" list. This is done recursively. If a config appears - more than once, only the first occurance will be used. + more than once, only the first occurence will be used. 6. public_configs pulled from dependencies, in the order of the "deps" list. If a dependency is public, they will be applied recursively. @@ -4388,7 +4391,7 @@ However, no verification is done on these so GN doesn't enforce this. The paths are just rebased and passed along when requested. - Note: On iOS and OS X, create_bundle targets will not be recursed into when + Note: On iOS and macOS, create_bundle targets will not be recursed into when gathering data. See "gn help create_bundle" for details. See "gn help runtime_deps" for how these are used. @@ -4405,7 +4408,7 @@ This is normally used for things like plugins or helper programs that a target needs at runtime. - Note: On iOS and OS X, create_bundle targets will not be recursed into when + Note: On iOS and macOS, create_bundle targets will not be recursed into when gathering data_deps. See "gn help create_bundle" for details. See also "gn help deps" and "gn help data". @@ -4440,7 +4443,7 @@ those configs appear in the list. 5. all_dependent_configs pulled from dependencies, in the order of the "deps" list. This is done recursively. If a config appears - more than once, only the first occurance will be used. + more than once, only the first occurence will be used. 6. public_configs pulled from dependencies, in the order of the "deps" list. If a dependency is public, they will be applied recursively. @@ -4496,7 +4499,7 @@ A list of target labels. Specifies private dependencies of a target. Private dependencies are - propagated up the dependency tree and linked to dependant targets, but do not + propagated up the dependency tree and linked to dependent targets, but do not grant the ability to include headers from the dependency. Public configs are not forwarded. ``` @@ -4511,7 +4514,7 @@ Executables, shared libraries, and complete static libraries will link all propagated targets and stop propagation. Actions and copy steps also stop propagation, allowing them to take a library as an input but not force - dependants to link to it. + dependents to link to it. Propagation of all_dependent_configs and public_configs happens independently of target type. all_dependent_configs are always propagated across all types @@ -4544,7 +4547,7 @@ those configs appear in the list. 5. all_dependent_configs pulled from dependencies, in the order of the "deps" list. This is done recursively. If a config appears - more than once, only the first occurance will be used. + more than once, only the first occurence will be used. 6. public_configs pulled from dependencies, in the order of the "deps" list. If a dependency is public, they will be applied recursively. @@ -4652,7 +4655,7 @@ those configs appear in the list. 5. all_dependent_configs pulled from dependencies, in the order of the "deps" list. This is done recursively. If a config appears - more than once, only the first occurance will be used. + more than once, only the first occurence will be used. 6. public_configs pulled from dependencies, in the order of the "deps" list. If a dependency is public, they will be applied recursively. @@ -4685,7 +4688,7 @@ those configs appear in the list. 5. all_dependent_configs pulled from dependencies, in the order of the "deps" list. This is done recursively. If a config appears - more than once, only the first occurance will be used. + more than once, only the first occurence will be used. 6. public_configs pulled from dependencies, in the order of the "deps" list. If a dependency is public, they will be applied recursively. @@ -4730,14 +4733,14 @@ System libraries Values not containing '/' will be treated as system library names. These will be passed unmodified to the linker and prefixed with the - "lib_prefix" attribute of the linker tool. Generally you would set the + "lib_switch" attribute of the linker tool. Generally you would set the "lib_dirs" so the given library is found. Your BUILD.gn file should not - specify the switch (like "-l"): this will be encoded in the "lib_prefix" + specify the switch (like "-l"): this will be encoded in the "lib_switch" of the tool. Apple frameworks System libraries ending in ".framework" will be special-cased: the switch - "-framework" will be prepended instead of the lib_prefix, and the + "-framework" will be prepended instead of the lib_switch, and the ".framework" suffix will be trimmed. This is to support the way Mac links framework dependencies. ``` @@ -4754,7 +4757,7 @@ those configs appear in the list. 5. all_dependent_configs pulled from dependencies, in the order of the "deps" list. This is done recursively. If a config appears - more than once, only the first occurance will be used. + more than once, only the first occurence will be used. 6. public_configs pulled from dependencies, in the order of the "deps" list. If a dependency is public, they will be applied recursively. @@ -5088,7 +5091,7 @@ those configs appear in the list. 5. all_dependent_configs pulled from dependencies, in the order of the "deps" list. This is done recursively. If a config appears - more than once, only the first occurance will be used. + more than once, only the first occurence will be used. 6. public_configs pulled from dependencies, in the order of the "deps" list. If a dependency is public, they will be applied recursively. @@ -5205,7 +5208,7 @@ As a special case, a file ending in ".def" will be treated as a Windows module definition file. It will be appended to the link line with a - preceeding "/DEF:" string. There must be at most one .def file in a target + preceding "/DEF:" string. There must be at most one .def file in a target and they do not cross dependency boundaries (so specifying a .def file in a static library or source set will have no effect on the executable or shared library they're linked into). @@ -5563,7 +5566,7 @@ ... target parameter definitions ... } - There is also a generic "target" function for programatically defined types + There is also a generic "target" function for programmatically defined types (see "gn help target"). You can define new types using templates (see "gn help template"). A template defines some custom code that expands to one or more other targets. @@ -5869,6 +5872,20 @@ Note that if the input is empty, the result will be a null value which will produce an error if assigned to a variable. + "json" + Parse the input as a JSON and convert it to equivalent GN rvalue. The data + type mapping is: + a string in JSON maps to string in GN + an integer in JSON maps to integer in GN + a float in JSON is unsupported and will result in an error + an object in JSON maps to scope in GN + an array in JSON maps to list in GN + a boolean in JSON maps to boolean in GN + a null in JSON is unsupported and will result in an error + + Nota that the dictionary keys have to be valid GN identifiers otherwise + they will produce an error. + "trim ..." Prefixing any of the other transformations with the word "trim" will result in whitespace being trimmed from the beginning and end of the
diff --git a/tools/gn/eclipse_writer.cc b/tools/gn/eclipse_writer.cc index dbc6eb9..720231b4 100644 --- a/tools/gn/eclipse_writer.cc +++ b/tools/gn/eclipse_writer.cc
@@ -47,7 +47,7 @@ languages_.push_back("Assembly"); } -EclipseWriter::~EclipseWriter() {} +EclipseWriter::~EclipseWriter() = default; // static bool EclipseWriter::RunAndWriteFile(
diff --git a/tools/gn/err.cc b/tools/gn/err.cc index 56e93bd..bdd6f4c 100644 --- a/tools/gn/err.cc +++ b/tools/gn/err.cc
@@ -146,22 +146,29 @@ Err::Err(const Err& other) = default; -Err::~Err() { -} +Err::~Err() = default; void Err::PrintToStdout() const { - InternalPrintToStdout(false); + InternalPrintToStdout(false, true); +} + +void Err::PrintNonfatalToStdout() const { + InternalPrintToStdout(false, false); } void Err::AppendSubErr(const Err& err) { sub_errs_.push_back(err); } -void Err::InternalPrintToStdout(bool is_sub_err) const { +void Err::InternalPrintToStdout(bool is_sub_err, bool is_fatal) const { DCHECK(has_error_); - if (!is_sub_err) - OutputString("ERROR ", DECORATION_RED); + if (!is_sub_err) { + if (is_fatal) + OutputString("ERROR ", DECORATION_RED); + else + OutputString("WARNING ", DECORATION_RED); + } // File name and location. const InputFile* input_file = location_.file(); @@ -191,5 +198,5 @@ // Sub errors. for (const auto& sub_err : sub_errs_) - sub_err.InternalPrintToStdout(true); + sub_err.InternalPrintToStdout(true, is_fatal); }
diff --git a/tools/gn/err.h b/tools/gn/err.h index eeec31a..90f3150 100644 --- a/tools/gn/err.h +++ b/tools/gn/err.h
@@ -24,7 +24,7 @@ // below. They can provide additional context. class Err { public: - typedef std::vector<LocationRange> RangeList; + using RangeList = std::vector<LocationRange>; // Indicates no error. Err(); @@ -70,8 +70,20 @@ void PrintToStdout() const; + // Prints to standard out but uses a "WARNING" messaging instead of the + // normal "ERROR" messaging. This is a property of the printing system rather + // than of the Err class because there is no expectation that code calling a + // function that take an Err check that the error is nonfatal and continue. + // Generally all Err objects with has_error() set are fatal. + // + // In some very specific cases code will detect a condition and print a + // nonfatal error to the screen instead of returning it. In these cases, that + // code can decide at printing time whether it will continue (and use this + // method) or not (and use PrintToStdout()). + void PrintNonfatalToStdout() const; + private: - void InternalPrintToStdout(bool is_sub_err) const; + void InternalPrintToStdout(bool is_sub_err, bool is_fatal) const; bool has_error_; Location location_;
diff --git a/tools/gn/escape_unittest.cc b/tools/gn/escape_unittest.cc index fc7692d..8d7ba8a 100644 --- a/tools/gn/escape_unittest.cc +++ b/tools/gn/escape_unittest.cc
@@ -35,7 +35,7 @@ // Backslashes at the end of the string get escaped. EXPECT_EQ("\"foo$ bar\\\\\\\\\"", EscapeString("foo bar\\\\", opts, nullptr)); - // Backslashes preceeding quotes are escaped, and the quote is escaped. + // Backslashes preceding quotes are escaped, and the quote is escaped. EXPECT_EQ("\"foo\\\\\\\"$ bar\"", EscapeString("foo\\\" bar", opts, nullptr)); }
diff --git a/tools/gn/filesystem_utils.cc b/tools/gn/filesystem_utils.cc index 44fa0eb..6cce895 100644 --- a/tools/gn/filesystem_utils.cc +++ b/tools/gn/filesystem_utils.cc
@@ -15,6 +15,10 @@ #include "tools/gn/settings.h" #include "tools/gn/source_dir.h" +#if defined(OS_WIN) +#include <windows.h> +#endif + namespace { enum DotDisposition { @@ -412,6 +416,47 @@ #endif } +base::FilePath MakeAbsoluteFilePathRelativeIfPossible( + const base::FilePath& base, + const base::FilePath& target) { + DCHECK(base.IsAbsolute()); + DCHECK(target.IsAbsolute()); + std::vector<base::FilePath::StringType> base_components; + std::vector<base::FilePath::StringType> target_components; + base.GetComponents(&base_components); + target.GetComponents(&target_components); +#if defined(OS_WIN) + // On Windows, it's impossible to have a relative path from C:\foo to D:\bar, + // so return the target as an aboslute path instead. + if (base_components[0] != target_components[0]) + return target; +#endif + size_t i; + for (i = 0; i < base_components.size() && i < target_components.size(); i++) { + if (base_components[i] != target_components[i]) + break; + } + std::vector<base::FilePath::StringType> relative_components; + for (size_t j = i; j < base_components.size(); j++) + relative_components.push_back(base::FilePath::kParentDirectory); + for (size_t j = i; j < target_components.size(); j++) + relative_components.push_back(target_components[j]); + if (relative_components.size() <= 1) { + // In case the file pointed-to is an executable, prepend the current + // directory to the path -- if the path was "gn", use "./gn" instead. If + // the file path is used in a command, this prevents issues where "gn" might + // not be in the PATH (or it is in the path, and the wrong gn is used). + relative_components.insert(relative_components.begin(), + base::FilePath::kCurrentDirectory); + } + // base::FilePath::Append(component) replaces the file path with |component| + // if the path is base::Filepath::kCurrentDirectory. We want to preserve the + // leading "./", so we build the path ourselves and use that to construct the + // base::FilePath. + base::FilePath::StringType separator(&base::FilePath::kSeparators[0], 1); + return base::FilePath(base::JoinString(relative_components, separator)); +} + void NormalizePath(std::string* path, const base::StringPiece& source_root) { char* pathbuf = path->empty() ? nullptr : &(*path)[0];
diff --git a/tools/gn/filesystem_utils.h b/tools/gn/filesystem_utils.h index bc14eb92..0396283 100644 --- a/tools/gn/filesystem_utils.h +++ b/tools/gn/filesystem_utils.h
@@ -116,6 +116,16 @@ const base::StringPiece& path, std::string* dest); +// Given two absolute paths |base| and |target|, returns a relative path to +// |target| as if the current directory was |base|. The relative path returned +// is minimal. For example, if "../../a/b/" and "../b" are both valid, then the +// latter will be returned. On Windows, it's impossible to have a relative path +// from C:\foo to D:\bar, so the absolute path |target| is returned instead for +// this case. +base::FilePath MakeAbsoluteFilePathRelativeIfPossible( + const base::FilePath& base, + const base::FilePath& target); + // Collapses "." and sequential "/"s and evaluates "..". |path| may be // system-absolute, source-absolute, or relative. If |path| is source-absolute // and |source_root| is non-empty, |path| may be system absolute after this
diff --git a/tools/gn/filesystem_utils_unittest.cc b/tools/gn/filesystem_utils_unittest.cc index f5724c43..dc2e512 100644 --- a/tools/gn/filesystem_utils_unittest.cc +++ b/tools/gn/filesystem_utils_unittest.cc
@@ -173,6 +173,50 @@ #endif } +TEST(FilesystemUtils, MakeAbsoluteFilePathRelativeIfPossible) { +#if defined(OS_WIN) + EXPECT_EQ( + base::FilePath(L"out\\Debug"), + MakeAbsoluteFilePathRelativeIfPossible( + base::FilePath(L"C:\\src"), base::FilePath(L"C:\\src\\out\\Debug"))); + EXPECT_EQ(base::FilePath(L".\\gn"), + MakeAbsoluteFilePathRelativeIfPossible( + base::FilePath(L"C:\\src\\out\\Debug"), + base::FilePath(L"C:\\src\\out\\Debug\\gn"))); + EXPECT_EQ( + base::FilePath(L"..\\.."), + MakeAbsoluteFilePathRelativeIfPossible( + base::FilePath(L"C:\\src\\out\\Debug"), base::FilePath(L"C:\\src"))); + EXPECT_EQ(base::FilePath(L"."), + MakeAbsoluteFilePathRelativeIfPossible(base::FilePath(L"C:\\src"), + base::FilePath(L"C:\\src"))); + EXPECT_EQ(base::FilePath(L"..\\..\\..\\u\\v\\w"), + MakeAbsoluteFilePathRelativeIfPossible( + base::FilePath(L"C:\\a\\b\\c\\x\\y\\z"), + base::FilePath(L"C:\\a\\b\\c\\u\\v\\w"))); + EXPECT_EQ(base::FilePath(L"D:\\bar"), + MakeAbsoluteFilePathRelativeIfPossible(base::FilePath(L"C:\\foo"), + base::FilePath(L"D:\\bar"))); +#else + EXPECT_EQ(base::FilePath("out/Debug"), + MakeAbsoluteFilePathRelativeIfPossible( + base::FilePath("/src"), base::FilePath("/src/out/Debug"))); + EXPECT_EQ(base::FilePath("./gn"), MakeAbsoluteFilePathRelativeIfPossible( + base::FilePath("/src/out/Debug"), + base::FilePath("/src/out/Debug/gn"))); + EXPECT_EQ(base::FilePath("../.."), + MakeAbsoluteFilePathRelativeIfPossible( + base::FilePath("/src/out/Debug"), base::FilePath("/src"))); + EXPECT_EQ(base::FilePath("."), + MakeAbsoluteFilePathRelativeIfPossible(base::FilePath("/src"), + base::FilePath("/src"))); + EXPECT_EQ( + base::FilePath("../../../u/v/w"), + MakeAbsoluteFilePathRelativeIfPossible(base::FilePath("/a/b/c/x/y/z"), + base::FilePath("/a/b/c/u/v/w"))); +#endif +} + TEST(FilesystemUtils, NormalizePath) { std::string input;
diff --git a/tools/gn/format_test_data/062.gn b/tools/gn/format_test_data/062.gn index d7fbb3c..8c4cc7d 100644 --- a/tools/gn/format_test_data/062.gn +++ b/tools/gn/format_test_data/062.gn
@@ -110,3 +110,13 @@ "srtp/crypto/rng/prng.c", "srtp/crypto/rng/rand_source.c", ] + +# Try "public" too. It should be treated the same. +public = [ + # Let's sort + "this", "into", "word", "salad", + + # But leave + "these", "two" + # alone! +]
diff --git a/tools/gn/format_test_data/062.golden b/tools/gn/format_test_data/062.golden index e939e449..b5545101 100644 --- a/tools/gn/format_test_data/062.golden +++ b/tools/gn/format_test_data/062.golden
@@ -115,3 +115,18 @@ "srtp/srtp/ekt.c", "srtp/srtp/srtp.c", ] + +# Try "public" too. It should be treated the same. +public = [ + # Let's sort + "into", + "salad", + "this", + "word", + + # But leave + "these", + "two", + + # alone! +]
diff --git a/tools/gn/format_test_data/068.gn b/tools/gn/format_test_data/068.gn new file mode 100644 index 0000000..7fb8e1b --- /dev/null +++ b/tools/gn/format_test_data/068.gn
@@ -0,0 +1,3 @@ +# Initial comment + +# Comment that should be separate, no subsequent content in file.
diff --git a/tools/gn/format_test_data/068.golden b/tools/gn/format_test_data/068.golden new file mode 100644 index 0000000..7fb8e1b --- /dev/null +++ b/tools/gn/format_test_data/068.golden
@@ -0,0 +1,3 @@ +# Initial comment + +# Comment that should be separate, no subsequent content in file.
diff --git a/tools/gn/format_test_data/069.gn b/tools/gn/format_test_data/069.gn new file mode 100644 index 0000000..200b313 --- /dev/null +++ b/tools/gn/format_test_data/069.gn
@@ -0,0 +1,3 @@ +if (true) { + configs -= [ "//third_party/mini_chromium/mini_chromium/build:Wexit_time_destructors", ] +}
diff --git a/tools/gn/format_test_data/069.golden b/tools/gn/format_test_data/069.golden new file mode 100644 index 0000000..64d4acce --- /dev/null +++ b/tools/gn/format_test_data/069.golden
@@ -0,0 +1,5 @@ +if (true) { + configs -= [ + "//third_party/mini_chromium/mini_chromium/build:Wexit_time_destructors", + ] +}
diff --git a/tools/gn/format_test_data/070.gn b/tools/gn/format_test_data/070.gn new file mode 100644 index 0000000..09d80d2 --- /dev/null +++ b/tools/gn/format_test_data/070.gn
@@ -0,0 +1,15 @@ +multiple = [ + { + name = "elements_test" + }, + { + name = "eapol_crypto_test" + }, + ] + + +single = [ + { + name = "elements_test" + }, + ]
diff --git a/tools/gn/format_test_data/070.golden b/tools/gn/format_test_data/070.golden new file mode 100644 index 0000000..0997aa4 --- /dev/null +++ b/tools/gn/format_test_data/070.golden
@@ -0,0 +1,14 @@ +multiple = [ + { + name = "elements_test" + }, + { + name = "eapol_crypto_test" + }, +] + +single = [ + { + name = "elements_test" + }, +]
diff --git a/tools/gn/function_exec_script.cc b/tools/gn/function_exec_script.cc index 8c4909c37..139b811 100644 --- a/tools/gn/function_exec_script.cc +++ b/tools/gn/function_exec_script.cc
@@ -7,6 +7,7 @@ #include "base/logging.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" +#include "base/threading/thread_restrictions.h" #include "base/time/time.h" #include "build/build_config.h" #include "tools/gn/err.h" @@ -115,6 +116,9 @@ exec_script("//foo/bar/myscript.py") )"; +class ExecScriptScopedAllowBaseSyncPrimitives + : public base::ScopedAllowBaseSyncPrimitives {}; + Value RunExecScript(Scope* scope, const FunctionCallNode* function, const std::vector<Value>& args, @@ -221,11 +225,15 @@ std::string output; std::string stderr_output; int exit_code = 0; - if (!internal::ExecProcess( - cmdline, startup_dir, &output, &stderr_output, &exit_code)) { - *err = Err(function->function(), "Could not execute python.", - "I was trying to execute \"" + FilePathToUTF8(python_path) + "\"."); - return Value(); + { + ExecScriptScopedAllowBaseSyncPrimitives allow_base_sync_primitives; + if (!internal::ExecProcess(cmdline, startup_dir, &output, &stderr_output, + &exit_code)) { + *err = Err( + function->function(), "Could not execute python.", + "I was trying to execute \"" + FilePathToUTF8(python_path) + "\"."); + return Value(); + } } if (g_scheduler->verbose_logging()) { g_scheduler->Log("Pythoning", script_source.value() + " took " +
diff --git a/tools/gn/function_forward_variables_from_unittest.cc b/tools/gn/function_forward_variables_from_unittest.cc index 84d8b6e..3d697886 100644 --- a/tools/gn/function_forward_variables_from_unittest.cc +++ b/tools/gn/function_forward_variables_from_unittest.cc
@@ -4,10 +4,12 @@ #include "testing/gtest/include/gtest/gtest.h" #include "tools/gn/scheduler.h" +#include "tools/gn/test_with_scheduler.h" #include "tools/gn/test_with_scope.h" -TEST(FunctionForwardVariablesFrom, List) { - Scheduler scheduler; +using FunctionForwardVariablesFromTest = TestWithScheduler; + +TEST_F(FunctionForwardVariablesFromTest, List) { Err err; std::string program = "template(\"a\") {\n" @@ -50,8 +52,7 @@ } } -TEST(FunctionForwardVariablesFrom, LiteralList) { - Scheduler scheduler; +TEST_F(FunctionForwardVariablesFromTest, LiteralList) { TestWithScope setup; // Forwards all variables from a literal scope into another scope definition. @@ -72,8 +73,7 @@ setup.print_output().clear(); } -TEST(FunctionForwardVariablesFrom, ListWithExclusion) { - Scheduler scheduler; +TEST_F(FunctionForwardVariablesFromTest, ListWithExclusion) { TestWithScope setup; // Defines a template and copy the two x and y, and z values out. @@ -100,8 +100,7 @@ setup.print_output().clear(); } -TEST(FunctionForwardVariablesFrom, ErrorCases) { - Scheduler scheduler; +TEST_F(FunctionForwardVariablesFromTest, ErrorCases) { TestWithScope setup; // Type check the source scope. @@ -190,8 +189,7 @@ EXPECT_EQ("Wrong number of arguments.", err.message()); } -TEST(FunctionForwardVariablesFrom, Star) { - Scheduler scheduler; +TEST_F(FunctionForwardVariablesFromTest, Star) { TestWithScope setup; // Defines a template and copy the two x and y values out. The "*" behavior @@ -217,9 +215,7 @@ setup.print_output().clear(); } - -TEST(FunctionForwardVariablesFrom, StarWithExclusion) { - Scheduler scheduler; +TEST_F(FunctionForwardVariablesFromTest, StarWithExclusion) { TestWithScope setup; // Defines a template and copy all values except z value. The "*" behavior
diff --git a/tools/gn/function_get_target_outputs_unittest.cc b/tools/gn/function_get_target_outputs_unittest.cc index abe07d4..d7354eb 100644 --- a/tools/gn/function_get_target_outputs_unittest.cc +++ b/tools/gn/function_get_target_outputs_unittest.cc
@@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <memory> #include <utility> -#include "base/memory/ptr_util.h" #include "testing/gtest/include/gtest/gtest.h" #include "tools/gn/functions.h" #include "tools/gn/target.h" @@ -61,7 +61,7 @@ TEST_F(GetTargetOutputsTest, Copy) { auto action = - base::MakeUnique<Target>(setup_.settings(), GetLabel("//foo/", "bar")); + std::make_unique<Target>(setup_.settings(), GetLabel("//foo/", "bar")); action->set_output_type(Target::COPY_FILES); action->sources().push_back(SourceFile("//file.txt")); action->action_values().outputs() = @@ -77,7 +77,7 @@ TEST_F(GetTargetOutputsTest, Action) { auto action = - base::MakeUnique<Target>(setup_.settings(), GetLabel("//foo/", "bar")); + std::make_unique<Target>(setup_.settings(), GetLabel("//foo/", "bar")); action->set_output_type(Target::ACTION); action->action_values().outputs() = SubstitutionList::MakeForTest( "//output1.txt", @@ -93,7 +93,7 @@ TEST_F(GetTargetOutputsTest, ActionForeach) { auto action = - base::MakeUnique<Target>(setup_.settings(), GetLabel("//foo/", "bar")); + std::make_unique<Target>(setup_.settings(), GetLabel("//foo/", "bar")); action->set_output_type(Target::ACTION_FOREACH); action->sources().push_back(SourceFile("//file.txt")); action->action_values().outputs() = SubstitutionList::MakeForTest(
diff --git a/tools/gn/function_toolchain.cc b/tools/gn/function_toolchain.cc index 707c5c4..19eaea8 100644 --- a/tools/gn/function_toolchain.cc +++ b/tools/gn/function_toolchain.cc
@@ -4,6 +4,7 @@ #include <algorithm> #include <limits> +#include <memory> #include <utility> #include "tools/gn/err.h" @@ -323,7 +324,7 @@ When a target has a dependency on a target using different toolchain (see "gn help labels" for how to specify this), GN will start a build using that secondary toolchain to resolve the target. GN will load the build config file - with the build arguements overridden as specified in the toolchain_args. + with the build arguments overridden as specified in the toolchain_args. Because the default toolchain is already known, calls to set_default_toolchain() are ignored. @@ -453,7 +454,8 @@ // This object will actually be copied into the one owned by the toolchain // manager, but that has to be done in the lock. - std::unique_ptr<Toolchain> toolchain(new Toolchain(scope->settings(), label)); + std::unique_ptr<Toolchain> toolchain = std::make_unique<Toolchain>( + scope->settings(), label, scope->build_dependency_files()); toolchain->set_defined_from(function); toolchain->visibility().SetPublic(); @@ -534,8 +536,8 @@ "action": Defaults for actions Platform specific tools: - "copy_bundle_data": [iOS, OS X] Tool to copy files in a bundle. - "compile_xcassets": [iOS, OS X] Tool to compile asset catalogs. + "copy_bundle_data": [iOS, macOS] Tool to copy files in a bundle. + "compile_xcassets": [iOS, macOS] Tool to compile asset catalogs. Tool variables @@ -838,10 +840,10 @@ {{libs}} Expands to the list of system libraries to link to. Each will be - prefixed by the "lib_prefix". + prefixed by the "lib_switch". As a special case to support Mac, libraries with names ending in - ".framework" will be added to the {{libs}} with "-framework" preceeding + ".framework" will be added to the {{libs}} with "-framework" preceding it, and the lib prefix will be ignored. Example: "-lfoo -lbar" @@ -868,7 +870,7 @@ Example: ".so" {{solibs}} - Extra libraries from shared library dependencide not specified in the + Extra libraries from shared library dependencies not specified in the {{inputs}}. This is the list of link_output files from shared libraries (if the solink tool specifies a "link_output" variable separate from the "depend_output"). @@ -886,7 +888,7 @@ common tool substitutions. The copy_bundle_data and compile_xcassets tools only allows the common tool - substitutions. Both tools are required to create iOS/OS X bundles and need + substitutions. Both tools are required to create iOS/macOS bundles and need only be defined on those platforms. The copy_bundle_data tool will be called with one source and needs to copy @@ -895,7 +897,7 @@ The compile_xcassets tool will be called with one or more source (each an asset catalog) that needs to be compiled to a single output. The following - substitutions are avaiable: + substitutions are available: {{inputs}} Expands to the list of .xcassets to use as input to compile the asset @@ -948,8 +950,8 @@ toolchain("my_toolchain") { # Put these at the top to apply to all tools below. - lib_prefix = "-l" - lib_dir_prefix = "-L" + lib_switch = "-l" + lib_dir_switch = "-L" tool("cc") { command = "gcc {{source}} -o {{output}}" @@ -1022,7 +1024,7 @@ subst_output_validator = &IsValidToolSubstitution; } - std::unique_ptr<Tool> tool(new Tool); + std::unique_ptr<Tool> tool = std::make_unique<Tool>(); tool->set_defined_from(function); if (!ReadPattern(&block_scope, "command", subst_validator, tool.get(),
diff --git a/tools/gn/function_toolchain_unittest.cc b/tools/gn/function_toolchain_unittest.cc index 2d8a548e..eec8779 100644 --- a/tools/gn/function_toolchain_unittest.cc +++ b/tools/gn/function_toolchain_unittest.cc
@@ -5,10 +5,12 @@ #include "testing/gtest/include/gtest/gtest.h" #include "tools/gn/functions.h" #include "tools/gn/scheduler.h" +#include "tools/gn/test_with_scheduler.h" #include "tools/gn/test_with_scope.h" -TEST(FunctionToolchain, RuntimeOutputs) { - Scheduler scheduler; +using FunctionToolchain = TestWithScheduler; + +TEST_F(FunctionToolchain, RuntimeOutputs) { TestWithScope setup; // These runtime outputs are a subset of the outputs so are OK.
diff --git a/tools/gn/function_write_file.cc b/tools/gn/function_write_file.cc index 0e2dd06..bfa79b6 100644 --- a/tools/gn/function_write_file.cc +++ b/tools/gn/function_write_file.cc
@@ -35,7 +35,7 @@ that depend on this file. One use for write_file is to write a list of inputs to an script that might - be too long for the command line. However, it is preferrable to use response + be too long for the command line. However, it is preferable to use response files for this purpose. See "gn help response_file_contents". TODO(brettw) we probably need an optional third argument to control list
diff --git a/tools/gn/function_write_file_unittest.cc b/tools/gn/function_write_file_unittest.cc index 8f2b42a..db2ea1e 100644 --- a/tools/gn/function_write_file_unittest.cc +++ b/tools/gn/function_write_file_unittest.cc
@@ -10,6 +10,7 @@ #include "testing/gtest/include/gtest/gtest.h" #include "tools/gn/functions.h" #include "tools/gn/scheduler.h" +#include "tools/gn/test_with_scheduler.h" #include "tools/gn/test_with_scope.h" namespace { @@ -33,8 +34,9 @@ } // namespace -TEST(WriteFile, WithData) { - Scheduler scheduler; +using WriteFileTest = TestWithScheduler; + +TEST_F(WriteFileTest, WithData) { TestWithScope setup; // Make a real directory for writing the files.
diff --git a/tools/gn/functions.cc b/tools/gn/functions.cc index 540c1da..fa968c9 100644 --- a/tools/gn/functions.cc +++ b/tools/gn/functions.cc
@@ -6,6 +6,7 @@ #include <stddef.h> #include <iostream> +#include <memory> #include <utility> #include "base/environment.h" @@ -337,7 +338,8 @@ g_scheduler->Log("Defining config", label.GetUserVisibleName(true)); // Create the new config. - std::unique_ptr<Config> config(new Config(scope->settings(), label)); + std::unique_ptr<Config> config = std::make_unique<Config>( + scope->settings(), label, scope->build_dependency_files()); config->set_defined_from(function); if (!Visibility::FillItemVisibility(config.get(), scope, err)) return Value(); @@ -552,7 +554,7 @@ value = getenv(env_var_name) - Returns the value of the given enironment variable. If the value is not + Returns the value of the given environment variable. If the value is not found, it will try to look up the variable with the "opposite" case (based on the case of the first letter of the variable), but is otherwise case-sensitive. @@ -631,6 +633,7 @@ SourceFile import_file = input_dir.ResolveRelativeFile(args[0], err, scope->settings()->build_settings()->root_path_utf8()); + scope->AddBuildDependencyFile(import_file); if (!err->has_error()) { scope->settings()->import_manager().DoImport(import_file, function, scope, err); @@ -668,7 +671,7 @@ const ListNode* args_list, Err* err) { const auto& args_vector = args_list->contents(); - if (args_vector.size() < 1 && args_vector.size() > 3) { + if (args_vector.size() < 1 || args_vector.size() > 3) { *err = Err(function, "Wrong number of arguments.", "Expecting one, two or three arguments."); return Value(); @@ -825,7 +828,7 @@ if (args.size() != 1) { *err = Err(function, "set_sources_assignment_filter takes one argument."); } else { - std::unique_ptr<PatternList> f(new PatternList); + std::unique_ptr<PatternList> f = std::make_unique<PatternList>(); f->SetFromValue(args[0], err); if (!err->has_error()) scope->set_sources_assignment_filter(std::move(f)); @@ -908,7 +911,8 @@ } // Create the new pool. - std::unique_ptr<Pool> pool(new Pool(scope->settings(), label)); + std::unique_ptr<Pool> pool = std::make_unique<Pool>( + scope->settings(), label, scope->build_dependency_files()); pool->set_depth(depth->int_value()); // Save the generated item.
diff --git a/tools/gn/functions_target.cc b/tools/gn/functions_target.cc index 7cf65f94..0e203678 100644 --- a/tools/gn/functions_target.cc +++ b/tools/gn/functions_target.cc
@@ -253,9 +253,9 @@ const char kBundleData[] = "bundle_data"; const char kBundleData_HelpShort[] = - "bundle_data: [iOS/OS X] Declare a target without output."; + "bundle_data: [iOS/macOS] Declare a target without output."; const char kBundleData_Help[] = - R"(bundle_data: [iOS/OS X] Declare a target without output. + R"(bundle_data: [iOS/macOS] Declare a target without output. This target type allows to declare data that is required at runtime. It is used to inform "create_bundle" targets of the files to copy into generated @@ -266,8 +266,8 @@ output. The output must reference a file inside of {{bundle_root_dir}}. This target can be used on all platforms though it is designed only to - generate iOS/OS X bundle. In cross-platform projects, it is advised to put it - behind iOS/Mac conditionals. + generate iOS/macOS bundle. In cross-platform projects, it is advised to put it + behind iOS/macOS conditionals. See "gn help create_bundle" for more information. @@ -318,11 +318,11 @@ const char kCreateBundle[] = "create_bundle"; const char kCreateBundle_HelpShort[] = - "create_bundle: [iOS/OS X] Build an OS X / iOS bundle."; + "create_bundle: [iOS/macOS] Build an iOS or macOS bundle."; const char kCreateBundle_Help[] = - R"(create_bundle: [iOS/OS X] Build an OS X / iOS bundle. + R"(create_bundle: [ios/macOS] Build an iOS or macOS bundle. - This target generates an iOS/OS X bundle (which is a directory with a + This target generates an iOS or macOS bundle (which is a directory with a well-know structure). This target does not define any sources, instead they are computed from all "bundle_data" target this one depends on transitively (the recursion stops at "create_bundle" targets). @@ -331,8 +331,8 @@ expansion of {{bundle_*_dir}} rules in "bundle_data" outputs. This target can be used on all platforms though it is designed only to - generate iOS/OS X bundle. In cross-platform projects, it is advised to put it - behind iOS/Mac conditionals. + generate iOS or macOS bundle. In cross-platform projects, it is advised to put + it behind iOS/macOS conditionals. If a create_bundle is specified as a data_deps for another target, the bundle is considered a leaf, and its public and private dependencies will not @@ -368,7 +368,7 @@ Example # Defines a template to create an application. On most platform, this is just - # an alias for an "executable" target, but on iOS/OS X, it builds an + # an alias for an "executable" target, but on iOS/macOS, it builds an # application bundle. template("app") { if (!is_ios && !is_mac) { @@ -656,10 +656,9 @@ // source_set ------------------------------------------------------------------ -extern const char kSourceSet[] = "source_set"; -extern const char kSourceSet_HelpShort[] = - "source_set: Declare a source set target."; -extern const char kSourceSet_Help[] = +const char kSourceSet[] = "source_set"; +const char kSourceSet_HelpShort[] = "source_set: Declare a source set target."; +const char kSourceSet_Help[] = R"(source_set: Declare a source set target. A source set is a collection of sources that get compiled, but are not linked @@ -685,11 +684,7 @@ Variables -)" - CONFIG_VALUES_VARS_HELP - DEPS_VARS - DEPENDENT_CONFIG_VARS - GENERAL_TARGET_VARS; +)" CONFIG_VALUES_VARS_HELP DEPS_VARS DEPENDENT_CONFIG_VARS GENERAL_TARGET_VARS; Value RunSourceSet(Scope* scope, const FunctionCallNode* function,
diff --git a/tools/gn/functions_target_unittest.cc b/tools/gn/functions_target_unittest.cc index cef75170..de701ef0 100644 --- a/tools/gn/functions_target_unittest.cc +++ b/tools/gn/functions_target_unittest.cc
@@ -5,12 +5,13 @@ #include "testing/gtest/include/gtest/gtest.h" #include "tools/gn/scheduler.h" #include "tools/gn/scope.h" +#include "tools/gn/test_with_scheduler.h" #include "tools/gn/test_with_scope.h" +using FunctionsTarget = TestWithScheduler; // Checks that we find unused identifiers in targets. -TEST(FunctionsTarget, CheckUnused) { - Scheduler scheduler; +TEST_F(FunctionsTarget, CheckUnused) { TestWithScope setup; // The target generator needs a place to put the targets or it will fail. @@ -38,8 +39,7 @@ } // Checks that we find uses of identifiers marked as not needed. -TEST(FunctionsTarget, CheckNotNeeded) { - Scheduler scheduler; +TEST_F(FunctionsTarget, CheckNotNeeded) { TestWithScope setup; // The target generator needs a place to put the targets or it will fail. @@ -93,8 +93,7 @@ // Checks that the defaults applied to a template invoked by target() use // the name of the template, rather than the string "target" (which is the // name of the actual function being called). -TEST(FunctionsTarget, TemplateDefaults) { - Scheduler scheduler; +TEST_F(FunctionsTarget, TemplateDefaults) { TestWithScope setup; // The target generator needs a place to put the targets or it will fail.
diff --git a/tools/gn/functions_unittest.cc b/tools/gn/functions_unittest.cc index 949b844..1ed509ae 100644 --- a/tools/gn/functions_unittest.cc +++ b/tools/gn/functions_unittest.cc
@@ -4,9 +4,9 @@ #include "tools/gn/functions.h" +#include <memory> #include <utility> -#include "base/memory/ptr_util.h" #include "testing/gtest/include/gtest/gtest.h" #include "tools/gn/parse_tree.h" #include "tools/gn/test_with_scope.h" @@ -22,7 +22,7 @@ Token undefined_token(Location(), Token::IDENTIFIER, "undef"); ListNode args_list_identifier_undefined; args_list_identifier_undefined.append_item( - std::unique_ptr<ParseNode>(new IdentifierNode(undefined_token))); + std::make_unique<IdentifierNode>(undefined_token)); Value result = functions::RunDefined(setup.scope(), &function_call, &args_list_identifier_undefined, &err); ASSERT_EQ(Value::BOOLEAN, result.type()); @@ -31,14 +31,13 @@ // Define a value that's itself a scope value. const char kDef[] = "def"; // Defined variable name. setup.scope()->SetValue( - kDef, Value(nullptr, std::unique_ptr<Scope>(new Scope(setup.scope()))), - nullptr); + kDef, Value(nullptr, std::make_unique<Scope>(setup.scope())), nullptr); // Test the defined identifier. Token defined_token(Location(), Token::IDENTIFIER, kDef); ListNode args_list_identifier_defined; args_list_identifier_defined.append_item( - std::unique_ptr<ParseNode>(new IdentifierNode(defined_token))); + std::make_unique<IdentifierNode>(defined_token)); result = functions::RunDefined(setup.scope(), &function_call, &args_list_identifier_defined, &err); ASSERT_EQ(Value::BOOLEAN, result.type()); @@ -46,9 +45,10 @@ // Should also work by passing an accessor node so you can do // "defined(def.foo)" to see if foo is defined on the def scope. - std::unique_ptr<AccessorNode> undef_accessor(new AccessorNode); + std::unique_ptr<AccessorNode> undef_accessor = + std::make_unique<AccessorNode>(); undef_accessor->set_base(defined_token); - undef_accessor->set_member(base::MakeUnique<IdentifierNode>(undefined_token)); + undef_accessor->set_member(std::make_unique<IdentifierNode>(undefined_token)); ListNode args_list_accessor_defined; args_list_accessor_defined.append_item(std::move(undef_accessor)); result = functions::RunDefined(setup.scope(), &function_call,
diff --git a/tools/gn/gn_main.cc b/tools/gn/gn_main.cc index 245270ee..4d51158 100644 --- a/tools/gn/gn_main.cc +++ b/tools/gn/gn_main.cc
@@ -2,9 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <algorithm> +#include <string> + #include "base/at_exit.h" #include "base/command_line.h" +#include "base/message_loop/message_loop.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" +#include "base/sys_info.h" +#include "base/task_scheduler/task_scheduler.h" #include "build/build_config.h" #include "tools/gn/commands.h" #include "tools/gn/err.h" @@ -34,6 +41,54 @@ #endif } +int GetThreadCount() { + std::string thread_count = + base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( + switches::kThreads); + + // See if an override was specified on the command line. + int result; + if (!thread_count.empty() && base::StringToInt(thread_count, &result) && + result >= 1) { + return result; + } + + // Base the default number of worker threads on number of cores in the + // system. When building large projects, the speed can be limited by how fast + // the main thread can dispatch work and connect the dependency graph. If + // there are too many worker threads, the main thread can be starved and it + // will run slower overall. + // + // One less worker thread than the number of physical CPUs seems to be a + // good value, both theoretically and experimentally. But always use at + // least some workers to prevent us from being too sensitive to I/O latency + // on low-end systems. + // + // The minimum thread count is based on measuring the optimal threads for the + // Chrome build on a several-year-old 4-core MacBook. + // Almost all CPUs now are hyperthreaded. + int num_cores = base::SysInfo::NumberOfProcessors() / 2; + return std::max(num_cores - 1, 8); +} + +void StartTaskScheduler() { + constexpr base::TimeDelta kSuggestedReclaimTime = + base::TimeDelta::FromSeconds(30); + + constexpr int kBackgroundMaxThreads = 1; + constexpr int kBackgroundBlockingMaxThreads = 2; + const int kForegroundMaxThreads = + std::max(1, base::SysInfo::NumberOfProcessors()); + const int foreground_blocking_max_threads = GetThreadCount(); + + base::TaskScheduler::Create("gn"); + base::TaskScheduler::GetInstance()->Start( + {{kBackgroundMaxThreads, kSuggestedReclaimTime}, + {kBackgroundBlockingMaxThreads, kSuggestedReclaimTime}, + {kForegroundMaxThreads, kSuggestedReclaimTime}, + {foreground_blocking_max_threads, kSuggestedReclaimTime}}); +} + } // namespace int main(int argc, char** argv) { @@ -71,7 +126,10 @@ int retval; if (found_command != command_map.end()) { + base::MessageLoop message_loop; + StartTaskScheduler(); retval = found_command->second.runner(args); + base::TaskScheduler::GetInstance()->Shutdown(); } else { Err(Location(), "Command \"" + command + "\" unknown.").PrintToStdout(); OutputString(
diff --git a/tools/gn/group_target_generator.cc b/tools/gn/group_target_generator.cc index 2c427f4..e546865 100644 --- a/tools/gn/group_target_generator.cc +++ b/tools/gn/group_target_generator.cc
@@ -15,8 +15,7 @@ : TargetGenerator(target, scope, function_call, err) { } -GroupTargetGenerator::~GroupTargetGenerator() { -} +GroupTargetGenerator::~GroupTargetGenerator() = default; void GroupTargetGenerator::DoRun() { target_->set_output_type(Target::GROUP);
diff --git a/tools/gn/header_checker.cc b/tools/gn/header_checker.cc index dd8dc0e..c47e6f1 100644 --- a/tools/gn/header_checker.cc +++ b/tools/gn/header_checker.cc
@@ -7,14 +7,15 @@ #include <algorithm> #include "base/bind.h" +#include "base/containers/queue.h" #include "base/files/file_util.h" -#include "base/message_loop/message_loop.h" #include "base/strings/string_util.h" -#include "base/threading/sequenced_worker_pool.h" +#include "base/task_scheduler/post_task.h" #include "tools/gn/build_settings.h" #include "tools/gn/builder.h" #include "tools/gn/c_include_iterator.h" #include "tools/gn/config.h" +#include "tools/gn/config_values_extractors.h" #include "tools/gn/err.h" #include "tools/gn/filesystem_utils.h" #include "tools/gn/scheduler.h" @@ -30,19 +31,6 @@ bool is_generated; }; -// If the given file is in the "gen" folder, trims this so it treats the gen -// directory as the source root: -// //out/Debug/gen/foo/bar.h -> //foo/bar.h -// If the file isn't in the generated root, returns the input unchanged. -SourceFile RemoveRootGenDirFromFile(const Target* target, - const SourceFile& file) { - const SourceDir& gen = target->settings()->toolchain_gen_dir(); - if (!gen.is_null() && base::StartsWith(file.value(), gen.value(), - base::CompareCase::SENSITIVE)) - return SourceFile("//" + file.value().substr(gen.value().size())); - return file; -} - // This class makes InputFiles on the stack as it reads files to check. When // we throw an error, the Err indicates a locatin which has a pointer to // an InputFile that must persist as long as the Err does. @@ -127,21 +115,23 @@ HeaderChecker::HeaderChecker(const BuildSettings* build_settings, const std::vector<const Target*>& targets) - : main_loop_(base::MessageLoop::current()), - build_settings_(build_settings) { + : build_settings_(build_settings), task_count_cv_(&lock_) { for (auto* target : targets) AddTargetToFileMap(target, &file_map_); } -HeaderChecker::~HeaderChecker() { -} +HeaderChecker::~HeaderChecker() = default; bool HeaderChecker::Run(const std::vector<const Target*>& to_check, bool force_check, std::vector<Err>* errors) { FileMap files_to_check; - for (auto* check : to_check) - AddTargetToFileMap(check, &files_to_check); + for (auto* check : to_check) { + // This function will get called with all target types, but check only + // applies to binary targets. + if (check->IsBinary()) + AddTargetToFileMap(check, &files_to_check); + } RunCheckOverFiles(files_to_check, force_check); if (errors_.empty()) @@ -151,11 +141,6 @@ } void HeaderChecker::RunCheckOverFiles(const FileMap& files, bool force_check) { - if (files.empty()) - return; - - scoped_refptr<base::SequencedWorkerPool> pool(new base::SequencedWorkerPool( - 16, "HeaderChecker", base::TaskPriority::USER_VISIBLE)); for (const auto& file : files) { // Only check C-like source files (RC files also have includes). SourceFileType type = GetSourceFileType(file.first); @@ -174,16 +159,18 @@ for (const auto& vect_i : file.second) { if (vect_i.target->check_includes()) { - pool->PostWorkerTaskWithShutdownBehavior( - FROM_HERE, - base::Bind(&HeaderChecker::DoWork, this, vect_i.target, file.first), - base::SequencedWorkerPool::BLOCK_SHUTDOWN); + task_count_.Increment(); + base::PostTaskWithTraits(FROM_HERE, {base::MayBlock()}, + base::BindOnce(&HeaderChecker::DoWork, this, + vect_i.target, file.first)); } } } - // After this call we're single-threaded again. - pool->Shutdown(); + // Wait for all tasks posted by this method to complete. + base::AutoLock auto_lock(lock_); + while (!task_count_.IsZero()) + task_count_cv_.Wait(); } void HeaderChecker::DoWork(const Target* target, const SourceFile& file) { @@ -192,6 +179,12 @@ base::AutoLock lock(lock_); errors_.push_back(err); } + + if (!task_count_.Decrement()) { + // Signal |task_count_cv_| when |task_count_| becomes zero. + base::AutoLock auto_lock(lock_); + task_count_cv_.Signal(); + } } // static @@ -201,14 +194,11 @@ std::map<SourceFile, PublicGeneratedPair> files_to_public; - // First collect the normal files, they get the default visibility. Always - // trim the root gen dir if it exists. This will only exist on outputs of an - // action, but those are often then wired into the sources of a compiled - // target to actually compile generated code. If you depend on the compiled - // target, it should be enough to be able to include the header. + // First collect the normal files, they get the default visibility. If you + // depend on the compiled target, it should be enough to be able to include + // the header. for (const auto& source : target->sources()) { - SourceFile file = RemoveRootGenDirFromFile(target, source); - files_to_public[file].is_public = default_public; + files_to_public[source].is_public = default_public; } // Add in the public files, forcing them to public. This may overwrite some @@ -216,8 +206,7 @@ if (default_public) // List only used when default is not public. DCHECK(target->public_headers().empty()); for (const auto& source : target->public_headers()) { - SourceFile file = RemoveRootGenDirFromFile(target, source); - files_to_public[file].is_public = true; + files_to_public[source].is_public = true; } // Add in outputs from actions. These are treated as public (since if other @@ -225,12 +214,7 @@ std::vector<SourceFile> outputs; target->action_values().GetOutputsAsSourceFiles(target, &outputs); for (const auto& output : outputs) { - // For generated files in the "gen" directory, add the filename to the - // map assuming "gen" is the source root. This means that when files include - // the generated header relative to there (the recommended practice), we'll - // find the file. - SourceFile output_file = RemoveRootGenDirFromFile(target, output); - PublicGeneratedPair* pair = &files_to_public[output_file]; + PublicGeneratedPair* pair = &files_to_public[output]; pair->is_public = true; pair->is_generated = true; } @@ -247,17 +231,27 @@ return file.value().compare(0, build_dir.size(), build_dir) == 0; } -// This current assumes all include paths are relative to the source root -// which is generally the case for Chromium. -// -// A future enhancement would be to search the include path for the target -// containing the source file containing this include and find the file to -// handle the cases where people do weird things with the paths. SourceFile HeaderChecker::SourceFileForInclude( - const base::StringPiece& input) const { - std::string str("//"); - input.AppendToString(&str); - return SourceFile(str); + const base::StringPiece& relative_file_path, + const std::vector<SourceDir>& include_dirs, + const InputFile& source_file, + const LocationRange& range, + Err* err) const { + using base::FilePath; + + Value relative_file_value(nullptr, relative_file_path.as_string()); + auto it = std::find_if( + include_dirs.begin(), include_dirs.end(), + [relative_file_value, err, this](const SourceDir& dir) -> bool { + SourceFile include_file = + dir.ResolveRelativeFile(relative_file_value, err); + return file_map_.find(include_file) != file_map_.end(); + }); + + if (it != include_dirs.end()) + return it->ResolveRelativeFile(relative_file_value, err); + + return SourceFile(); } bool HeaderChecker::CheckFile(const Target* from_target, @@ -285,13 +279,25 @@ InputFile input_file(file); input_file.SetContents(contents); + std::vector<SourceDir> include_dirs; + include_dirs.push_back(file.GetDir()); + for (ConfigValuesIterator iter(from_target); !iter.done(); iter.Next()) { + const std::vector<SourceDir>& target_include_dirs = + iter.cur().include_dirs(); + include_dirs.insert(include_dirs.end(), target_include_dirs.begin(), + target_include_dirs.end()); + } + CIncludeIterator iter(&input_file); base::StringPiece current_include; LocationRange range; while (iter.GetNextIncludeString(¤t_include, &range)) { - SourceFile include = SourceFileForInclude(current_include); - if (!CheckInclude(from_target, input_file, include, range, err)) - return false; + SourceFile include = SourceFileForInclude(current_include, include_dirs, + input_file, range, err); + if (!include.is_null()) { + if (!CheckInclude(from_target, input_file, include, range, err)) + return false; + } } return true; @@ -480,7 +486,7 @@ // search_for. std::map<const Target*, ChainLink> breadcrumbs; - std::queue<ChainLink> work_queue; + base::queue<ChainLink> work_queue; work_queue.push(ChainLink(search_from, true)); bool first_time = true; @@ -580,4 +586,3 @@ return Err(CreatePersistentRange(source_file, range), "Include not allowed.", msg); } -
diff --git a/tools/gn/header_checker.h b/tools/gn/header_checker.h index 0c0eb4a9..3645d7a 100644 --- a/tools/gn/header_checker.h +++ b/tools/gn/header_checker.h
@@ -6,16 +6,17 @@ #define TOOLS_GN_HEADER_CHECKER_H_ #include <map> -#include <set> #include <vector> +#include "base/atomic_ref_count.h" #include "base/gtest_prod_util.h" #include "base/macros.h" #include "base/memory/ref_counted.h" -#include "base/run_loop.h" #include "base/strings/string_piece.h" +#include "base/synchronization/condition_variable.h" #include "base/synchronization/lock.h" #include "tools/gn/err.h" +#include "tools/gn/source_dir.h" class BuildSettings; class InputFile; @@ -24,7 +25,7 @@ class Target; namespace base { -class MessageLoop; +class FilePath; } class HeaderChecker : public base::RefCountedThreadSafe<HeaderChecker> { @@ -67,6 +68,9 @@ FRIEND_TEST_ALL_PREFIXES(HeaderCheckerTest, CheckInclude); FRIEND_TEST_ALL_PREFIXES(HeaderCheckerTest, PublicFirst); FRIEND_TEST_ALL_PREFIXES(HeaderCheckerTest, CheckIncludeAllowCircular); + FRIEND_TEST_ALL_PREFIXES(HeaderCheckerTest, SourceFileForInclude); + FRIEND_TEST_ALL_PREFIXES(HeaderCheckerTest, + SourceFileForInclude_FileNotFound); ~HeaderChecker(); struct TargetInfo { @@ -88,6 +92,8 @@ typedef std::vector<TargetInfo> TargetVector; typedef std::map<SourceFile, TargetVector> FileMap; + typedef base::RepeatingCallback<bool(const base::FilePath& path)> + PathExistsCallback; // Backend for Run() that takes the list of files to check. The errors_ list // will be populate on failure. @@ -102,7 +108,11 @@ bool IsFileInOuputDir(const SourceFile& file) const; // Resolves the contents of an include to a SourceFile. - SourceFile SourceFileForInclude(const base::StringPiece& input) const; + SourceFile SourceFileForInclude(const base::StringPiece& relative_file_path, + const std::vector<SourceDir>& include_dirs, + const InputFile& source_file, + const LocationRange& range, + Err* err) const; // from_target is the target the file was defined from. It will be used in // error messages. @@ -160,14 +170,15 @@ // These are initialized during construction (which happens on one thread) // and are not modified after, so any thread can read these without locking. - base::MessageLoop* main_loop_; - base::RunLoop main_thread_runner_; - const BuildSettings* build_settings_; // Maps source files to targets it appears in (usually just one target). FileMap file_map_; + // Number of tasks posted by RunCheckOverFiles() that haven't completed their + // execution. + base::AtomicRefCount task_count_; + // Locked variables ---------------------------------------------------------- // // These are mutable during runtime and require locking. @@ -176,6 +187,9 @@ std::vector<Err> errors_; + // Signaled when |task_count_| becomes zero. + base::ConditionVariable task_count_cv_; + DISALLOW_COPY_AND_ASSIGN(HeaderChecker); };
diff --git a/tools/gn/header_checker_unittest.cc b/tools/gn/header_checker_unittest.cc index 84550b43..5bb5c70 100644 --- a/tools/gn/header_checker_unittest.cc +++ b/tools/gn/header_checker_unittest.cc
@@ -2,18 +2,21 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <ostream> #include <vector> +#include "base/bind.h" #include "testing/gtest/include/gtest/gtest.h" #include "tools/gn/config.h" #include "tools/gn/header_checker.h" #include "tools/gn/scheduler.h" #include "tools/gn/target.h" +#include "tools/gn/test_with_scheduler.h" #include "tools/gn/test_with_scope.h" namespace { -class HeaderCheckerTest : public testing::Test { +class HeaderCheckerTest : public TestWithScheduler { public: HeaderCheckerTest() : a_(setup_.settings(), Label(SourceDir("//a/"), "a")), @@ -52,8 +55,6 @@ } protected: - Scheduler scheduler_; - TestWithScope setup_; // Some headers that are automatically set up with a public dependency chain. @@ -68,6 +69,10 @@ } // namespace +void PrintTo(const SourceFile& source_file, ::std::ostream* os) { + *os << source_file.value(); +} + TEST_F(HeaderCheckerTest, IsDependencyOf) { scoped_refptr<HeaderChecker> checker( new HeaderChecker(setup_.build_settings(), targets_)); @@ -289,3 +294,57 @@ EXPECT_TRUE(checker->CheckInclude(&b_, input_file, a_public, range, &err)); EXPECT_FALSE(err.has_error()); } + +TEST_F(HeaderCheckerTest, SourceFileForInclude) { + using base::FilePath; + const std::vector<SourceDir> kIncludeDirs = { + SourceDir("/c/custom_include/"), SourceDir("//"), SourceDir("//subdir")}; + a_.sources().push_back(SourceFile("//lib/header1.h")); + b_.sources().push_back(SourceFile("/c/custom_include/header2.h")); + + InputFile dummy_input_file(SourceFile("//some_file.cc")); + dummy_input_file.SetContents(std::string()); + LocationRange dummy_range; + + scoped_refptr<HeaderChecker> checker( + new HeaderChecker(setup_.build_settings(), targets_)); + { + Err err; + SourceFile source_file = checker->SourceFileForInclude( + "lib/header1.h", kIncludeDirs, dummy_input_file, dummy_range, &err); + EXPECT_FALSE(err.has_error()); + EXPECT_EQ(SourceFile("//lib/header1.h"), source_file); + } + + { + Err err; + SourceFile source_file = checker->SourceFileForInclude( + "header2.h", kIncludeDirs, dummy_input_file, dummy_range, &err); + EXPECT_FALSE(err.has_error()); + EXPECT_EQ(SourceFile("/c/custom_include/header2.h"), source_file); + } +} + +TEST_F(HeaderCheckerTest, SourceFileForInclude_FileNotFound) { + using base::FilePath; + const char kFileContents[] = "Some dummy contents"; + const std::vector<SourceDir> kIncludeDirs = {SourceDir("//")}; + scoped_refptr<HeaderChecker> checker( + new HeaderChecker(setup_.build_settings(), targets_)); + + Err err; + InputFile input_file(SourceFile("//input.cc")); + input_file.SetContents(std::string(kFileContents)); + const int kLineNumber = 10; + const int kColumnNumber = 16; + const int kLength = 8; + const int kByteNumber = 100; + LocationRange range( + Location(&input_file, kLineNumber, kColumnNumber, kByteNumber), + Location(&input_file, kLineNumber, kColumnNumber + kLength, kByteNumber)); + + SourceFile source_file = checker->SourceFileForInclude( + "header.h", kIncludeDirs, input_file, range, &err); + EXPECT_TRUE(source_file.is_null()); + EXPECT_FALSE(err.has_error()); +}
diff --git a/tools/gn/import_manager.cc b/tools/gn/import_manager.cc index c9a44d4..405eb017 100644 --- a/tools/gn/import_manager.cc +++ b/tools/gn/import_manager.cc
@@ -4,6 +4,8 @@ #include "tools/gn/import_manager.h" +#include <memory> + #include "tools/gn/err.h" #include "tools/gn/parse_tree.h" #include "tools/gn/scheduler.h" @@ -24,7 +26,8 @@ if (!node) return nullptr; - std::unique_ptr<Scope> scope(new Scope(settings->base_config())); + std::unique_ptr<Scope> scope = + std::make_unique<Scope>(settings->base_config()); scope->set_source_dir(file.GetDir()); // Don't allow ScopePerFileProvider to provide target-related variables. @@ -48,8 +51,8 @@ } // namespace struct ImportManager::ImportInfo { - ImportInfo() {} - ~ImportInfo() {} + ImportInfo() = default; + ~ImportInfo() = default; // This lock protects the unique_ptr. Once the scope is computed, // it is const and can be accessed read-only outside of the lock. @@ -63,16 +66,18 @@ Err load_result; }; -ImportManager::ImportManager() { -} +ImportManager::ImportManager() = default; -ImportManager::~ImportManager() { -} +ImportManager::~ImportManager() = default; bool ImportManager::DoImport(const SourceFile& file, const ParseNode* node_for_err, Scope* scope, Err* err) { + // Key for the current import on the current thread in imports_in_progress_. + std::string key = + std::to_string(base::PlatformThread::CurrentId()) + file.value(); + // See if we have a cached import, but be careful to actually do the scope // copying outside of the lock. ImportInfo* import_info = nullptr; @@ -80,10 +85,16 @@ base::AutoLock lock(imports_lock_); std::unique_ptr<ImportInfo>& info_ptr = imports_[file]; if (!info_ptr) - info_ptr.reset(new ImportInfo); + info_ptr = std::make_unique<ImportInfo>(); // Promote the ImportInfo to outside of the imports lock. import_info = info_ptr.get(); + + if (imports_in_progress_.find(key) != imports_in_progress_.end()) { + *err = Err(Location(), file.value() + " is part of an import loop."); + return false; + } + imports_in_progress_.insert(key); } // Now use the per-import-file lock to block this thread if another thread @@ -127,6 +138,12 @@ Scope::MergeOptions options; options.skip_private_vars = true; options.mark_dest_used = true; // Don't require all imported values be used. + + { + base::AutoLock lock(imports_lock_); + imports_in_progress_.erase(key); + } + return import_scope->NonRecursiveMergeTo(scope, options, node_for_err, "import", err); }
diff --git a/tools/gn/import_manager.h b/tools/gn/import_manager.h index f371520..01d8af612 100644 --- a/tools/gn/import_manager.h +++ b/tools/gn/import_manager.h
@@ -7,6 +7,7 @@ #include <map> #include <memory> +#include <unordered_set> #include <vector> #include "base/macros.h" @@ -36,13 +37,16 @@ private: struct ImportInfo; - // Protects access to imports_. Do not hold when actually executing imports. + // Protects access to imports_ and imports_in_progress_. Do not hold when + // actually executing imports. base::Lock imports_lock_; // Owning pointers to the scopes. typedef std::map<SourceFile, std::unique_ptr<ImportInfo>> ImportMap; ImportMap imports_; + std::unordered_set<std::string> imports_in_progress_; + DISALLOW_COPY_AND_ASSIGN(ImportManager); };
diff --git a/tools/gn/inherited_libraries.cc b/tools/gn/inherited_libraries.cc index 06ac9ae..62c4150d5f 100644 --- a/tools/gn/inherited_libraries.cc +++ b/tools/gn/inherited_libraries.cc
@@ -6,11 +6,9 @@ #include "tools/gn/target.h" -InheritedLibraries::InheritedLibraries() { -} +InheritedLibraries::InheritedLibraries() = default; -InheritedLibraries::~InheritedLibraries() { -} +InheritedLibraries::~InheritedLibraries() = default; std::vector<const Target*> InheritedLibraries::GetOrdered() const { std::vector<const Target*> result;
diff --git a/tools/gn/input_conversion.cc b/tools/gn/input_conversion.cc index d452759..a7abcf4 100644 --- a/tools/gn/input_conversion.cc +++ b/tools/gn/input_conversion.cc
@@ -4,11 +4,14 @@ #include "tools/gn/input_conversion.h" +#include <memory> #include <utility> +#include "base/json/json_reader.h" #include "base/macros.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" +#include "base/values.h" #include "tools/gn/build_settings.h" #include "tools/gn/err.h" #include "tools/gn/input_file.h" @@ -74,7 +77,7 @@ if (!parse_root) return Value(); - std::unique_ptr<Scope> scope(new Scope(settings)); + std::unique_ptr<Scope> scope = std::make_unique<Scope>(settings); Value result = parse_root->Execute(scope.get(), err); if (err->has_error()) return Value(); @@ -105,6 +108,98 @@ return ret; } +bool IsIdentifier(const base::StringPiece& buffer) { + DCHECK(buffer.size() > 0); + if (!Tokenizer::IsIdentifierFirstChar(buffer[0])) + return false; + for (size_t i = 1; i < buffer.size(); i++) + if (!Tokenizer::IsIdentifierContinuingChar(buffer[i])) + return false; + return true; +} + +Value ParseJSONValue(const Settings* settings, + const base::Value& value, + const ParseNode* origin, + InputFile* input_file, + Err* err) { + switch (value.type()) { + case base::Value::Type::NONE: + *err = Err(origin, "Null values are not supported."); + return Value(); + case base::Value::Type::BOOLEAN: + return Value(origin, value.GetBool()); + case base::Value::Type::INTEGER: + return Value(origin, static_cast<int64_t>(value.GetInt())); + case base::Value::Type::DOUBLE: + *err = Err(origin, "Floating point values are not supported."); + return Value(); + case base::Value::Type::STRING: + return Value(origin, value.GetString()); + case base::Value::Type::BINARY: + *err = Err(origin, "Binary values are not supported."); + return Value(); + case base::Value::Type::DICTIONARY: { + std::unique_ptr<Scope> scope = std::make_unique<Scope>(settings); + for (const auto& it : value.DictItems()) { + Value value = + ParseJSONValue(settings, it.second, origin, input_file, err); + if (!IsIdentifier(it.first)) { + *err = Err(origin, "Invalid identifier \"" + it.first + "\"."); + return Value(); + } + // Search for the key in the input file. We know it's present because + // it was parsed by the JSON reader, but we need its location to + // construct a StringPiece that can be used as key in the Scope. + size_t off = input_file->contents().find("\"" + it.first + "\""); + if (off == std::string::npos) { + *err = Err(origin, "Invalid encoding \"" + it.first + "\"."); + return Value(); + } + base::StringPiece key(&input_file->contents()[off + 1], + it.first.size()); + scope->SetValue(key, std::move(value), origin); + } + return Value(origin, std::move(scope)); + } + case base::Value::Type::LIST: { + Value result(origin, Value::LIST); + result.list_value().reserve(value.GetList().size()); + for (const auto& val : value.GetList()) { + Value value = ParseJSONValue(settings, val, origin, input_file, err); + result.list_value().push_back(value); + } + return result; + } + } + return Value(); +} + +// Parses the JSON string and converts it to GN value. +Value ParseJSON(const Settings* settings, + const std::string& input, + const ParseNode* origin, + Err* err) { + InputFile* input_file; + std::vector<Token>* tokens; + std::unique_ptr<ParseNode>* parse_root_ptr; + g_scheduler->input_file_manager()->AddDynamicInput(SourceFile(), &input_file, + &tokens, &parse_root_ptr); + input_file->SetContents(input); + + int error_code_out; + std::string error_msg_out; + std::unique_ptr<base::Value> value = base::JSONReader::ReadAndReturnError( + input, base::JSONParserOptions::JSON_PARSE_RFC, &error_code_out, + &error_msg_out); + if (!value) { + *err = Err(origin, "Input is not a valid JSON: " + error_msg_out); + return Value(); + } + + return ParseJSONValue(settings, *value, origin, input_file, err); +} + // Backend for ConvertInputToValue, this takes the extracted string for the // input conversion so we can recursively call ourselves to handle the optional // "trim" prefix. This original value is also kept for the purposes of throwing @@ -138,6 +233,8 @@ return ParseList(input, origin, err); if (input_conversion == "scope") return ParseValueOrScope(settings, input, PARSE_SCOPE, origin, err); + if (input_conversion == "json") + return ParseJSON(settings, input, origin, err); *err = Err(original_input_conversion, "Not a valid input_conversion.", "Run gn help input_conversion to see your options."); @@ -146,7 +243,7 @@ } // namespace -extern const char kInputConversion_Help[] = +const char kInputConversion_Help[] = R"(input_conversion: Specifies how to transform input to a variable. input_conversion is an argument to read_file and exec_script that specifies @@ -188,6 +285,20 @@ Note that if the input is empty, the result will be a null value which will produce an error if assigned to a variable. + "json" + Parse the input as a JSON and convert it to equivalent GN rvalue. The data + type mapping is: + a string in JSON maps to string in GN + an integer in JSON maps to integer in GN + a float in JSON is unsupported and will result in an error + an object in JSON maps to scope in GN + an array in JSON maps to list in GN + a boolean in JSON maps to boolean in GN + a null in JSON is unsupported and will result in an error + + Nota that the dictionary keys have to be valid GN identifiers otherwise + they will produce an error. + "trim ..." Prefixing any of the other transformations with the word "trim" will result in whitespace being trimmed from the beginning and end of the
diff --git a/tools/gn/input_conversion_unittest.cc b/tools/gn/input_conversion_unittest.cc index c5209b06..dfc82c90 100644 --- a/tools/gn/input_conversion_unittest.cc +++ b/tools/gn/input_conversion_unittest.cc
@@ -2,28 +2,28 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "tools/gn/input_conversion.h" + #include "testing/gtest/include/gtest/gtest.h" #include "tools/gn/err.h" -#include "tools/gn/input_conversion.h" #include "tools/gn/input_file.h" #include "tools/gn/parse_tree.h" #include "tools/gn/scheduler.h" +#include "tools/gn/test_with_scheduler.h" #include "tools/gn/test_with_scope.h" #include "tools/gn/value.h" namespace { // InputConversion needs a global scheduler object. -class InputConversionTest : public testing::Test { +class InputConversionTest : public TestWithScheduler { public: - InputConversionTest() {} + InputConversionTest() = default; const Settings* settings() { return setup_.settings(); } private: TestWithScope setup_; - - Scheduler scheduler_; }; } // namespace @@ -132,6 +132,98 @@ EXPECT_EQ(input, a_file->contents()); } +TEST_F(InputConversionTest, ValueJSON) { + Err err; + std::string input(R"*({ + "a": 5, + "b": "foo", + "c": { + "d": true, + "e": [ + { + "f": "bar" + } + ] + } +})*"); + Value result = ConvertInputToValue(settings(), input, nullptr, + Value(nullptr, "json"), &err); + EXPECT_FALSE(err.has_error()); + ASSERT_EQ(Value::SCOPE, result.type()); + + const Value* a_value = result.scope_value()->GetValue("a"); + ASSERT_TRUE(a_value); + EXPECT_EQ(5, a_value->int_value()); + + const Value* b_value = result.scope_value()->GetValue("b"); + ASSERT_TRUE(b_value); + EXPECT_EQ("foo", b_value->string_value()); + + const Value* c_value = result.scope_value()->GetValue("c"); + ASSERT_TRUE(c_value); + ASSERT_EQ(Value::SCOPE, c_value->type()); + + const Value* d_value = c_value->scope_value()->GetValue("d"); + ASSERT_TRUE(d_value); + EXPECT_EQ(true, d_value->boolean_value()); + + const Value* e_value = c_value->scope_value()->GetValue("e"); + ASSERT_TRUE(e_value); + ASSERT_EQ(Value::LIST, e_value->type()); + + EXPECT_EQ(1u, e_value->list_value().size()); + ASSERT_EQ(Value::SCOPE, e_value->list_value()[0].type()); + const Value* f_value = e_value->list_value()[0].scope_value()->GetValue("f"); + ASSERT_TRUE(f_value); + EXPECT_EQ("bar", f_value->string_value()); +} + +TEST_F(InputConversionTest, ValueJSONInvalidInput) { + Err err; + std::string input(R"*({ + "a": 5, + "b": +})*"); + Value result = ConvertInputToValue(settings(), input, nullptr, + Value(nullptr, "json"), &err); + EXPECT_TRUE(err.has_error()); + EXPECT_EQ("Input is not a valid JSON: Line: 4, column: 2, Unexpected token.", + err.message()); +} + +TEST_F(InputConversionTest, ValueJSONUnsupportedValue) { + Err err; + std::string input(R"*({ + "a": null +})*"); + Value result = ConvertInputToValue(settings(), input, nullptr, + Value(nullptr, "json"), &err); + EXPECT_TRUE(err.has_error()); + EXPECT_EQ("Null values are not supported.", err.message()); +} + +TEST_F(InputConversionTest, ValueJSONInvalidVariable) { + Err err; + std::string input(R"*({ + "a\\x0001b": 5 +})*"); + Value result = ConvertInputToValue(settings(), input, nullptr, + Value(nullptr, "json"), &err); + EXPECT_TRUE(err.has_error()); + EXPECT_EQ("Invalid identifier \"a\\x0001b\".", err.message()); +} + +TEST_F(InputConversionTest, ValueJSONUnsupported) { + Err err; + std::string input(R"*({ + "d": 0.0 +})*"); + Value result = ConvertInputToValue(settings(), input, nullptr, + Value(nullptr, "json"), &err); + EXPECT_TRUE(err.has_error()); + EXPECT_EQ("Floating point values are not supported.", err.message()); +} + TEST_F(InputConversionTest, ValueEmpty) { Err err; Value result = ConvertInputToValue(settings(), "", nullptr,
diff --git a/tools/gn/input_file.cc b/tools/gn/input_file.cc index 74e419d..4d310e8 100644 --- a/tools/gn/input_file.cc +++ b/tools/gn/input_file.cc
@@ -12,8 +12,7 @@ contents_loaded_(false) { } -InputFile::~InputFile() { -} +InputFile::~InputFile() = default; void InputFile::SetContents(const std::string& c) { contents_loaded_ = true;
diff --git a/tools/gn/input_file_manager.cc b/tools/gn/input_file_manager.cc index 9fd3def..6fe3cae8 100644 --- a/tools/gn/input_file_manager.cc +++ b/tools/gn/input_file_manager.cc
@@ -4,6 +4,7 @@ #include "tools/gn/input_file_manager.h" +#include <memory> #include <utility> #include "base/bind.h" @@ -86,11 +87,9 @@ sync_invocation(false) { } -InputFileManager::InputFileData::~InputFileData() { -} +InputFileManager::InputFileData::~InputFileData() = default; -InputFileManager::InputFileManager() { -} +InputFileManager::InputFileManager() = default; InputFileManager::~InputFileManager() { // Should be single-threaded by now. @@ -111,7 +110,8 @@ InputFileMap::const_iterator found = input_files_.find(file_name); if (found == input_files_.end()) { // New file, schedule load. - std::unique_ptr<InputFileData> data(new InputFileData(file_name)); + std::unique_ptr<InputFileData> data = + std::make_unique<InputFileData>(file_name); data->scheduled_callbacks.push_back(callback); schedule_this = base::Bind(&InputFileManager::BackgroundLoadFile, this, @@ -162,7 +162,8 @@ InputFileMap::iterator found = input_files_.find(file_name); if (found == input_files_.end()) { // Haven't seen this file yet, start loading right now. - std::unique_ptr<InputFileData> new_data(new InputFileData(file_name)); + std::unique_ptr<InputFileData> new_data = + std::make_unique<InputFileData>(file_name); data = new_data.get(); data->sync_invocation = true; input_files_[file_name] = std::move(new_data); @@ -202,9 +203,9 @@ if (!data->loaded) { // Wait for the already-pending sync load to complete. if (!data->completion_event) { - data->completion_event.reset(new base::WaitableEvent( + data->completion_event = std::make_unique<base::WaitableEvent>( base::WaitableEvent::ResetPolicy::AUTOMATIC, - base::WaitableEvent::InitialState::NOT_SIGNALED)); + base::WaitableEvent::InitialState::NOT_SIGNALED); } { base::AutoUnlock unlock(lock_); @@ -230,7 +231,7 @@ InputFile** file, std::vector<Token>** tokens, std::unique_ptr<ParseNode>** parse_root) { - std::unique_ptr<InputFileData> data(new InputFileData(name)); + std::unique_ptr<InputFileData> data = std::make_unique<InputFileData>(name); *file = &data->file; *tokens = &data->tokens; *parse_root = &data->parsed_root;
diff --git a/tools/gn/item.cc b/tools/gn/item.cc index adf770a..f36ff02 100644 --- a/tools/gn/item.cc +++ b/tools/gn/item.cc
@@ -7,11 +7,15 @@ #include "base/logging.h" #include "tools/gn/settings.h" -Item::Item(const Settings* settings, const Label& label) - : settings_(settings), label_(label), defined_from_(nullptr) {} +Item::Item(const Settings* settings, + const Label& label, + const std::set<SourceFile>& build_dependency_files) + : settings_(settings), + label_(label), + build_dependency_files_(build_dependency_files), + defined_from_(nullptr) {} -Item::~Item() { -} +Item::~Item() = default; Config* Item::AsConfig() { return nullptr;
diff --git a/tools/gn/item.h b/tools/gn/item.h index 3ec482a..f2e7c065 100644 --- a/tools/gn/item.h +++ b/tools/gn/item.h
@@ -5,15 +5,18 @@ #ifndef TOOLS_GN_ITEM_H_ #define TOOLS_GN_ITEM_H_ +#include <set> #include <string> #include "tools/gn/label.h" +#include "tools/gn/source_file.h" #include "tools/gn/visibility.h" class Config; class ParseNode; class Pool; class Settings; +class SourceFile; class Target; class Toolchain; @@ -21,7 +24,9 @@ // graph. class Item { public: - Item(const Settings* settings, const Label& label); + Item(const Settings* settings, + const Label& label, + const std::set<SourceFile>& build_dependency_files = {}); virtual ~Item(); const Settings* settings() const { return settings_; } @@ -50,6 +55,16 @@ // be used in logging and error messages. std::string GetItemTypeName() const; + // Returns the set of build files that may affect this item, please refer to + // Scope for how this is determined. + const std::set<SourceFile>& build_dependency_files() const { + return build_dependency_files_; + } + + std::set<SourceFile>& build_dependency_files() { + return build_dependency_files_; + } + // Called when this item is resolved, meaning it and all of its dependents // have no unresolved deps. Returns true on success. Sets the error and // returns false on failure. @@ -58,6 +73,7 @@ private: const Settings* settings_; Label label_; + std::set<SourceFile> build_dependency_files_; const ParseNode* defined_from_; Visibility visibility_;
diff --git a/tools/gn/json_project_writer.cc b/tools/gn/json_project_writer.cc index dfb3cdb..4f4b0e7 100644 --- a/tools/gn/json_project_writer.cc +++ b/tools/gn/json_project_writer.cc
@@ -5,10 +5,10 @@ #include "tools/gn/json_project_writer.h" #include <iostream> +#include <memory> #include "base/command_line.h" #include "base/json/json_writer.h" -#include "base/memory/ptr_util.h" #include "base/strings/string_number_conversions.h" #include "tools/gn/builder.h" #include "tools/gn/commands.h" @@ -86,7 +86,7 @@ std::vector<const Target*>& all_targets) { Label default_toolchain_label; - auto targets = base::MakeUnique<base::DictionaryValue>(); + auto targets = std::make_unique<base::DictionaryValue>(); for (const auto* target : all_targets) { if (default_toolchain_label.is_null()) default_toolchain_label = target->settings()->default_toolchain_label(); @@ -105,7 +105,7 @@ std::move(description)); } - auto settings = base::MakeUnique<base::DictionaryValue>(); + auto settings = std::make_unique<base::DictionaryValue>(); settings->SetKey("root_path", base::Value(build_settings->root_path_utf8())); settings->SetKey("build_dir", base::Value(build_settings->build_dir().value())); @@ -113,7 +113,7 @@ "default_toolchain", base::Value(default_toolchain_label.GetUserVisibleName(false))); - auto output = base::MakeUnique<base::DictionaryValue>(); + auto output = std::make_unique<base::DictionaryValue>(); output->SetWithoutPathExpansion("targets", std::move(targets)); output->SetWithoutPathExpansion("build_settings", std::move(settings));
diff --git a/tools/gn/label.cc b/tools/gn/label.cc index 967d146..26e452f 100644 --- a/tools/gn/label.cc +++ b/tools/gn/label.cc
@@ -248,8 +248,7 @@ //tools/gn -> //tools/gn:gn )*"; -Label::Label() { -} +Label::Label() = default; Label::Label(const SourceDir& dir, const base::StringPiece& name, @@ -268,8 +267,7 @@ Label::Label(const Label& other) = default; -Label::~Label() { -} +Label::~Label() = default; // static Label Label::Resolve(const SourceDir& current_dir,
diff --git a/tools/gn/label_pattern.cc b/tools/gn/label_pattern.cc index 5b8bf80f..c4e9bb6 100644 --- a/tools/gn/label_pattern.cc +++ b/tools/gn/label_pattern.cc
@@ -63,8 +63,7 @@ LabelPattern::LabelPattern(const LabelPattern& other) = default; -LabelPattern::~LabelPattern() { -} +LabelPattern::~LabelPattern() = default; // static LabelPattern LabelPattern::GetPattern(const SourceDir& current_dir,
diff --git a/tools/gn/lib_file.cc b/tools/gn/lib_file.cc index 86eacb2..9c55aaa 100644 --- a/tools/gn/lib_file.cc +++ b/tools/gn/lib_file.cc
@@ -6,7 +6,7 @@ #include "base/logging.h" -LibFile::LibFile() {} +LibFile::LibFile() = default; LibFile::LibFile(const SourceFile& source_file) : source_file_(source_file) {}
diff --git a/tools/gn/loader.cc b/tools/gn/loader.cc index ba214c2..2e10c9a 100644 --- a/tools/gn/loader.cc +++ b/tools/gn/loader.cc
@@ -4,8 +4,9 @@ #include "tools/gn/loader.h" +#include <memory> + #include "base/bind.h" -#include "base/memory/ptr_util.h" #include "base/threading/thread_task_runner_handle.h" #include "tools/gn/build_settings.h" #include "tools/gn/err.h" @@ -23,9 +24,7 @@ struct SourceFileAndOrigin { SourceFileAndOrigin(const SourceFile& f, const LocationRange& o) - : file(f), - origin(o) { - } + : file(f), origin(o) {} SourceFile file; LocationRange origin; @@ -36,11 +35,9 @@ // Identifies one time a file is loaded in a given toolchain so we don't load // it more than once. struct LoaderImpl::LoadID { - LoadID() {} + LoadID() = default; LoadID(const SourceFile& f, const Label& tc_name) - : file(f), - toolchain_name(tc_name) { - } + : file(f), toolchain_name(tc_name) {} bool operator<(const LoadID& other) const { if (file.value() == other.file.value()) @@ -60,9 +57,10 @@ ToolchainRecord(const BuildSettings* build_settings, const Label& toolchain_label, const Label& default_toolchain_label) - : settings(build_settings, - GetOutputSubdirName(toolchain_label, - toolchain_label == default_toolchain_label)), + : settings( + build_settings, + GetOutputSubdirName(toolchain_label, + toolchain_label == default_toolchain_label)), is_toolchain_loaded(false), is_config_loaded(false) { settings.set_default_toolchain_label(default_toolchain_label); @@ -81,11 +79,9 @@ const void* const Loader::kDefaultToolchainKey = &kDefaultToolchainKey; -Loader::Loader() { -} +Loader::Loader() = default; -Loader::~Loader() { -} +Loader::~Loader() = default; void Loader::Load(const Label& label, const LocationRange& origin) { Load(BuildFileForLabel(label), origin, label.GetToolchainLabel()); @@ -106,14 +102,14 @@ task_runner_ = base::ThreadTaskRunnerHandle::Get(); } -LoaderImpl::~LoaderImpl() { -} +LoaderImpl::~LoaderImpl() = default; void LoaderImpl::Load(const SourceFile& file, const LocationRange& origin, const Label& in_toolchain_name) { const Label& toolchain_name = in_toolchain_name.is_null() - ? default_toolchain_label_ : in_toolchain_name; + ? default_toolchain_label_ + : in_toolchain_name; LoadID load_id(file, toolchain_name); if (!invocations_.insert(load_id).second) return; // Already in set, so this file was already loaded or schedulerd. @@ -123,8 +119,8 @@ // should not specify a toolchain. DCHECK(toolchain_name.is_null()); - std::unique_ptr<ToolchainRecord> new_record( - new ToolchainRecord(build_settings_, Label(), Label())); + std::unique_ptr<ToolchainRecord> new_record = + std::make_unique<ToolchainRecord>(build_settings_, Label(), Label()); ToolchainRecord* record = new_record.get(); toolchain_records_[Label()] = std::move(new_record); @@ -149,8 +145,9 @@ DCHECK(!default_toolchain_label_.is_null()); // No reference to this toolchain found yet, make one. - std::unique_ptr<ToolchainRecord> new_record(new ToolchainRecord( - build_settings_, toolchain_name, default_toolchain_label_)); + std::unique_ptr<ToolchainRecord> new_record = + std::make_unique<ToolchainRecord>(build_settings_, toolchain_name, + default_toolchain_label_); record = new_record.get(); toolchain_records_[toolchain_name] = std::move(new_record); @@ -168,8 +165,9 @@ ToolchainRecord* record = toolchain_records_[toolchain->label()].get(); if (!record) { DCHECK(!default_toolchain_label_.is_null()); - std::unique_ptr<ToolchainRecord> new_record(new ToolchainRecord( - build_settings_, toolchain->label(), default_toolchain_label_)); + std::unique_ptr<ToolchainRecord> new_record = + std::make_unique<ToolchainRecord>(build_settings_, toolchain->label(), + default_toolchain_label_); record = new_record.get(); toolchain_records_[toolchain->label()] = std::move(new_record); } @@ -253,6 +251,7 @@ Scope our_scope(settings->base_config()); ScopePerFileProvider per_file_provider(&our_scope, true); our_scope.set_source_dir(file_name.GetDir()); + our_scope.AddBuildDependencyFile(file_name); // Targets, etc. generated as part of running this file will end up here. Scope::ItemVector collected_items; @@ -294,9 +293,11 @@ Scope* base_config = settings->base_config(); base_config->set_source_dir(SourceDir("//")); + base_config->AddBuildDependencyFile( + settings->build_settings()->build_config_file()); - settings->build_settings()->build_args().SetupRootScope( - base_config, toolchain_overrides); + settings->build_settings()->build_args().SetupRootScope(base_config, + toolchain_overrides); base_config->SetProcessingBuildConfig(); @@ -306,7 +307,7 @@ base_config->SetProperty(kDefaultToolchainKey, &default_toolchain_label); ScopedTrace trace(TraceItem::TRACE_FILE_EXECUTE, - settings->build_settings()->build_config_file().value()); + settings->build_settings()->build_config_file().value()); trace.SetToolchain(settings->toolchain_label()); Err err; @@ -327,7 +328,8 @@ // The default toolchain must have been set in the default build config // file. if (default_toolchain_label.is_null()) { - g_scheduler->FailWithError(Err(Location(), + g_scheduler->FailWithError(Err( + Location(), "The default build config file did not call set_default_toolchain()", "If you don't call this, I can't figure out what toolchain to use\n" "for all of this code.")); @@ -423,6 +425,5 @@ return g_scheduler->input_file_manager()->AsyncLoadFile( origin, build_settings, file_name, callback, err); } - return async_load_file_.Run( - origin, build_settings, file_name, callback, err); + return async_load_file_.Run(origin, build_settings, file_name, callback, err); }
diff --git a/tools/gn/loader_unittest.cc b/tools/gn/loader_unittest.cc index 20b8609..e42ee5b 100644 --- a/tools/gn/loader_unittest.cc +++ b/tools/gn/loader_unittest.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include <map> +#include <memory> #include <utility> #include <vector> @@ -15,16 +16,45 @@ #include "tools/gn/parse_tree.h" #include "tools/gn/parser.h" #include "tools/gn/scheduler.h" +#include "tools/gn/test_with_scheduler.h" #include "tools/gn/tokenizer.h" namespace { +bool ItemContainsBuildDependencyFile(const Item* item, + const SourceFile& source_file) { + const auto& build_dependency_files = item->build_dependency_files(); + return build_dependency_files.end() != + build_dependency_files.find(source_file); +} + +class MockBuilder { + public: + void OnItemDefined(std::unique_ptr<Item> item); + std::vector<const Item*> GetAllItems() const; + + private: + std::vector<std::unique_ptr<Item>> items_; +}; + +void MockBuilder::OnItemDefined(std::unique_ptr<Item> item) { + items_.push_back(std::move(item)); +} + +std::vector<const Item*> MockBuilder::GetAllItems() const { + std::vector<const Item*> result; + for (const auto& item : items_) { + result.push_back(item.get()); + } + + return result; +} + class MockInputFileManager { public: typedef base::Callback<void(const ParseNode*)> Callback; - MockInputFileManager() { - } + MockInputFileManager() = default; LoaderImpl::AsyncLoadFileCallback GetCallback(); @@ -68,8 +98,8 @@ // Sets a given response for a given source file. void MockInputFileManager::AddCannedResponse(const SourceFile& source_file, const std::string& source) { - std::unique_ptr<CannedResult> canned(new CannedResult); - canned->input_file.reset(new InputFile(source_file)); + std::unique_ptr<CannedResult> canned = std::make_unique<CannedResult>(); + canned->input_file = std::make_unique<InputFile>(source_file); canned->input_file->SetContents(source); // Tokenize. @@ -110,15 +140,15 @@ // LoaderTest ------------------------------------------------------------------ -class LoaderTest : public testing::Test { +class LoaderTest : public TestWithScheduler { public: LoaderTest() { build_settings_.SetBuildDir(SourceDir("//out/Debug/")); } protected: - Scheduler scheduler_; BuildSettings build_settings_; + MockBuilder mock_builder_; MockInputFileManager mock_ifm_; }; @@ -182,5 +212,53 @@ base::RunLoop().RunUntilIdle(); EXPECT_TRUE(mock_ifm_.HasTwoPending(second_file, third_file)); - EXPECT_FALSE(scheduler_.is_failed()); + EXPECT_FALSE(scheduler().is_failed()); +} + +TEST_F(LoaderTest, BuildDependencyFilesAreCollected) { + SourceFile build_config("//build/config/BUILDCONFIG.gn"); + SourceFile root_build("//BUILD.gn"); + build_settings_.set_build_config_file(build_config); + build_settings_.set_item_defined_callback(base::Bind( + &MockBuilder::OnItemDefined, base::Unretained(&mock_builder_))); + + scoped_refptr<LoaderImpl> loader(new LoaderImpl(&build_settings_)); + mock_ifm_.AddCannedResponse(build_config, + "set_default_toolchain(\"//tc:tc\")"); + mock_ifm_.AddCannedResponse(SourceFile("//test.gni"), "concurrent_jobs = 1"); + std::string root_build_content = + "executable(\"a\") { sources = [ \"a.cc\" ] }\n" + "config(\"b\") { configs = [\"//t:t\"] }\n" + "toolchain(\"c\") {}\n" + "pool(\"d\") { depth = 1 }"; + mock_ifm_.AddCannedResponse(root_build, root_build_content); + + loader->set_async_load_file(mock_ifm_.GetCallback()); + + // Request the root build file be loaded. This should kick off the default + // build config loading. + loader->Load(root_build, LocationRange(), Label()); + EXPECT_TRUE(mock_ifm_.HasOnePending(build_config)); + + // Completing the build config load should kick off the root build file load. + mock_ifm_.IssueAllPending(); + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(mock_ifm_.HasOnePending(root_build)); + + // Completing the root build file should define a target which must have + // set of source files hashes. + mock_ifm_.IssueAllPending(); + base::RunLoop().RunUntilIdle(); + + std::vector<const Item*> items = mock_builder_.GetAllItems(); + EXPECT_TRUE(items[0]->AsTarget()); + EXPECT_TRUE(ItemContainsBuildDependencyFile(items[0], root_build)); + EXPECT_TRUE(items[1]->AsConfig()); + EXPECT_TRUE(ItemContainsBuildDependencyFile(items[1], root_build)); + EXPECT_TRUE(items[2]->AsToolchain()); + EXPECT_TRUE(ItemContainsBuildDependencyFile(items[2], root_build)); + EXPECT_TRUE(items[3]->AsPool()); + EXPECT_TRUE(ItemContainsBuildDependencyFile(items[3], root_build)); + + EXPECT_FALSE(scheduler().is_failed()); }
diff --git a/tools/gn/location.cc b/tools/gn/location.cc index 49ca3ff..f3c2d9186 100644 --- a/tools/gn/location.cc +++ b/tools/gn/location.cc
@@ -61,8 +61,7 @@ return ret; } -LocationRange::LocationRange() { -} +LocationRange::LocationRange() = default; LocationRange::LocationRange(const Location& begin, const Location& end) : begin_(begin),
diff --git a/tools/gn/misc/vim/README.chromium b/tools/gn/misc/vim/README.chromium index 0783496..7b73cfc 100644 --- a/tools/gn/misc/vim/README.chromium +++ b/tools/gn/misc/vim/README.chromium
@@ -1,5 +1,5 @@ You can use this by adding - set runtimepath^=.../tools/gn/misc/vim + set runtimepath+=/path/to/src/tools/gn/misc/vim to your .vimrc.
diff --git a/tools/gn/ninja_action_target_writer.cc b/tools/gn/ninja_action_target_writer.cc index 74270a0..263cf23 100644 --- a/tools/gn/ninja_action_target_writer.cc +++ b/tools/gn/ninja_action_target_writer.cc
@@ -24,8 +24,7 @@ ESCAPE_NONE) { } -NinjaActionTargetWriter::~NinjaActionTargetWriter() { -} +NinjaActionTargetWriter::~NinjaActionTargetWriter() = default; void NinjaActionTargetWriter::Run() { std::string custom_rule_name = WriteRuleDefinition(); @@ -39,13 +38,13 @@ for (const auto& pair : target_->GetDeps(Target::DEPS_LINKED)) extra_hard_deps.push_back(pair.ptr); - // For ACTIONs this is a bit inefficient since it creates an input dep - // stamp file even though we're only going to use it once. It would save a - // build step to skip this and write the order-only deps directly on the - // build rule. This should probably be handled by WriteInputDepsStampAndGetDep - // automatically if we supply a count of sources (so it can optimize based on - // how many times things would be duplicated). - OutputFile input_dep = WriteInputDepsStampAndGetDep(extra_hard_deps); + // For ACTIONs, the input deps appear only once in the generated ninja + // file, so WriteInputDepsStampAndGetDep() won't create a stamp file + // and the action will just depend on all the input deps directly. + size_t num_stamp_uses = + target_->output_type() == Target::ACTION ? 1u : target_->sources().size(); + std::vector<OutputFile> input_deps = + WriteInputDepsStampAndGetDep(extra_hard_deps, num_stamp_uses); out_ << std::endl; // Collects all output files for writing below. @@ -53,7 +52,7 @@ if (target_->output_type() == Target::ACTION_FOREACH) { // Write separate build lines for each input source file. - WriteSourceRules(custom_rule_name, input_dep, &output_files); + WriteSourceRules(custom_rule_name, input_deps, &output_files); } else { DCHECK(target_->output_type() == Target::ACTION); @@ -65,11 +64,11 @@ path_output_.WriteFiles(out_, output_files); out_ << ": " << custom_rule_name; - if (!input_dep.value().empty()) { + if (!input_deps.empty()) { // As in WriteSourceRules, we want to force this target to rebuild any // time any of its dependencies change. - out_ << " | "; - path_output_.WriteFile(out_, input_dep); + out_ << " |"; + path_output_.WriteFiles(out_, input_deps); } out_ << std::endl; if (target_->action_values().has_depfile()) { @@ -89,6 +88,8 @@ // Write the stamp, which also depends on all data deps. These are needed at // runtime and should be compiled when the action is, but don't need to be // done before we run the action. + // TODO(thakis): If the action has just a single output, make things depend + // on that output directly without writing a stamp file. std::vector<OutputFile> data_outs; for (const auto& dep : target_->data_deps()) data_outs.push_back(dep.ptr->dependency_output_file()); @@ -159,7 +160,7 @@ void NinjaActionTargetWriter::WriteSourceRules( const std::string& custom_rule_name, - const OutputFile& input_dep, + const std::vector<OutputFile>& input_deps, std::vector<OutputFile>* output_files) { EscapeOptions args_escape_options; args_escape_options.mode = ESCAPE_NINJA_COMMAND; @@ -174,13 +175,13 @@ out_ << ": " << custom_rule_name << " "; path_output_.WriteFile(out_, sources[i]); - if (!input_dep.value().empty()) { + if (!input_deps.empty()) { // Using "|" for the dependencies forces all implicit dependencies to be // fully up to date before running the action, and will re-run this // action if any input dependencies change. This is important because // this action may consume the outputs of previous steps. - out_ << " | "; - path_output_.WriteFile(out_, input_dep); + out_ << " |"; + path_output_.WriteFiles(out_, input_deps); } out_ << std::endl; @@ -207,6 +208,12 @@ WriteDepfile(sources[i]); out_ << std::endl; } + if (target_->action_values().pool().ptr) { + out_ << " pool = "; + out_ << target_->action_values().pool().ptr->GetNinjaName( + settings_->default_toolchain_label()); + out_ << std::endl; + } } }
diff --git a/tools/gn/ninja_action_target_writer.h b/tools/gn/ninja_action_target_writer.h index 71c12397..d0010f9 100644 --- a/tools/gn/ninja_action_target_writer.h +++ b/tools/gn/ninja_action_target_writer.h
@@ -39,10 +39,9 @@ // Writes the rules for compiling each source, writing all output files // to the given vector. // - // input_dep is a file expressing the depencies common to all build steps. - // It will be a stamp file if there is more than one. + // input_deps are the dependencies common to all build steps. void WriteSourceRules(const std::string& custom_rule_name, - const OutputFile& input_dep, + const std::vector<OutputFile>& input_deps, std::vector<OutputFile>* output_files); // Writes the output files generated by the output template for the given
diff --git a/tools/gn/ninja_action_target_writer_unittest.cc b/tools/gn/ninja_action_target_writer_unittest.cc index e73f0ab0..53f96c3 100644 --- a/tools/gn/ninja_action_target_writer_unittest.cc +++ b/tools/gn/ninja_action_target_writer_unittest.cc
@@ -45,7 +45,7 @@ target.set_output_type(Target::ACTION); target.action_values().set_script(SourceFile("//foo/script.py")); - target.inputs().push_back(SourceFile("//foo/included.txt")); + target.config_values().inputs().push_back(SourceFile("//foo/included.txt")); target.action_values().outputs() = SubstitutionList::MakeForTest("//out/Debug/foo.out"); @@ -60,17 +60,16 @@ NinjaActionTargetWriter writer(&target, out); writer.Run(); - const char expected[] = - "rule __foo_bar___rule\n" - " command = /usr/bin/python ../../foo/script.py\n" - " description = ACTION //foo:bar()\n" - " restat = 1\n" - "build obj/foo/bar.inputdeps.stamp: stamp ../../foo/script.py " - "../../foo/included.txt\n" - "\n" - "build foo.out: __foo_bar___rule | obj/foo/bar.inputdeps.stamp\n" - "\n" - "build obj/foo/bar.stamp: stamp foo.out\n"; + const char* expected = 1 /* skip initial newline */ + R"( +rule __foo_bar___rule + command = /usr/bin/python ../../foo/script.py + description = ACTION //foo:bar() + restat = 1 + +build foo.out: __foo_bar___rule | ../../foo/script.py ../../foo/included.txt + +build obj/foo/bar.stamp: stamp foo.out +)"; EXPECT_EQ(expected, out.str()); } @@ -84,7 +83,7 @@ target.set_output_type(Target::ACTION); target.action_values().set_script(SourceFile("//foo/script.py")); - target.inputs().push_back(SourceFile("//foo/included.txt")); + target.config_values().inputs().push_back(SourceFile("//foo/included.txt")); target.action_values().outputs() = SubstitutionList::MakeForTest("//out/Debug/foo.out"); @@ -105,18 +104,17 @@ NinjaActionTargetWriter writer(&target, out); writer.Run(); - const char expected[] = - "rule __foo_bar___rule\n" - " command = /usr/bin/python ../../foo/script.py\n" - " description = ACTION //foo:bar()\n" - " restat = 1\n" - "build obj/foo/bar.inputdeps.stamp: stamp ../../foo/script.py " - "../../foo/included.txt\n" - "\n" - "build foo.out: __foo_bar___rule | obj/foo/bar.inputdeps.stamp\n" - " pool = foo_pool\n" - "\n" - "build obj/foo/bar.stamp: stamp foo.out\n"; + const char* expected = 1 /* skip initial newline */ + R"( +rule __foo_bar___rule + command = /usr/bin/python ../../foo/script.py + description = ACTION //foo:bar() + restat = 1 + +build foo.out: __foo_bar___rule | ../../foo/script.py ../../foo/included.txt + pool = foo_pool + +build obj/foo/bar.stamp: stamp foo.out +)"; EXPECT_EQ(expected, out.str()); } @@ -132,7 +130,7 @@ target.action_values().set_script(SourceFile("//foo/script.py")); target.sources().push_back(SourceFile("//foo/source.txt")); - target.inputs().push_back(SourceFile("//foo/included.txt")); + target.config_values().inputs().push_back(SourceFile("//foo/included.txt")); target.action_values().outputs() = SubstitutionList::MakeForTest("//out/Debug/foo.out"); @@ -152,10 +150,9 @@ " command = /usr/bin/python ../../foo/script.py\n" " description = ACTION //foo:bar()\n" " restat = 1\n" - "build obj/foo/bar.inputdeps.stamp: stamp ../../foo/script.py " - "../../foo/included.txt ../../foo/source.txt\n" "\n" - "build foo.out: __foo_bar___rule | obj/foo/bar.inputdeps.stamp\n" + "build foo.out: __foo_bar___rule | ../../foo/script.py " + "../../foo/included.txt ../../foo/source.txt\n" "\n" "build obj/foo/bar.stamp: stamp foo.out\n"; EXPECT_EQ(expected_linux, out.str()); @@ -198,7 +195,7 @@ target.action_values().outputs() = SubstitutionList::MakeForTest( "//out/Debug/{{source_name_part}}.out"); - target.inputs().push_back(SourceFile("//foo/included.txt")); + target.config_values().inputs().push_back(SourceFile("//foo/included.txt")); target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); @@ -268,7 +265,7 @@ target.action_values().outputs() = SubstitutionList::MakeForTest( "//out/Debug/{{source_name_part}}.out"); - target.inputs().push_back(SourceFile("//foo/included.txt")); + target.config_values().inputs().push_back(SourceFile("//foo/included.txt")); setup.build_settings()->set_python_path(base::FilePath(FILE_PATH_LITERAL( "/usr/bin/python"))); @@ -359,3 +356,54 @@ "build obj/foo/bar.stamp: stamp input1.out\n"; EXPECT_EQ(expected_linux, out.str()); } + +TEST(NinjaActionTargetWriter, ForEachWithPool) { + Err err; + TestWithScope setup; + + Target target(setup.settings(), Label(SourceDir("//foo/"), "bar")); + target.set_output_type(Target::ACTION_FOREACH); + + target.sources().push_back(SourceFile("//foo/input1.txt")); + target.action_values().set_script(SourceFile("//foo/script.py")); + + Pool pool(setup.settings(), + Label(SourceDir("//foo/"), "pool", setup.toolchain()->label().dir(), + setup.toolchain()->label().name())); + pool.set_depth(5); + target.action_values().set_pool(LabelPtrPair<Pool>(&pool)); + + target.SetToolchain(setup.toolchain()); + ASSERT_TRUE(target.OnResolved(&err)); + + // Make sure we get interesting substitutions for both the args and the + // response file contents. + target.action_values().args() = + SubstitutionList::MakeForTest("{{source}}", "{{source_file_part}}"); + target.action_values().outputs() = + SubstitutionList::MakeForTest("//out/Debug/{{source_name_part}}.out"); + + setup.build_settings()->set_python_path( + base::FilePath(FILE_PATH_LITERAL("/usr/bin/python"))); + + std::ostringstream out; + NinjaActionTargetWriter writer(&target, out); + writer.Run(); + + const char expected_linux[] = + "rule __foo_bar___rule\n" + // These come from the args. + " command = /usr/bin/python ../../foo/script.py ${in} " + "${source_file_part}\n" + " description = ACTION //foo:bar()\n" + " restat = 1\n" + "\n" + "build input1.out: __foo_bar___rule ../../foo/input1.txt" + " | ../../foo/script.py\n" + // Substitution for the args. + " source_file_part = input1.txt\n" + " pool = foo_pool\n" + "\n" + "build obj/foo/bar.stamp: stamp input1.out\n"; + EXPECT_EQ(expected_linux, out.str()); +}
diff --git a/tools/gn/ninja_binary_target_writer.cc b/tools/gn/ninja_binary_target_writer.cc index 9772b85..0e2bab0f 100644 --- a/tools/gn/ninja_binary_target_writer.cc +++ b/tools/gn/ninja_binary_target_writer.cc
@@ -70,8 +70,7 @@ struct IncludeWriter { explicit IncludeWriter(PathOutput& path_output) : path_output_(path_output) { } - ~IncludeWriter() { - } + ~IncludeWriter() = default; void operator()(const SourceDir& d, std::ostream& out) const { std::ostringstream path_out; @@ -259,8 +258,7 @@ rule_prefix_(GetNinjaRulePrefixForToolchain(settings_)) { } -NinjaBinaryTargetWriter::~NinjaBinaryTargetWriter() { -} +NinjaBinaryTargetWriter::~NinjaBinaryTargetWriter() = default; void NinjaBinaryTargetWriter::Run() { // Figure out what source types are needed. @@ -295,16 +293,24 @@ // this case it's sufficient to ensure that the upstream dependencies are // built first. This is exactly what Ninja's order-only dependencies // expresses. - OutputFile order_only_dep = - WriteInputDepsStampAndGetDep(std::vector<const Target*>()); + // + // The order only deps are referenced by each source file compile, + // but also by PCH compiles. The latter are annoying to count, so omit + // them here. This means that binary targets with a single source file + // that also use PCH files won't have a stamp file even though having + // one would make output ninja file size a bit lower. That's ok, binary + // targets with a single source are rare. + size_t num_stamp_uses = target_->sources().size(); + std::vector<OutputFile> order_only_deps = WriteInputDepsStampAndGetDep( + std::vector<const Target*>(), num_stamp_uses); // For GCC builds, the .gch files are not object files, but still need to be // added as explicit dependencies below. The .gch output files are placed in // |pch_other_files|. This is to prevent linking against them. std::vector<OutputFile> pch_obj_files; std::vector<OutputFile> pch_other_files; - WritePCHCommands(used_types, input_dep, order_only_dep, - &pch_obj_files, &pch_other_files); + WritePCHCommands(used_types, input_dep, order_only_deps, &pch_obj_files, + &pch_other_files); std::vector<OutputFile>* pch_files = !pch_obj_files.empty() ? &pch_obj_files : &pch_other_files; @@ -322,7 +328,8 @@ // object file list. std::vector<OutputFile> obj_files; std::vector<SourceFile> other_files; - WriteSources(*pch_files, input_dep, order_only_dep, &obj_files, &other_files); + WriteSources(*pch_files, input_dep, order_only_deps, &obj_files, + &other_files); // Link all MSVC pch object files. The vector will be empty on GCC toolchains. obj_files.insert(obj_files.end(), pch_obj_files.begin(), pch_obj_files.end()); @@ -408,13 +415,20 @@ << "Toolchain not set on target " << target_->label().GetUserVisibleName(true); - if (target_->inputs().size() == 0) + std::vector<const SourceFile*> inputs; + for (ConfigValuesIterator iter(target_); !iter.done(); iter.Next()) { + for (const auto& input : iter.cur().inputs()) { + inputs.push_back(&input); + } + } + + if (inputs.size() == 0) return OutputFile(); // No inputs // If we only have one input, return it directly instead of writing a stamp // file for it. - if (target_->inputs().size() == 1) - return OutputFile(settings_->build_settings(), target_->inputs()[0]); + if (inputs.size() == 1) + return OutputFile(settings_->build_settings(), *inputs[0]); // Make a stamp file. OutputFile input_stamp_file = @@ -429,9 +443,9 @@ << Toolchain::ToolTypeToName(Toolchain::TYPE_STAMP); // File inputs. - for (const auto& input : target_->inputs()) { + for (const auto* input : inputs) { out_ << " "; - path_output_.WriteFile(out_, input); + path_output_.WriteFile(out_, *input); } out_ << "\n"; @@ -494,7 +508,7 @@ void NinjaBinaryTargetWriter::WritePCHCommands( const SourceFileTypeSet& used_types, const OutputFile& input_dep, - const OutputFile& order_only_dep, + const std::vector<OutputFile>& order_only_deps, std::vector<OutputFile>* object_files, std::vector<OutputFile>* other_files) { if (!target_->config_values().has_precompiled_headers()) @@ -504,29 +518,26 @@ if (tool_c && tool_c->precompiled_header_type() != Tool::PCH_NONE && used_types.Get(SOURCE_C)) { - WritePCHCommand(SUBSTITUTION_CFLAGS_C, - Toolchain::TYPE_CC, - tool_c->precompiled_header_type(), - input_dep, order_only_dep, object_files, other_files); + WritePCHCommand(SUBSTITUTION_CFLAGS_C, Toolchain::TYPE_CC, + tool_c->precompiled_header_type(), input_dep, + order_only_deps, object_files, other_files); } const Tool* tool_cxx = target_->toolchain()->GetTool(Toolchain::TYPE_CXX); if (tool_cxx && tool_cxx->precompiled_header_type() != Tool::PCH_NONE && used_types.Get(SOURCE_CPP)) { - WritePCHCommand(SUBSTITUTION_CFLAGS_CC, - Toolchain::TYPE_CXX, - tool_cxx->precompiled_header_type(), - input_dep, order_only_dep, object_files, other_files); + WritePCHCommand(SUBSTITUTION_CFLAGS_CC, Toolchain::TYPE_CXX, + tool_cxx->precompiled_header_type(), input_dep, + order_only_deps, object_files, other_files); } const Tool* tool_objc = target_->toolchain()->GetTool(Toolchain::TYPE_OBJC); if (tool_objc && tool_objc->precompiled_header_type() == Tool::PCH_GCC && used_types.Get(SOURCE_M)) { - WritePCHCommand(SUBSTITUTION_CFLAGS_OBJC, - Toolchain::TYPE_OBJC, - tool_objc->precompiled_header_type(), - input_dep, order_only_dep, object_files, other_files); + WritePCHCommand(SUBSTITUTION_CFLAGS_OBJC, Toolchain::TYPE_OBJC, + tool_objc->precompiled_header_type(), input_dep, + order_only_deps, object_files, other_files); } const Tool* tool_objcxx = @@ -534,10 +545,9 @@ if (tool_objcxx && tool_objcxx->precompiled_header_type() == Tool::PCH_GCC && used_types.Get(SOURCE_MM)) { - WritePCHCommand(SUBSTITUTION_CFLAGS_OBJCC, - Toolchain::TYPE_OBJCXX, - tool_objcxx->precompiled_header_type(), - input_dep, order_only_dep, object_files, other_files); + WritePCHCommand(SUBSTITUTION_CFLAGS_OBJCC, Toolchain::TYPE_OBJCXX, + tool_objcxx->precompiled_header_type(), input_dep, + order_only_deps, object_files, other_files); } } @@ -546,16 +556,16 @@ Toolchain::ToolType tool_type, Tool::PrecompiledHeaderType header_type, const OutputFile& input_dep, - const OutputFile& order_only_dep, + const std::vector<OutputFile>& order_only_deps, std::vector<OutputFile>* object_files, std::vector<OutputFile>* other_files) { switch (header_type) { case Tool::PCH_MSVC: - WriteWindowsPCHCommand(flag_type, tool_type, input_dep, order_only_dep, + WriteWindowsPCHCommand(flag_type, tool_type, input_dep, order_only_deps, object_files); break; case Tool::PCH_GCC: - WriteGCCPCHCommand(flag_type, tool_type, input_dep, order_only_dep, + WriteGCCPCHCommand(flag_type, tool_type, input_dep, order_only_deps, other_files); break; case Tool::PCH_NONE: @@ -568,7 +578,7 @@ SubstitutionType flag_type, Toolchain::ToolType tool_type, const OutputFile& input_dep, - const OutputFile& order_only_dep, + const std::vector<OutputFile>& order_only_deps, std::vector<OutputFile>* gch_files) { // Compute the pch output file (it will be language-specific). std::vector<OutputFile> outputs; @@ -584,7 +594,7 @@ // Build line to compile the file. WriteCompilerBuildLine(target_->config_values().precompiled_source(), - extra_deps, order_only_dep, tool_type, outputs); + extra_deps, order_only_deps, tool_type, outputs); // This build line needs a custom language-specific flags value. Rule-specific // variables are just indented underneath the rule line. @@ -620,7 +630,7 @@ SubstitutionType flag_type, Toolchain::ToolType tool_type, const OutputFile& input_dep, - const OutputFile& order_only_dep, + const std::vector<OutputFile>& order_only_deps, std::vector<OutputFile>* object_files) { // Compute the pch output file (it will be language-specific). std::vector<OutputFile> outputs; @@ -636,7 +646,7 @@ // Build line to compile the file. WriteCompilerBuildLine(target_->config_values().precompiled_source(), - extra_deps, order_only_dep, tool_type, outputs); + extra_deps, order_only_deps, tool_type, outputs); // This build line needs a custom language-specific flags value. Rule-specific // variables are just indented underneath the rule line. @@ -655,7 +665,7 @@ void NinjaBinaryTargetWriter::WriteSources( const std::vector<OutputFile>& pch_deps, const OutputFile& input_dep, - const OutputFile& order_only_dep, + const std::vector<OutputFile>& order_only_deps, std::vector<OutputFile>* object_files, std::vector<SourceFile>* other_files) { object_files->reserve(object_files->size() + target_->sources().size()); @@ -704,7 +714,7 @@ } } } - WriteCompilerBuildLine(source, deps, order_only_dep, tool_type, + WriteCompilerBuildLine(source, deps, order_only_deps, tool_type, tool_outputs); } @@ -718,7 +728,7 @@ void NinjaBinaryTargetWriter::WriteCompilerBuildLine( const SourceFile& source, const std::vector<OutputFile>& extra_deps, - const OutputFile& order_only_dep, + const std::vector<OutputFile>& order_only_deps, Toolchain::ToolType tool_type, const std::vector<OutputFile>& outputs) { out_ << "build"; @@ -730,15 +740,12 @@ if (!extra_deps.empty()) { out_ << " |"; - for (const OutputFile& dep : extra_deps) { - out_ << " "; - path_output_.WriteFile(out_, dep); - } + path_output_.WriteFiles(out_, extra_deps); } - if (!order_only_dep.value().empty()) { - out_ << " || "; - path_output_.WriteFile(out_, order_only_dep); + if (!order_only_deps.empty()) { + out_ << " ||"; + path_output_.WriteFiles(out_, order_only_deps); } out_ << std::endl; }
diff --git a/tools/gn/ninja_binary_target_writer.h b/tools/gn/ninja_binary_target_writer.h index 0188720..93e5b2d 100644 --- a/tools/gn/ninja_binary_target_writer.h +++ b/tools/gn/ninja_binary_target_writer.h
@@ -61,7 +61,7 @@ // compiling this target. It will be empty if there are no input deps. void WritePCHCommands(const SourceFileTypeSet& used_types, const OutputFile& input_dep, - const OutputFile& order_only_dep, + const std::vector<OutputFile>& order_only_deps, std::vector<OutputFile>* object_files, std::vector<OutputFile>* other_files); @@ -70,39 +70,39 @@ Toolchain::ToolType tool_type, Tool::PrecompiledHeaderType header_type, const OutputFile& input_dep, - const OutputFile& order_only_dep, + const std::vector<OutputFile>& order_only_deps, std::vector<OutputFile>* object_files, std::vector<OutputFile>* other_files); void WriteGCCPCHCommand(SubstitutionType flag_type, Toolchain::ToolType tool_type, const OutputFile& input_dep, - const OutputFile& order_only_dep, + const std::vector<OutputFile>& order_only_deps, std::vector<OutputFile>* gch_files); void WriteWindowsPCHCommand(SubstitutionType flag_type, Toolchain::ToolType tool_type, const OutputFile& input_dep, - const OutputFile& order_only_dep, + const std::vector<OutputFile>& order_only_deps, std::vector<OutputFile>* object_files); // pch_deps are additional dependencies to run before the rule. They are // expected to abide by the naming conventions specified by GetPCHOutputFiles. // - // order_only_dep is the name of the stamp file that covers the dependencies - // that must be run before doing any compiles. + // order_only_dep are the dependencies that must be run before doing any + // compiles. // // The files produced by the compiler will be added to two output vectors. void WriteSources(const std::vector<OutputFile>& pch_deps, const OutputFile& input_dep, - const OutputFile& order_only_dep, + const std::vector<OutputFile>& order_only_deps, std::vector<OutputFile>* object_files, std::vector<SourceFile>* other_files); // Writes a build line. void WriteCompilerBuildLine(const SourceFile& source, const std::vector<OutputFile>& extra_deps, - const OutputFile& order_only_dep, + const std::vector<OutputFile>& order_only_deps, Toolchain::ToolType tool_type, const std::vector<OutputFile>& outputs);
diff --git a/tools/gn/ninja_binary_target_writer_unittest.cc b/tools/gn/ninja_binary_target_writer_unittest.cc index fc0b3280..e801723 100644 --- a/tools/gn/ninja_binary_target_writer_unittest.cc +++ b/tools/gn/ninja_binary_target_writer_unittest.cc
@@ -4,15 +4,20 @@ #include "tools/gn/ninja_binary_target_writer.h" +#include <memory> #include <sstream> #include <utility> #include "testing/gtest/include/gtest/gtest.h" +#include "tools/gn/config.h" #include "tools/gn/scheduler.h" #include "tools/gn/target.h" +#include "tools/gn/test_with_scheduler.h" #include "tools/gn/test_with_scope.h" -TEST(NinjaBinaryTargetWriter, SourceSet) { +using NinjaBinaryTargetWriterTest = TestWithScheduler; + +TEST_F(NinjaBinaryTargetWriterTest, SourceSet) { Err err; TestWithScope setup; @@ -145,7 +150,7 @@ } } -TEST(NinjaBinaryTargetWriter, StaticLibrary) { +TEST_F(NinjaBinaryTargetWriterTest, StaticLibrary) { TestWithScope setup; Err err; @@ -177,7 +182,7 @@ EXPECT_EQ(expected, out_str); } -TEST(NinjaBinaryTargetWriter, CompleteStaticLibrary) { +TEST_F(NinjaBinaryTargetWriterTest, CompleteStaticLibrary) { TestWithScope setup; Err err; @@ -254,7 +259,7 @@ // This tests that output extension and output dir overrides apply, and input // dependencies are applied. -TEST(NinjaBinaryTargetWriter, OutputExtensionAndInputDeps) { +TEST_F(NinjaBinaryTargetWriterTest, OutputExtensionAndInputDeps) { Err err; TestWithScope setup; @@ -309,7 +314,7 @@ } // Tests libs are applied. -TEST(NinjaBinaryTargetWriter, LibsAndLibDirs) { +TEST_F(NinjaBinaryTargetWriterTest, LibsAndLibDirs) { Err err; TestWithScope setup; @@ -344,7 +349,7 @@ EXPECT_EQ(expected, out_str); } -TEST(NinjaBinaryTargetWriter, EmptyOutputExtension) { +TEST_F(NinjaBinaryTargetWriterTest, EmptyOutputExtension) { Err err; TestWithScope setup; @@ -388,7 +393,7 @@ EXPECT_EQ(expected, out_str); } -TEST(NinjaBinaryTargetWriter, SourceSetDataDeps) { +TEST_F(NinjaBinaryTargetWriterTest, SourceSetDataDeps) { Err err; TestWithScope setup; @@ -468,7 +473,7 @@ EXPECT_EQ(final_expected, final_out.str()); } -TEST(NinjaBinaryTargetWriter, SharedLibraryModuleDefinitionFile) { +TEST_F(NinjaBinaryTargetWriterTest, SharedLibraryModuleDefinitionFile) { Err err; TestWithScope setup; @@ -502,7 +507,7 @@ EXPECT_EQ(expected, out.str()); } -TEST(NinjaBinaryTargetWriter, LoadableModule) { +TEST_F(NinjaBinaryTargetWriterTest, LoadableModule) { Err err; TestWithScope setup; @@ -568,7 +573,7 @@ EXPECT_EQ(final_expected, final_out.str()); } -TEST(NinjaBinaryTargetWriter, WinPrecompiledHeaders) { +TEST_F(NinjaBinaryTargetWriterTest, WinPrecompiledHeaders) { Err err; // This setup's toolchain does not have precompiled headers defined. @@ -582,7 +587,7 @@ pch_settings.set_default_toolchain_label(setup.toolchain()->label()); // Declare a C++ compiler that supports PCH. - std::unique_ptr<Tool> cxx_tool(new Tool); + std::unique_ptr<Tool> cxx_tool = std::make_unique<Tool>(); TestWithScope::SetCommandForTool( "c++ {{source}} {{cflags}} {{cflags_cc}} {{defines}} {{include_dirs}} " "-o {{output}}", @@ -593,7 +598,7 @@ pch_toolchain.SetTool(Toolchain::TYPE_CXX, std::move(cxx_tool)); // Add a C compiler as well. - std::unique_ptr<Tool> cc_tool(new Tool); + std::unique_ptr<Tool> cc_tool = std::make_unique<Tool>(); TestWithScope::SetCommandForTool( "cc {{source}} {{cflags}} {{cflags_c}} {{defines}} {{include_dirs}} " "-o {{output}}", @@ -695,7 +700,7 @@ } } -TEST(NinjaBinaryTargetWriter, GCCPrecompiledHeaders) { +TEST_F(NinjaBinaryTargetWriterTest, GCCPrecompiledHeaders) { Err err; // This setup's toolchain does not have precompiled headers defined. @@ -709,7 +714,7 @@ pch_settings.set_default_toolchain_label(setup.toolchain()->label()); // Declare a C++ compiler that supports PCH. - std::unique_ptr<Tool> cxx_tool(new Tool); + std::unique_ptr<Tool> cxx_tool = std::make_unique<Tool>(); TestWithScope::SetCommandForTool( "c++ {{source}} {{cflags}} {{cflags_cc}} {{defines}} {{include_dirs}} " "-o {{output}}", @@ -721,7 +726,7 @@ pch_toolchain.ToolchainSetupComplete(); // Add a C compiler as well. - std::unique_ptr<Tool> cc_tool(new Tool); + std::unique_ptr<Tool> cc_tool = std::make_unique<Tool>(); TestWithScope::SetCommandForTool( "cc {{source}} {{cflags}} {{cflags_c}} {{defines}} {{include_dirs}} " "-o {{output}}", @@ -820,27 +825,25 @@ // Should throw an error with the scheduler if a duplicate object file exists. // This is dependent on the toolchain's object file mapping. -TEST(NinjaBinaryTargetWriter, DupeObjFileError) { - Scheduler scheduler; - +TEST_F(NinjaBinaryTargetWriterTest, DupeObjFileError) { TestWithScope setup; TestTarget target(setup, "//foo:bar", Target::EXECUTABLE); target.sources().push_back(SourceFile("//a.cc")); target.sources().push_back(SourceFile("//a.cc")); - EXPECT_FALSE(scheduler.is_failed()); + EXPECT_FALSE(scheduler().is_failed()); std::ostringstream out; NinjaBinaryTargetWriter writer(&target, out); writer.Run(); // Should have issued an error. - EXPECT_TRUE(scheduler.is_failed()); + EXPECT_TRUE(scheduler().is_failed()); } // This tests that output extension and output dir overrides apply, and input // dependencies are applied. -TEST(NinjaBinaryTargetWriter, InputFiles) { +TEST_F(NinjaBinaryTargetWriterTest, InputFiles) { Err err; TestWithScope setup; @@ -851,7 +854,7 @@ target.visibility().SetPublic(); target.sources().push_back(SourceFile("//foo/input1.cc")); target.sources().push_back(SourceFile("//foo/input2.cc")); - target.inputs().push_back(SourceFile("//foo/input.data")); + target.config_values().inputs().push_back(SourceFile("//foo/input.data")); target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); @@ -886,8 +889,8 @@ target.visibility().SetPublic(); target.sources().push_back(SourceFile("//foo/input1.cc")); target.sources().push_back(SourceFile("//foo/input2.cc")); - target.inputs().push_back(SourceFile("//foo/input1.data")); - target.inputs().push_back(SourceFile("//foo/input2.data")); + target.config_values().inputs().push_back(SourceFile("//foo/input1.data")); + target.config_values().inputs().push_back(SourceFile("//foo/input2.data")); target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); @@ -916,4 +919,52 @@ EXPECT_EQ(expected, out.str()); } + + // This target has one input itself, one from an immediate config, and one + // from a config tacked on to said config. + { + Config far_config(setup.settings(), Label(SourceDir("//foo/"), "qux")); + far_config.own_values().inputs().push_back(SourceFile("//foo/input3.data")); + ASSERT_TRUE(far_config.OnResolved(&err)); + + Config config(setup.settings(), Label(SourceDir("//foo/"), "baz")); + config.own_values().inputs().push_back(SourceFile("//foo/input2.data")); + config.configs().push_back(LabelConfigPair(&far_config)); + ASSERT_TRUE(config.OnResolved(&err)); + + Target target(setup.settings(), Label(SourceDir("//foo/"), "bar")); + target.set_output_type(Target::SOURCE_SET); + target.visibility().SetPublic(); + target.sources().push_back(SourceFile("//foo/input1.cc")); + target.sources().push_back(SourceFile("//foo/input2.cc")); + target.config_values().inputs().push_back(SourceFile("//foo/input1.data")); + target.configs().push_back(LabelConfigPair(&config)); + target.SetToolchain(setup.toolchain()); + ASSERT_TRUE(target.OnResolved(&err)); + + std::ostringstream out; + NinjaBinaryTargetWriter writer(&target, out); + writer.Run(); + + const char expected[] = + "defines =\n" + "include_dirs =\n" + "cflags =\n" + "cflags_cc =\n" + "root_out_dir = .\n" + "target_out_dir = obj/foo\n" + "target_output_name = bar\n" + "\n" + "build obj/foo/bar.inputs.stamp: stamp" + " ../../foo/input1.data ../../foo/input2.data ../../foo/input3.data\n" + "build obj/foo/bar.input1.o: cxx ../../foo/input1.cc" + " | obj/foo/bar.inputs.stamp\n" + "build obj/foo/bar.input2.o: cxx ../../foo/input2.cc" + " | obj/foo/bar.inputs.stamp\n" + "\n" + "build obj/foo/bar.stamp: stamp obj/foo/bar.input1.o " + "obj/foo/bar.input2.o\n"; + + EXPECT_EQ(expected, out.str()); + } }
diff --git a/tools/gn/ninja_build_writer.cc b/tools/gn/ninja_build_writer.cc index 857b668..334071a6 100644 --- a/tools/gn/ninja_build_writer.cc +++ b/tools/gn/ninja_build_writer.cc
@@ -48,10 +48,15 @@ }; std::string GetSelfInvocationCommand(const BuildSettings* build_settings) { - base::FilePath executable; - PathService::Get(base::FILE_EXE, &executable); + const base::FilePath build_path = + build_settings->build_dir().Resolve(build_settings->root_path()); - base::CommandLine cmdline(executable.NormalizePathSeparatorsTo('/')); + base::FilePath exe_path; + PathService::Get(base::FILE_EXE, &exe_path); + if (build_path.IsAbsolute()) + exe_path = MakeAbsoluteFilePathRelativeIfPossible(build_path, exe_path); + + base::CommandLine cmdline(exe_path.NormalizePathSeparatorsTo('/')); // Use "." for the directory to generate. When Ninja runs the command it // will have the build directory as the current one. Coding it explicitly @@ -59,8 +64,12 @@ cmdline.AppendArg("gen"); cmdline.AppendArg("."); + base::FilePath root_path = build_settings->root_path(); + if (build_path.IsAbsolute()) + root_path = MakeAbsoluteFilePathRelativeIfPossible(build_path, root_path); + cmdline.AppendSwitchPath(std::string("--") + switches::kRoot, - build_settings->root_path()); + root_path.NormalizePathSeparatorsTo('/')); // Successful automatic invocations shouldn't print output. cmdline.AppendSwitch(std::string("-") + switches::kQuiet); @@ -165,8 +174,7 @@ build_settings->root_path_utf8(), ESCAPE_NINJA) {} -NinjaBuildWriter::~NinjaBuildWriter() { -} +NinjaBuildWriter::~NinjaBuildWriter() = default; bool NinjaBuildWriter::Run(Err* err) { WriteNinjaRules(); @@ -268,8 +276,13 @@ std::set<base::FilePath> fileset(input_files.begin(), input_files.end()); fileset.insert(other_files.begin(), other_files.end()); - for (const auto& other_file : fileset) - dep_out_ << " " << FilePathToUTF8(other_file); + const base::FilePath build_path = + build_settings_->build_dir().Resolve(build_settings_->root_path()); + for (const auto& other_file : fileset) { + const base::FilePath file = + MakeAbsoluteFilePathRelativeIfPossible(build_path, other_file); + dep_out_ << " " << FilePathToUTF8(file.NormalizePathSeparatorsTo('/')); + } out_ << std::endl; }
diff --git a/tools/gn/ninja_build_writer_unittest.cc b/tools/gn/ninja_build_writer_unittest.cc index 6dac481b..1937135 100644 --- a/tools/gn/ninja_build_writer_unittest.cc +++ b/tools/gn/ninja_build_writer_unittest.cc
@@ -9,10 +9,12 @@ #include "tools/gn/pool.h" #include "tools/gn/scheduler.h" #include "tools/gn/target.h" +#include "tools/gn/test_with_scheduler.h" #include "tools/gn/test_with_scope.h" -TEST(NinjaBuildWriter, TwoTargets) { - Scheduler scheduler; +using NinjaBuildWriterTest = TestWithScheduler; + +TEST_F(NinjaBuildWriterTest, TwoTargets) { TestWithScope setup; Err err; @@ -95,8 +97,7 @@ #undef EXPECT_SNIPPET } -TEST(NinjaBuildWriter, DuplicateOutputs) { - Scheduler scheduler; +TEST_F(NinjaBuildWriterTest, DuplicateOutputs) { TestWithScope setup; Err err;
diff --git a/tools/gn/ninja_bundle_data_target_writer.cc b/tools/gn/ninja_bundle_data_target_writer.cc index 26bfefb..ec3cf74 100644 --- a/tools/gn/ninja_bundle_data_target_writer.cc +++ b/tools/gn/ninja_bundle_data_target_writer.cc
@@ -12,7 +12,7 @@ std::ostream& out) : NinjaTargetWriter(target, out) {} -NinjaBundleDataTargetWriter::~NinjaBundleDataTargetWriter() {} +NinjaBundleDataTargetWriter::~NinjaBundleDataTargetWriter() = default; void NinjaBundleDataTargetWriter::Run() { std::vector<OutputFile> output_files; @@ -21,10 +21,9 @@ OutputFile(settings_->build_settings(), source_file)); } - std::vector<const Target*> extra_hard_deps; - OutputFile input_dep = WriteInputDepsStampAndGetDep(extra_hard_deps); - if (!input_dep.value().empty()) - output_files.push_back(input_dep); + std::vector<OutputFile> input_deps = WriteInputDepsStampAndGetDep( + std::vector<const Target*>(), /*num_stamp_uses=*/1); + output_files.insert(output_files.end(), input_deps.begin(), input_deps.end()); std::vector<OutputFile> order_only_deps; for (const auto& pair : target_->data_deps())
diff --git a/tools/gn/ninja_copy_target_writer.cc b/tools/gn/ninja_copy_target_writer.cc index 9ffd0fc..194e2aa6 100644 --- a/tools/gn/ninja_copy_target_writer.cc +++ b/tools/gn/ninja_copy_target_writer.cc
@@ -19,8 +19,7 @@ : NinjaTargetWriter(target, out) { } -NinjaCopyTargetWriter::~NinjaCopyTargetWriter() { -} +NinjaCopyTargetWriter::~NinjaCopyTargetWriter() = default; void NinjaCopyTargetWriter::Run() { const Tool* copy_tool = target_->toolchain()->GetTool(Toolchain::TYPE_COPY); @@ -71,8 +70,9 @@ GetNinjaRulePrefixForToolchain(settings_) + Toolchain::ToolTypeToName(Toolchain::TYPE_COPY); - OutputFile input_dep = - WriteInputDepsStampAndGetDep(std::vector<const Target*>()); + size_t num_stamp_uses = target_->sources().size(); + std::vector<OutputFile> input_deps = WriteInputDepsStampAndGetDep( + std::vector<const Target*>(), num_stamp_uses); // Note that we don't write implicit deps for copy steps. "copy" only // depends on the output files themselves, rather than having includes @@ -110,9 +110,9 @@ path_output_.WriteFile(out_, output_file); out_ << ": " << tool_name << " "; path_output_.WriteFile(out_, input_file); - if (!input_dep.value().empty()) { - out_ << " || "; - path_output_.WriteFile(out_, input_dep); + if (!input_deps.empty()) { + out_ << " ||"; + path_output_.WriteFiles(out_, input_deps); } out_ << std::endl; }
diff --git a/tools/gn/ninja_copy_target_writer_unittest.cc b/tools/gn/ninja_copy_target_writer_unittest.cc index 44973a7..b00a644 100644 --- a/tools/gn/ninja_copy_target_writer_unittest.cc +++ b/tools/gn/ninja_copy_target_writer_unittest.cc
@@ -77,7 +77,7 @@ target.sources().push_back(SourceFile("//foo/input1.txt")); target.action_values().outputs() = SubstitutionList::MakeForTest("//out/Debug/{{source_name_part}}.out"); - target.inputs().push_back(SourceFile("//foo/script.py")); + target.config_values().inputs().push_back(SourceFile("//foo/script.py")); target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err));
diff --git a/tools/gn/ninja_create_bundle_target_writer.cc b/tools/gn/ninja_create_bundle_target_writer.cc index 038d526..873a1906 100644 --- a/tools/gn/ninja_create_bundle_target_writer.cc +++ b/tools/gn/ninja_create_bundle_target_writer.cc
@@ -49,7 +49,7 @@ std::ostream& out) : NinjaTargetWriter(target, out) {} -NinjaCreateBundleTargetWriter::~NinjaCreateBundleTargetWriter() {} +NinjaCreateBundleTargetWriter::~NinjaCreateBundleTargetWriter() = default; void NinjaCreateBundleTargetWriter::Run() { if (!EnsureAllToolsAvailable(target_))
diff --git a/tools/gn/ninja_group_target_writer.cc b/tools/gn/ninja_group_target_writer.cc index c298413e..baff95a 100644 --- a/tools/gn/ninja_group_target_writer.cc +++ b/tools/gn/ninja_group_target_writer.cc
@@ -15,8 +15,7 @@ : NinjaTargetWriter(target, out) { } -NinjaGroupTargetWriter::~NinjaGroupTargetWriter() { -} +NinjaGroupTargetWriter::~NinjaGroupTargetWriter() = default; void NinjaGroupTargetWriter::Run() { // A group rule just generates a stamp file with dependencies on each of
diff --git a/tools/gn/ninja_target_writer.cc b/tools/gn/ninja_target_writer.cc index 2b30d65..c8d1b84cb 100644 --- a/tools/gn/ninja_target_writer.cc +++ b/tools/gn/ninja_target_writer.cc
@@ -8,6 +8,7 @@ #include "base/files/file_util.h" #include "base/strings/string_util.h" +#include "tools/gn/config_values_extractors.h" #include "tools/gn/err.h" #include "tools/gn/escape.h" #include "tools/gn/filesystem_utils.h" @@ -35,8 +36,7 @@ ESCAPE_NINJA) { } -NinjaTargetWriter::~NinjaTargetWriter() { -} +NinjaTargetWriter::~NinjaTargetWriter() = default; // static std::string NinjaTargetWriter::RunAndWriteFile(const Target* target) { @@ -179,8 +179,9 @@ out_ << std::endl; } -OutputFile NinjaTargetWriter::WriteInputDepsStampAndGetDep( - const std::vector<const Target*>& extra_hard_deps) const { +std::vector<OutputFile> NinjaTargetWriter::WriteInputDepsStampAndGetDep( + const std::vector<const Target*>& extra_hard_deps, + size_t num_stamp_uses) const { CHECK(target_->toolchain()) << "Toolchain not set on target " << target_->label().GetUserVisibleName(true); @@ -201,8 +202,10 @@ // implicit dependency instead. The implicit depedency in this case is // handled separately by the binary target writer. if (!target_->IsBinary()) { - for (const auto& input : target_->inputs()) - input_deps_sources.push_back(&input); + for (ConfigValuesIterator iter(target_); !iter.done(); iter.Next()) { + for (const auto& input : iter.cur().inputs()) + input_deps_sources.push_back(&input); + } } // For an action (where we run a script only once) the sources are the same @@ -249,18 +252,39 @@ // Write the outputs. if (input_deps_sources.size() + input_deps_targets.size() == 0) - return OutputFile(); // No input dependencies. + return std::vector<OutputFile>(); // No input dependencies. // If we're only generating one input dependency, return it directly instead // of writing a stamp file for it. if (input_deps_sources.size() == 1 && input_deps_targets.size() == 0) - return OutputFile(settings_->build_settings(), *input_deps_sources[0]); + return std::vector<OutputFile>{ + OutputFile(settings_->build_settings(), *input_deps_sources[0])}; if (input_deps_sources.size() == 0 && input_deps_targets.size() == 1) { const OutputFile& dep = input_deps_targets[0]->dependency_output_file(); DCHECK(!dep.value().empty()); - return dep; + return std::vector<OutputFile>{dep}; } + std::vector<OutputFile> outs; + // File input deps. + for (const SourceFile* source : input_deps_sources) + outs.push_back(OutputFile(settings_->build_settings(), *source)); + // Target input deps. Sort by label so the output is deterministic (otherwise + // some of the targets will have gone through std::sets which will have + // sorted them by pointer). + std::sort( + input_deps_targets.begin(), input_deps_targets.end(), + [](const Target* a, const Target* b) { return a->label() < b->label(); }); + for (auto* dep : input_deps_targets) { + DCHECK(!dep->dependency_output_file().value().empty()); + outs.push_back(dep->dependency_output_file()); + } + + // If there are multiple inputs, but the stamp file would be referenced only + // once, don't write it but depend on the inputs directly. + if (num_stamp_uses == 1u) + return outs; + // Make a stamp file. OutputFile input_stamp_file = GetBuildDirForTargetAsOutputFile(target_, BuildDirType::OBJ); @@ -272,27 +296,10 @@ out_ << ": " << GetNinjaRulePrefixForToolchain(settings_) << Toolchain::ToolTypeToName(Toolchain::TYPE_STAMP); - - // File input deps. - for (const SourceFile* source : input_deps_sources) { - out_ << " "; - path_output_.WriteFile(out_, *source); - } - - // Target input deps. Sort by label so the output is deterministic (otherwise - // some of the targets will have gone through std::sets which will have - // sorted them by pointer). - std::sort( - input_deps_targets.begin(), input_deps_targets.end(), - [](const Target* a, const Target* b) { return a->label() < b->label(); }); - for (auto* dep : input_deps_targets) { - DCHECK(!dep->dependency_output_file().value().empty()); - out_ << " "; - path_output_.WriteFile(out_, dep->dependency_output_file()); - } + path_output_.WriteFiles(out_, outs); out_ << "\n"; - return input_stamp_file; + return std::vector<OutputFile>{input_stamp_file}; } void NinjaTargetWriter::WriteStampForTarget(
diff --git a/tools/gn/ninja_target_writer.h b/tools/gn/ninja_target_writer.h index 5a3af18..dc9a885 100644 --- a/tools/gn/ninja_target_writer.h +++ b/tools/gn/ninja_target_writer.h
@@ -42,11 +42,14 @@ // Writes to the output stream a stamp rule for input dependencies, and // returns the file to be appended to source rules that encodes the - // order-only dependencies for the current target. The returned OutputFile - // will be empty if there are no implicit dependencies and no extra target - // dependencies passed in. - OutputFile WriteInputDepsStampAndGetDep( - const std::vector<const Target*>& extra_hard_deps) const; + // order-only dependencies for the current target. + // If num_stamp_uses is small, this might return all input dependencies + // directly, without writing a stamp file. + // If there are no implicit dependencies and no extra target dependencies + // are passed in, this returns an empty vector. + std::vector<OutputFile> WriteInputDepsStampAndGetDep( + const std::vector<const Target*>& extra_hard_deps, + size_t num_stamp_uses) const; // Writes to the output file a final stamp rule for the target that stamps // the given list of files. This function assumes the stamp is for the target
diff --git a/tools/gn/ninja_target_writer_unittest.cc b/tools/gn/ninja_target_writer_unittest.cc index 55bbde0..68a59c81 100644 --- a/tools/gn/ninja_target_writer_unittest.cc +++ b/tools/gn/ninja_target_writer_unittest.cc
@@ -22,9 +22,11 @@ void Run() override {} // Make this public so the test can call it. - OutputFile WriteInputDepsStampAndGetDep( - const std::vector<const Target*>& extra_hard_deps) { - return NinjaTargetWriter::WriteInputDepsStampAndGetDep(extra_hard_deps); + std::vector<OutputFile> WriteInputDepsStampAndGetDep( + const std::vector<const Target*>& extra_hard_deps, + size_t num_stamp_uses) { + return NinjaTargetWriter::WriteInputDepsStampAndGetDep(extra_hard_deps, + num_stamp_uses); } }; @@ -47,7 +49,7 @@ target.set_output_type(Target::EXECUTABLE); target.visibility().SetPublic(); target.SetToolchain(setup.toolchain()); - target.inputs().push_back(SourceFile("//foo/input.txt")); + target.config_values().inputs().push_back(SourceFile("//foo/input.txt")); target.sources().push_back(SourceFile("//foo/source.txt")); target.public_deps().push_back(LabelTargetPair(&base_target)); @@ -69,12 +71,13 @@ { std::ostringstream stream; TestingNinjaTargetWriter writer(&base_target, setup.toolchain(), stream); - OutputFile dep = - writer.WriteInputDepsStampAndGetDep(std::vector<const Target*>()); + std::vector<OutputFile> dep = + writer.WriteInputDepsStampAndGetDep(std::vector<const Target*>(), 10u); // Since there is only one dependency, it should just be returned and // nothing written to the stream. - EXPECT_EQ("../../foo/script.py", dep.value()); + ASSERT_EQ(1u, dep.size()); + EXPECT_EQ("../../foo/script.py", dep[0].value()); EXPECT_EQ("", stream.str()); } @@ -82,12 +85,13 @@ { std::ostringstream stream; TestingNinjaTargetWriter writer(&target, setup.toolchain(), stream); - OutputFile dep = - writer.WriteInputDepsStampAndGetDep(std::vector<const Target*>()); + std::vector<OutputFile> dep = + writer.WriteInputDepsStampAndGetDep(std::vector<const Target*>(), 10u); // Since there is only one dependency, a stamp file will be returned // directly without writing any additional rules. - EXPECT_EQ("obj/foo/base.stamp", dep.value()); + ASSERT_EQ(1u, dep.size()); + EXPECT_EQ("obj/foo/base.stamp", dep[0].value()); } // Input deps for action which should depend on the base since its a hard dep @@ -95,10 +99,11 @@ { std::ostringstream stream; TestingNinjaTargetWriter writer(&action, setup.toolchain(), stream); - OutputFile dep = - writer.WriteInputDepsStampAndGetDep(std::vector<const Target*>()); + std::vector<OutputFile> dep = + writer.WriteInputDepsStampAndGetDep(std::vector<const Target*>(), 10u); - EXPECT_EQ("obj/foo/action.inputdeps.stamp", dep.value()); + ASSERT_EQ(1u, dep.size()); + EXPECT_EQ("obj/foo/action.inputdeps.stamp", dep[0].value()); EXPECT_EQ("build obj/foo/action.inputdeps.stamp: stamp ../../foo/script.py " "../../foo/action_source.txt obj/foo/base.stamp\n", stream.str()); @@ -129,11 +134,12 @@ std::ostringstream stream; TestingNinjaTargetWriter writer(&target, setup.toolchain(), stream); - OutputFile dep = - writer.WriteInputDepsStampAndGetDep(std::vector<const Target*>()); + std::vector<OutputFile> dep = + writer.WriteInputDepsStampAndGetDep(std::vector<const Target*>(), 10u); // Since there is more than one dependency, a stamp file will be returned // and the rule for the stamp file will be written to the stream. - EXPECT_EQ("obj/foo/setup.stamp", dep.value()); + ASSERT_EQ(1u, dep.size()); + EXPECT_EQ("obj/foo/setup.stamp", dep[0].value()); EXPECT_EQ("", stream.str()); }
diff --git a/tools/gn/ninja_toolchain_writer.cc b/tools/gn/ninja_toolchain_writer.cc index 911a474..d22740f 100644 --- a/tools/gn/ninja_toolchain_writer.cc +++ b/tools/gn/ninja_toolchain_writer.cc
@@ -36,8 +36,7 @@ ESCAPE_NINJA) { } -NinjaToolchainWriter::~NinjaToolchainWriter() { -} +NinjaToolchainWriter::~NinjaToolchainWriter() = default; void NinjaToolchainWriter::Run( const std::vector<NinjaWriter::TargetRulePair>& rules) {
diff --git a/tools/gn/ninja_writer.cc b/tools/gn/ninja_writer.cc index 4fd5b22..3326f83 100644 --- a/tools/gn/ninja_writer.cc +++ b/tools/gn/ninja_writer.cc
@@ -16,8 +16,7 @@ : builder_(builder) { } -NinjaWriter::~NinjaWriter() { -} +NinjaWriter::~NinjaWriter() = default; // static bool NinjaWriter::RunAndWriteFiles(
diff --git a/tools/gn/operators_unittest.cc b/tools/gn/operators_unittest.cc index d72e08b..4b8ab37 100644 --- a/tools/gn/operators_unittest.cc +++ b/tools/gn/operators_unittest.cc
@@ -5,6 +5,8 @@ #include "tools/gn/operators.h" #include <stdint.h> + +#include <memory> #include <utility> #include "testing/gtest/include/gtest/gtest.h" @@ -62,7 +64,7 @@ } void SetLeftToValue(const Value& value) { - set_left(std::unique_ptr<ParseNode>(new TestParseNode(value))); + set_left(std::make_unique<TestParseNode>(value)); } // Sets the left-hand side of the operator to an identifier node, this is @@ -70,23 +72,23 @@ void SetLeftToIdentifier(const char* identifier) { left_identifier_token_ownership_ = Token(Location(), Token::IDENTIFIER, identifier); - set_left(std::unique_ptr<ParseNode>( - new IdentifierNode(left_identifier_token_ownership_))); + set_left( + std::make_unique<IdentifierNode>(left_identifier_token_ownership_)); } void SetRightToValue(const Value& value) { - set_right(std::unique_ptr<ParseNode>(new TestParseNode(value))); + set_right(std::make_unique<TestParseNode>(value)); } void SetRightToListOfValue(const Value& value) { Value list(nullptr, Value::LIST); list.list_value().push_back(value); - set_right(std::unique_ptr<ParseNode>(new TestParseNode(list))); + set_right(std::make_unique<TestParseNode>(list)); } void SetRightToListOfValue(const Value& value1, const Value& value2) { Value list(nullptr, Value::LIST); list.list_value().push_back(value1); list.list_value().push_back(value2); - set_right(std::unique_ptr<ParseNode>(new TestParseNode(list))); + set_right(std::make_unique<TestParseNode>(list)); } private: @@ -113,7 +115,7 @@ node.SetLeftToIdentifier(sources); // Set up the filter on the scope to remove everything ending with "rm" - std::unique_ptr<PatternList> pattern_list(new PatternList); + std::unique_ptr<PatternList> pattern_list = std::make_unique<PatternList>(); pattern_list->Append(Pattern("*rm")); setup.scope()->set_sources_assignment_filter(std::move(pattern_list)); @@ -189,7 +191,7 @@ // This should fail. const char str_str[] = "\"hi\""; Token str(Location(), Token::STRING, str_str); - node.set_right(std::unique_ptr<ParseNode>(new LiteralNode(str))); + node.set_right(std::make_unique<LiteralNode>(str)); ExecuteBinaryOperator(setup.scope(), &node, node.left(), node.right(), &err); EXPECT_TRUE(err.has_error()); err = Err(); @@ -276,8 +278,7 @@ // Set right as foo, but don't define a value for it. const char foo[] = "foo"; Token identifier_token(Location(), Token::IDENTIFIER, foo); - node.set_right( - std::unique_ptr<ParseNode>(new IdentifierNode(identifier_token))); + node.set_right(std::make_unique<IdentifierNode>(identifier_token)); Value ret = ExecuteBinaryOperator(setup.scope(), &node, node.left(), node.right(), &err); @@ -295,8 +296,7 @@ // Set right as foo, but don't define a value for it. const char foo[] = "foo"; Token identifier_token(Location(), Token::IDENTIFIER, foo); - node.set_right( - std::unique_ptr<ParseNode>(new IdentifierNode(identifier_token))); + node.set_right(std::make_unique<IdentifierNode>(identifier_token)); Value ret = ExecuteBinaryOperator(setup.scope(), &node, node.left(), node.right(), &err); @@ -336,8 +336,7 @@ // Set up "foo" with a nonempty scope. const char bar[] = "bar"; - old_value = - Value(nullptr, std::unique_ptr<Scope>(new Scope(setup.settings()))); + old_value = Value(nullptr, std::make_unique<Scope>(setup.settings())); old_value.scope_value()->SetValue(bar, Value(nullptr, "bar"), nullptr); setup.scope()->SetValue(foo, old_value, nullptr); @@ -350,7 +349,7 @@ // Assigning an empty list should succeed. node.SetRightToValue( - Value(nullptr, std::unique_ptr<Scope>(new Scope(setup.settings())))); + Value(nullptr, std::make_unique<Scope>(setup.settings()))); node.Execute(setup.scope(), &err); ASSERT_FALSE(err.has_error()); new_value = setup.scope()->GetValue(foo);
diff --git a/tools/gn/output_file.cc b/tools/gn/output_file.cc index 12845fb..a70bae9 100644 --- a/tools/gn/output_file.cc +++ b/tools/gn/output_file.cc
@@ -25,8 +25,7 @@ build_settings->root_path_utf8())) { } -OutputFile::~OutputFile() { -} +OutputFile::~OutputFile() = default; SourceFile OutputFile::AsSourceFile(const BuildSettings* build_settings) const { DCHECK(!value_.empty());
diff --git a/tools/gn/parse_node_value_adapter.cc b/tools/gn/parse_node_value_adapter.cc index 82f6f79..70c78e5 100644 --- a/tools/gn/parse_node_value_adapter.cc +++ b/tools/gn/parse_node_value_adapter.cc
@@ -10,9 +10,7 @@ ParseNodeValueAdapter::ParseNodeValueAdapter() : ref_(nullptr) { } -ParseNodeValueAdapter::~ParseNodeValueAdapter() { -} - +ParseNodeValueAdapter::~ParseNodeValueAdapter() = default; bool ParseNodeValueAdapter::Init(Scope* scope, const ParseNode* node,
diff --git a/tools/gn/parse_tree.cc b/tools/gn/parse_tree.cc index d1de9cbf..df95bf5 100644 --- a/tools/gn/parse_tree.cc +++ b/tools/gn/parse_tree.cc
@@ -6,6 +6,7 @@ #include <stdint.h> +#include <memory> #include <string> #include <tuple> @@ -79,22 +80,18 @@ } // namespace -Comments::Comments() { -} +Comments::Comments() = default; -Comments::~Comments() { -} +Comments::~Comments() = default; void Comments::ReverseSuffix() { for (int i = 0, j = static_cast<int>(suffix_.size() - 1); i < j; ++i, --j) std::swap(suffix_[i], suffix_[j]); } -ParseNode::ParseNode() { -} +ParseNode::ParseNode() = default; -ParseNode::~ParseNode() { -} +ParseNode::~ParseNode() = default; const AccessorNode* ParseNode::AsAccessor() const { return nullptr; } const BinaryOpNode* ParseNode::AsBinaryOp() const { return nullptr; } @@ -110,7 +107,7 @@ Comments* ParseNode::comments_mutable() { if (!comments_) - comments_.reset(new Comments); + comments_ = std::make_unique<Comments>(); return comments_.get(); } @@ -128,11 +125,9 @@ // AccessorNode --------------------------------------------------------------- -AccessorNode::AccessorNode() { -} +AccessorNode::AccessorNode() = default; -AccessorNode::~AccessorNode() { -} +AccessorNode::~AccessorNode() = default; const AccessorNode* AccessorNode::AsAccessor() const { return this; @@ -255,9 +250,9 @@ size_t index_sizet = static_cast<size_t>(index_int); if (index_sizet >= max_len) { *err = Err(index_->GetRange(), "Array subscript out of range.", - "You gave me " + base::Int64ToString(index_int) + - " but I was expecting something from 0 to " + - base::SizeTToString(max_len) + ", inclusive."); + "You gave me " + base::Int64ToString(index_int) + + " but I was expecting something from 0 to " + + base::NumberToString(max_len) + ", inclusive."); return false; } @@ -267,11 +262,9 @@ // BinaryOpNode --------------------------------------------------------------- -BinaryOpNode::BinaryOpNode() { -} +BinaryOpNode::BinaryOpNode() = default; -BinaryOpNode::~BinaryOpNode() { -} +BinaryOpNode::~BinaryOpNode() = default; const BinaryOpNode* BinaryOpNode::AsBinaryOp() const { return this; @@ -302,8 +295,7 @@ BlockNode::BlockNode(ResultMode result_mode) : result_mode_(result_mode) { } -BlockNode::~BlockNode() { -} +BlockNode::~BlockNode() = default; const BlockNode* BlockNode::AsBlock() const { return this; @@ -315,7 +307,7 @@ Scope* execution_scope; // Either the enclosing_scope or nested_scope. if (result_mode_ == RETURNS_SCOPE) { // Create a nested scope to save the values for returning. - nested_scope.reset(new Scope(enclosing_scope)); + nested_scope = std::make_unique<Scope>(enclosing_scope); execution_scope = nested_scope.get(); } else { // Use the enclosing scope. Modifications will go into this also (for @@ -380,11 +372,9 @@ // ConditionNode -------------------------------------------------------------- -ConditionNode::ConditionNode() { -} +ConditionNode::ConditionNode() = default; -ConditionNode::~ConditionNode() { -} +ConditionNode::~ConditionNode() = default; const ConditionNode* ConditionNode::AsConditionNode() const { return this; @@ -436,11 +426,9 @@ // FunctionCallNode ----------------------------------------------------------- -FunctionCallNode::FunctionCallNode() { -} +FunctionCallNode::FunctionCallNode() = default; -FunctionCallNode::~FunctionCallNode() { -} +FunctionCallNode::~FunctionCallNode() = default; const FunctionCallNode* FunctionCallNode::AsFunctionCall() const { return this; @@ -473,14 +461,12 @@ // IdentifierNode -------------------------------------------------------------- -IdentifierNode::IdentifierNode() { -} +IdentifierNode::IdentifierNode() = default; IdentifierNode::IdentifierNode(const Token& token) : value_(token) { } -IdentifierNode::~IdentifierNode() { -} +IdentifierNode::~IdentifierNode() = default; const IdentifierNode* IdentifierNode::AsIdentifier() const { return this; @@ -529,8 +515,7 @@ ListNode::ListNode() : prefer_multiline_(false) { } -ListNode::~ListNode() { -} +ListNode::~ListNode() = default; const ListNode* ListNode::AsList() const { return this; @@ -720,14 +705,12 @@ // LiteralNode ----------------------------------------------------------------- -LiteralNode::LiteralNode() { -} +LiteralNode::LiteralNode() = default; LiteralNode::LiteralNode(const Token& token) : value_(token) { } -LiteralNode::~LiteralNode() { -} +LiteralNode::~LiteralNode() = default; const LiteralNode* LiteralNode::AsLiteral() const { return this; @@ -788,11 +771,9 @@ // UnaryOpNode ---------------------------------------------------------------- -UnaryOpNode::UnaryOpNode() { -} +UnaryOpNode::UnaryOpNode() = default; -UnaryOpNode::~UnaryOpNode() { -} +UnaryOpNode::~UnaryOpNode() = default; const UnaryOpNode* UnaryOpNode::AsUnaryOp() const { return this; @@ -822,11 +803,9 @@ // BlockCommentNode ------------------------------------------------------------ -BlockCommentNode::BlockCommentNode() { -} +BlockCommentNode::BlockCommentNode() = default; -BlockCommentNode::~BlockCommentNode() { -} +BlockCommentNode::~BlockCommentNode() = default; const BlockCommentNode* BlockCommentNode::AsBlockComment() const { return this; @@ -855,8 +834,7 @@ EndNode::EndNode(const Token& token) : value_(token) { } -EndNode::~EndNode() { -} +EndNode::~EndNode() = default; const EndNode* EndNode::AsEnd() const { return this;
diff --git a/tools/gn/parse_tree_unittest.cc b/tools/gn/parse_tree_unittest.cc index 06092157..a786925b4 100644 --- a/tools/gn/parse_tree_unittest.cc +++ b/tools/gn/parse_tree_unittest.cc
@@ -5,6 +5,8 @@ #include "tools/gn/parse_tree.h" #include <stdint.h> + +#include <memory> #include <utility> #include "testing/gtest/include/gtest/gtest.h" @@ -24,8 +26,8 @@ AccessorNode accessor; accessor.set_base(base_token); - std::unique_ptr<IdentifierNode> member_identifier( - new IdentifierNode(member_token)); + std::unique_ptr<IdentifierNode> member_identifier = + std::make_unique<IdentifierNode>(member_token); accessor.set_member(std::move(member_identifier)); // The access should fail because a is not defined. @@ -37,8 +39,7 @@ // Define a as a Scope. It should still fail because b isn't defined. err = Err(); setup.scope()->SetValue( - "a", Value(nullptr, std::unique_ptr<Scope>(new Scope(setup.scope()))), - nullptr); + "a", Value(nullptr, std::make_unique<Scope>(setup.scope())), nullptr); result = accessor.Execute(setup.scope(), &err); EXPECT_TRUE(err.has_error()); EXPECT_EQ(Value::NONE, result.type());
diff --git a/tools/gn/parser.cc b/tools/gn/parser.cc index 7e2c7f43..c8dd654 100644 --- a/tools/gn/parser.cc +++ b/tools/gn/parser.cc
@@ -4,10 +4,10 @@ #include "tools/gn/parser.h" +#include <memory> #include <utility> #include "base/logging.h" -#include "base/memory/ptr_util.h" #include "tools/gn/functions.h" #include "tools/gn/operators.h" #include "tools/gn/token.h" @@ -299,8 +299,7 @@ } } -Parser::~Parser() { -} +Parser::~Parser() = default; // static std::unique_ptr<ParseNode> Parser::Parse(const std::vector<Token>& tokens, @@ -460,7 +459,7 @@ } std::unique_ptr<ParseNode> Parser::Literal(const Token& token) { - return base::MakeUnique<LiteralNode>(token); + return std::make_unique<LiteralNode>(token); } std::unique_ptr<ParseNode> Parser::Name(const Token& token) { @@ -468,7 +467,8 @@ } std::unique_ptr<ParseNode> Parser::BlockComment(const Token& token) { - std::unique_ptr<BlockCommentNode> comment(new BlockCommentNode()); + std::unique_ptr<BlockCommentNode> comment = + std::make_unique<BlockCommentNode>(); comment->set_comment(token); return std::move(comment); } @@ -490,7 +490,7 @@ *err_ = Err(token, "Expected right-hand side for '!'."); return std::unique_ptr<ParseNode>(); } - std::unique_ptr<UnaryOpNode> unary_op(new UnaryOpNode); + std::unique_ptr<UnaryOpNode> unary_op = std::make_unique<UnaryOpNode>(); unary_op->set_op(token); unary_op->set_operand(std::move(expr)); return std::move(unary_op); @@ -515,7 +515,7 @@ } return std::unique_ptr<ParseNode>(); } - std::unique_ptr<BinaryOpNode> binary_op(new BinaryOpNode); + std::unique_ptr<BinaryOpNode> binary_op = std::make_unique<BinaryOpNode>(); binary_op->set_op(token); binary_op->set_left(std::move(left)); binary_op->set_right(std::move(right)); @@ -525,9 +525,9 @@ std::unique_ptr<ParseNode> Parser::IdentifierOrCall( std::unique_ptr<ParseNode> left, const Token& token) { - std::unique_ptr<ListNode> list(new ListNode); + std::unique_ptr<ListNode> list = std::make_unique<ListNode>(); list->set_begin_token(token); - list->set_end(base::MakeUnique<EndNode>(token)); + list->set_end(std::make_unique<EndNode>(token)); std::unique_ptr<BlockNode> block; bool has_arg = false; if (LookAhead(Token::LEFT_PAREN)) { @@ -552,9 +552,10 @@ if (!left && !has_arg) { // Not a function call, just a standalone identifier. - return std::unique_ptr<ParseNode>(new IdentifierNode(token)); + return std::make_unique<IdentifierNode>(token); } - std::unique_ptr<FunctionCallNode> func_call(new FunctionCallNode); + std::unique_ptr<FunctionCallNode> func_call = + std::make_unique<FunctionCallNode>(); func_call->set_function(token); func_call->set_args(std::move(list)); if (block) @@ -576,7 +577,7 @@ *err_ = Err(token, "Expected right-hand side for assignment."); return std::unique_ptr<ParseNode>(); } - std::unique_ptr<BinaryOpNode> assign(new BinaryOpNode); + std::unique_ptr<BinaryOpNode> assign = std::make_unique<BinaryOpNode>(); assign->set_op(token); assign->set_left(std::move(left)); assign->set_right(std::move(value)); @@ -596,7 +597,7 @@ } std::unique_ptr<ParseNode> value = ParseExpression(); Consume(Token::RIGHT_BRACKET, "Expecting ']' after subscript."); - std::unique_ptr<AccessorNode> accessor(new AccessorNode); + std::unique_ptr<AccessorNode> accessor = std::make_unique<AccessorNode>(); accessor->set_base(left->AsIdentifier()->value()); accessor->set_index(std::move(value)); return std::move(accessor); @@ -619,7 +620,7 @@ return std::unique_ptr<ParseNode>(); } - std::unique_ptr<AccessorNode> accessor(new AccessorNode); + std::unique_ptr<AccessorNode> accessor = std::make_unique<AccessorNode>(); accessor->set_base(left->AsIdentifier()->value()); accessor->set_member(std::unique_ptr<IdentifierNode>( static_cast<IdentifierNode*>(right.release()))); @@ -630,7 +631,7 @@ std::unique_ptr<ListNode> Parser::ParseList(const Token& start_token, Token::Type stop_before, bool allow_trailing_comma) { - std::unique_ptr<ListNode> list(new ListNode); + std::unique_ptr<ListNode> list = std::make_unique<ListNode>(); list->set_begin_token(start_token); bool just_got_comma = false; bool first_time = true; @@ -667,12 +668,13 @@ *err_ = Err(cur_token(), "Trailing comma"); return std::unique_ptr<ListNode>(); } - list->set_end(base::MakeUnique<EndNode>(cur_token())); + list->set_end(std::make_unique<EndNode>(cur_token())); return list; } std::unique_ptr<ParseNode> Parser::ParseFile() { - std::unique_ptr<BlockNode> file(new BlockNode(BlockNode::DISCARDS_RESULT)); + std::unique_ptr<BlockNode> file = + std::make_unique<BlockNode>(BlockNode::DISCARDS_RESULT); for (;;) { if (at_end()) break; @@ -721,12 +723,12 @@ BlockNode::ResultMode result_mode) { if (has_error()) return std::unique_ptr<BlockNode>(); - std::unique_ptr<BlockNode> block(new BlockNode(result_mode)); + std::unique_ptr<BlockNode> block = std::make_unique<BlockNode>(result_mode); block->set_begin_token(begin_brace); for (;;) { if (LookAhead(Token::RIGHT_BRACE)) { - block->set_end(base::MakeUnique<EndNode>(Consume())); + block->set_end(std::make_unique<EndNode>(Consume())); break; } @@ -739,7 +741,7 @@ } std::unique_ptr<ParseNode> Parser::ParseCondition() { - std::unique_ptr<ConditionNode> condition(new ConditionNode); + std::unique_ptr<ConditionNode> condition = std::make_unique<ConditionNode>(); condition->set_if_token(Consume(Token::IF, "Expected 'if'")); Consume(Token::LEFT_PAREN, "Expected '(' after 'if'."); condition->set_condition(ParseExpression());
diff --git a/tools/gn/parser_fuzzer.cc b/tools/gn/parser_fuzzer.cc index c7b43255..e40da78 100644 --- a/tools/gn/parser_fuzzer.cc +++ b/tools/gn/parser_fuzzer.cc
@@ -9,6 +9,51 @@ #include "tools/gn/source_file.h" #include "tools/gn/tokenizer.h" +namespace { + +enum { kMaxContentDepth = 256, kMaxDodgy = 256 }; + +// Some auto generated input is too unreasonable for fuzzing GN. +// We see stack overflow when the parser hits really deeply "nested" input. +// (I.E.: certain input that causes nested parsing function calls). +// +// Abstract max limits are undesirable in the release GN code, so some sanity +// checks in the fuzzer to prevent stack overflow are done here. +// - 1) Too many opening bracket, paren, or brace in a row. +// - 2) Too many '!', '<' or '>' operators in a row. +bool SanityCheckContent(const std::vector<Token>& tokens) { + int depth = 0; + int dodgy_count = 0; + for (const auto& token : tokens) { + switch (token.type()) { + case Token::LEFT_PAREN: + case Token::LEFT_BRACKET: + case Token::LEFT_BRACE: + ++depth; + break; + case Token::RIGHT_PAREN: + case Token::RIGHT_BRACKET: + case Token::RIGHT_BRACE: + --depth; + break; + case Token::BANG: + case Token::LESS_THAN: + case Token::GREATER_THAN: + ++dodgy_count; + break; + default: + break; + } + // Bail out as soon as a boundary is hit, inside the loop. + if (depth >= kMaxContentDepth || dodgy_count >= kMaxDodgy) + return false; + } + + return true; +} + +} // namespace + extern "C" int LLVMFuzzerTestOneInput(const unsigned char* data, size_t size) { SourceFile source; InputFile input(source); @@ -16,6 +61,8 @@ Err err; std::vector<Token> tokens = Tokenizer::Tokenize(&input, &err); + if (!SanityCheckContent(tokens)) + return 0; if (!err.has_error()) Parser::Parse(tokens, &err);
diff --git a/tools/gn/path_output.cc b/tools/gn/path_output.cc index 711341fc..61c4ee0a 100644 --- a/tools/gn/path_output.cc +++ b/tools/gn/path_output.cc
@@ -20,8 +20,7 @@ options_.mode = escaping; } -PathOutput::~PathOutput() { -} +PathOutput::~PathOutput() = default; void PathOutput::WriteFile(std::ostream& out, const SourceFile& file) const { WritePathStr(out, file.value());
diff --git a/tools/gn/pattern.cc b/tools/gn/pattern.cc index 3de96a3..15bbf581 100644 --- a/tools/gn/pattern.cc +++ b/tools/gn/pattern.cc
@@ -62,8 +62,7 @@ Pattern::Pattern(const Pattern& other) = default; -Pattern::~Pattern() { -} +Pattern::~Pattern() = default; bool Pattern::MatchesString(const std::string& s) const { // Empty pattern matches only empty string. @@ -150,13 +149,11 @@ return false; } -PatternList::PatternList() { -} +PatternList::PatternList() = default; PatternList::PatternList(const PatternList& other) = default; -PatternList::~PatternList() { -} +PatternList::~PatternList() = default; void PatternList::Append(const Pattern& pattern) { patterns_.push_back(pattern);
diff --git a/tools/gn/pool.cc b/tools/gn/pool.cc index 75a7504..4b9629b 100644 --- a/tools/gn/pool.cc +++ b/tools/gn/pool.cc
@@ -8,7 +8,7 @@ #include "base/logging.h" -Pool::~Pool() {} +Pool::~Pool() = default; Pool* Pool::AsPool() { return this;
diff --git a/tools/gn/pool.h b/tools/gn/pool.h index 81a021d..42a8078 100644 --- a/tools/gn/pool.h +++ b/tools/gn/pool.h
@@ -7,6 +7,7 @@ #include <string> +#include "base/macros.h" #include "tools/gn/item.h" // Represents a named pool in the dependency graph. @@ -18,9 +19,6 @@ using Item::Item; ~Pool() override; - Pool(const Pool&) = delete; - Pool& operator=(const Pool&) = delete; - // Item implementation. Pool* AsPool() override; const Pool* AsPool() const override; @@ -36,6 +34,8 @@ std::string GetNinjaName(bool include_toolchain) const; int64_t depth_ = 0; + + DISALLOW_COPY_AND_ASSIGN(Pool); }; #endif // TOOLS_GN_POOL_H_
diff --git a/tools/gn/qt_creator_writer.cc b/tools/gn/qt_creator_writer.cc index db0c9b8..687bff2 100644 --- a/tools/gn/qt_creator_writer.cc +++ b/tools/gn/qt_creator_writer.cc
@@ -68,7 +68,7 @@ project_prefix_(project_prefix), root_target_name_(root_target_name) {} -QtCreatorWriter::~QtCreatorWriter() {} +QtCreatorWriter::~QtCreatorWriter() = default; void QtCreatorWriter::CollectDeps(const Target* target) { for (const auto& dep : target->GetDeps(Target::DEPS_ALL)) { @@ -121,9 +121,11 @@ AddToSources(target->sources()); AddToSources(target->public_headers()); - AddToSources(target->inputs()); for (ConfigValuesIterator it(target); !it.done(); it.Next()) { + for (const auto& input : it.cur().inputs()) + sources_.insert(FilePathToUTF8(build_settings_->GetFullPath(input))); + SourceFile precompiled_source = it.cur().precompiled_source(); if (!precompiled_source.is_null()) { sources_.insert(
diff --git a/tools/gn/runtime_deps_unittest.cc b/tools/gn/runtime_deps_unittest.cc index ed0eea4..bb5d46f7 100644 --- a/tools/gn/runtime_deps_unittest.cc +++ b/tools/gn/runtime_deps_unittest.cc
@@ -9,6 +9,7 @@ #include "tools/gn/runtime_deps.h" #include "tools/gn/scheduler.h" #include "tools/gn/target.h" +#include "tools/gn/test_with_scheduler.h" #include "tools/gn/test_with_scope.h" namespace { @@ -40,8 +41,10 @@ } // namespace +using RuntimeDeps = TestWithScheduler; + // Tests an exe depending on different types of libraries. -TEST(RuntimeDeps, Libs) { +TEST_F(RuntimeDeps, Libs) { TestWithScope setup; Err err; @@ -113,7 +116,7 @@ // Tests that executables that aren't listed as data deps aren't included in // the output, but executables that are data deps are included. -TEST(RuntimeDeps, ExeDataDep) { +TEST_F(RuntimeDeps, ExeDataDep) { TestWithScope setup; Err err; @@ -165,7 +168,7 @@ << GetVectorDescription(result); } -TEST(RuntimeDeps, ActionSharedLib) { +TEST_F(RuntimeDeps, ActionSharedLib) { TestWithScope setup; Err err; @@ -208,7 +211,7 @@ // Tests that action and copy outputs are considered if they're data deps, but // not if they're regular deps. Action and copy "data" files are always // included. -TEST(RuntimeDeps, ActionOutputs) { +TEST_F(RuntimeDeps, ActionOutputs) { TestWithScope setup; Err err; @@ -294,7 +297,7 @@ // Tests that the search for dependencies terminates at a bundle target, // ignoring any shared libraries or loadable modules that get copied into the // bundle. -TEST(RuntimeDeps, CreateBundle) { +TEST_F(RuntimeDeps, CreateBundle) { TestWithScope setup; Err err; @@ -350,10 +353,12 @@ Target bundle(setup.settings(), Label(source_dir, "bundle")); InitTargetWithType(setup, &bundle, Target::CREATE_BUNDLE); - const std::string root_dir(build_dir + "Bundle.framework/Versions/A/"); + const std::string root_dir(build_dir + "Bundle.framework/"); + const std::string contents_dir(root_dir + "Versions/A/"); bundle.bundle_data().root_dir() = SourceDir(root_dir); - bundle.bundle_data().resources_dir() = SourceDir(root_dir + "Resources"); - bundle.bundle_data().executable_dir() = SourceDir(root_dir + "MacOS"); + bundle.bundle_data().contents_dir() = SourceDir(contents_dir); + bundle.bundle_data().resources_dir() = SourceDir(contents_dir + "Resources"); + bundle.bundle_data().executable_dir() = SourceDir(contents_dir + "MacOS"); bundle.private_deps().push_back(LabelTargetPair(&dylib_data)); bundle.private_deps().push_back(LabelTargetPair(&module_data)); bundle.data_deps().push_back(LabelTargetPair(&data_dep)); @@ -391,7 +396,7 @@ // Tests that a dependency duplicated in regular and data deps is processed // as a data dep. -TEST(RuntimeDeps, Dupe) { +TEST_F(RuntimeDeps, Dupe) { TestWithScope setup; Err err; @@ -416,8 +421,7 @@ } // Tests that actions can't have output substitutions. -TEST(RuntimeDeps, WriteRuntimeDepsVariable) { - Scheduler scheduler; +TEST_F(RuntimeDeps, WriteRuntimeDepsVariable) { TestWithScope setup; Err err; @@ -440,5 +444,5 @@ " group(\"bar\") { write_runtime_deps = \"//out/Debug/bar.txt\" }\n" "}", &err)); EXPECT_EQ(1U, setup.items().size()); - EXPECT_EQ(1U, scheduler.GetWriteRuntimeDepsTargets().size()); + EXPECT_EQ(1U, scheduler().GetWriteRuntimeDepsTargets().size()); }
diff --git a/tools/gn/scheduler.cc b/tools/gn/scheduler.cc index 5327792..cf66dc74 100644 --- a/tools/gn/scheduler.cc +++ b/tools/gn/scheduler.cc
@@ -7,80 +7,26 @@ #include <algorithm> #include "base/bind.h" -#include "base/command_line.h" #include "base/single_thread_task_runner.h" -#include "base/strings/string_number_conversions.h" -#include "build/build_config.h" +#include "base/task_scheduler/post_task.h" +#include "base/threading/thread_task_runner_handle.h" #include "tools/gn/standard_out.h" -#include "tools/gn/switches.h" #include "tools/gn/target.h" -#if defined(OS_WIN) -#include <windows.h> -#else -#include <unistd.h> -#endif - Scheduler* g_scheduler = nullptr; -namespace { - -#if defined(OS_WIN) -int GetCPUCount() { - SYSTEM_INFO sysinfo; - ::GetSystemInfo(&sysinfo); - return sysinfo.dwNumberOfProcessors; -} -#else -int GetCPUCount() { - return static_cast<int>(sysconf(_SC_NPROCESSORS_ONLN)); -} -#endif - -int GetThreadCount() { - std::string thread_count = - base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( - switches::kThreads); - - // See if an override was specified on the command line. - int result; - if (!thread_count.empty() && base::StringToInt(thread_count, &result)) - return result; - - // Base the default number of worker threads on number of cores in the - // system. When building large projects, the speed can be limited by how fast - // the main thread can dispatch work and connect the dependency graph. If - // there are too many worker threads, the main thread can be starved and it - // will run slower overall. - // - // One less worker thread than the number of physical CPUs seems to be a - // good value, both theoretically and experimentally. But always use at - // least some workers to prevent us from being too sensitive to I/O latency - // on low-end systems. - // - // The minimum thread count is based on measuring the optimal threads for the - // Chrome build on a several-year-old 4-core MacBook. - int num_cores = GetCPUCount() / 2; // Almost all CPUs now are hyperthreaded. - return std::max(num_cores - 1, 8); -} - -} // namespace - Scheduler::Scheduler() - : pool_(new base::SequencedWorkerPool(GetThreadCount(), - "worker_", - base::TaskPriority::USER_VISIBLE)), + : main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()), input_file_manager_(new InputFileManager), verbose_logging_(false), - work_count_(0), + pool_work_count_cv_(&pool_work_count_lock_), is_failed_(false), has_been_shutdown_(false) { g_scheduler = this; } Scheduler::~Scheduler() { - if (!has_been_shutdown_) - pool_->Shutdown(); + WaitForPoolTasks(); g_scheduler = nullptr; } @@ -92,9 +38,9 @@ local_is_failed = is_failed(); has_been_shutdown_ = true; } - // Don't do this inside the lock since it will block on the workers, which - // may be in turn waiting on the lock. - pool_->Shutdown(); + // Don't do this while holding |lock_|, since it will block on the workers, + // which may be in turn waiting on the lock. + WaitForPoolTasks(); return !local_is_failed; } @@ -131,12 +77,13 @@ } } -void Scheduler::ScheduleWork(const base::Closure& work) { +void Scheduler::ScheduleWork(base::OnceClosure work) { IncrementWorkCount(); - pool_->PostWorkerTaskWithShutdownBehavior( - FROM_HERE, base::Bind(&Scheduler::DoWork, - base::Unretained(this), work), - base::SequencedWorkerPool::BLOCK_SHUTDOWN); + pool_work_count_.Increment(); + base::PostTaskWithTraits( + FROM_HERE, {base::MayBlock()}, + base::BindOnce(&Scheduler::DoWork, base::Unretained(this), + std::move(work))); } void Scheduler::AddGenDependency(const base::FilePath& file) { @@ -230,9 +177,13 @@ runner_.Quit(); } -void Scheduler::DoWork(const base::Closure& closure) { - closure.Run(); +void Scheduler::DoWork(base::OnceClosure closure) { + std::move(closure).Run(); DecrementWorkCount(); + if (!pool_work_count_.Decrement()) { + base::AutoLock auto_lock(pool_work_count_lock_); + pool_work_count_cv_.Signal(); + } } void Scheduler::OnComplete() { @@ -240,3 +191,9 @@ DCHECK(task_runner()->BelongsToCurrentThread()); runner_.Quit(); } + +void Scheduler::WaitForPoolTasks() { + base::AutoLock lock(pool_work_count_lock_); + while (!pool_work_count_.IsZero()) + pool_work_count_cv_.Wait(); +}
diff --git a/tools/gn/scheduler.h b/tools/gn/scheduler.h index e20bced..b0732aea 100644 --- a/tools/gn/scheduler.h +++ b/tools/gn/scheduler.h
@@ -13,8 +13,8 @@ #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/single_thread_task_runner.h" +#include "base/synchronization/condition_variable.h" #include "base/synchronization/lock.h" -#include "base/threading/sequenced_worker_pool.h" #include "tools/gn/input_file_manager.h" #include "tools/gn/label.h" #include "tools/gn/source_file.h" @@ -31,7 +31,7 @@ bool Run(); scoped_refptr<base::SingleThreadTaskRunner> task_runner() { - return main_loop_.task_runner(); + return main_thread_task_runner_; } InputFileManager* input_file_manager() { return input_file_manager_.get(); } @@ -45,7 +45,7 @@ void Log(const std::string& verb, const std::string& msg); void FailWithError(const Err& err); - void ScheduleWork(const base::Closure& work); + void ScheduleWork(base::OnceClosure work); void Shutdown(); @@ -97,12 +97,15 @@ void DoTargetFileWrite(const Target* target); - void DoWork(const base::Closure& closure); + void DoWork(base::OnceClosure closure); void OnComplete(); - base::MessageLoop main_loop_; - scoped_refptr<base::SequencedWorkerPool> pool_; + // Waits for tasks scheduled via ScheduleWork() to complete their execution. + void WaitForPoolTasks(); + + // TaskRunner for the thread on which the Scheduler is initialized. + const scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_; scoped_refptr<InputFileManager> input_file_manager_; @@ -112,6 +115,16 @@ base::AtomicRefCount work_count_; + // Number of tasks scheduled by ScheduleWork() that haven't completed their + // execution. + base::AtomicRefCount pool_work_count_; + + // Lock for |pool_work_count_cv_|. + base::Lock pool_work_count_lock_; + + // Condition variable signaled when |pool_work_count_| reaches zero. + base::ConditionVariable pool_work_count_cv_; + mutable base::Lock lock_; bool is_failed_;
diff --git a/tools/gn/scope.cc b/tools/gn/scope.cc index 024d5ec..145d6ad 100644 --- a/tools/gn/scope.cc +++ b/tools/gn/scope.cc
@@ -4,9 +4,11 @@ #include "tools/gn/scope.h" +#include <memory> + #include "base/logging.h" -#include "base/memory/ptr_util.h" #include "tools/gn/parse_tree.h" +#include "tools/gn/source_file.h" #include "tools/gn/template.h" namespace { @@ -29,11 +31,9 @@ Scope::MergeOptions::MergeOptions() : clobber_existing(false), skip_private_vars(false), - mark_dest_used(false) { -} + mark_dest_used(false) {} -Scope::MergeOptions::~MergeOptions() { -} +Scope::MergeOptions::~MergeOptions() = default; Scope::ProgrammaticProvider::~ProgrammaticProvider() { scope_->RemoveProvider(this); @@ -51,17 +51,18 @@ mutable_containing_(parent), settings_(parent->settings()), mode_flags_(0), - item_collector_(nullptr) {} + item_collector_(nullptr), + build_dependency_files_(parent->build_dependency_files_) {} Scope::Scope(const Scope* parent) : const_containing_(parent), mutable_containing_(nullptr), settings_(parent->settings()), mode_flags_(0), - item_collector_(nullptr) {} + item_collector_(nullptr), + build_dependency_files_(parent->build_dependency_files_) {} -Scope::~Scope() { -} +Scope::~Scope() = default; void Scope::DetachFromContaining() { const_containing_ = nullptr; @@ -122,8 +123,8 @@ // Search in the parent mutable scope if requested, but not const one. if (search_mode == SEARCH_NESTED && mutable_containing_) { - return mutable_containing_->GetMutableValue( - ident, Scope::SEARCH_NESTED, counts_as_used); + return mutable_containing_->GetMutableValue(ident, Scope::SEARCH_NESTED, + counts_as_used); } return nullptr; } @@ -248,7 +249,8 @@ bool Scope::CheckForUnusedVars(Err* err) const { for (const auto& pair : values_) { if (!pair.second.used) { - std::string help = "You set the variable \"" + pair.first.as_string() + + std::string help = + "You set the variable \"" + pair.first.as_string() + "\" here and it was unused before it went\nout of scope."; const BinaryOpNode* binary = pair.second.value.origin()->AsBinaryOp(); @@ -295,13 +297,16 @@ // Value present in both the source and the dest. std::string desc_string(desc_for_err); *err = Err(node_for_err, "Value collision.", - "This " + desc_string + " contains \"" + current_name.as_string() + - "\""); - err->AppendSubErr(Err(pair.second.value, "defined here.", - "Which would clobber the one in your current scope")); - err->AppendSubErr(Err(*existing_value, "defined here.", - "Executing " + desc_string + " should not conflict with anything " - "in the current\nscope unless the values are identical.")); + "This " + desc_string + " contains \"" + + current_name.as_string() + "\""); + err->AppendSubErr( + Err(pair.second.value, "defined here.", + "Which would clobber the one in your current scope")); + err->AppendSubErr( + Err(*existing_value, "defined here.", + "Executing " + desc_string + + " should not conflict with anything " + "in the current\nscope unless the values are identical.")); return false; } } @@ -334,19 +339,25 @@ // target defaults. std::string desc_string(desc_for_err); *err = Err(node_for_err, "Target defaults collision.", - "This " + desc_string + " contains target defaults for\n" - "\"" + current_name + "\" which would clobber one for the\n" - "same target type in your current scope. It's unfortunate that " - "I'm too stupid\nto tell you the location of where the target " - "defaults were set. Usually\nthis happens in the BUILDCONFIG.gn " - "file or in a related .gni file.\n"); + "This " + desc_string + + " contains target defaults for\n" + "\"" + + current_name + + "\" which would clobber one for the\n" + "same target type in your current scope. It's " + "unfortunate that " + "I'm too stupid\nto tell you the location of where " + "the target " + "defaults were set. Usually\nthis happens in the " + "BUILDCONFIG.gn " + "file or in a related .gni file.\n"); return false; } } } std::unique_ptr<Scope>& dest_scope = dest->target_defaults_[current_name]; - dest_scope = base::MakeUnique<Scope>(settings_); + dest_scope = std::make_unique<Scope>(settings_); pair.second->NonRecursiveMergeTo(dest_scope.get(), options, node_for_err, "<SHOULDN'T HAPPEN>", err); } @@ -358,13 +369,14 @@ // Sources assignment filter present in both the source and the dest. std::string desc_string(desc_for_err); *err = Err(node_for_err, "Assignment filter collision.", - "The " + desc_string + " contains a sources_assignment_filter " - "which\nwould clobber the one in your current scope."); + "The " + desc_string + + " contains a sources_assignment_filter " + "which\nwould clobber the one in your current scope."); return false; } } - dest->sources_assignment_filter_.reset( - new PatternList(*sources_assignment_filter_)); + dest->sources_assignment_filter_ = + std::make_unique<PatternList>(*sources_assignment_filter_); } // Templates. @@ -387,15 +399,16 @@ // same one. std::string desc_string(desc_for_err); *err = Err(node_for_err, "Template collision.", - "This " + desc_string + " contains a template \"" + - current_name + "\""); - err->AppendSubErr(Err(pair.second->GetDefinitionRange(), - "defined here.", - "Which would clobber the one in your current scope")); + "This " + desc_string + " contains a template \"" + + current_name + "\""); + err->AppendSubErr( + Err(pair.second->GetDefinitionRange(), "defined here.", + "Which would clobber the one in your current scope")); err->AppendSubErr(Err(existing_template->GetDefinitionRange(), - "defined here.", - "Executing " + desc_string + " should not conflict with anything " - "in the current\nscope.")); + "defined here.", + "Executing " + desc_string + + " should not conflict with anything " + "in the current\nscope.")); return false; } } @@ -404,6 +417,10 @@ dest->templates_[current_name] = pair.second; } + // Propogate build dependency files, + dest->build_dependency_files_.insert(build_dependency_files_.begin(), + build_dependency_files_.end()); + return true; } @@ -412,14 +429,14 @@ if (const_containing_) { // We reached the top of the mutable scope stack. The result scope just // references the const scope (which will never change). - result.reset(new Scope(const_containing_)); + result = std::make_unique<Scope>(const_containing_); } else if (mutable_containing_) { // There are more nested mutable scopes. Recursively go up the stack to // get the closure. result = mutable_containing_->MakeClosure(); } else { // This is a standalone scope, just copy it. - result.reset(new Scope(settings_)); + result = std::make_unique<Scope>(settings_); } // Want to clobber since we've flattened some nested scopes, and our parent @@ -437,7 +454,7 @@ Scope* Scope::MakeTargetDefaults(const std::string& target_type) { std::unique_ptr<Scope>& dest = target_defaults_[target_type]; - dest = base::MakeUnique<Scope>(settings_); + dest = std::make_unique<Scope>(settings_); return dest.get(); } @@ -502,6 +519,10 @@ return source_dir_; } +void Scope::AddBuildDependencyFile(const SourceFile& build_dependency_file) { + build_dependency_files_.insert(build_dependency_file); +} + Scope::ItemVector* Scope::GetItemCollector() { if (item_collector_) return item_collector_;
diff --git a/tools/gn/scope.h b/tools/gn/scope.h index 8ad14ed..9e683d2 100644 --- a/tools/gn/scope.h +++ b/tools/gn/scope.h
@@ -22,6 +22,7 @@ class Item; class ParseNode; class Settings; +class SourceFile; class Template; // Scope for the script execution. @@ -284,6 +285,15 @@ const SourceDir& GetSourceDir() const; void set_source_dir(const SourceDir& d) { source_dir_ = d; } + // Set of files that may affect the execution of this scope. Note that this + // set is constructed conservatively, meanining that every file that can + // potentially affect this scope is included, but not necessarily every change + // to these files will affect this scope. + const std::set<SourceFile>& build_dependency_files() const { + return build_dependency_files_; + } + void AddBuildDependencyFile(const SourceFile& build_dependency_file); + // The item collector is where Items (Targets, Configs, etc.) go that have // been defined. If a scope can generate items, this non-owning pointer will // point to the storage for such items. The creator of this scope will be @@ -379,6 +389,8 @@ SourceDir source_dir_; + std::set<SourceFile> build_dependency_files_; + DISALLOW_COPY_AND_ASSIGN(Scope); };
diff --git a/tools/gn/scope_per_file_provider.cc b/tools/gn/scope_per_file_provider.cc index 737a5cd..a577129 100644 --- a/tools/gn/scope_per_file_provider.cc +++ b/tools/gn/scope_per_file_provider.cc
@@ -4,6 +4,8 @@ #include "tools/gn/scope_per_file_provider.h" +#include <memory> + #include "tools/gn/filesystem_utils.h" #include "tools/gn/settings.h" #include "tools/gn/source_file.h" @@ -16,8 +18,7 @@ allow_target_vars_(allow_target_vars) { } -ScopePerFileProvider::~ScopePerFileProvider() { -} +ScopePerFileProvider::~ScopePerFileProvider() = default; const Value* ScopePerFileProvider::GetProgrammaticValue( const base::StringPiece& ident) { @@ -46,77 +47,73 @@ const Value* ScopePerFileProvider::GetCurrentToolchain() { if (!current_toolchain_) { - current_toolchain_.reset(new Value( + current_toolchain_ = std::make_unique<Value>( nullptr, - scope_->settings()->toolchain_label().GetUserVisibleName(false))); + scope_->settings()->toolchain_label().GetUserVisibleName(false)); } return current_toolchain_.get(); } const Value* ScopePerFileProvider::GetDefaultToolchain() { if (!default_toolchain_) { - default_toolchain_.reset(new Value( + default_toolchain_ = std::make_unique<Value>( nullptr, scope_->settings()->default_toolchain_label().GetUserVisibleName( - false))); + false)); } return default_toolchain_.get(); } const Value* ScopePerFileProvider::GetPythonPath() { if (!python_path_) { - python_path_.reset(new Value( + python_path_ = std::make_unique<Value>( nullptr, - FilePathToUTF8(scope_->settings()->build_settings()->python_path()))); + FilePathToUTF8(scope_->settings()->build_settings()->python_path())); } return python_path_.get(); } const Value* ScopePerFileProvider::GetRootBuildDir() { if (!root_build_dir_) { - root_build_dir_.reset(new Value( + root_build_dir_ = std::make_unique<Value>( nullptr, DirectoryWithNoLastSlash( - scope_->settings()->build_settings()->build_dir()))); + scope_->settings()->build_settings()->build_dir())); } return root_build_dir_.get(); } const Value* ScopePerFileProvider::GetRootGenDir() { if (!root_gen_dir_) { - root_gen_dir_.reset(new Value( - nullptr, - DirectoryWithNoLastSlash(GetBuildDirAsSourceDir( - BuildDirContext(scope_), BuildDirType::GEN)))); + root_gen_dir_ = std::make_unique<Value>( + nullptr, DirectoryWithNoLastSlash(GetBuildDirAsSourceDir( + BuildDirContext(scope_), BuildDirType::GEN))); } return root_gen_dir_.get(); } const Value* ScopePerFileProvider::GetRootOutDir() { if (!root_out_dir_) { - root_out_dir_.reset(new Value( - nullptr, - DirectoryWithNoLastSlash(GetScopeCurrentBuildDirAsSourceDir( - scope_, BuildDirType::TOOLCHAIN_ROOT)))); + root_out_dir_ = std::make_unique<Value>( + nullptr, DirectoryWithNoLastSlash(GetScopeCurrentBuildDirAsSourceDir( + scope_, BuildDirType::TOOLCHAIN_ROOT))); } return root_out_dir_.get(); } const Value* ScopePerFileProvider::GetTargetGenDir() { if (!target_gen_dir_) { - target_gen_dir_.reset(new Value( - nullptr, - DirectoryWithNoLastSlash( - GetScopeCurrentBuildDirAsSourceDir(scope_, BuildDirType::GEN)))); + target_gen_dir_ = std::make_unique<Value>( + nullptr, DirectoryWithNoLastSlash(GetScopeCurrentBuildDirAsSourceDir( + scope_, BuildDirType::GEN))); } return target_gen_dir_.get(); } const Value* ScopePerFileProvider::GetTargetOutDir() { if (!target_out_dir_) { - target_out_dir_.reset(new Value( - nullptr, - DirectoryWithNoLastSlash( - GetScopeCurrentBuildDirAsSourceDir(scope_, BuildDirType::OBJ)))); + target_out_dir_ = std::make_unique<Value>( + nullptr, DirectoryWithNoLastSlash(GetScopeCurrentBuildDirAsSourceDir( + scope_, BuildDirType::OBJ))); } return target_out_dir_.get(); }
diff --git a/tools/gn/scope_unittest.cc b/tools/gn/scope_unittest.cc index a90d725..ce3fe0b 100644 --- a/tools/gn/scope_unittest.cc +++ b/tools/gn/scope_unittest.cc
@@ -2,10 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "tools/gn/scope.h" + #include "testing/gtest/include/gtest/gtest.h" #include "tools/gn/input_file.h" #include "tools/gn/parse_tree.h" -#include "tools/gn/scope.h" +#include "tools/gn/source_file.h" #include "tools/gn/template.h" #include "tools/gn/test_with_scope.h" @@ -22,8 +24,25 @@ return value->string_value() == expected_value; } +bool ContainsBuildDependencyFile(const Scope* scope, + const SourceFile& source_file) { + const auto& build_dependency_files = scope->build_dependency_files(); + return build_dependency_files.end() != + build_dependency_files.find(source_file); +} + } // namespace +TEST(Scope, InheritBuildDependencyFilesFromParent) { + TestWithScope setup; + SourceFile source_file = SourceFile("//a/BUILD.gn"); + setup.scope()->AddBuildDependencyFile(source_file); + + Scope new_scope(setup.scope()); + EXPECT_EQ(1U, new_scope.build_dependency_files().size()); + EXPECT_TRUE(ContainsBuildDependencyFile(&new_scope, source_file)); +} + TEST(Scope, NonRecursiveMergeTo) { TestWithScope setup; @@ -192,6 +211,24 @@ EXPECT_TRUE(new_scope.CheckForUnusedVars(&err)); EXPECT_FALSE(err.has_error()); } + + // Build dependency files are merged. + { + Scope from_scope(setup.settings()); + SourceFile source_file = SourceFile("//a/BUILD.gn"); + from_scope.AddBuildDependencyFile(source_file); + + Scope to_scope(setup.settings()); + EXPECT_FALSE(ContainsBuildDependencyFile(&to_scope, source_file)); + + Scope::MergeOptions options; + Err err; + EXPECT_TRUE(from_scope.NonRecursiveMergeTo(&to_scope, options, &assignment, + "error", &err)); + EXPECT_FALSE(err.has_error()); + EXPECT_EQ(1U, to_scope.build_dependency_files().size()); + EXPECT_TRUE(ContainsBuildDependencyFile(&to_scope, source_file)); + } } TEST(Scope, MakeClosure) {
diff --git a/tools/gn/settings.cc b/tools/gn/settings.cc index 034e601..d206f5c9 100644 --- a/tools/gn/settings.cc +++ b/tools/gn/settings.cc
@@ -31,5 +31,4 @@ toolchain_gen_dir_ = SourceDir(toolchain_output_dir_.value() + "gen/"); } -Settings::~Settings() { -} +Settings::~Settings() = default;
diff --git a/tools/gn/setup.cc b/tools/gn/setup.cc index 7fc4a2e..36b6ec5 100644 --- a/tools/gn/setup.cc +++ b/tools/gn/setup.cc
@@ -5,7 +5,9 @@ #include "tools/gn/setup.h" #include <stdlib.h> + #include <algorithm> +#include <memory> #include <sstream> #include <utility> @@ -40,7 +42,7 @@ #include <windows.h> #endif -extern const char kDotfile_Help[] = +const char kDotfile_Help[] = R"(.gn file When gn starts, it will search the current directory and parent directories @@ -295,8 +297,7 @@ loader_->set_task_runner(scheduler_.task_runner()); } -Setup::~Setup() { -} +Setup::~Setup() = default; bool Setup::DoSetup(const std::string& build_dir, bool force_create) { base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess(); @@ -324,7 +325,7 @@ if (default_args_) { Scope::KeyValueMap overrides; default_args_->GetCurrentScopeValues(&overrides); - build_settings_.build_args().AddArgOverrides(overrides); + build_settings_.build_args().AddDefaultArgOverrides(overrides); } if (fill_arguments_) { @@ -371,13 +372,14 @@ } if (!build_settings_.build_args().VerifyAllOverridesUsed(&err)) { - // TODO(brettw) implement a system to have a different marker for - // warnings. Until we have a better system, print the error but don't - // return failure unless requested on the command line. - err.PrintToStdout(); if (base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kFailOnUnusedArgs)) + switches::kFailOnUnusedArgs)) { + err.PrintToStdout(); return false; + } + err.PrintNonfatalToStdout(); + OutputString("\nThe build continued as if that argument was " + "unspecified.\n\n"); return true; } @@ -422,7 +424,7 @@ } bool Setup::FillArgsFromCommandLine(const std::string& args) { - args_input_file_.reset(new InputFile(SourceFile())); + args_input_file_ = std::make_unique<InputFile>(SourceFile()); args_input_file_->SetContents(args); args_input_file_->set_friendly_name("the command-line \"--args\""); return FillArgsFromArgsInputFile(); @@ -446,7 +448,7 @@ if (contents.empty()) return true; // Empty file, do nothing. - args_input_file_.reset(new InputFile(build_arg_source_file)); + args_input_file_ = std::make_unique<InputFile>(build_arg_source_file); args_input_file_->SetContents(contents); args_input_file_->set_friendly_name( "build arg file (use \"gn args <out_dir>\" to edit)"); @@ -486,6 +488,8 @@ Scope::KeyValueMap overrides; arg_scope.GetCurrentScopeValues(&overrides); build_settings_.build_args().AddArgOverrides(overrides); + build_settings_.build_args().set_build_args_dependency_files( + arg_scope.build_dependency_files()); return true; } @@ -667,7 +671,7 @@ if (scheduler_.verbose_logging()) scheduler_.Log("Got dotfile", FilePathToUTF8(dotfile_name_)); - dotfile_input_file_.reset(new InputFile(SourceFile("//.gn"))); + dotfile_input_file_ = std::make_unique<InputFile>(SourceFile("//.gn")); if (!dotfile_input_file_->Load(dotfile_name_)) { Err(Location(), "Could not load dotfile.", "The file \"" + FilePathToUTF8(dotfile_name_) + "\" couldn't be loaded") @@ -688,6 +692,7 @@ return false; } + dotfile_scope_.AddBuildDependencyFile(SourceFile("//.gn")); dotfile_root_->Execute(&dotfile_scope_, &err); if (err.has_error()) { err.PrintToStdout(); @@ -770,7 +775,8 @@ err.PrintToStdout(); return false; } - std::unique_ptr<std::set<SourceFile>> whitelist(new std::set<SourceFile>); + std::unique_ptr<std::set<SourceFile>> whitelist = + std::make_unique<std::set<SourceFile>>(); for (const auto& item : exec_script_whitelist_value->list_value()) { if (!item.VerifyTypeIs(Value::STRING, &err)) { err.PrintToStdout();
diff --git a/tools/gn/setup.h b/tools/gn/setup.h index 68a8f0b3..08bb11b 100644 --- a/tools/gn/setup.h +++ b/tools/gn/setup.h
@@ -44,7 +44,7 @@ // is malformed. // // With force_create = false, setup will fail if the build directory doesn't - // alreay exist with an args file in it. With force_create set to true, the + // already exist with an args file in it. With force_create set to true, the // directory will be created if necessary. Commands explicitly doing // generation should set this to true to create it, but querying commands // should set it to false to prevent creating oddly-named directories in case @@ -85,8 +85,10 @@ Builder& builder() { return builder_; } LoaderImpl* loader() { return loader_.get(); } + const SourceFile& GetDotFile() const { return dotfile_input_file_->name(); } + // Name of the file in the root build directory that contains the build - // arguements. + // arguments. static const char kBuildArgFileName[]; private:
diff --git a/tools/gn/source_dir.cc b/tools/gn/source_dir.cc index 41c8931..e8fdff0 100644 --- a/tools/gn/source_dir.cc +++ b/tools/gn/source_dir.cc
@@ -25,8 +25,7 @@ } // namespace -SourceDir::SourceDir() { -} +SourceDir::SourceDir() = default; SourceDir::SourceDir(const base::StringPiece& p) : value_(p.data(), p.size()) { @@ -42,8 +41,7 @@ AssertValueSourceDirString(value_); } -SourceDir::~SourceDir() { -} +SourceDir::~SourceDir() = default; SourceFile SourceDir::ResolveRelativeFile( const Value& p,
diff --git a/tools/gn/source_file.cc b/tools/gn/source_file.cc index 41a602d..b28c3ac 100644 --- a/tools/gn/source_file.cc +++ b/tools/gn/source_file.cc
@@ -23,8 +23,7 @@ } // namespace -SourceFile::SourceFile() { -} +SourceFile::SourceFile() = default; SourceFile::SourceFile(const base::StringPiece& p) : value_(p.data(), p.size()) { @@ -40,8 +39,7 @@ NormalizePath(&value_); } -SourceFile::~SourceFile() { -} +SourceFile::~SourceFile() = default; std::string SourceFile::GetName() const { if (is_null())
diff --git a/tools/gn/source_file.h b/tools/gn/source_file.h index 87fd590..06bbd11 100644 --- a/tools/gn/source_file.h +++ b/tools/gn/source_file.h
@@ -27,6 +27,7 @@ // Takes a known absolute source file. Always begins in a slash. explicit SourceFile(const base::StringPiece& p); + SourceFile(const SourceFile& other) = default; // Constructs from the given string by swapping in the contents of the given // value. The value will be the empty string after this call.
diff --git a/tools/gn/string_utils_unittest.cc b/tools/gn/string_utils_unittest.cc index eb021a8..3e87c77 100644 --- a/tools/gn/string_utils_unittest.cc +++ b/tools/gn/string_utils_unittest.cc
@@ -5,6 +5,8 @@ #include "tools/gn/string_utils.h" #include <stdint.h> + +#include <memory> #include <utility> #include "testing/gtest/include/gtest/gtest.h" @@ -23,8 +25,8 @@ scope.SetValue("onestring", Value(nullptr, "one"), nullptr); // Nested scope called "onescope" with a value "one" inside it. - std::unique_ptr<Scope> onescope( - new Scope(static_cast<const Settings*>(nullptr))); + std::unique_ptr<Scope> onescope = + std::make_unique<Scope>(static_cast<const Settings*>(nullptr)); onescope->SetValue("one", Value(nullptr, one), nullptr); scope.SetValue("onescope", Value(nullptr, std::move(onescope)), nullptr);
diff --git a/tools/gn/substitution_list.cc b/tools/gn/substitution_list.cc index 517f327..a0fa00f4 100644 --- a/tools/gn/substitution_list.cc +++ b/tools/gn/substitution_list.cc
@@ -9,13 +9,11 @@ #include "tools/gn/value.h" -SubstitutionList::SubstitutionList() { -} +SubstitutionList::SubstitutionList() = default; SubstitutionList::SubstitutionList(const SubstitutionList& other) = default; -SubstitutionList::~SubstitutionList() { -} +SubstitutionList::~SubstitutionList() = default; bool SubstitutionList::Parse(const Value& value, Err* err) { if (!value.VerifyTypeIs(Value::LIST, err))
diff --git a/tools/gn/substitution_pattern.cc b/tools/gn/substitution_pattern.cc index c8e54899..756200c 100644 --- a/tools/gn/substitution_pattern.cc +++ b/tools/gn/substitution_pattern.cc
@@ -22,8 +22,7 @@ literal(l) { } -SubstitutionPattern::Subrange::~Subrange() { -} +SubstitutionPattern::Subrange::~Subrange() = default; SubstitutionPattern::SubstitutionPattern() : origin_(nullptr) { } @@ -31,8 +30,7 @@ SubstitutionPattern::SubstitutionPattern(const SubstitutionPattern& other) = default; -SubstitutionPattern::~SubstitutionPattern() { -} +SubstitutionPattern::~SubstitutionPattern() = default; bool SubstitutionPattern::Parse(const Value& value, Err* err) { if (!value.VerifyTypeIs(Value::STRING, err)) @@ -79,9 +77,8 @@ // most people will not be writing substitution patterns and the code // to exactly indicate the error location is tricky. *err = Err(origin, "Unknown substitution pattern", - "Found a {{ at offset " + - base::SizeTToString(next) + - " and did not find a known substitution following it."); + "Found a {{ at offset " + base::NumberToString(next) + + " and did not find a known substitution following it."); ranges_.clear(); return false; }
diff --git a/tools/gn/substitution_writer.cc b/tools/gn/substitution_writer.cc index 50b1e2d..19a4436e 100644 --- a/tools/gn/substitution_writer.cc +++ b/tools/gn/substitution_writer.cc
@@ -584,14 +584,12 @@ if (target->output_dir().is_null()) { return ApplyPatternToLinkerAsOutputFile( target, tool, tool->default_output_dir()).value(); - } else { - SetDirOrDotWithNoSlash(RebasePath( - target->output_dir().value(), - target->settings()->build_settings()->build_dir()), - &result); - return result; } - break; + SetDirOrDotWithNoSlash(RebasePath( + target->output_dir().value(), + target->settings()->build_settings()->build_dir()), + &result); + return result; case SUBSTITUTION_OUTPUT_EXTENSION: // Use the extension provided on the target if specified, otherwise
diff --git a/tools/gn/target.cc b/tools/gn/target.cc index 7790a85..b8939bb 100644 --- a/tools/gn/target.cc +++ b/tools/gn/target.cc
@@ -235,7 +235,7 @@ ... target parameter definitions ... } - There is also a generic "target" function for programatically defined types + There is also a generic "target" function for programmatically defined types (see "gn help target"). You can define new types using templates (see "gn help template"). A template defines some custom code that expands to one or more other targets. @@ -273,8 +273,10 @@ future, do not rely on this behavior. )"; -Target::Target(const Settings* settings, const Label& label) - : Item(settings, label), +Target::Target(const Settings* settings, + const Label& label, + const std::set<SourceFile>& build_dependency_files) + : Item(settings, label, build_dependency_files), output_type_(UNKNOWN), output_prefix_override_(false), output_extension_set_(false), @@ -284,8 +286,7 @@ testonly_(false), toolchain_(nullptr) {} -Target::~Target() { -} +Target::~Target() = default; // static const char* Target::GetStringForOutputType(OutputType type) { @@ -826,8 +827,10 @@ // See Scheduler::AddUnknownGeneratedInput's declaration for more. for (const SourceFile& file : sources_) CheckSourceGenerated(file); - for (const SourceFile& file : inputs_) - CheckSourceGenerated(file); + for (ConfigValuesIterator iter(this); !iter.done(); iter.Next()) { + for (const SourceFile& file : iter.cur().inputs()) + CheckSourceGenerated(file); + } // TODO(agrieve): Check all_libs_ here as well (those that are source files). // http://crbug.com/571731 }
diff --git a/tools/gn/target.h b/tools/gn/target.h index 1890a535..b286518 100644 --- a/tools/gn/target.h +++ b/tools/gn/target.h
@@ -55,7 +55,11 @@ typedef std::vector<SourceFile> FileList; typedef std::vector<std::string> StringVector; - Target(const Settings* settings, const Label& label); + // We track the set of build files that may affect this target, please refer + // to Scope for how this is determined. + Target(const Settings* settings, + const Label& label, + const std::set<SourceFile>& build_dependency_files = {}); ~Target() override; // Returns a string naming the output type. @@ -152,10 +156,6 @@ write_runtime_deps_output_ = value; } - // Compile-time extra dependencies. - const FileList& inputs() const { return inputs_; } - FileList& inputs() { return inputs_; } - // Runtime dependencies. These are "file-like things" that can either be // directories or files. They do not need to exist, these are just passed as // runtime dependencies to external test systems as necessary. @@ -309,7 +309,7 @@ std::vector<OutputFile>* outputs) const; private: - FRIEND_TEST_ALL_PREFIXES(Target, ResolvePrecompiledHeaders); + FRIEND_TEST_ALL_PREFIXES(TargetTest, ResolvePrecompiledHeaders); // Pulls necessary information from dependencies to this one when all // dependencies have been resolved. @@ -346,7 +346,6 @@ bool check_includes_; bool complete_static_lib_; bool testonly_; - FileList inputs_; std::vector<std::string> data_; BundleData bundle_data_; OutputFile write_runtime_deps_output_; @@ -377,9 +376,9 @@ std::vector<LabelPattern> assert_no_deps_; - // Used for all binary targets. The precompiled header values in this struct - // will be resolved to the ones to use for this target, if precompiled - // headers are used. + // Used for all binary targets, and for inputs in regular targets. The + // precompiled header values in this struct will be resolved to the ones to + // use for this target, if precompiled headers are used. ConfigValues config_values_; // Used for action[_foreach] targets.
diff --git a/tools/gn/target_generator.cc b/tools/gn/target_generator.cc index d7511156..bbc9793 100644 --- a/tools/gn/target_generator.cc +++ b/tools/gn/target_generator.cc
@@ -6,6 +6,7 @@ #include <stddef.h> +#include <memory> #include <utility> #include "tools/gn/action_target_generator.h" @@ -37,8 +38,7 @@ err_(err) { } -TargetGenerator::~TargetGenerator() { -} +TargetGenerator::~TargetGenerator() = default; void TargetGenerator::Run() { // All target types use these. @@ -90,7 +90,8 @@ if (g_scheduler->verbose_logging()) g_scheduler->Log("Defining target", label.GetUserVisibleName(true)); - std::unique_ptr<Target> target(new Target(scope->settings(), label)); + std::unique_ptr<Target> target = std::make_unique<Target>( + scope->settings(), label, scope->build_dependency_files()); target->set_defined_from(function_call); // Create and call out to the proper generator. @@ -186,19 +187,6 @@ return true; } -bool TargetGenerator::FillInputs() { - const Value* value = scope_->GetValue(variables::kInputs, true); - if (!value) - return true; - - Target::FileList dest_inputs; - if (!ExtractListOfRelativeFiles(scope_->settings()->build_settings(), *value, - scope_->GetSourceDir(), &dest_inputs, err_)) - return false; - target_->inputs().swap(dest_inputs); - return true; -} - bool TargetGenerator::FillConfigs() { return FillGenericConfigs(variables::kConfigs, &target_->configs()); }
diff --git a/tools/gn/target_generator.h b/tools/gn/target_generator.h index a3bdd58..549f2cd 100644 --- a/tools/gn/target_generator.h +++ b/tools/gn/target_generator.h
@@ -49,7 +49,6 @@ bool FillSources(); bool FillPublic(); - bool FillInputs(); bool FillConfigs(); bool FillOutputs(bool allow_substitutions); bool FillCheckIncludes();
diff --git a/tools/gn/target_unittest.cc b/tools/gn/target_unittest.cc index 9ddcf37..31d3382 100644 --- a/tools/gn/target_unittest.cc +++ b/tools/gn/target_unittest.cc
@@ -4,6 +4,7 @@ #include "tools/gn/target.h" +#include <memory> #include <utility> #include "testing/gtest/include/gtest/gtest.h" @@ -11,6 +12,7 @@ #include "tools/gn/config.h" #include "tools/gn/scheduler.h" #include "tools/gn/settings.h" +#include "tools/gn/test_with_scheduler.h" #include "tools/gn/test_with_scope.h" #include "tools/gn/toolchain.h" @@ -32,9 +34,11 @@ } // namespace +using TargetTest = TestWithScheduler; + // Tests that lib[_dir]s are inherited across deps boundaries for static // libraries but not executables. -TEST(Target, LibInheritance) { +TEST_F(TargetTest, LibInheritance) { TestWithScope setup; Err err; @@ -79,7 +83,7 @@ } // Test all_dependent_configs and public_config inheritance. -TEST(Target, DependentConfigs) { +TEST_F(TargetTest, DependentConfigs) { TestWithScope setup; Err err; @@ -138,7 +142,7 @@ } // Tests that dependent configs don't propagate between toolchains. -TEST(Target, NoDependentConfigsBetweenToolchains) { +TEST_F(TargetTest, NoDependentConfigsBetweenToolchains) { TestWithScope setup; Err err; @@ -192,7 +196,7 @@ ASSERT_EQ(0u, a.all_dependent_configs().size()); } -TEST(Target, InheritLibs) { +TEST_F(TargetTest, InheritLibs) { TestWithScope setup; Err err; @@ -229,7 +233,7 @@ EXPECT_EQ(&b, a_inherited[0]); } -TEST(Target, InheritCompleteStaticLib) { +TEST_F(TargetTest, InheritCompleteStaticLib) { TestWithScope setup; Err err; @@ -270,7 +274,7 @@ EXPECT_EQ(lib_dir, a.all_lib_dirs()[0]); } -TEST(Target, InheritCompleteStaticLibStaticLibDeps) { +TEST_F(TargetTest, InheritCompleteStaticLibStaticLibDeps) { TestWithScope setup; Err err; @@ -299,7 +303,7 @@ EXPECT_EQ(&b, a_inherited[0]); } -TEST(Target, InheritCompleteStaticLibInheritedCompleteStaticLibDeps) { +TEST_F(TargetTest, InheritCompleteStaticLibInheritedCompleteStaticLibDeps) { TestWithScope setup; Err err; @@ -330,7 +334,7 @@ EXPECT_EQ(&c, a_inherited[1]); } -TEST(Target, NoActionDepPropgation) { +TEST_F(TargetTest, NoActionDepPropgation) { TestWithScope setup; Err err; @@ -355,7 +359,7 @@ } } -TEST(Target, GetComputedOutputName) { +TEST_F(TargetTest, GetComputedOutputName) { TestWithScope setup; Err err; @@ -392,7 +396,7 @@ } // Test visibility failure case. -TEST(Target, VisibilityFails) { +TEST_F(TargetTest, VisibilityFails) { TestWithScope setup; Err err; @@ -410,7 +414,7 @@ } // Test visibility with a single data_dep. -TEST(Target, VisibilityDatadeps) { +TEST_F(TargetTest, VisibilityDatadeps) { TestWithScope setup; Err err; @@ -428,7 +432,7 @@ // Tests that A -> Group -> B where the group is visible from A but B isn't, // passes visibility even though the group's deps get expanded into A. -TEST(Target, VisibilityGroup) { +TEST_F(TargetTest, VisibilityGroup) { TestWithScope setup; Err err; @@ -456,7 +460,7 @@ // Verifies that only testonly targets can depend on other testonly targets. // Many of the above dependency checking cases covered the non-testonly // case. -TEST(Target, Testonly) { +TEST_F(TargetTest, Testonly) { TestWithScope setup; Err err; @@ -478,7 +482,7 @@ ASSERT_FALSE(product.OnResolved(&err)); } -TEST(Target, PublicConfigs) { +TEST_F(TargetTest, PublicConfigs) { TestWithScope setup; Err err; @@ -518,7 +522,7 @@ } // Tests that configs are ordered properly between local and pulled ones. -TEST(Target, ConfigOrdering) { +TEST_F(TargetTest, ConfigOrdering) { TestWithScope setup; Err err; @@ -583,13 +587,13 @@ } // Tests that different link/depend outputs work for solink tools. -TEST(Target, LinkAndDepOutputs) { +TEST_F(TargetTest, LinkAndDepOutputs) { TestWithScope setup; Err err; Toolchain toolchain(setup.settings(), Label(SourceDir("//tc/"), "tc")); - std::unique_ptr<Tool> solink_tool(new Tool()); + std::unique_ptr<Tool> solink_tool = std::make_unique<Tool>(); solink_tool->set_output_prefix("lib"); solink_tool->set_default_output_extension(".so"); @@ -624,13 +628,13 @@ // Tests that runtime_outputs works without an explicit link_output for // solink tools. -TEST(Target, RuntimeOuputs) { +TEST_F(TargetTest, RuntimeOuputs) { TestWithScope setup; Err err; Toolchain toolchain(setup.settings(), Label(SourceDir("//tc/"), "tc")); - std::unique_ptr<Tool> solink_tool(new Tool()); + std::unique_ptr<Tool> solink_tool = std::make_unique<Tool>(); solink_tool->set_output_prefix(""); solink_tool->set_default_output_extension(".dll"); @@ -669,7 +673,7 @@ // Shared libraries should be inherited across public shared liobrary // boundaries. -TEST(Target, SharedInheritance) { +TEST_F(TargetTest, SharedInheritance) { TestWithScope setup; Err err; @@ -709,8 +713,7 @@ EXPECT_EQ(&pub, exe_inherited[1]); } -TEST(Target, GeneratedInputs) { - Scheduler scheduler; +TEST_F(TargetTest, GeneratedInputs) { TestWithScope setup; Err err; @@ -723,7 +726,7 @@ EXPECT_TRUE(non_existent_generator.OnResolved(&err)) << err.message(); AssertSchedulerHasOneUnknownFileMatching(&non_existent_generator, generated_file); - scheduler.ClearUnknownGeneratedInputsAndWrittenFiles(); + scheduler().ClearUnknownGeneratedInputsAndWrittenFiles(); // Make a target that generates the file. TestTarget generator(setup, "//foo:generator", Target::ACTION); @@ -739,7 +742,7 @@ existent_generator.sources().push_back(generated_file); existent_generator.private_deps().push_back(LabelTargetPair(&generator)); EXPECT_TRUE(existent_generator.OnResolved(&err)) << err.message(); - EXPECT_TRUE(scheduler.GetUnknownGeneratedInputs().empty()); + EXPECT_TRUE(scheduler().GetUnknownGeneratedInputs().empty()); // A target that depends on the previous one should *not* be allowed to // use the generated file, because existent_generator used private deps. @@ -752,7 +755,7 @@ LabelTargetPair(&existent_generator)); EXPECT_TRUE(indirect_private.OnResolved(&err)); AssertSchedulerHasOneUnknownFileMatching(&indirect_private, generated_file); - scheduler.ClearUnknownGeneratedInputsAndWrittenFiles(); + scheduler().ClearUnknownGeneratedInputsAndWrittenFiles(); // Now make a chain like the above but with all public deps, it should be OK. TestTarget existent_public(setup, "//foo:existent_public", @@ -764,12 +767,11 @@ indirect_public.sources().push_back(generated_file); indirect_public.public_deps().push_back(LabelTargetPair(&existent_public)); EXPECT_TRUE(indirect_public.OnResolved(&err)) << err.message(); - EXPECT_TRUE(scheduler.GetUnknownGeneratedInputs().empty()); + EXPECT_TRUE(scheduler().GetUnknownGeneratedInputs().empty()); } // This is sort of a Scheduler test, but is related to the above test more. -TEST(Target, WriteFileGeneratedInputs) { - Scheduler scheduler; +TEST_F(TargetTest, WriteFileGeneratedInputs) { TestWithScope setup; Err err; @@ -782,21 +784,20 @@ EXPECT_TRUE(non_existent_generator.OnResolved(&err)); AssertSchedulerHasOneUnknownFileMatching(&non_existent_generator, generated_file); - scheduler.ClearUnknownGeneratedInputsAndWrittenFiles(); + scheduler().ClearUnknownGeneratedInputsAndWrittenFiles(); // This target has a generated file and we've decared we write it. TestTarget existent_generator(setup, "//foo:existent_generator", Target::EXECUTABLE); existent_generator.sources().push_back(generated_file); EXPECT_TRUE(existent_generator.OnResolved(&err)); - scheduler.AddWrittenFile(generated_file); + scheduler().AddWrittenFile(generated_file); // Should be OK. - EXPECT_TRUE(scheduler.GetUnknownGeneratedInputs().empty()); + EXPECT_TRUE(scheduler().GetUnknownGeneratedInputs().empty()); } -TEST(Target, WriteRuntimeDepsGeneratedInputs) { - Scheduler scheduler; +TEST_F(TargetTest, WriteRuntimeDepsGeneratedInputs) { TestWithScope setup; Err err; @@ -815,14 +816,14 @@ dep_missing.sources().push_back(source_file); EXPECT_TRUE(dep_missing.OnResolved(&err)); AssertSchedulerHasOneUnknownFileMatching(&dep_missing, source_file); - scheduler.ClearUnknownGeneratedInputsAndWrittenFiles(); + scheduler().ClearUnknownGeneratedInputsAndWrittenFiles(); // This target has a generated file and we've directly dependended on it. TestTarget dep_present(setup, "//foo:with_dep", Target::EXECUTABLE); dep_present.sources().push_back(source_file); dep_present.private_deps().push_back(LabelTargetPair(&generator)); EXPECT_TRUE(dep_present.OnResolved(&err)); - EXPECT_TRUE(scheduler.GetUnknownGeneratedInputs().empty()); + EXPECT_TRUE(scheduler().GetUnknownGeneratedInputs().empty()); // This target has a generated file and we've indirectly dependended on it // via data_deps. @@ -831,7 +832,7 @@ dep_indirect.data_deps().push_back(LabelTargetPair(&middle_data_dep)); EXPECT_TRUE(dep_indirect.OnResolved(&err)); AssertSchedulerHasOneUnknownFileMatching(&dep_indirect, source_file); - scheduler.ClearUnknownGeneratedInputsAndWrittenFiles(); + scheduler().ClearUnknownGeneratedInputsAndWrittenFiles(); // This target has a generated file and we've directly dependended on it // via data_deps. @@ -839,15 +840,14 @@ data_dep_present.sources().push_back(source_file); data_dep_present.data_deps().push_back(LabelTargetPair(&generator)); EXPECT_TRUE(data_dep_present.OnResolved(&err)); - EXPECT_TRUE(scheduler.GetUnknownGeneratedInputs().empty()); + EXPECT_TRUE(scheduler().GetUnknownGeneratedInputs().empty()); } // Tests that intermediate object files generated by binary targets are also // considered generated for the purposes of input checking. Above, we tested // the failure cases for generated inputs, so here only test .o files that are // present. -TEST(Target, ObjectGeneratedInputs) { - Scheduler scheduler; +TEST_F(TargetTest, ObjectGeneratedInputs) { TestWithScope setup; Err err; @@ -861,13 +861,13 @@ SourceFile object_file("//out/Debug/obj/source_target.source.o"); TestTarget final_target(setup, "//:final", Target::ACTION); - final_target.inputs().push_back(object_file); + final_target.config_values().inputs().push_back(object_file); EXPECT_TRUE(final_target.OnResolved(&err)); AssertSchedulerHasOneUnknownFileMatching(&final_target, object_file); } -TEST(Target, ResolvePrecompiledHeaders) { +TEST_F(TargetTest, ResolvePrecompiledHeaders) { TestWithScope setup; Err err; @@ -885,7 +885,7 @@ ASSERT_TRUE(config_1.OnResolved(&err)); target.configs().push_back(LabelConfigPair(&config_1)); - // No PCH info specified on target, but the config specifies one, the + // No PCH info specified on TargetTest, but the config specifies one, the // values should get copied to the target. EXPECT_TRUE(target.ResolvePrecompiledHeaders(&err)); EXPECT_EQ(pch_1, target.config_values().precompiled_header()); @@ -924,7 +924,7 @@ err.help_text()); } -TEST(Target, AssertNoDeps) { +TEST_F(TargetTest, AssertNoDeps) { TestWithScope setup; Err err; @@ -979,7 +979,7 @@ ASSERT_TRUE(a2.OnResolved(&err)); } -TEST(Target, PullRecursiveBundleData) { +TEST_F(TargetTest, PullRecursiveBundleData) { TestWithScope setup; Err err;
diff --git a/tools/gn/template.cc b/tools/gn/template.cc index 66d6745..ad28680 100644 --- a/tools/gn/template.cc +++ b/tools/gn/template.cc
@@ -4,6 +4,7 @@ #include "tools/gn/template.h" +#include <memory> #include <utility> #include "tools/gn/err.h" @@ -22,8 +23,7 @@ Template::Template(std::unique_ptr<Scope> scope, const FunctionCallNode* def) : closure_(std::move(scope)), definition_(def) {} -Template::~Template() { -} +Template::~Template() = default; Value Template::Invoke(Scope* scope, const FunctionCallNode* invocation, @@ -38,7 +38,7 @@ // First run the invocation's block. Need to allocate the scope on the heap // so we can pass ownership to the template. - std::unique_ptr<Scope> invocation_scope(new Scope(scope)); + std::unique_ptr<Scope> invocation_scope = std::make_unique<Scope>(scope); if (!FillTargetBlockScope(scope, invocation, template_name, block, args, invocation_scope.get(), err)) return Value();
diff --git a/tools/gn/template.h b/tools/gn/template.h index da5a1a45..6386ba9 100644 --- a/tools/gn/template.h +++ b/tools/gn/template.h
@@ -21,7 +21,7 @@ // includes a closure and the code to run when the template is invoked. // // This class is immutable so we can reference it from multiple threads without -// locking. Normally, this will be assocated with a .gni file and then a +// locking. Normally, this will be associated with a .gni file and then a // reference will be taken by each .gn file that imports it. These files might // execute the template in parallel. class Template : public base::RefCountedThreadSafe<Template> { @@ -52,7 +52,15 @@ Template(); ~Template(); - std::unique_ptr<Scope> closure_; + // It's important that this Scope is const. A template can be referenced by + // the root BUILDCONFIG file and then duplicated to all threads. Therefore, + // this scope must be usable from multiple threads at the same time. + // + // When executing a template, a new scope will be created as a child of this + // one, which will reference it as mutable or not according to the mutability + // of this value. + std::unique_ptr<const Scope> closure_; + const FunctionCallNode* definition_; };
diff --git a/tools/gn/test_with_scheduler.cc b/tools/gn/test_with_scheduler.cc new file mode 100644 index 0000000..ce7a90c --- /dev/null +++ b/tools/gn/test_with_scheduler.cc
@@ -0,0 +1,8 @@ +// Copyright 2018 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 "tools/gn/test_with_scheduler.h" + +TestWithScheduler::TestWithScheduler() = default; +TestWithScheduler::~TestWithScheduler() = default;
diff --git a/tools/gn/test_with_scheduler.h b/tools/gn/test_with_scheduler.h new file mode 100644 index 0000000..230f69e5 --- /dev/null +++ b/tools/gn/test_with_scheduler.h
@@ -0,0 +1,27 @@ +// Copyright 2018 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. + +#ifndef TOOLS_GN_TEST_WITH_SCHEDULER_H_ +#define TOOLS_GN_TEST_WITH_SCHEDULER_H_ + +#include "base/macros.h" +#include "base/test/scoped_task_environment.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "tools/gn/scheduler.h" + +class TestWithScheduler : public testing::Test { + protected: + TestWithScheduler(); + ~TestWithScheduler() override; + + Scheduler& scheduler() { return scheduler_; } + + private: + base::test::ScopedTaskEnvironment scoped_task_environment_; + Scheduler scheduler_; + + DISALLOW_COPY_AND_ASSIGN(TestWithScheduler); +}; + +#endif // TOOLS_GN_TEST_WITH_SCHEDULER_H_
diff --git a/tools/gn/test_with_scope.cc b/tools/gn/test_with_scope.cc index b239c640..c834e7c74 100644 --- a/tools/gn/test_with_scope.cc +++ b/tools/gn/test_with_scope.cc
@@ -4,6 +4,7 @@ #include "tools/gn/test_with_scope.h" +#include <memory> #include <utility> #include "base/bind.h" @@ -36,8 +37,7 @@ scope_.set_item_collector(&items_); } -TestWithScope::~TestWithScope() { -} +TestWithScope::~TestWithScope() = default; Label TestWithScope::ParseLabel(const std::string& str) const { Err err; @@ -74,7 +74,7 @@ Err err; // CC - std::unique_ptr<Tool> cc_tool(new Tool); + std::unique_ptr<Tool> cc_tool = std::make_unique<Tool>(); SetCommandForTool( "cc {{source}} {{cflags}} {{cflags_c}} {{defines}} {{include_dirs}} " "-o {{output}}", @@ -84,7 +84,7 @@ toolchain->SetTool(Toolchain::TYPE_CC, std::move(cc_tool)); // CXX - std::unique_ptr<Tool> cxx_tool(new Tool); + std::unique_ptr<Tool> cxx_tool = std::make_unique<Tool>(); SetCommandForTool( "c++ {{source}} {{cflags}} {{cflags_cc}} {{defines}} {{include_dirs}} " "-o {{output}}", @@ -94,7 +94,7 @@ toolchain->SetTool(Toolchain::TYPE_CXX, std::move(cxx_tool)); // OBJC - std::unique_ptr<Tool> objc_tool(new Tool); + std::unique_ptr<Tool> objc_tool = std::make_unique<Tool>(); SetCommandForTool( "objcc {{source}} {{cflags}} {{cflags_objc}} {{defines}} " "{{include_dirs}} -o {{output}}", @@ -104,7 +104,7 @@ toolchain->SetTool(Toolchain::TYPE_OBJC, std::move(objc_tool)); // OBJC - std::unique_ptr<Tool> objcxx_tool(new Tool); + std::unique_ptr<Tool> objcxx_tool = std::make_unique<Tool>(); SetCommandForTool( "objcxx {{source}} {{cflags}} {{cflags_objcc}} {{defines}} " "{{include_dirs}} -o {{output}}", @@ -116,7 +116,7 @@ // Don't use RC and ASM tools in unit tests yet. Add here if needed. // ALINK - std::unique_ptr<Tool> alink_tool(new Tool); + std::unique_ptr<Tool> alink_tool = std::make_unique<Tool>(); SetCommandForTool("ar {{output}} {{source}}", alink_tool.get()); alink_tool->set_lib_switch("-l"); alink_tool->set_lib_dir_switch("-L"); @@ -126,7 +126,7 @@ toolchain->SetTool(Toolchain::TYPE_ALINK, std::move(alink_tool)); // SOLINK - std::unique_ptr<Tool> solink_tool(new Tool); + std::unique_ptr<Tool> solink_tool = std::make_unique<Tool>(); SetCommandForTool("ld -shared -o {{target_output_name}}.so {{inputs}} " "{{ldflags}} {{libs}}", solink_tool.get()); solink_tool->set_lib_switch("-l"); @@ -138,7 +138,7 @@ toolchain->SetTool(Toolchain::TYPE_SOLINK, std::move(solink_tool)); // SOLINK_MODULE - std::unique_ptr<Tool> solink_module_tool(new Tool); + std::unique_ptr<Tool> solink_module_tool = std::make_unique<Tool>(); SetCommandForTool("ld -bundle -o {{target_output_name}}.so {{inputs}} " "{{ldflags}} {{libs}}", solink_module_tool.get()); solink_module_tool->set_lib_switch("-l"); @@ -151,7 +151,7 @@ std::move(solink_module_tool)); // LINK - std::unique_ptr<Tool> link_tool(new Tool); + std::unique_ptr<Tool> link_tool = std::make_unique<Tool>(); SetCommandForTool("ld -o {{target_output_name}} {{source}} " "{{ldflags}} {{libs}}", link_tool.get()); link_tool->set_lib_switch("-l"); @@ -161,23 +161,23 @@ toolchain->SetTool(Toolchain::TYPE_LINK, std::move(link_tool)); // STAMP - std::unique_ptr<Tool> stamp_tool(new Tool); + std::unique_ptr<Tool> stamp_tool = std::make_unique<Tool>(); SetCommandForTool("touch {{output}}", stamp_tool.get()); toolchain->SetTool(Toolchain::TYPE_STAMP, std::move(stamp_tool)); // COPY - std::unique_ptr<Tool> copy_tool(new Tool); + std::unique_ptr<Tool> copy_tool = std::make_unique<Tool>(); SetCommandForTool("cp {{source}} {{output}}", copy_tool.get()); toolchain->SetTool(Toolchain::TYPE_COPY, std::move(copy_tool)); // COPY_BUNDLE_DATA - std::unique_ptr<Tool> copy_bundle_data_tool(new Tool); + std::unique_ptr<Tool> copy_bundle_data_tool = std::make_unique<Tool>(); SetCommandForTool("cp {{source}} {{output}}", copy_bundle_data_tool.get()); toolchain->SetTool(Toolchain::TYPE_COPY_BUNDLE_DATA, std::move(copy_bundle_data_tool)); // COMPILE_XCASSETS - std::unique_ptr<Tool> compile_xcassets_tool(new Tool); + std::unique_ptr<Tool> compile_xcassets_tool = std::make_unique<Tool>(); SetCommandForTool("touch {{output}}", compile_xcassets_tool.get()); toolchain->SetTool(Toolchain::TYPE_COMPILE_XCASSETS, std::move(compile_xcassets_tool)); @@ -208,8 +208,7 @@ parsed_ = Parser::Parse(tokens_, &parse_err_); } -TestParseInput::~TestParseInput() { -} +TestParseInput::~TestParseInput() = default; TestTarget::TestTarget(const TestWithScope& setup, const std::string& label_string, @@ -220,5 +219,4 @@ SetToolchain(setup.toolchain()); } -TestTarget::~TestTarget() { -} +TestTarget::~TestTarget() = default;
diff --git a/tools/gn/tokenizer.cc b/tools/gn/tokenizer.cc index 0568bec..306f626 100644 --- a/tools/gn/tokenizer.cc +++ b/tools/gn/tokenizer.cc
@@ -77,8 +77,7 @@ column_number_(1) { } -Tokenizer::~Tokenizer() { -} +Tokenizer::~Tokenizer() = default; // static std::vector<Token> Tokenizer::Tokenize(const InputFile* input_file, Err* err) { @@ -357,7 +356,7 @@ return false; // Check for escaping. \" is not a string terminator, but \\" is. Count - // the number of preceeding backslashes. + // the number of preceding backslashes. int num_backslashes = 0; for (int i = static_cast<int>(cur_) - 1; i >= 0 && input_[i] == '\\'; i--) num_backslashes++;
diff --git a/tools/gn/tool.cc b/tools/gn/tool.cc index 2c955b8..31fb668 100644 --- a/tools/gn/tool.cc +++ b/tools/gn/tool.cc
@@ -12,8 +12,7 @@ complete_(false) { } -Tool::~Tool() { -} +Tool::~Tool() = default; void Tool::SetComplete() { DCHECK(!complete_);
diff --git a/tools/gn/toolchain.cc b/tools/gn/toolchain.cc index e54323c2..879acd94 100644 --- a/tools/gn/toolchain.cc +++ b/tools/gn/toolchain.cc
@@ -28,11 +28,12 @@ const char* Toolchain::kToolCompileXCAssets = "compile_xcassets"; const char* Toolchain::kToolAction = "action"; -Toolchain::Toolchain(const Settings* settings, const Label& label) - : Item(settings, label), setup_complete_(false) {} +Toolchain::Toolchain(const Settings* settings, + const Label& label, + const std::set<SourceFile>& build_dependency_files) + : Item(settings, label, build_dependency_files), setup_complete_(false) {} -Toolchain::~Toolchain() { -} +Toolchain::~Toolchain() = default; Toolchain* Toolchain::AsToolchain() { return this;
diff --git a/tools/gn/toolchain.h b/tools/gn/toolchain.h index 368c2db..1e9bc2e 100644 --- a/tools/gn/toolchain.h +++ b/tools/gn/toolchain.h
@@ -77,7 +77,12 @@ // Loader::GetToolchainSettings(). Many toolchain objects may be created in a // given build, but only a few might be used, and the Loader is in charge of // this process. - Toolchain(const Settings* settings, const Label& label); + // + // We also track the set of build files that may affect this target, please + // refer to Scope for how this is determined. + Toolchain(const Settings* settings, + const Label& label, + const std::set<SourceFile>& build_dependency_files = {}); ~Toolchain() override; // Item overrides.
diff --git a/tools/gn/trace.cc b/tools/gn/trace.cc index 74a3e71..f290613 100644 --- a/tools/gn/trace.cc +++ b/tools/gn/trace.cc
@@ -121,8 +121,7 @@ thread_id_(thread_id) { } -TraceItem::~TraceItem() { -} +TraceItem::~TraceItem() = default; ScopedTrace::ScopedTrace(TraceItem::Type t, const std::string& name) : item_(nullptr), done_(false) {
diff --git a/tools/gn/value.cc b/tools/gn/value.cc index 0afbc7d..f92c885 100644 --- a/tools/gn/value.cc +++ b/tools/gn/value.cc
@@ -75,8 +75,7 @@ Value::Value(Value&& other) noexcept = default; -Value::~Value() { -} +Value::~Value() = default; Value& Value::operator=(const Value& other) { type_ = other.type_;
diff --git a/tools/gn/value.h b/tools/gn/value.h index 3103509b..13beb6fd 100644 --- a/tools/gn/value.h +++ b/tools/gn/value.h
@@ -120,8 +120,8 @@ private: // This are a lot of objects associated with every Value that need // initialization and tear down every time. It might be more efficient to - // create a union of ManualConstructor objects (see small_map) and only - // use the one we care about. + // create a union of objects (see small_map) and only use the one we care + // about. Type type_; std::string string_value_; bool boolean_value_;
diff --git a/tools/gn/variables.cc b/tools/gn/variables.cc index 582e3b6..80c6b360 100644 --- a/tools/gn/variables.cc +++ b/tools/gn/variables.cc
@@ -383,23 +383,23 @@ // Target variables ------------------------------------------------------------ -#define COMMON_ORDERING_HELP \ - "\n" \ - "Ordering of flags and values\n" \ - "\n" \ - " 1. Those set on the current target (not in a config).\n" \ - " 2. Those set on the \"configs\" on the target in order that the\n" \ - " configs appear in the list.\n" \ - " 3. Those set on the \"all_dependent_configs\" on the target in order\n" \ - " that the configs appear in the list.\n" \ - " 4. Those set on the \"public_configs\" on the target in order that\n" \ - " those configs appear in the list.\n" \ - " 5. all_dependent_configs pulled from dependencies, in the order of\n" \ - " the \"deps\" list. This is done recursively. If a config appears\n" \ - " more than once, only the first occurance will be used.\n" \ - " 6. public_configs pulled from dependencies, in the order of the\n" \ - " \"deps\" list. If a dependency is public, they will be applied\n" \ - " recursively.\n" +#define COMMON_ORDERING_HELP \ + "\n" \ + "Ordering of flags and values\n" \ + "\n" \ + " 1. Those set on the current target (not in a config).\n" \ + " 2. Those set on the \"configs\" on the target in order that the\n" \ + " configs appear in the list.\n" \ + " 3. Those set on the \"all_dependent_configs\" on the target in order\n" \ + " that the configs appear in the list.\n" \ + " 4. Those set on the \"public_configs\" on the target in order that\n" \ + " those configs appear in the list.\n" \ + " 5. all_dependent_configs pulled from dependencies, in the order of\n" \ + " the \"deps\" list. This is done recursively. If a config appears\n" \ + " more than once, only the first occurence will be used.\n" \ + " 6. public_configs pulled from dependencies, in the order of the\n" \ + " \"deps\" list. If a dependency is public, they will be applied\n" \ + " recursively.\n" const char kAllDependentConfigs[] = "all_dependent_configs"; const char kAllDependentConfigs_HelpShort[] = @@ -972,7 +972,7 @@ However, no verification is done on these so GN doesn't enforce this. The paths are just rebased and passed along when requested. - Note: On iOS and OS X, create_bundle targets will not be recursed into when + Note: On iOS and macOS, create_bundle targets will not be recursed into when gathering data. See "gn help create_bundle" for details. See "gn help runtime_deps" for how these are used. @@ -993,7 +993,7 @@ This is normally used for things like plugins or helper programs that a target needs at runtime. - Note: On iOS and OS X, create_bundle targets will not be recursed into when + Note: On iOS and macOS, create_bundle targets will not be recursed into when gathering data_deps. See "gn help create_bundle" for details. See also "gn help deps" and "gn help data". @@ -1074,7 +1074,7 @@ A list of target labels. Specifies private dependencies of a target. Private dependencies are - propagated up the dependency tree and linked to dependant targets, but do not + propagated up the dependency tree and linked to dependent targets, but do not grant the ability to include headers from the dependency. Public configs are not forwarded. @@ -1087,7 +1087,7 @@ Executables, shared libraries, and complete static libraries will link all propagated targets and stop propagation. Actions and copy steps also stop propagation, allowing them to take a library as an input but not force - dependants to link to it. + dependents to link to it. Propagation of all_dependent_configs and public_configs happens independently of target type. all_dependent_configs are always propagated across all types @@ -1278,14 +1278,14 @@ System libraries Values not containing '/' will be treated as system library names. These will be passed unmodified to the linker and prefixed with the - "lib_prefix" attribute of the linker tool. Generally you would set the + "lib_switch" attribute of the linker tool. Generally you would set the "lib_dirs" so the given library is found. Your BUILD.gn file should not - specify the switch (like "-l"): this will be encoded in the "lib_prefix" + specify the switch (like "-l"): this will be encoded in the "lib_switch" of the tool. Apple frameworks System libraries ending in ".framework" will be special-cased: the switch - "-framework" will be prepended instead of the lib_prefix, and the + "-framework" will be prepended instead of the lib_switch, and the ".framework" suffix will be trimmed. This is to support the way Mac links framework dependencies. )" @@ -1759,7 +1759,7 @@ As a special case, a file ending in ".def" will be treated as a Windows module definition file. It will be appended to the link line with a - preceeding "/DEF:" string. There must be at most one .def file in a target + preceding "/DEF:" string. There must be at most one .def file in a target and they do not cross dependency boundaries (so specifying a .def file in a static library or source set will have no effect on the executable or shared library they're linked into).
diff --git a/tools/gn/visibility.cc b/tools/gn/visibility.cc index b32586ce..38d1b33 100644 --- a/tools/gn/visibility.cc +++ b/tools/gn/visibility.cc
@@ -4,7 +4,8 @@ #include "tools/gn/visibility.h" -#include "base/memory/ptr_util.h" +#include <memory> + #include "base/strings/string_piece.h" #include "base/strings/string_util.h" #include "base/values.h" @@ -16,11 +17,9 @@ #include "tools/gn/value.h" #include "tools/gn/variables.h" -Visibility::Visibility() { -} +Visibility::Visibility() = default; -Visibility::~Visibility() { -} +Visibility::~Visibility() = default; bool Visibility::Set(const SourceDir& current_dir, const Value& value, @@ -86,11 +85,10 @@ } std::unique_ptr<base::Value> Visibility::AsValue() const { - auto* res = new base::ListValue(); + auto res = std::make_unique<base::ListValue>(); for (const auto& pattern : patterns_) res->AppendString(pattern.Describe()); - - return WrapUnique(res); + return res; } // static
diff --git a/tools/gn/visual_studio_writer.cc b/tools/gn/visual_studio_writer.cc index 9f72a6f..a8fe041 100644 --- a/tools/gn/visual_studio_writer.cc +++ b/tools/gn/visual_studio_writer.cc
@@ -8,10 +8,10 @@ #include <iterator> #include <map> #include <memory> -#include <queue> #include <set> #include <string> +#include "base/containers/queue.h" #include "base/logging.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" @@ -79,7 +79,7 @@ const char kVersionStringVs2015[] = "Visual Studio 2015"; // Visual Studio 2015 const char kVersionStringVs2017[] = "Visual Studio 2017"; // Visual Studio 2017 const char kWindowsKitsVersion[] = "10"; // Windows 10 SDK -const char kWindowsKitsDefaultVersion[] = "10.0.14393.0"; // Windows 10 SDK +const char kWindowsKitsDefaultVersion[] = "10.0.15063.0"; // Windows 10 SDK const char kGuidTypeProject[] = "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}"; const char kGuidTypeFolder[] = "{2150E333-8FDC-42A3-9474-1A3956D46DE8}"; @@ -205,7 +205,7 @@ return true; std::set<Label> labels; - std::queue<const Target*> to_process; + base::queue<const Target*> to_process; for (const Target* target : *targets) { labels.insert(target->label()); to_process.push(target); @@ -306,8 +306,7 @@ windows_kits_include_dirs_ = GetWindowsKitsIncludeDirs(win_kit); } -VisualStudioWriter::~VisualStudioWriter() { -} +VisualStudioWriter::~VisualStudioWriter() = default; // static bool VisualStudioWriter::RunAndWriteFiles(const BuildSettings* build_settings, @@ -316,6 +315,7 @@ const std::string& sln_name, const std::string& filters, const std::string& win_sdk, + const std::string& ninja_extra_args, bool no_deps, Err* err) { std::vector<const Target*> targets; @@ -351,7 +351,7 @@ continue; } - if (!writer.WriteProjectFiles(target, err)) + if (!writer.WriteProjectFiles(target, ninja_extra_args, err)) return false; } @@ -372,7 +372,9 @@ return writer.WriteSolutionFile(sln_name, err); } -bool VisualStudioWriter::WriteProjectFiles(const Target* target, Err* err) { +bool VisualStudioWriter::WriteProjectFiles(const Target* target, + const std::string& ninja_extra_args, + Err* err) { std::string project_name = target->label().name(); const char* project_config_platform = config_platform_; if (!target->settings()->is_default()) { @@ -394,7 +396,7 @@ base::FilePath vcxproj_path = build_settings_->GetFullPath(target_file); std::string vcxproj_path_str = FilePathToUTF8(vcxproj_path); - projects_.emplace_back(new SolutionProject( + projects_.push_back(std::make_unique<SolutionProject>( project_name, vcxproj_path_str, MakeGuid(vcxproj_path_str, kGuidSeedProject), FilePathToUTF8(build_settings_->GetFullPath(target->label().dir())), @@ -403,7 +405,7 @@ std::stringstream vcxproj_string_out; SourceFileCompileTypePairs source_types; if (!WriteProjectFileContents(vcxproj_string_out, *projects_.back(), target, - &source_types, err)) { + ninja_extra_args, &source_types, err)) { projects_.pop_back(); return false; } @@ -424,6 +426,7 @@ std::ostream& out, const SolutionProject& solution_project, const Target* target, + const std::string& ninja_extra_args, SourceFileCompileTypePairs* source_types, Err* err) { PathOutput path_output( @@ -509,6 +512,8 @@ project.SubElement("PropertyGroup", XmlAttributes("Label", "UserMacros")); + std::string ninja_target = GetNinjaTarget(target); + { std::unique_ptr<XmlElementWriter> properties = project.SubElement("PropertyGroup"); @@ -521,8 +526,7 @@ } properties->SubElement("TargetName")->Text("$(ProjectName)"); if (target->output_type() != Target::GROUP) { - properties->SubElement("TargetPath") - ->Text("$(OutDir)\\$(ProjectName)$(TargetExt)"); + properties->SubElement("TargetPath")->Text("$(OutDir)\\" + ninja_target); } } @@ -611,6 +615,7 @@ std::unique_ptr<XmlElementWriter> build = group->SubElement( compile_type, "Include", SourceFileWriter(path_output, file)); build->SubElement("Command")->Text("call ninja.exe -C $(OutDir) " + + ninja_extra_args + " " + tool_outputs[0].value()); build->SubElement("Outputs")->Text("$(OutDir)" + tool_outputs[0].value()); @@ -632,14 +637,13 @@ "$(VCTargetsPath)\\BuildCustomizations\\masm.targets")); project.SubElement("ImportGroup", XmlAttributes("Label", "ExtensionTargets")); - std::string ninja_target = GetNinjaTarget(target); - { std::unique_ptr<XmlElementWriter> build = project.SubElement("Target", XmlAttributes("Name", "Build")); build->SubElement( - "Exec", XmlAttributes("Command", - "call ninja.exe -C $(OutDir) " + ninja_target)); + "Exec", + XmlAttributes("Command", "call ninja.exe -C $(OutDir) " + + ninja_extra_args + " " + ninja_target)); } { @@ -811,9 +815,9 @@ project->parent_folder = it->second; } else { std::string folder_path_str = folder_path.as_string(); - std::unique_ptr<SolutionEntry> folder(new SolutionEntry( + std::unique_ptr<SolutionEntry> folder = std::make_unique<SolutionEntry>( FindLastDirComponent(SourceDir(folder_path)).as_string(), - folder_path_str, MakeGuid(folder_path_str, kGuidSeedFolder))); + folder_path_str, MakeGuid(folder_path_str, kGuidSeedFolder)); project->parent_folder = folder.get(); processed_paths[folder_path] = folder.get(); folders_.push_back(std::move(folder)); @@ -856,10 +860,11 @@ if (it != processed_paths.end()) { folder = it->second; } else { - std::unique_ptr<SolutionEntry> new_folder(new SolutionEntry( - FindLastDirComponent(SourceDir(parent_path)).as_string(), - parent_path.as_string(), - MakeGuid(parent_path.as_string(), kGuidSeedFolder))); + std::unique_ptr<SolutionEntry> new_folder = + std::make_unique<SolutionEntry>( + FindLastDirComponent(SourceDir(parent_path)).as_string(), + parent_path.as_string(), + MakeGuid(parent_path.as_string(), kGuidSeedFolder)); processed_paths[parent_path] = new_folder.get(); folder = new_folder.get(); additional_folders.push_back(std::move(new_folder));
diff --git a/tools/gn/visual_studio_writer.h b/tools/gn/visual_studio_writer.h index db2f3ea..d9bb883 100644 --- a/tools/gn/visual_studio_writer.h +++ b/tools/gn/visual_studio_writer.h
@@ -45,6 +45,7 @@ const std::string& sln_name, const std::string& filters, const std::string& win_sdk, + const std::string& ninja_extra_args, bool no_deps, Err* err); @@ -104,10 +105,13 @@ const std::string& win_kit); ~VisualStudioWriter(); - bool WriteProjectFiles(const Target* target, Err* err); + bool WriteProjectFiles(const Target* target, + const std::string& ninja_extra_args, + Err* err); bool WriteProjectFileContents(std::ostream& out, const SolutionProject& solution_project, const Target* target, + const std::string& ninja_extra_args, SourceFileCompileTypePairs* source_types, Err* err); void WriteFiltersFileContents(std::ostream& out,
diff --git a/tools/gn/visual_studio_writer_unittest.cc b/tools/gn/visual_studio_writer_unittest.cc index 1ad7c61c..b924182 100644 --- a/tools/gn/visual_studio_writer_unittest.cc +++ b/tools/gn/visual_studio_writer_unittest.cc
@@ -4,6 +4,8 @@ #include "tools/gn/visual_studio_writer.h" +#include <memory> + #include "base/strings/string_util.h" #include "testing/gtest/include/gtest/gtest.h" #include "tools/gn/test_with_scope.h" @@ -29,28 +31,32 @@ TEST_F(VisualStudioWriterTest, ResolveSolutionFolders) { VisualStudioWriter writer(setup_.build_settings(), "Win32", VisualStudioWriter::Version::Vs2015, - "10.0.14393.0"); + "10.0.15063.0"); std::string path = MakeTestPath("/foo/chromium/src/out/Debug/obj/base/base.vcxproj"); - writer.projects_.emplace_back(new VisualStudioWriter::SolutionProject( - "base", path, MakeGuid(path, "project"), - MakeTestPath("/foo/chromium/src/base"), "Win32")); + writer.projects_.push_back( + std::make_unique<VisualStudioWriter::SolutionProject>( + "base", path, MakeGuid(path, "project"), + MakeTestPath("/foo/chromium/src/base"), "Win32")); path = MakeTestPath("/foo/chromium/src/out/Debug/obj/tools/gn/gn.vcxproj"); - writer.projects_.emplace_back(new VisualStudioWriter::SolutionProject( - "gn", path, MakeGuid(path, "project"), - MakeTestPath("/foo/chromium/src/tools/gn"), "Win32")); + writer.projects_.push_back( + std::make_unique<VisualStudioWriter::SolutionProject>( + "gn", path, MakeGuid(path, "project"), + MakeTestPath("/foo/chromium/src/tools/gn"), "Win32")); path = MakeTestPath("/foo/chromium/src/out/Debug/obj/chrome/chrome.vcxproj"); - writer.projects_.emplace_back(new VisualStudioWriter::SolutionProject( - "chrome", path, MakeGuid(path, "project"), - MakeTestPath("/foo/chromium/src/chrome"), "Win32")); + writer.projects_.push_back( + std::make_unique<VisualStudioWriter::SolutionProject>( + "chrome", path, MakeGuid(path, "project"), + MakeTestPath("/foo/chromium/src/chrome"), "Win32")); path = MakeTestPath("/foo/chromium/src/out/Debug/obj/base/bar.vcxproj"); - writer.projects_.emplace_back(new VisualStudioWriter::SolutionProject( - "bar", path, MakeGuid(path, "project"), - MakeTestPath("/foo/chromium/src/base"), "Win32")); + writer.projects_.push_back( + std::make_unique<VisualStudioWriter::SolutionProject>( + "bar", path, MakeGuid(path, "project"), + MakeTestPath("/foo/chromium/src/base"), "Win32")); writer.ResolveSolutionFolders(); @@ -84,24 +90,27 @@ TEST_F(VisualStudioWriterTest, ResolveSolutionFolders_AbsPath) { VisualStudioWriter writer(setup_.build_settings(), "Win32", VisualStudioWriter::Version::Vs2015, - "10.0.14393.0"); + "10.0.15063.0"); std::string path = MakeTestPath("/foo/chromium/src/out/Debug/obj/base/base.vcxproj"); - writer.projects_.emplace_back(new VisualStudioWriter::SolutionProject( - "base", path, MakeGuid(path, "project"), - MakeTestPath("/foo/chromium/src/base"), "Win32")); + writer.projects_.push_back( + std::make_unique<VisualStudioWriter::SolutionProject>( + "base", path, MakeGuid(path, "project"), + MakeTestPath("/foo/chromium/src/base"), "Win32")); path = MakeTestPath("/foo/chromium/src/out/Debug/obj/tools/gn/gn.vcxproj"); - writer.projects_.emplace_back(new VisualStudioWriter::SolutionProject( - "gn", path, MakeGuid(path, "project"), - MakeTestPath("/foo/chromium/src/tools/gn"), "Win32")); + writer.projects_.push_back( + std::make_unique<VisualStudioWriter::SolutionProject>( + "gn", path, MakeGuid(path, "project"), + MakeTestPath("/foo/chromium/src/tools/gn"), "Win32")); path = MakeTestPath( "/foo/chromium/src/out/Debug/obj/ABS_PATH/C/foo/bar/bar.vcxproj"); - writer.projects_.emplace_back(new VisualStudioWriter::SolutionProject( - "bar", path, MakeGuid(path, "project"), MakeTestPath("/foo/bar"), - "Win32")); + writer.projects_.push_back( + std::make_unique<VisualStudioWriter::SolutionProject>( + "bar", path, MakeGuid(path, "project"), MakeTestPath("/foo/bar"), + "Win32")); std::string baz_label_dir_path = MakeTestPath("/foo/bar/baz"); #if defined(OS_WIN) @@ -110,8 +119,9 @@ #endif path = MakeTestPath( "/foo/chromium/src/out/Debug/obj/ABS_PATH/C/foo/bar/baz/baz.vcxproj"); - writer.projects_.emplace_back(new VisualStudioWriter::SolutionProject( - "baz", path, MakeGuid(path, "project"), baz_label_dir_path, "Win32")); + writer.projects_.push_back( + std::make_unique<VisualStudioWriter::SolutionProject>( + "baz", path, MakeGuid(path, "project"), baz_label_dir_path, "Win32")); writer.ResolveSolutionFolders();
diff --git a/tools/gn/xcode_object.cc b/tools/gn/xcode_object.cc index 8a314703..bd5c440 100644 --- a/tools/gn/xcode_object.cc +++ b/tools/gn/xcode_object.cc
@@ -5,12 +5,12 @@ #include "tools/gn/xcode_object.h" #include <iomanip> +#include <memory> #include <sstream> #include <utility> #include "base/logging.h" #include "base/macros.h" -#include "base/memory/ptr_util.h" #include "base/strings/string_util.h" #include "tools/gn/filesystem_utils.h" @@ -273,15 +273,15 @@ // PBXObjectVisitor ----------------------------------------------------------- -PBXObjectVisitor::PBXObjectVisitor() {} +PBXObjectVisitor::PBXObjectVisitor() = default; -PBXObjectVisitor::~PBXObjectVisitor() {} +PBXObjectVisitor::~PBXObjectVisitor() = default; // PBXObject ------------------------------------------------------------------ -PBXObject::PBXObject() {} +PBXObject::PBXObject() = default; -PBXObject::~PBXObject() {} +PBXObject::~PBXObject() = default; void PBXObject::SetId(const std::string& id) { DCHECK(id_.empty()); @@ -307,9 +307,9 @@ // PBXBuildPhase -------------------------------------------------------------- -PBXBuildPhase::PBXBuildPhase() {} +PBXBuildPhase::PBXBuildPhase() = default; -PBXBuildPhase::~PBXBuildPhase() {} +PBXBuildPhase::~PBXBuildPhase() = default; // PBXTarget ------------------------------------------------------------------ @@ -321,11 +321,11 @@ name_(name) { if (!shell_script.empty()) { build_phases_.push_back( - base::MakeUnique<PBXShellScriptBuildPhase>(name, shell_script)); + std::make_unique<PBXShellScriptBuildPhase>(name, shell_script)); } } -PBXTarget::~PBXTarget() {} +PBXTarget::~PBXTarget() = default; void PBXTarget::AddDependency(std::unique_ptr<PBXTargetDependency> dependency) { DCHECK(dependency); @@ -353,7 +353,7 @@ const PBXAttributes& attributes) : PBXTarget(name, shell_script, config_name, attributes) {} -PBXAggregateTarget::~PBXAggregateTarget() {} +PBXAggregateTarget::~PBXAggregateTarget() = default; PBXObjectClass PBXAggregateTarget::Class() const { return PBXAggregateTargetClass; @@ -384,7 +384,7 @@ DCHECK(build_phase_); } -PBXBuildFile::~PBXBuildFile() {} +PBXBuildFile::~PBXBuildFile() = default; PBXObjectClass PBXBuildFile::Class() const { return PBXBuildFileClass; @@ -414,7 +414,7 @@ const PBXTarget* target) : project_(project), target_(target) {} -PBXContainerItemProxy::~PBXContainerItemProxy() {} +PBXContainerItemProxy::~PBXContainerItemProxy() = default; PBXObjectClass PBXContainerItemProxy::Class() const { return PBXContainerItemProxyClass; @@ -447,7 +447,7 @@ const std::string& type) : name_(name), path_(path), type_(type) {} -PBXFileReference::~PBXFileReference() {} +PBXFileReference::~PBXFileReference() = default; PBXObjectClass PBXFileReference::Class() const { return PBXFileReferenceClass; @@ -486,9 +486,9 @@ // PBXFrameworksBuildPhase ---------------------------------------------------- -PBXFrameworksBuildPhase::PBXFrameworksBuildPhase() {} +PBXFrameworksBuildPhase::PBXFrameworksBuildPhase() = default; -PBXFrameworksBuildPhase::~PBXFrameworksBuildPhase() {} +PBXFrameworksBuildPhase::~PBXFrameworksBuildPhase() = default; PBXObjectClass PBXFrameworksBuildPhase::Class() const { return PBXFrameworksBuildPhaseClass; @@ -514,7 +514,7 @@ PBXGroup::PBXGroup(const std::string& path, const std::string& name) : name_(name), path_(path) {} -PBXGroup::~PBXGroup() {} +PBXGroup::~PBXGroup() = default; PBXObject* PBXGroup::AddChild(std::unique_ptr<PBXObject> child) { DCHECK(child); @@ -541,7 +541,7 @@ } } - children_.push_back(base::MakeUnique<PBXFileReference>( + children_.push_back(std::make_unique<PBXFileReference>( navigator_path, source_path, std::string())); return static_cast<PBXFileReference*>(children_.back().get()); } @@ -560,7 +560,7 @@ } if (!group) { - children_.push_back(base::MakeUnique<PBXGroup>(component.as_string(), + children_.push_back(std::make_unique<PBXGroup>(component.as_string(), component.as_string())); group = static_cast<PBXGroup*>(children_.back().get()); } @@ -617,19 +617,19 @@ product_type_(product_type), product_name_(product_name) { DCHECK(product_reference_); - build_phases_.push_back(base::MakeUnique<PBXSourcesBuildPhase>()); + build_phases_.push_back(std::make_unique<PBXSourcesBuildPhase>()); source_build_phase_ = static_cast<PBXSourcesBuildPhase*>(build_phases_.back().get()); - build_phases_.push_back(base::MakeUnique<PBXFrameworksBuildPhase>()); + build_phases_.push_back(std::make_unique<PBXFrameworksBuildPhase>()); } -PBXNativeTarget::~PBXNativeTarget() {} +PBXNativeTarget::~PBXNativeTarget() = default; void PBXNativeTarget::AddFileForIndexing(const PBXFileReference* file_reference, const CompilerFlags compiler_flag) { DCHECK(file_reference); - source_build_phase_->AddBuildFile(base::MakeUnique<PBXBuildFile>( + source_build_phase_->AddBuildFile(std::make_unique<PBXBuildFile>( file_reference, source_build_phase_, compiler_flag)); } @@ -664,16 +664,16 @@ main_group_.reset(new PBXGroup); sources_ = static_cast<PBXGroup*>( - main_group_->AddChild(base::MakeUnique<PBXGroup>(source_path, "Source"))); + main_group_->AddChild(std::make_unique<PBXGroup>(source_path, "Source"))); sources_->set_is_source(true); products_ = static_cast<PBXGroup*>(main_group_->AddChild( - base::MakeUnique<PBXGroup>(std::string(), "Product"))); - main_group_->AddChild(base::MakeUnique<PBXGroup>(std::string(), "Build")); + std::make_unique<PBXGroup>(std::string(), "Product"))); + main_group_->AddChild(std::make_unique<PBXGroup>(std::string(), "Build")); configurations_.reset(new XCConfigurationList(config_name, attributes, this)); } -PBXProject::~PBXProject() {} +PBXProject::~PBXProject() = default; void PBXProject::AddSourceFileToIndexingTarget( const std::string& navigator_path, @@ -707,7 +707,7 @@ attributes["CONFIGURATION_BUILD_DIR"] = "."; attributes["PRODUCT_NAME"] = name; - targets_.push_back(base::MakeUnique<PBXAggregateTarget>( + targets_.push_back(std::make_unique<PBXAggregateTarget>( name, shell_script, config_name_, attributes)); } @@ -719,11 +719,11 @@ attributes["PRODUCT_NAME"] = "sources"; PBXFileReference* product_reference = static_cast<PBXFileReference*>( - products_->AddChild(base::MakeUnique<PBXFileReference>( + products_->AddChild(std::make_unique<PBXFileReference>( std::string(), "sources", "compiled.mach-o.executable"))); const char product_type[] = "com.apple.product-type.tool"; - targets_.push_back(base::MakeUnique<PBXNativeTarget>( + targets_.push_back(std::make_unique<PBXNativeTarget>( "sources", std::string(), config_name_, attributes, product_type, "sources", product_reference)); target_for_indexing_ = static_cast<PBXNativeTarget*>(targets_.back().get()); @@ -738,21 +738,29 @@ const PBXAttributes& extra_attributes) { base::StringPiece ext = FindExtension(&output_name); PBXFileReference* product = static_cast<PBXFileReference*>( - products_->AddChild(base::MakeUnique<PBXFileReference>( + products_->AddChild(std::make_unique<PBXFileReference>( std::string(), output_name, type.empty() ? GetSourceType(ext) : type))); - size_t ext_offset = FindExtensionOffset(output_name); + // Per Xcode build settings documentation: Product Name (PRODUCT_NAME) should + // the basename of the product generated by the target. + // Therefore, take the basename of output name without file extension as the + // "PRODUCT_NAME". + size_t basename_offset = FindFilenameOffset(output_name); + std::string output_basename = basename_offset != std::string::npos + ? output_name.substr(basename_offset) + : output_name; + size_t ext_offset = FindExtensionOffset(output_basename); std::string product_name = ext_offset != std::string::npos - ? output_name.substr(0, ext_offset - 1) - : output_name; + ? output_basename.substr(0, ext_offset - 1) + : output_basename; PBXAttributes attributes = extra_attributes; attributes["CODE_SIGNING_REQUIRED"] = "NO"; attributes["CONFIGURATION_BUILD_DIR"] = "."; attributes["PRODUCT_NAME"] = product_name; - targets_.push_back(base::MakeUnique<PBXNativeTarget>( + targets_.push_back(std::make_unique<PBXNativeTarget>( name, shell_script, config_name_, attributes, output_type, product_name, product)); return static_cast<PBXNativeTarget*>(targets_.back().get()); @@ -820,7 +828,7 @@ : name_("Action \"Compile and copy " + name + " via ninja\""), shell_script_(shell_script) {} -PBXShellScriptBuildPhase::~PBXShellScriptBuildPhase() {} +PBXShellScriptBuildPhase::~PBXShellScriptBuildPhase() = default; PBXObjectClass PBXShellScriptBuildPhase::Class() const { return PBXShellScriptBuildPhaseClass; @@ -849,9 +857,9 @@ // PBXSourcesBuildPhase ------------------------------------------------------- -PBXSourcesBuildPhase::PBXSourcesBuildPhase() {} +PBXSourcesBuildPhase::PBXSourcesBuildPhase() = default; -PBXSourcesBuildPhase::~PBXSourcesBuildPhase() {} +PBXSourcesBuildPhase::~PBXSourcesBuildPhase() = default; void PBXSourcesBuildPhase::AddBuildFile( std::unique_ptr<PBXBuildFile> build_file) { @@ -889,7 +897,7 @@ std::unique_ptr<PBXContainerItemProxy> container_item_proxy) : target_(target), container_item_proxy_(std::move(container_item_proxy)) {} -PBXTargetDependency::~PBXTargetDependency() {} +PBXTargetDependency::~PBXTargetDependency() = default; PBXObjectClass PBXTargetDependency::Class() const { return PBXTargetDependencyClass; @@ -917,7 +925,7 @@ const PBXAttributes& attributes) : attributes_(attributes), name_(name) {} -XCBuildConfiguration::~XCBuildConfiguration() {} +XCBuildConfiguration::~XCBuildConfiguration() = default; PBXObjectClass XCBuildConfiguration::Class() const { return XCBuildConfigurationClass; @@ -945,10 +953,10 @@ : owner_reference_(owner_reference) { DCHECK(owner_reference_); configurations_.push_back( - base::MakeUnique<XCBuildConfiguration>(name, attributes)); + std::make_unique<XCBuildConfiguration>(name, attributes)); } -XCConfigurationList::~XCConfigurationList() {} +XCConfigurationList::~XCConfigurationList() = default; PBXObjectClass XCConfigurationList::Class() const { return XCConfigurationListClass;
diff --git a/tools/gn/xcode_object_unittest.cc b/tools/gn/xcode_object_unittest.cc index 52a98b9..656d0b7 100644 --- a/tools/gn/xcode_object_unittest.cc +++ b/tools/gn/xcode_object_unittest.cc
@@ -4,7 +4,6 @@ #include "tools/gn/xcode_object.h" -#include "base/memory/ptr_util.h" #include "testing/gtest/include/gtest/gtest.h" namespace { @@ -306,22 +305,23 @@ // Tests the mapping between PBXObjectClass and it's name as a string. TEST(XcodeObject, ClassToString) { - EXPECT_EQ("PBXAggregateTarget", ToString(PBXAggregateTargetClass)); - EXPECT_EQ("PBXBuildFile", ToString(PBXBuildFileClass)); - EXPECT_EQ("PBXAggregateTarget", ToString(PBXAggregateTargetClass)); - EXPECT_EQ("PBXBuildFile", ToString(PBXBuildFileClass)); - EXPECT_EQ("PBXContainerItemProxy", ToString(PBXContainerItemProxyClass)); - EXPECT_EQ("PBXFileReference", ToString(PBXFileReferenceClass)); - EXPECT_EQ("PBXFrameworksBuildPhase", ToString(PBXFrameworksBuildPhaseClass)); - EXPECT_EQ("PBXGroup", ToString(PBXGroupClass)); - EXPECT_EQ("PBXNativeTarget", ToString(PBXNativeTargetClass)); - EXPECT_EQ("PBXProject", ToString(PBXProjectClass)); - EXPECT_EQ("PBXSourcesBuildPhase", ToString(PBXSourcesBuildPhaseClass)); - EXPECT_EQ("PBXTargetDependency", ToString(PBXTargetDependencyClass)); - EXPECT_EQ("XCBuildConfiguration", ToString(XCBuildConfigurationClass)); - EXPECT_EQ("XCConfigurationList", ToString(XCConfigurationListClass)); - EXPECT_EQ("PBXShellScriptBuildPhase", - ToString(PBXShellScriptBuildPhaseClass)); + EXPECT_STREQ("PBXAggregateTarget", ToString(PBXAggregateTargetClass)); + EXPECT_STREQ("PBXBuildFile", ToString(PBXBuildFileClass)); + EXPECT_STREQ("PBXAggregateTarget", ToString(PBXAggregateTargetClass)); + EXPECT_STREQ("PBXBuildFile", ToString(PBXBuildFileClass)); + EXPECT_STREQ("PBXContainerItemProxy", ToString(PBXContainerItemProxyClass)); + EXPECT_STREQ("PBXFileReference", ToString(PBXFileReferenceClass)); + EXPECT_STREQ("PBXFrameworksBuildPhase", + ToString(PBXFrameworksBuildPhaseClass)); + EXPECT_STREQ("PBXGroup", ToString(PBXGroupClass)); + EXPECT_STREQ("PBXNativeTarget", ToString(PBXNativeTargetClass)); + EXPECT_STREQ("PBXProject", ToString(PBXProjectClass)); + EXPECT_STREQ("PBXSourcesBuildPhase", ToString(PBXSourcesBuildPhaseClass)); + EXPECT_STREQ("PBXTargetDependency", ToString(PBXTargetDependencyClass)); + EXPECT_STREQ("XCBuildConfiguration", ToString(XCBuildConfigurationClass)); + EXPECT_STREQ("XCConfigurationList", ToString(XCConfigurationListClass)); + EXPECT_STREQ("PBXShellScriptBuildPhase", + ToString(PBXShellScriptBuildPhaseClass)); } // Tests the mapping between PBXObject and it's name as a string.
diff --git a/tools/gn/xcode_writer.cc b/tools/gn/xcode_writer.cc index c10ebb4..f5dd65aa 100644 --- a/tools/gn/xcode_writer.cc +++ b/tools/gn/xcode_writer.cc
@@ -13,7 +13,6 @@ #include "base/environment.h" #include "base/logging.h" -#include "base/memory/ptr_util.h" #include "base/sha1.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" @@ -36,8 +35,10 @@ using TargetToTarget = std::unordered_map<const Target*, const Target*>; using TargetToPBXTarget = std::unordered_map<const Target*, PBXTarget*>; -const char kEarlGreyFileNameIdentifier[] = "egtest.mm"; -const char kXCTestFileNameIdentifier[] = "xctest.mm"; +const char* kXCTestFileSuffixes[] = { + "egtest.m", "egtest.mm", "xctest.m", "xctest.mm", +}; + const char kXCTestModuleTargetNamePostfix[] = "_module"; const char kXCUITestRunnerTargetNamePostfix[] = "_runner"; @@ -126,10 +127,15 @@ } bool IsXCTestFile(const SourceFile& file) { - return base::EndsWith(file.GetName(), kEarlGreyFileNameIdentifier, - base::CompareCase::SENSITIVE) || - base::EndsWith(file.GetName(), kXCTestFileNameIdentifier, - base::CompareCase::SENSITIVE); + std::string file_name = file.GetName(); + for (size_t i = 0; i < arraysize(kXCTestFileSuffixes); ++i) { + if (base::EndsWith(file_name, kXCTestFileSuffixes[i], + base::CompareCase::SENSITIVE)) { + return true; + } + } + + return false; } const Target* FindApplicationTargetByName( @@ -151,8 +157,8 @@ PBXTarget* dependent_pbxtarget, const PBXProject* project) { auto container_item_proxy = - base::MakeUnique<PBXContainerItemProxy>(project, base_pbxtarget); - auto dependency = base::MakeUnique<PBXTargetDependency>( + std::make_unique<PBXContainerItemProxy>(project, base_pbxtarget); + auto dependency = std::make_unique<PBXTargetDependency>( base_pbxtarget, std::move(container_item_proxy)); dependent_pbxtarget->AddDependency(std::move(dependency)); @@ -282,7 +288,7 @@ class CollectPBXObjectsPerClassHelper : public PBXObjectVisitor { public: - CollectPBXObjectsPerClassHelper() {} + CollectPBXObjectsPerClassHelper() = default; void Visit(PBXObject* object) override { DCHECK(object); @@ -400,7 +406,7 @@ name_.assign("all"); } -XcodeWriter::~XcodeWriter() {} +XcodeWriter::~XcodeWriter() = default; // static bool XcodeWriter::FilterTargets(const BuildSettings* build_settings,
diff --git a/tools/gn/xml_element_writer.cc b/tools/gn/xml_element_writer.cc index ecc4f7b..360d8af 100644 --- a/tools/gn/xml_element_writer.cc +++ b/tools/gn/xml_element_writer.cc
@@ -4,9 +4,9 @@ #include "tools/gn/xml_element_writer.h" -#include "base/memory/ptr_util.h" +#include <memory> -XmlAttributes::XmlAttributes() {} +XmlAttributes::XmlAttributes() = default; XmlAttributes::XmlAttributes(const base::StringPiece& attr_key, const base::StringPiece& attr_value) { @@ -64,7 +64,7 @@ const std::string& tag, const XmlAttributes& attributes) { StartContent(true); - return base::MakeUnique<XmlElementWriter>(out_, tag, attributes, indent_ + 2); + return std::make_unique<XmlElementWriter>(out_, tag, attributes, indent_ + 2); } std::ostream& XmlElementWriter::StartContent(bool start_new_line) {
diff --git a/tools/gn/xml_element_writer.h b/tools/gn/xml_element_writer.h index 0e8fa01f..4aa5f7e3 100644 --- a/tools/gn/xml_element_writer.h +++ b/tools/gn/xml_element_writer.h
@@ -12,7 +12,6 @@ #include <vector> #include "base/macros.h" -#include "base/memory/ptr_util.h" #include "base/strings/string_piece.h" // Vector of XML attribute key-value pairs. @@ -116,7 +115,7 @@ const std::string& attribute_name, const Writer& attribute_value_writer) { StartContent(true); - return base::MakeUnique<XmlElementWriter>( + return std::make_unique<XmlElementWriter>( out_, tag, attribute_name, attribute_value_writer, indent_ + 2); }
diff --git a/tools/grit/OWNERS b/tools/grit/OWNERS index 40b5c310..e94bc00d 100644 --- a/tools/grit/OWNERS +++ b/tools/grit/OWNERS
@@ -1,3 +1,4 @@ +agrieve@chromium.org flackr@chromium.org thakis@chromium.org thestig@chromium.org
diff --git a/tools/grit/grit/format/android_xml.py b/tools/grit/grit/format/android_xml.py index 25774ab..42ba6bc 100755 --- a/tools/grit/grit/format/android_xml.py +++ b/tools/grit/grit/format/android_xml.py
@@ -174,13 +174,17 @@ return None body_in = plural_match.group('items').strip() lines = [] + quantities_so_far = set() for item_match in _PLURALS_ITEM_PATTERN.finditer(body_in): quantity_in = item_match.group('quantity') quantity_out = _PLURALS_QUANTITY_MAP.get(quantity_in) value_in = item_match.group('value') value_out = '"' + value_in.replace('#', '%d') + '"' if quantity_out: - lines.append(_PLURALS_ITEM_TEMPLATE % (quantity_out, value_out)) + # only one line per quantity out (https://crbug.com/787488) + if quantity_out not in quantities_so_far: + quantities_so_far.add(quantity_out) + lines.append(_PLURALS_ITEM_TEMPLATE % (quantity_out, value_out)) else: raise Exception('Unsupported plural quantity for android ' 'strings.xml: %s' % quantity_in)
diff --git a/tools/grit/grit/format/android_xml_unittest.py b/tools/grit/grit/format/android_xml_unittest.py index 5e9871ed..6f496b61 100755 --- a/tools/grit/grit/format/android_xml_unittest.py +++ b/tools/grit/grit/format/android_xml_unittest.py
@@ -80,6 +80,34 @@ """ self.assertEqual(output.strip(), expected.strip()) + + def testConflictingPlurals(self): + root = util.ParseGrdForUnittest(ur""" + <messages> + <message name="IDS_PLURALS" desc="A string using the ICU plural format"> + {NUM_THINGS, plural, + =1 {Maybe I'll get one laser.} + one {Maybe I'll get one laser.} + other {Maybe I'll get # lasers.}} + </message> + </messages> + """) + + buf = StringIO.StringIO() + build.RcBuilder.ProcessNode(root, DummyOutput('android', 'en'), buf) + output = buf.getvalue() + expected = ur""" +<?xml version="1.0" encoding="utf-8"?> +<resources xmlns:android="http://schemas.android.com/apk/res/android"> +<plurals name="plurals"> + <item quantity="one">"Maybe I\'ll get one laser."</item> + <item quantity="other">"Maybe I\'ll get %d lasers."</item> +</plurals> +</resources> +""" + self.assertEqual(output.strip(), expected.strip()) + + def testTaggedOnly(self): root = util.ParseGrdForUnittest(ur""" <messages>
diff --git a/tools/grit/grit/format/data_pack.py b/tools/grit/grit/format/data_pack.py index f1b1660..6037dc60 100755 --- a/tools/grit/grit/format/data_pack.py +++ b/tools/grit/grit/format/data_pack.py
@@ -33,23 +33,59 @@ pass -DataPackContents = collections.namedtuple( - 'DataPackContents', 'resources encoding') +class DataPackSizes(object): + def __init__(self, header, id_table, alias_table, data): + self.header = header + self.id_table = id_table + self.alias_table = alias_table + self.data = data + + @property + def total(self): + return sum(v for v in self.__dict__.itervalues()) + + def __iter__(self): + yield ('header', self.header) + yield ('id_table', self.id_table) + yield ('alias_table', self.alias_table) + yield ('data', self.data) + + def __eq__(self, other): + return self.__dict__ == other.__dict__ + + def __repr__(self): + return self.__class__.__name__ + repr(self.__dict__) + + +class DataPackContents(object): + def __init__(self, resources, encoding, version, aliases, sizes): + # Map of resource_id -> str. + self.resources = resources + # Encoding (int). + self.encoding = encoding + # Version (int). + self.version = version + # Map of resource_id->canonical_resource_id + self.aliases = aliases + # DataPackSizes instance. + self.sizes = sizes def Format(root, lang='en', output_dir='.'): """Writes out the data pack file format (platform agnostic resource file).""" + id_map = root.GetIdMap() data = {} root.info = [] for node in root.ActiveDescendants(): with node: if isinstance(node, (include.IncludeNode, message.MessageNode, structure.StructureNode)): - id, value = node.GetDataPackPair(lang, UTF8) + value = node.GetDataPackValue(lang, UTF8) if value is not None: - data[id] = value - root.info.append( - '{},{},{}'.format(node.attrs.get('name'), id, node.source)) + resource_id = id_map[node.GetTextualIds()[0]] + data[resource_id] = value + root.info.append('{},{},{}'.format( + node.attrs.get('name'), resource_id, node.source)) return WriteDataPackToString(data, UTF8) @@ -59,45 +95,51 @@ def ReadDataPackFromString(data): """Reads a data pack file and returns a dictionary.""" - original_data = data - # Read the header. version = struct.unpack('<I', data[:4])[0] if version == 4: resource_count, encoding = struct.unpack('<IB', data[4:9]) alias_count = 0 - data = data[9:] + header_size = 9 elif version == 5: encoding, resource_count, alias_count = struct.unpack('<BxxxHH', data[4:12]) - data = data[12:] + header_size = 12 else: raise WrongFileVersion('Found version: ' + str(version)) resources = {} kIndexEntrySize = 2 + 4 # Each entry is a uint16 and a uint32. def entry_at_index(idx): - offset = idx * kIndexEntrySize + offset = header_size + idx * kIndexEntrySize return struct.unpack('<HI', data[offset:offset + kIndexEntrySize]) prev_resource_id, prev_offset = entry_at_index(0) for i in xrange(1, resource_count + 1): resource_id, offset = entry_at_index(i) - resources[prev_resource_id] = original_data[prev_offset:offset] + resources[prev_resource_id] = data[prev_offset:offset] prev_resource_id, prev_offset = resource_id, offset + id_table_size = (resource_count + 1) * kIndexEntrySize # Read the alias table. - alias_data = data[(resource_count + 1) * kIndexEntrySize:] kAliasEntrySize = 2 + 2 # uint16, uint16 def alias_at_index(idx): - offset = idx * kAliasEntrySize - return struct.unpack('<HH', alias_data[offset:offset + kAliasEntrySize]) + offset = header_size + id_table_size + idx * kAliasEntrySize + return struct.unpack('<HH', data[offset:offset + kAliasEntrySize]) + aliases = {} for i in xrange(alias_count): resource_id, index = alias_at_index(i) aliased_id = entry_at_index(index)[0] + aliases[resource_id] = aliased_id resources[resource_id] = resources[aliased_id] - return DataPackContents(resources, encoding) + alias_table_size = kAliasEntrySize * alias_count + sizes = DataPackSizes( + header_size, id_table_size, alias_table_size, + len(data) - header_size - id_table_size - alias_table_size) + assert sizes.total == len(data), 'original={} computed={}'.format( + len(data), sizes.total) + return DataPackContents(resources, encoding, version, aliases, sizes) def WriteDataPackToString(resources, encoding): @@ -181,8 +223,9 @@ if whitelist_file: whitelist = util.ReadFile(whitelist_file, util.RAW_TEXT).strip().split('\n') whitelist = set(map(int, whitelist)) + inputs = [(p.resources, p.encoding) for p in input_data_packs] resources, encoding = RePackFromDataPackStrings( - input_data_packs, whitelist, suppress_removed_key_output) + inputs, whitelist, suppress_removed_key_output) WriteDataPack(resources, output_file, encoding) with open(output_file + '.info', 'w') as output_info_file: for filename in input_info_files: @@ -192,17 +235,16 @@ def RePackFromDataPackStrings(inputs, whitelist, suppress_removed_key_output=False): - """Returns a data pack string that combines the resources from inputs. + """Combines all inputs into one. Args: - inputs: a list of data pack strings that need to be combined. + inputs: a list of (resources_by_id, encoding) tuples to be combined. whitelist: a list of resource IDs that should be kept in the output string or None to include all resources. suppress_removed_key_output: Do not print removed keys. Returns: - DataPackContents: a tuple containing the new combined data pack and its - encoding. + Returns (resources_by_id, encoding). Raises: KeyError: if there are duplicate keys or resource encoding is @@ -210,46 +252,36 @@ """ resources = {} encoding = None - for content in inputs: + for input_resources, input_encoding in inputs: # Make sure we have no dups. - duplicate_keys = set(content.resources.keys()) & set(resources.keys()) + duplicate_keys = set(input_resources.keys()) & set(resources.keys()) if duplicate_keys: raise exceptions.KeyError('Duplicate keys: ' + str(list(duplicate_keys))) # Make sure encoding is consistent. if encoding in (None, BINARY): - encoding = content.encoding - elif content.encoding not in (BINARY, encoding): + encoding = input_encoding + elif input_encoding not in (BINARY, encoding): raise exceptions.KeyError('Inconsistent encodings: ' + str(encoding) + - ' vs ' + str(content.encoding)) + ' vs ' + str(input_encoding)) if whitelist: - whitelisted_resources = dict([(key, content.resources[key]) - for key in content.resources.keys() + whitelisted_resources = dict([(key, input_resources[key]) + for key in input_resources.keys() if key in whitelist]) resources.update(whitelisted_resources) - removed_keys = [key for key in content.resources.keys() + removed_keys = [key for key in input_resources.keys() if key not in whitelist] if not suppress_removed_key_output: for key in removed_keys: print 'RePackFromDataPackStrings Removed Key:', key else: - resources.update(content.resources) + resources.update(input_resources) # Encoding is 0 for BINARY, 1 for UTF8 and 2 for UTF16 if encoding is None: encoding = BINARY - return DataPackContents(resources, encoding) - - -# Temporary hack for external programs that import data_pack. -# TODO(benrg): Remove this. -class DataPack(object): - pass -DataPack.ReadDataPack = staticmethod(ReadDataPack) -DataPack.WriteDataPackToString = staticmethod(WriteDataPackToString) -DataPack.WriteDataPack = staticmethod(WriteDataPack) -DataPack.RePack = staticmethod(RePack) + return resources, encoding def main():
diff --git a/tools/grit/grit/format/data_pack_unittest.py b/tools/grit/grit/format/data_pack_unittest.py index 28a7b29..ba36590 100755 --- a/tools/grit/grit/format/data_pack_unittest.py +++ b/tools/grit/grit/format/data_pack_unittest.py
@@ -28,16 +28,15 @@ '\x0a\x00\x3f\x00\x00\x00' # index entry 10 '\x00\x00\x3f\x00\x00\x00' # extra entry for the size of last 'this is id 4this is id 6') # data - expected_resources = { - 1: '', - 4: 'this is id 4', - 6: 'this is id 6', - 10: '', - } expected_data_pack = data_pack.DataPackContents( - expected_resources, data_pack.UTF8) + { + 1: '', + 4: 'this is id 4', + 6: 'this is id 6', + 10: '', + }, data_pack.UTF8, 4, {}, data_pack.DataPackSizes(9, 30, 0, 24)) loaded = data_pack.ReadDataPackFromString(expected_data) - self.assertEquals(loaded, expected_data_pack) + self.assertDictEqual(expected_data_pack.__dict__, loaded.__dict__) def testReadWriteDataPackV5(self): expected_data = ( @@ -51,19 +50,24 @@ '\x00\x00\x40\x00\x00\x00' # extra entry for the size of last '\x0a\x00\x01\x00' # alias table 'this is id 4this is id 6') # data - expected_resources = { + input_resources = { 1: '', 4: 'this is id 4', 6: 'this is id 6', 10: 'this is id 4', } - data = data_pack.WriteDataPackToString(expected_resources, data_pack.UTF8) + data = data_pack.WriteDataPackToString(input_resources, data_pack.UTF8) self.assertEquals(data, expected_data) expected_data_pack = data_pack.DataPackContents( - expected_resources, data_pack.UTF8) + { + 1: '', + 4: input_resources[4], + 6: input_resources[6], + 10: input_resources[4], + }, data_pack.UTF8, 5, {10: 4}, data_pack.DataPackSizes(12, 24, 4, 24)) loaded = data_pack.ReadDataPackFromString(expected_data) - self.assertEquals(loaded, expected_data_pack) + self.assertDictEqual(expected_data_pack.__dict__, loaded.__dict__) def testRePackUnittest(self): expected_with_whitelist = { @@ -79,8 +83,7 @@ {40: 'Never', 50: 'gonna run around and', 60: 'desert you'}, {65: 'Close', 70: 'Awww, snap!'}] whitelist = [1, 10, 20, 30, 40, 50, 60] - inputs = [data_pack.DataPackContents(input, data_pack.UTF8) for input - in inputs] + inputs = [(i, data_pack.UTF8) for i in inputs] # RePack using whitelist output, _ = data_pack.RePackFromDataPackStrings(
diff --git a/tools/grit/grit/format/gzip_string_unittest.py b/tools/grit/grit/format/gzip_string_unittest.py old mode 100644 new mode 100755 index 8df8b3b..a920693 --- a/tools/grit/grit/format/gzip_string_unittest.py +++ b/tools/grit/grit/format/gzip_string_unittest.py
@@ -1,3 +1,4 @@ +#!/usr/bin/env python # Copyright (c) 2016 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.
diff --git a/tools/grit/grit/format/minifier.py b/tools/grit/grit/format/minifier.py index 84028f9..a45b5545 100644 --- a/tools/grit/grit/format/minifier.py +++ b/tools/grit/grit/format/minifier.py
@@ -19,11 +19,6 @@ file_type = path.splitext(filename)[1] if not file_type == '.js' or not __js_minifier: return source - # TODO (BUG http://crbug/644392) searchbox_api.js uses Chrome extensions so - # can't be minified. Remove this when that is fixed. - if path.abspath(filename).endswith( - '/chrome/renderer/resources/extensions/searchbox_api.js'): - return source p = subprocess.Popen( __js_minifier, stdin=subprocess.PIPE,
diff --git a/tools/grit/grit/format/rc.py b/tools/grit/grit/format/rc.py index bd3de1a..47ad5a03 100755 --- a/tools/grit/grit/format/rc.py +++ b/tools/grit/grit/format/rc.py
@@ -12,7 +12,6 @@ from functools import partial from grit import util -from grit.format import rc_header from grit.node import misc @@ -414,8 +413,8 @@ relative_path = item.attrs['relativepath'] == 'true' else: assert (isinstance(item, structure.StructureNode) and item.attrs['type'] in - ['admin_template', 'chrome_html', 'chrome_scaled_image', 'igoogle', - 'muppet', 'tr_html', 'txt']) + ['admin_template', 'chrome_html', 'chrome_scaled_image', + 'tr_html', 'txt']) filename_only = False relative_path = False @@ -442,7 +441,7 @@ return '' name = item.attrs['name'] - item_id = rc_header.GetIds(item.GetRoot())[name] + item_id = item.GetRoot().GetIdMap()[name] return '// ID: %d\n%-18s %-18s "%s"\n' % (item_id, name, type, filename) @@ -462,8 +461,6 @@ 'chrome_html' : partial(FormatInclude, type='BINDATA', process_html=True), 'chrome_scaled_image' : partial(FormatInclude, type='BINDATA'), - 'igoogle' : partial(FormatInclude, type='XML'), - 'muppet' : partial(FormatInclude, type='XML'), 'tr_html' : partial(FormatInclude, type='HTML'), 'txt' : partial(FormatInclude, type='TXT'), 'policy_template_metafile': _DoNotFormat,
diff --git a/tools/grit/grit/format/rc_header.py b/tools/grit/grit/format/rc_header.py index 7b02122..7dedd37 100755 --- a/tools/grit/grit/format/rc_header.py +++ b/tools/grit/grit/format/rc_header.py
@@ -6,9 +6,7 @@ '''Item formatters for RC headers. ''' -from grit import exception -from grit import util -from grit.extern import FP +from grit.node import message def Format(root, lang='en', output_dir='.'): @@ -30,208 +28,22 @@ for line in emit_lines or default_includes: yield line + '\n' - for line in FormatDefines(root, root.ShouldOutputAllResourceDefines(), - root.GetRcHeaderFormat()): + for line in FormatDefines(root, root.GetRcHeaderFormat()): yield line -def FormatDefines(root, output_all_resource_defines=True, - rc_header_format=None): +def FormatDefines(root, rc_header_format=None): '''Yields #define SYMBOL 1234 lines. Args: root: A GritNode. - output_all_resource_defines: If False, output only the symbols used in the - current output configuration. ''' - from grit.node import message - tids = GetIds(root) - - if output_all_resource_defines: - items = root.Preorder() - else: - items = root.ActiveDescendants() + tids = root.GetIdMap() if not rc_header_format: rc_header_format = "#define {textual_id} {numeric_id}" rc_header_format += "\n" - seen = set() - for item in items: - if not isinstance(item, message.MessageNode): - with item: - for tid in item.GetTextualIds(): - if tid in tids and tid not in seen: - seen.add(tid) - yield rc_header_format.format(textual_id=tid,numeric_id=tids[tid]) - - # Temporarily mimic old behavior: MessageNodes were only output if active, - # even with output_all_resource_defines set. TODO(benrg): Remove this after - # fixing problems in the Chrome tree. for item in root.ActiveDescendants(): - if isinstance(item, message.MessageNode): - with item: - for tid in item.GetTextualIds(): - if tid in tids and tid not in seen: - seen.add(tid) - yield rc_header_format.format(textual_id=tid,numeric_id=tids[tid]) - - -_cached_ids = {} - - -_predetermined_tids = {} - - -def SetPredeterminedIdsFile(predetermined_ids_file): - global _predetermined_tids - if predetermined_ids_file: - _predetermined_tids = _ReadIdsFromFile(predetermined_ids_file) - else: - _predetermined_tids = {} - - -def _ReadIdsFromFile(path): - with open(path, "r") as f: - content = f.readlines() - tids = {} # Maps textual id to numeric id - for line in content: - tid, id = line.split() - tids[tid] = int(id) - return tids - - -def GetIds(root): - '''Return a dictionary mapping textual ids to numeric ids for the given tree. - - Args: - root: A GritNode. - ''' - global _cached_ids - global _predetermined_tids - # TODO(benrg): Since other formatters use this, it might make sense to move it - # and _ComputeIds to GritNode and store the cached ids as an attribute. On the - # other hand, GritNode has too much random stuff already. - if root not in _cached_ids: - _cached_ids[root] = _ComputeIds(root, _predetermined_tids) - return _cached_ids[root] - - -def _ComputeIds(root, predetermined_tids): - from grit.node import empty, include, message, misc, structure - - ids = {} # Maps numeric id to textual id - tids = {} # Maps textual id to numeric id - id_reasons = {} # Maps numeric id to text id and a human-readable explanation - group = None - last_id = None - predetermined_ids = {value: key - for key, value in predetermined_tids.iteritems()} - - for item in root: - if isinstance(item, empty.GroupingNode): - # Note: this won't work if any GroupingNode can be contained inside - # another. - group = item - last_id = None - continue - - assert not item.GetTextualIds() or isinstance(item, - (include.IncludeNode, message.MessageNode, - misc.IdentifierNode, structure.StructureNode)) - - # Resources that use the RES protocol don't need - # any numerical ids generated, so we skip them altogether. - # This is accomplished by setting the flag 'generateid' to false - # in the GRD file. - if item.attrs.get('generateid', 'true') == 'false': - continue - - for tid in item.GetTextualIds(): - if util.SYSTEM_IDENTIFIERS.match(tid): - # Don't emit a new ID for predefined IDs - continue - - if tid in tids: - continue - - if predetermined_tids and tid in predetermined_tids: - id = predetermined_tids[tid] - reason = "from predetermined_tids map" - - # Some identifier nodes can provide their own id, - # and we use that id in the generated header in that case. - elif hasattr(item, 'GetId') and item.GetId(): - id = long(item.GetId()) - reason = 'returned by GetId() method' - - elif ('offset' in item.attrs and group and - group.attrs.get('first_id', '') != ''): - offset_text = item.attrs['offset'] - parent_text = group.attrs['first_id'] - - try: - offset_id = long(offset_text) - except ValueError: - offset_id = tids[offset_text] - - try: - parent_id = long(parent_text) - except ValueError: - parent_id = tids[parent_text] - - id = parent_id + offset_id - reason = 'first_id %d + offset %d' % (parent_id, offset_id) - - # We try to allocate IDs sequentially for blocks of items that might - # be related, for instance strings in a stringtable (as their IDs might be - # used e.g. as IDs for some radio buttons, in which case the IDs must - # be sequential). - # - # We do this by having the first item in a section store its computed ID - # (computed from a fingerprint) in its parent object. Subsequent children - # of the same parent will then try to get IDs that sequentially follow - # the currently stored ID (on the parent) and increment it. - elif last_id is None: - # First check if the starting ID is explicitly specified by the parent. - if group and group.attrs.get('first_id', '') != '': - id = long(group.attrs['first_id']) - reason = "from parent's first_id attribute" - else: - # Automatically generate the ID based on the first clique from the - # first child of the first child node of our parent (i.e. when we - # first get to this location in the code). - - # According to - # http://msdn.microsoft.com/en-us/library/t2zechd4(VS.71).aspx - # the safe usable range for resource IDs in Windows is from decimal - # 101 to 0x7FFF. - - id = FP.UnsignedFingerPrint(tid) - id = id % (0x7FFF - 101) + 101 - reason = 'chosen by random fingerprint -- use first_id to override' - - last_id = id - else: - id = last_id = last_id + 1 - reason = 'sequentially assigned' - - reason = "%s (%s)" % (tid, reason) - # Don't fail when 'offset' is specified, as the base and the 0th - # offset will have the same ID. - if id in id_reasons and not 'offset' in item.attrs: - raise exception.IdRangeOverlap('ID %d was assigned to both %s and %s.' - % (id, id_reasons[id], reason)) - - if id < 101: - print ('WARNING: Numeric resource IDs should be greater than 100 to\n' - 'avoid conflicts with system-defined resource IDs.') - - if tid not in predetermined_tids and id in predetermined_ids: - raise exception.IdRangeOverlap('ID %d overlaps between %s and %s' - % (id, tid, predetermined_ids[tid])) - - ids[id] = tid - tids[tid] = id - id_reasons[id] = reason - - return tids + with item: + for tid in item.GetTextualIds(): + yield rc_header_format.format(textual_id=tid,numeric_id=tids[tid])
diff --git a/tools/grit/grit/format/rc_header_unittest.py b/tools/grit/grit/format/rc_header_unittest.py index 22c5f38..2eb2a638 100755 --- a/tools/grit/grit/format/rc_header_unittest.py +++ b/tools/grit/grit/format/rc_header_unittest.py
@@ -10,13 +10,11 @@ import os import sys -import tempfile +import unittest + if __name__ == '__main__': sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) -import StringIO -import unittest - from grit import exception from grit import grd_reader from grit import util @@ -25,122 +23,66 @@ class RcHeaderFormatterUnittest(unittest.TestCase): def FormatAll(self, grd): - output = rc_header.FormatDefines(grd, grd.ShouldOutputAllResourceDefines()) + output = rc_header.FormatDefines(grd) return ''.join(output).replace(' ', '') - def _MakeTempPredeterminedIdsFile(self, content): - tmp_dir = tempfile.gettempdir() - predetermined_ids_file = tmp_dir + "/predetermined_ids.txt" - with open(predetermined_ids_file, 'w') as f: - f.write(content) - return predetermined_ids_file - def testFormatter(self): - grd = grd_reader.Parse(StringIO.StringIO('''<?xml version="1.0" encoding="UTF-8"?> - <grit latest_public_release="2" source_lang_id="en" current_release="3" base_dir="."> - <release seq="3"> - <includes first_id="300" comment="bingo"> - <include type="gif" name="ID_LOGO" file="images/logo.gif" /> - </includes> - <messages first_id="10000"> - <message name="IDS_GREETING" desc="Printed to greet the currently logged in user"> - Hello <ph name="USERNAME">%s<ex>Joi</ex></ph>, how are you doing today? - </message> - <message name="IDS_BONGO"> - Bongo! - </message> - </messages> - <structures> - <structure type="dialog" name="IDD_NARROW_DIALOG" file="rc_files/dialogs.rc" /> - <structure type="version" name="VS_VERSION_INFO" file="rc_files/version.rc" /> - </structures> - </release> - </grit>'''), '.') + grd = util.ParseGrdForUnittest(''' + <includes first_id="300" comment="bingo"> + <include type="gif" name="ID_LOGO" file="images/logo.gif" /> + </includes> + <messages first_id="10000"> + <message name="IDS_GREETING" desc="Printed to greet the currently logged in user"> + Hello <ph name="USERNAME">%s<ex>Joi</ex></ph>, how are you doing today? + </message> + <message name="IDS_BONGO"> + Bongo! + </message> + </messages> + <structures> + <structure type="dialog" name="IDD_NARROW_DIALOG" file="rc_files/dialogs.rc" /> + <structure type="version" name="VS_VERSION_INFO" file="rc_files/version.rc" /> + </structures>''') output = self.FormatAll(grd) self.failUnless(output.count('IDS_GREETING10000')) self.failUnless(output.count('ID_LOGO300')) def testOnlyDefineResourcesThatSatisfyOutputCondition(self): - grd = grd_reader.Parse(StringIO.StringIO('''<?xml version="1.0" encoding="UTF-8"?> - <grit latest_public_release="2" source_lang_id="en" current_release="3" - base_dir="." output_all_resource_defines="false"> - <release seq="3"> - <includes first_id="300" comment="bingo"> - <include type="gif" name="ID_LOGO" file="images/logo.gif" /> - </includes> - <messages first_id="10000"> - <message name="IDS_FIRSTPRESENTSTRING" desc="Present in .rc file."> - I will appear in the .rc file. + grd = util.ParseGrdForUnittest(''' + <includes first_id="300" comment="bingo"> + <include type="gif" name="ID_LOGO" file="images/logo.gif" /> + </includes> + <messages first_id="10000"> + <message name="IDS_FIRSTPRESENTSTRING" desc="Present in .rc file."> + I will appear in the .rc file. + </message> + <if expr="False"> <!--Do not include in the .rc files until used.--> + <message name="IDS_MISSINGSTRING" desc="Not present in .rc file."> + I will not appear in the .rc file. </message> - <if expr="False"> <!--Do not include in the .rc files until used.--> - <message name="IDS_MISSINGSTRING" desc="Not present in .rc file."> - I will not appear in the .rc file. - </message> - </if> - <if expr="lang != 'es'"> - <message name="IDS_LANGUAGESPECIFICSTRING" desc="Present in .rc file."> - Hello. - </message> - </if> - <if expr="lang == 'es'"> - <message name="IDS_LANGUAGESPECIFICSTRING" desc="Present in .rc file."> - Hola. - </message> - </if> - <message name="IDS_THIRDPRESENTSTRING" desc="Present in .rc file."> - I will also appear in the .rc file. + </if> + <if expr="lang != 'es'"> + <message name="IDS_LANGUAGESPECIFICSTRING" desc="Present in .rc file."> + Hello. </message> - </messages> - </release> - </grit>'''), '.') + </if> + <if expr="lang == 'es'"> + <message name="IDS_LANGUAGESPECIFICSTRING" desc="Present in .rc file."> + Hola. + </message> + </if> + <message name="IDS_THIRDPRESENTSTRING" desc="Present in .rc file."> + I will also appear in the .rc file. + </message> + </messages>''') output = self.FormatAll(grd) self.failUnless(output.count('IDS_FIRSTPRESENTSTRING10000')) self.failIf(output.count('IDS_MISSINGSTRING')) - self.failIf(output.count('10001')) # IDS_MISSINGSTRING should get this ID self.failUnless(output.count('IDS_LANGUAGESPECIFICSTRING10002')) self.failUnless(output.count('IDS_THIRDPRESENTSTRING10003')) - def testExplicitFirstIdOverlaps(self): - # second first_id will overlap preexisting range - grd = grd_reader.Parse(StringIO.StringIO('''<?xml version="1.0" encoding="UTF-8"?> - <grit latest_public_release="2" source_lang_id="en" current_release="3" base_dir="."> - <release seq="3"> - <includes first_id="300" comment="bingo"> - <include type="gif" name="ID_LOGO" file="images/logo.gif" /> - <include type="gif" name="ID_LOGO2" file="images/logo2.gif" /> - </includes> - <messages first_id="301"> - <message name="IDS_GREETING" desc="Printed to greet the currently logged in user"> - Hello <ph name="USERNAME">%s<ex>Joi</ex></ph>, how are you doing today? - </message> - <message name="IDS_SMURFGEBURF">Frubegfrums</message> - </messages> - </release> - </grit>'''), '.') - self.assertRaises(exception.IdRangeOverlap, self.FormatAll, grd) - - def testImplicitOverlapsPreexisting(self): - # second message in <messages> will overlap preexisting range - grd = grd_reader.Parse(StringIO.StringIO('''<?xml version="1.0" encoding="UTF-8"?> - <grit latest_public_release="2" source_lang_id="en" current_release="3" base_dir="."> - <release seq="3"> - <includes first_id="301" comment="bingo"> - <include type="gif" name="ID_LOGO" file="images/logo.gif" /> - <include type="gif" name="ID_LOGO2" file="images/logo2.gif" /> - </includes> - <messages first_id="300"> - <message name="IDS_GREETING" desc="Printed to greet the currently logged in user"> - Hello <ph name="USERNAME">%s<ex>Joi</ex></ph>, how are you doing today? - </message> - <message name="IDS_SMURFGEBURF">Frubegfrums</message> - </messages> - </release> - </grit>'''), '.') - self.assertRaises(exception.IdRangeOverlap, self.FormatAll, grd) - def testEmit(self): - grd = grd_reader.Parse(StringIO.StringIO('''<?xml version="1.0" encoding="UTF-8"?> - <grit latest_public_release="2" source_lang_id="en" current_release="3" base_dir="."> + grd = util.ParseGrdForUnittest(''' <outputs> <output type="rc_all" filename="dummy"> <emit emit_type="prepend">Wrong</emit> @@ -156,33 +98,27 @@ <output type="rc_header" filename="dummy"> <emit emit_type="prepend">Bingo</emit> </output> - </outputs> - </grit>'''), '.') + </outputs>''') output = ''.join(rc_header.Format(grd, 'en', '.')) output = util.StripBlankLinesAndComments(output) self.assertEqual('#pragma once\nBingo', output) def testRcHeaderFormat(self): - grd = grd_reader.Parse(StringIO.StringIO('''<?xml version="1.0" encoding="UTF-8"?> - <grit latest_public_release="2" source_lang_id="en" current_release="3" base_dir="."> - <release seq="3"> - <includes first_id="300" comment="bingo"> - <include type="gif" name="IDR_LOGO" file="images/logo.gif" /> - </includes> - <messages first_id="10000"> - <message name="IDS_GREETING" desc="Printed to greet the currently logged in user"> - Hello <ph name="USERNAME">%s<ex>Joi</ex></ph>, how are you doing today? - </message> - <message name="IDS_BONGO"> - Bongo! - </message> - </messages> - </release> - </grit>'''), '.') + grd = util.ParseGrdForUnittest(''' + <includes first_id="300" comment="bingo"> + <include type="gif" name="IDR_LOGO" file="images/logo.gif" /> + </includes> + <messages first_id="10000"> + <message name="IDS_GREETING" desc="Printed to greet the currently logged in user"> + Hello <ph name="USERNAME">%s<ex>Joi</ex></ph>, how are you doing today? + </message> + <message name="IDS_BONGO"> + Bongo! + </message> + </messages>''') # Using the default rc_header format string. - output = rc_header.FormatDefines(grd, grd.ShouldOutputAllResourceDefines(), - grd.GetRcHeaderFormat()) + output = rc_header.FormatDefines(grd, grd.GetRcHeaderFormat()) self.assertEqual(('#define IDR_LOGO 300\n' '#define IDS_GREETING 10000\n' '#define IDS_BONGO 10001\n'), ''.join(output)) @@ -190,60 +126,11 @@ # Using a custom rc_header format string. grd.AssignRcHeaderFormat( '#define {textual_id} _Pragma("{textual_id}") {numeric_id}') - output = rc_header.FormatDefines(grd, grd.ShouldOutputAllResourceDefines(), - grd.GetRcHeaderFormat()) + output = rc_header.FormatDefines(grd, grd.GetRcHeaderFormat()) self.assertEqual(('#define IDR_LOGO _Pragma("IDR_LOGO") 300\n' '#define IDS_GREETING _Pragma("IDS_GREETING") 10000\n' '#define IDS_BONGO _Pragma("IDS_BONGO") 10001\n'), ''.join(output)) - def testPredeterminedIds(self): - predetermined_ids_file = self._MakeTempPredeterminedIdsFile( - 'IDS_BONGO 101\nID_LOGO 102\n') - grd = grd_reader.Parse(StringIO.StringIO('''<?xml version="1.0" encoding="UTF-8"?> - <grit latest_public_release="2" source_lang_id="en" current_release="3" base_dir="."> - <release seq="3"> - <includes first_id="300" comment="bingo"> - <include type="gif" name="ID_LOGO" file="images/logo.gif" /> - </includes> - <messages first_id="10000"> - <message name="IDS_GREETING" desc="Printed to greet the currently logged in user"> - Hello <ph name="USERNAME">%s<ex>Joi</ex></ph>, how are you doing today? - </message> - <message name="IDS_BONGO"> - Bongo! - </message> - </messages> - </release> - </grit>'''), '.', predetermined_ids_file=predetermined_ids_file) - output = rc_header.FormatDefines(grd, grd.ShouldOutputAllResourceDefines(), - grd.GetRcHeaderFormat()) - self.assertEqual(('#define ID_LOGO 102\n' - '#define IDS_GREETING 10000\n' - '#define IDS_BONGO 101\n'), ''.join(output)) - - def testPredeterminedIdsOverlap(self): - predetermined_ids_file = self._MakeTempPredeterminedIdsFile( - 'ID_LOGO 10000\n') - grd = grd_reader.Parse(StringIO.StringIO('''<?xml version="1.0" encoding="UTF-8"?> - <grit latest_public_release="2" source_lang_id="en" current_release="3" base_dir="."> - <release seq="3"> - <includes first_id="300" comment="bingo"> - <include type="gif" name="ID_LOGO" file="images/logo.gif" /> - </includes> - <messages first_id="10000"> - <message name="IDS_GREETING" desc="Printed to greet the currently logged in user"> - Hello <ph name="USERNAME">%s<ex>Joi</ex></ph>, how are you doing today? - </message> - <message name="IDS_BONGO"> - Bongo! - </message> - </messages> - </release> - </grit>'''), '.', predetermined_ids_file=predetermined_ids_file) - output = rc_header.FormatDefines(grd, grd.ShouldOutputAllResourceDefines(), - grd.GetRcHeaderFormat()) - self.assertRaises(exception.IdRangeOverlap, self.FormatAll, grd) - if __name__ == '__main__': unittest.main()
diff --git a/tools/grit/grit/format/resource_map.py b/tools/grit/grit/format/resource_map.py index f1e3132..5fee06b8 100755 --- a/tools/grit/grit/format/resource_map.py +++ b/tools/grit/grit/format/resource_map.py
@@ -20,6 +20,10 @@ return partial(_FormatSource, _GetItemName) if type == 'resource_file_map_source': return partial(_FormatSource, _GetItemPath) + if type == 'gzipped_resource_map_header': + return partial(_FormatHeader, include_gzipped=True) + if type == 'gzipped_resource_file_map_source': + return partial(_FormatSource, _GetItemPath, include_gzipped=True) def GetMapName(root): @@ -45,7 +49,7 @@ return 'k' + filename -def _FormatHeader(root, lang='en', output_dir='.'): +def _FormatHeader(root, lang='en', output_dir='.', include_gzipped=False): '''Create the header file for the resource mapping. This file just declares an array of name/value pairs.''' return '''\ @@ -53,33 +57,38 @@ #include <stddef.h> -#ifndef GRIT_RESOURCE_MAP_STRUCT_ -#define GRIT_RESOURCE_MAP_STRUCT_ -struct GritResourceMap { +#ifndef %(macro_prefix)sGRIT_RESOURCE_MAP_STRUCT_ +#define %(macro_prefix)sGRIT_RESOURCE_MAP_STRUCT_ +struct %(struct_prefix)sGritResourceMap { const char* name; - int value; + int value;%(maybe_gzipped_bool)s }; -#endif // GRIT_RESOURCE_MAP_STRUCT_ +#endif // %(macro_prefix)sGRIT_RESOURCE_MAP_STRUCT_ -extern const GritResourceMap %(map_name)s[]; +extern const %(struct_prefix)sGritResourceMap %(map_name)s[]; extern const size_t %(map_name)sSize; -''' % { 'map_name': GetMapName(root) } +''' % { 'map_name': GetMapName(root), + 'maybe_gzipped_bool': '\n bool gzipped;' if include_gzipped else '', + 'struct_prefix': 'Gzipped' if include_gzipped else '', + 'macro_prefix': 'GZIPPED_' if include_gzipped else '', + } -def _FormatSourceHeader(root, output_dir): +def _FormatSourceHeader(root, output_dir, include_gzipped): '''Create the header of the C++ source file for the resource mapping.''' rc_header_file = None map_header_file = None for output in root.GetOutputFiles(): - if 'rc_header' == output.GetType(): + type = output.GetType() + if 'rc_header' == type: rc_header_file = util.MakeRelativePath(output_dir, output.GetOutputFilename()) - elif 'resource_map_header' == output.GetType(): + elif 'resource_map_header' == type or 'gzipped_resource_map_header' == type: map_header_file = util.MakeRelativePath(output_dir, output.GetOutputFilename()) if not rc_header_file or not map_header_file: raise Exception('resource_map_source output type requires ' - 'resource_map_header and rc_header outputs') + 'a *resource_map_header and rc_header outputs') return '''\ // This file is automatically generated by GRIT. Do not edit. @@ -91,10 +100,11 @@ #include "%(rc_header_file)s" -const GritResourceMap %(map_name)s[] = { +const %(struct_prefix)sGritResourceMap %(map_name)s[] = { ''' % { 'map_header_file': map_header_file, 'rc_header_file': rc_header_file, 'map_name': GetMapName(root), + 'struct_prefix': 'Gzipped' if include_gzipped else '', } @@ -107,24 +117,23 @@ ''' % { 'map_name': GetMapName(root) } -def _FormatSource(get_key, root, lang, output_dir): - from grit.format import rc_header +def _FormatSource(get_key, root, lang, output_dir, include_gzipped=False): from grit.node import include, structure, message - yield _FormatSourceHeader(root, output_dir) - tids = rc_header.GetIds(root) + id_map = root.GetIdMap() + yield _FormatSourceHeader(root, output_dir, include_gzipped) seen = set() - active_descendants = [item for item in root.ActiveDescendants()] - output_all_resource_defines = root.ShouldOutputAllResourceDefines() - for item in root: + for item in root.ActiveDescendants(): if not item.IsResourceMapSource(): continue key = get_key(item) tid = item.attrs['name'] - if tid not in tids or key in seen: + if tid not in id_map or key in seen: continue - if item.GeneratesResourceMapEntry(output_all_resource_defines, - item in active_descendants): - seen.add(key) + seen.add(key) + if include_gzipped: + gzipped = item.attrs.get('compress', '') == 'gzip' + yield ' {"%s", %s, %s},\n' % (key, tid, 'true' if gzipped else 'false') + else: yield ' {"%s", %s},\n' % (key, tid) yield _FormatSourceFooter(root)
diff --git a/tools/grit/grit/format/resource_map_unittest.py b/tools/grit/grit/format/resource_map_unittest.py index 31d481e..8be4167 100755 --- a/tools/grit/grit/format/resource_map_unittest.py +++ b/tools/grit/grit/format/resource_map_unittest.py
@@ -10,7 +10,6 @@ if __name__ == '__main__': sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) -import StringIO import unittest from grit import grd_reader @@ -20,10 +19,7 @@ class FormatResourceMapUnittest(unittest.TestCase): def testFormatResourceMap(self): - grd = grd_reader.Parse(StringIO.StringIO( - '''<?xml version="1.0" encoding="UTF-8"?> - <grit latest_public_release="2" source_lang_id="en" current_release="3" - base_dir="."> + grd = util.ParseGrdForUnittest(''' <outputs> <output type="rc_header" filename="the_rc_header.h" /> <output type="resource_map_header" @@ -47,10 +43,7 @@ </if> <include type="foo" file="mno" name="IDS_THIRDPRESENT" /> </includes> - </release> - </grit>'''), util.PathFromRoot('.')) - grd.SetOutputLanguage('en') - grd.RunGatherers() + </release>''', run_gatherers=True) output = util.StripBlankLinesAndComments(''.join( resource_map.GetFormatter('resource_map_header')(grd, 'en', '.'))) self.assertEqual('''\ @@ -74,7 +67,6 @@ const GritResourceMap kTheRcHeader[] = { {"IDC_KLONKMENU", IDC_KLONKMENU}, {"IDS_FIRSTPRESENT", IDS_FIRSTPRESENT}, - {"IDS_MISSING", IDS_MISSING}, {"IDS_LANGUAGESPECIFIC", IDS_LANGUAGESPECIFIC}, {"IDS_THIRDPRESENT", IDS_THIRDPRESENT}, }; @@ -89,18 +81,61 @@ const GritResourceMap kTheRcHeader[] = { {"grit/testdata/klonk.rc", IDC_KLONKMENU}, {"abc", IDS_FIRSTPRESENT}, - {"def", IDS_MISSING}, {"ghi", IDS_LANGUAGESPECIFIC}, - {"jkl", IDS_LANGUAGESPECIFIC}, {"mno", IDS_THIRDPRESENT}, }; const size_t kTheRcHeaderSize = arraysize(kTheRcHeader);''', output) + def testGzippedMapHeaderAndFileSource(self): + grd = util.ParseGrdForUnittest('''\ + <outputs> + <output type="rc_header" filename="the_rc_header.h" /> + <output type="gzipped_resource_map_header" + filename="gzipped_resource_map_header.h" /> + </outputs> + <release seq="3"> + <structures first_id="300"> + <structure type="menu" name="IDC_KLONKMENU" compress="gzip" + file="grit\\testdata\\klonk.rc" encoding="utf-16" /> + </structures> + <includes first_id="10000"> + <include type="foo" file="abc" name="IDS_FIRSTPRESENT" + compress="" /> + <if expr="False"> + <include type="foo" file="def" name="IDS_MISSING" + compress="garbage" /> + </if> + </includes> + </release>''', run_gatherers=True) + formatter = resource_map.GetFormatter('gzipped_resource_map_header') + output = util.StripBlankLinesAndComments(''.join(formatter(grd, 'en', '.'))) + self.assertEqual('''\ +#include <stddef.h> +#ifndef GZIPPED_GRIT_RESOURCE_MAP_STRUCT_ +#define GZIPPED_GRIT_RESOURCE_MAP_STRUCT_ +struct GzippedGritResourceMap { + const char* name; + int value; + bool gzipped; +}; +#endif // GZIPPED_GRIT_RESOURCE_MAP_STRUCT_ +extern const GzippedGritResourceMap kTheRcHeader[]; +extern const size_t kTheRcHeaderSize;''', output) + formatter = resource_map.GetFormatter('gzipped_resource_file_map_source') + output = util.StripBlankLinesAndComments(''.join(formatter(grd, 'en', '.'))) + self.assertEqual('''\ +#include "gzipped_resource_map_header.h" +#include <stddef.h> +#include "base/macros.h" +#include "the_rc_header.h" +const GzippedGritResourceMap kTheRcHeader[] = { + {"grit/testdata/klonk.rc", IDC_KLONKMENU, true}, + {"abc", IDS_FIRSTPRESENT, false}, +}; +const size_t kTheRcHeaderSize = arraysize(kTheRcHeader);''', output) + def testFormatResourceMapWithOutputAllEqualsFalseForStructures(self): - grd = grd_reader.Parse(StringIO.StringIO( - '''<?xml version="1.0" encoding="UTF-8"?> - <grit latest_public_release="2" source_lang_id="en" current_release="3" - base_dir="." output_all_resource_defines="false"> + grd = util.ParseGrdForUnittest(''' <outputs> <output type="rc_header" filename="the_rc_header.h" /> <output type="resource_map_header" @@ -139,10 +174,7 @@ file="xyz.png" /> </if> </structures> - </release> - </grit>'''), util.PathFromRoot('.')) - grd.SetOutputLanguage('en') - grd.RunGatherers() + </release>''', run_gatherers=True) output = util.StripBlankLinesAndComments(''.join( resource_map.GetFormatter('resource_map_header')(grd, 'en', '.'))) self.assertEqual('''\ @@ -186,10 +218,7 @@ const size_t kTheRcHeaderSize = arraysize(kTheRcHeader);''', output) def testFormatResourceMapWithOutputAllEqualsFalseForIncludes(self): - grd = grd_reader.Parse(StringIO.StringIO( - '''<?xml version="1.0" encoding="UTF-8"?> - <grit latest_public_release="2" source_lang_id="en" current_release="3" - base_dir="." output_all_resource_defines="false"> + grd = util.ParseGrdForUnittest(''' <outputs> <output type="rc_header" filename="the_rc_header.h" /> <output type="resource_map_header" @@ -224,10 +253,7 @@ <include type="foo" file="xyz" name="IDS_LAST" /> </if> </includes> - </release> - </grit>'''), util.PathFromRoot('.')) - grd.SetOutputLanguage('en') - grd.RunGatherers() + </release>''', run_gatherers=True) output = util.StripBlankLinesAndComments(''.join( resource_map.GetFormatter('resource_map_header')(grd, 'en', '.'))) self.assertEqual('''\ @@ -275,10 +301,7 @@ const size_t kTheRcHeaderSize = arraysize(kTheRcHeader);''', output) def testFormatStringResourceMap(self): - grd = grd_reader.Parse(StringIO.StringIO( - '''<?xml version="1.0" encoding="UTF-8"?> - <grit latest_public_release="2" source_lang_id="en" current_release="3" - base_dir="."> + grd = util.ParseGrdForUnittest(''' <outputs> <output type="rc_header" filename="the_rc_header.h" /> <output type="resource_map_header" filename="the_rc_map_header.h" /> @@ -302,10 +325,8 @@ </message> </if> </messages> - </release> - </grit>'''), util.PathFromRoot('.')) - grd.SetOutputLanguage('en') - grd.RunGatherers() + </release>''', run_gatherers=True) + grd.InitializeIds() output = util.StripBlankLinesAndComments(''.join( resource_map.GetFormatter('resource_map_header')(grd, 'en', '.'))) self.assertEqual('''\
diff --git a/tools/grit/grit/gather/chrome_scaled_image_unittest.py b/tools/grit/grit/gather/chrome_scaled_image_unittest.py index 4b0bbfc..d0e665f 100755 --- a/tools/grit/grit/gather/chrome_scaled_image_unittest.py +++ b/tools/grit/grit/gather/chrome_scaled_image_unittest.py
@@ -46,7 +46,7 @@ def _GetFilesInPak(pakname): '''Get a set of the files that were actually included in the .pak output. ''' - return set(data_pack.DataPack.ReadDataPack(pakname).resources.values()) + return set(data_pack.ReadDataPack(pakname).resources.values()) def _GetFilesInRc(rcname, tmp_dir, contents):
diff --git a/tools/grit/grit/gather/igoogle_strings.py b/tools/grit/grit/gather/igoogle_strings.py deleted file mode 100755 index 79ed839..0000000 --- a/tools/grit/grit/gather/igoogle_strings.py +++ /dev/null
@@ -1,123 +0,0 @@ -#!/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. - -'''Support for ALL_ALL.xml format used by Igoogle plug-ins in Google Desktop.''' - -import StringIO -import re -import xml.sax -import xml.sax.handler -import xml.sax.saxutils - -from grit.gather import regexp -from grit import util -from grit import tclib - -# Placeholders can be defined in strings.xml files by putting the name of the -# placeholder between [![ and ]!] e.g. <MSG>Hello [![USER]!] how are you<MSG> -PLACEHOLDER_RE = re.compile('(\[!\[|\]!\])') - - -class IgoogleStringsContentHandler(xml.sax.handler.ContentHandler): - '''A very dumb parser for splitting the strings.xml file into translateable - and nontranslateable chunks.''' - - def __init__(self, parent): - self.curr_elem = '' - self.curr_text = '' - self.parent = parent - self.resource_name = '' - self.meaning = '' - self.translateable = True - - def startElement(self, name, attrs): - if (name != 'messagebundle'): - self.curr_elem = name - - attr_names = attrs.getQNames() - if 'name' in attr_names: - self.resource_name = attrs.getValueByQName('name') - - att_text = [] - for attr_name in attr_names: - att_text.append(' ') - att_text.append(attr_name) - att_text.append('=') - att_text.append( - xml.sax.saxutils.quoteattr(attrs.getValueByQName(attr_name))) - - self.parent._AddNontranslateableChunk("<%s%s>" % - (name, ''.join(att_text))) - - def characters(self, content): - if self.curr_elem != '': - self.curr_text += content - - def endElement(self, name): - if name != 'messagebundle': - self.parent.AddMessage(self.curr_text, self.resource_name, - self.meaning, self.translateable) - self.parent._AddNontranslateableChunk("</%s>\n" % name) - self.curr_elem = '' - self.curr_text = '' - self.resource_name = '' - self.meaning = '' - self.translateable = True - - def ignorableWhitespace(self, whitespace): - pass - - -class IgoogleStrings(regexp.RegexpGatherer): - '''Supports the ALL_ALL.xml format used by Igoogle gadgets.''' - - def AddMessage(self, msgtext, description, meaning, translateable): - if msgtext == '': - return - - msg = tclib.Message(description=description, meaning=meaning) - - unescaped_text = self.UnEscape(msgtext) - parts = PLACEHOLDER_RE.split(unescaped_text) - in_placeholder = False - for part in parts: - if part == '': - continue - elif part == '[![': - in_placeholder = True - elif part == ']!]': - in_placeholder = False - else: - if in_placeholder: - msg.AppendPlaceholder(tclib.Placeholder(part, '[![%s]!]' % part, - '(placeholder)')) - else: - msg.AppendText(part) - - self.skeleton_.append( - self.uberclique.MakeClique(msg, translateable=translateable)) - - # if statement needed because this is supposed to be idempotent (so never - # set back to false) - if translateable: - self.translatable_chunk_ = True - - # Although we use the RegexpGatherer base class, we do not use the - # _RegExpParse method of that class to implement Parse(). Instead, we - # parse using a SAX parser. - def Parse(self): - if self.have_parsed_: - return - self.have_parsed_ = True - - self.text_ = self._LoadInputFile().strip() - self._AddNontranslateableChunk(u'<messagebundle>\n') - stream = StringIO.StringIO(self.text_) - handler = IgoogleStringsContentHandler(self) - xml.sax.parse(stream, handler) - self._AddNontranslateableChunk(u'</messagebundle>\n') - - def Escape(self, text): - return util.EncodeCdata(text)
diff --git a/tools/grit/grit/gather/igoogle_strings_unittest.py b/tools/grit/grit/gather/igoogle_strings_unittest.py deleted file mode 100755 index 3a4488c..0000000 --- a/tools/grit/grit/gather/igoogle_strings_unittest.py +++ /dev/null
@@ -1,29 +0,0 @@ -#!/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. - -'''Unit tests for grit.gather.igoogle_strings''' - -import os -import sys -if __name__ == '__main__': - sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) - -import unittest -import StringIO - -from grit.gather import igoogle_strings - -class IgoogleStringsUnittest(unittest.TestCase): - def testParsing(self): - original = '''<messagebundle><msg test="hello_world">Hello World</msg></messagebundle>''' - gatherer = igoogle_strings.IgoogleStrings(StringIO.StringIO(original)) - gatherer.Parse() - print len(gatherer.GetCliques()) - print gatherer.GetCliques()[0].GetMessage().GetRealContent() - self.failUnless(len(gatherer.GetCliques()) == 1) - self.failUnless(gatherer.Translate('en').replace('\n', '') == original) - -if __name__ == '__main__': - unittest.main()
diff --git a/tools/grit/grit/gather/muppet_strings.py b/tools/grit/grit/gather/muppet_strings.py deleted file mode 100755 index ab2f08a3d..0000000 --- a/tools/grit/grit/gather/muppet_strings.py +++ /dev/null
@@ -1,133 +0,0 @@ -#!/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. - -'''Support for "strings.xml" format used by Muppet plug-ins in Google Desktop.''' - -import StringIO -import xml.sax -import xml.sax.handler -import xml.sax.saxutils - -from grit import lazy_re -from grit import tclib -from grit import util -from grit.gather import regexp - - -# Placeholders can be defined in strings.xml files by putting the name of the -# placeholder between [![ and ]!] e.g. <MSG>Hello [![USER]!] how are you<MSG> -PLACEHOLDER_RE = lazy_re.compile('(\[!\[|\]!\])') - - -class MuppetStringsContentHandler(xml.sax.handler.ContentHandler): - '''A very dumb parser for splitting the strings.xml file into translateable - and nontranslateable chunks.''' - - def __init__(self, parent): - self.curr_elem = '' - self.curr_text = '' - self.parent = parent - self.description = '' - self.meaning = '' - self.translateable = True - - def startElement(self, name, attrs): - if (name != 'strings'): - self.curr_elem = name - - attr_names = attrs.getQNames() - if 'desc' in attr_names: - self.description = attrs.getValueByQName('desc') - if 'meaning' in attr_names: - self.meaning = attrs.getValueByQName('meaning') - if 'translateable' in attr_names: - value = attrs.getValueByQName('translateable') - if value.lower() not in ['true', 'yes']: - self.translateable = False - - att_text = [] - for attr_name in attr_names: - att_text.append(' ') - att_text.append(attr_name) - att_text.append('=') - att_text.append( - xml.sax.saxutils.quoteattr(attrs.getValueByQName(attr_name))) - - self.parent._AddNontranslateableChunk("<%s%s>" % - (name, ''.join(att_text))) - - def characters(self, content): - if self.curr_elem != '': - self.curr_text += content - - def endElement(self, name): - if name != 'strings': - self.parent.AddMessage(self.curr_text, self.description, - self.meaning, self.translateable) - self.parent._AddNontranslateableChunk("</%s>\n" % name) - self.curr_elem = '' - self.curr_text = '' - self.description = '' - self.meaning = '' - self.translateable = True - - def ignorableWhitespace(self, whitespace): - pass - -class MuppetStrings(regexp.RegexpGatherer): - '''Supports the strings.xml format used by Muppet gadgets.''' - - def AddMessage(self, msgtext, description, meaning, translateable): - if msgtext == '': - return - - msg = tclib.Message(description=description, meaning=meaning) - - unescaped_text = self.UnEscape(msgtext) - parts = PLACEHOLDER_RE.split(unescaped_text) - in_placeholder = False - for part in parts: - if part == '': - continue - elif part == '[![': - in_placeholder = True - elif part == ']!]': - in_placeholder = False - else: - if in_placeholder: - msg.AppendPlaceholder(tclib.Placeholder(part, '[![%s]!]' % part, - '(placeholder)')) - else: - msg.AppendText(part) - - self.skeleton_.append( - self.uberclique.MakeClique(msg, translateable=translateable)) - - # if statement needed because this is supposed to be idempotent (so never - # set back to false) - if translateable: - self.translatable_chunk_ = True - - # Although we use the RegexpGatherer base class, we do not use the - # _RegExpParse method of that class to implement Parse(). Instead, we - # parse using a SAX parser. - def Parse(self): - if self.have_parsed_: - return - self.have_parsed_ = True - - text = self._LoadInputFile().encode(self.encoding) - if util.IsExtraVerbose(): - print text - self.text_ = text.strip() - - self._AddNontranslateableChunk(u'<strings>\n') - stream = StringIO.StringIO(self.text_) - handler = MuppetStringsContentHandler(self) - xml.sax.parse(stream, handler) - self._AddNontranslateableChunk(u'</strings>\n') - - def Escape(self, text): - return util.EncodeCdata(text)
diff --git a/tools/grit/grit/gather/muppet_strings_unittest.py b/tools/grit/grit/gather/muppet_strings_unittest.py deleted file mode 100755 index adf66b65..0000000 --- a/tools/grit/grit/gather/muppet_strings_unittest.py +++ /dev/null
@@ -1,67 +0,0 @@ -#!/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. - -'''Unit tests for grit.gather.muppet_strings''' - -import os -import sys -if __name__ == '__main__': - sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) - -import unittest -import StringIO - -from grit.gather import muppet_strings - -class MuppetStringsUnittest(unittest.TestCase): - def testParsing(self): - original = '''<strings><BLA desc="Says hello">hello!</BLA><BINGO>YEEEESSS!!!</BINGO></strings>''' - gatherer = muppet_strings.MuppetStrings(StringIO.StringIO(original)) - gatherer.Parse() - self.failUnless(len(gatherer.GetCliques()) == 2) - self.failUnless(gatherer.Translate('en').replace('\n', '') == original) - - def testEscapingAndLinebreaks(self): - original = ('''\ -<strings> -<LINEBREAK desc="Howdie">Hello -there -how -are -you?</LINEBREAK> <ESCAPED meaning="bingo">4 < 6</ESCAPED> -</strings>''') - gatherer = muppet_strings.MuppetStrings(StringIO.StringIO(original)) - gatherer.Parse() - self.failUnless(gatherer.GetCliques()[0].translateable) - self.failUnless(len(gatherer.GetCliques()) == 2) - self.failUnless(gatherer.GetCliques()[0].GetMessage().GetRealContent() == - 'Hello\nthere\nhow\nare\nyou?') - self.failUnless(gatherer.GetCliques()[0].GetMessage().GetDescription() == 'Howdie') - self.failUnless(gatherer.GetCliques()[1].GetMessage().GetRealContent() == - '4 < 6') - self.failUnless(gatherer.GetCliques()[1].GetMessage().GetMeaning() == 'bingo') - - def testPlaceholders(self): - original = "<strings><MESSAGE translateable='True'>Hello [![USER]!] how are you? [![HOUR]!]:[![MINUTE]!]</MESSAGE></strings>" - gatherer = muppet_strings.MuppetStrings(StringIO.StringIO(original)) - gatherer.Parse() - self.failUnless(gatherer.GetCliques()[0].translateable) - msg = gatherer.GetCliques()[0].GetMessage() - self.failUnless(len(msg.GetPlaceholders()) == 3) - ph = msg.GetPlaceholders()[0] - self.failUnless(ph.GetOriginal() == '[![USER]!]') - self.failUnless(ph.GetPresentation() == 'USER') - - def testTranslateable(self): - original = "<strings><BINGO translateable='false'>Yo yo hi there</BINGO></strings>" - gatherer = muppet_strings.MuppetStrings(StringIO.StringIO(original)) - gatherer.Parse() - msg = gatherer.GetCliques()[0].GetMessage() - self.failUnless(msg.GetRealContent() == "Yo yo hi there") - self.failUnless(not gatherer.GetCliques()[0].translateable) - -if __name__ == '__main__': - unittest.main() -
diff --git a/tools/grit/grit/gather/policy_json.py b/tools/grit/grit/gather/policy_json.py index 9e95dc6..d11de75 100755 --- a/tools/grit/grit/gather/policy_json.py +++ b/tools/grit/grit/gather/policy_json.py
@@ -205,7 +205,8 @@ self._AddIndentedNontranslateableChunk(depth + 1, "'items': [\n") self._AddItems(item1['items'], 'enum_item', item1, depth + 2) self._AddIndentedNontranslateableChunk(depth + 1, "],\n") - elif key == 'policies': + elif key == 'policies' and all(not isinstance(x, str) + for x in item1['policies']): self._AddIndentedNontranslateableChunk(depth + 1, "'policies': [\n") self._AddItems(item1['policies'], 'policy', item1, depth + 2) self._AddIndentedNontranslateableChunk(depth + 1, "],\n")
diff --git a/tools/grit/grit/gather/policy_json_unittest.py b/tools/grit/grit/gather/policy_json_unittest.py index f536f5d8..34f4a42 100755 --- a/tools/grit/grit/gather/policy_json_unittest.py +++ b/tools/grit/grit/gather/policy_json_unittest.py
@@ -81,18 +81,41 @@ expected = self.GetExpectedOutput(original) self.failUnless(expected == eval(gatherer.Translate('en'))) - def testSubPolicy(self): + # Keeping for backwards compatibility. + def testSubPolicyOldFormat(self): original = ( "{" " 'policy_definitions': [" " {" + " 'type': 'group'," " 'policies': [" " {" " 'name': 'Policy1'," " 'caption': 'nothing special'," " }" " ]" + " }" + " ]," + " 'messages': {}" + "}") + gatherer = policy_json.PolicyJson(StringIO.StringIO(original)) + gatherer.Parse() + self.failUnless(len(gatherer.GetCliques()) == 1) + expected = self.GetExpectedOutput(original) + self.failUnless(expected == eval(gatherer.Translate('en'))) + + def testSubPolicyNewFormat(self): + original = ( + "{" + " 'policy_definitions': [" + " {" + " 'type': 'group'," + " 'policies': ['Policy1']" " }," + " {" + " 'name': 'Policy1'," + " 'caption': 'nothing special'," + " }" " ]," " 'messages': {}" "}")
diff --git a/tools/grit/grit/grd_reader.py b/tools/grit/grit/grd_reader.py index fb33e9c7..733dc23 100755 --- a/tools/grit/grit/grd_reader.py +++ b/tools/grit/grit/grd_reader.py
@@ -13,7 +13,6 @@ from grit import exception from grit import util -from grit.format import rc_header from grit.node import base from grit.node import mapping from grit.node import misc @@ -192,7 +191,6 @@ else: source = None - rc_header.SetPredeterminedIdsFile(predetermined_ids_file) handler = GrdContentHandler(stop_after=stop_after, debug=debug, dir=dir, defines=defines, tags_to_ignore=tags_to_ignore, target_platform=target_platform, source=source) @@ -215,6 +213,7 @@ handler.root.SetOwnDir(dir) if isinstance(handler.root, misc.GritNode): + handler.root.SetPredeterminedIdsFile(predetermined_ids_file) if first_ids_file: # Make the path to the first_ids_file relative to the grd file, # unless it begins with GRIT_DIR.
diff --git a/tools/grit/grit/grit_runner.py b/tools/grit/grit/grit_runner.py index 6c1cf5e..58160e4 100755 --- a/tools/grit/grit/grit_runner.py +++ b/tools/grit/grit/grit_runner.py
@@ -111,12 +111,6 @@ if not _HIDDEN in info.keys(): tool_list += ' %-12s %s\n' % (tool, info[_FACTORY]().ShortDescription()) - # TODO(joi) Put these back into the usage when appropriate: - # - # -d Work disconnected. This causes GRIT not to attempt connections with - # e.g. Perforce. - # - # -c Use the specified Perforce CLIENT when talking to Perforce. print """GRIT - the Google Resource and Internationalization Tool Usage: grit [GLOBALOPTIONS] TOOL [args to tool] @@ -152,23 +146,18 @@ """Option storage and parsing.""" def __init__(self): - self.disconnected = False - self.client = '' self.hash = None self.input = None self.verbose = False self.extra_verbose = False self.output_stream = sys.stdout self.profile_dest = None - self.psyco = False def ReadOptions(self, args): """Reads options from the start of args and returns the remainder.""" - (opts, args) = getopt.getopt(args, 'g:qdvxc:i:p:h:', ('psyco',)) + (opts, args) = getopt.getopt(args, 'vxi:p:h:') for (key, val) in opts: - if key == '-d': self.disconnected = True - elif key == '-c': self.client = val - elif key == '-h': self.hash = val + if key == '-h': self.hash = val elif key == '-i': self.input = val elif key == '-v': self.verbose = True @@ -179,7 +168,6 @@ self.extra_verbose = True util.extra_verbose = True elif key == '-p': self.profile_dest = val - elif key == '--psyco': self.psyco = True if not self.input: if 'GRIT_INPUT' in os.environ: @@ -190,8 +178,8 @@ return args def __repr__(self): - return '(disconnected: %d, verbose: %d, client: %s, input: %s)' % ( - self.disconnected, self.verbose, self.client, self.input) + return '(verbose: %d, input: %s)' % ( + self.verbose, self.input) def _GetToolInfo(tool): @@ -249,13 +237,6 @@ ' from the current directory.' % options.input) return 2 - if options.psyco: - # Psyco is a specializing JIT for Python. Early tests indicate that it - # could speed up GRIT (at the expense of more memory) for large GRIT - # compilations. See http://psyco.sourceforge.net/ - import psyco - psyco.profile() - if options.hash: grit.extern.FP.UseUnsignedFingerPrintFromModule(options.hash)
diff --git a/tools/grit/grit/grit_runner_unittest.py b/tools/grit/grit/grit_runner_unittest.py index ad6b2ec..591eeae 100755 --- a/tools/grit/grit/grit_runner_unittest.py +++ b/tools/grit/grit/grit_runner_unittest.py
@@ -28,9 +28,8 @@ def testSimple(self): grit.grit_runner.Main(['-i', util.PathFromRoot('grit/testdata/simple-input.xml'), - '-d', 'test', 'bla', 'voff', 'ga']) + 'test', 'bla', 'voff', 'ga']) output = self.buf.getvalue() - self.failUnless(output.count('disconnected')) self.failUnless(output.count("'test'") == 0) # tool name doesn't occur self.failUnless(output.count('bla')) self.failUnless(output.count('simple-input.xml'))
diff --git a/tools/grit/grit/node/base.py b/tools/grit/grit/node/base.py index a91f879..e40bad8 100755 --- a/tools/grit/grit/node/base.py +++ b/tools/grit/grit/node/base.py
@@ -8,12 +8,14 @@ import ast import os +import sys import types from xml.sax import saxutils from grit import clique from grit import exception from grit import util +import grit.format.gzip_string class Node(object): @@ -595,16 +597,24 @@ '''Whether this node is a resource map source.''' return False - def GeneratesResourceMapEntry(self, output_all_resource_defines, - is_active_descendant): - '''Whether this node should output a resource map entry. + def CompressDataIfNeeded(self, data): + '''Compress data using the format specified in the compress attribute. Args: - output_all_resource_defines: The value of output_all_resource_defines for - the root node. - is_active_descendant: Whether the current node is an active descendant - from the root node.''' - return False + data: The data to compressed. + Returns: + The data in compressed format. If the format was unknown then this returns + the data uncompressed. + ''' + if self.attrs.get('compress') != 'gzip': + return data + + # We only use rsyncable compression on Linux. + # We exclude ChromeOS since ChromeOS bots are Linux based but do not have + # the --rsyncable option built in for gzip. See crbug.com/617950. + if sys.platform == 'linux2' and 'chromeos' not in self.GetRoot().defines: + return grit.format.gzip_string.GzipStringRsyncable(data) + return grit.format.gzip_string.GzipString(data) class ContentNode(Node):
diff --git a/tools/grit/grit/node/include.py b/tools/grit/grit/node/include.py index 46f1c07..27cff17a10 100755 --- a/tools/grit/grit/node/include.py +++ b/tools/grit/grit/node/include.py
@@ -7,14 +7,11 @@ """ import os -import sys from grit import exception from grit import util -import grit.format.gzip_string import grit.format.html_inline import grit.format.rc -import grit.format.rc_header from grit.format import minifier from grit.node import base @@ -79,15 +76,8 @@ return self.ToRealPath(input_path) - def GetDataPackPair(self, lang, encoding): - """Returns a (id, string) pair that represents the resource id and raw - bytes of the data. This is used to generate the data pack data file. - """ - # TODO(benrg/joi): Move this and other implementations of GetDataPackPair - # to grit.format.data_pack? - from grit.format import rc_header - id_map = rc_header.GetIds(self.GetRoot()) - id = id_map[self.GetTextualIds()[0]] + def GetDataPackValue(self, lang, encoding): + '''Returns a str represenation for a data_pack entry.''' filename = self.ToRealPath(self.GetInputPath()) if self.attrs['flattenhtml'] == 'true': allow_external_script = self.attrs['allowexternalscript'] == 'true' @@ -97,19 +87,10 @@ # Note that the minifier will only do anything if a minifier command # has been set in the command line. data = minifier.Minify(data, filename) - use_gzip = self.attrs.get('compress', '') == 'gzip' - if use_gzip and self.GetRoot().target_platform != 'ios': - # We only use rsyncable compression on Linux. - # We exclude ChromeOS since ChromeOS bots are Linux based but do not have - # the --rsyncable option built in for gzip. See crbug.com/617950. - if sys.platform == 'linux2' and 'chromeos' not in self.GetRoot().defines: - data = grit.format.gzip_string.GzipStringRsyncable(data) - else: - data = grit.format.gzip_string.GzipString(data) # Include does not care about the encoding, because it only returns binary # data. - return id, data + return self.CompressDataIfNeeded(data) def Process(self, output_dir): """Rewrite file references to be base64 encoded data URLs. The new file @@ -137,13 +118,6 @@ def IsResourceMapSource(self): return True - def GeneratesResourceMapEntry(self, output_all_resource_defines, - is_active_descendant): - # includes always generate resource entries. - if output_all_resource_defines: - return True - return is_active_descendant - @staticmethod def Construct(parent, name, type, file, translateable=True, filenameonly=False, mkoutput=False, relativepath=False):
diff --git a/tools/grit/grit/node/include_unittest.py b/tools/grit/grit/node/include_unittest.py index 031c1bf..3bf1a6891 100755 --- a/tools/grit/grit/node/include_unittest.py +++ b/tools/grit/grit/node/include_unittest.py
@@ -76,7 +76,7 @@ compress="gzip" type="BINDATA"/> </includes>''', base_dir = util.PathFromRoot('grit/testdata')) inc, = root.GetChildrenOfType(include.IncludeNode) - throwaway, compressed = inc.GetDataPackPair(lang='en', encoding=1) + compressed = inc.GetDataPackValue(lang='en', encoding=1) decompressed_data = zlib.decompress(compressed, 16 + zlib.MAX_WBITS) self.assertEqual(util.ReadFile(util.PathFromRoot('grit/testdata')
diff --git a/tools/grit/grit/node/message.py b/tools/grit/grit/node/message.py index e3024fb..1b887c2 100755 --- a/tools/grit/grit/node/message.py +++ b/tools/grit/grit/node/message.py
@@ -223,25 +223,14 @@ '''We always expand variables on Messages.''' return True - def GetDataPackPair(self, lang, encoding): - '''Returns a (id, string) pair that represents the string id and the string - in the specified encoding, where |encoding| is one of the encoding values - accepted by util.Encode. This is used to generate the data pack data file. - ''' - from grit.format import rc_header - id_map = rc_header.GetIds(self.GetRoot()) - id = id_map[self.GetTextualIds()[0]] - + def GetDataPackValue(self, lang, encoding): + '''Returns a str represenation for a data_pack entry.''' message = self.ws_at_start + self.Translate(lang) + self.ws_at_end - return id, util.Encode(message, encoding) + return util.Encode(message, encoding) def IsResourceMapSource(self): return True - def GeneratesResourceMapEntry(self, output_all_resource_defines, - is_active_descendant): - return is_active_descendant - @staticmethod def Construct(parent, message, name, desc='', meaning='', translateable=True): '''Constructs a new message node that is a child of 'parent', with the
diff --git a/tools/grit/grit/node/misc.py b/tools/grit/grit/node/misc.py index bd999709b..f3bcab90 100755 --- a/tools/grit/grit/node/misc.py +++ b/tools/grit/grit/node/misc.py
@@ -13,6 +13,7 @@ from grit import constants from grit import exception from grit import util +from grit.extern import FP import grit.format.rc_header from grit.node import base from grit.node import io @@ -72,6 +73,138 @@ return (src_root_dir, first_ids_dict) +def _ComputeIds(root, predetermined_tids): + """Returns a dict of textual id -> numeric id for all nodes in root. + + IDs are mostly assigned sequentially, but will vary based on: + * first_id node attribute (from first_ids_file) + * hash of textual id (if not first_id is defined) + * offset node attribute + * whether the textual id matches a system id + * whether the node generates its own ID via GetId() + + Args: + predetermined_tids: Dict of textual id -> numeric id to use in return dict. + """ + from grit.node import empty, include, message, misc, structure + + ids = {} # Maps numeric id to textual id + tids = {} # Maps textual id to numeric id + id_reasons = {} # Maps numeric id to text id and a human-readable explanation + group = None + last_id = None + predetermined_ids = {value: key + for key, value in predetermined_tids.iteritems()} + + for item in root: + if isinstance(item, empty.GroupingNode): + # Note: this won't work if any GroupingNode can be contained inside + # another. + group = item + last_id = None + continue + + assert not item.GetTextualIds() or isinstance(item, + (include.IncludeNode, message.MessageNode, + misc.IdentifierNode, structure.StructureNode)) + + # Resources that use the RES protocol don't need + # any numerical ids generated, so we skip them altogether. + # This is accomplished by setting the flag 'generateid' to false + # in the GRD file. + if item.attrs.get('generateid', 'true') == 'false': + continue + + for tid in item.GetTextualIds(): + if util.SYSTEM_IDENTIFIERS.match(tid): + # Don't emit a new ID for predefined IDs + continue + + if tid in tids: + continue + + if predetermined_tids and tid in predetermined_tids: + id = predetermined_tids[tid] + reason = "from predetermined_tids map" + + # Some identifier nodes can provide their own id, + # and we use that id in the generated header in that case. + elif hasattr(item, 'GetId') and item.GetId(): + id = long(item.GetId()) + reason = 'returned by GetId() method' + + elif ('offset' in item.attrs and group and + group.attrs.get('first_id', '') != ''): + offset_text = item.attrs['offset'] + parent_text = group.attrs['first_id'] + + try: + offset_id = long(offset_text) + except ValueError: + offset_id = tids[offset_text] + + try: + parent_id = long(parent_text) + except ValueError: + parent_id = tids[parent_text] + + id = parent_id + offset_id + reason = 'first_id %d + offset %d' % (parent_id, offset_id) + + # We try to allocate IDs sequentially for blocks of items that might + # be related, for instance strings in a stringtable (as their IDs might be + # used e.g. as IDs for some radio buttons, in which case the IDs must + # be sequential). + # + # We do this by having the first item in a section store its computed ID + # (computed from a fingerprint) in its parent object. Subsequent children + # of the same parent will then try to get IDs that sequentially follow + # the currently stored ID (on the parent) and increment it. + elif last_id is None: + # First check if the starting ID is explicitly specified by the parent. + if group and group.attrs.get('first_id', '') != '': + id = long(group.attrs['first_id']) + reason = "from parent's first_id attribute" + else: + # Automatically generate the ID based on the first clique from the + # first child of the first child node of our parent (i.e. when we + # first get to this location in the code). + + # According to + # http://msdn.microsoft.com/en-us/library/t2zechd4(VS.71).aspx + # the safe usable range for resource IDs in Windows is from decimal + # 101 to 0x7FFF. + + id = FP.UnsignedFingerPrint(tid) + id = id % (0x7FFF - 101) + 101 + reason = 'chosen by random fingerprint -- use first_id to override' + + last_id = id + else: + id = last_id = last_id + 1 + reason = 'sequentially assigned' + + reason = "%s (%s)" % (tid, reason) + # Don't fail when 'offset' is specified, as the base and the 0th + # offset will have the same ID. + if id in id_reasons and not 'offset' in item.attrs: + raise exception.IdRangeOverlap('ID %d was assigned to both %s and %s.' + % (id, id_reasons[id], reason)) + + if id < 101: + print ('WARNING: Numeric resource IDs should be greater than 100 to\n' + 'avoid conflicts with system-defined resource IDs.') + + if tid not in predetermined_tids and id in predetermined_ids: + raise exception.IdRangeOverlap('ID %d overlaps between %s and %s' + % (id, tid, predetermined_ids[tid])) + + ids[id] = tid + tids[tid] = id + id_reasons[id] = reason + + return tids + class SplicingNode(base.Node): """A node whose children should be considered to be at the same level as its siblings for most purposes. This includes <if> and <part> nodes. @@ -172,6 +305,8 @@ self.defines = {} self.substituter = None self.target_platform = sys.platform + self._predetermined_ids_file = None + self._id_map = None # Dict of textual_id -> numeric_id. def _IsValidChild(self, child): from grit.node import empty @@ -200,7 +335,6 @@ 'source_lang_id' : 'en', 'enc_check' : constants.ENCODING_CHECK, 'tc_project' : 'NEED_TO_SET_tc_project_ATTRIBUTE', - 'output_all_resource_defines': 'true', 'rc_header_format': None } @@ -292,18 +426,6 @@ """ return self.attrs['base_dir'] - def SetShouldOutputAllResourceDefines(self, value): - """Overrides the value of output_all_resource_defines found in the grd file. - """ - self.attrs['output_all_resource_defines'] = 'true' if value else 'false' - - def ShouldOutputAllResourceDefines(self): - """Returns true if all resource defines should be output, false if - defines for resources not emitted to resource files should be - skipped. - """ - return self.attrs['output_all_resource_defines'] == 'true' - def GetRcHeaderFormat(self): return self.attrs['rc_header_format'] @@ -322,6 +444,11 @@ # Check if the input is required for any output configuration. input_files = set() + # Collect even inactive PartNodes since they affect ID assignments. + for node in self: + if isinstance(node, misc.PartNode): + input_files.add(self.ToRealPath(node.GetInputPath())) + old_output_language = self.output_language for lang, ctx, fallback in self.GetConfigurations(): self.SetOutputLanguage(lang or self.GetSourceLanguage()) @@ -329,7 +456,7 @@ self.SetFallbackToDefaultLayout(fallback) for node in self.ActiveDescendants(): - if isinstance(node, (io.FileNode, include.IncludeNode, misc.PartNode, + if isinstance(node, (io.FileNode, include.IncludeNode, structure.StructureNode, variant.SkeletonNode)): input_path = node.GetInputPath() if input_path is not None: @@ -442,6 +569,7 @@ """Assign first ids to each grouping node based on values from the first_ids file (if specified on the <grit> node). """ + assert self._id_map is None, 'AssignFirstIds() after InitializeIds()' # If the input is a stream, then we're probably in a unit test and # should skip this step. if type(filename_or_stream) not in (str, unicode): @@ -487,6 +615,25 @@ raise Exception('Please update %s and add a first id for %s (%s).' % (first_ids_filename, filename, node.name)) + def GetIdMap(self): + '''Return a dictionary mapping textual ids to numeric ids.''' + return self._id_map + + def SetPredeterminedIdsFile(self, predetermined_ids_file): + assert self._id_map is None, ( + 'SetPredeterminedIdsFile() after InitializeIds()') + self._predetermined_ids_file = predetermined_ids_file + + def InitializeIds(self): + '''Initializes the text ID -> numeric ID mapping.''' + predetermined_id_map = {} + if self._predetermined_ids_file: + with open(self._predetermined_ids_file) as f: + for line in f: + tid, nid = line.split() + predetermined_id_map[tid] = int(nid) + self._id_map = _ComputeIds(self, predetermined_id_map) + def RunGatherers(self, debug=False): '''Call RunPreSubstitutionGatherer() on every node of the tree, then apply substitutions, then call RunPostSubstitutionGatherer() on every node.
diff --git a/tools/grit/grit/node/misc_unittest.py b/tools/grit/grit/node/misc_unittest.py index 005cbf6..0589631 100755 --- a/tools/grit/grit/node/misc_unittest.py +++ b/tools/grit/grit/node/misc_unittest.py
@@ -6,21 +6,32 @@ '''Unit tests for misc.GritNode''' +import StringIO +import contextlib import os import sys +import tempfile +import unittest + if __name__ == '__main__': sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) -import unittest -import StringIO - from grit import grd_reader import grit.exception from grit import util from grit.format import rc +from grit.format import rc_header from grit.node import misc +@contextlib.contextmanager +def _MakeTempPredeterminedIdsFile(content): + with tempfile.NamedTemporaryFile() as f: + f.write(content) + f.flush() + yield f.name + + class GritNodeUnittest(unittest.TestCase): def testUniqueNameAttribute(self): try: @@ -106,6 +117,83 @@ actual = [path.replace('\\', '/') for path in actual] self.assertEquals(expected, actual) + def testNonDefaultEntry(self): + grd = util.ParseGrdForUnittest(''' + <messages> + <message name="IDS_A" desc="foo">bar</message> + <if expr="lang == 'fr'"> + <message name="IDS_B" desc="foo">bar</message> + </if> + </messages>''') + grd.SetOutputLanguage('fr') + output = ''.join(rc_header.Format(grd, 'fr', '.')) + self.assertIn('#define IDS_A 2378\n#define IDS_B 2379', output) + + def testExplicitFirstIdOverlaps(self): + # second first_id will overlap preexisting range + self.assertRaises(grit.exception.IdRangeOverlap, + util.ParseGrdForUnittest, ''' + <includes first_id="300" comment="bingo"> + <include type="gif" name="ID_LOGO" file="images/logo.gif" /> + <include type="gif" name="ID_LOGO2" file="images/logo2.gif" /> + </includes> + <messages first_id="301"> + <message name="IDS_GREETING" desc="Printed to greet the currently logged in user"> + Hello <ph name="USERNAME">%s<ex>Joi</ex></ph>, how are you doing today? + </message> + <message name="IDS_SMURFGEBURF">Frubegfrums</message> + </messages>''') + + def testImplicitOverlapsPreexisting(self): + # second message in <messages> will overlap preexisting range + self.assertRaises(grit.exception.IdRangeOverlap, + util.ParseGrdForUnittest, ''' + <includes first_id="301" comment="bingo"> + <include type="gif" name="ID_LOGO" file="images/logo.gif" /> + <include type="gif" name="ID_LOGO2" file="images/logo2.gif" /> + </includes> + <messages first_id="300"> + <message name="IDS_GREETING" desc="Printed to greet the currently logged in user"> + Hello <ph name="USERNAME">%s<ex>Joi</ex></ph>, how are you doing today? + </message> + <message name="IDS_SMURFGEBURF">Frubegfrums</message> + </messages>''') + + def testPredeterminedIds(self): + with _MakeTempPredeterminedIdsFile('IDS_A 101\nIDS_B 102') as ids_file: + grd = util.ParseGrdForUnittest(''' + <includes first_id="300" comment="bingo"> + <include type="gif" name="IDS_B" file="images/logo.gif" /> + </includes> + <messages first_id="10000"> + <message name="IDS_GREETING" desc="Printed to greet the currently logged in user"> + Hello <ph name="USERNAME">%s<ex>Joi</ex></ph>, how are you doing today? + </message> + <message name="IDS_A"> + Bongo! + </message> + </messages>''', predetermined_ids_file=ids_file) + output = rc_header.FormatDefines(grd, grd.GetRcHeaderFormat()) + self.assertEqual(('#define IDS_B 102\n' + '#define IDS_GREETING 10000\n' + '#define IDS_A 101\n'), ''.join(output)) + + def testPredeterminedIdsOverlap(self): + with _MakeTempPredeterminedIdsFile('ID_LOGO 10000') as ids_file: + self.assertRaises(grit.exception.IdRangeOverlap, + util.ParseGrdForUnittest, ''' + <includes first_id="300" comment="bingo"> + <include type="gif" name="ID_LOGO" file="images/logo.gif" /> + </includes> + <messages first_id="10000"> + <message name="IDS_GREETING" desc="Printed to greet the currently logged in user"> + Hello <ph name="USERNAME">%s<ex>Joi</ex></ph>, how are you doing today? + </message> + <message name="IDS_BONGO"> + Bongo! + </message> + </messages>''', predetermined_ids_file=ids_file) + class IfNodeUnittest(unittest.TestCase): def testIffyness(self):
diff --git a/tools/grit/grit/node/structure.py b/tools/grit/grit/node/structure.py index 07fe649..7b6f7bf 100755 --- a/tools/grit/grit/node/structure.py +++ b/tools/grit/grit/node/structure.py
@@ -18,15 +18,12 @@ import grit.gather.admin_template import grit.gather.chrome_html import grit.gather.chrome_scaled_image -import grit.gather.igoogle_strings -import grit.gather.muppet_strings import grit.gather.policy_json import grit.gather.rc import grit.gather.tr_html import grit.gather.txt import grit.format.rc -import grit.format.rc_header # Type of the gatherer to use for each type attribute _GATHERERS = { @@ -35,9 +32,7 @@ 'chrome_html' : grit.gather.chrome_html.ChromeHtml, 'chrome_scaled_image' : grit.gather.chrome_scaled_image.ChromeScaledImage, 'dialog' : grit.gather.rc.Dialog, - 'igoogle' : grit.gather.igoogle_strings.IgoogleStrings, 'menu' : grit.gather.rc.Menu, - 'muppet' : grit.gather.muppet_strings.MuppetStrings, 'rcdata' : grit.gather.rc.RCData, 'tr_html' : grit.gather.tr_html.TrHtml, 'txt' : grit.gather.txt.TxtFile, @@ -150,6 +145,7 @@ # dependencies. 'sconsdep' : 'false', 'variables': '', + 'compress': 'false', } def IsExcludedFromRc(self): @@ -195,18 +191,14 @@ def GetCliques(self): return self.gatherer.GetCliques() - def GetDataPackPair(self, lang, encoding): - """Returns a (id, string|None) pair that represents the resource id and raw - bytes of the data (or None if no resource is generated). This is used to - generate the data pack data file. - """ - from grit.format import rc_header - id_map = rc_header.GetIds(self.GetRoot()) - id = id_map[self.GetTextualIds()[0]] + def GetDataPackValue(self, lang, encoding): + """Returns a str represenation for a data_pack entry.""" if self.ExpandVariables(): text = self.gatherer.GetText() - return id, util.Encode(self._Substitute(text), encoding) - return id, self.gatherer.GetData(lang, encoding) + data = util.Encode(self._Substitute(text), encoding) + else: + data = self.gatherer.GetData(lang, encoding) + return self.CompressDataIfNeeded(data) def GetHtmlResourceFilenames(self): """Returns a set of all filenames inlined by this node.""" @@ -245,7 +237,7 @@ def HasFileForLanguage(self): return self.attrs['type'] in ['tr_html', 'admin_template', 'txt', - 'muppet', 'igoogle', 'chrome_scaled_image', + 'chrome_scaled_image', 'chrome_html'] def ExpandVariables(self): @@ -341,12 +333,6 @@ def IsResourceMapSource(self): return True - def GeneratesResourceMapEntry(self, output_all_resource_defines, - is_active_descendant): - if output_all_resource_defines: - return True - return is_active_descendant - @staticmethod def Construct(parent, name, type, file, encoding='cp1252'): '''Creates a new node which is a child of 'parent', with attributes set
diff --git a/tools/grit/grit/node/structure_unittest.py b/tools/grit/grit/node/structure_unittest.py index a039bce..2da15ed9 100755 --- a/tools/grit/grit/node/structure_unittest.py +++ b/tools/grit/grit/node/structure_unittest.py
@@ -9,6 +9,7 @@ import os import os.path import sys +import zlib if __name__ == '__main__': sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) @@ -64,6 +65,35 @@ ' Hello!\n' '</p>\n'), result) + def testCompressGzip(self): + test_data_root = util.PathFromRoot('grit/testdata') + root = util.ParseGrdForUnittest(''' + <structures> + <structure name="TEST_TXT" file="test_text.txt" + compress="gzip" type="chrome_html" /> + </structures>''', base_dir=test_data_root) + struct, = root.GetChildrenOfType(structure.StructureNode) + struct.RunPreSubstitutionGatherer() + compressed = struct.GetDataPackValue(lang='en', encoding=1) + + decompressed_data = zlib.decompress(compressed, 16 + zlib.MAX_WBITS) + self.assertEqual(util.ReadFile( + os.path.join(test_data_root, "test_text.txt"), util.BINARY), + decompressed_data) + + def testNotCompressed(self): + test_data_root = util.PathFromRoot('grit/testdata') + root = util.ParseGrdForUnittest(''' + <structures> + <structure name="TEST_TXT" file="test_text.txt" type="chrome_html" /> + </structures>''', base_dir=test_data_root) + struct, = root.GetChildrenOfType(structure.StructureNode) + struct.RunPreSubstitutionGatherer() + data = struct.GetDataPackValue(lang='en', encoding=1) + + self.assertEqual(util.ReadFile( + os.path.join(test_data_root, "test_text.txt"), util.BINARY), data) + if __name__ == '__main__': unittest.main()
diff --git a/tools/grit/grit/test_suite_all.py b/tools/grit/grit/test_suite_all.py index 4befd33..db66bb4 100755 --- a/tools/grit/grit/test_suite_all.py +++ b/tools/grit/grit/test_suite_all.py
@@ -45,8 +45,6 @@ import grit.gather.admin_template_unittest import grit.gather.chrome_html_unittest import grit.gather.chrome_scaled_image_unittest - import grit.gather.igoogle_strings_unittest - import grit.gather.muppet_strings_unittest import grit.gather.policy_json_unittest import grit.gather.rc_unittest import grit.gather.tr_html_unittest @@ -91,8 +89,6 @@ grit.gather.admin_template_unittest.AdmGathererUnittest, grit.gather.chrome_html_unittest.ChromeHtmlUnittest, grit.gather.chrome_scaled_image_unittest.ChromeScaledImageUnittest, - grit.gather.igoogle_strings_unittest.IgoogleStringsUnittest, - grit.gather.muppet_strings_unittest.MuppetStringsUnittest, grit.gather.policy_json_unittest.PolicyJsonUnittest, grit.gather.rc_unittest.RcUnittest, grit.gather.tr_html_unittest.ParserUnittest,
diff --git a/tools/grit/grit/testdata/default_100_percent/a.png b/tools/grit/grit/testdata/default_100_percent/a.png index 7898192..5d50890 100644 --- a/tools/grit/grit/testdata/default_100_percent/a.png +++ b/tools/grit/grit/testdata/default_100_percent/a.png Binary files differ
diff --git a/tools/grit/grit/testdata/depfile.grd b/tools/grit/grit/testdata/depfile.grd new file mode 100644 index 0000000..e2f7191 --- /dev/null +++ b/tools/grit/grit/testdata/depfile.grd
@@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> <!-- -*- XML -*- --> +<grit + base_dir="." + latest_public_release="0" + current_release="1"> + <outputs> + <output filename="default_100_percent.pak" lang="en" type="data_package" context="default_100_percent" /> + <output filename="special_100_percent.pak" lang="en" type="data_package" context="special_100_percent" /> + </outputs> + <release seq="1"> + <structures fallback_to_low_resolution="true"> + <if expr="False"> + <part file="grit_part.grdp" /> + </if> + <structure type="chrome_scaled_image" name="IDR_A" file="a.png" /> + </structures> + </release> +</grit>
diff --git a/tools/grit/grit/testdata/grit_part.grdp b/tools/grit/grit/testdata/grit_part.grdp new file mode 100644 index 0000000..c8e9d926 --- /dev/null +++ b/tools/grit/grit/testdata/grit_part.grdp
@@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8"?> +<grit-part> + <!-- Important for test purposes that this file not exist. --> + <structure type="chrome_scaled_image" name="IDR_DOES_NOT_EXIST" file="does-not-exist.png" /> +</grit-part>
diff --git a/tools/grit/grit/testdata/special_100_percent/a.png b/tools/grit/grit/testdata/special_100_percent/a.png index 7898192..5d50890 100644 --- a/tools/grit/grit/testdata/special_100_percent/a.png +++ b/tools/grit/grit/testdata/special_100_percent/a.png Binary files differ
diff --git a/tools/grit/grit/tool/build.py b/tools/grit/grit/tool/build.py index 13a02ed..0f5b001 100755 --- a/tools/grit/grit/tool/build.py +++ b/tools/grit/grit/tool/build.py
@@ -28,19 +28,21 @@ # require importing all of them on every run of GRIT. '''Map from <output> node types to modules under grit.format.''' _format_modules = { - 'android': 'android_xml', - 'c_format': 'c_format', - 'chrome_messages_json': 'chrome_messages_json', - 'policy_templates': 'policy_templates_json', - 'data_package': 'data_pack', - 'js_map_format': 'js_map_format', - 'rc_all': 'rc', - 'rc_translateable': 'rc', - 'rc_nontranslateable': 'rc', - 'rc_header': 'rc_header', - 'resource_map_header': 'resource_map', - 'resource_map_source': 'resource_map', + 'android': 'android_xml', + 'c_format': 'c_format', + 'chrome_messages_json': 'chrome_messages_json', + 'data_package': 'data_pack', + 'gzipped_resource_file_map_source': 'resource_map', + 'gzipped_resource_map_header': 'resource_map', + 'js_map_format': 'js_map_format', + 'policy_templates': 'policy_templates_json', + 'rc_all': 'rc', + 'rc_header': 'rc_header', + 'rc_nontranslateable': 'rc', + 'rc_translateable': 'rc', 'resource_file_map_source': 'resource_map', + 'resource_map_header': 'resource_map', + 'resource_map_source': 'resource_map', } def GetFormatter(type): @@ -116,11 +118,6 @@ and {numeric_id}. E.g. "#define {textual_id} {numeric_id}" Otherwise it will use the default "#define SYMBOL 1234" - --output-all-resource-defines - --no-output-all-resource-defines If specified, overrides the value of the - output_all_resource_defines attribute of the root <grit> - element of the input .grd file. - --write-only-new flag If flag is non-0, write output files to a temporary file first, and copy it to the real output only if the new file @@ -160,7 +157,6 @@ depfile = None depdir = None rc_header_format = None - output_all_resource_defines = None write_only_new = False depend_on_stamp = False js_minifier = None @@ -194,10 +190,6 @@ first_ids_file = val elif key == '-w': whitelist_filenames.append(val) - elif key == '--output-all-resource-defines': - output_all_resource_defines = True - elif key == '--no-output-all-resource-defines': - output_all_resource_defines = False elif key == '--no-replace-ellipsis': replace_ellipsis = False elif key == '-p': @@ -247,11 +239,6 @@ defines=self.defines, target_platform=target_platform) - # If the output_all_resource_defines option is specified, override the value - # found in the grd file. - if output_all_resource_defines is not None: - self.res.SetShouldOutputAllResourceDefines(output_all_resource_defines) - # Set an output context so that conditionals can use defines during the # gathering stage; we use a dummy language here since we are not outputting # a specific language. @@ -334,8 +321,30 @@ outfile.writelines(formatted) if output_node.GetType() == 'data_package': with open(output_node.GetOutputFilename() + '.info', 'w') as infofile: - infofile.writelines('\n'.join(node.info)) + if node.info: + # We terminate with a newline so that when these files are + # concatenated later we consistently terminate with a newline so + # consumers can account for terminating newlines. + infofile.writelines(['\n'.join(node.info), '\n']) + @staticmethod + def _EncodingForOutputType(output_type): + # Microsoft's RC compiler can only deal with single-byte or double-byte + # files (no UTF-8), so we make all RC files UTF-16 to support all + # character sets. + if output_type in ('rc_header', 'resource_map_header', + 'resource_map_source', 'resource_file_map_source', + 'gzipped_resource_map_header', + 'gzipped_resource_file_map_source'): + return 'cp1252' + if output_type in ('android', 'c_format', 'js_map_format', 'plist', + 'plist_strings', 'doc', 'json', 'android_policy'): + return 'utf_8' + if output_type in ('chrome_messages_json'): + # Chrome Web Store currently expects BOM for UTF-8 files :-( + return 'utf-8-sig' + # TODO(gfeher) modify here to set utf-8 encoding for admx/adml + return 'utf_16' def Process(self): # Update filenames with those provided by SCons if we're being invoked @@ -361,28 +370,16 @@ for output in self.res.GetOutputFiles(): self.VerboseOut('Creating %s...' % output.GetOutputFilename()) - # Microsoft's RC compiler can only deal with single-byte or double-byte - # files (no UTF-8), so we make all RC files UTF-16 to support all - # character sets. - if output.GetType() in ('rc_header', 'resource_map_header', - 'resource_map_source', 'resource_file_map_source'): - encoding = 'cp1252' - elif output.GetType() in ('android', 'c_format', 'js_map_format', 'plist', - 'plist_strings', 'doc', 'json', 'android_policy'): - encoding = 'utf_8' - elif output.GetType() in ('chrome_messages_json'): - # Chrome Web Store currently expects BOM for UTF-8 files :-( - encoding = 'utf-8-sig' - else: - # TODO(gfeher) modify here to set utf-8 encoding for admx/adml - encoding = 'utf_16' - # Set the context, for conditional inclusion of resources self.res.SetOutputLanguage(output.GetLanguage()) self.res.SetOutputContext(output.GetContext()) self.res.SetFallbackToDefaultLayout(output.GetFallbackToDefaultLayout()) self.res.SetDefines(self.defines) + # Assign IDs only once to ensure that all outputs use the same IDs. + if self.res.GetIdMap() is None: + self.res.InitializeIds() + # Make the output directory if it doesn't exist. self.MakeDirectoriesTo(output.GetOutputFilename()) @@ -391,6 +388,7 @@ outfile = self.fo_create(output.GetOutputFilename() + '.tmp', 'wb') if output.GetType() != 'data_package': + encoding = self._EncodingForOutputType(output.GetType()) outfile = util.WrapOutputStream(outfile, encoding) # Iterate in-order through entire resource tree, calling formatters on
diff --git a/tools/grit/grit/tool/build_unittest.py b/tools/grit/grit/tool/build_unittest.py index 1750bfc..7dad441 100755 --- a/tools/grit/grit/tool/build_unittest.py +++ b/tools/grit/grit/tool/build_unittest.py
@@ -21,6 +21,15 @@ class BuildUnittest(unittest.TestCase): + # IDs should not change based on whitelisting. + # Android WebView currently relies on this. + EXPECTED_ID_MAP = { + 'IDS_MESSAGE_WHITELISTED': 6889, + 'IDR_STRUCTURE_WHITELISTED': 11546, + 'IDR_STRUCTURE_IN_TRUE_IF_WHITELISTED': 11548, + 'IDR_INCLUDE_WHITELISTED': 15601, + } + def testFindTranslationsWithSubstitutions(self): # This is a regression test; we had a bug where GRIT would fail to find # messages with substitutions e.g. "Hello [IDS_USER]" where IDS_USER is @@ -39,7 +48,7 @@ builder = build.RcBuilder() class DummyOpts(object): def __init__(self): - self.input = util.PathFromRoot('grit/testdata/substitute.grd') + self.input = util.PathFromRoot('grit/testdata/depfile.grd') self.verbose = False self.extra_verbose = False expected_dep_file = os.path.join(output_dir, 'substitute.grd.d') @@ -53,10 +62,12 @@ (dep_output_file, deps_string) = line.split(': ') deps = deps_string.split(' ') - self.failUnlessEqual("resource.h", dep_output_file) - self.failUnlessEqual(1, len(deps)) - self.failUnlessEqual(deps[0], - util.PathFromRoot('grit/testdata/substitute.xmb')) + self.failUnlessEqual("default_100_percent.pak", dep_output_file) + self.failUnlessEqual(deps, [ + util.PathFromRoot('grit/testdata/default_100_percent/a.png'), + util.PathFromRoot('grit/testdata/grit_part.grdp'), + util.PathFromRoot('grit/testdata/special_100_percent/a.png'), + ]) def testGenerateDepFileWithResourceIds(self): output_dir = tempfile.mkdtemp() @@ -157,6 +168,13 @@ for whitelisted_id in whitelisted_ids: if whitelisted_id in line: whitelisted_ids_found.append(whitelisted_id) + if filename.endswith('.h'): + numeric_id = int(line.split()[2]) + expected_numeric_id = self.EXPECTED_ID_MAP.get(whitelisted_id) + self.assertEqual( + expected_numeric_id, numeric_id, + 'Numeric ID for {} was {} should be {}'.format( + whitelisted_id, numeric_id, expected_numeric_id)) for non_whitelisted_id in non_whitelisted_ids: if non_whitelisted_id in line: non_whitelisted_ids_found.append(non_whitelisted_id) @@ -236,73 +254,6 @@ non_whitelisted_ids, ) - def testOutputAllResourceDefinesTrue(self): - output_dir = tempfile.mkdtemp() - builder = build.RcBuilder() - class DummyOpts(object): - def __init__(self): - self.input = util.PathFromRoot('grit/testdata/whitelist_resources.grd') - self.verbose = False - self.extra_verbose = False - whitelist_file = util.PathFromRoot('grit/testdata/whitelist.txt') - builder.Run(DummyOpts(), ['-o', output_dir, - '-w', whitelist_file, - '--output-all-resource-defines',]) - header = os.path.join(output_dir, 'whitelist_test_resources.h') - map_cc = os.path.join(output_dir, 'whitelist_test_resources_map.cc') - - whitelisted_ids = [ - 'IDR_STRUCTURE_WHITELISTED', - 'IDR_STRUCTURE_NOT_WHITELISTED', - 'IDR_STRUCTURE_IN_TRUE_IF_WHITELISTED', - 'IDR_STRUCTURE_IN_TRUE_IF_NOT_WHITELISTED', - 'IDR_STRUCTURE_IN_FALSE_IF_WHITELISTED', - 'IDR_STRUCTURE_IN_FALSE_IF_NOT_WHITELISTED', - 'IDR_INCLUDE_WHITELISTED', - 'IDR_INCLUDE_NOT_WHITELISTED', - ] - non_whitelisted_ids = [] - for output_file in (header, map_cc): - self._verifyWhitelistedOutput( - output_file, - whitelisted_ids, - non_whitelisted_ids, - ) - - def testOutputAllResourceDefinesFalse(self): - output_dir = tempfile.mkdtemp() - builder = build.RcBuilder() - class DummyOpts(object): - def __init__(self): - self.input = util.PathFromRoot('grit/testdata/whitelist_resources.grd') - self.verbose = False - self.extra_verbose = False - whitelist_file = util.PathFromRoot('grit/testdata/whitelist.txt') - builder.Run(DummyOpts(), ['-o', output_dir, - '-w', whitelist_file, - '--no-output-all-resource-defines',]) - header = os.path.join(output_dir, 'whitelist_test_resources.h') - map_cc = os.path.join(output_dir, 'whitelist_test_resources_map.cc') - - whitelisted_ids = [ - 'IDR_STRUCTURE_WHITELISTED', - 'IDR_STRUCTURE_IN_TRUE_IF_WHITELISTED', - 'IDR_INCLUDE_WHITELISTED', - ] - non_whitelisted_ids = [ - 'IDR_STRUCTURE_NOT_WHITELISTED', - 'IDR_STRUCTURE_IN_TRUE_IF_NOT_WHITELISTED', - 'IDR_STRUCTURE_IN_FALSE_IF_WHITELISTED', - 'IDR_STRUCTURE_IN_FALSE_IF_NOT_WHITELISTED', - 'IDR_INCLUDE_NOT_WHITELISTED', - ] - for output_file in (header, map_cc): - self._verifyWhitelistedOutput( - output_file, - whitelisted_ids, - non_whitelisted_ids, - ) - def testWriteOnlyNew(self): output_dir = tempfile.mkdtemp() builder = build.RcBuilder() @@ -374,9 +325,9 @@ deps = deps_string.split(' ') self.failUnlessEqual(expected_stamp_file_name, dep_output_file) - self.failUnlessEqual(1, len(deps)) - self.failUnlessEqual(deps[0], - util.PathFromRoot('grit/testdata/substitute.xmb')) + self.failUnlessEqual(deps, [ + util.PathFromRoot('grit/testdata/substitute.xmb'), + ]) if __name__ == '__main__':
diff --git a/tools/grit/grit/tool/toolbar_postprocess.py b/tools/grit/grit/tool/toolbar_postprocess.py deleted file mode 100755 index 3d56108..0000000 --- a/tools/grit/grit/tool/toolbar_postprocess.py +++ /dev/null
@@ -1,126 +0,0 @@ -#!/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. - -''' Toolbar postprocessing class. Modifies the previously processed GRD tree -by creating separate message groups for each of the IDS_COMMAND macros. -Also adds some identifiers nodes to declare specific ids to be included -in the generated grh file. -''' - -import postprocess_interface -from grit import lazy_re -import grit.node.empty -from grit.node import misc - -class ToolbarPostProcessor(postprocess_interface.PostProcessor): - ''' Defines message groups within the grd file for each of the - IDS_COMMAND stuff. - ''' - - _IDS_COMMAND = lazy_re.compile(r'IDS_COMMAND_') - _GRAB_PARAMETERS = lazy_re.compile( - r'(IDS_COMMAND_[a-zA-Z0-9]+)_([a-zA-z0-9]+)') - - def Process(self, rctext, rcpath, grdnode): - ''' Processes the data in rctext and grdnode. - Args: - rctext: string containing the contents of the RC file being processed. - rcpath: the path used to access the file. - grdnode: the root node of the grd xml data generated by - the rc2grd tool. - - Return: - The root node of the processed GRD tree. - ''' - - release = grdnode.children[2] - messages = release.children[2] - - identifiers = grit.node.empty.IdentifiersNode() - identifiers.StartParsing('identifiers', release) - identifiers.EndParsing() - release.AddChild(identifiers) - - - # - # Turn the IDS_COMMAND messages into separate message groups - # with ids that are offsetted to the message group's first id - # - previous_name_attr = '' - previous_prefix = '' - previous_node = '' - new_messages_node = self.ConstructNewMessages(release) - for node in messages.children[:]: - name_attr = node.attrs['name'] - if self._IDS_COMMAND.search(name_attr): - mo = self._GRAB_PARAMETERS.search(name_attr) - mp = self._GRAB_PARAMETERS.search(previous_name_attr) - if mo and mp: - prefix = mo.group(1) - previous_prefix = mp.group(1) - new_message_id = mp.group(2) - if prefix == previous_prefix: - messages.RemoveChild(previous_name_attr) - previous_node.attrs['offset'] = 'PCI_' + new_message_id - del previous_node.attrs['name'] - new_messages_node.AddChild(previous_node) - else: - messages.RemoveChild(previous_name_attr) - previous_node.attrs['offset'] = 'PCI_' + new_message_id - del previous_node.attrs['name'] - new_messages_node.AddChild(previous_node) - new_messages_node.attrs['first_id'] = previous_prefix - new_messages_node = self.ConstructNewMessages(release) - else: - if self._IDS_COMMAND.search(previous_name_attr): - messages.RemoveChild(previous_name_attr) - previous_prefix = mp.group(1) - new_message_id = mp.group(2) - previous_node.attrs['offset'] = 'PCI_' + new_message_id - del previous_node.attrs['name'] - new_messages_node.AddChild(previous_node) - new_messages_node.attrs['first_id'] = previous_prefix - new_messages_node = self.ConstructNewMessages(release) - else: - if self._IDS_COMMAND.search(previous_name_attr): - messages.RemoveChild(previous_name_attr) - mp = self._GRAB_PARAMETERS.search(previous_name_attr) - previous_prefix = mp.group(1) - new_message_id = mp.group(2) - previous_node.attrs['offset'] = 'PCI_' + new_message_id - del previous_node.attrs['name'] - new_messages_node.AddChild(previous_node) - new_messages_node.attrs['first_id'] = previous_prefix - new_messages_node = self.ConstructNewMessages(release) - previous_name_attr = name_attr - previous_node = node - - - self.AddIdentifiers(rctext, identifiers) - return grdnode - - def ConstructNewMessages(self, parent): - new_node = grit.node.empty.MessagesNode() - new_node.StartParsing('messages', parent) - new_node.EndParsing() - parent.AddChild(new_node) - return new_node - - def AddIdentifiers(self, rctext, node): - node.AddChild(misc.IdentifierNode.Construct(node, 'IDS_COMMAND_gcFirst', '12000', '')) - node.AddChild(misc.IdentifierNode.Construct(node, - 'IDS_COMMAND_PCI_SPACE', '16', '')) - node.AddChild(misc.IdentifierNode.Construct(node, 'PCI_BUTTON', '0', '')) - node.AddChild(misc.IdentifierNode.Construct(node, 'PCI_MENU', '1', '')) - node.AddChild(misc.IdentifierNode.Construct(node, 'PCI_TIP', '2', '')) - node.AddChild(misc.IdentifierNode.Construct(node, 'PCI_OPTIONS_TEXT', '3', '')) - node.AddChild(misc.IdentifierNode.Construct(node, 'PCI_TIP_DISABLED', '4', '')) - node.AddChild(misc.IdentifierNode.Construct(node, 'PCI_TIP_MENU', '5', '')) - node.AddChild(misc.IdentifierNode.Construct(node, 'PCI_TIP_MENU_DISABLED', '6', '')) - node.AddChild(misc.IdentifierNode.Construct(node, 'PCI_TIP_OPTIONS', '7', '')) - node.AddChild(misc.IdentifierNode.Construct(node, 'PCI_TIP_OPTIONS_DISABLED', '8', '')) - node.AddChild(misc.IdentifierNode.Construct(node, - 'PCI_TIP_DISABLED_BY_POLICY', '9', '')) -
diff --git a/tools/grit/grit/tool/toolbar_preprocess.py b/tools/grit/grit/tool/toolbar_preprocess.py deleted file mode 100755 index ff26f88..0000000 --- a/tools/grit/grit/tool/toolbar_preprocess.py +++ /dev/null
@@ -1,61 +0,0 @@ -#!/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. - -''' Toolbar preprocessing code. Turns all IDS_COMMAND macros in the RC file -into simpler constructs that can be understood by GRIT. Also deals with -expansion of $lf; placeholders into the correct linefeed character. -''' - -import preprocess_interface - -from grit import lazy_re - -class ToolbarPreProcessor(preprocess_interface.PreProcessor): - ''' Toolbar PreProcessing class. - ''' - - _IDS_COMMAND_MACRO = lazy_re.compile( - r'(.*IDS_COMMAND)\s*\(([a-zA-Z0-9_]*)\s*,\s*([a-zA-Z0-9_]*)\)(.*)') - _LINE_FEED_PH = lazy_re.compile(r'\$lf;') - _PH_COMMENT = lazy_re.compile(r'PHRWR') - _COMMENT = lazy_re.compile(r'^(\s*)//.*') - - - def Process(self, rctext, rcpath): - ''' Processes the data in rctext. - Args: - rctext: string containing the contents of the RC file being processed - rcpath: the path used to access the file. - - Return: - The processed text. - ''' - - ret = '' - rclines = rctext.splitlines() - for line in rclines: - - if self._LINE_FEED_PH.search(line): - # Replace "$lf;" placeholder comments by an empty line. - # this will not be put into the processed result - if self._PH_COMMENT.search(line): - mm = self._COMMENT.search(line) - if mm: - line = '%s//' % mm.group(1) - - else: - # Replace $lf by the right linefeed character - line = self._LINE_FEED_PH.sub(r'\\n', line) - - # Deal with IDS_COMMAND_MACRO stuff - mo = self._IDS_COMMAND_MACRO.search(line) - if mo: - line = '%s_%s_%s%s' % (mo.group(1), mo.group(2), mo.group(3), mo.group(4)) - - ret += (line + '\n') - - return ret - -
diff --git a/tools/grit/grit/tool/unit.py b/tools/grit/grit/tool/unit.py index f483262..00ffcb1 100755 --- a/tools/grit/grit/tool/unit.py +++ b/tools/grit/grit/tool/unit.py
@@ -14,8 +14,7 @@ class UnitTestTool(interface.Tool): '''By using this tool (e.g. 'grit unit') you run all the unit tests for GRIT. -This happens in the environment that is set up by the basic GRIT runner, i.e. -whether to run disconnected has been specified, etc.''' +This happens in the environment that is set up by the basic GRIT runner.''' def ShortDescription(self): return 'Use this tool to run all the unit tests for GRIT.' @@ -23,4 +22,3 @@ def Run(self, opts, args): return unittest.TextTestRunner(verbosity=2).run( grit.test_suite_all.TestSuiteAll()) -
diff --git a/tools/grit/grit/util.py b/tools/grit/grit/util.py index 93dce261..aac2dd91 100755 --- a/tools/grit/grit/util.py +++ b/tools/grit/grit/util.py
@@ -319,7 +319,8 @@ return os.path.normpath(os.path.join(_root_dir, path)) -def ParseGrdForUnittest(body, base_dir=None): +def ParseGrdForUnittest(body, base_dir=None, predetermined_ids_file=None, + run_gatherers=False): '''Parse a skeleton .grd file and return it, for use in unit tests. Args: @@ -332,15 +333,24 @@ body = body.encode('utf-8') if base_dir is None: base_dir = PathFromRoot('.') - body = '''<?xml version="1.0" encoding="UTF-8"?> -<grit latest_public_release="2" current_release="3" source_lang_id="en" base_dir="%s"> - <outputs> - </outputs> - <release seq="3"> - %s - </release> -</grit>''' % (base_dir, body) - return grd_reader.Parse(StringIO.StringIO(body), dir=".") + lines = ['<?xml version="1.0" encoding="UTF-8"?>'] + lines.append(('<grit latest_public_release="2" current_release="3" ' + 'source_lang_id="en" base_dir="{}">').format(base_dir)) + if '<outputs>' in body: + lines.append(body) + else: + lines.append(' <outputs></outputs>') + lines.append(' <release seq="3">') + lines.append(body) + lines.append(' </release>') + lines.append('</grit>') + ret = grd_reader.Parse(StringIO.StringIO('\n'.join(lines)), dir=".") + ret.SetOutputLanguage('en') + if run_gatherers: + ret.RunGatherers() + ret.SetPredeterminedIdsFile(predetermined_ids_file) + ret.InitializeIds() + return ret def StripBlankLinesAndComments(text):
diff --git a/tools/grit/grit_info.py b/tools/grit/grit_info.py index 07e9b9d..a7f9601 100755 --- a/tools/grit/grit_info.py +++ b/tools/grit/grit_info.py
@@ -119,12 +119,6 @@ parser.add_option("-E", action="append", dest="build_env", default=[]) parser.add_option("-p", action="store", dest="predetermined_ids_file") parser.add_option("-w", action="append", dest="whitelist_files", default=[]) - parser.add_option("--output-all-resource-defines", action="store_true", - dest="output_all_resource_defines", default=True, - help="Unused") - parser.add_option("--no-output-all-resource-defines", action="store_false", - dest="output_all_resource_defines", default=True, - help="Unused") parser.add_option("-f", dest="ids_file", default="") parser.add_option("-t", dest="target_platform", default=None)
diff --git a/tools/grit/grit_rule.gni b/tools/grit/grit_rule.gni index b304c749..82bf44e 100644 --- a/tools/grit/grit_rule.gni +++ b/tools/grit/grit_rule.gni
@@ -163,13 +163,6 @@ ] } -if (use_ash) { - grit_defines += [ - "-D", - "use_ash", - ] -} - if (use_nss_certs) { grit_defines += [ "-D",
diff --git a/tools/grit/pak_util.py b/tools/grit/pak_util.py index dd98049..a1d4738 100755 --- a/tools/grit/pak_util.py +++ b/tools/grit/pak_util.py
@@ -31,9 +31,23 @@ f.write(payload) +def _CreateMain(args): + pak = {} + for name in os.listdir(args.input_dir): + try: + resource_id = int(name) + except: + continue + filename = os.path.join(args.input_dir, name) + if os.path.isfile(filename): + with open(filename, 'rb') as f: + pak[resource_id] = f.read() + data_pack.WriteDataPack(pak, args.output_pak_file, data_pack.UTF8) + + def _PrintMain(args): pak = data_pack.ReadDataPack(args.pak_file) - id_map = {id(v): k for k, v in sorted(pak.resources.items(), reverse=True)} + output = args.output encoding = 'binary' if pak.encoding == 1: encoding = 'utf-8' @@ -41,14 +55,21 @@ encoding = 'utf-16' else: encoding = '?' + str(pak.encoding) - print 'Encoding:', encoding - try_decode = encoding.startswith('utf') + output.write('version: {}\n'.format(pak.version)) + output.write('encoding: {}\n'.format(encoding)) + output.write('num_resources: {}\n'.format(len(pak.resources))) + output.write('num_aliases: {}\n'.format(len(pak.aliases))) + breakdown = ', '.join('{}: {}'.format(*x) for x in pak.sizes) + output.write('total_size: {} ({})\n'.format(pak.sizes.total, breakdown)) + + try_decode = args.decode and encoding.startswith('utf') # Print IDs in ascending order, since that's the order in which they appear in # the file (order is lost by Python dict). for resource_id in sorted(pak.resources): data = pak.resources[resource_id] - desc = '<binary>' + canonical_id = pak.aliases.get(resource_id, resource_id) + desc = '<data>' if try_decode: try: desc = unicode(data, encoding) @@ -58,19 +79,14 @@ except UnicodeDecodeError: pass sha1 = hashlib.sha1(data).hexdigest()[:10] - canonical_id = id_map[id(data)] - if resource_id == canonical_id: - line = u'Entry(id={}, len={}, sha1={}): {}'.format( - resource_id, len(data), sha1, desc) - else: - line = u'Entry(id={}, alias_of={}): {}'.format( - resource_id, canonical_id, desc) - print line.encode('utf-8') + output.write( + u'Entry(id={}, canonical_id={}, size={}, sha1={}): {}\n'.format( + resource_id, canonical_id, len(data), sha1, desc).encode('utf-8')) def _ListMain(args): - resources, _ = data_pack.ReadDataPack(args.pak_file) - for resource_id in sorted(resources.keys()): + pak = data_pack.ReadDataPack(args.pak_file) + for resource_id in sorted(pak.resources): args.output.write('%d\n' % resource_id) @@ -96,11 +112,23 @@ help='Directory to extract to.') sub_parser.set_defaults(func=_ExtractMain) + sub_parser = sub_parsers.add_parser('create', + help='Creates pak file from extracted directory.') + sub_parser.add_argument('output_pak_file', help='File to create.') + sub_parser.add_argument('-i', '--input-dir', default='.', + help='Directory to create from.') + sub_parser.set_defaults(func=_CreateMain) + sub_parser = sub_parsers.add_parser('print', help='Prints all pak IDs and contents. Useful for diffing.') sub_parser.add_argument('pak_file') + sub_parser.add_argument('--output', type=argparse.FileType('w'), + default=sys.stdout, + help='The resource list path to write (default stdout)') + sub_parser.add_argument('--no-decode', dest='decode', action='store_false', + default=True, help='Do not print entry data.') sub_parser.set_defaults(func=_PrintMain) - + sub_parser = sub_parsers.add_parser('list-id', help='Outputs all resource IDs to a file.') sub_parser.add_argument('pak_file')
diff --git a/tools/gritsettings/resource_ids b/tools/gritsettings/resource_ids index ee0116d..fc1c4aa 100644 --- a/tools/gritsettings/resource_ids +++ b/tools/gritsettings/resource_ids
@@ -81,44 +81,53 @@ # START chrome/browser section. "chrome/browser/browser_resources.grd": { "includes": [11000], - "structures": [11520], + "structures": [11470], }, "chrome/browser/resources/component_extension_resources.grd": { - "includes": [11610], - "structures": [11860], + "includes": [11560], + "structures": [11810], }, "chrome/browser/resources/invalidations_resources.grd": { - "includes": [11910], + "includes": [11860], + }, + "chrome/browser/resources/md_extensions/extensions_resources_vulcanized.grd": { + "includes": [11900], + }, + "chrome/browser/resources/md_extensions/extensions_resources.grd": { + "structures": [11910], }, "chrome/browser/resources/net_internals_resources.grd": { - "includes": [11960], + "includes": [12000], }, - "chrome/browser/resources/password_manager_internals_resources.grd": { - "includes": [12040], + "chrome/browser/resources/print_preview/print_preview_resources.grd": { + "structures": [12010], }, "chrome/browser/resources/quota_internals_resources.grd": { - "includes": [12050], + "includes": [12110], }, "chrome/browser/resources/settings/settings_resources_vulcanized.grd": { - "includes": [12070], + "includes": [12130], }, "chrome/browser/resources/settings/settings_resources.grd": { - "structures": [12080], + "structures": [12140], }, "chrome/browser/resources/sync_file_system_internals_resources.grd": { - "includes": [12580], + "includes": [12640], }, "chrome/browser/resources/task_scheduler_internals/resources.grd": { - "includes": [12610], + "includes": [12670], }, "chrome/browser/resources/translate_internals_resources.grd": { - "includes": [12620], + "includes": [12680], }, "chrome/browser/resources/vr_shell_resources.grd": { - "includes": [12630], + "includes": [12690], }, "chrome/browser/resources/webapks_ui_resources.grd": { - "includes": [12640], + "includes": [12700], + }, + "chrome/browser/vr/testapp/vr_testapp_resources.grd": { + "includes": [12710], }, # END chrome/browser section. @@ -373,6 +382,10 @@ "third_party/libaddressinput/chromium/address_input_strings.grd": { "messages": [28700], }, + + "mojo/public/js/mojo_bindings_resources.grd": { + "includes": [28800], + }, # END "everything else" section. # Everything but chrome/, components/, content/, and ios/
diff --git a/tools/gritsettings/startup_resources_mac.txt b/tools/gritsettings/startup_resources_mac.txt index f9daa12..dbfbe4a 100644 --- a/tools/gritsettings/startup_resources_mac.txt +++ b/tools/gritsettings/startup_resources_mac.txt
@@ -261,6 +261,5 @@ IDS_AUTOCOMPLETE_SEARCH_DESCRIPTION 361 IDS_AUTOCOMPLETE_MATCH_DESCRIPTION_SEPARATOR 362 IDR_OVERLAY_DROP_SHADOW 363 -IDS_ANNOUNCEMENT_COMPLETION_AVAILABLE_MAC 364 -IDS_EXTENSION_PROMPT_WARNING_CLIPBOARD_READWRITE 365 -IDS_EXTENSION_PROMPT_WARNING_NOTIFICATIONS 366 +IDS_EXTENSION_PROMPT_WARNING_CLIPBOARD_READWRITE 364 +IDS_EXTENSION_PROMPT_WARNING_NOTIFICATIONS 365
diff --git a/tools/idl_parser/idl_lexer.py b/tools/idl_parser/idl_lexer.py index c983404..60b8288 100755 --- a/tools/idl_parser/idl_lexer.py +++ b/tools/idl_parser/idl_lexer.py
@@ -79,6 +79,7 @@ 'legacycaller' : 'LEGACYCALLER', 'long' : 'LONG', 'maplike': 'MAPLIKE', + 'namespace' : 'NAMESPACE', 'Nan' : 'NAN', 'null' : 'NULL', 'object' : 'OBJECT',
diff --git a/tools/idl_parser/idl_parser.py b/tools/idl_parser/idl_parser.py index 3426b061..d498a66 100755 --- a/tools/idl_parser/idl_parser.py +++ b/tools/idl_parser/idl_parser.py
@@ -254,6 +254,7 @@ def p_Definition(self, p): """Definition : CallbackOrInterface + | Namespace | Partial | Dictionary | Enum @@ -302,7 +303,8 @@ def p_PartialDefinition(self, p): """PartialDefinition : PartialDictionary - | PartialInterface""" + | PartialInterface + | Namespace""" p[0] = p[1] def p_PartialInterface(self, p): @@ -670,7 +672,7 @@ if len(p) > 1: p[0] = p[1] else: - p[0] = '_unnamed_' + p[0] = '' def p_ArgumentList(self, p): """ArgumentList : Argument Arguments @@ -754,6 +756,46 @@ """SetlikeRest : SETLIKE '<' TypeWithExtendedAttributes '>' ';'""" p[0] = self.BuildProduction('Setlike', p, 2, p[3]) + def p_Namespace(self, p): + """Namespace : NAMESPACE identifier '{' NamespaceMembers '}' ';'""" + p[0] = self.BuildNamed('Namespace', p, 2, p[4]) + + # Error recovery for namespace. + def p_NamespaceError(self, p): + """Namespace : NAMESPACE identifier '{' error""" + p[0] = self.BuildError(p, 'Namespace') + + def p_NamespaceMembers(self, p): + """NamespaceMembers : NamespaceMember NamespaceMembers + | """ + if len(p) > 1: + p[0] = ListFromConcat(p[1], p[2]) + + # Error recovery for NamespaceMembers + def p_NamespaceMembersError(self, p): + """NamespaceMembers : ExtendedAttributeList error""" + p[0] = self.BuildError(p, 'NamespaceMembers') + + def p_NamespaceMember(self, p): + """NamespaceMember : ExtendedAttributeList ReturnType OperationRest + | ExtendedAttributeList READONLY AttributeRest""" + if p[2] != 'readonly': + applicable_to_types, non_applicable_to_types = \ + DivideExtAttrsIntoApplicableAndNonApplicable(p[1]) + if applicable_to_types: + attributes = self.BuildProduction('ExtAttributes', p, 1, + applicable_to_types) + p[2].AddChildren(attributes) + p[3].AddChildren(p[2]) + if non_applicable_to_types: + attributes = self.BuildProduction('ExtAttributes', p, 1, + non_applicable_to_types) + p[3].AddChildren(attributes) + else: + p[3].AddChildren(self.BuildTrue('READONLY')) + p[3].AddChildren(p[1]) + p[0] = p[3] + # This rule has custom additions (i.e. SpecialComments). def p_ExtendedAttributeList(self, p): """ExtendedAttributeList : '[' ExtendedAttribute ExtendedAttributes ']' @@ -806,6 +848,7 @@ | IMPLEMENTS | INHERIT | LEGACYCALLER + | NAMESPACE | PARTIAL | SERIALIZER | SETTER
diff --git a/tools/idl_parser/idl_parser_test.py b/tools/idl_parser/idl_parser_test.py index f9d0edf..6aeabd4 100755 --- a/tools/idl_parser/idl_parser_test.py +++ b/tools/idl_parser/idl_parser_test.py
@@ -4,6 +4,7 @@ # found in the LICENSE file. import glob +import os import unittest from idl_lexer import IDLLexer @@ -20,7 +21,9 @@ def setUp(self): self.parser = IDLParser(IDLLexer(), mute_error=True) - self.filenames = glob.glob('test_parser/*_web.idl') + test_dir = os.path.abspath( + os.path.join(os.path.dirname(__file__), 'test_parser')) + self.filenames = glob.glob('%s/*_web.idl' % test_dir) def _TestNode(self, node): comments = node.GetListOf('SpecialComment')
diff --git a/tools/idl_parser/test_parser/interface_web.idl b/tools/idl_parser/test_parser/interface_web.idl index 7cf6dae..589a47c 100644 --- a/tools/idl_parser/test_parser/interface_web.idl +++ b/tools/idl_parser/test_parser/interface_web.idl
@@ -218,7 +218,7 @@ * StringType(DOMString) * Type() * PrimitiveType(void) - * Operation(_unnamed_) + * Operation() * GETTER: True * Arguments() * Argument(property) @@ -236,7 +236,7 @@ *Interface(MyIFaceStringifiers) * Stringifier() * Stringifier() - * Operation(_unnamed_) + * Operation() * Arguments() * Type() * StringType(DOMString) @@ -555,3 +555,70 @@ void voidMethodTestArgumentWithExtAttribute1([Clamp, XAttr] long long myLong); void voidMethodTestArgumentWithExtAttribute2([EnforceRange] long longArg); }; + +/** TREE + *Interface(InterfaceConstructors) + * ExtAttributes() + * ExtAttribute(Constructor) + * ExtAttribute(Constructor) + * Arguments() + * Argument(doubleArg) + * Type() + * PrimitiveType(double) + * ExtAttribute(CustomConstructor) + * ExtAttribute(CustomConstructor) + * Arguments() + * Argument(doubleArg) + * Type() + * PrimitiveType(double) + * ExtAttribute(NamedConstructor) = "Audio" + * ExtAttribute(NamedConstructor) + * Call(Audio) + * Arguments() + * Argument(src) + * Type() + * StringType(DOMString) + */ +[ + Constructor, + Constructor(double doubleArg), + CustomConstructor, + CustomConstructor(double doubleArg), + NamedConstructor=Audio, + NamedConstructor=Audio(DOMString src) +] interface InterfaceConstructors { }; + +/** TREE + *Interface(InterfaceExposed) + * ExtAttributes() + * ExtAttribute(Exposed) = "Window" + * ExtAttribute(Exposed) = "['Window', 'Worker']" + * ExtAttribute(Exposed) + * Arguments() + * Argument(Feature1) + * Type() + * Typeref(Window) + * ExtAttribute(Exposed) + * Arguments() + * Argument(Feature1) + * Type() + * Typeref(Window) + * Argument(Feature2) + * Type() + * Typeref(Worker) + */ +[ + Exposed=Window, + Exposed=(Window, Worker), + Exposed(Window Feature1), + Exposed(Window Feature1, Worker Feature2) +] interface InterfaceExposed { }; + +/** TREE + *Interface(InterfaceExposedError) + * ExtAttributes() + * ExtAttribute(Exposed) + * Arguments() + * Error(Unexpected ,.) + */ +[ Exposed(Window, Worker) ] interface InterfaceExposedError { };
diff --git a/tools/idl_parser/test_parser/namespace_web.idl b/tools/idl_parser/test_parser/namespace_web.idl new file mode 100644 index 0000000..06e42a4 --- /dev/null +++ b/tools/idl_parser/test_parser/namespace_web.idl
@@ -0,0 +1,150 @@ +// Copyright 2017 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. + +/* Test Namespace productions + +Run with --test to generate an AST and verify that all comments accurately +reflect the state of the Nodes. + +TREE +Type(Name) + Type(Name) + Type(Name) + Type(Name) + ... +This comment signals that a tree of nodes matching the BUILD comment +symatics should exist. This is an exact match. +*/ + + +/** TREE + *Namespace(MyNamespace) + */ +namespace MyNamespace { }; + +/** TREE + *Namespace(MyNamespace2) + * Operation(fooLong) + * Arguments() + * Type() + * PrimitiveType(long) + * Operation(voidArgLong) + * Arguments() + * Argument(arg) + * Type() + * PrimitiveType(long) + * Type() + * PrimitiveType(void) + */ +namespace MyNamespace2 { + long fooLong(); + void voidArgLong(long arg); +}; + +/** TREE + *Namespace(MyNamespaceMissingArgument) + * Operation(foo) + * Arguments() + * Argument(arg) + * Type() + * StringType(DOMString) + * Error(Missing argument.) + * Type() + * PrimitiveType(void) + */ +namespace MyNamespaceMissingArgument { + void foo(DOMString arg, ); +}; + +/** TREE + *Namespace(VectorUtils) + * Attribute(unit) + * READONLY: True + * Type() + * Typeref(Vector) + * Operation(dotProduct) + * Arguments() + * Argument(x) + * Type() + * Typeref(Vector) + * Argument(y) + * Type() + * Typeref(Vector) + * Type() + * PrimitiveType(double) + * Operation(crossProduct) + * Arguments() + * Argument(x) + * Type() + * Typeref(Vector) + * Argument(y) + * Type() + * Typeref(Vector) + * Type() + * Typeref(Vector) + */ +namespace VectorUtils { + readonly attribute Vector unit; + double dotProduct(Vector x, Vector y); + Vector crossProduct(Vector x, Vector y); +}; + +/**TREE + *Namespace(ErrorOnlyExtAttrs) + * Error(Unexpected ";" after "]".) + */ +namespace ErrorOnlyExtAttrs { + [Clamp]; +}; + +/** TREE + *Error(Unexpected keyword "attribute" after "{".) + */ +namespace ErrorNonReadonly { + attribute Vector unit2; +}; + +/** TREE + *Error(Unexpected ";" after "{".) + */ +namespace NameSpaceError { + ; + +/**TREE + *Namespace(PartialNamespace) + * PARTIAL: True + * Operation(fooLong) + * Arguments() + * Type() + * PrimitiveType(long) + */ +partial namespace PartialNamespace { + long fooLong(); +}; + +/** TREE + *Namespace(NamespaceWithExtAttrs) + * Operation(fooLong) + * Arguments() + * Type() + * PrimitiveType(long) + * ExtAttributes() + * ExtAttribute(Replaceable) + */ +[Replaceable] namespace NamespaceWithExtAttrs { + long fooLong(); +}; + +/** TREE + *Namespace(NamespaceAnnotatedTypeMember) + * Operation(fooLong) + * Arguments() + * Type() + * PrimitiveType(long) + * ExtAttributes() + * ExtAttribute(Clamp) + */ +namespace NamespaceAnnotatedTypeMember { + [Clamp] long fooLong(); +};
diff --git a/tools/imagediff/image_diff.cc b/tools/imagediff/image_diff.cc index 56d1be9c..e73bb3f 100644 --- a/tools/imagediff/image_diff.cc +++ b/tools/imagediff/image_diff.cc
@@ -56,11 +56,7 @@ Image() : w_(0), h_(0) { } - Image(const Image& image) - : w_(image.w_), - h_(image.h_), - data_(image.data_) { - } + Image(const Image& image) = default; bool has_image() const { return w_ > 0 && h_ > 0;
diff --git a/tools/ipc_fuzzer/fuzzer/fuzzer.cc b/tools/ipc_fuzzer/fuzzer/fuzzer.cc index 395eab1..a986bb9 100644 --- a/tools/ipc_fuzzer/fuzzer/fuzzer.cc +++ b/tools/ipc_fuzzer/fuzzer/fuzzer.cc
@@ -642,8 +642,8 @@ }; template <> -struct FuzzTraits<cc::CompositorFrame> { - static bool Fuzz(cc::CompositorFrame* p, Fuzzer* fuzzer) { +struct FuzzTraits<viz::CompositorFrame> { + static bool Fuzz(viz::CompositorFrame* p, Fuzzer* fuzzer) { // TODO(mbarbella): Support mutation. if (!fuzzer->ShouldGenerate()) return true; @@ -966,7 +966,6 @@ bool verified_flush = false; gpu::CommandBufferNamespace namespace_id = gpu::CommandBufferNamespace::INVALID; - int32_t extra_data_field = 0; gpu::CommandBufferId command_buffer_id; uint64_t release_count = 0; @@ -974,15 +973,13 @@ return false; if (!FuzzParam(&namespace_id, fuzzer)) return false; - if (!FuzzParam(&extra_data_field, fuzzer)) - return false; if (!FuzzParam(&command_buffer_id, fuzzer)) return false; if (!FuzzParam(&release_count, fuzzer)) return false; p->Clear(); - p->Set(namespace_id, extra_data_field, command_buffer_id, release_count); + p->Set(namespace_id, command_buffer_id, release_count); if (verified_flush) p->SetVerifyFlush(); return true; @@ -1444,14 +1441,14 @@ }; template <> -struct FuzzTraits<storage::DataElement> { - static bool Fuzz(storage::DataElement* p, Fuzzer* fuzzer) { +struct FuzzTraits<network::DataElement> { + static bool Fuzz(network::DataElement* p, Fuzzer* fuzzer) { // TODO(mbarbella): Support mutation. if (!fuzzer->ShouldGenerate()) return true; switch (RandInRange(4)) { - case storage::DataElement::Type::TYPE_BYTES: { + case network::DataElement::Type::TYPE_BYTES: { if (RandEvent(2)) { p->SetToEmptyBytes(); } else { @@ -1462,7 +1459,7 @@ } return true; } - case storage::DataElement::Type::TYPE_FILE: { + case network::DataElement::Type::TYPE_FILE: { base::FilePath path; uint64_t offset; uint64_t length; @@ -1478,7 +1475,7 @@ p->SetToFilePathRange(path, offset, length, modification_time); return true; } - case storage::DataElement::Type::TYPE_BLOB: { + case network::DataElement::Type::TYPE_BLOB: { std::string uuid; uint64_t offset; uint64_t length; @@ -1491,22 +1488,6 @@ p->SetToBlobRange(uuid, offset, length); return true; } - case storage::DataElement::Type::TYPE_FILE_FILESYSTEM: { - GURL url; - uint64_t offset; - uint64_t length; - base::Time modification_time; - if (!FuzzParam(&url, fuzzer)) - return false; - if (!FuzzParam(&offset, fuzzer)) - return false; - if (!FuzzParam(&length, fuzzer)) - return false; - if (!FuzzParam(&modification_time, fuzzer)) - return false; - p->SetToFileSystemUrlRange(url, offset, length, modification_time); - return true; - } default: { NOTREACHED(); return false; @@ -1539,17 +1520,14 @@ std::string scheme = p->scheme(); std::string host = p->host(); uint16_t port = p->port(); - std::string suborigin = p->suborigin(); if (!FuzzParam(&scheme, fuzzer)) return false; if (!FuzzParam(&host, fuzzer)) return false; if (!FuzzParam(&port, fuzzer)) return false; - if (!FuzzParam(&suborigin, fuzzer)) - return false; *p = url::Origin::UnsafelyCreateOriginWithoutNormalization(scheme, host, - port, suborigin); + port); // Force a unique origin 1% of the time: if (RandInRange(100) == 1)
diff --git a/tools/ipc_fuzzer/fuzzer/mutator.cc b/tools/ipc_fuzzer/fuzzer/mutator.cc index 25cc587..6e74d20 100644 --- a/tools/ipc_fuzzer/fuzzer/mutator.cc +++ b/tools/ipc_fuzzer/fuzzer/mutator.cc
@@ -29,8 +29,8 @@ const T& literal1, const T& literal2) { if (RandEvent(frequency)) { switch (RandInRange(5)) { - case 4: (*value) = (*value) + (*value); // FALLTHROUGH - case 3: (*value) = (*value) + (*value); // FALLTHROUGH + case 4: (*value) = (*value) + (*value); FALLTHROUGH; + case 3: (*value) = (*value) + (*value); FALLTHROUGH; case 2: (*value) = (*value) + (*value); break; case 1: (*value) += literal1; break; case 0: (*value) = literal2; break;
diff --git a/tools/ipc_fuzzer/message_lib/BUILD.gn b/tools/ipc_fuzzer/message_lib/BUILD.gn index a947294e..3852da3f 100644 --- a/tools/ipc_fuzzer/message_lib/BUILD.gn +++ b/tools/ipc_fuzzer/message_lib/BUILD.gn
@@ -2,7 +2,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import("//build/config/features.gni") +import("//components/nacl/features.gni") import("//remoting/remoting_enable.gni") static_library("ipc_message_lib") { @@ -30,7 +30,7 @@ "//third_party/WebKit/public:blink_headers", "//third_party/mt19937ar", "//third_party/webrtc_overrides", - "//ui/accessibility:ax_gen", + "//ui/accessibility:ax_enums_mojo", ] sources = [ "all_messages.h",
diff --git a/tools/ipc_fuzzer/message_lib/all_messages.h b/tools/ipc_fuzzer/message_lib/all_messages.h index 9b8f4e8..0004326 100644 --- a/tools/ipc_fuzzer/message_lib/all_messages.h +++ b/tools/ipc_fuzzer/message_lib/all_messages.h
@@ -8,8 +8,8 @@ // Force all multi-include optional files to be included again. #undef CHROME_COMMON_COMMON_PARAM_TRAITS_MACROS_H_ -#undef COMPONENTS_AUTOFILL_CONTENT_COMMON_AUTOFILL_PARAM_TRAITS_MACROS_H_ #undef COMPONENTS_NACL_COMMON_NACL_TYPES_PARAM_TRAITS_H_ +#undef COMPONENTS_TRACING_COMMON_TRACING_MESSAGES_H_ #undef CONTENT_COMMON_CONTENT_PARAM_TRAITS_MACROS_H_ #undef CONTENT_COMMON_FRAME_PARAM_MACROS_H_ #undef CONTENT_PUBLIC_COMMON_COMMON_PARAM_TRAITS_MACROS_H_
diff --git a/tools/ipc_fuzzer/message_replay/replay_process.cc b/tools/ipc_fuzzer/message_replay/replay_process.cc index 2ac4c95..9023c9ea 100644 --- a/tools/ipc_fuzzer/message_replay/replay_process.cc +++ b/tools/ipc_fuzzer/message_replay/replay_process.cc
@@ -150,9 +150,10 @@ base::MakeUnique<IPCChannelBootstrapper>(std::move(ipc_pipe.handle0))); service_manager_connection_->Start(); channel_ = IPC::ChannelProxy::Create( - IPC::ChannelMojo::CreateClientFactory(std::move(ipc_pipe.handle1), - io_thread_.task_runner()), - this, io_thread_.task_runner()); + IPC::ChannelMojo::CreateClientFactory( + std::move(ipc_pipe.handle1), io_thread_.task_runner(), + base::ThreadTaskRunnerHandle::Get()), + this, io_thread_.task_runner(), base::ThreadTaskRunnerHandle::Get()); } bool ReplayProcess::OpenTestcase() {
diff --git a/tools/ipc_fuzzer/message_tools/message_list.cc b/tools/ipc_fuzzer/message_tools/message_list.cc index 5e701f03..8ccb4b81 100644 --- a/tools/ipc_fuzzer/message_tools/message_list.cc +++ b/tools/ipc_fuzzer/message_tools/message_list.cc
@@ -9,6 +9,7 @@ #include <string> #include <vector> +#include "base/stl_util.h" #include "build/build_config.h" // Include once to get the type definitions @@ -55,6 +56,7 @@ exemptions.push_back(CastChannelMsgStart); // Reserved for chromecast. exemptions.push_back(CastMediaMsgStart); // Reserved for chromecast. exemptions.push_back(IPCTestMsgStart); + exemptions.push_back(WorkerMsgStart); // Now only used by tests. #if !BUILDFLAG(ENABLE_NACL) exemptions.push_back(NaClMsgStart); @@ -102,9 +104,7 @@ result = false; } while (class_id > previous_class_id + 1) { - std::vector<int>::iterator iter; - iter = find(exemptions.begin(), exemptions.end(), previous_class_id + 1); - if (iter == exemptions.end()) { + if (!base::ContainsValue(exemptions, previous_class_id + 1)) { std::cout << "Missing message file for enum " << class_id - (previous_class_id + 1) << " before enum used by " << file_name << "\n"; @@ -119,9 +119,7 @@ } while (LastIPCMsgStart > highest_class_id + 1) { - std::vector<int>::iterator iter; - iter = find(exemptions.begin(), exemptions.end(), highest_class_id+1); - if (iter == exemptions.end()) { + if (!base::ContainsValue(exemptions, highest_class_id + 1)) { std::cout << "Missing message file for enum " << LastIPCMsgStart - (highest_class_id + 1) << " before enum LastIPCMsgStart\n"; @@ -164,7 +162,7 @@ bool show_ids = false; bool skip_check = false; bool show_comma = false; - const char *filter = NULL; + const char* filter = NULL; while (--argc > 0) { ++argv;
diff --git a/tools/json_comment_eater/json_comment_eater_test.py b/tools/json_comment_eater/json_comment_eater_test.py index 5a230eb2..ae03474 100755 --- a/tools/json_comment_eater/json_comment_eater_test.py +++ b/tools/json_comment_eater/json_comment_eater_test.py
@@ -4,6 +4,7 @@ # found in the LICENSE file. from json_comment_eater import Nom +import os import unittest class JsonCommentEaterTest(unittest.TestCase): @@ -13,7 +14,8 @@ contents as a tuple in that order. ''' def read(file_name): - with open(file_name, 'r') as f: + file_path = os.path.join(os.path.dirname(__file__), file_name) + with open(file_path, 'r') as f: return f.read() return [read(pattern % test_name) for pattern in ('%s.json', '%s_expected.json')]
diff --git a/tools/json_schema_compiler/cc_generator.py b/tools/json_schema_compiler/cc_generator.py index 63016eb..ba0a0a8 100644 --- a/tools/json_schema_compiler/cc_generator.py +++ b/tools/json_schema_compiler/cc_generator.py
@@ -307,7 +307,7 @@ self._util_cc_helper.GetValueTypeString('value')))) .Append('return false;')) elif type_.property_type == PropertyType.OBJECT: - (c.Sblock('if (!value.IsType(base::Value::Type::DICTIONARY)) {') + (c.Sblock('if (!value.is_dict()) {') .Concat(self._GenerateError( '"expected dictionary, got " + ' + self._util_cc_helper.GetValueTypeString('value'))) @@ -363,7 +363,7 @@ return '(%s)' % ' || '.join(self._GenerateValueIsTypeExpression(var, choice) for choice in real_type.choices) - return '%s.IsType(%s)' % (var, cpp_util.GetValueType(real_type)) + return '%s.type() == %s' % (var, cpp_util.GetValueType(real_type)) def _GenerateTypePopulateProperty(self, prop, src, dst): """Generate the code to populate a single property in a type. @@ -710,7 +710,7 @@ value_var = param.unix_name + '_value' (c.Append('const base::Value* %(value_var)s = NULL;') .Append('if (args.Get(%(i)s, &%(value_var)s) &&') - .Sblock(' !%(value_var)s->IsType(base::Value::Type::NONE)) {') + .Sblock(' !%(value_var)s->is_none()) {') .Concat(self._GeneratePopulatePropertyFromValue( param, value_var, 'params', failure_value)) .Eblock('}') @@ -884,7 +884,7 @@ dst_var, failure_value)) elif underlying_type.property_type == PropertyType.BINARY: - (c.Sblock('if (!%(src_var)s->IsType(base::Value::Type::BINARY)) {') + (c.Sblock('if (!%(src_var)s->is_blob()) {') .Concat(self._GenerateError( '"\'%%(key)s\': expected binary, got " + ' + self._util_cc_helper.GetValueTypeString('%%(src_var)s', True)))
diff --git a/tools/json_schema_compiler/cpp_bundle_generator.py b/tools/json_schema_compiler/cpp_bundle_generator.py index a6531b0..620b3f191 100644 --- a/tools/json_schema_compiler/cpp_bundle_generator.py +++ b/tools/json_schema_compiler/cpp_bundle_generator.py
@@ -290,9 +290,6 @@ def Generate(self, _): # namespace not relevant, this is a bundle c = code.Code() - c.Append('#include <map>') - c.Append('#include <string>') - c.Append() c.Append('#include "base/strings/string_piece.h"') c.Append() c.Concat(cpp_util.OpenNamespace(self._bundle._cpp_namespace)) @@ -301,10 +298,10 @@ self._bundle._GenerateBundleClass('GeneratedSchemas')) c.Sblock(' public:') c.Append('// Determines if schema named |name| is generated.') - c.Append('static bool IsGenerated(std::string name);') + c.Append('static bool IsGenerated(base::StringPiece name);') c.Append() c.Append('// Gets the API schema named |name|.') - c.Append('static base::StringPiece Get(const std::string& name);') + c.Append('static base::StringPiece Get(base::StringPiece name);') c.Eblock('};') c.Append() c.Concat(cpp_util.CloseNamespace(self._bundle._cpp_namespace)) @@ -332,8 +329,6 @@ c.Append('#include "%s"' % (os.path.join(self._bundle._source_file_dir, 'generated_schemas.h'))) c.Append() - c.Append('#include "base/lazy_instance.h"') - c.Append() c.Append('namespace {') for api in self._bundle._api_defs: namespace = self._bundle._model.namespaces[api.get('namespace')] @@ -350,35 +345,37 @@ for i in xrange(0, len(json_content), max_length)] c.Append('const char %s[] = "%s";' % (_FormatNameAsConstant(namespace.name), '" "'.join(segments))) - c.Append() - c.Sblock('struct Static {') - c.Sblock('Static() {') - for api in self._bundle._api_defs: - namespace = self._bundle._model.namespaces[api.get('namespace')] - c.Append('schemas["%s"] = %s;' % (namespace.name, - _FormatNameAsConstant(namespace.name))) - c.Eblock('}') - c.Append() - c.Append('std::map<std::string, const char*> schemas;') - c.Eblock('};') - c.Append() - c.Append('base::LazyInstance<Static>::DestructorAtExit g_lazy_instance;') - c.Append() c.Append('} // namespace') c.Append() c.Concat(cpp_util.OpenNamespace(self._bundle._cpp_namespace)) c.Append() c.Append('// static') - c.Sblock('base::StringPiece %s::Get(const std::string& name) {' % + c.Sblock('bool %s::IsGenerated(base::StringPiece name) {' % self._bundle._GenerateBundleClass('GeneratedSchemas')) - c.Append('return IsGenerated(name) ? ' - 'g_lazy_instance.Get().schemas[name] : "";') + c.Append('return !Get(name).empty();') c.Eblock('}') c.Append() c.Append('// static') - c.Sblock('bool %s::IsGenerated(std::string name) {' % + c.Sblock('base::StringPiece %s::Get(base::StringPiece name) {' % self._bundle._GenerateBundleClass('GeneratedSchemas')) - c.Append('return g_lazy_instance.Get().schemas.count(name) > 0;') + c.Append('static const struct {') + c.Append(' base::StringPiece name;') + c.Append(' base::StringPiece schema;') + c.Sblock('} kSchemas[] = {') + namespaces = [self._bundle._model.namespaces[api.get('namespace')].name + for api in self._bundle._api_defs] + for namespace in sorted(namespaces): + schema_constant_name = _FormatNameAsConstant(namespace) + c.Append('{{"%s", %d}, {%s, sizeof(%s) - 1}},' % + (namespace, len(namespace), + schema_constant_name, schema_constant_name)) + c.Eblock('};') + c.Sblock('for (const auto& schema : kSchemas) {') + c.Sblock('if (schema.name == name)') + c.Append('return schema.schema;') + c.Eblock() + c.Eblock('}') + c.Append('return base::StringPiece();') c.Eblock('}') c.Append() c.Concat(cpp_util.CloseNamespace(self._bundle._cpp_namespace))
diff --git a/tools/json_schema_compiler/test/features_generation_unittest.cc b/tools/json_schema_compiler/test/features_generation_unittest.cc index 81ab003..e620998 100644 --- a/tools/json_schema_compiler/test/features_generation_unittest.cc +++ b/tools/json_schema_compiler/test/features_generation_unittest.cc
@@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/optional.h" #include "extensions/common/features/complex_feature.h" #include "extensions/common/features/feature.h" #include "extensions/common/features/simple_feature.h" @@ -21,9 +22,6 @@ EXPECT_EQ(expected, actual) << name; } -SimpleFeature::Location kDefaultLocation = SimpleFeature::UNSPECIFIED_LOCATION; -const int kDefaultMinVersion = 0; -const int kDefaultMaxVersion = 0; const bool kDefaultAutoGrant = true; const bool kDefaultInternal = false; @@ -44,27 +42,28 @@ std::vector<Manifest::Type> extension_types; std::vector<Feature::Context> contexts; std::vector<Feature::Platform> platforms; + URLPatternSet matches; - SimpleFeature::Location location; - int min_manifest_version; - int max_manifest_version; - bool component_extensions_auto_granted; - std::string command_line_switch; - std::unique_ptr<version_info::Channel> channel; - bool internal; + + base::Optional<SimpleFeature::Location> location; + base::Optional<int> min_manifest_version; + base::Optional<int> max_manifest_version; + base::Optional<std::string> command_line_switch; + base::Optional<version_info::Channel> channel; + std::string alias; std::string source; + + bool component_extensions_auto_granted; + bool internal; }; FeatureComparator::FeatureComparator(const std::string& name) : name(name), - location(kDefaultLocation), - min_manifest_version(kDefaultMinVersion), - max_manifest_version(kDefaultMaxVersion), component_extensions_auto_granted(kDefaultAutoGrant), internal(kDefaultInternal) {} -FeatureComparator::~FeatureComparator() {} +FeatureComparator::~FeatureComparator() = default; void FeatureComparator::CompareFeature(const SimpleFeature* feature) { ASSERT_TRUE(feature); @@ -83,9 +82,7 @@ feature->component_extensions_auto_granted()) << name; EXPECT_EQ(command_line_switch, feature->command_line_switch()) << name; - ASSERT_EQ(channel.get() != nullptr, feature->has_channel()) << name; - if (channel) - EXPECT_EQ(*channel, feature->channel()) << name; + EXPECT_EQ(channel, feature->channel()) << name; EXPECT_EQ(internal, feature->IsInternal()) << name; EXPECT_EQ(alias, feature->alias()) << name; EXPECT_EQ(source, feature->source()) << name; @@ -114,8 +111,7 @@ FeatureComparator comparator("alpha"); comparator.dependencies = {"permission:alpha"}; comparator.contexts = {Feature::BLESSED_EXTENSION_CONTEXT}; - comparator.channel.reset( - new version_info::Channel(version_info::Channel::STABLE)); + comparator.channel = version_info::Channel::STABLE; comparator.max_manifest_version = 1; comparator.CompareFeature(feature); } @@ -123,8 +119,7 @@ const SimpleFeature* feature = GetAsSimpleFeature("beta"); FeatureComparator comparator("beta"); comparator.contexts = {Feature::BLESSED_EXTENSION_CONTEXT}; - comparator.channel.reset( - new version_info::Channel(version_info::Channel::DEV)); + comparator.channel = version_info::Channel::DEV; comparator.extension_types = {Manifest::TYPE_EXTENSION, Manifest::TYPE_PLATFORM_APP}; comparator.location = SimpleFeature::COMPONENT_LOCATION; @@ -136,8 +131,7 @@ { const SimpleFeature* feature = GetAsSimpleFeature("gamma"); FeatureComparator comparator("gamma"); - comparator.channel.reset( - new version_info::Channel(version_info::Channel::BETA)); + comparator.channel = version_info::Channel::BETA; comparator.platforms = {Feature::WIN_PLATFORM, Feature::MACOSX_PLATFORM}; comparator.contexts = {Feature::BLESSED_EXTENSION_CONTEXT}; comparator.dependencies = {"permission:gamma"}; @@ -161,8 +155,7 @@ FeatureComparator comparator("gamma.unparented"); comparator.blacklist = {"ddd"}; comparator.contexts = {Feature::UNBLESSED_EXTENSION_CONTEXT}; - comparator.channel.reset( - new version_info::Channel(version_info::Channel::DEV)); + comparator.channel = version_info::Channel::DEV; comparator.CompareFeature(feature); } { @@ -170,8 +163,7 @@ GetAsComplexFeature("gamma.complex_unparented"); FeatureComparator comparator("gamma.complex_unparented"); comparator.contexts = {Feature::UNBLESSED_EXTENSION_CONTEXT}; - comparator.channel.reset( - new version_info::Channel(version_info::Channel::STABLE)); + comparator.channel = version_info::Channel::STABLE; // We cheat and have both children exactly the same for ease of comparing; // complex features are tested more thoroughly below. for (const auto& feature : complex_feature->features_) @@ -182,8 +174,7 @@ FeatureComparator comparator("delta"); comparator.contexts = {Feature::BLESSED_EXTENSION_CONTEXT, Feature::WEBUI_CONTEXT}; - comparator.channel.reset( - new version_info::Channel(version_info::Channel::DEV)); + comparator.channel = version_info::Channel::DEV; comparator.matches.AddPattern( URLPattern(URLPattern::SCHEME_ALL, "*://example.com/*")); comparator.min_manifest_version = 2; @@ -204,8 +195,7 @@ Manifest::TYPE_EXTENSION, Manifest::TYPE_HOSTED_APP, Manifest::TYPE_LEGACY_PACKAGED_APP, Manifest::TYPE_PLATFORM_APP, Manifest::TYPE_SHARED_MODULE, Manifest::TYPE_THEME}; - comparator.channel.reset( - new version_info::Channel(version_info::Channel::BETA)); + comparator.channel = version_info::Channel::BETA; comparator.CompareFeature(feature); } { @@ -213,8 +203,7 @@ const SimpleFeature* feature = GetAsSimpleFeature("omega"); FeatureComparator comparator("omega"); comparator.contexts = {Feature::WEB_PAGE_CONTEXT}; - comparator.channel.reset( - new version_info::Channel(version_info::Channel::DEV)); + comparator.channel = version_info::Channel::DEV; comparator.min_manifest_version = 2; comparator.CompareFeature(feature); } @@ -250,8 +239,7 @@ { // Check the default parent. FeatureComparator comparator("complex"); - comparator.channel.reset( - new version_info::Channel(version_info::Channel::STABLE)); + comparator.channel = version_info::Channel::STABLE; comparator.contexts = {Feature::BLESSED_EXTENSION_CONTEXT}; comparator.extension_types = {Manifest::TYPE_EXTENSION}; comparator.CompareFeature(default_parent); @@ -266,8 +254,7 @@ { // Finally, check the branch of the complex feature. FeatureComparator comparator("complex"); - comparator.channel.reset( - new version_info::Channel(version_info::Channel::BETA)); + comparator.channel = version_info::Channel::BETA; comparator.contexts = {Feature::BLESSED_EXTENSION_CONTEXT}; comparator.extension_types = {Manifest::TYPE_EXTENSION}; comparator.whitelist = {"aaa"}; @@ -280,8 +267,7 @@ const SimpleFeature* feature = GetAsSimpleFeature("alias"); FeatureComparator comparator("alias"); comparator.contexts = {Feature::BLESSED_EXTENSION_CONTEXT}; - comparator.channel.reset( - new version_info::Channel(version_info::Channel::STABLE)); + comparator.channel = version_info::Channel::STABLE; comparator.source = "alias_source"; comparator.CompareFeature(feature); } @@ -289,8 +275,7 @@ const SimpleFeature* feature = GetAsSimpleFeature("alias_source"); FeatureComparator comparator("alias_source"); comparator.contexts = {Feature::BLESSED_EXTENSION_CONTEXT}; - comparator.channel.reset( - new version_info::Channel(version_info::Channel::STABLE)); + comparator.channel = version_info::Channel::STABLE; comparator.alias = "alias"; comparator.CompareFeature(feature); }
diff --git a/tools/json_schema_compiler/test/idl_schemas_unittest.cc b/tools/json_schema_compiler/test/idl_schemas_unittest.cc index 751b743..1b9fbac3 100644 --- a/tools/json_schema_compiler/test/idl_schemas_unittest.cc +++ b/tools/json_schema_compiler/test/idl_schemas_unittest.cc
@@ -68,7 +68,7 @@ std::unique_ptr<base::ListValue> f5_results(Function5::Results::Create(13)); base::Value* f5_result_int = NULL; ASSERT_TRUE(f5_results->Get(0, &f5_result_int)); - EXPECT_TRUE(f5_result_int->IsType(base::Value::Type::INTEGER)); + EXPECT_TRUE(f5_result_int->is_int()); std::unique_ptr<base::ListValue> f6_results(Function6::Results::Create(a)); base::Value* f6_result_dict = NULL;
diff --git a/tools/json_schema_compiler/util.cc b/tools/json_schema_compiler/util.cc index 441fc25..227ad3b 100644 --- a/tools/json_schema_compiler/util.cc +++ b/tools/json_schema_compiler/util.cc
@@ -20,7 +20,7 @@ error->append(base::ASCIIToUTF16("; ")); error->append(base::ASCIIToUTF16(base::StringPrintf( "expected %s, got %s", base::Value::GetTypeName(expected), - base::Value::GetTypeName(from.GetType())))); + base::Value::GetTypeName(from.type())))); return false; // Always false on purpose. }
diff --git a/tools/json_schema_compiler/util_cc_helper.py b/tools/json_schema_compiler/util_cc_helper.py index 5f5ab0f..1b5189a 100644 --- a/tools/json_schema_compiler/util_cc_helper.py +++ b/tools/json_schema_compiler/util_cc_helper.py
@@ -36,7 +36,7 @@ return '#include "tools/json_schema_compiler/util.h"' def GetValueTypeString(self, value, is_ptr=False): - call = '.GetType()' + call = '.type()' if is_ptr: - call = '->GetType()' + call = '->type()' return 'std::string(base::Value::GetTypeName(%s%s))' % (value, call)
diff --git a/tools/licenses.py b/tools/licenses.py index 1021763..f0bf0bb 100755 --- a/tools/licenses.py +++ b/tools/licenses.py
@@ -17,6 +17,7 @@ import argparse import cgi +import json import os import shutil import re @@ -25,7 +26,7 @@ import tempfile # TODO(agrieve): Move build_utils.WriteDepFile into a non-android directory. -_REPOSITORY_ROOT = os.path.dirname(os.path.dirname(__file__)) +_REPOSITORY_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) sys.path.append(os.path.join(_REPOSITORY_ROOT, 'build/android/gyp/util')) import build_utils @@ -91,6 +92,9 @@ # For testing only, presents on some bots. os.path.join('isolate_deps_dir'), + # Mock test data. + os.path.join('tools', 'binary_size', 'libsupersize', 'testdata'), + # Overrides some WebRTC files, same license. Skip this one. os.path.join('third_party', 'webrtc_overrides'), ]) @@ -101,14 +105,19 @@ ('out', 'Debug', 'Release', # build files 'layout_tests')) # lots of subdirs +# A third_party directory can define this file, containing a list of +# subdirectories to process instead of itself. Intended for directories that +# contain multiple others as transitive dependencies. +ADDITIONAL_PATHS_FILENAME = 'additional_readme_paths.json' + ADDITIONAL_PATHS = ( - os.path.join('breakpad'), os.path.join('chrome', 'common', 'extensions', 'docs', 'examples'), os.path.join('chrome', 'test', 'chromeos', 'autotest'), os.path.join('chrome', 'test', 'data'), os.path.join('native_client'), os.path.join('testing', 'gmock'), os.path.join('testing', 'gtest'), + os.path.join('third_party', 'boringssl', 'src', 'third_party', 'fiat'), os.path.join('tools', 'gyp'), os.path.join('tools', 'page_cycler', 'acid3'), os.path.join('url', 'third_party', 'mozilla'), @@ -283,6 +292,7 @@ os.path.join('third_party', 'libXNVCtrl'), os.path.join('third_party', 'libevent'), os.path.join('third_party', 'libjpeg'), + os.path.join('third_party', 'libovr'), os.path.join('third_party', 'libusb'), os.path.join('third_party', 'libxslt'), os.path.join('third_party', 'lss'), @@ -354,7 +364,7 @@ readme_path = os.path.join(root, path, 'README.chromium') if not os.path.exists(readme_path): raise LicenseError("missing README.chromium or licenses.py " - "SPECIAL_CASES entry in %s" % path) + "SPECIAL_CASES entry in %s\n" % path) for line in open(readme_path): line = line.strip() @@ -391,7 +401,7 @@ metadata["License File"] = license_path if errors: - raise LicenseError(";\n".join(errors)) + raise LicenseError("Errors in %s:\n %s\n" % (path, ";\n ".join(errors))) return metadata @@ -434,7 +444,14 @@ # Add all subdirectories that are not marked for skipping. for dir in dirs: dirpath = os.path.join(path, dir) - if dirpath not in prune_paths: + additional_paths_file = os.path.join( + dirpath, ADDITIONAL_PATHS_FILENAME) + if os.path.exists(additional_paths_file): + with open(additional_paths_file) as paths_file: + extra_paths = json.load(paths_file) + third_party_dirs.update([ + os.path.join(dirpath, p) for p in extra_paths]) + elif dirpath not in prune_paths: third_party_dirs.add(dirpath) # Don't recurse into any subdirs from here. @@ -480,12 +497,17 @@ Note that it always returns the direct sub-directory of third_party where README.chromium and LICENSE files are, so that it can be passed to ParseDir(). e.g.: - .../third_party/cld_3/src/src/BUILD.gn -> .../third_party/cld_3 + third_party/cld_3/src/src/BUILD.gn -> third_party/cld_3 + + It returns relative paths from _REPOSITORY_ROOT, not absolute paths. """ third_party_deps = set() - for build_dep in gn_deps.split(): - m = re.search(r'^(.+/third_party/[^/]+)/(.+/)?BUILD\.gn$', build_dep) - if m and not os.path.join('build', 'secondary') in build_dep: + for absolute_build_dep in gn_deps.split(): + relative_build_dep = os.path.relpath( + absolute_build_dep, _REPOSITORY_ROOT) + m = re.search( + r'^((.+/)?third_party/[^/]+)/(.+/)?BUILD\.gn$', relative_build_dep) + if m and not os.path.join('build', 'secondary') in relative_build_dep: third_party_deps.add(m.group(1)) return third_party_deps @@ -606,7 +628,7 @@ continue entries.append(MetadataToTemplateEntry(metadata, entry_template)) - entries.sort(key=lambda entry: (entry['name'], entry['content'])) + entries.sort(key=lambda entry: (entry['name'].lower(), entry['content'])) for entry_id, entry in enumerate(entries): entry['content'] = entry['content'].replace('{{id}}', str(entry_id))
diff --git a/tools/lldb/lldb_chrome.py b/tools/lldb/lldb_chrome.py index 2c93d34..985f76c1 100644 --- a/tools/lldb/lldb_chrome.py +++ b/tools/lldb/lldb_chrome.py
@@ -29,6 +29,8 @@ data = l.GetChildMemberWithName('__data_').GetPointeeData(0, length) error = lldb.SBError() bytes_to_read = 2 * length + if not bytes_to_read: + return '""' byte_string = data.ReadRawData(error, 0, bytes_to_read) if error.fail: return 'Summary error: %s' % error.description
diff --git a/tools/luci-go/.gitignore b/tools/luci-go/.gitignore new file mode 100644 index 0000000..06e95105 --- /dev/null +++ b/tools/luci-go/.gitignore
@@ -0,0 +1,3 @@ +/linux64/isolate +/mac64/isolate +/win64/isolate.exe
diff --git a/tools/luci-go/README.md b/tools/luci-go/README.md index a87c34f..f53bec17 100644 --- a/tools/luci-go/README.md +++ b/tools/luci-go/README.md
@@ -1,7 +1,7 @@ # luci-go Contains executable built out of -https://github.com/luci/luci-go/tree/master/client/cmd/. +https://chromium.googlesource.com/infra/luci/luci-go/+/master/client/cmd The binaries are retrieved from the following builders:
diff --git a/tools/luci-go/linux64/isolate.sha1 b/tools/luci-go/linux64/isolate.sha1 index f923147..5a23e1c 100644 --- a/tools/luci-go/linux64/isolate.sha1 +++ b/tools/luci-go/linux64/isolate.sha1
@@ -1 +1 @@ -48ffe036be8eff7d39ebbdbb705bd26f0ec6f404 +b1c3c39fe8fe084bd2ec4ed0f03037751a3a8650
diff --git a/tools/luci-go/mac64/isolate.sha1 b/tools/luci-go/mac64/isolate.sha1 index 328cc06..72d9784 100644 --- a/tools/luci-go/mac64/isolate.sha1 +++ b/tools/luci-go/mac64/isolate.sha1
@@ -1 +1 @@ -f0d9ea71e7059a164962658b588286ebf262c5dd +ffb6a624bd14abdff34618fe97562b34350199f7
diff --git a/tools/luci-go/win64/isolate.exe.sha1 b/tools/luci-go/win64/isolate.exe.sha1 index 8038c79..d3ab3b3 100644 --- a/tools/luci-go/win64/isolate.exe.sha1 +++ b/tools/luci-go/win64/isolate.exe.sha1
@@ -1 +1 @@ -40790017e9b7856009c36768bf9244a4182ad5d1 +bb2a587cbc0a8e5b0ae41be4ffb5ad33b213dcf9
diff --git a/tools/mac/rewrite_modern_objc.py b/tools/mac/rewrite_modern_objc.py new file mode 100755 index 0000000..8aa1d27 --- /dev/null +++ b/tools/mac/rewrite_modern_objc.py
@@ -0,0 +1,146 @@ +#!/usr/bin/env python +# Copyright 2018 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. + +"""Runs clang's "modern objective-c" rewriter on chrome code. +Does the same as Xcode's Edit->Convert->To Modern Objective-C Syntax. + +Note that this just runs compile commands and doesn't look at build +dependencies, i.e. it doesn't make sure generated headers exist. It also +requires goma to be disabled. Suggested workflow: Build the target you want +to convert locally with goma to create generated headers, then disable goma, +re-run gn, and then run this script. +""" + +import argparse +import glob +import json +import math +import os +import shlex +import subprocess +import sys + +def main(): + # As far as I can tell, clang's ObjC rewriter can't do in-place rewriting + # (the ARC rewriter can). libclang exposes functions for parsing the remap + # file, but doing that manually in python seems a lot easier. + + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('builddir', help='build directory, e.g. out/gn') + parser.add_argument('substr', default='', nargs='?', + help='source dir part, eg chrome/browser/ui/cocoa') + args = parser.parse_args() + + rewrite_dir = os.path.abspath( + os.path.join(args.builddir, 'rewrite_modern_objc')) + try: + os.mkdir(rewrite_dir) + except OSError: + pass + + remap_file = os.path.join(rewrite_dir, 'remap') + try: + # Remove remap files from prior runs. + os.remove(remap_file) + except OSError: + pass + + # The basic idea is to call clang's objcmt rewriter for each source file. + # The rewriter writes a "remap" file containing N times 3 lines: + # Name of an original source file, the original file's timestamp + # at rewriting time, and the name of a temp file containing the rewritten + # contents. + # The rewriter gets confused if several instances run in parallel. We could + # be fancy and have num_cpus rewrite dirs and combine their contents in the + # end, but for now just run the rewrites serially. + + # First, ask ninja for the compile commands of all .m and .mm files. + compdb = subprocess.check_output( + ['ninja', '-C', args.builddir, '-t', 'compdb', 'objc', 'objcxx']) + + for cmd in json.loads(compdb): + objc_file = cmd['file'] + if args.substr not in objc_file: + continue + clang_cmd = cmd['command'] + + had_error = False + if 'gomacc' in clang_cmd: + print >>sys.stderr, 'need builddir with use_goma not set' + had_error = True + if 'jumbo' in clang_cmd: + print >>sys.stderr, 'need builddir with use_jumbo_build not set' + had_error = True + if 'precompile.h-m' in clang_cmd: + print >>sys.stderr, 'need builddir with enable_precompiled_headers=false' + had_error = True + if had_error: + sys.exit(1) + + # Ninja creates the directory containing the build output, but we + # don't run ninja, so we need to do that ourselves. + split_cmd = shlex.split(clang_cmd) + o_index = split_cmd.index('-o') + assert o_index != -1 + try: + os.makedirs(os.path.dirname(split_cmd[o_index + 1])) + except OSError: + pass + + # Add flags to tell clang to do the rewriting. + # Passing "-ccc-objcmt-migrate dir" doesn't give us control over each + # individual setting, so use the Xclang flags. The individual flags are at + # http://llvm-cs.pcc.me.uk/tools/clang/include/clang/Driver/Options.td#291 + # Note that -objcmt-migrate-all maps to ObjCMT_MigrateDecls in + # http://llvm-cs.pcc.me.uk/tools/clang/lib/Frontend/CompilerInvocation.cpp#1479 + # which is not quite all the options: + # http://llvm-cs.pcc.me.uk/tools/clang/include/clang/Frontend/FrontendOptions.h#248 + + flags = ['-Xclang', '-mt-migrate-directory', '-Xclang', rewrite_dir] + flags += ['-Xclang', '-objcmt-migrate-subscripting' ] + flags += ['-Xclang', '-objcmt-migrate-literals' ] + flags += ['-Xclang', '-objcmt-returns-innerpointer-property'] + #flags += ['-Xclang', '-objcmt-migrate-property-dot-syntax'] # do not want + # objcmt-migrate-all is the same as the flags following it here (it does + # not include the flags listed above it). + # Probably don't want ns-nonatomic-iosonly (or atomic-property), so we + # can't use migrate-alll which includes that, and have to manually set the + # bits of migrate-all we do want. + #flags += ['-Xclang', '-objcmt-migrate-all'] + #flags += ['-Xclang', '-objcmt-migrate-property'] # not sure if want + flags += ['-Xclang', '-objcmt-migrate-annotation'] + flags += ['-Xclang', '-objcmt-migrate-instancetype'] + flags += ['-Xclang', '-objcmt-migrate-ns-macros'] + flags += ['-Xclang', '-objcmt-migrate-protocol-conformance'] + #flags += ['-Xclang', '-objcmt-atomic-property'] # not sure if want + #flags += ['-Xclang', '-objcmt-ns-nonatomic-iosonly'] # not sure if want + flags += ['-Xclang', '-objcmt-migrate-designated-init'] + clang_cmd += ' ' + ' '.join(flags) + + print objc_file + subprocess.check_call(clang_cmd, shell=True, cwd=cmd['directory']) + + if not os.path.exists(remap_file): + print 'no changes' + return + + # Done with rewriting. Now the read the above-described 'remap' file and + # copy modified files over the originals. + remap = open(remap_file).readlines() + for i in range(0, len(remap), 3): + infile, mtime, outfile = map(str.strip, remap[i:i+3]) + if args.substr not in infile: + # Ignore rewritten header files not containing args.substr too. + continue + if math.trunc(os.path.getmtime(infile)) != int(mtime): + print '%s was modified since rewriting; exiting' % infile + sys.exit(1) + os.rename(outfile, infile) # Copy rewritten file over. + + print 'all done. commit, run `git cl format`, commit again, and upload!' + + +if __name__ == '__main__': + main()
diff --git a/tools/mb/OWNERS b/tools/mb/OWNERS index f7dae03..1ae0b4e 100644 --- a/tools/mb/OWNERS +++ b/tools/mb/OWNERS
@@ -1,6 +1,5 @@ dpranke@chromium.org jbudorick@chromium.org -phajdan.jr@chromium.org scottmg@chromium.org tansell@chromium.org
diff --git a/tools/mb/README.md b/tools/mb/README.md index 4e73a8e9..6483f0e 100644 --- a/tools/mb/README.md +++ b/tools/mb/README.md
@@ -1,13 +1,19 @@ # MB - The Meta-Build wrapper -MB is a simple wrapper intended to provide a uniform interface to either -GYP or GN, such that users and bots can call one script and not need to -worry about whether a given bot is meant to use GN or GYP. +MB is a simple wrapper around the GN build tool. + +It was originally written as part of the GYP->GN migration, in order to +provide a uniform interface to either GYP or GN, such that users and bots +can call one script and not need to worry about whether a given bot was +meant to use GN or GYP. + +It eventually grew additional functionality and is now still used even +though everything is GN-only. It supports two main functions: -1. "gen" - the main `gyp_chromium` / `gn gen` invocation that generates the - Ninja files needed for the build. +1. "gen" - the main `gn gen` invocation that generates the Ninja files + needed for the build. 2. "analyze" - the step that takes a list of modified files and a list of desired targets and reports which targets will need to be rebuilt.
diff --git a/tools/mb/docs/design_spec.md b/tools/mb/docs/design_spec.md index fb202da..7836d8ec 100644 --- a/tools/mb/docs/design_spec.md +++ b/tools/mb/docs/design_spec.md
@@ -4,21 +4,22 @@ ## Intro -MB is intended to address two major aspects of the GYP -> GN transition -for Chromium: +MB was originally intended to address two major aspects of the GYP -> GN +transition for Chromium: 1. "bot toggling" - make it so that we can easily flip a given bot back and forth between GN and GYP. 2. "bot configuration" - provide a single source of truth for all of - the different configurations (os/arch/`gyp_define` combinations) of + the different configurations (os/arch/`gn_args` combinations) of Chromium that are supported. -MB must handle at least the `gen` and `analyze` steps on the bots, i.e., -we need to wrap both the `gyp_chromium` invocation to generate the -Ninja files, and the `analyze` step that takes a list of modified files -and a list of targets to build and returns which targets are affected by -the files. +Now that everything is using GN, only the second purpose is really relevant, +but it's still important. MB must handle at least the `gen` and `analyze` +steps on the bots, i.e., we need to wrap both the `gn gen` invocation to +generate the Ninja files, and the `analyze` step that takes a list of +modified files and a list of targets to build and returns which targets +are affected by the files. For more information on how to actually use MB, see [the user guide](user_guide.md). @@ -26,7 +27,7 @@ ## Design MB is intended to be as simple as possible, and to defer as much work as -possible to GN or GYP. It should live as a very simple Python wrapper +possible to GN. It should live as a very simple Python wrapper that offers little in the way of surprises. ### Command line @@ -40,16 +41,12 @@ `mb` will first look for a bot config file in a set of different locations (initially just in //ios/build/bots). Bot config files are JSON files that -contain keys for 'GYP_DEFINES' (a list of strings that will be joined together -with spaces and passed to GYP, or a dict that will be similarly converted), -'gn_args' (a list of strings that will be joined together), and an -'mb_type' field that says whether to use GN or GYP. Bot config files -require the full list of settings to be given explicitly. +contain keys for 'gn_args' (a list of strings that will be joined together). +Bot config files require the full list of settings to be given explicitly. If no matching bot config file is found, `mb` looks in the -`//tools/mb/mb_config.pyl` config file to determine whether to use GYP or GN -for a particular build directory, and what set of flags (`GYP_DEFINES` or `gn -args`) to use. +`//tools/mb/mb_config.pyl` config file to determine what set of flags +(`gn args`) to use. A config can either be specified directly (useful for testing) or by specifying the master name and builder name (useful on the bots so that they do not need @@ -64,10 +61,6 @@ The way analyze works can be subtle and complicated (see below). -Since the interface basically mirrors the way the "analyze" step on the bots -invokes `gyp_chromium` today, when the config is found to be a gyp config, -the arguments are passed straight through. - It implements the equivalent functionality in GN by calling `gn refs [list of files] --type=executable --all --as=output` and filtering the output to match the list of targets. @@ -110,16 +103,15 @@ you need to build base_unittests. For others (like the telemetry and layout tests), you might need to build several executables in order to run the tests, and that mapping might best be captured by a *meta* - target (a GN group or a GYP 'none' target like `webkit_tests`) that - depends on the right list of files. Because the GN and GYP files know - nothing about test steps, we have to have some way of mapping back - and forth between test steps and build targets. That mapping - is *not* currently available to MB (or GN or GYP), and so we have to - enough information to make it possible for the caller to do the mapping. + target (a GN group like `webkit_tests`) that depends on the right list + of files. Because the BUILD.gn files know nothing about test steps, we + have to have some way of mapping back and forth between test steps and + build targets. That mapping is *not* currently available to MB (or GN), + and so we have to provide enough information to make it possible for + the caller to do the mapping. 3. We might also want to know when test targets are affected by data files that aren't compiled (python scripts, or the layout tests themselves). - There's no good way to do this in GYP, but GN supports this. 4. We also want to ensure that particular targets still compile even if they are not actually tested; consider testing the installers themselves, or @@ -137,9 +129,9 @@ 6. As noted above, in the ideal case we actually have enough resources and things are fast enough that we can afford to build everything affected by a patch, but listing every possible target explicitly would be painful. The - GYP and GN Ninja generators provide an 'all' target that captures (nearly, + GN Ninja generator provides an 'all' target that captures (nearly, see [crbug.com/503241](crbug.com/503241)) everything, but unfortunately - neither GN nor GYP actually represents 'all' as a meta target in the build + GN doesn't actually represent 'all' as a meta target in the build graph, so we will need to write code to handle that specially. 7. In some cases, we will not be able to correctly analyze the build graph to @@ -216,7 +208,7 @@ build, or that there were no affected test targets as appropriate. Note that passing no arguments to Ninja is equivalent to passing -`all` to Ninja (at least given how GN and GYP work); however, we +`all` to Ninja (at least given how GN works); however, we don't want to take advantage of this in most cases because we don't actually want to build every out of date target, only the targets potentially affected by the files. One could try to indicate @@ -225,7 +217,7 @@ confusing, and adding a new field for this seems unwarranted at this time. There is an "error" field in case something goes wrong (like the -empty file list case, above, or an internal error in MB/GYP/GN). The +empty file list case, above, or an internal error in MB/GN). The analyze code should also return an error code to the shell if appropriate to indicate that the command failed. @@ -350,8 +342,7 @@ The first issue is whether or not this should exist as a script in Chromium at all; an alternative would be to simply change the bot -configurations to know whether to use GYP or GN, and which flags to -pass. +configurations to know which flags to pass. That would certainly work, but experience over the past two years suggests a few things: @@ -373,23 +364,12 @@ ### Why not have MB be smarter about de-duping flags? This just adds complexity to the MB implementation, and duplicates logic -that GYP and GN already have to support anyway; in particular, it might -require MB to know how to parse GYP and GN values. The belief is that +that GN already has to support anyway; in particular, it might +require MB to know how to parse GN values. The belief is that if MB does *not* do this, it will lead to fewer surprises. It will not be hard to change this if need be. -### Integration w/ gclient runhooks - -On the bots, we will disable `gyp_chromium` as part of runhooks (using -`GYP_CHROMIUM_NO_ACTION=1`), so that mb shows up as a separate step. - -At the moment, we expect most developers to either continue to use -`gyp_chromium` in runhooks or to disable at as above if they have no -use for GYP at all. We may revisit how this works once we encourage more -people to use GN full-time (i.e., we might take `gyp_chromium` out of -runhooks altogether). - ### Config per flag set or config per (os/arch/flag set)? Currently, mb_config.pyl does not specify the host_os, target_os, host_cpu, or @@ -410,17 +390,15 @@ ### Non-goals -* MB is not intended to replace direct invocation of GN or GYP for +* MB is not intended to replace direct invocation of GN for complicated build scenarios (a.k.a. Chrome OS), where multiple flags need to be set to user-defined paths for specific toolchains (e.g., where Chrome OS needs to specify specific board types and compilers). * MB is not intended at this time to be something developers use frequently, - or to add a lot of features to. We hope to be able to get rid of it once - the GYP->GN migration is done, and so we should not add things for - developers that can't easily be added to GN itself. + or to add a lot of features to. We hope to be able to get rid of it + eventually. * MB is not intended to replace the - [CR tool](https://code.google.com/p/chromium/wiki/CRUserManual). Not - only is it only intended to replace the gyp\_chromium part of `'gclient - runhooks'`, it is not really meant as a developer-facing tool. + [CR tool](https://code.google.com/p/chromium/wiki/CRUserManual), and + it is not really meant as a developer-facing tool.
diff --git a/tools/mb/docs/user_guide.md b/tools/mb/docs/user_guide.md index 0abb235..1bbef2f2 100644 --- a/tools/mb/docs/user_guide.md +++ b/tools/mb/docs/user_guide.md
@@ -4,8 +4,8 @@ ## Introduction -`mb` is a simple python wrapper around the GYP and GN meta-build tools to -be used as part of the GYP->GN migration. +`mb` is a simple python wrapper GN meta-build tool; it was originally +written as part of the GYP->GN migration. It is intended to be used by bots to make it easier to manage the configuration each bot builds (i.e., the configurations can be changed from chromium @@ -45,7 +45,7 @@ reflect the stuff we might want to build *in addition to* the list passed in `test_targets`. Targets in this list will be treated specially, in the following way: if a given target is a "meta" - (GN: group, GYP: none) target like 'blink_tests' or or even the + (GN: group) target like 'blink_tests' or or even the ninja-specific 'all' target, then only the *dependencies* of the target that are affected by the modified files will be rebuilt (not the target itself, which might also cause unaffected dependencies @@ -93,18 +93,11 @@ The `-b/--builder`, `-c/--config`, `-f/--config-file`, `-m/--master`, `-q/--quiet`, and `-v/--verbose` flags work as documented for `mb gen`. -### `mb audit` - -`mb audit` is used to track the progress of the GYP->GN migration. You can -use it to check a single master, or all the masters we care about. See -`mb help audit` for more details (most people are not expected to care about -this). - ### `mb gen` -`mb gen` is responsible for generating the Ninja files by invoking either GYP -or GN as appropriate. It takes arguments to specify a build config and -a directory, then runs GYP or GN as appropriate: +`mb gen` is responsible for generating the Ninja files by invoking GN with +the right sets of build args for the given bot. It takes arguments to +specify a build config and a directory, then runs GN as appropriate: ``` % mb gen -m tryserver.chromium.linux -b linux_rel //out/Release @@ -133,17 +126,19 @@ If the build config will use the Goma distributed-build system, you can pass the path to your Goma client in the `-g/--goma-dir` flag, and it will be -incorporated into the appropriate flags for GYP or GN as needed. - -If gen ends up using GYP, the path must have a valid GYP configuration as the -last component of the path (i.e., specify `//out/Release_x64`, not `//out`). -The gyp script defaults to `//build/gyp_chromium`, but can be overridden with -the `--gyp-script` flag, e.g. `--gyp-script=gypfiles/gyp_v8`. +incorporated into the appropriate flags for GN as needed. ### `mb help` Produces help output on the other subcommands +### `mb isolate` + +Builds a given (ninja) target and produces an `.isolated` file suitable +for then running the command either locally in an isolated environment, +or remotely by uploading it to an isolate server and running it under +swarming. See below for more information on isolates and swarming. + ### `mb lookup` Prints what command will be run by `mb gen` (like `mb gen -n` but does @@ -153,6 +148,24 @@ `--phase`, `-q/--quiet`, and `-v/--verbose` flags work as documented for `mb gen`. +### `mb run` + +Builds and runs a given (ninja) target. By default the target will +be run locally but isolated (i.e., outside of the source tree, just +as it would be run under swarming). If the `-s/--swarming` flag is +passed, the target will be built, run, uploaded to the isolate server, +and run under swarming. + +By default, a set of dimensions appropriate for running the target in the +default pool for the build will be provided. You can specify additional +dimensions with the `-d/--dimension` flags, and you can skip the default +dimensions with the `--no-default-dimensions` flag (which can be useful +if you need to run on devices or in a different pool). See below for more +information on isolates and swarming. + +In either case, any flags past `--` will be passed on to the command +to be run inside the isolate. + ### `mb validate` Does internal checking to make sure the config file is syntactically @@ -179,11 +192,14 @@ -t -b meta_config origin/meta/config && mv buildbucket.config.new buildbucket.config` to update the file. +Note that after committing, `git cl upload` will not work. Instead, use `git +push origin HEAD:refs/for/refs/meta/config` to upload the CL for review. + ## Isolates and Swarming `mb gen` is also responsible for generating the `.isolate` and `.isolated.gen.json` files needed to run test executables through swarming -in a GN build (in a GYP build, this is done as part of the compile step). +in a GN build. If you wish to generate the isolate files, pass `mb gen` the `--swarming-targets-file` command line argument; that arg should be a path @@ -207,7 +223,7 @@ supported build configurations for Chromium. Generally speaking, you should never need to (or want to) build a configuration that isn't listed here, and so by using the configs in this file you can avoid -having to juggle long lists of GYP_DEFINES and gn args by hand. +having to juggle long lists of gn args by hand. `mb_config.pyl` is structured as a file containing a single PYthon Literal expression: a dictionary with three main keys, `masters`, `configs` and @@ -236,49 +252,38 @@ Each mixin value is itself a dictionary that contains one or more of the following keys: - * `gyp_crosscompile`: a boolean; if true, GYP_CROSSCOMPILE=1 is set in - the environment and passed to GYP. - * `gyp_defines`: a string containing a list of GYP_DEFINES. * `gn_args`: a string containing a list of values passed to gn --args. * `mixins`: a list of other mixins that should be included. - * `type`: a string with either the value `gyp` or `gn`; - setting this indicates which meta-build tool to use. When `mb gen` or `mb analyze` executes, it takes a config name, looks it up in the 'configs' dict, and then does a left-to-right expansion of the -mixins; gyp_defines and gn_args values are concatenated, and the type values -override each other. +mixins; gn_args values are concatenated. For example, if you had: ``` { 'configs`: { - 'linux_release_trybot': ['gyp_release', 'trybot'], + 'linux_release_trybot': ['gn_release', 'trybot'], 'gn_shared_debug': None, } 'mixins': { 'bot': { - 'gyp_defines': 'use_goma=1 dcheck_always_on=0', 'gn_args': 'use_goma=true dcheck_always_on=false', }, 'debug': { 'gn_args': 'is_debug=true', }, - 'gn': {'type': 'gn'}, - 'gyp_release': { + 'gn_release': { 'mixins': ['release'], - 'type': 'gyp', }, 'release': { 'gn_args': 'is_debug=false', } 'shared': { 'gn_args': 'is_component_build=true', - 'gyp_defines': 'component=shared_library', }, 'trybot': { - 'gyp_defines': 'dcheck_always_on=1', 'gn_args': 'dcheck_always_on=true', } } @@ -286,11 +291,10 @@ ``` and you ran `mb gen -c linux_release_trybot //out/Release`, it would -translate into a call to `gyp_chromium -G Release` with `GYP_DEFINES` set to -`"use_goma=true dcheck_always_on=false dcheck_always_on=true"`. +translate into a call to `gn --args="use_goma=true dcheck_always_on=false dcheck_always_on=true"`. (From that you can see that mb is intentionally dumb and does not -attempt to de-dup the flags, it lets gyp do that). +attempt to de-dup the flags, it lets GN do that). ## Debugging MB
diff --git a/tools/mb/mb.py b/tools/mb/mb.py index 5a3ad63..7337d2c 100755 --- a/tools/mb/mb.py +++ b/tools/mb/mb.py
@@ -3,16 +3,12 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -"""MB - the Meta-Build wrapper around GYP and GN +"""MB - the Meta-Build wrapper around GN. -MB is a wrapper script for GYP and GN that can be used to generate build files +MB is a wrapper script for GN that can be used to generate build files for sets of canned configurations and analyze them. """ -# TODO(thomasanderson): Remove this comment. It is added to -# workaround https://crbug.com/736215 for CL -# https://codereview.chromium.org/2974603002/ - from __future__ import print_function import argparse @@ -21,6 +17,7 @@ import json import os import pipes +import platform import pprint import re import shutil @@ -94,21 +91,17 @@ help='path to config file ' '(default is %(default)s)') subp.add_argument('-i', '--isolate-map-file', metavar='PATH', - default=self.default_isolate_map, help='path to isolate map file ' - '(default is %(default)s)') + '(default is %(default)s)', + default=[], + action='append', + dest='isolate_map_files') subp.add_argument('-g', '--goma-dir', help='path to goma directory') - subp.add_argument('--gyp-script', metavar='PATH', - default=self.PathJoin('build', 'gyp_chromium'), - help='path to gyp script relative to project root ' - '(default is %(default)s)') subp.add_argument('--android-version-code', - help='Sets GN arg android_default_version_code and ' - 'GYP_DEFINE app_manifest_version_code') + help='Sets GN arg android_default_version_code') subp.add_argument('--android-version-name', - help='Sets GN arg android_default_version_name and ' - 'GYP_DEFINE app_manifest_version_name') + help='Sets GN arg android_default_version_name') subp.add_argument('-n', '--dryrun', action='store_true', help='Do a dry run (i.e., do nothing, just print ' 'the commands that will run)') @@ -189,7 +182,6 @@ ' --test-launcher-retry-limit=0' '\n' ) - AddCommonOptions(subp) subp.add_argument('-j', '--jobs', dest='jobs', type=int, help='Number of jobs to pass to ninja') @@ -201,6 +193,14 @@ ' This can be either a regular path or a ' 'GN-style source-relative path like ' '//out/Default.')) + subp.add_argument('-s', '--swarmed', action='store_true', + help='Run under swarming with the default dimensions') + subp.add_argument('-d', '--dimension', default=[], action='append', nargs=2, + dest='dimensions', metavar='FOO bar', + help='dimension to filter on') + subp.add_argument('--no-default-dimensions', action='store_false', + dest='default_dimensions', default=True, + help='Do not automatically add dimensions to the task') subp.add_argument('target', nargs=1, help='ninja target to build and run') subp.add_argument('extra_args', nargs='*', @@ -216,26 +216,6 @@ help='path to config file (default is %(default)s)') subp.set_defaults(func=self.CmdValidate) - subp = subps.add_parser('audit', - help='Audit the config file to track progress') - subp.add_argument('-f', '--config-file', metavar='PATH', - default=self.default_config, - help='path to config file (default is %(default)s)') - subp.add_argument('-i', '--internal', action='store_true', - help='check internal masters also') - subp.add_argument('-m', '--master', action='append', - help='master to audit (default is all non-internal ' - 'masters in file)') - subp.add_argument('-u', '--url-template', action='store', - default='https://build.chromium.org/p/' - '{master}/json/builders', - help='URL scheme for JSON APIs to buildbot ' - '(default: %(default)s) ') - subp.add_argument('-c', '--check-compile', action='store_true', - help='check whether tbd and master-only bots actually' - ' do compiles') - subp.set_defaults(func=self.CmdAudit) - subp = subps.add_parser('gerrit-buildbucket-config', help='Print buildbucket.config for gerrit ' '(see MB user guide)') @@ -271,11 +251,7 @@ def CmdAnalyze(self): vals = self.Lookup() - self.ClobberIfNeeded(vals) - if vals['type'] == 'gn': - return self.RunGNAnalyze(vals) - else: - return self.RunGYPAnalyze(vals) + return self.RunGNAnalyze(vals) def CmdExport(self): self.ReadConfigFile() @@ -307,11 +283,7 @@ def CmdGen(self): vals = self.Lookup() - self.ClobberIfNeeded(vals) - if vals['type'] == 'gn': - return self.RunGNGen(vals) - else: - return self.RunGYPGen(vals) + return self.RunGNGen(vals) def CmdHelp(self): if self.args.subcommand: @@ -323,21 +295,14 @@ vals = self.GetConfig() if not vals: return 1 - - if vals['type'] == 'gn': - return self.RunGNIsolate(vals) - else: - return self.Build('%s_run' % self.args.target[0]) + return self.RunGNIsolate(vals) def CmdLookup(self): vals = self.Lookup() - if vals['type'] == 'gn': - cmd = self.GNCmd('gen', '_path_') - gn_args = self.GNArgs(vals) - self.Print('\nWriting """\\\n%s""" to _path_/args.gn.\n' % gn_args) - env = None - else: - cmd, env = self.GYPCmd('_path_', vals) + cmd = self.GNCmd('gen', '_path_') + gn_args = self.GNArgs(vals) + self.Print('\nWriting """\\\n%s""" to _path_/args.gn.\n' % gn_args) + env = None self.PrintCmd(cmd, env) return 0 @@ -350,33 +315,87 @@ build_dir = self.args.path[0] target = self.args.target[0] - if vals['type'] == 'gn': - if self.args.build: - ret = self.Build(target) - if ret: - return ret - ret = self.RunGNIsolate(vals) + if self.args.build: + ret = self.Build(target) if ret: return ret - else: - ret = self.Build('%s_run' % target) - if ret: - return ret + ret = self.RunGNIsolate(vals) + if ret: + return ret + if self.args.swarmed: + return self._RunUnderSwarming(build_dir, target) + else: + return self._RunLocallyIsolated(build_dir, target) + + def _RunUnderSwarming(self, build_dir, target): + # TODO(dpranke): Look up the information for the target in + # the //testing/buildbot.json file, if possible, so that we + # can determine the isolate target, command line, and additional + # swarming parameters, if possible. + # + # TODO(dpranke): Also, add support for sharding and merging results. + dimensions = [] + for k, v in self._DefaultDimensions() + self.args.dimensions: + dimensions += ['-d', k, v] + + cmd = [ + self.executable, + self.PathJoin('tools', 'swarming_client', 'isolate.py'), + 'archive', + '-s', + self.ToSrcRelPath('%s/%s.isolated' % (build_dir, target)), + '-I', 'isolateserver.appspot.com', + ] + ret, out, _ = self.Run(cmd, force_verbose=False) + if ret: + return ret + + isolated_hash = out.splitlines()[0].split()[0] + cmd = [ + self.executable, + self.PathJoin('tools', 'swarming_client', 'swarming.py'), + 'run', + '-s', isolated_hash, + '-I', 'isolateserver.appspot.com', + '-S', 'chromium-swarm.appspot.com', + ] + dimensions + if self.args.extra_args: + cmd += ['--'] + self.args.extra_args + ret, _, _ = self.Run(cmd, force_verbose=True, buffer_output=False) + return ret + + def _RunLocallyIsolated(self, build_dir, target): cmd = [ self.executable, self.PathJoin('tools', 'swarming_client', 'isolate.py'), 'run', '-s', self.ToSrcRelPath('%s/%s.isolated' % (build_dir, target)), - ] + ] if self.args.extra_args: - cmd += ['--'] + self.args.extra_args - - ret, _, _ = self.Run(cmd, force_verbose=False, buffer_output=False) - + cmd += ['--'] + self.args.extra_args + ret, _, _ = self.Run(cmd, force_verbose=True, buffer_output=False) return ret + def _DefaultDimensions(self): + if not self.args.default_dimensions: + return [] + + # This code is naive and just picks reasonable defaults per platform. + if self.platform == 'darwin': + os_dim = ('os', 'Mac-10.12') + elif self.platform.startswith('linux'): + os_dim = ('os', 'Ubuntu-14.04') + elif self.platform == 'win32': + os_dim = ('os', 'Windows-10-14393') + else: + raise MBErr('unrecognized platform string "%s"' % self.platform) + + return [('pool', 'Chrome'), + ('cpu', 'x86-64'), + os_dim] + def CmdBuildbucket(self): self.ReadConfigFile() @@ -480,154 +499,26 @@ self.Print('mb config file %s looks ok.' % self.args.config_file) return 0 - def CmdAudit(self): - """Track the progress of the GYP->GN migration on the bots.""" - - # First, make sure the config file is okay, but don't print anything - # if it is (it will throw an error if it isn't). - self.CmdValidate(print_ok=False) - - stats = OrderedDict() - STAT_MASTER_ONLY = 'Master only' - STAT_CONFIG_ONLY = 'Config only' - STAT_TBD = 'Still TBD' - STAT_GYP = 'Still GYP' - STAT_DONE = 'Done (on GN)' - stats[STAT_MASTER_ONLY] = 0 - stats[STAT_CONFIG_ONLY] = 0 - stats[STAT_TBD] = 0 - stats[STAT_GYP] = 0 - stats[STAT_DONE] = 0 - - def PrintBuilders(heading, builders, notes): - stats.setdefault(heading, 0) - stats[heading] += len(builders) - if builders: - self.Print(' %s:' % heading) - for builder in sorted(builders): - self.Print(' %s%s' % (builder, notes[builder])) - - self.ReadConfigFile() - - masters = self.args.master or self.masters - for master in sorted(masters): - url = self.args.url_template.replace('{master}', master) - - self.Print('Auditing %s' % master) - - MASTERS_TO_SKIP = ( - 'client.skia', - 'client.v8.fyi', - 'tryserver.v8', - ) - if master in MASTERS_TO_SKIP: - # Skip these bots because converting them is the responsibility of - # those teams and out of scope for the Chromium migration to GN. - self.Print(' Skipped (out of scope)') - self.Print('') - continue - - INTERNAL_MASTERS = ('official.desktop', 'official.desktop.continuous', - 'internal.client.kitchensync') - if master in INTERNAL_MASTERS and not self.args.internal: - # Skip these because the servers aren't accessible by default ... - self.Print(' Skipped (internal)') - self.Print('') - continue - - try: - # Fetch the /builders contents from the buildbot master. The - # keys of the dict are the builder names themselves. - json_contents = self.Fetch(url) - d = json.loads(json_contents) - except Exception as e: - self.Print(str(e)) - return 1 - - config_builders = set(self.masters[master]) - master_builders = set(d.keys()) - both = master_builders & config_builders - master_only = master_builders - config_builders - config_only = config_builders - master_builders - tbd = set() - gyp = set() - done = set() - notes = {builder: '' for builder in config_builders | master_builders} - - for builder in both: - config = self.masters[master][builder] - if config == 'tbd': - tbd.add(builder) - elif isinstance(config, dict): - vals = self.FlattenConfig(config.values()[0]) - if vals['type'] == 'gyp': - gyp.add(builder) - else: - done.add(builder) - elif config.startswith('//'): - done.add(builder) - else: - vals = self.FlattenConfig(config) - if vals['type'] == 'gyp': - gyp.add(builder) - else: - done.add(builder) - - if self.args.check_compile and (tbd or master_only): - either = tbd | master_only - for builder in either: - notes[builder] = ' (' + self.CheckCompile(master, builder) +')' - - if master_only or config_only or tbd or gyp: - PrintBuilders(STAT_MASTER_ONLY, master_only, notes) - PrintBuilders(STAT_CONFIG_ONLY, config_only, notes) - PrintBuilders(STAT_TBD, tbd, notes) - PrintBuilders(STAT_GYP, gyp, notes) - else: - self.Print(' All GN!') - - stats[STAT_DONE] += len(done) - - self.Print('') - - fmt = '{:<27} {:>4}' - self.Print(fmt.format('Totals', str(sum(int(v) for v in stats.values())))) - self.Print(fmt.format('-' * 27, '----')) - for stat, count in stats.items(): - self.Print(fmt.format(stat, str(count))) - - return 0 - def GetConfig(self): build_dir = self.args.path[0] vals = self.DefaultVals() if self.args.builder or self.args.master or self.args.config: vals = self.Lookup() - if vals['type'] == 'gn': - # Re-run gn gen in order to ensure the config is consistent with the - # build dir. - self.RunGNGen(vals) + # Re-run gn gen in order to ensure the config is consistent with the + # build dir. + self.RunGNGen(vals) return vals - mb_type_path = self.PathJoin(self.ToAbsPath(build_dir), 'mb_type') - if not self.Exists(mb_type_path): - toolchain_path = self.PathJoin(self.ToAbsPath(build_dir), - 'toolchain.ninja') - if not self.Exists(toolchain_path): - self.Print('Must either specify a path to an existing GN build dir ' - 'or pass in a -m/-b pair or a -c flag to specify the ' - 'configuration') - return {} - else: - mb_type = 'gn' - else: - mb_type = self.ReadFile(mb_type_path).strip() + toolchain_path = self.PathJoin(self.ToAbsPath(build_dir), + 'toolchain.ninja') + if not self.Exists(toolchain_path): + self.Print('Must either specify a path to an existing GN build dir ' + 'or pass in a -m/-b pair or a -c flag to specify the ' + 'configuration') + return {} - if mb_type == 'gn': - vals['gn_args'] = self.GNArgsFromDir(build_dir) - vals['type'] = mb_type - + vals['gn_args'] = self.GNArgsFromDir(build_dir) return vals def GNArgsFromDir(self, build_dir): @@ -659,14 +550,6 @@ raise MBErr('Config "%s" not found in %s' % (config, self.args.config_file)) vals = self.FlattenConfig(config) - - # Do some basic sanity checking on the config so that we - # don't have to do this in every caller. - if 'type' not in vals: - vals['type'] = 'gn' - assert vals['type'] in ('gn', 'gyp'), ( - 'Unknown meta-build type "%s"' % vals['gn_args']) - return vals def ReadIOSBotConfig(self): @@ -678,17 +561,10 @@ return {} contents = json.loads(self.ReadFile(path)) - gyp_vals = contents.get('GYP_DEFINES', {}) - if isinstance(gyp_vals, dict): - gyp_defines = ' '.join('%s=%s' % (k, v) for k, v in gyp_vals.items()) - else: - gyp_defines = ' '.join(gyp_vals) gn_args = ' '.join(contents.get('gn_args', [])) vals = self.DefaultVals() vals['gn_args'] = gn_args - vals['gyp_defines'] = gyp_defines - vals['type'] = contents.get('mb_type', 'gn') return vals def ReadConfigFile(self): @@ -707,14 +583,26 @@ self.mixins = contents['mixins'] def ReadIsolateMap(self): - if not self.Exists(self.args.isolate_map_file): - raise MBErr('isolate map file not found at %s' % - self.args.isolate_map_file) - try: - return ast.literal_eval(self.ReadFile(self.args.isolate_map_file)) - except SyntaxError as e: - raise MBErr('Failed to parse isolate map file "%s": %s' % - (self.args.isolate_map_file, e)) + if not self.args.isolate_map_files: + self.args.isolate_map_files = [self.default_isolate_map] + + for f in self.args.isolate_map_files: + if not self.Exists(f): + raise MBErr('isolate map file not found at %s' % f) + isolate_maps = {} + for isolate_map in self.args.isolate_map_files: + try: + isolate_map = ast.literal_eval(self.ReadFile(isolate_map)) + duplicates = set(isolate_map).intersection(isolate_maps) + if duplicates: + raise MBErr( + 'Duplicate targets in isolate map files: %s.' % + ', '.join(duplicates)) + isolate_maps.update(isolate_map) + except SyntaxError as e: + raise MBErr( + 'Failed to parse isolate map file "%s": %s' % (isolate_map, e)) + return isolate_maps def ConfigFromArgs(self): if self.args.config: @@ -765,9 +653,6 @@ 'args_file': '', 'cros_passthrough': False, 'gn_args': '', - 'gyp_defines': '', - 'gyp_crosscompile': False, - 'type': 'gn', } def FlattenMixins(self, mixins, vals, visited): @@ -791,50 +676,11 @@ vals['gn_args'] += ' ' + mixin_vals['gn_args'] else: vals['gn_args'] = mixin_vals['gn_args'] - if 'gyp_crosscompile' in mixin_vals: - vals['gyp_crosscompile'] = mixin_vals['gyp_crosscompile'] - if 'gyp_defines' in mixin_vals: - if vals['gyp_defines']: - vals['gyp_defines'] += ' ' + mixin_vals['gyp_defines'] - else: - vals['gyp_defines'] = mixin_vals['gyp_defines'] - if 'type' in mixin_vals: - vals['type'] = mixin_vals['type'] if 'mixins' in mixin_vals: self.FlattenMixins(mixin_vals['mixins'], vals, visited) return vals - def ClobberIfNeeded(self, vals): - path = self.args.path[0] - build_dir = self.ToAbsPath(path) - mb_type_path = self.PathJoin(build_dir, 'mb_type') - needs_clobber = False - new_mb_type = vals['type'] - if self.Exists(build_dir): - if self.Exists(mb_type_path): - old_mb_type = self.ReadFile(mb_type_path) - if old_mb_type != new_mb_type: - self.Print("Build type mismatch: was %s, will be %s, clobbering %s" % - (old_mb_type, new_mb_type, path)) - needs_clobber = True - else: - # There is no 'mb_type' file in the build directory, so this probably - # means that the prior build(s) were not done through mb, and we - # have no idea if this was a GYP build or a GN build. Clobber it - # to be safe. - self.Print("%s/mb_type missing, clobbering to be safe" % path) - needs_clobber = True - - if self.args.dryrun: - return - - if needs_clobber: - self.RemoveDirectory(build_dir) - - self.MaybeMakeDirectory(build_dir) - self.WriteFile(mb_type_path, new_mb_type) - def RunGNGen(self, vals, compute_grit_inputs_for_analyze=False): build_dir = self.args.path[0] @@ -879,6 +725,7 @@ return ret android = 'target_os="android"' in vals['gn_args'] + fuchsia = 'target_os="fuchsia"' in vals['gn_args'] for target in swarming_targets: if android: # Android targets may be either android_apk or executable. The former @@ -888,6 +735,11 @@ runtime_deps_targets = [ target + '.runtime_deps', 'obj/%s.stamp.runtime_deps' % label.replace(':', '/')] + elif fuchsia: + # Only emit a runtime deps file for the group() target on Fuchsia. + label = isolate_map[target]['label'] + runtime_deps_targets = [ + 'obj/%s.stamp.runtime_deps' % label.replace(':', '/')] elif (isolate_map[target]['type'] == 'script' or isolate_map[target].get('label_type') == 'group'): # For script targets, the build target is usually a group, @@ -1048,38 +900,6 @@ gn_args = ('import("%s")\n' % vals['args_file']) + gn_args return gn_args - def RunGYPGen(self, vals): - path = self.args.path[0] - - output_dir = self.ParseGYPConfigPath(path) - cmd, env = self.GYPCmd(output_dir, vals) - ret, _, _ = self.Run(cmd, env=env) - return ret - - def RunGYPAnalyze(self, vals): - output_dir = self.ParseGYPConfigPath(self.args.path[0]) - if self.args.verbose: - inp = self.ReadInputJSON(['files', 'test_targets', - 'additional_compile_targets']) - self.Print() - self.Print('analyze input:') - self.PrintJSON(inp) - self.Print() - - cmd, env = self.GYPCmd(output_dir, vals) - cmd.extend(['-f', 'analyzer', - '-G', 'config_path=%s' % self.args.input_path[0], - '-G', 'analyzer_output_path=%s' % self.args.output_path[0]]) - ret, _, _ = self.Run(cmd, env=env) - if not ret and self.args.verbose: - outp = json.loads(self.ReadFile(self.args.output_path[0])) - self.Print() - self.Print('analyze output:') - self.PrintJSON(outp) - self.Print() - - return ret - def GetIsolateCommand(self, target, vals): isolate_map = self.ReadIsolateMap() @@ -1106,7 +926,10 @@ executable_suffix = '.exe' if self.platform == 'win32' else '' cmdline = [] - extra_files = [] + extra_files = [ + '../../.vpython', + '../../testing/test_env.py', + ] if test_type == 'nontest': self.WriteFailureAndRaise('We should not be isolating %s.' % target, @@ -1114,17 +937,18 @@ if is_android and test_type != "script": cmdline = [ + '../../testing/test_env.py', '../../build/android/test_wrapper/logdog_wrapper.py', '--target', target, '--logdog-bin-cmd', '../../bin/logdog_butler', '--store-tombstones'] elif is_fuchsia and test_type != 'script': - cmdline = [os.path.join('bin', 'run_%s' % target)] - elif use_xvfb and test_type == 'windowed_test_launcher': - extra_files = [ + cmdline = [ '../../testing/test_env.py', - '../../testing/xvfb.py', + os.path.join('bin', 'run_%s' % target), ] + elif use_xvfb and test_type == 'windowed_test_launcher': + extra_files.append('../../testing/xvfb.py') cmdline = [ '../../testing/xvfb.py', './' + str(executable) + executable_suffix, @@ -1136,9 +960,6 @@ '--cfi-diag=%d' % cfi_diag, ] elif test_type in ('windowed_test_launcher', 'console_test_launcher'): - extra_files = [ - '../../testing/test_env.py' - ] cmdline = [ '../../testing/test_env.py', './' + str(executable) + executable_suffix, @@ -1150,15 +971,11 @@ '--cfi-diag=%d' % cfi_diag, ] elif test_type == 'script': - extra_files = [ - '../../testing/test_env.py' - ] cmdline = [ '../../testing/test_env.py', '../../' + self.ToSrcRelPath(isolate_map[target]['script']) ] elif test_type in ('raw'): - extra_files = [] cmdline = [ './' + str(target) + executable_suffix, ] @@ -1182,86 +999,6 @@ return path[2:].replace('/', self.sep) return self.RelPath(path, self.chromium_src_dir) - def ParseGYPConfigPath(self, path): - rpath = self.ToSrcRelPath(path) - output_dir, _, _ = rpath.rpartition(self.sep) - return output_dir - - def GYPCmd(self, output_dir, vals): - if vals['cros_passthrough']: - if not 'GYP_DEFINES' in os.environ: - raise MBErr('MB is expecting GYP_DEFINES to be in the environment') - gyp_defines = os.environ['GYP_DEFINES'] - if not 'chromeos=1' in gyp_defines: - raise MBErr('GYP_DEFINES is missing chromeos=1: (GYP_DEFINES=%s)' % - gyp_defines) - else: - gyp_defines = vals['gyp_defines'] - - goma_dir = self.args.goma_dir - - # GYP uses shlex.split() to split the gyp defines into separate arguments, - # so we can support backslashes and and spaces in arguments by quoting - # them, even on Windows, where this normally wouldn't work. - if goma_dir and ('\\' in goma_dir or ' ' in goma_dir): - goma_dir = "'%s'" % goma_dir - - if goma_dir: - gyp_defines += ' gomadir=%s' % goma_dir - - android_version_code = self.args.android_version_code - if android_version_code: - gyp_defines += ' app_manifest_version_code=%s' % android_version_code - - android_version_name = self.args.android_version_name - if android_version_name: - gyp_defines += ' app_manifest_version_name=%s' % android_version_name - - cmd = [ - self.executable, - self.args.gyp_script, - '-G', - 'output_dir=' + output_dir, - ] - - # Ensure that we have an environment that only contains - # the exact values of the GYP variables we need. - env = os.environ.copy() - - # This is a terrible hack to work around the fact that - # //tools/clang/scripts/update.py is invoked by GYP and GN but - # currently relies on an environment variable to figure out - # what revision to embed in the command line #defines. - # For GN, we've made this work via a gn arg that will cause update.py - # to get an additional command line arg, but getting that to work - # via GYP_DEFINES has proven difficult, so we rewrite the GYP_DEFINES - # to get rid of the arg and add the old var in, instead. - # See crbug.com/582737 for more on this. This can hopefully all - # go away with GYP. - m = re.search('llvm_force_head_revision=1\s*', gyp_defines) - if m: - env['LLVM_FORCE_HEAD_REVISION'] = '1' - gyp_defines = gyp_defines.replace(m.group(0), '') - - # This is another terrible hack to work around the fact that - # GYP sets the link concurrency to use via the GYP_LINK_CONCURRENCY - # environment variable, and not via a proper GYP_DEFINE. See - # crbug.com/611491 for more on this. - m = re.search('gyp_link_concurrency=(\d+)(\s*)', gyp_defines) - if m: - env['GYP_LINK_CONCURRENCY'] = m.group(1) - gyp_defines = gyp_defines.replace(m.group(0), '') - - env['GYP_GENERATORS'] = 'ninja' - if 'GYP_CHROMIUM_NO_ACTION' in env: - del env['GYP_CHROMIUM_NO_ACTION'] - if 'GYP_CROSSCOMPILE' in env: - del env['GYP_CROSSCOMPILE'] - env['GYP_DEFINES'] = gyp_defines - if vals['gyp_crosscompile']: - env['GYP_CROSSCOMPILE'] = '1' - return cmd, env - def RunGNAnalyze(self, vals): # Analyze runs before 'gn gen' now, so we need to run gn gen # in order to ensure that we have a build directory. @@ -1336,11 +1073,46 @@ if 'invalid_targets' in gn_outp: outp['invalid_targets'] = gn_outp['invalid_targets'] if 'compile_targets' in gn_outp: + all_input_compile_targets = sorted( + set(inp['test_targets'] + inp['additional_compile_targets'])) + + # If we're building 'all', we can throw away the rest of the targets + # since they're redundant. if 'all' in gn_outp['compile_targets']: outp['compile_targets'] = ['all'] else: + outp['compile_targets'] = gn_outp['compile_targets'] + + # crbug.com/736215: When GN returns targets back, for targets in + # the default toolchain, GN will have generated a phony ninja + # target matching the label, and so we can safely (and easily) + # transform any GN label into the matching ninja target. For + # targets in other toolchains, though, GN doesn't generate the + # phony targets, and we don't know how to turn the labels into + # compile targets. In this case, we also conservatively give up + # and build everything. Probably the right thing to do here is + # to have GN return the compile targets directly. + if any("(" in target for target in outp['compile_targets']): + self.Print('WARNING: targets with non-default toolchains were ' + 'found, building everything instead.') + outp['compile_targets'] = all_input_compile_targets + else: outp['compile_targets'] = [ - label.replace('//', '') for label in gn_outp['compile_targets']] + label.replace('//', '') for label in outp['compile_targets']] + + # Windows has a maximum command line length of 8k; even Linux + # maxes out at 128k; if analyze returns a *really long* list of + # targets, we just give up and conservatively build everything instead. + # Probably the right thing here is for ninja to support response + # files as input on the command line + # (see https://github.com/ninja-build/ninja/issues/1355). + if len(' '.join(outp['compile_targets'])) > 7*1024: + self.Print('WARNING: Too many compile targets were affected.') + self.Print('WARNING: Building everything instead to avoid ' + 'command-line length issues.') + outp['compile_targets'] = all_input_compile_targets + + if 'test_targets' in gn_outp: outp['test_targets'] = [ labels_to_targets[label] for label in gn_outp['test_targets']] @@ -1428,9 +1200,6 @@ if env and var in env: self.Print('%s%s=%s' % (env_prefix, var, env_quoter(env[var]))) - print_env('GYP_CROSSCOMPILE') - print_env('GYP_DEFINES') - print_env('GYP_LINK_CONCURRENCY') print_env('LLVM_FORCE_HEAD_REVISION') if cmd[0] == self.executable: @@ -1567,7 +1336,6 @@ def QuoteForCmd(arg): # First, escape the arg so that CommandLineToArgvW will parse it properly. - # From //tools/gyp/pylib/gyp/msvs_emulation.py:23. if arg == '' or ' ' in arg or '"' in arg: quote_re = re.compile(r'(\\*)"') arg = '"%s"' % (quote_re.sub(lambda mo: 2 * mo.group(1) + '\\"', arg))
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index 1578278..2f9b8b6 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -32,9 +32,9 @@ }, 'chromium.android': { + 'Android ASAN (dbg)': 'android_clang_asan_debug_bot_minimal_symbols', 'Android Cronet ARM64 Builder': 'android_cronet_release_bot_minimal_symbols_arm64', 'Android Cronet ARM64 Builder (dbg)': 'android_cronet_debug_static_bot_arm64', - 'Android Cronet ARMv6 Builder': 'android_cronet_release_bot_minimal_symbols_armv6', 'Android Cronet Builder': 'android_cronet_release_bot_minimal_symbols_arm_no_neon', 'Android Cronet Builder (dbg)': 'android_cronet_debug_static_bot_arm_no_neon', 'Android Cronet Builder Asan': 'android_cronet_release_bot_minimal_symbols_arm_no_neon_clang_asan', @@ -43,7 +43,6 @@ 'Android Cronet Lollipop Builder': 'android_cronet_release_bot_minimal_symbols_arm_no_neon', 'Android Cronet Marshmallow 64bit Builder': 'android_cronet_release_bot_minimal_symbols_arm64', 'Android Cronet Marshmallow 64bit Perf': 'android_cronet_release_bot_minimal_symbols_arm64', - 'Android Cronet MIPS Builder': 'android_cronet_release_bot_minimal_symbols_mipsel', 'Android Cronet x86 Builder': 'android_cronet_release_bot_minimal_symbols_x86', 'Android Cronet x86 Builder (dbg)': 'android_cronet_debug_static_bot_x86', 'Android MIPS Builder (dbg)': 'android_debug_static_bot_mipsel', @@ -52,10 +51,12 @@ 'Android arm64 Builder (dbg)': 'android_debug_static_bot_arm64', 'Android x64 Builder (dbg)': 'android_debug_static_bot_x64', 'Android x86 Builder (dbg)': 'android_debug_static_bot_x86', + 'Cast Android (dbg)': 'android_cast_debug_static_bot', + 'KitKat Phone Tester (rel)': 'android_release_bot_minimal_symbols', + 'Marshmallow Phone Tester (rel)': 'android_release_bot_minimal_symbols_arm64', }, 'chromium.android.fyi': { - 'Android Cronet ARMv6 Builder': 'android_cronet_release_bot_minimal_symbols_armv6', 'Android Cronet Builder (dbg)': 'android_cronet_debug_static_bot_arm_no_neon', 'Android Cronet Builder Asan': 'android_cronet_release_bot_minimal_symbols_arm_no_neon_clang_asan', 'Android Cronet Data Reduction Proxy Builder': 'android_cronet_data_reduction_proxy_release_bot_minimal_symbols_arm_no_neon', @@ -96,34 +97,95 @@ 'Linux ChromiumOS Builder': 'chromeos_with_codecs_release_bot', 'Linux ChromiumOS Builder (dbg)': 'chromeos_with_codecs_debug_bot', 'Linux ChromiumOS Full': 'chromeos_with_codecs_release_bot', + + 'chromeos-amd64-generic-rel': 'cros_chrome_sdk', + 'chromeos-daisy-rel': 'cros_chrome_sdk', + 'linux-chromeos-rel': 'chromeos_with_codecs_release_bot', + 'linux-chromeos-dbg': 'chromeos_with_codecs_debug_bot', + }, + + 'chromium.clang': { + 'CFI Linux CF': 'cfi_full_cfi_diag_recover_release_static', + 'CFI Linux ToT': 'clang_tot_cfi_full_cfi_diag_thin_lto_release_static_dcheck_always_on', + 'CFI Linux (icall)': 'cfi_full_diag_icall_release_static_dcheck_always_on', + 'CrWinAsan': 'asan_clang_fuzzer_static_v8_heap_x86_full_symbols_release', + 'CrWinAsan(dll)': 'asan_clang_shared_v8_heap_x86_full_symbols_release', + 'CrWinAsanCov': 'asan_clang_edge_fuzzer_static_v8_heap_x86_full_symbols_release', + + # TODO(crbug.com/751220): These are MSVC bots. Rename the buildbots at + # some point. + 'CrWinClang': 'win_msvc_release_bot_x86', + 'CrWinClang(dbg)': 'win_msvc_debug_bot_x86', + 'CrWinClang(shared)': 'win_msvc_shared_release_bot_x86', + 'CrWinClang64': 'win_msvc_release_bot', + 'CrWinClang64(dbg)': 'win_msvc_debug_bot', + 'CrWinClang64(dll)': 'win_msvc_shared_release_bot', + + 'CrWinClangLLD': 'clang_tot_official_static_use_lld_x86', + 'CrWinClangLLD64': 'clang_tot_shared_release_use_lld_dcheck', + 'CrWinClngLLD64dbg': 'clang_tot_full_symbols_shared_debug_use_lld', + 'CrWinClngLLDdbg': 'clang_tot_full_symbols_shared_debug_use_lld_x86', + 'ToTAndroid': 'android_clang_tot_release', + 'ToTAndroid64': 'android_clang_tot_release_arm64', + 'ToTAndroidASan': 'android_clang_tot_asan', + 'ToTAndroid (dbg)': 'android_clang_tot_dbg', + 'ToTAndroid': 'android_clang_tot_release', + 'ToTAndroidCFI': 'android_clang_tot_cfi_full_cfi_diag_thin_lto_release_static_dcheck_always_on', + 'ToTAndroid64': 'android_clang_tot_release_arm64', + 'ToTAndroid x64': 'android_clang_tot_x64', + 'ToTLinux': 'clang_tot_linux_full_symbols_shared_release', + 'ToTLinux (dbg)': 'clang_tot_shared_debug', + 'ToTLinuxASan': 'clang_tot_asan_lsan_static_release', + 'ToTLinuxASanLibfuzzer': 'release_libfuzzer_asan_clang_tot', + 'ToTLinuxMSan': 'clang_tot_msan_release', + 'ToTLinuxThinLTO': 'clang_tot_release_minimal_symbols_thin_lto_static_use_lld', + 'ToTLinuxUBSanVptr': 'clang_tot_edge_ubsan_no_recover_hack_static_release', + 'ToTMac': 'clang_tot_minimal_symbols_shared_release', + 'ToTMac (dbg)': 'clang_tot_shared_debug', + 'ToTMacASan': 'asan_disable_nacl_clang_tot_full_symbols_static_release', + 'ToTWin': 'clang_tot_official_minimal_symbols_static_release_x86', + 'ToTWin(dbg)': 'clang_tot_shared_debug_x86', + 'ToTWin(dll)': 'clang_tot_minimal_symbols_shared_release_x86_dcheck', + 'ToTWin64': 'clang_tot_official_minimal_symbols_static_release', + 'ToTWin64(dbg)': 'clang_tot_shared_debug', + 'ToTWin64(dll)': 'clang_tot_shared_release_dcheck', + 'ToTWinCFI': 'clang_tot_cfi_full_cfi_diag_thin_lto_release_static_dcheck_always_on_x86', + 'ToTWinCFI64': 'clang_tot_cfi_full_cfi_diag_thin_lto_release_static_dcheck_always_on', + 'ToTWinThinLTO64': 'clang_tot_official_full_symbols_thin_lto_static_use_lld', + 'ToTiOS': 'ios', + 'UBSanVptr Linux': 'ubsan_vptr_release_bot', }, 'chromium.fyi': { 'Afl Upload Linux ASan': 'release_afl_asan', 'Android Builder (dbg)': 'android_debug_static_bot_vrdata', - 'Android Builder Goma Canary (dbg)': 'android_debug_bot', + + 'Android Builder (dbg) Goma Canary': 'android_debug_static_bot_vrdata', + 'Android deterministic': 'android_without_codecs_release_bot_minimal_symbols', 'Android deterministic (dbg)': 'android_debug_bot', 'Browser Side Navigation Linux': 'release_bot', 'CFI Linux CF': 'cfi_full_cfi_diag_recover_release_static', 'CFI Linux ToT': 'clang_tot_cfi_full_cfi_diag_thin_lto_release_static_dcheck_always_on', - 'CFI Linux (icall)': 'cfi_full_diag_recover_icall_release_static', - 'ChromeOS amd64 Chromium Goma Canary': 'cros_chrome_sdk', - 'Chromium Linux Goma Canary': 'release_bot', - 'Chromium Linux Goma Canary': 'release_bot', - 'Chromium Linux Goma Canary (clobber)': 'release_bot', - 'Chromium Linux Goma Canary LocalOutputCache': 'release_bot', - 'Chromium Linux Precise Goma LinkTest': 'release_bot', - 'Chromium Linux32 Goma Canary (clobber)': 'release_bot_x86', + 'CFI Linux (icall)': 'cfi_full_diag_icall_release_static_dcheck_always_on', + 'chromeos-amd64-generic-rel-goma-canary': 'cros_chrome_sdk', + + 'Linux Builder Goma Canary': 'release_bot', + 'Linux x64 Goma Canary (clobber)': 'release_bot', + 'Linux x64 Goma Canary LocalOutputCache': 'release_bot', + 'linux-gcc-rel': 'release_bot_x86_minimal_symbols_no_clang', + 'Chromium Mac 10.10 MacViews': 'mac_views_browser_release_bot', 'Chromium Mac 10.11': 'release_bot', 'Chromium Mac 10.11 Force Mac Toolchain': 'release_bot_mac_new_sdk', 'Chromium Mac 10.13': 'release_bot', - 'Chromium Mac 10.9 Goma Canary': 'release_bot', - 'Chromium Mac 10.9 Goma Canary (clobber)': 'release_bot', - 'Chromium Mac 10.9 Goma Canary (dbg)': 'debug_bot', - 'Chromium Mac 10.9 Goma Canary (dbg)(clobber)': 'debug_bot', - 'Chromium Mac Goma Canary LocalOutputCache': 'release_bot', + + 'Mac Builder Goma Canary': 'gpu_tests_release_bot', + 'Mac Goma Canary (clobber)': 'release_bot_mac_strip', + 'Mac Builder (dbg) Goma Canary': 'debug_bot', + 'Mac Builder (dbg) Goma Canary (clobber)': 'debug_bot', + 'Mac Goma Canary LocalOutputCache': 'release_bot_mac_strip', + 'Chromium Win 10 GCE Tests': 'release_bot_minimal_symbols', 'Chromium Win PGO Builder': { '1': 'official_optimize_chrome_pgo_phase_1_x86', @@ -134,66 +196,28 @@ '2': 'official_optimize_chrome_pgo_phase_2', }, 'Chromium Windows Analyze': 'windows_analyze', - 'CrWin7Goma': 'release_bot_x86_minimal_symbols', - 'CrWin7Goma(clbr)': 'shared_release_bot_x86', - 'CrWin7Goma(dbg)': 'debug_bot_x86_minimal_symbols', - 'CrWin7Goma(dll)': 'shared_release_bot_x86', - # if CrWinClang is modified, please update CrWinClangGoma in the same way. - 'CrWinClang': 'clang_official_release_bot_minimal_symbols_x86', + 'Win7 Builder Goma Canary': 'release_bot_x86_minimal_symbols', + 'Win7 Builder (dbg) Goma Canary': 'debug_trybot_x86_minimal_symbols', + 'Win cl.exe Goma Canary LocalOutputCache': 'release_bot_x86_minimal_symbols_no_clang', + 'Win Builder Goma Canary': 'release_bot_x86_minimal_symbols', + 'Win Builder (dbg) Goma Canary': 'debug_bot_x86_minimal_symbols', + 'Win Goma Canary LocalOutputCache': 'release_bot_x86_minimal_symbols', + 'WinMSVC64 Goma Canary': 'win_msvc_release_bot', - 'CrWinClang(dbg)': 'clang_debug_bot_minimal_symbols_x86', - 'CrWinClang64': 'clang_official_release_bot_minimal_symbols', - 'CrWinClang64(dll)': 'clang_shared_release_bot_dcheck', - 'CrWinClangGoma': 'clang_official_optimize_release_bot_minimal_symbols_x86', - 'CrWinGoma': 'release_bot_x86_minimal_symbols', - 'CrWinGoma(dll)': 'shared_release_bot_x86', - 'CrWinGoma(loc)': 'shared_release_bot_x86', - 'ClangToTAndroidASan': 'android_clang_tot_asan', - 'ClangToTAndroid (dbg)': 'android_clang_tot_dbg', - 'ClangToTAndroid': 'android_clang_tot_release', - 'ClangToTAndroid64': 'android_clang_tot_release_arm64', - 'ClangToTAndroid x64': 'android_clang_tot_x64', - 'ClangToTLinux': 'clang_tot_linux_full_symbols_shared_release', - 'ClangToTLinux (dbg)': 'clang_tot_shared_debug', - 'ClangToTLinuxASan': 'clang_tot_asan_lsan_static_release', - 'ClangToTLinuxASanLibfuzzer': 'release_libfuzzer_asan_clang_tot', - 'ClangToTLinuxMSan': 'clang_tot_msan_release_bot', - 'ClangToTLinuxLLD': 'clang_tot_lld_release_shared', - 'ClangToTLinuxThinLTO': 'clang_tot_release_full_symbols_thin_lto_static_use_lld', - 'ClangToTLinuxUBSanVptr': 'clang_tot_edge_ubsan_no_recover_hack_static_release', - 'ClangToTMac': 'clang_tot_minimal_symbols_shared_release', - 'ClangToTMac (dbg)': 'clang_tot_shared_debug', - 'ClangToTMacASan': 'asan_disable_nacl_clang_tot_full_symbols_static_release', - 'ClangToTWin': 'clang_tot_official_minimal_symbols_static_release_x86', - 'ClangToTWin(dbg)': 'clang_tot_shared_debug_x86', - 'ClangToTWin(dll)': 'clang_tot_minimal_symbols_shared_release_x86_dcheck', - 'ClangToTWin64': 'clang_tot_official_minimal_symbols_static_release', - 'ClangToTWin64(dbg)': 'clang_tot_shared_debug', - 'ClangToTWin64(dll)': 'clang_tot_shared_release_dcheck', - 'ClangToTWinCFI': 'clang_tot_cfi_full_cfi_diag_thin_lto_release_static_dcheck_always_on_x86', - 'ClangToTWinCFI64': 'clang_tot_cfi_full_cfi_diag_thin_lto_release_static_dcheck_always_on', - 'ClangToTWinThinLTO64': 'clang_tot_official_full_symbols_thin_lto_static_use_lld', - 'ClangToTiOS': 'ios', - 'Closure Compilation Linux': 'closure_compilation', - 'CrWinAsan': 'asan_clang_fuzzer_static_v8_heap_x86_full_symbols_release', - 'CrWinAsan(dll)': 'asan_clang_shared_v8_heap_x86_full_symbols_release', - 'CrWinAsanCov': 'asan_clang_edge_fuzzer_static_v8_heap_x86_full_symbols_release', - 'CrWinClang(shared)': 'clang_minimal_symbols_shared_release_bot_x86_dcheck', - 'CrWinClang64(dbg)': 'win_clang_debug_bot', - 'CrWinClangLLD': 'clang_tot_official_static_use_lld_x86', - 'CrWinClangLLD64': 'clang_tot_shared_release_use_lld_dcheck', - 'CrWinClngLLD64dbg': 'clang_tot_full_symbols_shared_debug_use_lld', - 'CrWinClngLLDdbg': 'clang_tot_full_symbols_shared_debug_use_lld_x86', 'EarlGreyiOS': 'ios', - 'Fuchsia': 'release_bot_fuchsia', 'Fuchsia (dbg)': 'debug_bot_fuchsia', - 'GomaCanaryiOS': 'ios', + 'Fuchsia ARM64': 'release_bot_fuchsia_arm64', + 'Fuchsia x64': 'release_bot_fuchsia', + 'Fuchsia': 'release_bot_fuchsia', + + 'ios-device-goma-canary-clobber': 'ios', + 'ios-simulator': 'ios', 'Headless Linux (dbg)': 'headless_linux_debug_bot', - 'Jumbo Linux x64': 'jumbo_release_bot', - 'Jumbo Mac': 'jumbo_release_bot', - 'Jumbo Win x64': 'jumbo_release_bot', + 'Jumbo Linux x64': 'jumbo_large_chunks_release_bot_minimal_symbols', + 'Jumbo Mac': 'jumbo_release_bot_minimal_symbols', + 'Jumbo Win x64': 'jumbo_release_bot_minimal_symbols', 'MD Top Chrome ChromeOS material-hybrid': 'chromeos_with_codecs_debug_bot', 'MD Top Chrome ChromeOS non-material': 'chromeos_with_codecs_debug_bot', 'MD Top Chrome Win material': 'debug_bot_minimal_symbols', @@ -212,12 +236,14 @@ 'Linux deterministic (dbg)': 'debug_bot', 'Linux remote_run Builder': 'release_bot', 'Linux remote_run Tester': 'release_bot', + 'Linux Viz': 'release_trybot', + 'Linux Xenial': 'release_bot', 'Mac deterministic': 'release_bot_mac_strip', 'Mac deterministic (dbg)': 'debug_bot', 'Mojo ChromiumOS': 'chromeos_with_codecs_release_trybot', + 'Mojo Android': 'android_release_bot_minimal_symbols_arm64', 'Mojo Linux': 'release_trybot', 'Mojo Windows': 'release_bot_x86_minimal_symbols', - 'Ozone Linux': 'ozone_linux_release_bot', 'Out of Process Profiling Android': 'android_release_bot_minimal_symbols', 'Out of Process Profiling Linux': 'release_bot', 'Out of Process Profiling Mac': 'release_bot', @@ -225,11 +251,7 @@ 'Site Isolation Android': 'android_release_bot_minimal_symbols_arm64', 'Site Isolation Linux': 'release_trybot', 'Site Isolation Win': 'release_trybot_x86', - 'ThinLTO Linux ToT': 'thin_lto_clang_tot_full_symbols_release_static_use_lld', - 'UBSanVptr Linux': 'ubsan_vptr_release_bot', - 'WebKit Linux - RandomOrder': 'release_trybot', - 'WebKit Mac - RandomOrder': 'release_trybot', - 'WebKit Win - RandomOrder': 'release_bot_x86_minimal_symbols', + 'VR Linux': 'vr_release_bot', 'Win 10 Fast Ring': 'release_trybot', 'Windows deterministic': 'release_bot_x86_minimal_symbols', 'Windows Clang deterministic': 'clang_release_bot_minimal_symbols_x86', @@ -242,8 +264,8 @@ 'CrWinGomaStaging': 'release_bot_x86_minimal_symbols', 'Chromium Linux Goma GCE Staging': 'release_bot', 'Chromium Mac Goma GCE Staging': 'release_bot', - 'CrWinGomaGCEStaging': 'release_bot_x86_minimal_symbols', - 'CrWinClangGomaGCEStaging': 'win_clang_release_bot', + 'CrWinClexeGomaGCEStaging': 'release_bot_x86_minimal_symbols_disable_nacl_no_clang', + 'CrWinClangGomaGCEStaging': 'win_clang_release_bot_disable_nacl', }, 'chromium.gpu': { @@ -254,9 +276,11 @@ 'GPU Linux Builder (dbg)': 'gpu_tests_debug_trybot', 'GPU Win Builder': 'gpu_tests_release_trybot_x86_minimal_symbols', 'GPU Win Builder (dbg)': 'gpu_tests_debug_trybot_x86_minimal_symbols', + 'Android Release (Nexus 5X)': 'gpu_tests_android_release_trybot_arm64', }, 'chromium.gpu.fyi': { + # TODO(kbr): remove old names. crbug.com/792780 # These all use the 'trybot' mixins to ensure that dcheck is on. 'Android dEQP Release (Nexus 5X)': 'deqp_android_release_trybot_arm64', 'Android Release (Nexus 5)': 'android_release_trybot', @@ -281,6 +305,30 @@ 'GPU Win x64 dEQP Builder': 'deqp_release_no_clang_trybot', 'Linux GPU TSAN Release': 'gpu_fyi_tests_release_trybot_tsan', 'Mac GPU ASAN Release': 'gpu_fyi_tests_release_trybot_asan', + + 'Android FYI dEQP Release (Nexus 5X)': 'deqp_android_release_trybot_arm64', + 'Android FYI Release (Nexus 5)': 'android_release_trybot', + 'Android FYI Release (Nexus 5X)': 'gpu_tests_android_release_trybot_arm64', + 'Android FYI Release (Nexus 6)': 'android_release_trybot', + 'Android FYI Release (Nexus 6P)': 'android_release_trybot_arm64', + 'Android FYI Release (Nexus 9)': 'android_release_trybot_arm64', + 'Android FYI Release (NVIDIA Shield TV)': 'android_release_trybot_arm64', + 'GPU FYI Linux Builder': 'gpu_fyi_tests_release_trybot', + 'GPU FYI Linux Ozone Builder': 'gpu_fyi_tests_ozone_linux_system_gbm_libdrm_release_trybot', + 'GPU FYI Linux Builder (dbg)': 'gpu_fyi_tests_debug_trybot', + 'GPU FYI Linux dEQP Builder': 'deqp_release_trybot', + 'GPU FYI Mac Builder': 'gpu_fyi_tests_release_trybot', + 'GPU FYI Mac Builder (dbg)': 'gpu_fyi_tests_debug_trybot', + 'GPU FYI Mac dEQP Builder': 'deqp_release_trybot', + 'GPU FYI Win Builder': 'gpu_fyi_tests_release_trybot_x86', + 'GPU FYI Win Builder (dbg)': 'gpu_fyi_tests_debug_trybot_x86', + 'GPU FYI Win dEQP Builder': 'deqp_release_no_clang_trybot_x86', + 'GPU FYI Win Clang Builder (dbg)': 'gpu_fyi_tests_win_clang_debug_bot', + 'GPU FYI Win x64 Builder': 'gpu_fyi_tests_release_trybot', + 'GPU FYI Win x64 Builder (dbg)': 'gpu_fyi_tests_debug_trybot', + 'GPU FYI Win x64 dEQP Builder': 'deqp_release_no_clang_trybot', + 'Linux FYI GPU TSAN Release': 'gpu_fyi_tests_release_trybot_tsan', + 'Mac FYI GPU ASAN Release': 'gpu_fyi_tests_release_trybot_asan', }, 'chromium.infra.codesearch': { @@ -300,17 +348,22 @@ 'Android Arm64 Builder (dbg)': 'android_debug_static_bot_arm64', 'Android Builder (dbg)': 'android_debug_static_bot', 'Android Builder': 'android_release_bot_minimal_symbols', - 'Android Clang Builder (dbg)': 'android_clang_asan_errorprone_findbugs_debug_bot_minimal_symbols', + 'Android Clang Builder (dbg)': 'android_clang_asan_debug_bot_minimal_symbols', 'Android Tests (dbg)': 'android_debug_static_bot', 'Android Tests': 'android_release_bot_minimal_symbols', 'Cast Android (dbg)': 'android_cast_debug_static_bot', 'Cast Linux': 'cast_release_bot', 'Cast Audio Linux': 'cast_audio_release_bot', + 'Leak Detection Linux': 'release_bot', 'Linux Builder (dbg)': 'debug_bot', 'Linux Builder (dbg)(32)': 'debug_bot_x86', 'Linux Builder': 'release_bot', 'Deterministic Linux': 'release_bot', - 'Fuchsia Compile': 'release_bot_fuchsia', + 'Fuchsia ARM64 Cast Audio': 'release_bot_fuchsia_arm64_cast_audio', + 'Fuchsia ARM64': 'release_bot_fuchsia_arm64', + 'Fuchsia x64 Cast Audio': 'release_bot_fuchsia_cast_audio', + 'Fuchsia x64': 'release_bot_fuchsia', + 'Ozone Linux': 'ozone_linux_release_bot', }, 'chromium.lkgr': { @@ -330,9 +383,8 @@ 'TSAN Release': 'tsan_disable_nacl_release_bot', 'UBSan Release': 'ubsan_release_bot', 'UBSan vptr Release': 'ubsan_vptr_edge_release_bot', - 'Win ASan Release Coverage': 'asan_edge_fuzzer_v8_heap_release_bot_x86', 'Win ASan Release Media': 'asan_fuzzer_v8_heap_chrome_with_codecs_release_bot_x86', - 'Win ASan Release': 'asan_fuzzer_v8_heap_release_bot_x86', + 'Win ASan Release': 'asan_fuzzer_v8_heap_release_bot', 'Win SyzyASAN LKGR': 'syzyasan_no_pch_release_x86', }, @@ -343,7 +395,7 @@ 'ios-device-xcode-clang': 'ios', 'ios-simulator': 'ios', 'ios-simulator-cronet': 'ios', - 'ios-simulator-eg': 'ios', + 'ios-simulator-full-configs': 'ios', 'ios-simulator-xcode-clang': 'ios', }, @@ -369,13 +421,12 @@ }, 'chromium.perf.fyi': { + 'Linux Compile FYI': 'official_goma_perf', 'Android Builder FYI': 'official_goma_minimal_symbols_android', 'Android arm64 Builder FYI': 'official_goma_minimal_symbols_android_arm64', - 'Win Builder FYI': 'official_goma', - 'Win Clang Builder': 'official_goma_minimal_symbols_clang', - 'Battor Agent Linux': 'official_goma_minimal_symbols_clang', - 'Battor Agent Mac': 'official_goma_minimal_symbols_clang', - 'Battor Agent Win': 'official_goma_minimal_symbols_clang', + 'Battor Agent Linux': 'release_bot', + 'Battor Agent Mac': 'release_bot', + 'Battor Agent Win': 'release_bot', }, 'chromium.swarm': { @@ -403,14 +454,19 @@ }, 'client.v8.fyi': { + # TODO(kbr): remove old names. crbug.com/792780 'Android Builder': 'official_goma_minimal_symbols_android', 'Android Release (Nexus 5X)': 'gpu_tests_android_release_trybot_arm64', + 'Android V8 FYI Release (Nexus 5X)': 'gpu_tests_android_release_trybot_arm64', 'Linux ASAN Builder': 'asan_lsan_release_bot', 'Linux Debug Builder': 'debug_bot', 'Linux Release (NVIDIA)': 'gpu_tests_release_trybot', + 'Linux V8 FYI Release (NVIDIA)': 'gpu_tests_release_trybot', 'Linux Release - concurrent marking (NVIDIA)': 'gpu_tests_release_trybot_cm', + 'Linux V8 FYI Release - concurrent marking (NVIDIA)': 'gpu_tests_release_trybot_cm', 'Linux Snapshot Builder': 'release_bot', 'Mac Release (Intel)': 'gpu_tests_release_trybot', + 'Mac V8 FYI Release (Intel)': 'gpu_tests_release_trybot', 'V8 Android GN (dbg)': 'android_debug_bot', 'V8 Linux GN': 'release_bot', 'V8-Blink Linux 64': 'release_bot', @@ -419,6 +475,7 @@ 'V8-Blink Mac': 'release_bot', 'V8-Blink Win': 'release_bot_x86_minimal_symbols', 'Win Release (NVIDIA)': 'gpu_tests_release_trybot_x86_minimal_symbols', + 'Win V8 FYI Release (NVIDIA)': 'gpu_tests_release_trybot_x86_minimal_symbols', }, 'chromium.webkit': { @@ -432,7 +489,6 @@ 'WebKit Mac Builder': 'release_bot', 'WebKit Mac10.11 (retina)': 'release_bot', 'WebKit Mac10.12': 'release_bot', - 'WebKit Mac10.9': 'release_bot', 'WebKit Win Builder (dbg)': 'debug_bot_x86_minimal_symbols', 'WebKit Win Builder': 'release_bot_x86_minimal_symbols', 'WebKit Win x64 Builder (dbg)': 'debug_bot_minimal_symbols', @@ -442,7 +498,7 @@ 'chromium.webrtc': { 'Linux Builder': 'release_bot_chrome_with_codecs', 'Mac Builder': 'release_bot_chrome_with_codecs', - 'Win Builder': 'release_bot_x86_minimal_symbols', + 'Win Builder': 'release_bot_x86_minimal_symbols_no_com_init_hooks', }, 'chromium.webrtc.fyi': { @@ -453,8 +509,8 @@ 'Linux Builder (dbg)': 'debug_bot', 'Mac Builder': 'release_bot_chrome_with_codecs', 'Mac Builder (dbg)': 'debug_bot', - 'Win Builder': 'release_bot_x86_minimal_symbols', - 'Win Builder (dbg)': 'debug_bot_x86_minimal_symbols', + 'Win Builder': 'release_bot_x86_minimal_symbols_no_com_init_hooks', + 'Win Builder (dbg)': 'debug_bot_x86_minimal_symbols_no_com_init_hooks', }, 'chromium.win': { @@ -463,7 +519,11 @@ 'Win Builder (dbg)': 'debug_bot_x86_minimal_symbols', 'Win x64 Builder': 'release_bot_minimal_symbols', 'Win x64 Builder (dbg)': 'debug_bot_minimal_symbols', + # TODO(thakis): Remove this once WinMSVC64 bots are live (the bots with + # unqualified names now use clang). 'WinClang64 (dbg)': 'win_clang_release_bot', + 'WinMSVC64': 'win_msvc_release_bot_compile_only', + 'WinMSVC64 (dbg)': 'win_msvc_debug_bot_compile_only', }, 'internal.client.kitchensync': { @@ -490,14 +550,11 @@ 'linux_trusty_blink_compile_rel': 'release_bot_minimal_symbols', 'linux_trusty_blink_dbg': 'debug_trybot', 'linux_trusty_blink_rel': 'release_bot_minimal_symbols', - 'mac10.9_blink_compile_dbg': 'debug_trybot', - 'mac10.9_blink_compile_rel': 'release_bot_minimal_symbols', - 'mac10.9_blink_dbg': 'debug_trybot', - 'mac10.9_blink_rel': 'release_bot_minimal_symbols', 'mac10.10_blink_rel': 'release_bot_minimal_symbols', 'mac10.11_blink_rel': 'release_bot_minimal_symbols', 'mac10.11_retina_blink_rel': 'release_bot_minimal_symbols', 'mac10.12_blink_rel': 'release_bot_minimal_symbols', + 'mac10.13_blink_rel': 'release_bot_minimal_symbols', 'win7_blink_compile_dbg': 'debug_trybot_x86_minimal_symbols', 'win7_blink_compile_rel': 'release_bot_x86_minimal_symbols', 'win7_blink_dbg': 'debug_trybot_x86_minimal_symbols', @@ -507,14 +564,13 @@ 'tryserver.chromium.android': { 'android_archive_rel_ng': 'android_release_trybot', - 'android_arm64_dbg_recipe': 'android_debug_trybot_arm64', + 'android_arm64_dbg_recipe': 'android_debug_trybot_compile_only_arm64', 'android_blink_rel': 'android_release_trybot', - 'android_clang_dbg_recipe': 'android_clang_asan_errorprone_findbugs_debug_trybot', - 'android_compile_dbg': 'android_debug_trybot', - 'android_compile_mips_dbg': 'android_debug_trybot_mipsel', - 'android_compile_rel': 'android_release_trybot', - 'android_compile_x64_dbg': 'android_debug_trybot_x64', - 'android_compile_x86_dbg': 'android_debug_trybot_x86', + 'android_clang_dbg_recipe': 'android_clang_asan_debug_trybot_compile_only', + 'android_compile_dbg': 'android_debug_trybot_compile_only', + 'android_compile_mips_dbg': 'android_debug_trybot_compile_only_mipsel', + 'android_compile_x64_dbg': 'android_debug_trybot_compile_only_x64', + 'android_compile_x86_dbg': 'android_debug_trybot_compile_only_x86', 'android_coverage': 'android_debug_trybot_java_coverage', 'android_cronet': 'android_cronet_release_trybot_arm_no_neon', @@ -522,44 +578,59 @@ # shared library loading is fixed. 'android_cronet_tester': 'android_cronet_debug_static_bot_arm_no_neon', + 'android_mojo': 'android_release_trybot_arm64', 'android_n5x_swarming_dbg': 'android_debug_trybot_arm64', 'android_n5x_swarming_rel': 'android_release_trybot_arm64', 'android_optional_gpu_tests_rel': 'gpu_tests_android_release_trybot_arm64', 'android_unswarmed_n5_rel': 'android_release_trybot', 'android_unswarmed_n5x_rel': 'android_release_trybot_arm64', - 'cast_shell_android': 'android_cast_debug_static_bot', + 'cast_shell_android': 'android_cast_debug_static_bot_compile_only', 'linux_android_dbg_ng': 'android_debug_trybot', 'linux_android_rel_ng': 'android_release_trybot', }, + # TODO(crbug/786044): Remove non-compile debug configs when migrated. 'tryserver.chromium.angle': { 'android_angle_rel_ng': 'gpu_tests_android_release_trybot_arm64', 'android_angle_deqp_rel_ng': 'deqp_android_release_trybot_arm64', 'linux_angle_ozone_rel_ng': 'gpu_fyi_tests_ozone_linux_system_gbm_libdrm_release_trybot', 'linux_angle_dbg_ng': 'gpu_fyi_tests_debug_trybot', + 'linux_angle_compile_dbg_ng': 'gpu_fyi_tests_debug_trybot', 'linux_angle_deqp_rel_ng': 'deqp_release_trybot', 'linux_angle_rel_ng': 'gpu_fyi_tests_release_trybot', 'mac_angle_dbg_ng': 'gpu_fyi_tests_debug_trybot', + 'mac_angle_compile_dbg_ng': 'gpu_fyi_tests_debug_trybot', 'mac_angle_rel_ng': 'gpu_fyi_tests_release_trybot', 'win_angle_dbg_ng': 'gpu_fyi_tests_debug_trybot_x86', + 'win_angle_compile_dbg_ng': 'gpu_fyi_tests_debug_trybot_x86', 'win_angle_deqp_rel_ng': 'deqp_release_no_clang_trybot_x86', 'win_angle_rel_ng': 'gpu_fyi_tests_release_trybot_x86', 'win_angle_x64_dbg_ng': 'gpu_fyi_tests_debug_trybot', + 'win_angle_compile_x64_dbg_ng': 'gpu_fyi_tests_debug_trybot', 'win_angle_x64_deqp_rel_ng': 'deqp_release_no_clang_trybot', 'win_angle_x64_rel_ng': 'gpu_fyi_tests_release_trybot', + 'win_angle_compile_x64_rel_ng': 'gpu_fyi_tests_release_trybot', + }, + + 'tryserver.chromium.chromiumos': { + 'chromeos-amd64-generic-rel': 'cros_chrome_sdk', + 'chromeos-daisy-rel': 'cros_chrome_sdk', + 'linux-chromeos-rel': 'chromeos_with_codecs_release_trybot', + 'linux-chromeos-compile-dbg': 'chromeos_with_codecs_debug_bot', + 'linux-chromeos-dbg': 'chromeos_with_codecs_debug_bot', }, 'tryserver.chromium.linux': { - 'Chromium Linux Codesearch Builder': 'codesearch', - 'ChromiumOS Codesearch Builder': 'codesearch', 'cast_shell_linux': 'cast_release_trybot', 'cast_shell_audio_linux': 'cast_audio_release_trybot', 'chromeos_amd64-generic_chromium_compile_only_ng': 'cros_chrome_sdk', 'chromeos_daisy_chromium_compile_only_ng': 'cros_chrome_sdk', 'chromium_presubmit': 'presubmit', 'closure_compilation': 'closure_compilation', - 'fuchsia': 'release_trybot_fuchsia', - 'fuchsia_compile': 'release_trybot_fuchsia', + 'fuchsia_arm64': 'release_trybot_fuchsia_arm64', + 'fuchsia_arm64_cast_audio': 'release_trybot_fuchsia_arm64_cast_audio', + 'fuchsia_x64': 'release_trybot_fuchsia', + 'fuchsia_x64_cast_audio': 'release_trybot_fuchsia_cast_audio', # TODO(kjellander): Remove linux_arm after tryserver restart. 'linux_arm': 'release_trybot_arm', 'linux_arm_dbg': 'debug_trybot_arm', @@ -585,9 +656,7 @@ 'linux_chromium_dbg_ng': 'debug_trybot', 'linux_chromium_gn_upload': 'gn_linux_upload', 'linux_chromium_headless_rel': 'headless_linux_release_trybot', - 'linux_chromium_ozone_compile_only_ng': 'ozone_linux_release_trybot', - 'linux_chromium_ozone_ng': 'ozone_linux_release_trybot', - 'linux_layout_tests_slimming_paint_v2': 'release_trybot', + 'linux_chromium_ozone_compile_only_ng': 'ozone_linux_release_trybot_compile_only', # This is intentionally a release_bot and not a release_trybot; # enabling DCHECKs seems to cause flaky failures that don't show up @@ -597,32 +666,32 @@ 'linux_chromium_rel_ng': 'gpu_tests_release_trybot', 'linux_chromium_tsan_rel_ng': 'tsan_disable_nacl_release_trybot', 'linux_chromium_ubsan_rel_ng': 'ubsan_vptr_release_trybot', - - # These are 'release_bot' rather than 'release_trybot' because - # 'release_trybot' includes 'dcheck_always_on', which might cause - # some layout test results to be different than for normal release - # builds (and we only store baselines for release builds). - 'linux_layout_tests_layout_ng': 'release_bot', - + 'linux_layout_tests_layout_ng': 'release_trybot', + 'linux_layout_tests_root_layer_scrolls': 'release_trybot', + 'linux_layout_tests_slimming_paint_v2': 'release_trybot', 'linux_mojo': 'release_trybot', - 'linux_mojo_chromeos': 'release_trybot', + 'linux_mojo_chromeos': 'chromeos_with_codecs_release_trybot', 'linux_nacl_sdk_build': 'release_bot', 'linux_nacl_sdk': 'release_bot', 'linux_optional_gpu_tests_rel': 'gpu_fyi_tests_release_trybot', 'linux_site_isolation': 'release_trybot', + 'linux_vr': 'vr_release_trybot', 'linux_upload_clang': 'release_bot', + 'leak_detection_linux': 'release_trybot', + 'layout_test_leak_detection': 'release_trybot', }, 'tryserver.chromium.mac': { 'ios-device': 'ios', 'ios-device-xcode-clang': 'ios', 'ios-simulator': 'ios', - 'ios-simulator-eg': 'ios', + 'ios-simulator-full-configs': 'ios', 'ios-simulator-cronet': 'ios', 'ios-simulator-xcode-clang': 'ios', 'mac_chromium_10.10': 'gpu_tests_release_trybot', 'mac_chromium_10.10_macviews': 'mac_views_browser_release_trybot', 'mac_chromium_10.12_rel_ng': 'gpu_tests_release_trybot', + 'mac_chromium_10.13_rel_ng': 'release_trybot', 'mac_chromium_archive_rel_ng': 'release_bot_mac_strip', 'mac_chromium_asan_rel_ng': 'asan_dcheck_disable_nacl_release_bot', 'mac_chromium_compile_dbg_ng': 'debug_trybot', @@ -637,6 +706,8 @@ }, 'tryserver.chromium.perf': { + 'Android Compile': 'official_goma_minimal_symbols_android', + 'Android arm64 Compile': 'official_goma_minimal_symbols_android_arm64', 'android_arm64_perf_bisect_builder': 'official_goma_minimal_symbols_android_arm64', 'android_fyi_perf_bisect': 'official_goma_minimal_symbols_android', 'android_nexus5X_perf_bisect': 'official_goma_minimal_symbols_android', @@ -648,6 +719,7 @@ 'android_perf_bisect_builder': 'official_goma_minimal_symbols_android', 'android_s5_perf_bisect': 'official_goma_minimal_symbols_android', 'android_webview_arm64_aosp_perf_bisect': 'official_goma_minimal_symbols_android', + 'Linux Builder': 'official_goma_perf', 'linux_fyi_perf_bisect': 'official_goma', 'linux_perf_bisect': 'official_goma', 'linux_perf_bisect_builder': 'official_goma', @@ -660,6 +732,9 @@ 'mac_perf_bisect_builder': 'official_goma', 'mac_retina_perf_bisect': 'official_goma', 'mac_retina_perf_cq': 'official_goma', + 'obbs_fyi': 'official_goma_perf', + 'Win Builder': 'official_goma_x86', + 'Win x64 Builder': 'official_goma', 'win_8_perf_bisect': 'official_goma_x86', 'win_fyi_perf_bisect': 'official_goma_x86', 'win_perf_bisect': 'official_goma_x86', @@ -676,19 +751,20 @@ 'tryserver.chromium.win': { 'win7_chromium_rel_ng': 'gpu_tests_release_trybot_x86_minimal_symbols', + 'win7_chromium_rel_loc_exp': 'gpu_tests_release_trybot_x86_minimal_symbols', 'win10_chromium_x64_rel_ng': 'release_trybot', 'win10_chromium_x64_rel_ng_exp': 'release_trybot', - 'win10_gce_x64_rel': 'release_bot_minimal_symbols', - 'win8_chromium_gn_upload': 'release_bot_x86_minimal_symbols', + 'win_chromium_gn_upload': 'release_bot_x86_minimal_symbols', 'win_x64_archive': 'release_trybot', 'win_archive': 'release_trybot_x86', 'win_chromium_compile_dbg_ng': 'debug_trybot_x86_minimal_symbols', 'win_chromium_compile_rel_ng': 'gpu_tests_release_trybot_x86_minimal_symbols', 'win_chromium_dbg_ng': 'debug_trybot_x86_minimal_symbols', - 'win_chromium_rel_ng': 'gpu_tests_release_trybot_x86_minimal_symbols', 'win_chromium_syzyasan_rel': 'syzyasan_no_pch_release_x86', 'win_chromium_x64_rel_ng': 'release_trybot_minimal_symbols', 'win_clang': 'win_clang_release_bot', + 'win-msvc-rel': 'win_msvc_release_bot_compile_only', + 'win-msvc-dbg': 'win_msvc_debug_bot_compile_only', 'win_clang_dbg': 'clang_debug_trybot_x86', 'win_clang_rel': 'clang_official_release_trybot_x86', 'win_clang_x64_dbg': 'win_clang_debug_bot', @@ -710,10 +786,16 @@ }, 'tryserver.v8': { - 'v8_android_chromium_gn_dbg': 'android_debug_bot', 'v8_linux_blink_rel': 'release_trybot', 'v8_linux_chromium_gn_rel': 'release_trybot', }, + + 'tryserver.webrtc': { + 'win_chromium_webrtc_compile_rel_ng': 'gpu_tests_release_trybot_x86_minimal_symbols', + 'mac_chromium_webrtc_compile_rel_ng': 'gpu_tests_release_trybot', + 'linux_chromium_webrtc_compile_rel_ng': 'release_trybot', + 'android_webrtc_compile_rel': 'android_release_trybot', + }, }, @@ -727,13 +809,17 @@ 'android', 'cast', 'clang', 'debug_static_bot', ], - 'android_clang_asan_errorprone_findbugs_debug_bot_minimal_symbols': [ - 'android', 'clang', 'asan', 'errorprone', 'findbugs', 'debug_bot', 'minimal_symbols', + 'android_cast_debug_static_bot_compile_only': [ + 'android', 'cast', 'clang', 'debug_static_bot', 'compile_only', + ], + + 'android_clang_asan_debug_bot_minimal_symbols': [ + 'android', 'clang', 'asan', 'debug_bot', 'minimal_symbols', 'strip_debug_info', ], - 'android_clang_asan_errorprone_findbugs_debug_trybot': [ - 'android', 'clang', 'asan', 'errorprone', 'findbugs', 'debug_trybot', + 'android_clang_asan_debug_trybot_compile_only': [ + 'android', 'clang', 'asan', 'debug_trybot', 'compile_only', ], 'android_clang_tot_asan': [ @@ -741,6 +827,11 @@ 'strip_debug_info', ], + 'android_clang_tot_cfi_full_cfi_diag_thin_lto_release_static_dcheck_always_on': [ + 'android_without_codecs', 'clang_tot', 'cfi_full', 'cfi_diag', 'thin_lto', 'release', + 'static', 'dcheck_always_on', + ], + 'android_clang_tot_dbg': [ 'android_without_codecs', 'clang_tot', 'shared', 'debug', ], @@ -797,11 +888,6 @@ 'strip_debug_info', ], - 'android_cronet_release_bot_minimal_symbols_armv6': [ - 'android', 'cronet', 'official_optimize', 'release_bot', 'minimal_symbols', 'armv6', - 'strip_debug_info', - ], - 'android_cronet_release_bot_minimal_symbols_arm_no_neon': [ 'android', 'cronet', 'official_optimize', 'release_bot', 'minimal_symbols', 'arm_no_neon', 'strip_debug_info', @@ -812,11 +898,6 @@ 'strip_debug_info', ], - 'android_cronet_release_bot_minimal_symbols_mipsel': [ - 'android', 'cronet', 'official_optimize', 'release_bot', 'minimal_symbols', 'mipsel', - 'strip_debug_info', - ], - 'android_cronet_release_bot_minimal_symbols_x86': [ 'android', 'cronet', 'official_optimize', 'release_bot', 'minimal_symbols', 'x86', 'strip_debug_info', @@ -842,6 +923,18 @@ 'android', 'debug_static_bot', 'arm64', ], + 'android_debug_static_bot_x64': [ + 'android', 'debug_static_bot', 'x64', + ], + + 'android_debug_static_bot_x86': [ + 'android', 'debug_static_bot', 'x86', + ], + + 'android_debug_static_bot_mipsel': [ + 'android', 'debug_static_bot', 'minimal_symbols', 'mipsel', 'strip_debug_info', + ], + 'android_debug_trybot': [ 'android', 'debug_trybot', ], @@ -850,6 +943,50 @@ 'android', 'debug_trybot', 'arm64', ], + 'android_debug_trybot_compile_only': [ + 'android', 'debug_trybot', 'compile_only', + ], + + 'android_debug_trybot_compile_only_arm64': [ + 'android', 'debug_trybot', 'compile_only', 'arm64', + ], + + 'android_debug_trybot_compile_only_mipsel': [ + 'android', 'debug_trybot', 'compile_only', 'mipsel', + ], + + 'android_debug_trybot_compile_only_x64': [ + 'android', 'debug_trybot', 'compile_only', 'x64', + ], + + 'android_debug_trybot_compile_only_x86': [ + 'android', 'debug_trybot', 'compile_only', 'x86', + ], + + 'android_debug_trybot_java_coverage': [ + 'android', 'debug_trybot', 'java_coverage', 'strip_debug_info', + ], + + 'android_ndk_next_release_bot_minimal_symbols': [ + 'android', 'ndk_next', 'release_bot', 'minimal_symbols', 'strip_debug_info', + ], + + 'android_ndk_next_release_bot_minimal_symbols_arm64': [ + 'android', 'ndk_next', 'release_bot', 'minimal_symbols', 'arm64', 'strip_debug_info', + ], + + 'android_ndk_next_release_bot_minimal_symbols_mipsel': [ + 'android', 'ndk_next', 'release_bot', 'minimal_symbols', 'mipsel', 'strip_debug_info', + ], + + 'android_ndk_next_release_bot_minimal_symbols_x64': [ + 'android', 'ndk_next', 'release_bot', 'minimal_symbols', 'x64', 'strip_debug_info', + ], + + 'android_ndk_next_release_bot_minimal_symbols_x86': [ + 'android', 'ndk_next', 'release_bot', 'minimal_symbols', 'x86', 'strip_debug_info', + ], + 'android_release_bot_minimal_symbols': [ 'android', 'release_bot', 'minimal_symbols', 'strip_debug_info', @@ -872,70 +1009,10 @@ 'android', 'release_trybot', 'arm64', 'strip_debug_info', ], - 'android_debug_static_bot_x64': [ - 'android', 'debug_static_bot', 'x64', - ], - - 'android_debug_static_bot_x86': [ - 'android', 'debug_static_bot', 'x86', - ], - - 'android_debug_static_bot_mipsel': [ - 'android', 'debug_static_bot', 'minimal_symbols', 'mipsel', 'strip_debug_info', - ], - - 'android_debug_trybot_java_coverage': [ - 'android', 'debug_trybot', 'java_coverage', 'strip_debug_info', - ], - - 'android_debug_trybot_mipsel': [ - 'android', 'debug_trybot', 'mipsel', 'strip_debug_info', - ], - - 'android_debug_trybot_x64': [ - 'android', 'debug_trybot', 'x64', 'strip_debug_info', - ], - - 'android_debug_trybot_x86': [ - 'android', 'debug_trybot', 'x86', 'strip_debug_info', - ], - - 'android_ndk_next_release_bot_minimal_symbols': [ - 'android', 'ndk_next', 'release_bot', 'minimal_symbols', 'strip_debug_info', - ], - - 'android_ndk_next_release_bot_minimal_symbols_arm64': [ - 'android', 'ndk_next', 'release_bot', 'minimal_symbols', 'arm64', 'strip_debug_info', - ], - - 'android_ndk_next_release_bot_minimal_symbols_mipsel': [ - 'android', 'ndk_next', 'release_bot', 'minimal_symbols', 'mipsel', 'strip_debug_info', - ], - - 'android_ndk_next_release_bot_minimal_symbols_x64': [ - 'android', 'ndk_next', 'release_bot', 'minimal_symbols', 'x64', 'strip_debug_info', - ], - - 'android_ndk_next_release_bot_minimal_symbols_x86': [ - 'android', 'ndk_next', 'release_bot', 'minimal_symbols', 'x86', 'strip_debug_info', - ], - - 'android_release_bot_minimal_symbols': [ - 'android', 'release_bot', 'minimal_symbols', 'strip_debug_info', - ], - 'android_shared_release_bot_x64': [ 'android_without_codecs', 'shared_release_bot', 'x64', 'dcheck_always_on', ], - 'android_release_trybot': [ - 'android', 'release_trybot', - ], - - 'android_release_trybot_arm64': [ - 'android', 'release_trybot', 'arm64', - ], - 'android_without_codecs_release_bot_minimal_symbols': [ 'android_without_codecs', 'release_bot', 'minimal_symbols', 'strip_debug_info', ], @@ -980,10 +1057,6 @@ 'asan', 'edge', 'fuzzer', 'v8_heap', 'release_bot', 'hybrid', ], - 'asan_edge_fuzzer_v8_heap_release_bot_x86': [ - 'clang', 'asan', 'edge', 'fuzzer', 'v8_heap', 'release_bot', 'x86', - ], - 'asan_edge_v8_heap_debug_bot_hybrid': [ 'asan', 'edge', 'v8_heap', 'debug_bot', 'hybrid', ], @@ -996,8 +1069,8 @@ 'clang', 'asan', 'fuzzer', 'v8_heap', 'chrome_with_codecs', 'release_bot', 'x86', ], - 'asan_fuzzer_v8_heap_release_bot_x86': [ - 'clang', 'asan', 'fuzzer', 'v8_heap', 'release_bot', 'x86', + 'asan_fuzzer_v8_heap_release_bot': [ + 'clang', 'asan', 'fuzzer', 'v8_heap', 'release_bot', ], 'asan_lsan_chromeos_release_trybot': [ @@ -1048,8 +1121,8 @@ 'cfi_full', 'cfi_diag', 'thin_lto', 'release', 'static', 'dcheck_always_on', 'goma', ], - 'cfi_full_diag_recover_icall_release_static': [ - 'cfi_full', 'cfi_diag', 'cfi_recover', 'cfi_icall', 'thin_lto', 'release', 'static', + 'cfi_full_diag_icall_release_static_dcheck_always_on': [ + 'cfi_full', 'cfi_diag', 'cfi_icall', 'thin_lto', 'release', 'static', 'dcheck_always_on', ], 'chromeos_asan_lsan_edge_fuzzer_v8_heap_release_bot': [ @@ -1061,48 +1134,29 @@ ], 'chromeos_with_codecs_debug_bot': [ - 'chromeos_with_codecs', 'debug_bot', + 'chromeos_with_codecs', 'debug_bot', 'use_vaapi', ], 'chromeos_with_codecs_debug_trybot': [ - 'chromeos_with_codecs', 'debug_trybot', + 'chromeos_with_codecs', 'debug_trybot', 'use_vaapi', ], 'chromeos_with_codecs_release_bot': [ - 'chromeos_with_codecs', 'release_bot', + 'chromeos_with_codecs', 'release_bot', 'use_vaapi', ], 'chromeos_with_codecs_release_trybot': [ - 'chromeos_with_codecs', 'release_trybot', + 'chromeos_with_codecs', 'release_trybot', 'use_vaapi', ], 'clang_debug_trybot_x86': [ 'clang', 'debug_trybot', 'x86', ], - 'clang_debug_bot_minimal_symbols_x86': [ - 'clang', 'debug_bot', 'minimal_symbols', 'x86', - ], - 'clang_release_bot_minimal_symbols_x86': [ 'clang', 'release_bot', 'minimal_symbols', 'x86', ], - 'clang_minimal_symbols_shared_release_bot_x86_dcheck': [ - 'clang', 'minimal_symbols', 'shared_release_bot', 'x86', 'dcheck_always_on', - ], - - 'clang_official_release_bot_minimal_symbols': [ - 'clang', 'official', 'release_bot', 'minimal_symbols', - ], - - 'clang_official_release_bot_minimal_symbols_x86': [ - 'clang', 'official', 'release_bot', 'minimal_symbols', 'x86', - ], - - 'clang_official_optimize_release_bot_minimal_symbols_x86': [ - 'clang', 'official_optimize', 'release_bot', 'minimal_symbols', 'x86', - ], 'clang_official_release_trybot': [ 'clang', 'official', 'release_trybot', @@ -1112,10 +1166,6 @@ 'clang', 'official', 'release_trybot', 'x86', ], - 'clang_shared_release_bot_dcheck': [ - 'clang', 'shared_release_bot', 'dcheck_always_on', - ], - 'clang_tot_asan_lsan_static_release': [ 'clang_tot', 'asan', 'lsan', 'static', 'release', ], @@ -1138,8 +1188,8 @@ 'clang_tot', 'full_symbols', 'shared', 'release', ], - 'clang_tot_msan_release_bot': [ - 'clang_tot', 'msan', 'release_bot', + 'clang_tot_msan_release': [ + 'clang_tot', 'msan', 'release', ], 'clang_tot_shared_debug': [ @@ -1159,13 +1209,11 @@ ], 'clang_tot_shared_release_use_lld_dcheck': [ - # TODO(crbug.com/706492): Enable symbols when LLD makes PDBs. - 'clang_tot', 'no_symbols', 'shared', 'release', 'use_lld', 'dcheck_always_on', + 'clang_tot', 'minimal_symbols', 'shared', 'release', 'use_lld', 'dcheck_always_on', ], 'clang_tot_official_static_use_lld_x86': [ - # TODO(crbug.com/706492): Enable symbols when LLD makes PDBs. - 'clang_tot', 'no_symbols', 'official', 'static', 'release', 'use_lld', 'x86', + 'clang_tot', 'minimal_symbols', 'official', 'static', 'release', 'use_lld', 'x86', ], 'clang_tot_minimal_symbols_shared_release': [ @@ -1192,13 +1240,8 @@ 'clang_tot', 'official', 'minimal_symbols', 'static', 'release', 'x86', ], - 'clang_tot_release_full_symbols_thin_lto_static_use_lld': [ - 'clang_tot', 'release', 'full_symbols', 'thin_lto', 'static', 'use_lld', - ], - - 'clang_tot_lld_release_shared': [ - # TODO(crbug.com/605819): Enable debug info in release builds. - 'clang_tot', 'release', 'shared', 'use_lld', + 'clang_tot_release_minimal_symbols_thin_lto_static_use_lld': [ + 'clang_tot', 'release', 'minimal_symbols', 'thin_lto', 'static', 'use_lld', ], 'clang_tot_shared_debug': [ @@ -1210,11 +1253,6 @@ 'error', ], - 'codesearch': [ - # The Codesearch bots run their own recipe and invoke GN directly. - 'error', - ], - 'codesearch_gen_chromium_android_bot': [ 'goma', 'clang', 'shared', 'debug', 'minimal_symbols', 'arm', 'android_without_codecs', ], @@ -1260,6 +1298,10 @@ 'debug_bot_minimal_symbols': [ 'debug_bot', 'minimal_symbols' ], 'debug_bot_x86_minimal_symbols': [ 'debug_bot', 'x86', 'minimal_symbols' ], + 'debug_bot_x86_minimal_symbols_no_com_init_hooks': [ + 'debug_bot', 'x86', 'minimal_symbols', 'no_com_init_hooks' + ], + 'debug_libfuzzer_asan': [ 'debug', 'libfuzzer', 'asan', 'chromeos_codecs', 'pdf_xfa', 'disable_nacl', ], @@ -1335,7 +1377,7 @@ ], 'gpu_fyi_tests_win_clang_debug_bot': [ - 'gpu_tests', 'internal_gles2_conform_tests', 'clang', 'debug_bot', 'minimal_symbols', + 'gpu_tests', 'internal_gles_conform_tests', 'clang', 'debug_bot', 'minimal_symbols', ], 'gpu_tests_android_release_trybot_arm64': [ @@ -1385,8 +1427,12 @@ # build files. 'ios': [ 'error'], - 'jumbo_release_bot': [ - 'jumbo', 'release_bot' + 'jumbo_release_bot_minimal_symbols': [ + 'jumbo', 'release_bot', 'minimal_symbols' + ], + + 'jumbo_large_chunks_release_bot_minimal_symbols': [ + 'jumbo_non_goma_chunks', 'release_bot', 'minimal_symbols' ], 'linux_chromium_analysis': [ @@ -1417,10 +1463,6 @@ 'msan', 'release_bot', ], - 'official_goma_minimal_symbols_clang': [ - 'official', 'goma', 'minimal_symbols', 'clang', - ], - 'official_goma': [ 'official', 'goma', ], @@ -1465,8 +1507,8 @@ 'ozone_linux', 'release_bot', ], - 'ozone_linux_release_trybot': [ - 'ozone_linux', 'release_trybot', + 'ozone_linux_release_trybot_compile_only': [ + 'ozone_linux', 'release_trybot', 'compile_only', ], 'presubmit': [ @@ -1475,7 +1517,7 @@ ], 'release_afl_asan': [ - 'release', 'afl', 'asan', 'chromeos_codecs', 'pdf_xfa', 'disable_nacl', + 'release', 'afl', 'asan', 'chromeos_codecs', 'pdf_xfa', 'disable_nacl', 'optimize_for_fuzzing', ], 'release_bot': [ @@ -1498,6 +1540,18 @@ 'release_bot', 'fuchsia', ], + 'release_bot_fuchsia_cast_audio': [ + 'release_bot', 'fuchsia', 'cast', 'cast_audio', 'no_symbols', + ], + + 'release_bot_fuchsia_arm64': [ + 'release_bot', 'fuchsia', 'arm64', + ], + + 'release_bot_fuchsia_arm64_cast_audio': [ + 'release_bot', 'fuchsia', 'arm64', 'cast', 'cast_audio', 'no_symbols', + ], + 'release_bot_mac_new_sdk': [ 'release_bot', 'mac_new_sdk', ], @@ -1516,6 +1570,15 @@ 'release_bot_minimal_symbols': [ 'release_bot', 'minimal_symbols' ], 'release_bot_x86_minimal_symbols': [ 'release_bot', 'x86', 'minimal_symbols' ], + 'release_bot_x86_minimal_symbols_no_com_init_hooks': [ + 'release_bot', 'x86', 'minimal_symbols', 'no_com_init_hooks' + ], + + # TODO(tikuta): Remove this once gcp goma backend supports all windows nacl compilers. + 'release_bot_x86_minimal_symbols_disable_nacl_no_clang': [ + 'release_bot_x86_minimal_symbols_disable_nacl', 'no_clang' + ], + 'release_libfuzzer_asan': [ 'release', 'libfuzzer', 'asan', 'chromeos_codecs', 'pdf_xfa', 'disable_nacl', 'optimize_for_fuzzing', ], @@ -1556,12 +1619,24 @@ 'release_trybot', 'fuchsia', ], + 'release_trybot_fuchsia_cast_audio': [ + 'release_trybot', 'fuchsia', 'cast', 'cast_audio', + ], + + 'release_trybot_fuchsia_arm64': [ + 'release_trybot', 'fuchsia', 'arm64', + ], + + 'release_trybot_fuchsia_arm64_cast_audio': [ + 'release_trybot', 'fuchsia', 'arm64', 'cast', 'cast_audio', + ], + 'release_trybot_x86': [ 'release_trybot', 'x86', ], - 'shared_release_bot_x86': [ - 'shared_release_bot', 'x86', + 'release_bot_x86_minimal_symbols_no_clang': [ + 'release_bot', 'x86', 'minimal_symbols', 'no_clang', ], 'syzyasan_no_pch_release_x86': [ @@ -1572,10 +1647,6 @@ 'disable_dcheck_always_on', ], - 'thin_lto_clang_tot_full_symbols_release_static_use_lld': [ - 'thin_lto', 'clang_tot', 'full_symbols', 'release', 'static', 'use_lld', - ], - 'tsan_disable_nacl_debug_bot': [ 'tsan', 'disable_nacl', 'debug_bot', ], @@ -1612,12 +1683,63 @@ 'v8_future', 'release_bot', ], + 'vr_release_bot': [ + 'vr', 'release_bot', 'ozone', + ], + + 'vr_release_trybot': [ + 'vr', 'release_trybot', 'ozone', + ], + 'win_clang_debug_bot': [ - 'clang', 'debug_bot', 'minimal_symbols', + # Now that the default win bots use clang, use a "clang" bot to make sure + # things stay compilable with msvc. TODO(thakis): Having a "clang" bot + # check that is very confusing, so rename the bot to "msvc". + 'no_clang', 'debug_bot', 'minimal_symbols', ], 'win_clang_release_bot': [ - 'clang', 'release_bot', 'minimal_symbols', + # Now that the default win bots use clang, use a "clang" bot to make sure + # things stay compilable with msvc. TODO(thakis): Having a "clang" bot + # check that is very confusing, so rename the bot to "msvc". + 'no_clang', 'release_bot', 'minimal_symbols', + ], + + 'win_msvc_release_bot': [ + 'no_clang', 'release_bot', + ], + + 'win_msvc_release_bot_compile_only': [ + 'no_clang', 'release_bot', 'compile_only', + ], + + 'win_msvc_release_bot_x86': [ + 'no_clang', 'minimal_symbols', 'release_bot', 'x86', + ], + + 'win_msvc_debug_bot': [ + 'no_clang', 'debug_bot', + ], + + 'win_msvc_debug_bot_compile_only': [ + 'no_clang', 'debug_bot', 'compile_only', + ], + + 'win_msvc_debug_bot_x86': [ + 'no_clang', 'minimal_symbols', 'debug_bot', 'x86', + ], + + 'win_msvc_shared_release_bot': [ + 'no_clang', 'minimal_symbols', 'shared_release_bot', 'dcheck_always_on', + ], + + 'win_msvc_shared_release_bot_x86': [ + 'no_clang', 'minimal_symbols', 'shared_release_bot', 'dcheck_always_on', 'x86', + ], + + # TODO(tikuta): Remove this once gcp goma backend supports all windows nacl compilers. + 'win_clang_release_bot_disable_nacl': [ + 'clang', 'release_bot', 'minimal_symbols', 'disable_nacl', ], 'windows_analyze': [ @@ -1656,10 +1778,6 @@ 'gn_args': 'target_cpu="arm64"', }, - 'armv6': { - 'gn_args': 'arm_version=6', - }, - 'arm_no_neon': { 'mixins': ['arm'], 'gn_args': 'arm_use_neon=false', @@ -1742,11 +1860,16 @@ 'gn_args': 'is_clang=false', }, + 'compile_only': { + 'mixins': ['no_symbols'], + }, + 'cronet': { 'gn_args': ('disable_file_support=true disable_ftp_support=true ' 'enable_websockets=false use_platform_icu_alternatives=true ' 'use_partition_alloc=false enable_reporting=false ' - 'include_transport_security_state_preload_list=false'), + 'include_transport_security_state_preload_list=false ' + 'clang_use_default_sample_profile=false'), }, 'cros_chrome_sdk': { @@ -1804,18 +1927,10 @@ 'gn_args': 'error', }, - 'errorprone': { - 'gn_args': 'use_errorprone_java_compiler=true', - }, - 'ffmpeg_branding_chromeos': { 'gn_args': 'ffmpeg_branding="ChromeOS"', }, - 'findbugs': { - 'gn_args': 'run_findbugs=true', - }, - 'full_symbols': { 'gn_args': 'symbol_level=2', }, @@ -1842,7 +1957,7 @@ }, 'gpu_fyi_tests': { - 'mixins': ['gpu_tests', 'internal_gles2_conform_tests'], + 'mixins': ['gpu_tests', 'internal_gles_conform_tests'], }, 'gpu_tests': { @@ -1866,8 +1981,8 @@ 'gn_args': 'include_vr_data=true', }, - 'internal_gles2_conform_tests': { - 'gn_args': 'internal_gles2_conform_tests=true', + 'internal_gles_conform_tests': { + 'gn_args': 'internal_gles2_conform_tests=true build_angle_gles1_conform_tests=true', }, 'java_coverage': { @@ -1878,16 +1993,16 @@ 'gn_args': 'use_jumbo_build=true', }, + 'jumbo_non_goma_chunks': { + 'gn_args': 'use_jumbo_build=true jumbo_file_merge_limit=50', + }, + 'libfuzzer': { 'gn_args': 'use_libfuzzer=true' }, 'lsan': { 'gn_args': 'is_lsan=true', }, - 'lto': { - 'gn_args': 'allow_posix_link_time_opt=true', - }, - 'mac_strip': { 'gn_args': 'enable_stripping=true', }, @@ -1918,6 +2033,10 @@ 'gn_args': 'android_ndk_version="r13b" android_ndk_major_version=13', }, + 'no_com_init_hooks': { + 'gn_args': 'com_init_check_hook_disabled=true', + }, + 'no_gnome_keyring': { 'gn_args': 'use_gnome_keyring=false', }, @@ -1943,11 +2062,15 @@ 'gn_args': 'optimize_for_fuzzing=true', }, + 'ozone': { + 'gn_args': 'use_ozone=true', + }, + 'ozone_linux': { 'gn_args': ('ozone_auto_platforms=false ozone_platform_wayland=true ' 'ozone_platform="x11" ' 'ozone_platform_x11=true ozone_platform_gbm=true ' - 'enable_package_mash_services=true use_ash=false ' + 'enable_mus=true ' 'use_xkbcommon=true use_ozone=true'), }, @@ -1973,6 +2096,14 @@ 'mixins': ['release', 'static', 'goma'], }, + 'release_bot_x86_minimal_symbols': { + 'mixins': ['release_bot', 'x86', 'minimal_symbols'] + }, + + 'release_bot_x86_minimal_symbols_disable_nacl': { + 'mixins': ['release_bot_x86_minimal_symbols', 'disable_nacl'] + }, + 'release_trybot': { 'mixins': ['release_bot', 'minimal_symbols', 'dcheck_always_on'], }, @@ -2004,7 +2135,6 @@ 'thin_lto': { 'gn_args': 'use_thin_lto=true', - 'mixins': ['lto'], }, 'tsan': { @@ -2032,6 +2162,10 @@ 'gn_args': 'use_lld=true', }, + 'use_vaapi': { + 'gn_args': 'use_vaapi=true', + }, + 'v8_concurrent_marking': { 'gn_args': 'v8_enable_concurrent_marking=true', }, @@ -2044,6 +2178,10 @@ 'gn_args': 'v8_enable_verify_heap=true', }, + 'vr': { + 'gn_args': 'enable_vr=true', + }, + 'win_analyze': { 'gn_args': 'use_vs_code_analysis=true', }, @@ -2058,6 +2196,6 @@ }, 'luci_tryservers': { - 'chromium.try': [ 'LUCI linux_chromium_rel_ng' ], + 'chromium.try': [ 'linux_chromium_rel_ng' ], }, }
diff --git a/tools/mb/mb_unittest.py b/tools/mb/mb_unittest.py index 73c3e9c..287e271 100755 --- a/tools/mb/mb_unittest.py +++ b/tools/mb/mb_unittest.py
@@ -64,8 +64,6 @@ self.files[path] = contents def Call(self, cmd, env=None, buffer_output=True): - if env: - self.cross_compile = env.get('GYP_CROSSCOMPILE') self.calls.append(cmd) if self.cmds: return self.cmds.pop(0) @@ -111,13 +109,10 @@ 'masters': { 'chromium': {}, 'fake_master': { - 'fake_builder': 'gyp_rel_bot', - 'fake_gn_builder': 'gn_rel_bot', - 'fake_gyp_crosscompile_builder': 'gyp_crosscompile', - 'fake_gn_debug_builder': 'gn_debug_goma', - 'fake_gyp_builder': 'gyp_debug', - 'fake_gn_args_bot': '//build/args/bots/fake_master/fake_gn_args_bot.gn', - 'fake_multi_phase': { 'phase_1': 'gn_phase_1', 'phase_2': 'gn_phase_2'}, + 'fake_builder': 'rel_bot', + 'fake_debug_builder': 'debug_goma', + 'fake_args_bot': '//build/args/bots/fake_master/fake_args_bot.gn', + 'fake_multi_phase': { 'phase_1': 'phase_1', 'phase_2': 'phase_2'}, 'fake_args_file': 'args_file_goma', 'fake_args_file_twice': 'args_file_twice', }, @@ -125,38 +120,26 @@ 'configs': { 'args_file_goma': ['args_file', 'goma'], 'args_file_twice': ['args_file', 'args_file'], - 'gyp_rel_bot': ['gyp', 'rel', 'goma'], - 'gn_debug_goma': ['gn', 'debug', 'goma'], - 'gyp_debug': ['gyp', 'debug', 'fake_feature1'], - 'gn_rel_bot': ['gn', 'rel', 'goma'], - 'gyp_crosscompile': ['gyp', 'crosscompile'], - 'gn_phase_1': ['gn', 'phase_1'], - 'gn_phase_2': ['gn', 'phase_2'], + 'rel_bot': ['rel', 'goma', 'fake_feature1'], + 'debug_goma': ['debug', 'goma'], + 'phase_1': ['phase_1'], + 'phase_2': ['phase_2'], }, 'mixins': { - 'crosscompile': { - 'gyp_crosscompile': True, - }, 'fake_feature1': { 'gn_args': 'enable_doom_melon=true', - 'gyp_defines': 'doom_melon=1', }, - 'gyp': {'type': 'gyp'}, - 'gn': {'type': 'gn'}, 'goma': { 'gn_args': 'use_goma=true', - 'gyp_defines': 'goma=1', }, 'args_file': { 'args_file': '//build/args/fake.gn', }, 'phase_1': { 'gn_args': 'phase=1', - 'gyp_args': 'phase=1', }, 'phase_2': { 'gn_args': 'phase=2', - 'gyp_args': 'phase=2', }, 'rel': { 'gn_args': 'is_debug=false', @@ -172,17 +155,16 @@ TEST_BAD_CONFIG = """\ { 'configs': { - 'gn_rel_bot_1': ['gn', 'rel', 'chrome_with_codecs'], - 'gn_rel_bot_2': ['gn', 'rel', 'bad_nested_config'], + 'rel_bot_1': ['rel', 'chrome_with_codecs'], + 'rel_bot_2': ['rel', 'bad_nested_config'], }, 'masters': { 'chromium': { - 'a': 'gn_rel_bot_1', - 'b': 'gn_rel_bot_2', + 'a': 'rel_bot_1', + 'b': 'rel_bot_2', }, }, 'mixins': { - 'gn': {'type': 'gn'}, 'chrome_with_codecs': { 'gn_args': 'proprietary_codecs=true', }, @@ -196,30 +178,6 @@ } """ - -GYP_HACKS_CONFIG = """\ -{ - 'masters': { - 'chromium': {}, - 'fake_master': { - 'fake_builder': 'fake_config', - }, - }, - 'configs': { - 'fake_config': ['fake_mixin'], - }, - 'mixins': { - 'fake_mixin': { - 'type': 'gyp', - 'gn_args': '', - 'gyp_defines': - ('foo=bar llvm_force_head_revision=1 ' - 'gyp_link_concurrency=1 baz=1'), - }, - }, -} -""" - TRYSERVER_CONFIG = """\ { 'masters': { @@ -257,7 +215,7 @@ }, }''') mbw.files.setdefault( - mbw.ToAbsPath('//build/args/bots/fake_master/fake_gn_args_bot.gn'), + mbw.ToAbsPath('//build/args/bots/fake_master/fake_args_bot.gn'), 'is_debug = false\n') if files: for path, contents in files.items(): @@ -277,38 +235,7 @@ self.assertEqual(mbw.err, err) return mbw - def test_clobber(self): - files = { - '/fake_src/out/Debug': None, - '/fake_src/out/Debug/mb_type': None, - } - mbw = self.fake_mbw(files) - - # The first time we run this, the build dir doesn't exist, so no clobber. - self.check(['gen', '-c', 'gn_debug_goma', '//out/Debug'], mbw=mbw, ret=0) - self.assertEqual(mbw.rmdirs, []) - self.assertEqual(mbw.files['/fake_src/out/Debug/mb_type'], 'gn') - - # The second time we run this, the build dir exists and matches, so no - # clobber. - self.check(['gen', '-c', 'gn_debug_goma', '//out/Debug'], mbw=mbw, ret=0) - self.assertEqual(mbw.rmdirs, []) - self.assertEqual(mbw.files['/fake_src/out/Debug/mb_type'], 'gn') - - # Now we switch build types; this should result in a clobber. - self.check(['gen', '-c', 'gyp_debug', '//out/Debug'], mbw=mbw, ret=0) - self.assertEqual(mbw.rmdirs, ['/fake_src/out/Debug']) - self.assertEqual(mbw.files['/fake_src/out/Debug/mb_type'], 'gyp') - - # Now we delete mb_type; this checks the case where the build dir - # exists but wasn't populated by mb; this should also result in a clobber. - del mbw.files['/fake_src/out/Debug/mb_type'] - self.check(['gen', '-c', 'gyp_debug', '//out/Debug'], mbw=mbw, ret=0) - self.assertEqual(mbw.rmdirs, - ['/fake_src/out/Debug', '/fake_src/out/Debug']) - self.assertEqual(mbw.files['/fake_src/out/Debug/mb_type'], 'gyp') - - def test_gn_analyze(self): + def test_analyze(self): files = {'/tmp/in.json': '''{\ "files": ["foo/foo_unittest.cc"], "test_targets": ["foo_unittests"], @@ -323,7 +250,7 @@ mbw = self.fake_mbw(files) mbw.Call = lambda cmd, env=None, buffer_output=True: (0, '', '') - self.check(['analyze', '-c', 'gn_debug_goma', '//out/Default', + self.check(['analyze', '-c', 'debug_goma', '//out/Default', '/tmp/in.json', '/tmp/out.json'], mbw=mbw, ret=0) out = json.loads(mbw.files['/tmp/out.json']) self.assertEqual(out, { @@ -332,9 +259,84 @@ 'test_targets': ['foo_unittests'] }) - def test_gn_gen(self): + def test_analyze_optimizes_compile_for_all(self): + files = {'/tmp/in.json': '''{\ + "files": ["foo/foo_unittest.cc"], + "test_targets": ["foo_unittests"], + "additional_compile_targets": ["all"] + }''', + '/tmp/out.json.gn': '''{\ + "status": "Found dependency", + "compile_targets": ["//foo:foo_unittests", "all"], + "test_targets": ["//foo:foo_unittests"] + }'''} + + mbw = self.fake_mbw(files) + mbw.Call = lambda cmd, env=None, buffer_output=True: (0, '', '') + + self.check(['analyze', '-c', 'debug_goma', '//out/Default', + '/tmp/in.json', '/tmp/out.json'], mbw=mbw, ret=0) + out = json.loads(mbw.files['/tmp/out.json']) + + # check that 'foo_unittests' is not in the compile_targets + self.assertEqual(['all'], out['compile_targets']) + + def test_analyze_handles_other_toolchains(self): + files = {'/tmp/in.json': '''{\ + "files": ["foo/foo_unittest.cc"], + "test_targets": ["foo_unittests"], + "additional_compile_targets": ["all"] + }''', + '/tmp/out.json.gn': '''{\ + "status": "Found dependency", + "compile_targets": ["//foo:foo_unittests", + "//foo:foo_unittests(bar)"], + "test_targets": ["//foo:foo_unittests"] + }'''} + + mbw = self.fake_mbw(files) + mbw.Call = lambda cmd, env=None, buffer_output=True: (0, '', '') + + self.check(['analyze', '-c', 'debug_goma', '//out/Default', + '/tmp/in.json', '/tmp/out.json'], mbw=mbw, ret=0) + out = json.loads(mbw.files['/tmp/out.json']) + + # crbug.com/736215: If GN returns a label containing a toolchain, + # MB (and Ninja) don't know how to handle it; to work around this, + # we give up and just build everything we were asked to build. The + # output compile_targets should include all of the input test_targets and + # additional_compile_targets. + self.assertEqual(['all', 'foo_unittests'], out['compile_targets']) + + def test_analyze_handles_way_too_many_results(self): + too_many_files = ', '.join(['"//foo:foo%d"' % i for i in xrange(4 * 1024)]) + files = {'/tmp/in.json': '''{\ + "files": ["foo/foo_unittest.cc"], + "test_targets": ["foo_unittests"], + "additional_compile_targets": ["all"] + }''', + '/tmp/out.json.gn': '''{\ + "status": "Found dependency", + "compile_targets": [''' + too_many_files + '''], + "test_targets": ["//foo:foo_unittests"] + }'''} + + mbw = self.fake_mbw(files) + mbw.Call = lambda cmd, env=None, buffer_output=True: (0, '', '') + + self.check(['analyze', '-c', 'debug_goma', '//out/Default', + '/tmp/in.json', '/tmp/out.json'], mbw=mbw, ret=0) + out = json.loads(mbw.files['/tmp/out.json']) + + # If GN returns so many compile targets that we might have command-line + # issues, we should give up and just build everything we were asked to + # build. The output compile_targets should include all of the input + # test_targets and additional_compile_targets. + self.assertEqual(['all', 'foo_unittests'], out['compile_targets']) + + def test_gen(self): mbw = self.fake_mbw() - self.check(['gen', '-c', 'gn_debug_goma', '//out/Default', '-g', '/goma'], + self.check(['gen', '-c', 'debug_goma', '//out/Default', '-g', '/goma'], mbw=mbw, ret=0) self.assertMultiLineEqual(mbw.files['/fake_src/out/Default/args.gn'], ('goma_dir = "/goma"\n' @@ -347,7 +349,7 @@ mbw.out) mbw = self.fake_mbw(win32=True) - self.check(['gen', '-c', 'gn_debug_goma', '-g', 'c:\\goma', '//out/Debug'], + self.check(['gen', '-c', 'debug_goma', '-g', 'c:\\goma', '//out/Debug'], mbw=mbw, ret=0) self.assertMultiLineEqual(mbw.files['c:\\fake_src\\out\\Debug\\args.gn'], ('goma_dir = "c:\\\\goma"\n' @@ -357,14 +359,14 @@ '--check\n', mbw.out) mbw = self.fake_mbw() - self.check(['gen', '-m', 'fake_master', '-b', 'fake_gn_args_bot', + self.check(['gen', '-m', 'fake_master', '-b', 'fake_args_bot', '//out/Debug'], mbw=mbw, ret=0) self.assertEqual( mbw.files['/fake_src/out/Debug/args.gn'], - 'import("//build/args/bots/fake_master/fake_gn_args_bot.gn")\n') + 'import("//build/args/bots/fake_master/fake_args_bot.gn")\n') - def test_gn_gen_args_file_mixins(self): + def test_gen_args_file_mixins(self): mbw = self.fake_mbw() self.check(['gen', '-m', 'fake_master', '-b', 'fake_args_file', '//out/Debug'], mbw=mbw, ret=0) @@ -378,12 +380,12 @@ self.check(['gen', '-m', 'fake_master', '-b', 'fake_args_file_twice', '//out/Debug'], mbw=mbw, ret=1) - def test_gn_gen_fails(self): + def test_gen_fails(self): mbw = self.fake_mbw() mbw.Call = lambda cmd, env=None, buffer_output=True: (1, '', '') - self.check(['gen', '-c', 'gn_debug_goma', '//out/Default'], mbw=mbw, ret=1) + self.check(['gen', '-c', 'debug_goma', '//out/Default'], mbw=mbw, ret=1) - def test_gn_gen_swarming(self): + def test_gen_swarming(self): files = { '/tmp/swarming_targets': 'base_unittests\n', '/fake_src/testing/buildbot/gn_isolate_map.pyl': ( @@ -399,7 +401,7 @@ } mbw = self.fake_mbw(files) self.check(['gen', - '-c', 'gn_debug_goma', + '-c', 'debug_goma', '--swarming-targets-file', '/tmp/swarming_targets', '//out/Default'], mbw=mbw, ret=0) self.assertIn('/fake_src/out/Default/base_unittests.isolate', @@ -407,7 +409,7 @@ self.assertIn('/fake_src/out/Default/base_unittests.isolated.gen.json', mbw.files) - def test_gn_gen_swarming_script(self): + def test_gen_swarming_script(self): files = { '/tmp/swarming_targets': 'cc_perftests\n', '/fake_src/testing/buildbot/gn_isolate_map.pyl': ( @@ -424,7 +426,7 @@ } mbw = self.fake_mbw(files=files, win32=True) self.check(['gen', - '-c', 'gn_debug_goma', + '-c', 'debug_goma', '--swarming-targets-file', '/tmp/swarming_targets', '--isolate-map-file', '/fake_src/testing/buildbot/gn_isolate_map.pyl', @@ -435,7 +437,76 @@ mbw.files) - def test_gn_isolate(self): + def test_multiple_isolate_maps(self): + files = { + '/tmp/swarming_targets': 'cc_perftests\n', + '/fake_src/testing/buildbot/gn_isolate_map.pyl': ( + "{'cc_perftests': {" + " 'label': '//cc:cc_perftests'," + " 'type': 'raw'," + " 'args': []," + "}}\n" + ), + '/fake_src/testing/buildbot/gn_isolate_map2.pyl': ( + "{'cc_perftests2': {" + " 'label': '//cc:cc_perftests'," + " 'type': 'raw'," + " 'args': []," + "}}\n" + ), + 'c:\\fake_src\out\Default\cc_perftests.exe.runtime_deps': ( + "cc_perftests\n" + ), + } + mbw = self.fake_mbw(files=files, win32=True) + self.check(['gen', + '-c', 'debug_goma', + '--swarming-targets-file', '/tmp/swarming_targets', + '--isolate-map-file', + '/fake_src/testing/buildbot/gn_isolate_map.pyl', + '--isolate-map-file', + '/fake_src/testing/buildbot/gn_isolate_map2.pyl', + '//out/Default'], mbw=mbw, ret=0) + self.assertIn('c:\\fake_src\\out\\Default\\cc_perftests.isolate', + mbw.files) + self.assertIn('c:\\fake_src\\out\\Default\\cc_perftests.isolated.gen.json', + mbw.files) + + + def test_duplicate_isolate_maps(self): + files = { + '/tmp/swarming_targets': 'cc_perftests\n', + '/fake_src/testing/buildbot/gn_isolate_map.pyl': ( + "{'cc_perftests': {" + " 'label': '//cc:cc_perftests'," + " 'type': 'raw'," + " 'args': []," + "}}\n" + ), + '/fake_src/testing/buildbot/gn_isolate_map2.pyl': ( + "{'cc_perftests': {" + " 'label': '//cc:cc_perftests'," + " 'type': 'raw'," + " 'args': []," + "}}\n" + ), + 'c:\\fake_src\out\Default\cc_perftests.exe.runtime_deps': ( + "cc_perftests\n" + ), + } + mbw = self.fake_mbw(files=files, win32=True) + # Check that passing duplicate targets into mb fails. + self.check(['gen', + '-c', 'debug_goma', + '--swarming-targets-file', '/tmp/swarming_targets', + '--isolate-map-file', + '/fake_src/testing/buildbot/gn_isolate_map.pyl', + '--isolate-map-file', + '/fake_src/testing/buildbot/gn_isolate_map2.pyl', + '//out/Default'], mbw=mbw, ret=1) + + + def test_isolate(self): files = { '/fake_src/out/Default/toolchain.ninja': "", '/fake_src/testing/buildbot/gn_isolate_map.pyl': ( @@ -449,7 +520,7 @@ "base_unittests\n" ), } - self.check(['isolate', '-c', 'gn_debug_goma', '//out/Default', + self.check(['isolate', '-c', 'debug_goma', '//out/Default', 'base_unittests'], files=files, ret=0) # test running isolate on an existing build_dir @@ -457,11 +528,10 @@ self.check(['isolate', '//out/Default', 'base_unittests'], files=files, ret=0) - files['/fake_src/out/Default/mb_type'] = 'gn\n' self.check(['isolate', '//out/Default', 'base_unittests'], files=files, ret=0) - def test_gn_run(self): + def test_run(self): files = { '/fake_src/testing/buildbot/gn_isolate_map.pyl': ( "{'base_unittests': {" @@ -474,55 +544,50 @@ "base_unittests\n" ), } - self.check(['run', '-c', 'gn_debug_goma', '//out/Default', + self.check(['run', '-c', 'debug_goma', '//out/Default', 'base_unittests'], files=files, ret=0) - def test_gn_lookup(self): - self.check(['lookup', '-c', 'gn_debug_goma'], ret=0) + def test_run_swarmed(self): + files = { + '/fake_src/testing/buildbot/gn_isolate_map.pyl': ( + "{'base_unittests': {" + " 'label': '//base:base_unittests'," + " 'type': 'raw'," + " 'args': []," + "}}\n" + ), + '/fake_src/out/Default/base_unittests.runtime_deps': ( + "base_unittests\n" + ), + } - def test_gn_lookup_goma_dir_expansion(self): - self.check(['lookup', '-c', 'gn_rel_bot', '-g', '/foo'], ret=0, + def run_stub(cmd, **_kwargs): + if 'isolate.py' in cmd[1]: + return 0, 'fake_hash base_unittests', '' + else: + return 0, '', '' + + mbw = self.fake_mbw(files=files) + mbw.Run = run_stub + self.check(['run', '-s', '-c', 'debug_goma', '//out/Default', + 'base_unittests'], mbw=mbw, ret=0) + self.check(['run', '-s', '-c', 'debug_goma', '-d', 'os', 'Win7', + '//out/Default', 'base_unittests'], mbw=mbw, ret=0) + + def test_lookup(self): + self.check(['lookup', '-c', 'debug_goma'], ret=0) + + def test_lookup_goma_dir_expansion(self): + self.check(['lookup', '-c', 'rel_bot', '-g', '/foo'], ret=0, out=('\n' 'Writing """\\\n' + 'enable_doom_melon = true\n' 'goma_dir = "/foo"\n' 'is_debug = false\n' 'use_goma = true\n' '""" to _path_/args.gn.\n\n' '/fake_src/buildtools/linux64/gn gen _path_\n')) - def test_gyp_analyze(self): - mbw = self.check(['analyze', '-c', 'gyp_rel_bot', '//out/Release', - '/tmp/in.json', '/tmp/out.json'], ret=0) - self.assertIn('analyzer', mbw.calls[0]) - - def test_gyp_crosscompile(self): - mbw = self.fake_mbw() - self.check(['gen', '-c', 'gyp_crosscompile', '//out/Release'], - mbw=mbw, ret=0) - self.assertTrue(mbw.cross_compile) - - def test_gyp_gen(self): - self.check(['gen', '-c', 'gyp_rel_bot', '-g', '/goma', '//out/Release'], - ret=0, - out=("GYP_DEFINES='goma=1 gomadir=/goma'\n" - "python build/gyp_chromium -G output_dir=out\n")) - - mbw = self.fake_mbw(win32=True) - self.check(['gen', '-c', 'gyp_rel_bot', '-g', 'c:\\goma', '//out/Release'], - mbw=mbw, ret=0, - out=("set GYP_DEFINES=goma=1 gomadir='c:\\goma'\n" - "python build\\gyp_chromium -G output_dir=out\n")) - - def test_gyp_gen_fails(self): - mbw = self.fake_mbw() - mbw.Call = lambda cmd, env=None, buffer_output=True: (1, '', '') - self.check(['gen', '-c', 'gyp_rel_bot', '//out/Release'], mbw=mbw, ret=1) - - def test_gyp_lookup_goma_dir_expansion(self): - self.check(['lookup', '-c', 'gyp_rel_bot', '-g', '/foo'], ret=0, - out=("GYP_DEFINES='goma=1 gomadir=/foo'\n" - "python build/gyp_chromium -G output_dir=_path_\n")) - def test_help(self): orig_stdout = sys.stdout try: @@ -540,7 +605,7 @@ self.assertIn('Must specify a build --phase', mbw.out) # Check that passing a --phase to a single-phase builder fails. - mbw = self.check(['lookup', '-m', 'fake_master', '-b', 'fake_gn_builder', + mbw = self.check(['lookup', '-m', 'fake_master', '-b', 'fake_builder', '--phase', 'phase_1'], ret=1) self.assertIn('Must not specify a build --phase', mbw.out) @@ -567,16 +632,6 @@ mbw.files[mbw.default_config] = TEST_BAD_CONFIG self.check(['validate'], mbw=mbw, ret=1) - def test_gyp_env_hacks(self): - mbw = self.fake_mbw() - mbw.files[mbw.default_config] = GYP_HACKS_CONFIG - self.check(['lookup', '-c', 'fake_config'], mbw=mbw, - ret=0, - out=("GYP_DEFINES='foo=bar baz=1'\n" - "GYP_LINK_CONCURRENCY=1\n" - "LLVM_FORCE_HEAD_REVISION=1\n" - "python build/gyp_chromium -G output_dir=_path_\n")) - def test_buildbucket(self): mbw = self.fake_mbw() mbw.files[mbw.default_config] = TRYSERVER_CONFIG
diff --git a/tools/md_browser/md_browser.py b/tools/md_browser/md_browser.py index 1621710..358a1106 100755 --- a/tools/md_browser/md_browser.py +++ b/tools/md_browser/md_browser.py
@@ -153,6 +153,8 @@ self._DoImage(full_path, 'image/png') elif path.lower().endswith('.jpg'): self._DoImage(full_path, 'image/jpeg') + elif path.lower().endswith('.svg'): + self._DoImage(full_path, 'image/svg+xml') elif os.path.isdir(full_path): self._DoDirListing(full_path) elif os.path.exists(full_path): @@ -180,7 +182,7 @@ md = markdown.Markdown(extensions=extensions, extension_configs=extension_configs, - tab_length=2, + tab_length=4, output_format='html4') has_a_single_h1 = (len([line for line in contents.splitlines()
diff --git a/tools/media_engagement_preload/BUILD.gn b/tools/media_engagement_preload/BUILD.gn new file mode 100644 index 0000000..e59e693a --- /dev/null +++ b/tools/media_engagement_preload/BUILD.gn
@@ -0,0 +1,58 @@ +# Copyright 2017 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. + +generator_sources = [ + "make_dafsa.py", + "media_engagement_preload_pb2.py", + + # protobuf dependency + "../../third_party/protobuf/python/google/protobuf/descriptor_pb2.py", + "../../third_party/protobuf/python/google/protobuf/json_format.py", + "../../third_party/protobuf/python/google/protobuf/service.py", + "../../third_party/protobuf/python/google/protobuf/message.py", + "../../third_party/protobuf/python/google/protobuf/service_reflection.py", + "../../third_party/protobuf/python/google/protobuf/text_encoding.py", + "../../third_party/protobuf/python/google/protobuf/proto_builder.py", + "../../third_party/protobuf/python/google/protobuf/python_protobuf.h", + "../../third_party/protobuf/python/google/protobuf/descriptor.py", + "../../third_party/protobuf/python/google/protobuf/descriptor_database.py", + "../../third_party/protobuf/python/google/protobuf/message_factory.py", + "../../third_party/protobuf/python/google/protobuf/symbol_database.py", + "../../third_party/protobuf/python/google/protobuf/text_format.py", + "../../third_party/protobuf/python/google/protobuf/descriptor_pool.py", + "../../third_party/protobuf/python/google/protobuf/internal/more_extensions.proto", + "../../third_party/protobuf/python/google/protobuf/internal/wire_format.py", + "../../third_party/protobuf/python/google/protobuf/internal/testing_refleaks.py", + "../../third_party/protobuf/python/google/protobuf/internal/type_checkers.py", + "../../third_party/protobuf/python/google/protobuf/internal/missing_enum_values.proto", + "../../third_party/protobuf/python/google/protobuf/internal/more_messages.proto", + "../../third_party/protobuf/python/google/protobuf/internal/containers.py", + "../../third_party/protobuf/python/google/protobuf/internal/test_bad_identifiers.proto", + "../../third_party/protobuf/python/google/protobuf/internal/_parameterized.py", + "../../third_party/protobuf/python/google/protobuf/internal/message_listener.py", + "../../third_party/protobuf/python/google/protobuf/internal/enum_type_wrapper.py", + "../../third_party/protobuf/python/google/protobuf/internal/api_implementation.py", + "../../third_party/protobuf/python/google/protobuf/internal/encoder.py", + "../../third_party/protobuf/python/google/protobuf/internal/test_util.py", + "../../third_party/protobuf/python/google/protobuf/internal/well_known_types.py", + "../../third_party/protobuf/python/google/protobuf/internal/decoder.py", + "../../third_party/protobuf/python/google/protobuf/internal/api_implementation.cc", + "../../third_party/protobuf/python/google/protobuf/internal/python_message.py", + "../../third_party/protobuf/python/google/protobuf/internal/message_set_extensions.proto", + "../../third_party/protobuf/python/google/protobuf/internal/python_protobuf.cc", + "../../third_party/protobuf/python/google/protobuf/internal/more_extensions_dynamic.proto", + "../../third_party/protobuf/python/google/protobuf/internal/__init__.py", + "../../third_party/protobuf/python/google/protobuf/reflection.py", + "../../third_party/protobuf/python/google/protobuf/__init__.py", + "../../third_party/protobuf/python/google/__init__.py", + "../../third_party/protobuf/third_party/six/six.py", +] + +copy("generator") { + sources = generator_sources + + outputs = [ + "$root_out_dir/{{source_root_relative_dir}}/{{source_file_part}}", + ] +}
diff --git a/tools/media_engagement_preload/OWNERS b/tools/media_engagement_preload/OWNERS new file mode 100644 index 0000000..9c383a5 --- /dev/null +++ b/tools/media_engagement_preload/OWNERS
@@ -0,0 +1,4 @@ +beccahughes@chromium.org +mlamouri@chromium.org + +# COMPONENT: Internals>Media
diff --git a/tools/media_engagement_preload/PRESUBMIT.py b/tools/media_engagement_preload/PRESUBMIT.py new file mode 100644 index 0000000..df19c77f --- /dev/null +++ b/tools/media_engagement_preload/PRESUBMIT.py
@@ -0,0 +1,32 @@ +# Copyright 2017 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. + + +"""Chromium presubmit script for src/tools/media_engagement_preload.""" + + +def _RunMakeDafsaTests(input_api, output_api): + """Runs unittest for make_dafsa if any related file has been modified.""" + files = ('tools/media_engagement_preload/make_dafsa.py', + 'tools/media_engagement_preload/make_dafsa_unittest.py') + if not any(f in input_api.LocalPaths() for f in files): + return [] + test_path = input_api.os_path.join(input_api.PresubmitLocalPath(), + 'make_dafsa_unittest.py') + cmd_name = 'make_dafsa_unittest' + cmd = [input_api.python_executable, test_path] + test_cmd = input_api.Command( + name=cmd_name, + cmd=cmd, + kwargs={}, + message=output_api.PresubmitPromptWarning) + return input_api.RunTests([test_cmd]) + + +def CheckChangeOnUpload(input_api, output_api): + return _RunMakeDafsaTests(input_api, output_api) + + +def CheckChangeOnCommit(input_api, output_api): + return _RunMakeDafsaTests(input_api, output_api)
diff --git a/tools/media_engagement_preload/build.sh b/tools/media_engagement_preload/build.sh new file mode 100644 index 0000000..f3f6ff1 --- /dev/null +++ b/tools/media_engagement_preload/build.sh
@@ -0,0 +1,6 @@ +# Copyright 2017 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. +protoc --python_out . \ + ../../chrome/browser/media/media_engagement_preload.proto \ + --proto_path ../../chrome/browser/media
diff --git a/tools/media_engagement_preload/make_dafsa.py b/tools/media_engagement_preload/make_dafsa.py new file mode 100755 index 0000000..fd73c68 --- /dev/null +++ b/tools/media_engagement_preload/make_dafsa.py
@@ -0,0 +1,488 @@ +#!/usr/bin/env python +# Copyright 2017 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 array +import json +import sys +import os +import urlparse + +SOURCE_ROOT = os.path.join(os.path.dirname( + os.path.abspath(__file__)), os.pardir, os.pardir) + +# Manually inject dependency paths. +sys.path.insert(0, os.path.join( + SOURCE_ROOT, "third_party", "protobuf", "third_party", "six")) +sys.path.insert(0, os.path.join( + SOURCE_ROOT, "third_party", "protobuf", "python")) + +import media_engagement_preload_pb2 + +""" +A Deterministic acyclic finite state automaton (DAFSA) is a compact +representation of an unordered word list (dictionary). + +http://en.wikipedia.org/wiki/Deterministic_acyclic_finite_state_automaton + +This python program converts a list of strings to a byte array in C++. +This python program fetches strings and return values from a gperf file +and generates a C++ file with a byte array representing graph that can be +used as a memory efficient replacement for the perfect hash table. + +The input strings are assumed to consist of printable 7-bit ASCII characters +and the return values are assumed to be one digit integers. + +In this program a DAFSA is a diamond shaped graph starting at a common +source node and ending at a common sink node. All internal nodes contain +a label and each word is represented by the labels in one path from +the source node to the sink node. + +The following python represention is used for nodes: + + Source node: [ children ] + Internal node: (label, [ children ]) + Sink node: None + +The graph is first compressed by prefixes like a trie. In the next step +suffixes are compressed so that the graph gets diamond shaped. Finally +one to one linked nodes are replaced by nodes with the labels joined. + +The order of the operations is crucial since lookups will be performed +starting from the source with no backtracking. Thus a node must have at +most one child with a label starting by the same character. The output +is also arranged so that all jumps are to increasing addresses, thus forward +in memory. + +The generated output has suffix free decoding so that the sign of leading +bits in a link (a reference to a child node) indicate if it has a size of one, +two or three bytes and if it is the last outgoing link from the actual node. +A node label is terminated by a byte with the leading bit set. + +The generated byte array can described by the following BNF: + +<byte> ::= < 8-bit value in range [0x00-0xFF] > + +<char> ::= < printable 7-bit ASCII character, byte in range [0x20-0x7F] > +<end_char> ::= < char + 0x80, byte in range [0xA0-0xFF] > +<return value> ::= < value + 0x80, byte in range [0x80-0x8F] > + +<offset1> ::= < byte in range [0x00-0x3F] > +<offset2> ::= < byte in range [0x40-0x5F] > +<offset3> ::= < byte in range [0x60-0x7F] > + +<end_offset1> ::= < byte in range [0x80-0xBF] > +<end_offset2> ::= < byte in range [0xC0-0xDF] > +<end_offset3> ::= < byte in range [0xE0-0xFF] > + +<prefix> ::= <char> + +<label> ::= <end_char> + | <char> <label> + +<end_label> ::= <return_value> + | <char> <end_label> + +<offset> ::= <offset1> + | <offset2> <byte> + | <offset3> <byte> <byte> + +<end_offset> ::= <end_offset1> + | <end_offset2> <byte> + | <end_offset3> <byte> <byte> + +<offsets> ::= <end_offset> + | <offset> <offsets> + +<source> ::= <offsets> + +<node> ::= <label> <offsets> + | <prefix> <node> + | <end_label> + +<dafsa> ::= <source> + | <dafsa> <node> + +Decoding: + +<char> -> printable 7-bit ASCII character +<end_char> & 0x7F -> printable 7-bit ASCII character +<return value> & 0x0F -> integer +<offset1 & 0x3F> -> integer +((<offset2> & 0x1F>) << 8) + <byte> -> integer +((<offset3> & 0x1F>) << 16) + (<byte> << 8) + <byte> -> integer + +end_offset1, end_offset2 and and_offset3 are decoded same as offset1, +offset2 and offset3 respectively. + +The first offset in a list of offsets is the distance in bytes between the +offset itself and the first child node. Subsequent offsets are the distance +between previous child node and next child node. Thus each offset links a node +to a child node. The distance is always counted between start addresses, i.e. +first byte in decoded offset or first byte in child node. + +Example 1: + +%% +aa, 1 +a, 2 +%% + +The input is first parsed to a list of words: +["aa1", "a2"] + +A fully expanded graph is created from the words: +source = [node1, node4] +node1 = ("a", [node2]) +node2 = ("a", [node3]) +node3 = ("\x01", [sink]) +node4 = ("a", [node5]) +node5 = ("\x02", [sink]) +sink = None + +Compression results in the following graph: +source = [node1] +node1 = ("a", [node2, node3]) +node2 = ("\x02", [sink]) +node3 = ("a\x01", [sink]) +sink = None + +A C++ representation of the compressed graph is generated: + +const unsigned char dafsa[7] = { + 0x81, 0xE1, 0x02, 0x81, 0x82, 0x61, 0x81, +}; + +The bytes in the generated array has the following meaning: + + 0: 0x81 <end_offset1> child at position 0 + (0x81 & 0x3F) -> jump to 1 + + 1: 0xE1 <end_char> label character (0xE1 & 0x7F) -> match "a" + 2: 0x02 <offset1> child at position 2 + (0x02 & 0x3F) -> jump to 4 + + 3: 0x81 <end_offset1> child at position 4 + (0x81 & 0x3F) -> jump to 5 + 4: 0x82 <return_value> 0x82 & 0x0F -> return 2 + + 5: 0x61 <char> label character 0x61 -> match "a" + 6: 0x81 <return_value> 0x81 & 0x0F -> return 1 + +Example 2: + +%% +aa, 1 +bbb, 2 +baa, 1 +%% + +The input is first parsed to a list of words: +["aa1", "bbb2", "baa1"] + +Compression results in the following graph: +source = [node1, node2] +node1 = ("b", [node2, node3]) +node2 = ("aa\x01", [sink]) +node3 = ("bb\x02", [sink]) +sink = None + +A C++ representation of the compressed graph is generated: + +const unsigned char dafsa[11] = { + 0x02, 0x83, 0xE2, 0x02, 0x83, 0x61, 0x61, 0x81, 0x62, 0x62, 0x82, +}; + +The bytes in the generated array has the following meaning: + + 0: 0x02 <offset1> child at position 0 + (0x02 & 0x3F) -> jump to 2 + 1: 0x83 <end_offset1> child at position 2 + (0x83 & 0x3F) -> jump to 5 + + 2: 0xE2 <end_char> label character (0xE2 & 0x7F) -> match "b" + 3: 0x02 <offset1> child at position 3 + (0x02 & 0x3F) -> jump to 5 + 4: 0x83 <end_offset1> child at position 5 + (0x83 & 0x3F) -> jump to 8 + + 5: 0x61 <char> label character 0x61 -> match "a" + 6: 0x61 <char> label character 0x61 -> match "a" + 7: 0x81 <return_value> 0x81 & 0x0F -> return 1 + + 8: 0x62 <char> label character 0x62 -> match "b" + 9: 0x62 <char> label character 0x62 -> match "b" +10: 0x82 <return_value> 0x82 & 0x0F -> return 2 +""" + + +HTTPS_ONLY = 0 +HTTP_AND_HTTPS = 1 + + +class InputError(Exception): + """Exception raised for errors in the input file.""" + + +def to_dafsa(words): + """Generates a DAFSA from a word list and returns the source node. + + Each word is split into characters so that each character is represented by + a unique node. It is assumed the word list is not empty. + """ + if not words: + raise InputError('The origin list must not be empty') + def ToNodes(word): + """Split words into characters""" + if not 0x1F < ord(word[0]) < 0x80: + raise InputError('Origins must be printable 7-bit ASCII') + if len(word) == 1: + return chr(ord(word[0]) & 0x0F), [None] + return word[0], [ToNodes(word[1:])] + return [ToNodes(word) for word in words] + + +def to_words(node): + """Generates a word list from all paths starting from an internal node.""" + if not node: + return [''] + return [(node[0] + word) for child in node[1] for word in to_words(child)] + + +def reverse(dafsa): + """Generates a new DAFSA that is reversed, so that the old sink node becomes + the new source node. + """ + sink = [] + nodemap = {} + + def dfs(node, parent): + """Creates reverse nodes. + + A new reverse node will be created for each old node. The new node will + get a reversed label and the parents of the old node as children. + """ + if not node: + sink.append(parent) + elif id(node) not in nodemap: + nodemap[id(node)] = (node[0][::-1], [parent]) + for child in node[1]: + dfs(child, nodemap[id(node)]) + else: + nodemap[id(node)][1].append(parent) + + for node in dafsa: + dfs(node, None) + return sink + + +def join_labels(dafsa): + """Generates a new DAFSA where internal nodes are merged if there is a one to + one connection. + """ + parentcount = { id(None): 2 } + nodemap = { id(None): None } + + def count_parents(node): + """Count incoming references""" + if id(node) in parentcount: + parentcount[id(node)] += 1 + else: + parentcount[id(node)] = 1 + for child in node[1]: + count_parents(child) + + def join(node): + """Create new nodes""" + if id(node) not in nodemap: + children = [join(child) for child in node[1]] + if len(children) == 1 and parentcount[id(node[1][0])] == 1: + child = children[0] + nodemap[id(node)] = (node[0] + child[0], child[1]) + else: + nodemap[id(node)] = (node[0], children) + return nodemap[id(node)] + + for node in dafsa: + count_parents(node) + return [join(node) for node in dafsa] + + +def join_suffixes(dafsa): + """Generates a new DAFSA where nodes that represent the same word lists + towards the sink are merged. + """ + nodemap = { frozenset(('',)): None } + + def join(node): + """Returns a macthing node. A new node is created if no matching node + exists. The graph is accessed in dfs order. + """ + suffixes = frozenset(to_words(node)) + if suffixes not in nodemap: + nodemap[suffixes] = (node[0], [join(child) for child in node[1]]) + return nodemap[suffixes] + + return [join(node) for node in dafsa] + + +def top_sort(dafsa): + """Generates list of nodes in topological sort order.""" + incoming = {} + + def count_incoming(node): + """Counts incoming references.""" + if node: + if id(node) not in incoming: + incoming[id(node)] = 1 + for child in node[1]: + count_incoming(child) + else: + incoming[id(node)] += 1 + + for node in dafsa: + count_incoming(node) + + for node in dafsa: + incoming[id(node)] -= 1 + + waiting = [node for node in dafsa if incoming[id(node)] == 0] + nodes = [] + + while waiting: + node = waiting.pop() + assert incoming[id(node)] == 0 + nodes.append(node) + for child in node[1]: + if child: + incoming[id(child)] -= 1 + if incoming[id(child)] == 0: + waiting.append(child) + return nodes + + +def encode_links(children, offsets, current): + """Encodes a list of children as one, two or three byte offsets.""" + if not children[0]: + # This is an <end_label> node and no links follow such nodes + assert len(children) == 1 + return [] + guess = 3 * len(children) + assert children + children = sorted(children, key = lambda x: -offsets[id(x)]) + while True: + offset = current + guess + buf = [] + for child in children: + last = len(buf) + distance = offset - offsets[id(child)] + assert distance > 0 and distance < (1 << 21) + + if distance < (1 << 6): + # A 6-bit offset: "s0xxxxxx" + buf.append(distance) + elif distance < (1 << 13): + # A 13-bit offset: "s10xxxxxxxxxxxxx" + buf.append(0x40 | (distance >> 8)) + buf.append(distance & 0xFF) + else: + # A 21-bit offset: "s11xxxxxxxxxxxxxxxxxxxxx" + buf.append(0x60 | (distance >> 16)) + buf.append((distance >> 8) & 0xFF) + buf.append(distance & 0xFF) + # Distance in first link is relative to following record. + # Distance in other links are relative to previous link. + offset -= distance + if len(buf) == guess: + break + guess = len(buf) + # Set most significant bit to mark end of links in this node. + buf[last] |= (1 << 7) + buf.reverse() + return buf + + +def encode_prefix(label): + """Encodes a node label as a list of bytes without a trailing high byte. + + This method encodes a node if there is exactly one child and the + child follows immidiately after so that no jump is needed. This label + will then be a prefix to the label in the child node. + """ + assert label + return [ord(c) for c in reversed(label)] + + +def encode_label(label): + """Encodes a node label as a list of bytes with a trailing high byte >0x80. + """ + buf = encode_prefix(label) + # Set most significant bit to mark end of label in this node. + buf[0] |= (1 << 7) + return buf + + +def encode(dafsa): + """Encodes a DAFSA to a list of bytes""" + output = [] + offsets = {} + + for node in reversed(top_sort(dafsa)): + if (len(node[1]) == 1 and node[1][0] and + (offsets[id(node[1][0])] == len(output))): + output.extend(encode_prefix(node[0])) + else: + output.extend(encode_links(node[1], offsets, len(output))) + output.extend(encode_label(node[0])) + offsets[id(node)] = len(output) + + output.extend(encode_links(dafsa, offsets, len(output))) + output.reverse() + return output + + +def to_proto(data): + """Generates protobuf from a list of encoded bytes.""" + message = media_engagement_preload_pb2.PreloadedData() + message.dafsa = array.array('B', data).tostring() + return message.SerializeToString() + + +def words_to_proto(words): + """Generates protobuf from a word list""" + dafsa = to_dafsa(words) + for fun in (reverse, join_suffixes, reverse, join_suffixes, join_labels): + dafsa = fun(dafsa) + return to_proto(encode(dafsa)) + + +def parse_json(infile): + """Parses the JSON input file and appends a 0 or 1 based on protocol.""" + try: + netlocs = {} + for entry in json.loads(infile): + # Parse the origin and reject any with an invalid protocol. + parsed = urlparse.urlparse(entry) + if parsed.scheme != 'http' and parsed.scheme != 'https': + raise InputError('Invalid protocol: %s' % entry) + + # Store the netloc in netlocs with a flag for either HTTP+HTTPS or HTTPS + # only. The HTTP+HTTPS value is numerically higher than HTTPS only so it + # will take priority. + netlocs[parsed.netloc] = max( + netlocs.get(parsed.netloc, HTTPS_ONLY), + HTTP_AND_HTTPS if parsed.scheme == 'http' else HTTPS_ONLY) + + # Join the numerical values to the netlocs. + output = [] + for location, value in netlocs.iteritems(): + output.append(location + str(value)) + return output + except ValueError: + raise InputError('Failed to parse JSON.') + +def main(): + if len(sys.argv) != 3: + print('usage: %s infile outfile' % sys.argv[0]) + return 1 + with open(sys.argv[1], 'r') as infile, open(sys.argv[2], 'wb') as outfile: + outfile.write(words_to_proto(parse_json(infile.read()))) + return 0 + + +if __name__ == '__main__': + sys.exit(main())
diff --git a/tools/media_engagement_preload/make_dafsa_unittest.py b/tools/media_engagement_preload/make_dafsa_unittest.py new file mode 100755 index 0000000..cdf7965 --- /dev/null +++ b/tools/media_engagement_preload/make_dafsa_unittest.py
@@ -0,0 +1,703 @@ +#!/usr/bin/env python +# Copyright 2017 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 sys +import unittest +import make_dafsa + + +class ToDafsaTest(unittest.TestCase): + def testEmptyInput(self): + """Tests exception is thrown at empty input.""" + words = () + self.assertRaises(make_dafsa.InputError, make_dafsa.to_dafsa, words) + + def testNonASCII(self): + """Tests exception is thrown if illegal characters are used.""" + words1 = ( chr(0x1F) + 'a1', ) + self.assertRaises(make_dafsa.InputError, make_dafsa.to_dafsa, words1) + + words2 = ( 'a' + chr(0x1F) + '1', ) + self.assertRaises(make_dafsa.InputError, make_dafsa.to_dafsa, words2) + + words3 = ( chr(0x80) + 'a1', ) + self.assertRaises(make_dafsa.InputError, make_dafsa.to_dafsa, words3) + + words4 = ( 'a' + chr(0x80) + '1', ) + self.assertRaises(make_dafsa.InputError, make_dafsa.to_dafsa, words4) + + def testChar(self): + """Tests a DAFSA can be created from a single character domain name.""" + words = [ 'a0' ] + node2 = ( chr(0), [ None ] ) + node1 = ( 'a', [ node2 ] ) + source = [ node1 ] + self.assertEqual(make_dafsa.to_dafsa(words), source) + + def testChars(self): + """Tests a DAFSA can be created from a multi character domain name.""" + words = [ 'ab0' ] + node3 = ( chr(0), [ None ] ) + node2 = ( 'b', [ node3 ] ) + node1 = ( 'a', [ node2 ] ) + source = [ node1 ] + self.assertEqual(make_dafsa.to_dafsa(words), source) + + def testWords(self): + """Tests a DAFSA can be created from a sequence of domain names.""" + words = [ 'a0', 'b1' ] + node4 = ( chr(1), [ None ] ) + node3 = ( 'b', [ node4 ] ) + node2 = ( chr(0), [ None ] ) + node1 = ( 'a', [ node2 ] ) + source = [ node1, node3 ] + self.assertEqual(make_dafsa.to_dafsa(words), source) + + +class ToWordsTest(unittest.TestCase): + def testSink(self): + """Tests the sink is exapnded to a list with an empty string.""" + node1 = None + words = [ '' ] + self.assertEqual(make_dafsa.to_words(node1), words) + + def testSingleNode(self): + """Tests a single node is expanded to a list with the label string.""" + + # 'ab' -> [ 'ab' ] + + node1 = ( 'ab', [ None ] ) + words = [ 'ab' ] + self.assertEqual(make_dafsa.to_words(node1), words) + + def testChain(self): + """Tests a sequence of nodes are preoperly expanded.""" + + # 'ab' -> 'cd' => [ 'abcd' ] + + node2 = ( 'cd', [ None ] ) + node1 = ( 'ab', [ node2 ] ) + words = [ 'abcd' ] + self.assertEqual(make_dafsa.to_words(node1), words) + + def testInnerTerminator(self): + """Tests a sequence with an inner terminator is expanded to two strings.""" + + # 'a' -> 'b' + # \ => [ 'ab', 'a' ] + # {sink} + + node2 = ( 'b', [ None ] ) + node1 = ( 'a', [ node2, None ] ) + words = [ 'ab', 'a' ] + self.assertEqual(make_dafsa.to_words(node1), words) + + def testDiamond(self): + """Tests a diamond can be expanded to a word list.""" + + # 'cd' + # / \ + # 'ab' 'gh' + # \ / + # 'ef' + + node4 = ( 'gh', [ None ] ) + node3 = ( 'ef', [ node4 ] ) + node2 = ( 'cd', [ node4 ] ) + node1 = ( 'ab', [ node2, node3 ] ) + words = [ 'abcdgh', 'abefgh' ] + self.assertEqual(make_dafsa.to_words(node1), words) + + +class JoinLabelsTest(unittest.TestCase): + def testLabel(self): + """Tests a single label passes unchanged.""" + + # 'a' => 'a' + + node1 = ( 'a', [ None ] ) + source = [ node1 ] + self.assertEqual(make_dafsa.join_labels(source), source) + + def testInnerTerminator(self): + """Tests a sequence with an inner terminator passes unchanged.""" + + # 'a' -> 'b' 'a' -> 'b' + # \ => \ + # {sink} {sink} + + node2 = ( 'b', [ None ] ) + node1 = ( 'a', [ node2, None ] ) + source = [ node1 ] + self.assertEqual(make_dafsa.join_labels(source), source) + + def testLabels(self): + """Tests a sequence of labels can be joined.""" + + # 'a' -> 'b' => 'ab' + + node2 = ( 'b', [ None ] ) + node1 = ( 'a', [ node2 ] ) + source1 = [ node1 ] + node3 = ( 'ab', [ None ] ) + source2 = [ node3 ] + self.assertEqual(make_dafsa.join_labels(source1), source2) + + def testCompositeLabels(self): + """Tests a sequence of multi character labels can be joined.""" + + # 'ab' -> 'cd' => 'abcd' + + node2 = ( 'cd', [ None ] ) + node1 = ( 'ab', [ node2 ] ) + source1 = [ node1 ] + node3 = ( 'abcd', [ None ] ) + source2 = [ node3 ] + self.assertEqual(make_dafsa.join_labels(source1), source2) + + def testAtomicTrie(self): + """Tests a trie formed DAFSA with atomic labels passes unchanged.""" + + # 'b' 'b' + # / / + # 'a' => 'a' + # \ \ + # 'c' 'c' + + node3 = ( 'c', [ None ] ) + node2 = ( 'b', [ None ] ) + node1 = ( 'a', [ node2, node3 ] ) + source = [ node1 ] + self.assertEqual(make_dafsa.join_labels(source), source) + + def testReverseAtomicTrie(self): + """Tests a reverse trie formed DAFSA with atomic labels passes unchanged.""" + + # 'a' 'a' + # \ \ + # 'c' => 'c' + # / / + # 'b' 'b' + + node3 = ( 'c', [ None ] ) + node2 = ( 'b', [ node3 ] ) + node1 = ( 'a', [ node3 ] ) + source = [ node1, node2 ] + self.assertEqual(make_dafsa.join_labels(source), source) + + def testChainedTrie(self): + """Tests a trie formed DAFSA with chained labels can be joined.""" + + # 'c' -> 'd' 'cd' + # / / + # 'a' -> 'b' => 'ab' + # \ \ + # 'e' -> 'f' 'ef' + + node6 = ( 'f', [ None ] ) + node5 = ( 'e', [ node6 ] ) + node4 = ( 'd', [ None ] ) + node3 = ( 'c', [ node4 ] ) + node2 = ( 'b', [ node3, node5 ] ) + node1 = ( 'a', [ node2 ] ) + source1 = [ node1 ] + node9 = ( 'ef', [ None ] ) + node8 = ( 'cd', [ None ] ) + node7 = ( 'ab', [ node8, node9 ] ) + source2 = [ node7 ] + self.assertEqual(make_dafsa.join_labels(source1), source2) + + def testReverseChainedTrie(self): + """Tests a reverse trie formed DAFSA with chained labels can be joined.""" + + # 'a' -> 'b' 'ab' + # \ \ + # 'e' -> 'f' => 'ef' + # / / + # 'c' -> 'd' 'cd' + + node6 = ( 'f', [ None ] ) + node5 = ( 'e', [ node6 ] ) + node4 = ( 'd', [ node5 ] ) + node3 = ( 'c', [ node4 ] ) + node2 = ( 'b', [ node5 ] ) + node1 = ( 'a', [ node2 ] ) + source1 = [ node1, node3 ] + node9 = ( 'ef', [ None ] ) + node8 = ( 'cd', [ node9 ] ) + node7 = ( 'ab', [ node9 ] ) + source2 = [ node7, node8 ] + self.assertEqual(make_dafsa.join_labels(source1), source2) + + +class JoinSuffixesTest(unittest.TestCase): + def testSingleLabel(self): + """Tests a single label passes unchanged.""" + + # 'a' => 'a' + + node1 = ( 'a', [ None ] ) + source = [ node1 ] + self.assertEqual(make_dafsa.join_suffixes(source), source) + + def testInnerTerminator(self): + """Tests a sequence with an inner terminator passes unchanged.""" + + # 'a' -> 'b' 'a' -> 'b' + # \ => \ + # {sink} {sink} + + node2 = ( 'b', [ None ] ) + node1 = ( 'a', [ node2, None ] ) + source = [ node1 ] + self.assertEqual(make_dafsa.join_suffixes(source), source) + + def testDistinctTrie(self): + """Tests a trie formed DAFSA with distinct labels passes unchanged.""" + + # 'b' 'b' + # / / + # 'a' => 'a' + # \ \ + # 'c' 'c' + + node3 = ( 'c', [ None ] ) + node2 = ( 'b', [ None ] ) + node1 = ( 'a', [ node2, node3 ] ) + source = [ node1 ] + self.assertEqual(make_dafsa.join_suffixes(source), source) + + def testReverseDistinctTrie(self): + """Tests a reverse trie formed DAFSA with distinct labels passes unchanged. + """ + + # 'a' 'a' + # \ \ + # 'c' => 'c' + # / / + # 'b' 'b' + + node3 = ( 'c', [ None ] ) + node2 = ( 'b', [ node3 ] ) + node1 = ( 'a', [ node3 ] ) + source = [ node1, node2 ] + self.assertEqual(make_dafsa.join_suffixes(source), source) + + def testJoinTwoHeads(self): + """Tests two heads can be joined even if there is something else between.""" + + # 'a' ------'a' + # / + # 'b' => 'b' / + # / + # 'a' --- + # + # The picture above should shows that the new version should have just one + # instance of the node with label 'a'. + + node3 = ( 'a', [ None ] ) + node2 = ( 'b', [ None ] ) + node1 = ( 'a', [ None ] ) + source1 = [ node1, node2, node3 ] + source2 = make_dafsa.join_suffixes(source1) + + # Both versions should expand to the same content. + self.assertEqual(source1, source2) + # But the new version should have just one instance of 'a'. + self.assertIs(source2[0], source2[2]) + + def testJoinTails(self): + """Tests tails can be joined.""" + + # 'a' -> 'c' 'a' + # \ + # => 'c' + # / + # 'b' -> 'c' 'b' + + node4 = ( 'c', [ None ] ) + node3 = ( 'b', [ node4 ] ) + node2 = ( 'c', [ None ] ) + node1 = ( 'a', [ node2 ] ) + source1 = [ node1, node3 ] + source2 = make_dafsa.join_suffixes(source1) + + # Both versions should expand to the same content. + self.assertEqual(source1, source2) + # But the new version should have just one tail. + self.assertIs(source2[0][1][0], source2[1][1][0]) + + def testMakeRecursiveTrie(self): + """Tests recursive suffix join.""" + + # 'a' -> 'e' -> 'g' 'a' + # \ + # 'e' + # / \ + # 'b' -> 'e' -> 'g' 'b' \ + # \ + # => 'g' + # / + # 'c' -> 'f' -> 'g' 'c' / + # \ / + # 'f' + # / + # 'd' -> 'f' -> 'g' 'd' + + node7 = ( 'g', [ None ] ) + node6 = ( 'f', [ node7 ] ) + node5 = ( 'e', [ node7 ] ) + node4 = ( 'd', [ node6 ] ) + node3 = ( 'c', [ node6 ] ) + node2 = ( 'b', [ node5 ] ) + node1 = ( 'a', [ node5 ] ) + source1 = [ node1, node2, node3, node4 ] + source2 = make_dafsa.join_suffixes(source1) + + # Both versions should expand to the same content. + self.assertEqual(source1, source2) + # But the new version should have just one 'e'. + self.assertIs(source2[0][1][0], source2[1][1][0]) + # And one 'f'. + self.assertIs(source2[2][1][0], source2[3][1][0]) + # And one 'g'. + self.assertIs(source2[0][1][0][1][0], source2[2][1][0][1][0]) + + def testMakeDiamond(self): + """Test we can join suffixes of a trie.""" + + # 'b' -> 'd' 'b' + # / / \ + # 'a' => 'a' 'd' + # \ \ / + # 'c' -> 'd' 'c' + + node5 = ( 'd', [ None ] ) + node4 = ( 'c', [ node5 ] ) + node3 = ( 'd', [ None ] ) + node2 = ( 'b', [ node3 ] ) + node1 = ( 'a', [ node2, node4 ] ) + source1 = [ node1 ] + source2 = make_dafsa.join_suffixes(source1) + + # Both versions should expand to the same content. + self.assertEqual(source1, source2) + # But the new version should have just one 'd'. + self.assertIs(source2[0][1][0][1][0], source2[0][1][1][1][0]) + + def testJoinOneChild(self): + """Tests that we can join some children but not all.""" + + # 'c' ----'c' + # / / / + # 'a' 'a' / + # \ \ / + # 'd' 'd'/ + # => / + # 'c' / + # / / + # 'b' 'b' + # \ \ + # 'e' 'e' + + node6 = ( 'e', [ None ] ) + node5 = ( 'c', [ None ] ) + node4 = ( 'b', [ node5, node6 ] ) + node3 = ( 'd', [ None ] ) + node2 = ( 'c', [ None ] ) + node1 = ( 'a', [ node2, node3 ] ) + source1 = [ node1, node4 ] + source2 = make_dafsa.join_suffixes(source1) + + # Both versions should expand to the same content. + self.assertEqual(source1, source2) + # But the new version should have just one 'c'. + self.assertIs(source2[0][1][0], source2[1][1][0]) + + +class ReverseTest(unittest.TestCase): + def testAtomicLabel(self): + """Tests an atomic label passes unchanged.""" + + # 'a' => 'a' + + node1 = ( 'a', [ None ] ) + source = [ node1 ] + self.assertEqual(make_dafsa.reverse(source), source) + + def testLabel(self): + """Tests that labels are reversed.""" + + # 'ab' => 'ba' + + node1 = ( 'ab', [ None ] ) + source1 = [ node1 ] + node2 = ( 'ba', [ None ] ) + source2 = [ node2 ] + self.assertEqual(make_dafsa.reverse(source1), source2) + + def testChain(self): + """Tests that edges are reversed.""" + + # 'a' -> 'b' => 'b' -> 'a' + + node2 = ( 'b', [ None ] ) + node1 = ( 'a', [ node2 ] ) + source1 = [ node1 ] + node4 = ( 'a', [ None ] ) + node3 = ( 'b', [ node4 ] ) + source2 = [ node3 ] + self.assertEqual(make_dafsa.reverse(source1), source2) + + def testInnerTerminator(self): + """Tests a sequence with an inner terminator can be reversed.""" + + # 'a' -> 'b' 'b' -> 'a' + # \ => / + # {sink} ------ + + node2 = ( 'b', [ None ] ) + node1 = ( 'a', [ node2, None ] ) + source1 = [ node1 ] + node4 = ( 'a', [ None ] ) + node3 = ( 'b', [ node4 ] ) + source2 = [ node3, node4 ] + self.assertEqual(make_dafsa.reverse(source1), source2) + + def testAtomicTrie(self): + """Tests a trie formed DAFSA can be reversed.""" + + # 'b' 'b' + # / \ + # 'a' => 'a' + # \ / + # 'c' 'c' + + node3 = ( 'c', [ None ] ) + node2 = ( 'b', [ None ] ) + node1 = ( 'a', [ node2, node3 ] ) + source1 = [ node1 ] + node6 = ( 'a', [ None ] ) + node5 = ( 'c', [ node6 ] ) + node4 = ( 'b', [ node6 ] ) + source2 = [ node4, node5 ] + self.assertEqual(make_dafsa.reverse(source1), source2) + + def testReverseAtomicTrie(self): + """Tests a reverse trie formed DAFSA can be reversed.""" + + # 'a' 'a' + # \ / + # 'c' => 'c' + # / \ + # 'b' 'b' + + node3 = ( 'c', [ None ] ) + node2 = ( 'b', [ node3 ] ) + node1 = ( 'a', [ node3 ] ) + source1 = [ node1, node2 ] + node6 = ( 'b', [ None ] ) + node5 = ( 'a', [ None ] ) + node4 = ( 'c', [ node5, node6 ] ) + source2 = [ node4 ] + self.assertEqual(make_dafsa.reverse(source1), source2) + + def testDiamond(self): + """Tests we can reverse both edges and nodes in a diamond.""" + + # 'cd' 'dc' + # / \ / \ + # 'ab' 'gh' => 'hg' 'ba' + # \ / \ / + # 'ef' 'fe' + + node4 = ( 'gh', [ None ] ) + node3 = ( 'ef', [ node4 ] ) + node2 = ( 'cd', [ node4 ] ) + node1 = ( 'ab', [ node2, node3 ] ) + source1 = [ node1 ] + node8 = ( 'ba', [ None ] ) + node7 = ( 'fe', [ node8 ] ) + node6 = ( 'dc', [ node8 ] ) + node5 = ( 'hg', [ node6, node7 ] ) + source2 = [ node5 ] + self.assertEqual(make_dafsa.reverse(source1), source2) + + +class TopSortTest(unittest.TestCase): + def testNode(self): + """Tests a DAFSA with one node can be sorted.""" + + # 'a' => [ 'a' ] + + node1 = ( 'a', [ None ] ) + source = [ node1 ] + nodes = [ node1 ] + self.assertEqual(make_dafsa.top_sort(source), nodes) + + def testDiamond(self): + """Tests nodes in a diamond can be sorted.""" + + # 'b' + # / \ + # 'a' 'd' + # \ / + # 'c' + + node4 = ( 'd', [ None ] ) + node3 = ( 'c', [ node4 ] ) + node2 = ( 'b', [ node4 ] ) + node1 = ( 'a', [ node2, node3 ] ) + source = [ node1 ] + nodes = make_dafsa.top_sort(source) + self.assertLess(nodes.index(node1), nodes.index(node2)) + self.assertLess(nodes.index(node2), nodes.index(node4)) + self.assertLess(nodes.index(node3), nodes.index(node4)) + + +class EncodePrefixTest(unittest.TestCase): + def testChar(self): + """Tests to encode a single character prefix.""" + label = 'a' + bytes = [ ord('a') ] + self.assertEqual(make_dafsa.encode_prefix(label), bytes) + + def testChars(self): + """Tests to encode a multi character prefix.""" + label = 'ab' + bytes = [ ord('b'), ord('a') ] + self.assertEqual(make_dafsa.encode_prefix(label), bytes) + + +class EncodeLabelTest(unittest.TestCase): + def testChar(self): + """Tests to encode a single character label.""" + label = 'a' + bytes = [ ord('a') + 0x80 ] + self.assertEqual(make_dafsa.encode_label(label), bytes) + + def testChars(self): + """Tests to encode a multi character label.""" + label = 'ab' + bytes = [ ord('b') + 0x80, ord('a') ] + self.assertEqual(make_dafsa.encode_label(label), bytes) + + +class EncodeLinksTest(unittest.TestCase): + def testEndLabel(self): + """Tests to encode link to the sink.""" + children = [ None ] + offsets = {} + bytes = 0 + output = [] + self.assertEqual(make_dafsa.encode_links(children, offsets, bytes), + output) + + def testOneByteOffset(self): + """Tests to encode a single one byte offset.""" + node = ( '', [ None ] ) + children = [ node ] + offsets = { id(node) : 2 } + bytes = 5 + output = [ 132 ] + self.assertEqual(make_dafsa.encode_links(children, offsets, bytes), + output) + + def testOneByteOffsets(self): + """Tests to encode a sequence of one byte offsets.""" + node1 = ( '', [ None ] ) + node2 = ( '', [ None ] ) + children = [ node1, node2 ] + offsets = { id(node1) : 2, id(node2) : 1 } + bytes = 5 + output = [ 129, 5 ] + self.assertEqual(make_dafsa.encode_links(children, offsets, bytes), + output) + + def testTwoBytesOffset(self): + """Tests to encode a single two byte offset.""" + node = ( '', [ None ] ) + children = [ node ] + offsets = { id(node) : 2 } + bytes = 1005 + output = [ 237, 195] + self.assertEqual(make_dafsa.encode_links(children, offsets, bytes), + output) + + def testTwoBytesOffsets(self): + """Tests to encode a sequence of two byte offsets.""" + node1 = ( '', [ None ] ) + node2 = ( '', [ None ] ) + node3 = ( '', [ None ] ) + children = [ node1, node2, node3 ] + offsets = { id(node1) : 1002, id(node2) : 2, id(node3) : 2002 } + bytes = 3005 + output = [ 232, 195, 232, 67, 241, 67 ] + self.assertEqual(make_dafsa.encode_links(children, offsets, bytes), + output) + + def testThreeBytesOffset(self): + """Tests to encode a single three byte offset.""" + node = ( '', [ None ] ) + children = [ node ] + offsets = { id(node) : 2 } + bytes = 100005 + output = [ 166, 134, 225 ] + self.assertEqual(make_dafsa.encode_links(children, offsets, bytes), + output) + + def testThreeBytesOffsets(self): + """Tests to encode a sequence of three byte offsets.""" + node1 = ( '', [ None ] ) + node2 = ( '', [ None ] ) + node3 = ( '', [ None ] ) + children = [ node1, node2, node3 ] + offsets = { id(node1) : 100002, id(node2) : 2, id(node3) : 200002 } + bytes = 300005 + output = [ 160, 134, 225, 160, 134, 97, 172, 134, 97 ] + self.assertEqual(make_dafsa.encode_links(children, offsets, bytes), + output) + + def testOneTwoThreeBytesOffsets(self): + """Tests to encode offsets of different sizes.""" + node1 = ( '', [ None ] ) + node2 = ( '', [ None ] ) + node3 = ( '', [ None ] ) + children = [ node1, node2, node3 ] + offsets = { id(node1) : 10003, id(node2) : 10002, id(node3) : 100002 } + bytes = 300005 + output = [ 129, 143, 95, 97, 74, 13, 99 ] + self.assertEqual(make_dafsa.encode_links(children, offsets, bytes), + output) + + +class ExamplesTest(unittest.TestCase): + def testExample1(self): + """Tests Example 1 from make_dafsa.py.""" + infile = '["https://www.example.com:8081", "http://www.example.org"]' + outfile = "\n\x1c\x81www.example\xae\x02\x89com:8081\x80org\x81" + self.assertEqual(make_dafsa.words_to_proto(make_dafsa.parse_json(infile)), + outfile) + + def testExample2(self): + """Tests Example 2 from make_dafsa.py.""" + infile = '["https://www.example.org", "http://www.google.com"]' + outfile = "\n\x1e\x81www\xae\x02\x8bgoogle.com\x81example.org\x80" + self.assertEqual(make_dafsa.words_to_proto(make_dafsa.parse_json(infile)), + outfile) + + def testBadJSON(self): + """Tests make_dafsa.py with bad JSON input.""" + self.assertRaises(make_dafsa.InputError, make_dafsa.parse_json, "badinput") + + def testInvalidProtocol(self): + """Tests make_dafsa.py with an invalid protocol.""" + self.assertRaises(make_dafsa.InputError, make_dafsa.parse_json, + '["ftp://www.example.com"]') + + +if __name__ == '__main__': + unittest.main()
diff --git a/tools/media_engagement_preload/media_engagement_preload_pb2.py b/tools/media_engagement_preload/media_engagement_preload_pb2.py new file mode 100644 index 0000000..0cde5091 --- /dev/null +++ b/tools/media_engagement_preload/media_engagement_preload_pb2.py
@@ -0,0 +1,63 @@ +# Copyright 2017 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. + +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: media_engagement_preload.proto + +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import descriptor_pb2 +# @@protoc_insertion_point(imports) + + + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='media_engagement_preload.proto', + package='chrome_browser_media', + serialized_pb='\n\x1emedia_engagement_preload.proto\x12\x14\x63hrome_browser_media\"\x1e\n\rPreloadedData\x12\r\n\x05\x64\x61\x66sa\x18\x01 \x01(\x0c\x42\x02H\x03') + + + + +_PRELOADEDDATA = _descriptor.Descriptor( + name='PreloadedData', + full_name='chrome_browser_media.PreloadedData', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='dafsa', full_name='chrome_browser_media.PreloadedData.dafsa', index=0, + number=1, type=12, cpp_type=9, label=1, + has_default_value=False, default_value="", + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + extension_ranges=[], + serialized_start=56, + serialized_end=86, +) + +DESCRIPTOR.message_types_by_name['PreloadedData'] = _PRELOADEDDATA + +class PreloadedData(_message.Message): + __metaclass__ = _reflection.GeneratedProtocolMessageType + DESCRIPTOR = _PRELOADEDDATA + + # @@protoc_insertion_point(class_scope:chrome_browser_media.PreloadedData) + + +DESCRIPTOR.has_options = True +DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), 'H\003') +# @@protoc_insertion_point(module_scope)
diff --git a/tools/memory/asan/blacklist_win.txt b/tools/memory/asan/blacklist_win.txt index c41f914..9c9ee19 100644 --- a/tools/memory/asan/blacklist_win.txt +++ b/tools/memory/asan/blacklist_win.txt
@@ -19,12 +19,27 @@ fun:*ResolverThunk*sandbox* fun:*Target*SandboxFactory*sandbox* fun:*ProcessState*sandbox* -src:*pe_image.h -src:*pe_image.cc -src:*resolver_32.cc + +# These functions run pre-binding in the 64 bit build, when the shadow is not +# available, and thus can't be instrumented. +fun:*InternalThunk* +fun:*TargetNtCreateFile64 +fun:*TargetNtMapViewOfSection* +fun:*TargetNtOpenFile64 +fun:*TargetNtOpenProcessToken64 +fun:*TargetNtOpenThreadToken* +fun:*TargetNtQueryAttributesFile64 +fun:*TargetNtSetInformationThread +fun:*TargetNtSetInformationThread64 +fun:*TargetNtUnmapViewOfSection64 + src:*filesystem_interception.cc +src:*interceptors_64.cc +src:*pe_image.cc +src:*pe_image.h src:*process_thread_interception.cc src:*registry_interception.cc +src:*resolver_32.cc src:*sandbox_nt_util.cc src:*sync_interception.cc ################################################################################
diff --git a/tools/metrics/BUILD.gn b/tools/metrics/BUILD.gn index 9e131b7a..fbad35e 100644 --- a/tools/metrics/BUILD.gn +++ b/tools/metrics/BUILD.gn
@@ -43,3 +43,71 @@ ":rappor_xml", ] } + +# This group defines the isolate files needed to run metrics_python_tests.py on +# on bots. This also tells the build system when the tests should be re-run - +# when one of the dependent files changes. +# +# When adding new entries to this test suite, you can test things locally with +# isolation using the following command: +# +# tools/mb/mb.py run out/gn metrics_python_tests -- \ +# --isolated-script-test-output=/tmp/output.json +# +group("metrics_python_tests") { + data = [ + # The run_isolated_script_test.py script and its dependencies. + "//testing/scripts/run_isolated_script_test.py", + "//testing/scripts/common.py", + "//testing/xvfb.py", + "//testing/test_env.py", + "//third_party/typ/", + + # Scripts we depend on. Their unit tests are also included. + "//tools/json_comment_eater/json_comment_eater.py", + "//tools/json_comment_eater/json_comment_eater_test.py", + "//tools/json_comment_eater/everything.json", + "//tools/json_comment_eater/everything_expected.json", + "//tools/json_to_struct/element_generator.py", + "//tools/json_to_struct/element_generator_test.py", + "//tools/json_to_struct/json_to_struct.py", + "//tools/json_to_struct/struct_generator.py", + "//tools/json_to_struct/struct_generator_test.py", + + # The metrics_python_tests.py runner and its dependencies. + "//tools/metrics/metrics_python_tests.py", + + "//tools/metrics/actions/action_utils.py", + "//tools/metrics/actions/extract_actions.py", + "//tools/metrics/actions/extract_actions_test.py", + "//tools/metrics/actions/pretty_print.py", + "//tools/metrics/actions/print_style.py", + + "//tools/metrics/common/diff_util.py", + "//tools/metrics/common/models.py", + "//tools/metrics/common/path_util.py", + "//tools/metrics/common/presubmit_util.py", + "//tools/metrics/common/pretty_print_xml.py", + + "//tools/metrics/histograms/extract_histograms.py", + "//tools/metrics/histograms/generate_expired_histograms_array.py", + "//tools/metrics/histograms/generate_expired_histograms_array_unittest.py", + "//tools/metrics/histograms/merge_xml.py", + + "//tools/metrics/ukm/model.py", + "//tools/metrics/ukm/pretty_print_test.py", + + "//tools/python/google/path_utils.py", + + "//tools/variations/fieldtrial_to_struct_unittest.py", + "//tools/variations/fieldtrial_to_struct.py", + "//tools/variations/fieldtrial_util_unittest.py", + "//tools/variations/fieldtrial_util.py", + "//tools/variations/unittest_data/expected_output.cc", + "//tools/variations/unittest_data/expected_output.h", + "//tools/variations/unittest_data/test_config.json", + "//components/variations/field_trial_config/field_trial_testing_config_schema.json", + "//components/variations/service/generate_ui_string_overrider.py", + "//components/variations/service/generate_ui_string_overrider_unittest.py", + ] +}
diff --git a/tools/metrics/OWNERS b/tools/metrics/OWNERS index 559d7b21..c929027 100644 --- a/tools/metrics/OWNERS +++ b/tools/metrics/OWNERS
@@ -1,8 +1,3 @@ -asvitkine@chromium.org -holte@chromium.org -isherman@chromium.org -jwd@chromium.org -mpearson@chromium.org -rkaplow@chromium.org +file://base/metrics/OWNERS # COMPONENT: Internals>Metrics
diff --git a/tools/metrics/actions/OWNERS b/tools/metrics/actions/OWNERS index 038b3f4..60794e4 100644 --- a/tools/metrics/actions/OWNERS +++ b/tools/metrics/actions/OWNERS
@@ -1,3 +1,3 @@ # Metrics changes should always be reviewed by owners. -per-file actions.xml=file://tools/metrics/OWNERS +per-file actions.xml=file://base/metrics/OWNERS per-file actions.xml=set noparent
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml index a4118f1..d732b0d 100644 --- a/tools/metrics/actions/actions.xml +++ b/tools/metrics/actions/actions.xml
@@ -677,6 +677,51 @@ <description>Please enter the description of this user action.</description> </action> +<action name="Accel_Media_Next_Track"> + <owner>warx@chromium.org</owner> + <description>User pressed the next track media control button.</description> +</action> + +<action name="Accel_Media_PlayPause"> + <owner>warx@chromium.org</owner> + <description>User pressed the play/pause media control button.</description> +</action> + +<action name="Accel_Media_Prev_Track"> + <owner>warx@chromium.org</owner> + <description> + User pressed the previous track media control button. + </description> +</action> + +<action name="Accel_Move_Window_To_Above_Display"> + <owner>warx@chromium.org</owner> + <description> + User presses accelerator trying to move active window to above display. + </description> +</action> + +<action name="Accel_Move_Window_To_Below_Display"> + <owner>warx@chromium.org</owner> + <description> + User presses accelerator trying to move active window to below display. + </description> +</action> + +<action name="Accel_Move_Window_To_Left_Display"> + <owner>warx@chromium.org</owner> + <description> + User presses accelerator trying to move active window to left display. + </description> +</action> + +<action name="Accel_Move_Window_To_Right_Display"> + <owner>warx@chromium.org</owner> + <description> + User presses accelerator trying to move active window to right display. + </description> +</action> + <action name="Accel_NewTab_T"> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <description>Please enter the description of this user action.</description> @@ -727,6 +772,14 @@ <description>Please enter the description of this user action.</description> </action> +<action name="Accel_PowerButton_Screenshot"> + <owner>warx@chromium.org</owner> + <description> + User takes a screenshot by pressing power button and volume down key + simultaneously on tablet mode. + </description> +</action> + <action name="Accel_PrevWindow_F5"> <obsolete>Unused as of 08/2017</obsolete> <owner>jamescook@chromium.org</owner> @@ -811,7 +864,7 @@ <description>Please enter the description of this user action.</description> </action> -<action name="Accel_Search_LWin"> +<action name="Accel_Search_LWin" not_user_triggered="true"> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <description>Please enter the description of this user action.</description> </action> @@ -937,6 +990,14 @@ <description>Please enter the description of this user action.</description> </action> +<action name="Accel_Toggle_Dictation"> + <owner>dtseng@chromium.org</owner> + <description> + Metric recorded when the user starts or stops dictation using keyboard + shortcut. + </description> +</action> + <action name="Accel_Toggle_High_Contrast"> <owner>dmazzoni@chromium.org</owner> <description> @@ -1008,8 +1069,13 @@ </action> <action name="Accel_Touch_Hud_Clear"> - <owner>Please list the metric's owners. Add more owner tags as needed.</owner> - <description>Please enter the description of this user action.</description> + <obsolete> + Deprecated 12/2017. Keyboard accelerator replaced with flag. + </obsolete> + <owner>jamescook@chromium.org</owner> + <description> + Debugging accelerator used to turn off the touch hud projection feature. + </description> </action> <action name="Accel_VolumeDown_F9"> @@ -1089,6 +1155,25 @@ </description> </action> +<action name="Accessibility.CrosSelectToSpeak.CancelSpeech"> + <owner>katie@chromium.org</owner> + <description> + A Chrome OS user manually cancels Select To Speak while it is speaking. + </description> +</action> + +<action name="Accessibility.CrosSelectToSpeak.LoadSettings"> + <owner>katie@chromium.org</owner> + <description> + A Chrome OS user loads the Select To Speak settings page. + </description> +</action> + +<action name="Accessibility.CrosSelectToSpeak.StartSpeech"> + <owner>katie@chromium.org</owner> + <description>A Chrome OS user manually starts Select To Speak.</description> +</action> + <action name="Accessibility.TwoFingersHeldGeneratedSpokenFeedbackCountdown"> <owner>dmazzoni@chromium.org</owner> <description> @@ -1142,6 +1227,46 @@ </description> </action> +<action name="Android.BookmarkPage.RemoveItem"> + <owner>huayinz@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + User removed an item on the native Android bookmark page by clicking + "delete" from the "more" menu. + </description> +</action> + +<action name="Android.BookmarkPage.SelectFromMenu"> + <owner>huayinz@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + User selected an item on the native Android bookmark page by clicking + "select" from the "more" menu. + </description> +</action> + +<action name="Android.ChromeHome.AcceptedSurvey"> + <obsolete> + Deprecated 1/2018. Replaced with the + Android.ChromeHome.Survey.InfoBarClosingState histogram. + </obsolete> + <owner>danielpark@chromium.org</owner> + <description> + User clicked on the invite to take a survey in the survey infobar. + </description> +</action> + +<action name="Android.ChromeHome.ClickedSurveyInfoBarCloseButton"> + <obsolete> + Deprecated 1/2018. Replaced with the + Android.ChromeHome.Survey.InfoBarClosingState histogram. + </obsolete> + <owner>danielpark@chromium.org</owner> + <description> + User dismissed the survey infobar by tapping on its close button. + </description> +</action> + <action name="Android.ChromeHome.Closed"> <owner>mdjones@chromium.org</owner> <owner>twellington@chromium.org</owner> @@ -1276,6 +1401,15 @@ </description> </action> +<action name="Android.ChromeHome.OptOutSnackbarClicked"> + <owner>mdjones@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + User clicked the 'Take Survey' button on the snackbar shown after they opted + out of Chrome Home. + </description> +</action> + <action name="Android.ChromeHome.ShowBookmarks"> <owner>mdjones@chromium.org</owner> <owner>twellington@chromium.org</owner> @@ -1308,6 +1442,11 @@ <description>User showed the suggestions bottom sheet content.</description> </action> +<action name="Android.ChromeHome.Survey.ShowSurveyInfoBar"> + <owner>danielpark@chromium.org</owner> + <description>The survey infobar was displayed.</description> +</action> + <action name="Android.ContentDetectorActivated"> <owner>twellington@chromium.org</owner> <description> @@ -1361,6 +1500,15 @@ </description> </action> +<action name="Android.DownloadManager.RemoveItem"> + <owner>huayinz@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + User removed an item on the native Android download page by clicking + "delete" from the "more" menu. + </description> +</action> + <action name="Android.DownloadManager.Search"> <owner>dfalcantara@chromium.org</owner> <owner>twellington@chromium.org</owner> @@ -1531,6 +1679,14 @@ <description>Promo banner for an instant app has been dismissed.</description> </action> +<action name="Android.InstantApps.BannerDismissedAppIsDefault"> + <owner>thildebr@chromium.org</owner> + <description> + A promo banner shown when opening the instant app is default has been + dismissed. + </description> +</action> + <action name="Android.InstantApps.BannerOpen"> <owner>mariakhomenko@chromium.org</owner> <description> @@ -1538,11 +1694,38 @@ </description> </action> +<action name="Android.InstantApps.BannerOpenAppIsDefault"> + <owner>thildebr@chromium.org</owner> + <description> + User clicked "Open App" button on an instant apps banner that was + shown when opening the app was default, signaling that they were using the + mobile web first, and decided to switch over to the instant app. + </description> +</action> + <action name="Android.InstantApps.BannerShown" not_user_triggered="true"> <owner>mariakhomenko@chromium.org</owner> <description>Promo banner for an instant app has been displayed.</description> </action> +<action name="Android.InstantApps.BannerShownAppIsDefault" + not_user_triggered="true"> + <owner>thildebr@chromium.org</owner> + <description> + Promo banner for an instant app has been displayed when opening the app is + default. + </description> +</action> + +<action name="Android.InstantApps.InstantAppsEligiblePageLoaded" + not_user_triggered="true"> + <owner>mariakhomenko@chromium.org</owner> + <description> + A page finished loading in Chrome that could have been loaded in an Instant + App. + </description> +</action> + <action name="Android.InstantApps.LaunchedByDefault" not_user_triggered="true"> <owner>mariakhomenko@chromium.org</owner> <description> @@ -1558,6 +1741,14 @@ </description> </action> +<action name="Android.InstantApps.OpenInstantAppButtonShown"> + <owner>mariakhomenko@chromium.org</owner> + <description> + Recorded when the user opened PageInfo dialog and saw a button to launch an + Instant App there. + </description> +</action> + <action name="Android.LauncherShortcut.NewIncognitoTab"> <owner>twellington@chromium.org</owner> <description> @@ -1633,6 +1824,13 @@ </description> </action> +<action name="Android.PhoneIntent"> + <owner>mariakhomenko@chromium.org</owner> + <description> + A user clicked on a telephone number link in Chrome content. + </description> +</action> + <action name="AppCloseButton_Clk"> <obsolete>Unused as of 08/2017</obsolete> <owner>jamescook@chromium.org</owner> @@ -1640,23 +1838,41 @@ </action> <action name="AppList_AutoLaunchCanceled"> + <obsolete>Voice search in Launcher is not supported anymore.</obsolete> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <description>Please enter the description of this user action.</description> </action> <action name="AppList_AutoLaunched"> + <obsolete>Voice search in Launcher is not supported anymore.</obsolete> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <description>Please enter the description of this user action.</description> </action> <action name="AppList_ClickOnApp"> + <owner>vadimt@chromium.org</owner> + <description> + User clicks an icon in app grid. Chrome and Files are counted. Folders, + suggested apps and search results aren't. + </description> +</action> + +<action name="AppList_ClickOnAppFromSearch"> + <obsolete> + Deprecated in favor of a more general AppList_OpenSearchResult event. + </obsolete> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <description>Please enter the description of this user action.</description> </action> -<action name="AppList_ClickOnAppFromSearch"> - <owner>Please list the metric's owners. Add more owner tags as needed.</owner> - <description>Please enter the description of this user action.</description> +<action name="AppList_EnterSearch"> + <owner>vadimt@chromium.org</owner> + <description>CrOS Launcher entered search mode.</description> +</action> + +<action name="AppList_FullToPeeking"> + <owner>vadimt@chromium.org</owner> + <description>CrOS Launcher went from full to peeking state.</description> </action> <action name="AppList_HotwordRecognized"> @@ -1664,28 +1880,60 @@ <description>Please enter the description of this user action.</description> </action> +<action name="AppList_LeaveSearch"> + <owner>vadimt@chromium.org</owner> + <description>CrOS Launcher left search mode.</description> +</action> + +<action name="AppList_OpenSearchResult"> + <owner>vadimt@chromium.org</owner> + <description>User opens a search result in CrOS Launcher.</description> +</action> + +<action name="AppList_OpenSuggestedApp"> + <owner>vadimt@chromium.org</owner> + <description> + User opens an app from the suggestions row in CrOS Launcher. + </description> +</action> + +<action name="AppList_PeekingToFull"> + <owner>vadimt@chromium.org</owner> + <description> + CrOS Launcher went from peeking to full state or, in a search mode, from + half to full. + </description> +</action> + <action name="AppList_Search"> + <obsolete>Name was bad. Renamed to AppList_OpenSearchResult.</obsolete> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <description>Please enter the description of this user action.</description> </action> <action name="AppList_SearchedBySpeech"> + <obsolete>App list doesn't have voice search anymore.</obsolete> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <description>Please enter the description of this user action.</description> </action> <action name="AppList_VoiceSearchCanceled"> + <obsolete>App list doesn't have voice search anymore.</obsolete> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <description>Please enter the description of this user action.</description> </action> <action name="AppList_VoiceSearchStartedManually"> + <obsolete>App list doesn't have voice search anymore.</obsolete> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <description>Please enter the description of this user action.</description> </action> <action name="Arc.Launcher.Search.OpenPlayStore.InstantApps"> - <owner>hejq@chromium.com</owner> + <obsolete> + Deprecated in favor of Apps.AppListSearchResultOpenType histogram. + </obsolete> + <owner>hejq@chromium.org</owner> <description> Recorded when the user opens the an instant app from a Play Store app search query. @@ -1693,7 +1941,10 @@ </action> <action name="Arc.Launcher.Search.OpenPlayStore.UninstalledApps"> - <owner>hejq@chromium.com</owner> + <obsolete> + Deprecated in favor of Apps.AppListSearchResultOpenType histogram. + </obsolete> + <owner>hejq@chromium.org</owner> <description> Recorded when the user opens the installing page of a Play Store app search result. @@ -2417,6 +2668,9 @@ </action> <action name="BindingsMismatchTerminate_RVH_WebUI"> + <obsolete> + Replaced in 1/2018 with bad_message::RVH_WEB_UI_BINDINGS_MISMATCH. + </obsolete> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <description>Please enter the description of this user action.</description> </action> @@ -2923,6 +3177,28 @@ <description>Please enter the description of this user action.</description> </action> +<action name="BrowserActions.MenuOpened"> + <owner>ltian@chromium.org</owner> + <description> + A Browser Actions menu is opened in Chrome. A Browser Actions menu is a + Chrome style context menu opened by 3rd party apps. + </description> +</action> + +<action name="BrowserActions.TabOpenedNotificationClicked"> + <owner>ltian@chromium.org</owner> + <description> + Users click the notification of opening tab in background. + </description> +</action> + +<action name="BrowserActions.TabOpenedNotificationCreated"> + <owner>ltian@chromium.org</owner> + <description> + Browser Actions creates a notifcation of opening tab in background. + </description> +</action> + <action name="BrowserForSystemProfile"> <owner>mlerman@chromium.org</owner> <description> @@ -3286,6 +3562,14 @@ <description>Please enter the description of this user action.</description> </action> +<action name="ClearBrowsingData_OlderThan30Days"> + <owner>dullweber@chromium.org</owner> + <owner>msramek@chromium.org</owner> + <description> + Browsing data has been cleared for older than 30 days timeperiod. + </description> +</action> + <action name="ClearBrowsingData_Passwords"> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <description>Please enter the description of this user action.</description> @@ -3307,6 +3591,11 @@ <description>Please enter the description of this user action.</description> </action> +<action name="ClearBrowsingData_SiteUsageData"> + <owner>mlamouri@chromium.org</owner> + <description>Recorded when the user clears site usage data.</description> +</action> + <action name="ClearBrowsingData_SwitchTo_AdvancedTab"> <owner>dullweber@chromium.org</owner> <owner>msramek@chromium.org</owner> @@ -3349,6 +3638,12 @@ <description>Time period in CBD was changed.</description> </action> +<action name="ClearBrowsingData_TimePeriodChanged_OlderThan30Days"> + <owner>dullweber@chromium.org</owner> + <owner>msramek@chromium.org</owner> + <description>Time period in CBD was changed to OlderThan30Days.</description> +</action> + <action name="ClearSelection"> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <description>Please enter the description of this user action.</description> @@ -3690,6 +3985,15 @@ </description> </action> +<action name="ContextualSearch.SmartSelectionSuppressed"> + <owner>donnd@chromium.org</owner> + <description> + The user did a long-press that would normally trigger Contextual Search but + the UX was suppressed to allow Smart Selection to handle the gesture + instead. + </description> +</action> + <action name="ContextualSearch.SwipeOrFlingClose"> <owner>donnd@chromium.org</owner> <description> @@ -3736,6 +4040,7 @@ </action> <action name="ContextualSearch.TapSuppressed.TapThresholdExceeded"> + <obsolete>Deprecated as of 11/2017.</obsolete> <owner>donnd@chromium.org</owner> <description> A tap that typically would have triggered Contextual Search was suppressed @@ -4763,7 +5068,18 @@ <description>Please enter the description of this user action.</description> </action> +<action name="FocusInactivePopupForAccessibility"> + <owner>dtseng@chromium.org</owner> + <description> + Places focus on non-modal UI such as info bars, bubble widgets for + accessibility. + </description> +</action> + <action name="FocusInfobars"> + <obsolete> + No longer used. Generalized/renamed to FocusInactivePopupForAccessibility. + </obsolete> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <description>Please enter the description of this user action.</description> </action> @@ -5258,6 +5574,9 @@ </action> <action name="Hotword.HotwordTrigger"> + <obsolete> + Deprecated as of 10/2017. Feature removed with crbug/761426. + </obsolete> <owner>amistry@chromium.org</owner> <owner>rlp@chromium.org</owner> <owner>somast@chromium.org</owner> @@ -5304,6 +5623,123 @@ <description>The user triggered an event in in-product help.</description> </action> +<action name="InProductHelp.NotifyEvent.IPH_ChromeHomeExpand"> + <owner>twellington@chromium.org</owner> + <owner>mdjones@chromium.org</owner> + <description> + The user triggered an event related to the Chrome Home cold start in-product + help. See //components/feature_engagement/README.md#Configuring-UMA for + details. + </description> +</action> + +<action name="InProductHelp.NotifyEvent.IPH_ChromeHomeMenuHeader"> + <owner>twellington@chromium.org</owner> + <owner>mdjones@chromium.org</owner> + <description> + The user triggered an event related to the Chrome Home menu header + in-product help. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action name="InProductHelp.NotifyEvent.IPH_ChromeHomePullToRefresh"> + <owner>twellington@chromium.org</owner> + <owner>mdjones@chromium.org</owner> + <description> + The user triggered an event related to the Chrome Home in-product help that + is shown after a pull-to-refresh. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action name="InProductHelp.NotifyEvent.IPH_ContextualSearch"> + <obsolete> + Replaced with InProductHelp.NotifyEvent.IPH_ContextualSearchWebSearch. + </obsolete> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + The user triggered an event related to the Contextual Search in-product + help. See //components/feature_engagement/README.md#Configuring-UMA for + details. + </description> +</action> + +<action name="InProductHelp.NotifyEvent.IPH_ContextualSearchOptIn"> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + The user triggered an event related to the opting-in for Contextual Search + in-product help. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action name="InProductHelp.NotifyEvent.IPH_ContextualSearchPanel"> + <obsolete> + Replaced with + InProductHelp.NotifyEvent.IPH_ContextualSearchPromotePanelOpen. + </obsolete> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + The user triggered an event related to opening the Contextual Search panel + in-product help. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action name="InProductHelp.NotifyEvent.IPH_ContextualSearchPromotePanelOpen"> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + The user triggered an event related to opening the Contextual Search panel + in-product help. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action name="InProductHelp.NotifyEvent.IPH_ContextualSearchPromoteTap"> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + The user triggered an event related to activation by tap for Contextual + Search in-product help. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action name="InProductHelp.NotifyEvent.IPH_ContextualSearchTap"> + <obsolete> + Replaced with InProductHelp.NotifyEvent.IPH_ContextualSearchPromoteTap. + </obsolete> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + The user triggered an event related to activation by tap for Contextual + Search in-product help. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action name="InProductHelp.NotifyEvent.IPH_ContextualSearchWebSearch"> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + The user triggered an event related to the Contextual Search web search + in-product help. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + <action name="InProductHelp.NotifyEvent.IPH_DataSaverDetail"> <owner>nyquist@chromium.org</owner> <owner>xingliu@chromium.org</owner> @@ -5382,6 +5818,124 @@ <description>The user triggered a used event in in-product help.</description> </action> +<action name="InProductHelp.NotifyUsedEvent.IPH_ChromeHomeExpand"> + <owner>twellington@chromium.org</owner> + <owner>mdjones@chromium.org</owner> + <description> + The user triggered a used event related to the Chrome Home cold start + in-product help. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action name="InProductHelp.NotifyUsedEvent.IPH_ChromeHomeMenuHeader"> + <owner>twellington@chromium.org</owner> + <owner>mdjones@chromium.org</owner> + <description> + The user triggered a used event related to the Chrome Home menu header + in-product help. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action name="InProductHelp.NotifyUsedEvent.IPH_ChromeHomePullToRefresh"> + <owner>twellington@chromium.org</owner> + <owner>mdjones@chromium.org</owner> + <description> + The user triggered a used event related to the Chrome Home in-product help + that is shown after a pull-to-refresh. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action name="InProductHelp.NotifyUsedEvent.IPH_ContextualSearch"> + <obsolete> + Replaced with InProductHelp.NotifyUsedEvent.IPH_ContextualSearchWebSearch. + </obsolete> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + The user triggered a used event related to the Contextual Search in-product + help. See //components/feature_engagement/README.md#Configuring-UMA for + details. + </description> +</action> + +<action name="InProductHelp.NotifyUsedEvent.IPH_ContextualSearchOptIn"> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + The user triggered a used event related to the opting-in for Contextual + Search in-product help. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action name="InProductHelp.NotifyUsedEvent.IPH_ContextualSearchPanel"> + <obsolete> + Replaced with + InProductHelp.NotifyUsedEvent.IPH_ContextualSearchPromotePanelOpen. + </obsolete> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + The user triggered a used event related to opening the Contextual Search + panel in-product help. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action + name="InProductHelp.NotifyUsedEvent.IPH_ContextualSearchPromotePanelOpen"> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + The user triggered a used event related to opening the Contextual Search + panel in-product help. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action name="InProductHelp.NotifyUsedEvent.IPH_ContextualSearchPromoteTap"> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + The user triggered a used event related to activation by tap for Contextual + Search in-product help. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action name="InProductHelp.NotifyUsedEvent.IPH_ContextualSearchTap"> + <obsolete> + Replaced with InProductHelp.NotifyUsedEvent.IPH_ContextualSearchPromoteTap. + </obsolete> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + The user triggered a used event related to activation by tap for Contextual + Search in-product help. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action name="InProductHelp.NotifyUsedEvent.IPH_ContextualSearchWebSearch"> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + The user triggered a used event related to the Contextual Search in-product + help. See //components/feature_engagement/README.md#Configuring-UMA for + details. + </description> +</action> + <action name="InProductHelp.NotifyUsedEvent.IPH_DataSaverDetail"> <owner>nyquist@chromium.org</owner> <owner>xingliu@chromium.org</owner> @@ -5460,6 +6014,131 @@ </description> </action> +<action name="InProductHelp.ShouldTriggerHelpUI.IPH_ChromeHomeExpand"> + <owner>twellington@chromium.org</owner> + <owner>mdjones@chromium.org</owner> + <description> + The feature engagement tracker tried to determine whether the Chrome Home + cold start in-product help should be shown to the user. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action name="InProductHelp.ShouldTriggerHelpUI.IPH_ChromeHomeMenuHeader"> + <owner>twellington@chromium.org</owner> + <owner>mdjones@chromium.org</owner> + <description> + The feature engagement tracker tried to determine whether the Chrome Home + menu header in-product help should be shown to the user. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action name="InProductHelp.ShouldTriggerHelpUI.IPH_ChromeHomePullToRefresh"> + <owner>twellington@chromium.org</owner> + <owner>mdjones@chromium.org</owner> + <description> + The feature engagement tracker tried to determine whether the Chrome Home + in-product help that is shown after a pull-to-refresh should be shown to the + user. See //components/feature_engagement/README.md#Configuring-UMA for + details. + </description> +</action> + +<action name="InProductHelp.ShouldTriggerHelpUI.IPH_ContextualSearch"> + <obsolete> + Replaced with + InProductHelp.ShouldTriggerHelpUI.IPH_ContextualSearchWebSearch. + </obsolete> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + The feature engagement tracker tried to determine whether the Contextual + Search in-product help should be shown to the user. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action name="InProductHelp.ShouldTriggerHelpUI.IPH_ContextualSearchOptIn"> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + The feature engagement tracker tried to determine whether the in-product + help related to opting-in for Contextual Search should be shown to the user. + See //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action name="InProductHelp.ShouldTriggerHelpUI.IPH_ContextualSearchPanel"> + <obsolete> + Replaced with + InProductHelp.ShouldTriggerHelpUI.IPH_ContextualSearchPromotePanelOpen. + </obsolete> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + The feature engagement tracker tried to determine whether the in-product + help related to opening the Contextual Search panel should be shown to the + user. See //components/feature_engagement/README.md#Configuring-UMA for + details. + </description> +</action> + +<action + name="InProductHelp.ShouldTriggerHelpUI.IPH_ContextualSearchPromotePanelOpen"> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + The feature engagement tracker tried to determine whether the in-product + help related to opening the Contextual Search panel should be shown to the + user. See //components/feature_engagement/README.md#Configuring-UMA for + details. + </description> +</action> + +<action name="InProductHelp.ShouldTriggerHelpUI.IPH_ContextualSearchPromoteTap"> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + The feature engagement tracker tried to determine whether the in-product + help related to activation by tap for Contextual Search should be shown to + the user. See //components/feature_engagement/README.md#Configuring-UMA for + details. + </description> +</action> + +<action name="InProductHelp.ShouldTriggerHelpUI.IPH_ContextualSearchTap"> + <obsolete> + Replaced with + InProductHelp.ShouldTriggerHelpUI.IPH_ContextualSearchPromoteTap. + </obsolete> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + The feature engagement tracker tried to determine whether the in-product + help related to activation by tap for Contextual Search should be shown to + the user. See //components/feature_engagement/README.md#Configuring-UMA for + details. + </description> +</action> + +<action name="InProductHelp.ShouldTriggerHelpUI.IPH_ContextualSearchWebSearch"> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + The feature engagement tracker tried to determine whether the Contextual + Search in-product help should be shown to the user. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + <action name="InProductHelp.ShouldTriggerHelpUI.IPH_DataSaverDetail"> <owner>nyquist@chromium.org</owner> <owner>xingliu@chromium.org</owner> @@ -5569,6 +6248,135 @@ </action> <action + name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_ChromeHomeExpand"> + <owner>twellington@chromium.org</owner> + <owner>mdjones@chromium.org</owner> + <description> + A user action that could have triggered the Chrome Home cold start + in-product help did not. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action + name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_ChromeHomeMenuHeader"> + <owner>twellington@chromium.org</owner> + <owner>mdjones@chromium.org</owner> + <description> + A user action that could have triggered the Chrome Home menu header + in-product help did not. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action + name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_ChromeHomePullToRefresh"> + <owner>twellington@chromium.org</owner> + <owner>mdjones@chromium.org</owner> + <description> + A pull-to-refresh that could have triggered the Chrome Home in-product help + did not. See //components/feature_engagement/README.md#Configuring-UMA for + details. + </description> +</action> + +<action + name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_ContextualSearch"> + <obsolete> + Replaced with + InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_ContextualSearchWebSearch. + </obsolete> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + A user action that could have triggered the Contextual Search in-product + help did not. See //components/feature_engagement/README.md#Configuring-UMA + for details. + </description> +</action> + +<action + name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_ContextualSearchOptIn"> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + A user action that could have triggered the in-product help related to + opting-in for Contextual Search did not. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action + name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_ContextualSearchPanel"> + <obsolete> + Replaced with + InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_ContextualSearchPromotePanelOpen. + </obsolete> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + A user action that could have triggered the in-product help related to + opening the Contextual Search panel did not. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action + name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_ContextualSearchPromotePanelOpen"> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + A user action that could have triggered the in-product help related to + opening the Contextual Search panel did not. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action + name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_ContextualSearchPromoteTap"> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + A user action that could have triggered the in-product help related to + activation by tap did not. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action + name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_ContextualSearchTap"> + <obsolete> + Replaced with + InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_ContextualSearchPromoteTap. + </obsolete> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + A user action that could have triggered the in-product help related to + activation by tap did not. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action + name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_ContextualSearchWebSearch"> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + A user action that could have triggered the Contextual Search in-product + help did not. See //components/feature_engagement/README.md#Configuring-UMA + for details. + </description> +</action> + +<action name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_DataSaverDetail"> <owner>nyquist@chromium.org</owner> <owner>xingliu@chromium.org</owner> @@ -5671,6 +6479,128 @@ </action> <action + name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_ChromeHomeExpand"> + <owner>twellington@chromium.org</owner> + <owner>mdjones@chromium.org</owner> + <description> + A user action triggered the Chrome Home cold start in-product help. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action + name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_ChromeHomeMenuHeader"> + <owner>twellington@chromium.org</owner> + <owner>mdjones@chromium.org</owner> + <description> + A user action triggered the Chrome Home menu header in-product help. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action + name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_ChromeHomePullToRefresh"> + <owner>twellington@chromium.org</owner> + <owner>mdjones@chromium.org</owner> + <description> + A pull-to-refresh triggered the Chrome Home in-product help. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action + name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_ContextualSearch"> + <obsolete> + Replaced with + InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_ContextualSearchWebSearch. + </obsolete> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + A user action triggered the Contextual Search in-product help. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action + name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_ContextualSearchOptIn"> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + A user action triggered the in-product help related to opting-in for + Contextual Search. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action + name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_ContextualSearchPanel"> + <obsolete> + Replaced with + InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_ContextualSearchPromotePanelOpen. + </obsolete> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + A user action triggered the in-product help related to opening the + Contextual Search panel. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action + name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_ContextualSearchPromotePanelOpen"> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + A user action triggered the in-product help related to opening the + Contextual Search panel. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action + name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_ContextualSearchPromoteTap"> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + A user action triggered the in-product help related to activation by tap. + See //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action + name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_ContextualSearchTap"> + <obsolete> + Replaced with + InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_ContextualSearchPromoteTap. + </obsolete> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + A user action triggered the in-product help related to activation by tap. + See //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action + name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_ContextualSearchWebSearch"> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + A user action triggered the Contextual Search in-product help. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_DataSaverDetail"> <owner>nyquist@chromium.org</owner> <owner>xingliu@chromium.org</owner> @@ -5738,6 +6668,159 @@ <description>A user action triggered In-Product Help.</description> </action> +<action + name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH_BadgedReadingList"> + <owner>edchin@chromium.org</owner> + <owner>gchatz@chromium.org</owner> + <description> + A user action would have triggered In-Product Help, but the feature was + configured for tracking only. + </description> +</action> + +<action + name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH_Bookmark"> + <owner>nyquist@chromium.org</owner> + <owner>xingliu@chromium.org</owner> + <description> + A user action would have triggered In-Product Help, but the feature was + configured for tracking only. + </description> +</action> + +<action + name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH_ChromeHomeExpand"> + <owner>twellington@chromium.org</owner> + <owner>mdjones@chromium.org</owner> + <description> + A user action would have triggered the Chrome Home cold start in-product + help, but the feature was configured for tracking only. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action + name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH_ChromeHomeMenuHeader"> + <owner>twellington@chromium.org</owner> + <owner>mdjones@chromium.org</owner> + <description> + A user action would have triggered the Chrome Home menu header in-product + help, but the feature was configured for tracking only. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action + name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH_ChromeHomePullToRefresh"> + <owner>twellington@chromium.org</owner> + <owner>mdjones@chromium.org</owner> + <description> + A pull-to-refresh would have triggered the Chrome Home in-product help, but + the feature was configured for tracking only. See + //components/feature_engagement/README.md#Configuring-UMA for details. + </description> +</action> + +<action + name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH_DataSaverDetail"> + <owner>nyquist@chromium.org</owner> + <owner>xingliu@chromium.org</owner> + <description> + A user action would have triggered In-Product Help, but the feature was + configured for tracking only. + </description> +</action> + +<action + name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH_DataSaverPreview"> + <owner>nyquist@chromium.org</owner> + <owner>xingliu@chromium.org</owner> + <description> + A user action would have triggered In-Product Help, but the feature was + configured for tracking only. + </description> +</action> + +<action + name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH_DownloadHome"> + <owner>nyquist@chromium.org</owner> + <owner>xingliu@chromium.org</owner> + <description> + A user action would have triggered In-Product Help, but the feature was + configured for tracking only. + </description> +</action> + +<action + name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH_DownloadPage"> + <owner>nyquist@chromium.org</owner> + <owner>xingliu@chromium.org</owner> + <description> + A user action would have triggered In-Product Help, but the feature was + configured for tracking only. + </description> +</action> + +<action + name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH_DownloadPageScreenshot"> + <owner>nyquist@chromium.org</owner> + <owner>xingliu@chromium.org</owner> + <description> + A user action would have triggered In-Product Help, but the feature was + configured for tracking only. + </description> +</action> + +<action + name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH_IncognitoWindow"> + <owner>nyquist@chromium.org</owner> + <owner>xingliu@chromium.org</owner> + <description> + A user action would have triggered In-Product Help, but the feature was + configured for tracking only. + </description> +</action> + +<action + name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH_MediaDownload"> + <owner>nyquist@chromium.org</owner> + <owner>xingliu@chromium.org</owner> + <description> + A user action would have triggered In-Product Help, but the feature was + configured for tracking only. + </description> +</action> + +<action + name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH_NewIncognitoTabTip"> + <owner>edchin@chromium.org</owner> + <owner>gchatz@chromium.org</owner> + <description> + A user action would have triggered In-Product Help, but the feature was + configured for tracking only. + </description> +</action> + +<action + name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH_NewTab"> + <owner>nyquist@chromium.org</owner> + <owner>xingliu@chromium.org</owner> + <description> + A user action would have triggered In-Product Help, but the feature was + configured for tracking only. + </description> +</action> + +<action + name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH_NewTabTip"> + <owner>edchin@chromium.org</owner> + <owner>gchatz@chromium.org</owner> + <description> + A user action would have triggered In-Product Help, but the feature was + configured for tracking only. + </description> +</action> + <action name="Indent"> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <description>Please enter the description of this user action.</description> @@ -9853,6 +10936,14 @@ <description>The user paused a media element from the controls.</description> </action> +<action name="Media.Controls.PauseOverlay"> + <owner>beccahughes@chromium.org</owner> + <owner>media-dev@chromium.org</owner> + <description> + The user paused a media element from the pause overlay button. + </description> +</action> + <action name="Media.Controls.Play"> <owner>mlamouri@chromium.org</owner> <description>The user played a media element from the controls.</description> @@ -9881,6 +10972,23 @@ </description> </action> +<action name="Media.Controls.RemoteSeekBackward"> + <owner>media-dev@chromium.org</owner> + <description> + User seeks the video backward using any controls apart from the media + element itself (aka remote controls: Android wear, headset, notification, + etc). + </description> +</action> + +<action name="Media.Controls.RemoteSeekForward"> + <owner>media-dev@chromium.org</owner> + <description> + User seeks the video forward using any controls apart from the media element + itself (aka remote controls: Android wear, headset, notification, etc). + </description> +</action> + <action name="Media.Controls.ScrubbingBegin"> <owner>mlamouri@chromium.org</owner> <description> @@ -10521,6 +11629,15 @@ <description>Please enter the description of this user action.</description> </action> +<action name="MobileFreTOSLinkTapped"> + <owner>justincohen@chromium.org</owner> + <description> + User tapped on the TOS link on the first run welcome view. This metric is + only recorded if and after the TOS are accepted. This metric is specific to + iOS. + </description> +</action> + <action name="MobileGoToBackground"> <owner>tedchoc@chromium.org</owner> <description> @@ -10933,6 +12050,13 @@ <description>Please enter the description of the metric.</description> </action> +<action name="MobileOmniboxDeleteUrl"> + <owner>thildebr@chromium.org</owner> + <description> + The user cleared the contents of the omnibox via the delete button. + </description> +</action> + <action name="MobileOmniboxRefineSuggestion"> <obsolete> Deprecated 07/2017. Replaced by MobileOmniboxRefineSuggestion.Query and @@ -11262,7 +12386,7 @@ </action> <action name="MobileTabClosedUndoShortCut"> - <owner>xingliu@chromium.com</owner> + <owner>xingliu@chromium.org</owner> <description> Undo tab closure by keyboard shortcut ctrl+shift+T, for Android only. </description> @@ -11325,6 +12449,13 @@ <description>Please enter the description of this user action.</description> </action> +<action name="MobileToolbarOmniboxShortcut"> + <owner>gambard@chromium.org</owner> + <description> + User pressed the omnibox shortcut on the toolbar. iOS only. + </description> +</action> + <action name="MobileToolbarReload"> <owner>tedchoc@chromium.org</owner> <description> @@ -11334,6 +12465,13 @@ </description> </action> +<action name="MobileToolbarShareMenu"> + <owner>gambard@chromium.org</owner> + <description> + User pressed the toolbar's button to open the share menu. iOS only. + </description> +</action> + <action name="MobileToolbarShowMenu"> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <description>Please enter the description of this user action.</description> @@ -11511,7 +12649,7 @@ <description>Please enter the description of this user action.</description> </action> -<action name="Mouse_Down"> +<action name="Mouse_Down" not_user_triggered="true"> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <description>Please enter the description of this user action.</description> </action> @@ -12104,12 +13242,12 @@ <description>Please enter the description of this user action.</description> </action> -<action name="OpenFileSystemPersistent"> +<action name="OpenFileSystemPersistent" not_user_triggered="true"> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <description>Please enter the description of this user action.</description> </action> -<action name="OpenFileSystemTemporary"> +<action name="OpenFileSystemTemporary" not_user_triggered="true"> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <description>Please enter the description of this user action.</description> </action> @@ -13925,7 +15063,9 @@ <action name="OutdatedUpgradeBubble.Later"> <owner>mad@chromium.org</owner> <description> - When the user clicks on the Later button of the outdated upgrade bubble. + When the user dismisses the outdated upgrade bubble without accepting it. In + m62 and earlier this was via a "Later" button. Since m63, that + button was removed and replaced by a close [x] reporting the same metric. </description> </action> @@ -14249,6 +15389,12 @@ <description>Please enter the description of this user action.</description> </action> +<action name="PageLoadInIncognito" not_user_triggered="true"> + <owner>dullweber@chromium.org</owner> + <owner>msramek@chromium.org</owner> + <description>A page was loaded in incognito mode.</description> +</action> + <action name="PageLoadSRP" not_user_triggered="true"> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <description>Please enter the description of this user action.</description> @@ -15147,6 +16293,11 @@ </action> <action name="SearchAnswer_StoppedLoading"> + <obsolete> + Deprecated in favor of analysing proportion of shown + (SearchAnswer.AnswerVisibleTime total) vs. successfully loaded + (SearchAnswer.RequestResult.REQUEST_RESULT_RECEIVED_ANSWER) cards. + </obsolete> <owner>vadimt@chromium.org</owner> <description>Answer card successfully loads.</description> </action> @@ -15650,6 +16801,14 @@ </description> </action> +<action name="Signin_Android_GmsUserRecoverableDialogAccepted"> + <owner>bsazonov@chromium.org</owner> + <description> + Recorded when user accepts an option presented by Google Play services error + dialog (e.g., clicks "Update" button). + </description> +</action> + <action name="Signin_Android_GmsUserRecoverableDialogShown" not_user_triggered="true"> <owner>bsazonov@chromium.org</owner> @@ -15829,6 +16988,7 @@ </action> <action name="Signin_Impression_FromCloudPrint"> + <obsolete>Deprecated 10/2017. No longer needed.</obsolete> <owner>gogerald@chromium.org</owner> <description> Recorded when showing sign in entry in the cloud print preview page. @@ -15956,6 +17116,15 @@ </description> </action> +<action name="Signin_SigninNewAccount_FromNTPContentSuggestions"> + <owner>bsazonov@chromium.org</owner> + <description> + Recorded on sign in start from access point + signin_metrics::AccessPoint::ACCESS_POINT_NTP_CONTENT_SUGGESTIONS, with a + new account. + </description> +</action> + <action name="Signin_SigninNewAccount_FromRecentTabs"> <owner>jlebel@chromium.org</owner> <description> @@ -15989,6 +17158,15 @@ </description> </action> +<action name="Signin_SigninNotDefault_FromNTPContentSuggestions"> + <owner>bsazonov@chromium.org</owner> + <description> + Recorded on sign in start from access point + signin_metrics::AccessPoint::ACCESS_POINT_NTP_CONTENT_SUGGESTIONS, using + another account than the default one. + </description> +</action> + <action name="Signin_SigninNotDefault_FromRecentTabs"> <owner>jlebel@chromium.org</owner> <description> @@ -16035,6 +17213,15 @@ </description> </action> +<action name="Signin_SigninWithDefault_FromNTPContentSuggestions"> + <owner>bsazonov@chromium.org</owner> + <description> + Recorded on sign in start from access point + signin_metrics::AccessPoint::ACCESS_POINT_NTP_CONTENT_SUGGESTIONS, using the + default account. + </description> +</action> + <action name="Signin_SigninWithDefault_FromRecentTabs"> <owner>jlebel@chromium.org</owner> <description> @@ -16365,11 +17552,18 @@ <action name="SoftwareReporter.CleanupWebui_StartCleanup"> <owner>alito@chromium.org</owner> <description> - The cleaner accepted the cleanup operation offered on the Chrome Cleaner + The cleaner started the cleanup operation offered on the Chrome Cleaner webui. </description> </action> +<action name="SoftwareReporter.CleanupWebui_StartScanning"> + <owner>ftirelo@chromium.org</owner> + <description> + The cleaner started the scan operation offered on the Chrome Cleaner webui. + </description> +</action> + <action name="SoftwareReporter.PromptDialog.LogsPermissionCheckbox_Disabled"> <owner>alito@chromium.org</owner> <description> @@ -16430,6 +17624,112 @@ </description> </action> +<action name="SoundContentSetting.MuteBy.DefaultSwitch"> + <owner>steimel@chromium.org</owner> + <owner>media-dev@chromium.org</owner> + <description> + User muted all sites by changing the default sound setting from the content + settings privacy page (Desktop) or the SingleCategoryPreferences page + (Android). + </description> +</action> + +<action name="SoundContentSetting.MuteBy.PageInfo"> + <owner>steimel@chromium.org</owner> + <owner>media-dev@chromium.org</owner> + <description>User muted site via the Page Info bubble.</description> +</action> + +<action name="SoundContentSetting.MuteBy.PatternException"> + <owner>steimel@chromium.org</owner> + <owner>media-dev@chromium.org</owner> + <description> + User muted site via adding/removing a pattern exception from the content + settings privacy page (Desktop) or the SingleCategoryPreferences page + (Android). + </description> +</action> + +<action name="SoundContentSetting.MuteBy.SiteSettings"> + <owner>steimel@chromium.org</owner> + <owner>media-dev@chromium.org</owner> + <description>User muted site via the site settings page.</description> +</action> + +<action name="SoundContentSetting.MuteBy.TabStrip"> + <owner>steimel@chromium.org</owner> + <owner>media-dev@chromium.org</owner> + <description>User muted site via the tab strip.</description> +</action> + +<action name="SoundContentSetting.UnmuteBy.DefaultSwitch"> + <owner>steimel@chromium.org</owner> + <owner>media-dev@chromium.org</owner> + <description> + User unmuted all sites by changing the default sound setting from the + content settings privacy page (Desktop) or the SingleCategoryPreferences + page (Android). + </description> +</action> + +<action name="SoundContentSetting.UnmuteBy.PageInfo"> + <owner>steimel@chromium.org</owner> + <owner>media-dev@chromium.org</owner> + <description>User unmuted site via the Page Info bubble.</description> +</action> + +<action name="SoundContentSetting.UnmuteBy.PatternException"> + <owner>steimel@chromium.org</owner> + <owner>media-dev@chromium.org</owner> + <description> + User unmuted site via adding/removing a pattern exception from the content + settings privacy page (Desktop) or the SingleCategoryPreferences page + (Android). + </description> +</action> + +<action name="SoundContentSetting.UnmuteBy.SiteSettings"> + <owner>steimel@chromium.org</owner> + <owner>media-dev@chromium.org</owner> + <description>User unmuted site via the site settings page.</description> +</action> + +<action name="SoundContentSetting.UnmuteBy.TabStrip"> + <owner>steimel@chromium.org</owner> + <owner>media-dev@chromium.org</owner> + <description>User unmuted site via the tab strip.</description> +</action> + +<action name="SplitView_DoubleTapDividerSwapWindows"> + <owner>xdai@chromium.org</owner> + <description> + Recorded when the user double tapped on the split divider to swap windows in + tablet mode on Chrome OS. + </description> +</action> + +<action name="SplitView_EndSplitView"> + <owner>xdai@chromium.org</owner> + <description> + Recorded when the user ended split view mode in tablet mode on Chrome OS. + </description> +</action> + +<action name="SplitView_ResizeWindows"> + <owner>xdai@chromium.org</owner> + <description> + Recorded when the user dragged the split divider to resize the windows in + tablet mode on Chrome OS. + </description> +</action> + +<action name="SplitView_SnapWindow"> + <owner>xdai@chromium.org</owner> + <description> + Recorded when a window was just snapped in tablet mode on Chrome OS. + </description> +</action> + <action name="StackedTab_DragActiveTab"> <owner>bruthig@chromium.org</owner> <owner>tdanderson@chromium.org</owner> @@ -16571,7 +17871,7 @@ <description>Please enter the description of this user action.</description> </action> -<action name="StatusArea_BrightnessChanged"> +<action name="StatusArea_BrightnessChanged" not_user_triggered="true"> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <description>Please enter the description of this user action.</description> </action> @@ -17018,6 +18318,15 @@ <description>Please enter the description of this user action.</description> </action> +<action name="Suggestions.AllDismissed.Shown"> + <owner>peconn@chromium.org</owner> + <description> + User dismissed all cards and was not able to get any more suggestions + resulting in the All Dismissed State. Only records for users with Chrome + Home enabled. + </description> +</action> + <action name="Suggestions.Card.ActionTapped"> <owner>finkm@chromium.org</owner> <owner>dgn@chromium.org</owner> @@ -17446,6 +18755,22 @@ </description> </action> +<action name="Tablet_LongPressOverviewButtonEnterSplitView"> + <owner>xdai@chromium.org</owner> + <description> + Recorded when the user long pressed the overview button to enter split view + in tablet mode on Chrome OS. + </description> +</action> + +<action name="Tablet_LongPressOverviewButtonExitSplitView"> + <owner>xdai@chromium.org</owner> + <description> + Recorded when the user long pressed the overview button to exit split view + in tablet mode on Chrome OS. + </description> +</action> + <action name="Tablet_QuickSwitch"> <owner>sammiequon@chromium.org</owner> <description> @@ -17504,6 +18829,9 @@ </action> <action name="Terminate_ProcessMismatch_CreateNewWidget"> + <obsolete> + Replaced in 1/2018 with bad_message::WCI_NEW_WIDGET_PROCESS_MISMATCH. + </obsolete> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <description>Please enter the description of this user action.</description> </action> @@ -17530,7 +18858,7 @@ </description> </action> -<action name="TextToSpeech.Stop"> +<action name="TextToSpeech.Stop" not_user_triggered="true"> <owner>dmazzoni@chromium.org</owner> <description>Synthesized speech is stopped.</description> </action> @@ -17715,7 +19043,7 @@ </description> </action> -<action name="TrackpadScrollFling"> +<action name="TrackpadScrollFling" not_user_triggered="true"> <owner>tdresser@chromium.org</owner> <description>Logged on an ET_SCROLL_FLING_START scroll event.</description> </action> @@ -18101,7 +19429,7 @@ </description> </action> -<action name="WebView.PermissionAllow.FileSystem"> +<action name="WebView.PermissionAllow.FileSystem" not_user_triggered="true"> <owner>fsamuel@chromium.org</owner> <owner>hanxi@chromium.org</owner> <description>
diff --git a/tools/metrics/actions/extract_actions.py b/tools/metrics/actions/extract_actions.py index 931d85ec..c572f7b 100755 --- a/tools/metrics/actions/extract_actions.py +++ b/tools/metrics/actions/extract_actions.py
@@ -34,9 +34,6 @@ import action_utils import print_style -sys.path.insert(1, os.path.join(sys.path[0], '..', '..', 'python')) -from google import path_utils - # Import the metrics/common module for pretty print xml. sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'common')) import presubmit_util @@ -158,7 +155,7 @@ ) # The path to the root of the repository. -REPOSITORY_ROOT = os.path.join(path_utils.ScriptDir(), '..', '..', '..') +REPOSITORY_ROOT = os.path.join(os.path.dirname(__file__), '..', '..', '..') number_of_files_total = 0 @@ -289,9 +286,6 @@ actions.add('ConnectivityDiagnostics.UA.TestResultExpanded') actions.add('ConnectivityDiagnostics.UA.TestSuiteRun') - # Actions sent by 'Ok Google' Hotwording. - actions.add('Hotword.HotwordTrigger') - class InvalidStatementException(Exception): """Indicates an invalid statement was found."""
diff --git a/tools/metrics/histograms/OWNERS b/tools/metrics/histograms/OWNERS index a3b1a4d9..8fa4cae 100644 --- a/tools/metrics/histograms/OWNERS +++ b/tools/metrics/histograms/OWNERS
@@ -1,6 +1,6 @@ # Metrics changes should always be reviewed by owners. +per-file histograms.xml=file://base/metrics/OWNERS per-file histograms.xml=set noparent -per-file histograms.xml=file://tools/metrics/OWNERS # Extending enums by adding new buckets is allowed without OWNERS review, but # you should add a metrics team OWNER if you are changing the semantics of
diff --git a/tools/metrics/histograms/README.md b/tools/metrics/histograms/README.md index b0c5a5b5..935a748 100644 --- a/tools/metrics/histograms/README.md +++ b/tools/metrics/histograms/README.md
@@ -43,30 +43,57 @@ However, the total count does not have to be meaningful for an enum histogram to still be the right choice. +If few buckets will be emitted to, consider using a [sparse +histogram](#When-To-Use-Sparse-Histograms). + You may append to your enum if the possible states/actions grows. However, you should not reorder, renumber, or otherwise reuse existing values. As such, please put this warning by the enum definition: ``` -// These values are written to logs. New enum values can be added, but existing -// enums must never be renumbered or deleted and reused. -enum NEW_TAB_PAGE_ACTION { +// These values are persisted to logs. Entries should not be renumbered and +// numeric values should never be reused. +enum class NEW_TAB_PAGE_ACTION { USE_OMNIBOX = 0, CLICK_TILE = 1, OPEN_BOOKMARK = 2, - NEW_TAB_PAGE_ACTION_COUNT + COUNT }; ``` Also, please explicitly set enum values `= 0`, `= 1`, `= 2`, etc. This makes clearer that the actual values are important. In addition, it helps confirm the values align between the enum definition and -[histograms.xml](./histograms.xml). If a "count" value is included it -should not include an explicit value. +[histograms.xml](./histograms.xml). The COUNT value should not include an +explicit value--this lets the compiler keep the COUNT up-to-date. If your enum histogram has a catch-all / miscellaneous bucket, put that bucket first (`= 0`). This will make the bucket easy to find on the dashboard if later you add additional buckets to your histogram. +### Flag Histograms + +When adding a new flag in +[about_flags.cc](../../../chrome/browser/about_flags.cc), you need to add a +corresponding entry to [enums.xml](./enums.xml). This will be automatically +verified by the `AboutFlagsHistogramTest` unit test. + +To add a new entry: + +1. Edit [enums.xml](./enums.xml), adding the feature to the `LoginCustomFlags` + enum section, with any unique value (just make one up, although whatever it + is needs to appear in sorted order; `pretty_print.py` will do this for you). +2. Build `unit_tests`, then run `unit_tests + --gtest_filter='AboutFlagsHistogramTest.*'` to compute the correct value. +3. Update the entry in [enums.xml](./enums.xml) with the correct value, and move + it so the list is sorted by value (`pretty_print.py` will do this for you). +4. Re-run the test to ensure the value and ordering are correct. + +You can also use `tools/metrics/histograms/validate_format.py` to check the +ordering (but not that the value is correct). + +Don't remove entries when removing a flag; they are still used to decode data +from previous Chrome versions. + ### Count Histograms [histogram_macros.h](https://cs.chromium.org/chromium/src/base/metrics/histogram_macros.h) @@ -213,10 +240,18 @@ tools not to treat the partial base name as a distinct histogram. Note that suffixes can be applied recursively. +### Enum labels + +_All_ histograms, including boolean and sparse histograms, may have enum labels +provided via [enums.xml](./enums.xml). Using labels is encouraged whenever +labels would be clearer than raw numeric values. + ## When To Use Sparse Histograms Sparse histograms are well suited for recording counts of exact sample values -that are sparsely distributed over a large range. +that are sparsely distributed over a large range. They can be used with enums +as well as regular integer values. It is often valuable to provide labels in +[enums.xml](./enums.xml). The implementation uses a lock and a map, whereas other histogram types use a vector and no lock. It is thus more costly to add values to, and each value
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 2f248df..a21b9e68 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -393,6 +393,7 @@ <int value="1" label="Social Eng Ads Interstitial"/> <int value="2" label="Phishing Interstitial"/> <int value="3" label="Subresource Filter"/> + <int value="4" label="Better Ads Standard"/> </enum> <enum name="ActiveWindowShowType"> @@ -537,6 +538,24 @@ <int value="4" label="Not QUIC, destination different from origin"/> </enum> +<enum name="Android.DownloadManager.List.View.Actions"> + <int value="0" label="OPEN"/> + <int value="1" label="RESUME"/> + <int value="2" label="PAUSE"/> + <int value="3" label="CANCEL"/> + <int value="4" label="MENU_SHARE"/> + <int value="5" label="MENU_DELETE"/> +</enum> + +<enum name="Android.DownloadManager.Menu.Actions"> + <int value="0" label="CLOSE"/> + <int value="1" label="MULTI_DELETE"/> + <int value="2" label="MULTI_SHARE"/> + <int value="3" label="SHOW_INFO"/> + <int value="4" label="HIDE_INFO"/> + <int value="5" label="SEARCH"/> +</enum> + <enum name="AndroidActivityId"> <int value="1" label="Unknown"/> <int value="2" label="Main"/> @@ -832,12 +851,17 @@ <int value="196620" label="3.12"/> <int value="196621" label="3.13"/> <int value="196622" label="3.14"/> + <int value="196623" label="3.15"/> <int value="196625" label="3.17"/> <int value="196626" label="3.18"/> <int value="196627" label="3.19"/> <int value="262144" label="4.0"/> <int value="262145" label="4.1"/> + <int value="262148" label="4.4"/> + <int value="262153" label="4.9"/> <int value="262154" label="4.10"/> + <int value="262157" label="4.13"/> + <int value="262158" label="4.14"/> </enum> <enum name="AndroidManageSpaceButton"> @@ -860,6 +884,12 @@ <int value="3" label="LowMemory"/> </enum> +<enum name="AndroidResourceExtractionStatus"> + <int value="0" label="No extraction performed"/> + <int value="1" label="Extraction success"/> + <int value="2" label="Extraction failure"/> +</enum> + <enum name="AndroidRestoreResult"> <int value="0" label="No restore attempted"/> <int value="1" label="Restore successful"/> @@ -1000,6 +1030,8 @@ <int value="30" label="Waiting for manifest to be fetched"/> <int value="31" label="Waiting for installability check"/> <int value="32" label="No gesture associated with call to prompt"/> + <int value="33" label="Waiting for native data"/> + <int value="34" label="App install dialog shown"/> </enum> <enum name="AppBannersInstallEvent"> @@ -1148,6 +1180,9 @@ </enum> <enum name="AppListDoodleAction"> + <obsolete> + App list doesn't support doodles anymore. + </obsolete> <int value="0" label="DOODLE_SHOWN"/> <int value="1" label="DOODLE_CLICKED"/> </enum> @@ -1170,7 +1205,7 @@ <int value="0" label="APPS"/> <int value="1" label="SEARCH_RESULTS"/> <int value="2" label="START"/> - <int value="3" label="CUSTOM_LAUNCHER_PAGE"/> + <int value="3" label="CUSTOM_LAUNCHER_PAGE_DEPRECATED"/> </enum> <enum name="AppListPageSwitcherSource"> @@ -1193,7 +1228,22 @@ <enum name="AppListPlayStoreQueryState"> <int value="0" label="SUCCESS"/> <int value="1" label="CANCELED"/> - <int value="2" label="ERROR"/> + <int value="2" label="ERROR_DEPRECATED"/> + <int value="3" label="PLAY_STORE_PROXY_NOT_AVAILABLE"/> + <int value="4" label="FAILED_TO_CALL_CANCEL"/> + <int value="5" label="FAILED_TO_CALL_FINDAPPS"/> + <int value="6" label="REQUEST_HAS_INVALID_PARAMS"/> + <int value="7" label="REQUEST_TIMEOUT"/> + <int value="8" label="PHONESKY_RESULT_REQUEST_CODE_UNMATCHED"/> + <int value="9" label="PHONESKY_RESULT_SESSION_ID_UNMATCHED"/> + <int value="10" label="PHONESKY_REQUEST_REQUEST_CODE_UNMATCHED"/> + <int value="11" label="PHONESKY_APP_DISCOVERY_NOT_AVAILABLE"/> + <int value="12" label="PHONESKY_VERSION_NOT_SUPPORTED"/> + <int value="13" label="PHONESKY_UNEXPECTED_EXCEPTION"/> + <int value="14" label="PHONESKY_MALFORMED_QUERY"/> + <int value="15" label="PHONESKY_INTERNAL_ERROR"/> + <int value="16" label="PHONESKY_RESULT_INVALID_DATA"/> + <int value="17" label="CHROME_GOT_INVALID_RESULT"/> </enum> <enum name="AppListSearchResult"> @@ -1279,6 +1329,11 @@ <int value="4" label="Outside of NTP (e.g. bookmarks bar)"/> </enum> +<enum name="AppsWindowType"> + <int value="0" label="Default"/> + <int value="1" label="Panel"/> +</enum> + <enum name="ArcAuthAccountCheckStatus"> <int value="0" label="Account is up to date"/> <int value="1" label="New account"/> @@ -1287,6 +1342,33 @@ <int value="4" label="Account check failed"/> </enum> +<enum name="ArcBootContinueCodeInstallationResult"> + <int value="0" label="Success"/> + <int value="1" label="Host side code is not ready"/> + <int value="2" label="Can not install host code"/> +</enum> + +<enum name="ArcCodeRelocationResult"> + <int value="0" label="Success"/> + <int value="1" label="Error bootlockboxd not ready"/> + <int value="2" label="Error unable to relocate"/> + <int value="3" label="Error unable to sign"/> +</enum> + +<enum name="ArcCodeVerificationResult"> + <int value="0" label="Success"/> + <int value="1" label="Error bootlockboxd not ready"/> + <int value="2" label="The first boot after OTA or OOBE boot"/> + <int value="3" label="Invalid code"/> +</enum> + +<enum name="ArcContainerLifetimeEvent"> + <int value="0" label="Starting"/> + <int value="1" label="Failed to start"/> + <int value="2" label="Crashed early"/> + <int value="3" label="Crashed"/> +</enum> + <enum name="ArcIntentHandlerAction"> <summary>Defines Arc intent handler actions</summary> <int value="0" label="Error"/> @@ -1304,13 +1386,20 @@ <int value="1" label="Chrome"/> </enum> +<enum name="ArcNativeBridgeType"> + <int value="0" label="Unknown"/> + <int value="1" label="None"/> + <int value="2" label="Houdini"/> + <int value="3" label="Ndk-translation"/> +</enum> + <enum name="ArcOptInAction"> <summary>Defines Arc OptIn actions</summary> <int value="0" label="Opted Out"/> <int value="1" label="Opted In"/> - <int value="2" label="Notification accepted"/> - <int value="3" label="Notification declined"/> - <int value="4" label="Notification timed out"/> + <int value="2" label="DEPRECATED: Notification accepted"/> + <int value="3" label="DEPRECATED: Notification declined"/> + <int value="4" label="DEPRECATED: Notification timed out"/> <int value="5" label="Retry after OptIn failure"/> </enum> @@ -1342,7 +1431,7 @@ <enum name="ArcOptInSilentAuthCode"> <summary>Defines Arc OptIn Silent Auth code state</summary> - <int value="0" label="Disabled"/> + <int value="0" label="Disabled (deprecated)"/> <int value="1" label="Success"/> <int value="2" label="HTTP Context cannot be prepared"/> <int value="3" label="No LST token is available"/> @@ -1374,6 +1463,8 @@ <int value="16" label="ARC instance is stopped before complete provisioning"/> <int value="17" label="Overall sign in timeout"/> <int value="19" label="Network is unavailable"/> + <int value="20" label="Disabled"/> + <int value="21" label="Already provisioned"/> </enum> <enum name="ArcVideoDecodeAcceleratorResult"> @@ -1670,6 +1761,33 @@ <int value="3" label="Audio and silence"/> </enum> +<enum name="AudioOutputProxyStreamFormat"> + <int value="0" label="Bitstream"/> + <int value="1" label="Linear PCM"/> + <int value="2" label="Low latency PCM"/> + <int value="3" label="Low latency PCM fall back to Fake"/> + <int value="4" label="Fake"/> +</enum> + +<enum name="AudioOutputResamplerLowLatencyOpenStreamResult"> + <int value="0" label="Creation of low latency stream failed"/> + <int value="1" label="Fallback to fake stream succeeded"/> + <int value="2" label="Fallback to linear stream succeeded"/> + <int value="3" label="Creation of low latency stream succeeded"/> + <int value="4" label="Subsequent creation of fake stream failed"/> + <int value="5" label="Subsequent creation of fake stream succeeded"/> + <int value="6" label="Subsequent creation of linear stream failed"/> + <int value="7" label="Subsequent creation of linear stream succeeded"/> + <int value="8" label="Subsequent creation of low latency stream failed"/> + <int value="9" label="Subsequent creation of low latency stream succeeded"/> +</enum> + +<enum name="AudioOutputStreamCreationResult"> + <int value="0" label="OK"/> + <int value="1" label="Failed to create stream"/> + <int value="2" label="Failed to open stream"/> +</enum> + <enum name="AudioRendererEvents"> <int value="0" label="Initialized"/> <int value="1" label="Runtime error"/> @@ -1701,6 +1819,13 @@ <int value="12" label="384 kHz"/> </enum> +<enum name="AudioStreamFormatRelatedInitError"> + <int value="0" label="Unsupported format"/> + <int value="1" label="Unsupported format when conversion was used"/> + <int value="2" label="Invalid argument"/> + <int value="3" label="Invalid argument when conversion was used"/> +</enum> + <enum name="AudioStreamOpenResult"> <int value="0" label="OK"/> <int value="1" label="CREATE_INSTANCE"/> @@ -1732,6 +1857,29 @@ <int value="2" label="Processing in WebRTC"/> </enum> +<enum name="AuthenticatedLaunchUserEvent"> + <int value="0" label="Local Reauth Dialog"/> + <int value="1" label="Gaia Reauth Dialog"/> + <int value="2" label="Supervised Profile Blocked Warning"/> + <int value="3" label="Used Profile Blocked Warning"/> + <int value="4" label="Forced Primary Signin Dialog"/> +</enum> + +<enum name="AuthMethod"> + <int value="0" label="Password"/> + <int value="1" label="PIN"/> + <int value="2" label="Smartlock"/> +</enum> + +<enum name="AuthMethodSwitchType"> + <int value="0" label="Password to PIN"/> + <int value="1" label="Password to Smartlock"/> + <int value="2" label="PIN to Password"/> + <int value="3" label="PIN to Smartlock"/> + <int value="4" label="Smartlock to Password"/> + <int value="5" label="Smartlock to PIN"/> +</enum> + <enum name="AuthPolicyErrorType"> <int value="0" label="Success"/> <int value="1" label="Unspecified error"/> @@ -1763,6 +1911,10 @@ <int value="25" label="Kerberos ticket expired while renewing credentials"/> <int value="26" label="klist exited with unspecified error"/> <int value="27" label="kinit failed because of bad machine name."/> + <int value="28" label="New password was rejected during password change."/> + <int value="29" + label="Could not store device policy since install attributes are not + locked yet; stored policy in cache instead."/> </enum> <enum name="AutocheckoutBubble"> @@ -2186,6 +2338,18 @@ (once)"/> <int value="19" label="Submitted with suggestion shown (once)"/> <int value="20" label="About to be submitted with suggestion shown (once)"/> + <int value="21" + label="Submitted with known card without selecting suggestions (once)"/> + <int value="22" + label="Submitted with unknown card without selecting suggestions (once)"/> + <int value="23" + label="Submitted with no card without selecting suggestions (once)"/> + <int value="24" + label="Submitted with wrong-length card without selecting suggestions + (once)"/> + <int value="25" + label="Submitted with fail-luhn-check card without selecting + suggestions (once)"/> </enum> <enum name="AutofillFormSubmittedState"> @@ -2247,6 +2411,12 @@ <int value="5" label="Response improves local (empty)"/> </enum> +<enum name="AutofillRationalizationQualityMetric"> + <int value="0" label="Good Rationalization"/> + <int value="1" label="Ok Rationalization"/> + <int value="2" label="Bad Rationalization"/> +</enum> + <enum name="AutofillSaveCreditCardPrompt"> <int value="0" label="Show requested"/> <int value="1" label="Shown"/> @@ -2377,6 +2547,11 @@ </enum> <enum name="AutofillUserHappiness"> + <summary> + These metrics track the user happiness about Autofill on address and credit + card forms. Starting from M63, these metrics are also split between + Autofill.UserHappiness.Address and Autofill.UserHappiness.CreditCard. + </summary> <int value="0" label="Forms loaded"/> <int value="1" label="Deprecated 1"/> <int value="2" label="Deprecated 2"/> @@ -2385,11 +2560,12 @@ <int value="5" label="User did type"/> <int value="6" label="Suggestions shown"/> <int value="7" label="Suggestions shown (once)"/> - <int value="8" label="User did autofill"/> - <int value="9" label="User did autofill (once)"/> + <int value="8" label="User triggered autofill"/> + <int value="9" label="User triggered autofill (once)"/> <int value="10" label="User edited autofilled field"/> <int value="11" label="User edited autofilled field (once)"/> <int value="12" label="User entered a UPI VPA into a form"/> + <int value="13" label="A field was populated by autofill"/> </enum> <enum name="AutofillWalletAddressConversionType"> @@ -2438,6 +2614,14 @@ <int value="3" label="Slow forward navigation"/> </enum> +<enum name="BackgroundedRendererTransition"> + <int value="0" label="Backgrounded"/> + <int value="1" label="Stopped after a delay"/> + <int value="2" label="Stopped due to critical resources"/> + <int value="3" label="Resumed"/> + <int value="4" label="Foregrounded"/> +</enum> + <enum name="BackgroundFetchEventDispatchResult"> <int value="0" label="Success"/> <int value="1" label="Cannot find worker"/> @@ -2489,6 +2673,8 @@ <int value="9" label="Download cleanup task"/> <int value="10" label="WebView variations task"/> <int value="11" label="Offline content notification task"/> + <int value="12" label="WebAPK update task"/> + <int value="13" label="Download resumption task"/> </enum> <enum name="BackgroundTracingState"> @@ -2526,40 +2712,40 @@ <int value="3" label="RFH_SANDBOX_FLAGS"/> <int value="4" label="RFH_NO_PROXY_TO_PARENT"/> <int value="5" label="RPH_DESERIALIZATION_FAILED"/> - <int value="6" label="RVH_CAN_ACCESS_FILES_OF_PAGE_STATE"/> + <int value="6" label="OBSOLETE_RVH_CAN_ACCESS_FILES_OF_PAGE_STATE"/> <int value="7" label="RFH_FILE_CHOOSER_PATH"/> - <int value="8" label="RWH_SYNTHETIC_GESTURE"/> - <int value="9" label="RWH_FOCUS"/> - <int value="10" label="RWH_BLUR"/> + <int value="8" label="OBSOLETE_RWH_SYNTHETIC_GESTURE"/> + <int value="9" label="OBSOLETE_RWH_FOCUS"/> + <int value="10" label="OBSOLETE_RWH_BLUR"/> <int value="11" label="RWH_SHARED_BITMAP"/> <int value="12" label="RWH_BAD_ACK_MESSAGE"/> - <int value="13" label="RWHVA_SHARED_MEMORY"/> + <int value="13" label="OBSOLETE_RWHVA_SHARED_MEMORY"/> <int value="14" label="SERVICE_WORKER_BAD_URL"/> - <int value="15" label="WC_INVALID_FRAME_SOURCE"/> - <int value="16" label="RWHVM_UNEXPECTED_FRAME_TYPE"/> + <int value="15" label="OBSOLETE_WC_INVALID_FRAME_SOURCE"/> + <int value="16" label="OBSOLETE_RWHVM_UNEXPECTED_FRAME_TYPE"/> <int value="17" label="RFPH_DETACH"/> <int value="18" label="DFH_BAD_EMBEDDER_MESSAGE"/> <int value="19" label="NC_AUTO_SUBFRAME"/> <int value="20" label="CSDH_NOT_RECOGNIZED"/> - <int value="21" label="DSMF_OPEN_STORAGE"/> + <int value="21" label="OBSOLETE_DSMF_OPEN_STORAGE"/> <int value="22" label="DSMF_LOAD_STORAGE"/> - <int value="23" label="DBMF_INVALID_ORIGIN_ON_OPEN"/> - <int value="24" label="DBMF_DB_NOT_OPEN_ON_MODIFY"/> - <int value="25" label="DBMF_DB_NOT_OPEN_ON_CLOSE"/> - <int value="26" label="DBMF_INVALID_ORIGIN_ON_SQLITE_ERROR"/> + <int value="23" label="OBSOLETE_DBMF_INVALID_ORIGIN_ON_OPEN"/> + <int value="24" label="OBSOLETE_DBMF_DB_NOT_OPEN_ON_MODIFY"/> + <int value="25" label="OBSOLETE_DBMF_DB_NOT_OPEN_ON_CLOSE"/> + <int value="26" label="OBSOLETE_DBMF_INVALID_ORIGIN_ON_SQLITE_ERROR"/> <int value="27" label="RDH_INVALID_PRIORITY"/> <int value="28" label="RDH_REQUEST_NOT_TRANSFERRING"/> <int value="29" label="RDH_BAD_DOWNLOAD"/> - <int value="30" label="NMF_NO_PERMISSION_SHOW"/> - <int value="31" label="NMF_NO_PERMISSION_CLOSE"/> - <int value="32" label="NMF_NO_PERMISSION_VERIFY"/> + <int value="30" label="OBSOLETE_NMF_NO_PERMISSION_SHOW"/> + <int value="31" label="OBSOLETE_NMF_NO_PERMISSION_CLOSE"/> + <int value="32" label="OBSOLETE_NMF_NO_PERMISSION_VERIFY"/> <int value="33" label="MH_INVALID_MIDI_PORT"/> <int value="34" label="MH_SYS_EX_PERMISSION"/> <int value="35" label="ACDH_REGISTER"/> <int value="36" label="ACDH_UNREGISTER"/> <int value="37" label="ACDH_SET_SPAWNING"/> <int value="38" label="ACDH_SELECT_CACHE"/> - <int value="39" label="ACDH_SELECT_CACHE_FOR_WORKER"/> + <int value="39" label="OBSOLETE_ACDH_SELECT_CACHE_FOR_WORKER"/> <int value="40" label="ACDH_SELECT_CACHE_FOR_SHARED_WORKER"/> <int value="41" label="ACDH_MARK_AS_FOREIGN_ENTRY"/> <int value="42" label="ACDH_PENDING_REPLY_IN_GET_STATUS"/> @@ -2569,59 +2755,61 @@ <int value="46" label="ACDH_PENDING_REPLY_IN_SWAP_CACHE"/> <int value="47" label="ACDH_SWAP_CACHE"/> <int value="48" label="SWDH_NOT_HANDLED"/> - <int value="49" label="SWDH_REGISTER_BAD_URL"/> - <int value="50" label="SWDH_REGISTER_NO_HOST"/> - <int value="51" label="SWDH_REGISTER_CANNOT"/> - <int value="52" label="SWDH_UNREGISTER_BAD_URL"/> - <int value="53" label="SWDH_UNREGISTER_NO_HOST"/> - <int value="54" label="SWDH_UNREGISTER_CANNOT"/> - <int value="55" label="SWDH_GET_REGISTRATION_BAD_URL"/> - <int value="56" label="SWDH_GET_REGISTRATION_NO_HOST"/> - <int value="57" label="SWDH_GET_REGISTRATION_CANNOT"/> - <int value="58" label="SWDH_GET_REGISTRATION_FOR_READY_NO_HOST"/> - <int value="59" label="SWDH_GET_REGISTRATION_FOR_READY_ALREADY_IN_PROGRESS"/> + <int value="49" label="OBSOLETE_SWDH_REGISTER_BAD_URL"/> + <int value="50" label="OBSOLETE_SWDH_REGISTER_NO_HOST"/> + <int value="51" label="OBSOLETE_SWDH_REGISTER_CANNOT"/> + <int value="52" label="OBSOLETE_SWDH_UNREGISTER_BAD_URL"/> + <int value="53" label="OBSOLETE_SWDH_UNREGISTER_NO_HOST"/> + <int value="54" label="OBSOLETE_SWDH_UNREGISTER_CANNOT"/> + <int value="55" label="OBSOLETE_SWDH_GET_REGISTRATION_BAD_URL"/> + <int value="56" label="OBSOLETE_SWDH_GET_REGISTRATION_NO_HOST"/> + <int value="57" label="OBSOLETE_SWDH_GET_REGISTRATION_CANNOT"/> + <int value="58" label="OBSOLETE_SWDH_GET_REGISTRATION_FOR_READY_NO_HOST"/> + <int value="59" + label="OBSOLETE_SWDH_GET_REGISTRATION_FOR_READY_ALREADY_IN_PROGRESS"/> <int value="60" label="SWDH_POST_MESSAGE"/> - <int value="61" label="SWDH_PROVIDER_CREATED_NO_HOST"/> - <int value="62" label="SWDH_PROVIDER_DESTROYED_NO_HOST"/> - <int value="63" label="SWDH_SET_HOSTED_VERSION_NO_HOST"/> + <int value="61" label="OBSOLETE_SWDH_PROVIDER_CREATED_NO_HOST"/> + <int value="62" label="OBSOLETE_SWDH_PROVIDER_DESTROYED_NO_HOST"/> + <int value="63" label="OBSOLETE_SWDH_SET_HOSTED_VERSION_NO_HOST"/> <int value="64" label="OBSOLETE_SWDH_SET_HOSTED_VERSION"/> - <int value="65" label="SWDH_WORKER_SCRIPT_LOAD_NO_HOST"/> + <int value="65" label="OBSOLETE_SWDH_WORKER_SCRIPT_LOAD_NO_HOST"/> <int value="66" label="SWDH_INCREMENT_WORKER_BAD_HANDLE"/> <int value="67" label="SWDH_DECREMENT_WORKER_BAD_HANDLE"/> - <int value="68" label="SWDH_INCREMENT_REGISTRATION_BAD_HANDLE"/> - <int value="69" label="SWDH_DECREMENT_REGISTRATION_BAD_HANDLE"/> + <int value="68" label="OBSOLETE_SWDH_INCREMENT_REGISTRATION_BAD_HANDLE"/> + <int value="69" label="OBSOLETE_SWDH_DECREMENT_REGISTRATION_BAD_HANDLE"/> <int value="70" label="SWDH_TERMINATE_BAD_HANDLE"/> - <int value="71" label="FAMF_APPEND_ITEM_TO_BLOB"/> - <int value="72" label="FAMF_APPEND_SHARED_MEMORY_TO_BLOB"/> - <int value="73" label="FAMF_MALFORMED_STREAM_URL"/> - <int value="74" label="FAMF_APPEND_ITEM_TO_STREAM"/> - <int value="75" label="FAMF_APPEND_SHARED_MEMORY_TO_STREAM"/> - <int value="76" label="IDBDH_CAN_READ_FILE"/> - <int value="77" label="IDBDH_GET_OR_TERMINATE"/> + <int value="71" label="OBSOLETE_FAMF_APPEND_ITEM_TO_BLOB"/> + <int value="72" label="OBSOLETE_FAMF_APPEND_SHARED_MEMORY_TO_BLOB"/> + <int value="73" label="OBSOLETE_FAMF_MALFORMED_STREAM_URL"/> + <int value="74" label="OBSOLETE_FAMF_APPEND_ITEM_TO_STREAM"/> + <int value="75" label="OBSOLETE_FAMF_APPEND_SHARED_MEMORY_TO_STREAM"/> + <int value="76" label="OBSOLETE_IDBDH_CAN_READ_FILE"/> + <int value="77" label="OBSOLETE_IDBDH_GET_OR_TERMINATE"/> <int value="78" label="RFMF_SET_COOKIE_BAD_ORIGIN"/> <int value="79" label="RFMF_GET_COOKIES_BAD_ORIGIN"/> - <int value="80" label="SWDH_GET_REGISTRATIONS_NO_HOST"/> - <int value="81" label="SWDH_GET_REGISTRATIONS_INVALID_ORIGIN"/> - <int value="82" label="AOAH_UNAUTHORIZED_URL"/> + <int value="80" label="OBSOLETE_SWDH_GET_REGISTRATIONS_NO_HOST"/> + <int value="81" label="OBSOLETE_SWDH_GET_REGISTRATIONS_INVALID_ORIGIN"/> + <int value="82" label="OBSOLETE_AOAH_UNAUTHORIZED_URL"/> <int value="83" label="BDH_INVALID_SERVICE_ID"/> - <int value="84" label="RFH_COMMIT_DESERIALIZATION_FAILED"/> + <int value="84" label="OBSOLETE_RFH_COMMIT_DESERIALIZATION_FAILED"/> <int value="85" label="BDH_INVALID_CHARACTERISTIC_ID"/> - <int value="86" label="SWDH_UPDATE_NO_HOST"/> - <int value="87" label="SWDH_UPDATE_BAD_REGISTRATION_ID"/> - <int value="88" label="SWDH_UPDATE_CANNOT"/> - <int value="89" label="SWDH_UNREGISTER_BAD_REGISTRATION_ID"/> + <int value="86" label="OBSOLETE_SWDH_UPDATE_NO_HOST"/> + <int value="87" label="OBSOLETE_SWDH_UPDATE_BAD_REGISTRATION_ID"/> + <int value="88" label="OBSOLETE_SWDH_UPDATE_CANNOT"/> + <int value="89" label="OBSOLETE_SWDH_UNREGISTER_BAD_REGISTRATION_ID"/> <int value="90" label="BDH_INVALID_WRITE_VALUE_LENGTH"/> - <int value="91" label="WC_MEMORY_CACHE_RESOURCE_BAD_SECURITY_INFO"/> - <int value="92" label="WC_RENDERER_DID_NAVIGATE_BAD_SECURITY_INFO"/> + <int value="91" label="OBSOLETE_WC_MEMORY_CACHE_RESOURCE_BAD_SECURITY_INFO"/> + <int value="92" label="OBSOLETE_WC_RENDERER_DID_NAVIGATE_BAD_SECURITY_INFO"/> <int value="93" label="OBSOLETE_BDH_DUPLICATE_REQUEST_DEVICE_ID"/> <int value="94" label="CSDH_INVALID_ORIGIN"/> <int value="95" label="RDH_ILLEGAL_ORIGIN"/> - <int value="96" label="RDH_UNAUTHORIZED_HEADER_REQUEST"/> + <int value="96" label="OBSOLETE_RDH_UNAUTHORIZED_HEADER_REQUEST"/> <int value="97" label="RDH_INVALID_URL"/> - <int value="98" label="BDH_CHARACTERISTIC_ALREADY_SUBSCRIBED"/> + <int value="98" label="OBSOLETE_BDH_CHARACTERISTIC_ALREADY_SUBSCRIBED"/> <int value="99" label="RFH_OWNER_PROPERTY"/> - <int value="100" label="BDH_EMPTY_OR_INVALID_FILTERS"/> - <int value="101" label="WC_CONTENT_WITH_CERT_ERRORS_BAD_SECURITY_INFO"/> + <int value="100" label="OBSOLETE_BDH_EMPTY_OR_INVALID_FILTERS"/> + <int value="101" + label="OBSOLETE_WC_CONTENT_WITH_CERT_ERRORS_BAD_SECURITY_INFO"/> <int value="102" label="RFMF_RENDERER_FAKED_ITS_OWN_DEATH"/> <int value="103" label="DWNLD_INVALID_SAVABLE_RESOURCE_LINKS_RESPONSE"/> <int value="104" label="DWNLD_INVALID_SERIALIZE_AS_MHTML_RESPONSE"/> @@ -2639,18 +2827,18 @@ <int value="116" label="BDH_CONSTRUCTION_FAILED"/> <int value="117" label="BDH_INVALID_REFCOUNT_OPERATION"/> <int value="118" label="BDH_INVALID_URL_OPERATION"/> - <int value="119" label="IDBDH_INVALID_ORIGIN"/> + <int value="119" label="OBSOLETE_IDBDH_INVALID_ORIGIN"/> <int value="120" label="RFH_FAIL_PROVISIONAL_LOAD_NO_HANDLE"/> - <int value="121" label="RFH_FAIL_PROVISIONAL_LOAD_NO_ERROR"/> + <int value="121" label="OBSOLETE_RFH_FAIL_PROVISIONAL_LOAD_NO_ERROR"/> <int value="122" label="NI_IN_PAGE_NAVIGATION"/> <int value="123" label="RPH_MOJO_PROCESS_ERROR"/> - <int value="124" label="DBMF_INVALID_ORIGIN_ON_GET_SPACE"/> - <int value="125" label="DBMF_INVALID_ORIGIN_ON_MODIFIED"/> - <int value="126" label="DBMF_INVALID_ORIGIN_ON_CLOSED"/> + <int value="124" label="OBSOLETE_DBMF_INVALID_ORIGIN_ON_GET_SPACE"/> + <int value="125" label="OBSOLETE_DBMF_INVALID_ORIGIN_ON_MODIFIED"/> + <int value="126" label="OBSOLETE_DBMF_INVALID_ORIGIN_ON_CLOSED"/> <int value="127" label="WSI_INVALID_HEADER_VALUE"/> - <int value="128" label="SWDH_SET_HOSTED_VERSION_INVALID_HOST"/> - <int value="129" label="SWDH_SET_HOSTED_VERSION_PROCESS_MISMATCH"/> - <int value="130" label="MSDH_INVALID_FRAME_ID"/> + <int value="128" label="OBSOLETE_SWDH_SET_HOSTED_VERSION_INVALID_HOST"/> + <int value="129" label="OBSOLETE_SWDH_SET_HOSTED_VERSION_PROCESS_MISMATCH"/> + <int value="130" label="OBSOLETE_MSDH_INVALID_FRAME_ID"/> <int value="131" label="SDH_INVALID_PORT_RANGE"/> <int value="132" label="SCO_INVALID_ARGUMENT"/> <int value="133" label="RFH_INCONSISTENT_DEVTOOLS_MESSAGE"/> @@ -2658,35 +2846,41 @@ <int value="135" label="DSH_NOT_CREATED_SESSION_ID"/> <int value="136" label="DSH_NOT_ALLOCATED_SESSION_ID"/> <int value="137" label="DSH_DELETED_SESSION_ID"/> - <int value="138" label="DSH_WRONG_STORAGE_PARTITION"/> + <int value="138" label="OBSOLETE_DSH_WRONG_STORAGE_PARTITION"/> <int value="139" label="BDH_DISALLOWED_ORIGIN"/> <int value="140" label="ARH_CREATED_STREAM_WITHOUT_AUTHORIZATION"/> <int value="141" label="MDDH_INVALID_DEVICE_TYPE_REQUEST"/> - <int value="142" label="MDDH_UNAUTHORIZED_ORIGIN"/> - <int value="143" label="SWDH_ENABLE_NAVIGATION_PRELOAD_NO_HOST"/> - <int value="144" label="SWDH_ENABLE_NAVIGATION_PRELOAD_INVALID_ORIGIN"/> - <int value="145" label="SWDH_ENABLE_NAVIGATION_PRELOAD_BAD_REGISTRATION_ID"/> + <int value="142" label="OBSOLETE_MDDH_UNAUTHORIZED_ORIGIN"/> + <int value="143" label="OBSOLETE_SWDH_ENABLE_NAVIGATION_PRELOAD_NO_HOST"/> + <int value="144" + label="OBSOLETE_SWDH_ENABLE_NAVIGATION_PRELOAD_INVALID_ORIGIN"/> + <int value="145" + label="OBSOLETE_SWDH_ENABLE_NAVIGATION_PRELOAD_BAD_REGISTRATION_ID"/> <int value="146" label="RDH_TRANSFERRING_REQUEST_NOT_FOUND"/> <int value="147" label="RDH_TRANSFERRING_NONNAVIGATIONAL_REQUEST"/> - <int value="148" label="SWDH_GET_NAVIGATION_PRELOAD_STATE_NO_HOST"/> - <int value="149" label="SWDH_GET_NAVIGATION_PRELOAD_STATE_INVALID_ORIGIN"/> + <int value="148" label="OBSOLETE_SWDH_GET_NAVIGATION_PRELOAD_STATE_NO_HOST"/> + <int value="149" + label="OBSOLETE_SWDH_GET_NAVIGATION_PRELOAD_STATE_INVALID_ORIGIN"/> <int value="150" - label="SWDH_GET_NAVIGATION_PRELOAD_STATE_BAD_REGISTRATION_ID"/> - <int value="151" label="SWDH_SET_NAVIGATION_PRELOAD_HEADER_NO_HOST"/> - <int value="152" label="SWDH_SET_NAVIGATION_PRELOAD_HEADER_INVALID_ORIGIN"/> + label="OBSOLETE_SWDH_GET_NAVIGATION_PRELOAD_STATE_BAD_REGISTRATION_ID"/> + <int value="151" label="OBSOLETE_SWDH_SET_NAVIGATION_PRELOAD_HEADER_NO_HOST"/> + <int value="152" + label="OBSOLETE_SWDH_SET_NAVIGATION_PRELOAD_HEADER_INVALID_ORIGIN"/> <int value="153" - label="SWDH_SET_NAVIGATION_PRELOAD_HEADER_BAD_REGISTRATION_ID"/> - <int value="154" label="SWDH_SET_NAVIGATION_PRELOAD_HEADER_BAD_VALUE"/> + label="OBSOLETE_SWDH_SET_NAVIGATION_PRELOAD_HEADER_BAD_REGISTRATION_ID"/> + <int value="154" + label="OBSOLETE_SWDH_SET_NAVIGATION_PRELOAD_HEADER_BAD_VALUE"/> <int value="155" label="MDDH_INVALID_SUBSCRIPTION_REQUEST"/> - <int value="156" label="MDDH_INVALID_UNSUBSCRIPTION_REQUEST"/> - <int value="157" label="AOAH_NONSENSE_DEVICE_ID"/> + <int value="156" label="OBSOLETE_MDDH_INVALID_UNSUBSCRIPTION_REQUEST"/> + <int value="157" label="OBSOLETE_AOAH_NONSENSE_DEVICE_ID"/> <int value="158" label="BDH_INVALID_OPTIONS"/> <int value="159" label="RFH_DID_ADD_CONSOLE_MESSAGE_BAD_SEVERITY"/> <int value="160" label="AIRH_VOLUME_OUT_OF_RANGE"/> <int value="161" label="BDH_INVALID_DESCRIPTOR_ID"/> - <int value="162" label="RWH_INVALID_BEGIN_FRAME_ACK_DID_NOT_SWAP"/> - <int value="163" label="RWH_INVALID_BEGIN_FRAME_ACK_COMPOSITOR_FRAME"/> - <int value="164" label="BFSI_INVALID_ID"/> + <int value="162" label="OBSOLETE_RWH_INVALID_BEGIN_FRAME_ACK_DID_NOT_SWAP"/> + <int value="163" + label="OBSOLETE_RWH_INVALID_BEGIN_FRAME_ACK_COMPOSITOR_FRAME"/> + <int value="164" label="BFSI_INVALID_DEVELOPER_ID"/> <int value="165" label="BFSI_INVALID_REQUESTS"/> <int value="166" label="BFSI_INVALID_TITLE"/> <int value="167" label="RWH_INVALID_FRAME_TOKEN"/> @@ -2695,12 +2889,33 @@ <int value="170" label="RFH_ILLEGAL_UPLOAD_PARAMS"/> <int value="171" label="RFH_BASE_URL_FOR_DATA_URL_SPECIFIED"/> <int value="172" label="RFPH_ILLEGAL_UPLOAD_PARAMS"/> - <int value="173" label="SWDH_PROVIDER_CREATED_ILLEGAL_TYPE"/> + <int value="173" label="OBSOLETE_SWDH_PROVIDER_CREATED_ILLEGAL_TYPE"/> <int value="174" label="SWDH_PROVIDER_CREATED_ILLEGAL_TYPE_NOT_WINDOW"/> <int value="175" label="SWDH_PROVIDER_CREATED_ILLEGAL_TYPE_CONTROLLER"/> <int value="176" label="SWDH_PROVIDER_CREATED_DUPLICATE_ID"/> <int value="177" label="SWDH_PROVIDER_CREATED_BAD_ID"/> <int value="178" label="RFH_KEEP_ALIVE_HANDLE_REQUESTED_INCORRECTLY"/> + <int value="179" label="BFSI_INVALID_UNIQUE_ID"/> + <int value="180" label="BPE_UNEXPECTED_MESSAGE_BEFORE_BPGM_CREATION"/> + <int value="181" label="WEBUI_SEND_FROM_UNAUTHORIZED_PROCESS"/> + <int value="182" + label="CPFC_RESIZE_PARAMS_CHANGED_LOCAL_SURFACE_ID_UNCHANGED"/> + <int value="183" + label="BPG_RESIZE_PARAMS_CHANGED_LOCAL_SURFACE_ID_UNCHANGED"/> + <int value="184" label="RFH_NEGATIVE_SELECTION_START_OFFSET"/> + <int value="185" label="WEBUI_BAD_SCHEME_ACCESS"/> + <int value="186" label="CSDH_UNEXPECTED_OPERATION"/> + <int value="187" label="RMF_BAD_URL_CACHEABLE_METADATA"/> + <int value="188" label="RFH_INTERFACE_PROVIDER_MISSING"/> + <int value="189" label="OBSOLETE_RFH_INTERFACE_PROVIDER_SUPERFLUOUS"/> + <int value="190" label="AIRH_UNEXPECTED_BITSTREAM"/> + <int value="191" label="ARH_UNEXPECTED_BITSTREAM"/> + <int value="192" label="RDH_NULL_CLIENT"/> + <int value="193" label="RVH_WEB_UI_BINDINGS_MISMATCH"/> + <int value="194" label="WCI_NEW_WIDGET_PROCESS_MISMATCH"/> + <int value="195" label="AUTH_INVALID_EFFECTIVE_DOMAIN"/> + <int value="196" label="AUTH_INVALID_RELYING_PARTY"/> + <int value="197" label="RWH_COPY_REQUEST_ATTEMPT"/> </enum> <enum name="BadMessageReasonExtensions"> @@ -2794,6 +3009,13 @@ <int value="2" label="1+"/> </enum> +<enum name="BeforeUnloadDialogResult"> + <int value="0" label="No dialog: no string returned"/> + <int value="1" label="No dialog: blocked, no user gesture"/> + <int value="2" label="No dialog: blocked, multiple confirmation panels"/> + <int value="3" label="Show dialog"/> +</enum> + <enum name="BiquadFilterType"> <int value="0" label="lowpass"/> <int value="1" label="highpass"/> @@ -2828,6 +3050,7 @@ <int value="3" label="Source died in transit"/> <int value="4" label="Blob dereferenced while building"/> <int value="5" label="Referenced blob broken"/> + <int value="6" label="Referenced file unavailable"/> </enum> <enum name="BlobStorageDiskSpaceAdjustment"> @@ -2985,6 +3208,38 @@ <int value="3" label="LE with random address"/> </enum> +<enum name="BookmarkAppNavigationResult"> + <int value="0" label="From app or tab to new tab: Context Menu navigation"/> + <int value="1" + label="From probably omnibox to same context: Typed navigation"/> + <int value="2" + label="From probably launch surface e.g. NTP, Shelf, etc. to new app or + tab: Auto Bookmark navigation"/> + <int value="3" label="Keep in subframe: Auto subframe navigation"/> + <int value="4" label="Keep in subframe: Manual subframe navigation"/> + <int value="5" + label="From probably tab to same context: Generated entry navigation"/> + <int value="6" + label="From probably tab to same context: Auto top level navigation"/> + <int value="7" label="From app or tab to same context: Reload navigation"/> + <int value="8" label="From probably tab to same context: Keyword navigation"/> + <int value="9" + label="From probably tab to same context: Generated keyword navigation"/> + <int value="10" + label="From app or tab to same context: Forward/Back navigation"/> + <int value="11" + label="From probably omnibox to same context: Address bar navigation"/> + <int value="12" label="From app to new tab: Out of scope launch"/> + <int value="13" label="From app to same context: Same scope navigation"/> + <int value="14" label="From tab to same context: Form submission"/> + <int value="15" label="From tab to same context: Same scope navigation"/> + <int value="16" label="In app or tab, cancel prerender link navigation"/> + <int value="17" + label="From app or tab to new app context, close previous context"/> + <int value="18" label="From app or tab to new app context"/> + <int value="19" label="From app to new tab: Out of scope navigation"/> +</enum> + <enum name="BookmarkLaunchLocation"> <int value="0" label="Attached bookmark bar"/> <int value="1" label="Detached (floating) bookmark bar"/> @@ -3011,6 +3266,20 @@ <int value="12" label="Copy"/> <int value="13" label="Cut"/> <int value="14" label="Paste"/> + <int value="15" label="Sort"/> + <int value="16" label="AddBookmark"/> + <int value="17" label="AddFolder"/> + <int value="18" label="Import"/> + <int value="19" label="Export"/> + <int value="20" label="Help center"/> +</enum> + +<enum name="BookmarkManagerMenuSource"> + <int value="0" label="None"/> + <int value="1" label="Item"/> + <int value="2" label="Tree"/> + <int value="3" label="Toolbar"/> + <int value="4" label="List"/> </enum> <enum name="BookmarksEntryPoint"> @@ -3036,6 +3305,11 @@ <int value="2" label="Open in incognito tab"/> </enum> +<enum name="BookmarkType"> + <int value="0" label="Normal"/> + <int value="1" label="Partner"/> +</enum> + <enum name="Boolean"> <int value="0" label="False"/> <int value="1" label="True"/> @@ -3071,6 +3345,11 @@ <int value="1" label="Allowed"/> </enum> +<enum name="BooleanAttached"> + <int value="0" label="Detached"/> + <int value="1" label="Attached"/> +</enum> + <enum name="BooleanAttempted"> <int value="0" label="Not Attempted"/> <int value="1" label="Attempted"/> @@ -3141,6 +3420,11 @@ <int value="1" label="Clicked"/> </enum> +<enum name="BooleanClickedThroughSBInterstitial"> + <int value="0" label="Didn't click through"/> + <int value="1" label="Clicked through"/> +</enum> + <enum name="BooleanCloned"> <int value="0" label="Not cloned"/> <int value="1" label="Cloned"/> @@ -3171,11 +3455,21 @@ <int value="1" label="Connected"/> </enum> +<enum name="BooleanConnectionError"> + <int value="0" label="Connected"/> + <int value="1" label="Connection error happened"/> +</enum> + <enum name="BooleanContainedMeCard"> <int value="0" label="Did not contain me card."/> <int value="1" label="Contained me card."/> </enum> +<enum name="BooleanContinueChoice"> + <int value="0" label="Chose CANCEL"/> + <int value="1" label="Chose CONTINUE"/> +</enum> + <enum name="BooleanCorrupt"> <int value="0" label="Not Corrupt"/> <int value="1" label="Corrupt"/> @@ -3251,6 +3545,21 @@ <int value="1" label="User did change scale"/> </enum> +<enum name="BooleanDispatched"> + <int value="0" label="Not dispatched"/> + <int value="1" label="Dispatched"/> +</enum> + +<enum name="BooleanDowngrade"> + <int value="0" label="Not downgraded"/> + <int value="1" label="Downgraded"/> +</enum> + +<enum name="BooleanDownloaded"> + <int value="0" label="Local file"/> + <int value="1" label="File downloaded"/> +</enum> + <enum name="BooleanDuplicate"> <int value="0" label="Not Duplicate"/> <int value="1" label="Duplicate"/> @@ -3266,6 +3575,11 @@ <int value="1" label="Enabled"/> </enum> +<enum name="BooleanEncryptedEvent"> + <int value="0" label="Media player instance"/> + <int value="1" label="Encrypted event fired"/> +</enum> + <enum name="BooleanEqual"> <int value="0" label="Not Equal"/> <int value="1" label="Equal"/> @@ -3391,6 +3705,11 @@ <int value="1" label="Hardware accelerated"/> </enum> +<enum name="BooleanHasCert"> + <int value="0" label="Certificate absent"/> + <int value="1" label="Certificate present"/> +</enum> + <enum name="BooleanHasCollapseKey"> <int value="0" label="No collapse_key"/> <int value="1" label="Has collapse_key"/> @@ -3456,6 +3775,11 @@ <int value="1" label="Foreground"/> </enum> +<enum name="BooleanInstalled"> + <int value="0" label="Not installed"/> + <int value="1" label="Installed"/> +</enum> + <enum name="BooleanInvalid"> <int value="0" label="Valid"/> <int value="1" label="Invalid"/> @@ -3486,6 +3810,16 @@ <int value="1" label="Is Shared"/> </enum> +<enum name="BooleanIsTagged"> + <int value="0" label="Not Tagged"/> + <int value="1" label="Is Tagged"/> +</enum> + +<enum name="BooleanLatched"> + <int value="0" label="Not latched"/> + <int value="1" label="Latched"/> +</enum> + <enum name="BooleanLoaded"> <int value="0" label="Not loaded"/> <int value="1" label="Loaded"/> @@ -3541,6 +3875,11 @@ <int value="1" label="FMP not OK, network was already quiet"/> </enum> +<enum name="BooleanNull"> + <int value="0" label="Is not a nullptr"/> + <int value="1" label="Is a nullptr"/> +</enum> + <enum name="BooleanNullStream"> <int value="0" label="Stream is not a nullptr"/> <int value="1" label="Stream is a nullptr"/> @@ -3581,6 +3920,11 @@ <int value="1" label="Panel was open"/> </enum> +<enum name="BooleanPasswordSavedWithFallback"> + <int value="0" label="Automatic prompt"/> + <int value="1" label="Manual fallback"/> +</enum> + <enum name="BooleanPending"> <int value="0" label="Decided"/> <int value="1" label="Pending"/> @@ -3796,11 +4140,21 @@ <int value="1" label="Unknown"/> </enum> +<enum name="BooleanUnresponsive"> + <int value="0" label="Responsive"/> + <int value="1" label="Unresponsive"/> +</enum> + <enum name="BooleanUsage"> <int value="0" label="Not Used"/> <int value="1" label="Used"/> </enum> +<enum name="BooleanUsernameCorrectionVote"> + <int value="0" label="No username correction found"/> + <int value="1" label="Username correction found"/> +</enum> + <enum name="BooleanValid"> <int value="0" label="Invalid"/> <int value="1" label="Valid"/> @@ -3831,6 +4185,11 @@ <int value="1" label="Waited"/> </enum> +<enum name="BooleanWarningReceived"> + <int value="0" label="Warning Not Received"/> + <int value="1" label="Warning Received"/> +</enum> + <enum name="BooleanWasFast"> <int value="0" label="Slow"/> <int value="1" label="Fast"/> @@ -3841,6 +4200,11 @@ <int value="1" label="Wasted"/> </enum> +<enum name="BooleanWebApkNotificationPermission"> + <int value="0" label="WebAPK notification permission disabled"/> + <int value="1" label="WebAPK notification permission enabled"/> +</enum> + <enum name="BooleanWiped"> <int value="0" label="Re-enabled"/> <int value="1" label="Wiped out"/> @@ -3910,6 +4274,21 @@ <int value="36" label="UNREACHABLE_6"/> </enum> +<enum name="BrowserActionsMenuOption"> + <int value="0" label="Open in new Chrome tab"/> + <int value="1" label="Open in incognito tab"/> + <int value="2" label="Download page"/> + <int value="3" label="Copy link"/> + <int value="4" label="Share link"/> + <int value="5" label="App provided items"/> +</enum> + +<enum name="BubbleDismissalReason"> + <int value="0" label="The timer dismissed the bubble."/> + <int value="1" label="A tap inside the bubble caused dismissal."/> + <int value="2" label="A tap outside the bubble caused dismissal."/> +</enum> + <enum name="BubbleType"> <int value="0" label="Unknown Bubble"/> <int value="1" label="Mock Bubble"/> @@ -3927,6 +4306,17 @@ <int value="4" label="CACHE_MISS"/> </enum> +<enum name="CacheStorageErrorType"> + <int value="0" label="OK"/> + <int value="1" label="Exists Error"/> + <int value="2" label="Storage Error"/> + <int value="3" label="Not Found Error"/> + <int value="4" label="Quota Exceeded Error"/> + <int value="5" label="Cache Name Not Found Error"/> + <int value="6" label="Query Too Large Error"/> + <int value="7" label="Not Implemented Error"/> +</enum> + <enum name="CALayerResult"> <int value="0" label="Success"/> <int value="1" label="Unknown failure"/> @@ -3961,6 +4351,22 @@ <int value="1" label="Not Used"/> </enum> +<enum name="CanonicalURLResult"> + <int value="0" label="Canonical URL not retrieved: Visible URL not HTTPS"/> + <int value="1" + label="(obsolete) Canonical URL not retrieved: Canonical URL not HTTPS + (but visible URL is)"/> + <int value="2" + label="Canonical URL not retrieved: Page had no canonical URL defined"/> + <int value="3" + label="Canonical URL not retrieved: Page's canonical URL was invalid"/> + <int value="4" label="Canonical URL retrieved: Differed from visible URL"/> + <int value="5" label="Canonical URL retrieved: Same as visible URL"/> + <int value="6" + label="Canonical URL retrieved: Canonical URL not HTTPS (but visible + URL is)"/> +</enum> + <enum name="CanvasContextType"> <int value="0" label="2d"/> <int value="1" label="(obsolete) webkit-3d"/> @@ -3973,12 +4379,12 @@ <enum name="CanvasContextUsage"> <int value="0" label="CanvasCreated"/> <int value="1" label="GPUAccelerated2DCanvasImageBufferCreated"/> - <int value="2" label="DisplayList2DCanvasImageBufferCreated"/> + <int value="2" label="(obsolete) DisplayList2DCanvasImageBufferCreated"/> <int value="3" label="Unaccelerated2DCanvasImageBufferCreated"/> <int value="4" label="Accelerated2DCanvasGPUContextLost"/> <int value="5" label="Unaccelerated2DCanvasImageBufferCreationFailed"/> <int value="6" label="GPUAccelerated2DCanvasImageBufferCreationFailed"/> - <int value="7" label="DisplayList2DCanvasFallbackToRaster"/> + <int value="7" label="(obsolete) DisplayList2DCanvasFallbackToRaster"/> <int value="8" label="GPUAccelerated2DCanvasDeferralDisabled"/> <int value="10" label="GPUAccelerated2DCanvasSurfaceCreationFailed"/> </enum> @@ -3995,13 +4401,16 @@ </enum> <enum name="CanvasDisplayListFallbackReason"> + <obsolete> + Deprecated 11/2017 with removal of Display List Canvas 2D mode. + </obsolete> <int value="0" label="Unknown (Should not be seen in production)."/> <int value="1" label="Canvas not cleared between consecutive frames."/> <int value="2" label="Canvas state stack too large (unbalanced save/restore?)."/> <int value="3" label="Direct pixel write."/> - <int value="4" label="Flush for initial clear."/> - <int value="5" label="Flush after drawing from a WebGL canvas."/> + <int value="4" label="Flush for initial clear. (obsolete)"/> + <int value="5" label="Flush after drawing from a WebGL canvas. (obsolete)"/> <int value="6" label="Acquiring snapshot for getImageData()."/> <int value="7" label="Acquiring snapshot for WebGL texture upload. (obsolete)"/> @@ -4220,6 +4629,13 @@ <int value="4" label="Init Verification Failed"/> </enum> +<enum name="CdmLoadResult"> + <int value="0" label="Success"/> + <int value="1" label="CDM file missing"/> + <int value="2" label="CDM file exists but load failed"/> + <int value="3" label="CDM loaded but entry point missing"/> +</enum> + <enum name="CdmPromiseResult"> <int value="0" label="Success"/> <int value="1" label="NotSupportedError"/> @@ -4233,6 +4649,13 @@ <int value="9" label="SessionAlreadyExists"/> </enum> +<enum name="CdmSystemCode"> +<!-- System Code is CDM specific. Use this as a placeholder to treat sparse +histogram as enum --> + + <int value="0" label="Unknown Error"/> +</enum> + <enum name="CertificateChainPosition"> <obsolete> Deprecated as of 01/2016. CertCacheTrial has been removed. @@ -4241,6 +4664,13 @@ <int value="0" label="Root Certificate"/> </enum> +<enum name="CertificateReportOutcome"> + <int value="0" label="Submitted"/> + <int value="1" label="Failed"/> + <int value="2" label="Successful"/> + <int value="3" label="Dropped or ignored"/> +</enum> + <enum name="CertificateTransparencyDnsQueryStatus"> <int value="0" label="SUCCESS"/> <int value="1" label="FAILED_UNKNOWN"/> @@ -4289,6 +4719,13 @@ <int value="3" label="Stream was never read at all"/> </enum> +<enum name="CheckerableImageType"> + <int value="0" label="Checkerable image was used with an img tag"/> + <int value="1" label="Checkerable image was used with an svg tag"/> + <int value="2" label="Checkerable image was used with a css style property"/> + <int value="3" label="Not checkerable image"/> +</enum> + <enum name="CheckerImagingDecision"> <int value="0" label="Can decode asynchronously."/> <int value="1" label="Image is animated."/> @@ -4337,6 +4774,20 @@ <int value="4" label="Browser Startup"/> </enum> +<enum name="ChromeHomePromoResult"> + <int value="0" label="Enabled Chome Home"/> + <int value="1" label="Disabled Chome Home"/> + <int value="2" label="Chrome Home remained enabled"/> + <int value="3" label="Chrome Home remained disabled"/> + <int value="4" label="No action"/> +</enum> + +<enum name="ChromeHomePromoShowReason"> + <int value="0" label="NTP"/> + <int value="1" label="Menu"/> + <int value="2" label="Startup"/> +</enum> + <enum name="ChromeNotifierServiceActionType"> <int value="0" label="Unknown"/> <int value="1" label="First service enabled"/> @@ -4472,6 +4923,41 @@ <int value="255" label="Unspecified/unknown error in user-mode"/> </enum> +<enum name="ChromeOSUICommands"> +<!-- Please put in checks to ensure Command IDs are stable before adding them to this enum. --> + + <int value="0" label="Launch App"/> + <int value="1" label="Close"/> + <int value="2" label="Toggle Pin"/> + <int value="3" label="Open in a pinned tab"/> + <int value="4" label="Open in a regular tab"/> + <int value="5" label="Open in fullscreen"/> + <int value="6" label="Open in window"/> + <int value="7" label="Open in a new window"/> + <int value="8" label="Open in a new incognito window"/> + <int value="100" label="Launch New"/> + <int value="101" label="Toggle Pin"/> + <int value="102" label="Show App Info"/> + <int value="103" label="Options"/> + <int value="104" label="Uninstall"/> + <int value="105" label="Remove From Folder"/> + <int value="106" label="Open in New Window"/> + <int value="107" label="Open in New Incognito Window"/> + <int value="108" label="Install"/> + <int value="200" label="Open in a pinned tab"/> + <int value="201" label="Open in a regular tab."/> + <int value="202" label="Open in fullscreen"/> + <int value="203" label="Open in a window"/> + <int value="500" label="Toggle Auto Hide"/> + <int value="501" label="Shelf Alignment Menu"/> + <int value="502" label="Shelf Alignment Left"/> + <int value="503" label="Shelf Alignment Right"/> + <int value="504" label="Shelf Alignment Bottom"/> + <int value="505" label="Change Wallpaper"/> +<!-- Please put in checks to ensure Command IDs are stable before adding them to this enum. --> + +</enum> + <enum name="ChromeOSUserImageId"> <summary> Indices of the default images as defined in @@ -4503,6 +4989,53 @@ <int value="22" label="Profile image"/> </enum> +<enum name="ChromePDFViewerActions"> + <int value="0" label="DocumentOpened"/> + <int value="1" label="RotateFirst"/> + <int value="2" label="Rotate"/> + <int value="3" label="FitToWidthFirst"/> + <int value="4" label="FitToWidth"/> + <int value="5" label="FitToPageFirst"/> + <int value="6" label="FitToPage"/> + <int value="7" label="OpenBookmarksPanelFirst"/> + <int value="8" label="OpenBookmarksPanel"/> + <int value="9" label="FollowBookmarkFirst"/> + <int value="10" label="FollowBookmark"/> + <int value="11" label="PageSelectorNavigateFirst"/> + <int value="12" label="PageSelectorNavigate"/> +</enum> + +<enum name="ChromePDFViewerAnnotationType"> + <int value="0" label="Unknown"/> + <int value="1" label="Text"/> + <int value="2" label="Link"/> + <int value="3" label="FreeText"/> + <int value="4" label="Line"/> + <int value="5" label="Square"/> + <int value="6" label="Circle"/> + <int value="7" label="Polygon"/> + <int value="8" label="Polyline"/> + <int value="9" label="Highlight"/> + <int value="10" label="Underline"/> + <int value="11" label="Squiggly"/> + <int value="12" label="StrikeOut"/> + <int value="13" label="Stamp"/> + <int value="14" label="Caret"/> + <int value="15" label="Ink"/> + <int value="16" label="Popup"/> + <int value="17" label="FileAttachment"/> + <int value="18" label="Sound"/> + <int value="19" label="Movie"/> + <int value="20" label="Widget"/> + <int value="21" label="Screen"/> + <int value="22" label="PrinterMark"/> + <int value="23" label="TrapNet"/> + <int value="24" label="Watermark"/> + <int value="25" label="3D"/> + <int value="26" label="RichMedia"/> + <int value="27" label="XFAWidget"/> +</enum> + <enum name="ChromePDFViewerLoadStatus"> <int value="0" label="Loaded a full-page PDF with Chrome PDF Viewer"/> <int value="1" label="Loaded an embedded PDF with Chrome PDF Viewer"/> @@ -4512,6 +5045,15 @@ <int value="5" label="View PDF button clicked in the PDF plugin placeholder"/> </enum> +<enum name="ChromePrimaryAccountStateInGaiaCookies"> + <int value="0" label="No Chrome primary account."/> + <int value="1" + label="Chrome primary account is the first account in Gaia cookies."/> + <int value="2" + label="Chrome primary account is another account in Gaia cookies."/> + <int value="3" label="Chrome primary account is not in Gaia cookies."/> +</enum> + <enum name="ChromiumAndroidLinkerBrowserState"> <int value="0" label="Normal, Random Address Load"/> <int value="1" label="Low memory, Fixed Address Load Success"/> @@ -4525,6 +5067,9 @@ </enum> <enum name="CLD2LanguageCode"> + <obsolete> + Deprecated as of 11/2017, since cld2 is deprecated. + </obsolete> <summary> See Language in third_party/cld_2/src/internal/generated_language.h. </summary> @@ -5316,6 +5861,7 @@ <int value="9" label="Line"/> <int value="10" label="Whatsapp"/> <int value="11" label="Gsa"/> + <int value="12" label="WebAPK"/> </enum> <enum name="ClipboardAction"> @@ -5422,7 +5968,8 @@ </enum> <enum name="CombinedHttpResponseAndNetErrorCode"> -<!-- Generated from net/base/net_error_list.h --> +<!-- Generated from net/base/net_error_list.h. +Called by update_net_error_codes.py.--> <int value="-806" label="DNS_SORT_ERROR"/> <int value="-805" label="DNS_SEARCH_EMPTY"/> @@ -5522,6 +6069,7 @@ <int value="-312" label="UNSAFE_PORT"/> <int value="-311" label="UNSAFE_REDIRECT"/> <int value="-310" label="TOO_MANY_REDIRECTS"/> + <int value="-303" label="INVALID_REDIRECT"/> <int value="-302" label="UNKNOWN_URL_SCHEME"/> <int value="-301" label="DISALLOWED_URL_SCHEME"/> <int value="-300" label="INVALID_URL"/> @@ -5540,6 +6088,7 @@ <int value="-202" label="CERT_AUTHORITY_INVALID"/> <int value="-201" label="CERT_DATE_INVALID"/> <int value="-200" label="CERT_COMMON_NAME_INVALID"/> + <int value="-176" label="NO_BUFFER_SPACE"/> <int value="-175" label="SSL_VERSION_INTERFERENCE"/> <int value="-174" label="READ_IF_READY_NOT_IMPLEMENTED"/> <int value="-173" label="WS_UPGRADE"/> @@ -5694,6 +6243,35 @@ <int value="2" label="Successful first layout"/> </enum> +<enum name="CompileHeuristicsDecision"> + <int value="0" label="NoCacheHandler"> + No CachedMetadataHandler was provided, thus caching functionality is + disabled. + </int> + <int value="1" label="CachingDisabled">Caching is disabled by settings.</int> + <int value="2" label="CodeTooShortToCache"> + The script is too short to benefit from caching, thus caching functionality + is disabled. + </int> + <int value="3" label="CacheTooCold"> + The script is not loaded often enough to benefit from caching, thus not + producing cache. + </int> + <int value="4" label="ProduceParserCache"> + Parser cache is produced for the script when compiled. + </int> + <int value="5" label="ConsumeParserCache"> + Consume previously generated parser cache for the script. + </int> + <int value="6" label="ProduceCodeCache"> + Code cache is produced for the script when compiled. + </int> + <int value="7" label="ConsumeCodeCache"> + Consume previously generated code cache for the script. + </int> + <int value="8" label="StreamingCompile">Use streamed compilation result.</int> +</enum> + <enum name="ComponentUpdaterCalls"> <int value="0" label="Install"/> <int value="1" label="Update"/> @@ -5751,6 +6329,9 @@ <int value="8" label="FAILURE_SESSION_RATE_PARSE"/> <int value="9" label="FAILURE_AVAILABILITY_PARSE"/> <int value="10" label="FAILURE_UNKNOWN_KEY"/> + <int value="11" label="FAILURE_SESSION_RATE_IMPACT_PARSE"/> + <int value="12" label="FAILURE_SESSION_RATE_IMPACT_UNKNOWN_FEATURE"/> + <int value="13" label="FAILURE_TRACKING_ONLY_PARSE"/> </enum> <enum name="ConnectionDiagnosticsIssue"> @@ -5821,6 +6402,12 @@ <int value="14" label="QUIC/36"/> <int value="15" label="QUIC/37"/> <int value="16" label="QUIC/38"/> + <int value="17" label="QUIC/39"/> + <int value="18" label="QUIC/40"/> + <int value="19" label="QUIC/41"/> + <int value="20" label="QUIC/42"/> + <int value="21" label="QUIC/43"/> + <int value="22" label="QUIC/99"/> </enum> <enum name="ConnectionResult"> @@ -5971,6 +6558,24 @@ <int value="5" label="DETECT_IMPORTANT_CONTENT"/> </enum> +<enum name="ContentSettingImageType"> + <int value="0" label="COOKIES"/> + <int value="1" label="IMAGES"/> + <int value="2" label="JAVASCRIPT"/> + <int value="3" label="PPAPI_BROKER"/> + <int value="4" label="PLUGINS"/> + <int value="5" label="POPUPS"/> + <int value="6" label="GEOLOCATION"/> + <int value="7" label="MIXEDSCRIPT"/> + <int value="8" label="PROTOCOL_HANDLERS"/> + <int value="9" label="MEDIASTREAM"/> + <int value="10" label="ADS"/> + <int value="11" label="AUTOMATIC_DOWNLOADS"/> + <int value="12" label="MIDI_SYSEX"/> + <int value="13" label="SOUND"/> + <int value="14" label="FRAMEBUST"/> +</enum> + <enum name="ContentSettingMixedScriptAction"> <int value="0" label="Displayed shield"/> <int value="1" label="Displayed bubble"/> @@ -6008,7 +6613,19 @@ <int value="6" label="chrome-search"/> </enum> +<enum name="ContentSuggestionsBreakingNewsMessageAction"> + <int value="0" label="No action"/> + <int value="1" label="Invalid action"/> + <int value="2" label="Push-by-value"/> + <int value="3" label="Push-to-refresh"/> +</enum> + <enum name="ContentSuggestionsBreakingNewsMessageContainsNews"> + <obsolete> + Deprecated as of 10/2017 as + NewTabPage.ContentSuggestions.BreakingNews.MessageReceived is replaced by + NewTabPage.ContentSuggestions.BreakingNews.ReceivedMessageAction. + </obsolete> <int value="0" label="Without pushed news, handler listening"/> <int value="1" label="With (possibly empty) pushed news, handler listening"/> <int value="2" label="Without pushed news, handler not listening"/> @@ -6377,6 +6994,9 @@ </enum> <enum name="ContextualSearchPeekPromoOutcome"> + <obsolete> + Removed because the feature no longer exists. + </obsolete> <summary>The outcome of the Contextual Search Peek Promo.</summary> <int value="0" label="Peek Promo was seen, Panel was opened"/> <int value="1" label="Peek Promo was seen, Panel was not opened"/> @@ -6562,6 +7182,29 @@ <int value="2" label="Cache miss"/> </enum> +<enum name="CoreAudioDispatchOverrideInitResult"> + <summary> + The result of trying to initialize the CoreAudio dispatch override hotfix. + See media/audio/mac/coreaudio_dispatch_override.cc. + </summary> + <int value="0" label="Not supported"/> + <int value="1" label="Initialized successfully"/> + <int value="2" label="dyld_dynamic_interpose not found"/> + <int value="3" label="dlopen of CoreAudio failed"/> + <int value="4" label="Symbol lookup in CoreAudio failed"/> + <int value="5" label="dladdr call failed"/> +</enum> + +<enum name="CoreAudioDispatchOverrideLookupEvent"> + <summary> + The types of lookup events that the CoreAudio dispatch override hotfix can + emit. See media/audio/mac/coreaudio_dispatch_override.cc. + </summary> + <int value="0" label="Lookup performed but didn't find ResumeIO/PauseIO"/> + <int value="1" label="ResumeIO callsite found"/> + <int value="2" label="PauseIO callsite found"/> +</enum> + <enum name="CorePageTransition"> <summary> The core value of PageTransition. See ui/base/page_transition_types.h. @@ -6595,31 +7238,42 @@ <int value="1" label="RESULT_CODE_KILLED"/> <int value="2" label="RESULT_CODE_HUNG"/> <int value="3" label="RESULT_CODE_KILLED_BAD_MESSAGE"/> - <int value="4" label="RESULT_CODE_INVALID_CMDLINE_URL"/> - <int value="5" label="RESULT_CODE_BAD_PROCESS_TYPE"/> - <int value="6" label="RESULT_CODE_MISSING_DATA"/> - <int value="7" label="RESULT_CODE_SHELL_INTEGRATION_FAILED"/> - <int value="8" label="RESULT_CODE_MACHINE_LEVEL_INSTALL_EXISTS"/> - <int value="9" label="RESULT_CODE_UNINSTALL_CHROME_ALIVE"/> - <int value="10" label="RESULT_CODE_UNINSTALL_USER_CANCEL"/> - <int value="11" label="RESULT_CODE_UNINSTALL_DELETE_PROFILE"/> - <int value="12" label="RESULT_CODE_UNSUPPORTED_PARAM"/> - <int value="13" label="RESULT_CODE_IMPORTER_HUNG"/> - <int value="14" label="RESULT_CODE_RESPAWN_FAILED"/> - <int value="15" label="RESULT_CODE_NORMAL_EXIT_EXP1"/> - <int value="16" label="RESULT_CODE_NORMAL_EXIT_EXP2"/> - <int value="17" label="RESULT_CODE_NORMAL_EXIT_EXP3"/> - <int value="18" label="RESULT_CODE_NORMAL_EXIT_EXP4"/> - <int value="19" label="RESULT_CODE_NORMAL_EXIT_CANCEL"/> - <int value="20" label="RESULT_CODE_PROFILE_IN_USE"/> - <int value="21" label="RESULT_CODE_PACK_EXTENSION_ERROR"/> - <int value="22" label="RESULT_CODE_UNINSTALL_EXTENSION_ERROR"/> - <int value="23" label="RESULT_CODE_NORMAL_EXIT_PROCESS_NOTIFIED"/> - <int value="25" label="RESULT_CODE_INSTALL_FROM_WEBSTORE_ERROR_2"/> - <int value="27" label="RESULT_CODE_EULA_REFUSED"/> - <int value="28" label="RESULT_CODE_SXS_MIGRATION_FAILED"/> - <int value="29" label="RESULT_CODE_ACTION_DISALLOWED_BY_POLICY"/> - <int value="30" label="RESULT_CODE_INVALID_SANDBOX_STATE"/> + <int value="4" label="RESULT_CODE_GPU_DEAD_ON_ARRIVAL"/> + <int value="5" label="RESULT_CODE_INVALID_CMDLINE_URL"/> + <int value="6" label="RESULT_CODE_BAD_PROCESS_TYPE"/> + <int value="7" label="RESULT_CODE_MISSING_DATA"/> + <int value="8" label="RESULT_CODE_SHELL_INTEGRATION_FAILED"/> + <int value="9" label="RESULT_CODE_MACHINE_LEVEL_INSTALL_EXISTS"/> + <int value="10" label="RESULT_CODE_UNINSTALL_CHROME_ALIVE"/> + <int value="11" label="RESULT_CODE_UNINSTALL_USER_CANCEL"/> + <int value="12" label="RESULT_CODE_UNINSTALL_DELETE_PROFILE"/> + <int value="13" label="RESULT_CODE_UNSUPPORTED_PARAM"/> + <int value="14" label="RESULT_CODE_IMPORTER_HUNG"/> + <int value="15" label="RESULT_CODE_RESPAWN_FAILED"/> + <int value="16" label="RESULT_CODE_NORMAL_EXIT_EXP1"/> + <int value="17" label="RESULT_CODE_NORMAL_EXIT_EXP2"/> + <int value="18" label="RESULT_CODE_NORMAL_EXIT_EXP3"/> + <int value="19" label="RESULT_CODE_NORMAL_EXIT_EXP4"/> + <int value="20" label="RESULT_CODE_NORMAL_EXIT_CANCEL"/> + <int value="21" label="RESULT_CODE_PROFILE_IN_USE"/> + <int value="22" label="RESULT_CODE_PACK_EXTENSION_ERROR"/> + <int value="23" label="RESULT_CODE_UNINSTALL_EXTENSION_ERROR"/> + <int value="24" label="RESULT_CODE_NORMAL_EXIT_PROCESS_NOTIFIED"/> + <int value="26" label="RESULT_CODE_INSTALL_FROM_WEBSTORE_ERROR_2"/> + <int value="28" label="RESULT_CODE_EULA_REFUSED"/> + <int value="29" label="RESULT_CODE_SXS_MIGRATION_FAILED_NOT_USED"/> + <int value="30" label="RESULT_CODE_ACTION_DISALLOWED_BY_POLICY"/> + <int value="31" label="RESULT_CODE_INVALID_SANDBOX_STATE"/> + <int value="131" label="SIGQUIT"/> + <int value="132" label="SIGILL"/> + <int value="133" label="SIGTRAP"/> + <int value="134" label="SIGABRT"/> + <int value="135" label="SIGBUS (7)"/> + <int value="136" label="SIGFPE"/> + <int value="137" label="SIGKILL"/> + <int value="138" label="SIGBUS (10)"/> + <int value="139" label="SIGSEGV"/> + <int value="140" label="SIGSYS"/> <int value="258" label="WAIT_TIMEOUT"/> <int value="7006" label="SBOX_FATAL_INTEGRITY"/> <int value="7007" label="SBOX_FATAL_DROPTOKEN"/> @@ -6997,6 +7651,29 @@ <int value="2" label="Finished with "Keep Exploring" button"/> </enum> +<enum name="CrosSelectToSpeakSpeechPitch"> + <int value="55" label="0.55: Lowest"/> + <int value="70" label="0.7: Lower"/> + <int value="85" label="0.85: Low"/> + <int value="100" label="1.0: Normal"/> + <int value="115" label="1.15: High"/> + <int value="130" label="1.3: Highest"/> +</enum> + +<enum name="CrosSelectToSpeakSpeechRate"> + <int value="50" label="0.5: Slowest"/> + <int value="75" label="0.75: Slow"/> + <int value="100" label="1.0: Normal"/> + <int value="125" label="1.25: Fast"/> + <int value="150" label="1.5: Faster"/> + <int value="200" label="2.0: Fastest"/> +</enum> + +<enum name="CrosSelectToSpeakStartSpeechMethod"> + <int value="0" label="Hold Search and click or drag"/> + <int value="1" label="Ctrl + S to read selection"/> +</enum> + <enum name="CrosShelfClickTarget"> <obsolete> Deprecated as of 12/2013. Default pinned apps trial is finished. @@ -7062,6 +7739,7 @@ <int value="16" label="TSS communication error"/> <int value="17" label="TSS invalid handle"/> <int value="18" label="Keyset wrapped both by TPM and Scrypt"/> + <int value="19" label="Failed to clean up ephemeral cryptohome"/> </enum> <enum name="CryptohomeMigrationToGaiaId"> @@ -7268,10 +7946,18 @@ <int value="194" label="TSS Error Unknown Error"/> </enum> +<enum name="CTComplianceStatus"> + <int value="0" label="Compliant"/> + <int value="1" label="Non-compliant, not enough SCTs"/> + <int value="2" label="Non-compliant, not diverse SCTs"/> + <int value="3" label="Compliance not evaluated, build not timely"/> +</enum> + <enum name="CTLogEntryInclusionCheckResult"> <int value="0" label="Obtained valid inclusion proof"/> <int value="1" label="Failed getting inclusion proof"/> <int value="2" label="Obtained inclusion proof is invalid"/> + <int value="3" label="DNS configuration is invalid"/> </enum> <enum name="CTRequirementCompliance"> @@ -7468,12 +8154,18 @@ </enum> <enum name="DataReductionProxyLoFiImplicitOptOutAction"> + <obsolete> + Obsolete as of October 2017. + </obsolete> <int value="0" label="Lo-Fi disabled for the remainder of the session"/> <int value="1" label="Lo-Fi disabled until next opt out epoch"/> <int value="2" label="Next implict opt out epoch, Lo-Fi re-enabled"/> </enum> <enum name="DataReductionProxyLoFiSessionState"> + <obsolete> + Deprecated as of October 2017 per transition to blacklist. + </obsolete> <int value="0" label="Lo-Fi was used"/> <int value="1" label="Lo-Fi was not used because the network quality was always good"/> @@ -7506,6 +8198,30 @@ <enum name="DataReductionProxyNetworkChangeEvent"> <int value="0" label="IP Address Change"/> <int value="1" label="Proxy disabled on VPN (deprecated)"/> + <int value="2" label="Network change event"/> +</enum> + +<enum name="DataReductionProxyPingbackCrashAction"> + <int value="0" label="Detected"> + A crash was detected during the page load. + </int> + <int value="1" label="Dump analysis succeeded"> + A crash was analyzed and the report was added to the pending pingback. + </int> + <int value="2" label="Dump analysis did not finish"> + A crash was attempted to be analyzed did not finish before the report was + sent. + </int> + <int value="3" label="Dump not analyzed"> + A crash was not analyzed and the report was added to the pending pingback. + This is default behavior for non-Android crashes. + </int> + <int value="4" label="Send succeeded"> + A crash report was successfully uploaded. + </int> + <int value="5" label="Send failed"> + A crash report was attempted to be sent, but did not upload successfully. + </int> </enum> <enum name="DataReductionProxyProbeURLFetchResult"> @@ -7564,6 +8280,7 @@ <int value="1" label="HTTP"/> <int value="2" label="HTTPS"/> <int value="3" label="QUIC"/> + <int value="4" label="Direct"/> </enum> <enum name="DataReductionProxyQuicDefaultAlternativeProxy"> @@ -7583,6 +8300,7 @@ <int value="1" label="Resolved HTTPS data reduction proxy does not support QUIC"/> <int value="2" label="QUIC proxies have been marked as broken"/> + <int value="3" label="QUIC proxies have been disabled via field trial"/> </enum> <enum name="DataReductionProxyResourceContentType"> @@ -7668,7 +8386,17 @@ <int value="26" label="Site breakdown expanded to see more sites"/> </enum> +<enum name="DataReductionProxyWarmupURLFetchAttemptEvent"> + <int value="0" label="Warmup URL fetch was initiated"/> + <int value="1" label="Fetch not initiated due to network unavailability"/> + <int value="2" label="Fetch not initiated because proxy was disabled"/> + <int value="3" label="Fetch not initiated because warm up URL was disabled"/> +</enum> + <enum name="DataUrlMimeType"> + <obsolete> + Removed from code October 2017. + </obsolete> <int value="0" label="Other"/> <int value="1" label="HTML"/> <int value="2" label="XHTML"/> @@ -7982,12 +8710,43 @@ <int value="3" label="Redirection to the default search engine"/> </enum> +<enum name="DetachableBasePairResult"> + <int value="0" label="UnknownError"/> + <int value="1" label="ChallengePassed"/> + <int value="2" label="ChallengeFailed"/> + <int value="3" label="NeedInjectEntropy"/> +</enum> + +<enum name="DetachableBasePendingRWUpdate"> + <int value="0" label="CommunicationError"/> + <int value="1" label="NoUpdate"/> + <int value="2" label="CriticalUpdate"/> + <int value="3" label="NonCriticalUpdate"/> +</enum> + +<enum name="DetachableBaseROUpdateResult"> + <int value="1" label="Succeeded"/> + <int value="2" label="TransferFailed"/> +</enum> + +<enum name="DetachableBaseRWUpdateResult"> + <int value="1" label="Succeeded"/> + <int value="2" label="TransferFailed"/> + <int value="3" label="InvalidKey"/> + <int value="4" label="RollbackDisallowed"/> +</enum> + <enum name="DeviceIdMismatch"> <int value="0" label="BOTH_NONEMPTY"/> <int value="1" label="SYNC_EMPTY"/> <int value="2" label="PREF_EMPTY"/> </enum> +<enum name="DeviceOrientation"> + <int value="0" label="Landscape"/> + <int value="1" label="Portrait"/> +</enum> + <enum name="DeviceOrientationSensorTypeAndroid"> <int value="0" label="Not Available"/> <int value="1" label="ROTATION_VECTOR"/> @@ -8057,6 +8816,7 @@ <int value="28" label="Coverage started"/> <int value="29" label="Audits started"/> <int value="30" label="Audits finished"/> + <int value="31" label="Showed third party badges"/> </enum> <enum name="DevToolsPanel"> @@ -8145,7 +8905,7 @@ <int value="11" label="Update Recommended"/> <int value="12" label="Crypto Password"/> <int value="13" label="Safe Browsing Download Feedback"/> - <int value="14" label="First Run Bubble"/> + <int value="14" label="First Run Bubble (Obsolete)"/> <int value="15" label="Network Share Profile Warning"/> <int value="16" label="Conflicting Module"/> <int value="17" label="Critical Notification (Upgrade Installed)"/> @@ -8211,6 +8971,7 @@ <int value="77" label="Validation Message"/> <int value="78" label="Web Share Target Picker"/> <int value="79" label="Zoom"/> + <int value="80" label="Lock Screen Note App Toast"/> </enum> <enum name="DidNavigateToAd"> @@ -8273,6 +9034,12 @@ <int value="2" label="Migration resumed"/> </enum> +<enum name="DirectIntentType"> + <int value="0" label="Fallback URL activated"/> + <int value="1" label="Intent URL clicked on SERP"/> + <int value="2" label="Intent URL clicked elsewhere"/> +</enum> + <enum name="DirectoryDatabaseRepairResult"> <int value="0" label="Succeeded"/> <int value="1" label="Failed"/> @@ -8340,6 +9107,15 @@ <int value="2" label="7.2 or later"/> </enum> +<enum name="DisplayMirrorModeTypes"> + <summary> + Defines the types of mirror mode in which displays connected to the device + are in. + </summary> + <int value="0" label="Normal mirror mode"/> + <int value="1" label="Mixed mirror mode"/> +</enum> + <enum name="DistillableType"> <int value="0" label="Not distillable"/> <int value="1" label="Non-mobile-friendly distillable"/> @@ -8563,6 +9339,9 @@ </enum> <enum name="DomainBoundCerts.GetCertResult"> + <obsolete> + Removed January 2018. + </obsolete> <int value="0" label="SYNC_SUCCESS"/> <int value="1" label="ASYNC_SUCCESS"/> <int value="2" label="ASYNC_CANCELLED"/> @@ -8635,6 +9414,151 @@ <int value="1" label="Touchview"/> </enum> +<enum name="DownEventInputFormFactorDestinationCombination"> + <int value="0" + label="Unknown input in clamshell mode, destination is + others(everything except browser and apps)"/> + <int value="1" + label="Unknown input in clamshell mode, destination is inside the + browser frame"/> + <int value="2" + label="Unknown input in clamshell mode, destination is regular chrome + app"/> + <int value="3" + label="Unknown input in clamshell mode, destination is ARC app(Android + app in ChromeOS)"/> + <int value="4" + label="Unknown input in touchview mode landscape orientation, + destination is others(everything except browser and apps)"/> + <int value="5" + label="Unknown input in touchview mode landscape orientation, + destination is inside the browser frame"/> + <int value="6" + label="Unknown input in touchview mode landscape orientation, + destination is regular chrome app"/> + <int value="7" + label="Unknown input in touchview mode landscape orientation, + destination is ARC app(Android app in ChromeOS)"/> + <int value="8" + label="Unknown input in touchview mode portrait orientation, + destination is others(everything except browser and apps)"/> + <int value="9" + label="Unknown input in touchview mode portrait orientation, + destination is inside the browser frame"/> + <int value="10" + label="Unknown input in touchview mode portrait orientation, + destination is regular chrome app"/> + <int value="11" + label="Unknown input in touchview mode portrait orientation, + destination is ARC app(Android app in ChromeOS)"/> + <int value="12" + label="Mouse input in clamshell mode, destination is others(everything + except browser and apps)"/> + <int value="13" + label="Mouse input in clamshell mode, destination is inside the browser + frame"/> + <int value="14" + label="Mouse input in clamshell mode, destination is regular chrome app"/> + <int value="15" + label="Mouse input in clamshell mode, destination is ARC app(Android + app in ChromeOS)"/> + <int value="16" + label="Mouse input in touchview mode landscape orientation, destination + is others(everything except browser and apps)"/> + <int value="17" + label="Mouse input in touchview mode landscape orientation, destination + is inside the browser frame"/> + <int value="18" + label="Mouse input in touchview mode landscape orientation, destination + is regular chrome app"/> + <int value="19" + label="Mouse input in touchview mode landscape orientation, destination + is ARC app(Android app in ChromeOS)"/> + <int value="20" + label="Mouse input in touchview mode portrait orientation, destination + is others(everything except browser and apps)"/> + <int value="21" + label="Mouse input in touchview mode portrait orientation, destination + is inside the browser frame"/> + <int value="22" + label="Mouse input in touchview mode portrait orientation, destination + is regular chrome app"/> + <int value="23" + label="Mouse input in touchview mode portrait orientation, destination + is ARC app(Android app in ChromeOS)"/> + <int value="24" + label="Stylus input in clamshell mode, destination is others(everything + except browser and apps)"/> + <int value="25" + label="Stylus input in clamshell mode, destination is inside the + browser frame"/> + <int value="26" + label="Stylus input in clamshell mode, destination is regular chrome + app"/> + <int value="27" + label="Stylus input in clamshell mode, destination is ARC app(Android + app in ChromeOS)"/> + <int value="28" + label="Stylus input in touchview mode landscape orientation, + destination is others(everything except browser and apps)"/> + <int value="29" + label="Stylus input in touchview mode landscape orientation, + destination is inside the browser frame"/> + <int value="30" + label="Stylus input in touchview mode landscape orientation, + destination is regular chrome app"/> + <int value="31" + label="Stylus input in touchview mode landscape orientation, + destination is ARC app(Android app in ChromeOS)"/> + <int value="32" + label="Stylus input in touchview mode portrait orientation, destination + is others(everything except browser and apps)"/> + <int value="33" + label="Stylus input in touchview mode portrait orientation, destination + is inside the browser frame"/> + <int value="34" + label="Stylus input in touchview mode portrait orientation, destination + is regular chrome app"/> + <int value="35" + label="Stylus input in touchview mode portrait orientation, destination + is ARC app(Android app in ChromeOS)"/> + <int value="36" + label="Touch input in clamshell mode, destination is others(everything + except browser and apps)"/> + <int value="37" + label="Touch input in clamshell mode, destination is inside the browser + frame"/> + <int value="38" + label="Touch input in clamshell mode, destination is regular chrome app"/> + <int value="39" + label="Touch input in clamshell mode, destination is ARC app(Android + app in ChromeOS)"/> + <int value="40" + label="Touch input in touchview mode landscape orientation, destination + is others(everything except browser and apps)"/> + <int value="41" + label="Touch input in touchview mode landscape orientation, destination + is inside the browser frame"/> + <int value="42" + label="Touch input in touchview mode landscape orientation, destination + is regular chrome app"/> + <int value="43" + label="Touch input in touchview mode landscape orientation, destination + is ARC app(Android app in ChromeOS)"/> + <int value="44" + label="Touch input in touchview mode portrait orientation, destination + is others(everything except browser and apps)"/> + <int value="45" + label="Touch input in touchview mode portrait orientation, destination + is inside the browser frame"/> + <int value="46" + label="Touch input in touchview mode portrait orientation, destination + is regular chrome app"/> + <int value="47" + label="Touch input in touchview mode portrait orientation, destination + is ARC app(Android app in ChromeOS)"/> +</enum> + <enum name="DownEventSource"> <int value="0" label="Unknown"/> <int value="1" label="Mouse"/> @@ -8645,6 +9569,7 @@ <enum name="Download.Service.BatteryRequirements"> <int value="0" label="BATTERY_INSENSITIVE"/> <int value="1" label="BATTERY_SENSITIVE"/> + <int value="2" label="BATTERY_CHARGING"/> </enum> <enum name="Download.Service.CompletionType"> @@ -8654,6 +9579,15 @@ <int value="3" label="TIMEOUT"/> <int value="4" label="UNKNOWN"/> <int value="5" label="CANCEL"/> + <int value="6" label="OUT_OF_RETRIES"/> + <int value="7" label="OUT_OF_RESUMPTIONS"/> +</enum> + +<enum name="Download.Service.EntryEvent"> + <int value="0" label="START"/> + <int value="1" label="RESUME"/> + <int value="2" label="RETRY"/> + <int value="3" label="SUSPEND"/> </enum> <enum name="Download.Service.EntryStates"> @@ -8677,6 +9611,14 @@ <int value="2" label="UNMETERED"/> </enum> +<enum name="Download.Service.PauseReason"> + <int value="0" label="ANY"/> + <int value="1" label="UNMET_DEVICE_CRITERIA"/> + <int value="2" label="PAUSE_BY_CLIENT"/> + <int value="3" label="EXTERNAL_DOWNLOAD"/> + <int value="4" label="EXTERNAL_NAVIGATION"/> +</enum> + <enum name="Download.Service.Priority"> <int value="0" label="LOW"/> <int value="1" label="NORMAL"/> @@ -8720,6 +9662,32 @@ <int value="4" label="FAILURE_REASON_FILE_MONITOR"/> </enum> +<enum name="Download.Shelf.DragEvent"> + <int value="0" label="Started"/> + <int value="1" label="Canceled"/> + <int value="2" label="Dropped"/> +</enum> + +<enum name="DownloadableStrings.InstallStatus"> + <obsolete> + Deprecated 2/2018 + </obsolete> + <int value="0" label="NONE"/> + <int value="1" label="UPDATE_IN_PROGRESS"/> + <int value="2" label="UPDATE_CANCELED"/> + <int value="3" label="RETRY_LATER"/> + <int value="4" label="SERVICE_ERROR"/> + <int value="5" label="UPDATE_CHECK_ERROR"/> + <int value="15" label="UNKNOWN"/> +</enum> + +<enum name="DownloadableStrings.MobileCountryCode"> + <obsolete> + Deprecated 2/2018 + </obsolete> + <int value="0" label="UNDETERMINED"/> +</enum> + <enum name="DownloadAudioType"> <int value="0" label="UNRECOGNIZED"/> <int value="1" label="AAC"/> @@ -8815,6 +9783,11 @@ <int value="24" label="No bytes received after content length mismatch"/> <int value="25" label="Target determination requeted"/> <int value="26" label="Target determination completed"/> + <int value="27" + label="Cross origin download without content disposition headers"/> + <int value="28" label="Download attemps before sending the request"/> + <int value="29" label="Download attempts for manual download resumption."/> + <int value="30" label="Download attempts for auto download resumption."/> </enum> <enum name="DownloadDatabaseRecordDroppedType"> @@ -8839,6 +9812,12 @@ <int value="11" label="Resume"/> </enum> +<enum name="DownloadedFileAction"> + <int value="0" label="Opened in Drive"/> + <int value="1" label="Opened in another app"/> + <int value="2" label="No action"/> +</enum> + <enum name="DownloadFilePickerResult"> <int value="0" label="SAME"/> <int value="1" label="DIFFERENT_DIR"/> @@ -8846,6 +9825,13 @@ <int value="3" label="CANCEL"/> </enum> +<enum name="DownloadFileResult"> + <int value="0" label="Completed"/> + <int value="1" label="Canceled"/> + <int value="2" label="Failure"/> + <int value="3" label="Other"/> +</enum> + <enum name="DownloadFunctions"> <int value="0" label="download"/> <int value="1" label="search"/> @@ -9146,7 +10132,52 @@ <int value="260" label="toast"/> <int value="261" label="udif"/> <int value="262" label="run"/> - <int value="263" label="ad"/> + <int value="263" label="mpkg"/> + <int value="264" label="as"/> + <int value="265" label="cpgz"/> + <int value="266" label="pax"/> + <int value="267" label="xip"/> + <int value="268" label="docx"/> + <int value="269" label="docm"/> + <int value="270" label="dott"/> + <int value="271" label="dotm"/> + <int value="272" label="docb"/> + <int value="273" label="xlsx"/> + <int value="274" label="xlsm"/> + <int value="275" label="xltx"/> + <int value="276" label="xltm"/> + <int value="277" label="pptx"/> + <int value="278" label="pptm"/> + <int value="279" label="potx"/> + <int value="280" label="ppam"/> + <int value="281" label="ppsx"/> + <int value="282" label="sldx"/> + <int value="283" label="sldm"/> + <int value="284" label="htm"/> + <int value="285" label="html"/> + <int value="286" label="xht"/> + <int value="287" label="xhtm"/> + <int value="288" label="xhtml"/> + <int value="289" label="vdx"/> + <int value="290" label="vsx"/> + <int value="291" label="vtx"/> + <int value="292" label="vsdx"/> + <int value="293" label="vssx"/> + <int value="294" label="vstx"/> + <int value="295" label="vsdm"/> + <int value="296" label="vssm"/> + <int value="297" label="vstm"/> + <int value="298" label="btapp"/> + <int value="299" label="btbtskin"/> + <int value="300" label="btinstall"/> + <int value="301" label="btkey"/> + <int value="302" label="btsearch"/> + <int value="303" label="dhtml"/> + <int value="304" label="dhtm"/> + <int value="305" label="dht"/> + <int value="306" label="shtml"/> + <int value="307" label="shtm"/> + <int value="308" label="sht"/> </enum> <enum name="DownloadItem.DangerType"> @@ -9161,6 +10192,33 @@ <int value="8" label="POTENTIALLY_UNWANTED"/> </enum> +<enum name="DownloadNotificationForegroundLifecycle"> + <int value="0" label="START"/> + <int value="1" label="UPDATE"/> + <int value="2" label="STOP"/> +</enum> + +<enum name="DownloadNotificationInteractions"> + <int value="0" label="CLICKED"/> + <int value="1" label="OPEN"/> + <int value="2" label="CANCEL"/> + <int value="3" label="PAUSE"/> + <int value="4" label="RESUME"/> +</enum> + +<enum name="DownloadNotificationLaunchType"> + <int value="0" label="LAUNCH"/> + <int value="1" label="RELAUNCH"/> +</enum> + +<enum name="DownloadNotificationServiceStopped"> + <int value="0" label="STOPPED"/> + <int value="1" label="DESTROYED"/> + <int value="2" label="TASK_REMOVED"/> + <int value="3" label="LOW_MEMORY"/> + <int value="4" label="START_STICKY"/> +</enum> + <enum name="DownloadOpenMethod"> <int value="0" label="Opened with plaform handler by default"/> <int value="1" label="Opened in browser by default"/> @@ -9185,6 +10243,22 @@ <int value="3" label="Wrong MIME Type Failure"/> </enum> +<enum name="DownloadPathGenerationEvent"> + <int value="0" label="Use existing virtual path"/> + <int value="1" label="Use force path"/> + <int value="2" label="Use last prompt directory"/> + <int value="3" label="Use default directory"/> + <int value="4" label="No valid path"/> +</enum> + +<enum name="DownloadPathValidationResult"> + <int value="0" label="Success"/> + <int value="1" label="Path not writable"/> + <int value="2" label="Name too long"/> + <int value="3" label="Conflict"/> + <int value="4" label="Same as source"/> +</enum> + <enum name="DownloadSavePackageEvent"> <int value="0" label="Started"/> <int value="1" label="Cancelled"/> @@ -11431,6 +12505,41 @@ <int value="387" label="DeviceNativePrintersAccessMode"/> <int value="388" label="DeviceNativePrintersBlacklist"/> <int value="389" label="DeviceNativePrintersWhitelist"/> + <int value="390" label="TPMFirmwareUpdateSettings"/> + <int value="391" label="RunAllFlashInAllowMode"/> + <int value="392" label="AutofillCreditCardEnabled"/> + <int value="393" label="NtlmV2Enabled"/> + <int value="394" label="MinimumRequiredChromeVersion"/> + <int value="395" label="PromptForDownloadLocation"/> + <int value="396" label="DeviceLoginScreenAutoSelectCertificateForUrls"/> + <int value="397" label="UnaffiliatedArcAllowed"/> + <int value="398" label="IsolateOrigins"/> + <int value="399" label="SitePerProcess"/> + <int value="400" label="UnsafelyTreatInsecureOriginAsSecure"/> + <int value="401" label="DefaultDownloadDirectory"/> + <int value="402" label="SecurityKeyPermitAttestation"/> + <int value="403" label="DeviceHostnameTemplate"/> + <int value="404" label="AbusiveExperienceInterventionEnforce"/> + <int value="405" label="SpellcheckLanguage"/> + <int value="406" label="SecondaryGoogleAccountSigninAllowed"/> + <int value="407" label="ThirdPartyBlockingEnabled"/> + <int value="408" label="SpellcheckEnabled"/> + <int value="409" label="AdsSettingForIntrusiveAdsSites"/> + <int value="410" label="RestrictAccountsToPatterns"/> + <int value="411" label="PasswordProtectionWarningTrigger"/> + <int value="412" label="PasswordProtectionRiskTrigger"/> + <int value="413" label="EnableSymantecLegacyInfrastructure"/> + <int value="414" label="WebDriverOverridesIncompatiblePolicies"/> + <int value="415" label="DeviceKerberosEncryptionTypes"/> + <int value="416" label="DeviceUserPolicyLoopbackProcessingMode"/> + <int value="417" label="DeviceLoginScreenIsolateOrigins"/> + <int value="418" label="DeviceLoginScreenSitePerProcess"/> + <int value="419" label="RelaunchNotification"/> + <int value="420" label="RelaunchNotificationPeriod"/> + <int value="421" label="VirtualMachinesAllowed"/> + <int value="422" label="SafeBrowsingWhitelistDomains"/> + <int value="423" label="PasswordProtectionLoginURLs"/> + <int value="424" label="PasswordProtectionChangePasswordURL"/> </enum> <enum name="EnterprisePolicyInvalidations"> @@ -11579,8 +12688,13 @@ </summary> <int value="0" label="Other type of error on retrieve policy request"/> <int value="1" label="Success"/> - <int value="2" label="Retrieve request issued before session started"/> + <int value="2" + label="Retrieve request issued before session started (Deprecated)"/> <int value="3" label="Failed to retrieve policy data in session manager"/> + <int value="4" + label="Session manager failed to get policy service, possibly because + the retrieve request was issued before the user session started + or the account id was invalid"/> </enum> <enum name="EnterpriseUploadJobSuccess"> @@ -11785,6 +12899,18 @@ <int value="700" label="SHUTDOWN_COMPLETE"/> </enum> +<enum name="ExifOrientation"> + <int value="0" label="Normal"/> + <int value="1" label="Rotate 90"/> + <int value="2" label="Rotate 190"/> + <int value="3" label="Rotate 270"/> + <int value="4" label="Transpose"/> + <int value="5" label="Transverse"/> + <int value="6" label="Flip Horizontally"/> + <int value="7" label="Flip Vertically"/> + <int value="8" label="Undefined"/> +</enum> + <enum name="ExpectCTHeaderResult"> <int value="0" label="EXPECT_CT_HEADER_BAD_VALUE"/> <int value="1" label="EXPECT_CT_HEADER_BUILD_NOT_TIMELY"/> @@ -11795,6 +12921,12 @@ <int value="6" label="EXPECT_CT_HEADER_PROCESSED"/> </enum> +<enum name="ExportPasswordsResult"> + <int value="0" label="Successful"/> + <int value="1" label="Canceled by the user"/> + <int value="2" label="Write failed"/> +</enum> + <enum name="ExtensionBackgroundPageType"> <int value="0" label="None"/> <int value="1" label="Persistent"/> @@ -12190,8 +13322,8 @@ <int value="331" label="WEB_VIEW_INTERNAL_CONTEXT_MENUS"/> <int value="332" label="CONTEXT_MENUS"/> <int value="333" label="TTS_ON_EVENT"/> - <int value="334" label="LAUNCHER_PAGE_ON_TRANSITION_CHANGED"/> - <int value="335" label="LAUNCHER_PAGE_ON_POP_SUBPAGE"/> + <int value="334" label="LAUNCHER_PAGE_ON_TRANSITION_CHANGED_DEPRECATED"/> + <int value="335" label="LAUNCHER_PAGE_ON_POP_SUBPAGE_DEPRECATED"/> <int value="336" label="DIAL_ON_DEVICE_LIST"/> <int value="337" label="DIAL_ON_ERROR"/> <int value="338" label="CAST_CHANNEL_ON_MESSAGE"/> @@ -12274,7 +13406,8 @@ <int value="411" label="WEB_VIEW_INTERNAL_ON_AUDIO_STATE_CHANGED"/> <int value="412" label="AUTOMATION_INTERNAL_ON_ACTION_RESULT"/> <int value="413" label="OMNIBOX_ON_DELETE_SUGGESTION"/> - <int value="414" label="PASSWORDS_PRIVATE_ON_SHOW_IMPORT_EXPORT_BUTTONS"/> + <int value="414" label="VIRTUAL_KEYBOARD_PRIVATE_ON_KEYBOARD_CONFIG_CHANGED"/> + <int value="415" label="PASSWORDS_PRIVATE_ON_PASSWORDS_FILE_EXPORT_PROGRESS"/> </enum> <enum name="ExtensionFileWriteResult"> @@ -13320,7 +14453,7 @@ <int value="1000" label="DEVELOPERPRIVATE_GETPROFILECONFIGURATION"/> <int value="1001" label="DEVELOPERPRIVATE_UPDATEPROFILECONFIGURATION"/> <int value="1002" label="SOCKETS_UDP_SETBROADCAST"/> - <int value="1003" label="FILEMANAGERPRIVATE_GETPROVIDINGEXTENSIONS"/> + <int value="1003" label="FILEMANAGERPRIVATE_GETPROVIDERS"/> <int value="1004" label="WEBVIEWINTERNAL_ADDCONTENTSCRIPTS"/> <int value="1005" label="WEBVIEWINTERNAL_REMOVECONTENTSCRIPTS"/> <int value="1006" label="DEVELOPERPRIVATE_REPAIREXTENSION"/> @@ -13439,8 +14572,8 @@ <int value="1113" label="INPUTMETHODPRIVATE_SHOWINPUTVIEW"/> <int value="1114" label="WALLPAPERPRIVATE_RECORDWALLPAPERUMA"/> <int value="1115" label="AUTOTESTPRIVATE_GETVISIBLENOTIFICATIONS"/> - <int value="1116" label="WEBRTCLOGGINGPRIVATE_STARTRTCEVENTLOGGING"/> - <int value="1117" label="WEBRTCLOGGINGPRIVATE_STOPRTCEVENTLOGGING"/> + <int value="1116" label="DELETED_WEBRTCLOGGINGPRIVATE_STARTRTCEVENTLOGGING"/> + <int value="1117" label="DELETED_WEBRTCLOGGINGPRIVATE_STOPRTCEVENTLOGGING"/> <int value="1118" label="PASSWORDSPRIVATE_GETSAVEDPASSWORDLIST"/> <int value="1119" label="PASSWORDSPRIVATE_GETPASSWORDEXCEPTIONLIST"/> <int value="1120" label="INPUTMETHODPRIVATE_OPENOPTIONSPAGE"/> @@ -13520,6 +14653,31 @@ <int value="1193" label="NETWORKINGPRIVATE_SELECTCELLULARMOBILENETWORK"/> <int value="1194" label="PASSWORDSPRIVATE_IMPORTPASSWORDS"/> <int value="1195" label="PASSWORDSPRIVATE_EXPORTPASSWORDS"/> + <int value="1196" + label="PASSWORDSPRIVATE_UNDOREMOVESAVEDPASSWORDOREXCEPTION"/> + <int value="1197" + label="ACCESSIBILITY_PRIVATE_SETNATIVECHROMEVOXARCSUPPORTFORCURRENTAPP"/> + <int value="1198" + label="LANGUAGESETTINGSPRIVATE_SETENABLETRANSLATIONFORLANGUAGE"/> + <int value="1199" label="LANGUAGESETTINGSPRIVATE_MOVELANGUAGE"/> + <int value="1200" label="MEDIAPERCEPTIONPRIVATE_SETANALYTICSCOMPONENT"/> + <int value="1201" label="ACCESSIBILITY_PRIVATE_SETHIGHLIGHTS"/> + <int value="1202" label="WEBRTCLOGGINGPRIVATE_GETLOGSDIRECTORY"/> + <int value="1203" label="VIRTUALKEYBOARDPRIVATE_SETDRAGGABLEAREA"/> + <int value="1204" label="METRICSPRIVATE_RECORDBOOLEAN"/> + <int value="1205" label="METRICSPRIVATE_RECORDENUMERATIONVALUE"/> + <int value="1206" label="DEVELOPERPRIVATE_NOTIFYDRAGINSTALLINPROGRESS"/> + <int value="1207" label="AUTOTESTPRIVATE_GETPRINTERLIST"/> + <int value="1208" label="DEVELOPERPRIVATE_GETEXTENSIONSIZE"/> + <int value="1209" label="CRYPTOTOKENPRIVATE_ISAPPIDHASHINENTERPRISECONTEXT"/> + <int value="1210" label="CRYPTOTOKENPRIVATE_CANAPPIDGETATTESTATION"/> + <int value="1211" label="SYSTEM_DISPLAY_SETMIRRORMODE"/> + <int value="1212" label="TTSENGINE_UPDATEVOICES"/> + <int value="1213" label="PASSWORDSPRIVATE_REQUESTEXPORTPROGRESSSTATUS"/> + <int value="1214" label="WALLPAPERPRIVATE_GETCOLLECTIONSINFO"/> + <int value="1215" label="WALLPAPERPRIVATE_GETIMAGESINFO"/> + <int value="1216" label="ACCESSIBILITY_PRIVATE_SENDSYNTHETICKEYEVENT"/> + <int value="1217" label="WALLPAPERPRIVATE_GETLOCALIMAGEPATHS"/> </enum> <enum name="ExtensionIconState"> @@ -13741,7 +14899,7 @@ </enum> <enum name="ExtensionPermission3"> -<!-- Generated from extensions/common/permissions/api_permission.h --> +<!-- Generated from extensions/common/permissions/api_permission.h.--> <int value="0" label="kInvalid"/> <int value="1" label="kUnknown"/> @@ -13857,7 +15015,7 @@ <int value="111" label="kPageCapture"/> <int value="112" label="kPointerLock"/> <int value="113" label="kPlatformKeys"/> - <int value="114" label="kPlugin"/> + <int value="114" label="kDeleted_Plugin"/> <int value="115" label="kPower"/> <int value="116" label="kPreferencesPrivate"/> <int value="117" label="kDeleted_PrincipalsPrivate"/> @@ -13950,6 +15108,9 @@ <int value="204" label="kMediaPerceptionPrivate"/> <int value="205" label="kLockScreen"/> <int value="206" label="kNewTabPageOverride"/> + <int value="207" label="kDeclarativeNetRequest"/> + <int value="208" label="kLockWindowFullscreenPrivate"/> + <int value="209" label="kWebrtcLoggingPrivateAudioDebug"/> </enum> <enum name="ExtensionServiceVerifyAllSuccess"> @@ -13967,6 +15128,7 @@ <int value="4" label="HOSTED_APP"/> <int value="5" label="LEGACY_PACKAGED_APP"/> <int value="6" label="PLATFORM_APP"/> + <int value="7" label="SHARED_MODULE"/> </enum> <enum name="ExtensionUninstallDialogAction"> @@ -14030,6 +15192,30 @@ <int value="35" label="CRX_EXPECTED_HASH_INVALID"/> </enum> +<enum name="ExtensionUpdaterUpdateResult"> + <int value="0" label="No update"/> + <int value="1" label="Update success"/> + <int value="2" label="Update error"/> +</enum> + +<enum name="ExtensionViewType"> + <int value="0" label="INVALID"/> + <int value="1" label="APP_WINDOW"/> + <int value="2" label="BACKGROUND_CONTENTS"/> + <int value="3" label="COMPONENT"/> + <int value="4" label="EXTENSION_BACKGROUND_PAGE"/> + <int value="5" label="EXTENSION_DIALOG"/> + <int value="6" label="EXTENSION_GUEST"/> + <int value="7" label="EXTENSION_POPUP"/> + <int value="8" label="PANEL"/> + <int value="9" label="TAB_CONTENTS"/> +</enum> + +<enum name="ExtensionViewTypeIsBackground"> + <int value="0" label="Not background"/> + <int value="1" label="Background"/> +</enum> + <enum name="ExternalDeviceAction"> <int value="0" label="Import to Drive"/> <int value="1" label="View files"/> @@ -14074,6 +15260,11 @@ <int value="7" label="UNINSTALLED (not in webstore)"/> </enum> +<enum name="ExternalLauncherOption"> + <int value="0" label="Cancel"/> + <int value="1" label="Open"/> +</enum> + <enum name="ExternallyConditionalizedType"> <int value="0" label="Cache entry requires validation"/> <int value="1" label="Cache entry usable"/> @@ -14167,6 +15358,23 @@ <int value="2" label="FAILURE">Failure - favicon not available</int> </enum> +<enum name="FaviconType"> + <summary> + Defines the icon type stored as cached in the history backend. + </summary> + <int value="0" label="Invalid">Not an actual icon.</int> + <int value="1" label="Favicon"> + Regular favicon (e.g. rel="icon"). + </int> + <int value="2" label="TouchIcon"> + Touch icon (rel="apple-touch-icon"). + </int> + <int value="3" label="TouchPrecomposedIcon"> + Precomposed touch icon (rel="apple-touch-icon-precomposed"). + </int> + <int value="4" label="WebManifestIcon">Icon listed in a Web Manifest.</int> +</enum> + <enum name="FeatureObserver"> <!-- Generated from third_party/WebKit/public/platform/web_feature.mojom.--> @@ -14320,7 +15528,7 @@ <int value="147" label="DOMNodeInsertedIntoDocumentEvent"/> <int value="148" label="DOMCharacterDataModifiedEvent"/> <int value="149" label="DocumentAllTags"/> - <int value="150" label="DocumentAllLegacyCall"/> + <int value="150" label="OBSOLETE_DocumentAllLegacyCall"/> <int value="151" label="HTMLAppletElementLegacyCall"/> <int value="152" label="HTMLEmbedElementLegacyCall"/> <int value="153" label="HTMLObjectElementLegacyCall"/> @@ -15144,7 +16352,8 @@ <int value="961" label="CredentialManagerGetMediationOptional"/> <int value="962" label="CredentialManagerGetMediationSilent"/> <int value="963" label="CredentialManagerStore"/> - <int value="964" label="CredentialManagerRequireUserMediation"/> + <int value="964" + label="CredentialManagerRequireUserMediation (obsolete as of M64)"/> <int value="965" label="RequestAutocomplete"/> <int value="966" label="BlockableMixedContentInSubframeBlocked"/> <int value="967" label="AddEventListenerThirdArgumentIsObject"/> @@ -15447,15 +16656,15 @@ <int value="1249" label="CSSAtRuleApply"/> <int value="1250" label="CSSSelectorPseudoAny"/> <int value="1251" label="PannerNodeSetVelocity"/> - <int value="1252" label="DocumentAllItemNoArguments"/> - <int value="1253" label="DocumentAllItemNamed"/> - <int value="1254" label="DocumentAllItemIndexed"/> - <int value="1255" label="DocumentAllItemIndexedWithNonNumber"/> - <int value="1256" label="DocumentAllLegacyCallNoArguments"/> - <int value="1257" label="DocumentAllLegacyCallNamed"/> - <int value="1258" label="DocumentAllLegacyCallIndexed"/> - <int value="1259" label="DocumentAllLegacyCallIndexedWithNonNumber"/> - <int value="1260" label="DocumentAllLegacyCallTwoArguments"/> + <int value="1252" label="OBSOLETE_DocumentAllItemNoArguments"/> + <int value="1253" label="OBSOLETE_DocumentAllItemNamed"/> + <int value="1254" label="OBSOLETE_DocumentAllItemIndexed"/> + <int value="1255" label="OBSOLETE_DocumentAllItemIndexedWithNonNumber"/> + <int value="1256" label="OBSOLETE_DocumentAllLegacyCallNoArguments"/> + <int value="1257" label="OBSOLETE_DocumentAllLegacyCallNamed"/> + <int value="1258" label="OBSOLETE_DocumentAllLegacyCallIndexed"/> + <int value="1259" label="OBSOLETE_DocumentAllLegacyCallIndexedWithNonNumber"/> + <int value="1260" label="OBSOLETE_DocumentAllLegacyCallTwoArguments"/> <int value="1261" label="HTMLLabelElementFormIsDifferentFromControlForm"/> <int value="1262" label="HTMLLabelElementHasNoControlAndFormIsAncestor"/> <int value="1263" label="HTMLLabelElementControlForNonFormAssociatedElement"/> @@ -15492,8 +16701,6 @@ <int value="1292" label="FormValidationStarted"/> <int value="1293" label="FormValidationAbortedSubmission"/> <int value="1294" label="FormValidationShowedMessage"/> - <int value="1295" label="WebAnimationsEasingAsFunctionLinear"/> - <int value="1296" label="WebAnimationsEasingAsFunctionOther"/> <int value="1297" label="V8Document_Images_AttributeGetter"/> <int value="1298" label="V8Document_Embeds_AttributeGetter"/> <int value="1299" label="V8Document_Plugins_AttributeGetter"/> @@ -16197,19 +17404,22 @@ <int value="1981" label="FieldEditInSecureContext"/> <int value="1982" label="FieldEditInNonSecureContext"/> <int value="1983" - label="CredentialManagerCredentialRequestOptionsUnmediated"/> + label="CredentialManagerCredentialRequestOptionsUnmediated (obsolete as + of M64)"/> <int value="1984" label="CredentialManagerGetMediationRequired"/> - <int value="1985" label="CredentialManagerIdName"/> - <int value="1986" label="CredentialManagerPasswordName"/> - <int value="1987" label="CredentialManagerAdditionalData"/> - <int value="1988" label="CredentialManagerCustomFetch"/> + <int value="1985" label="CredentialManagerIdName (obsolete as of M64)"/> + <int value="1986" label="CredentialManagerPasswordName (obsolete as of M64)"/> + <int value="1987" + label="CredentialManagerAdditionalData (obsolete as of M64)"/> + <int value="1988" label="CredentialManagerCustomFetch (obsolete as of M64)"/> <int value="1989" label="NetInfoRtt"/> <int value="1990" label="NetInfoDownlink"/> <int value="1991" label="ShapeDetection_BarcodeDetectorConstructor"/> <int value="1992" label="ShapeDetection_FaceDetectorConstructor"/> <int value="1993" label="ShapeDetection_TextDetectorConstructor"/> <int value="1994" - label="CredentialManagerCredentialRequestOptionsOnlyUnmediated"/> + label="CredentialManagerCredentialRequestOptionsOnlyUnmediated + (obsolete as of M64)"/> <int value="1995" label="InertAttribute"/> <int value="1996" label="PluginInstanceAccessFromIsolatedWorld"/> <int value="1997" label="PluginInstanceAccessFromMainWorld"/> @@ -16290,7 +17500,8 @@ <int value="2065" label="PersistentClientHintHeader"/> <int value="2066" label="StyleSheetListNonNullAnonymousNamedGetter"/> <int value="2067" label="OffMainThreadFetch"/> - <int value="2068" label="HTMLOptionsCollectionNamedGetterReturnsNodeList"/> + <int value="2068" + label="OBSOLETE_HTMLOptionsCollectionNamedGetterReturnsNodeList"/> <int value="2069" label="ARIAActiveDescendantAttribute"/> <int value="2070" label="ARIAAtomicAttribute"/> <int value="2071" label="ARIAAutocompleteAttribute"/> @@ -16380,6 +17591,217 @@ <int value="2155" label="WebAudioDezipperBiquadFilterNodeQ"/> <int value="2156" label="WebAudioDezipperBiquadFilterNodeGain"/> <int value="2157" label="PerformanceServerTiming"/> + <int value="2158" label="FileReaderResultBeforeCompletion"/> + <int value="2159" label="SyncXhrInPageDismissal"/> + <int value="2160" label="AsyncXhrInPageDismissal"/> + <int value="2161" + label="V8LineOrParagraphSeparatorAsLineTerminator (obsolete)"/> + <int value="2162" label="AnimationSetPlaybackRateCompensatorySeek"/> + <int value="2163" label="DeepCombinatorInStaticProfile"/> + <int value="2164" label="PseudoShadowInStaticProfile"/> + <int value="2165" label="SchemeBypassesCSP"/> + <int value="2166" label="InnerSchemeBypassesCSP"/> + <int value="2167" label="SameOriginApplicationOctetStream"/> + <int value="2168" label="SameOriginApplicationXml"/> + <int value="2169" label="SameOriginTextHtml"/> + <int value="2170" label="SameOriginTextPlain"/> + <int value="2171" label="SameOriginTextXml"/> + <int value="2172" label="CrossOriginApplicationOctetStream"/> + <int value="2173" label="CrossOriginApplicationXml"/> + <int value="2174" label="CrossOriginTextHtml"/> + <int value="2175" label="CrossOriginTextPlain"/> + <int value="2176" label="CrossOriginTextXml"/> + <int value="2177" label="SameOriginWorkerApplicationOctetStream"/> + <int value="2178" label="SameOriginWorkerApplicationXml"/> + <int value="2179" label="SameOriginWorkerTextHtml"/> + <int value="2180" label="SameOriginWorkerTextPlain"/> + <int value="2181" label="SameOriginWorkerTextXml"/> + <int value="2182" label="CrossOriginWorkerApplicationOctetStream"/> + <int value="2183" label="CrossOriginWorkerApplicationXml"/> + <int value="2184" label="CrossOriginWorkerTextHtml"/> + <int value="2185" label="CrossOriginWorkerTextPlain"/> + <int value="2186" label="CrossOriginWorkerTextXml"/> + <int value="2187" label="OBSOLETE_ImageCaptureSetOptions"/> + <int value="2188" label="PerformanceObserverForWindow"/> + <int value="2189" label="PerformanceObserverForWorker"/> + <int value="2190" label="PaintTimingObserved"/> + <int value="2191" label="PaintTimingRequested"/> + <int value="2192" label="HTMLMediaElementMediaPlaybackRateOutOfRange"/> + <int value="2193" label="CSSFilterFunctionNegativeBrightness"/> + <int value="2194" label="CookieSet"/> + <int value="2195" label="CookieGet"/> + <int value="2196" label="GeolocationDisabledByFeaturePolicy"/> + <int value="2197" label="EncryptedMediaDisabledByFeaturePolicy"/> + <int value="2198" label="BatteryStatusGetBattery"/> + <int value="2199" label="BatteryStatusInsecureOrigin"/> + <int value="2200" label="BatteryStatusCrossOrigin"/> + <int value="2201" label="BatteryStatusSameOriginABA"/> + <int value="2202" label="WebAudioValueSetterIsSetValue (Obsolete)"/> + <int value="2203" label="HasIDClassTagAttribute"/> + <int value="2204" label="HasBeforeOrAfterPseudoElement"/> + <int value="2205" label="ShapeOutsideMaybeAffectedInlineSize"/> + <int value="2206" label="ShapeOutsideMaybeAffectedInlinePosition"/> + <int value="2207" label="GamepadVibrationActuator"/> + <int value="2208" label="MicrophoneDisabledByFeaturePolicyEstimate"/> + <int value="2209" label="CameraDisabledByFeaturePolicyEstimate"/> + <int value="2210" label="MidiDisabledByFeaturePolicy"/> + <int value="2211" label="DocumentGetPreferredStylesheetSet"/> + <int value="2212" label="DocumentGetSelectedStylesheetSet"/> + <int value="2213" label="DocumentSetSelectedStylesheetSet"/> + <int value="2214" label="GeolocationGetCurrentPosition"/> + <int value="2215" label="GeolocationWatchPosition"/> + <int value="2216" label="DataUriHasOctothorpe"/> + <int value="2217" label="NetInfoSaveData"/> + <int value="2218" label="V8Element_GetClientRects_Method"/> + <int value="2219" label="V8Element_GetBoundingClientRect_Method"/> + <int value="2220" label="V8Range_GetClientRects_Method"/> + <int value="2221" label="V8Range_GetBoundingClientRect_Method"/> + <int value="2222" label="V8ErrorCaptureStackTrace"/> + <int value="2223" label="V8ErrorPrepareStackTrace"/> + <int value="2224" label="V8ErrorStackTraceLimit"/> + <int value="2225" label="PaintWorklet"/> + <int value="2226" label="DocumentPageHideRegistered"/> + <int value="2227" label="DocumentPageHideFired"/> + <int value="2228" label="DocumentPageShowRegistered"/> + <int value="2229" label="DocumentPageShowFired"/> + <int value="2230" label="ReplaceCharsetInXHR"/> + <int value="2231" label="RespondToSameOriginRequestWithCrossOriginResponse"/> + <int value="2232" label="LinkRelModulePreload"/> + <int value="2233" label="PerformanceMeasurePassedInObject"/> + <int value="2234" label="PerformanceMeasurePassedInNavigationTiming"/> + <int value="2235" label="HTMLFrameSetElementNonNullAnonymousNamedGetter"/> + <int value="2236" label="CSPWithUnsafeEval"/> + <int value="2237" label="WebAssemblyInstantiation"/> + <int value="2238" label="V8IndexAccessor"/> + <int value="2239" label="V8MediaCapabilities_DecodingInfo_Method"/> + <int value="2240" label="V8MediaCapabilities_EncodingInfo_Method"/> + <int value="2241" label="V8MediaCapabilitiesInfo_Supported_AttributeGetter"/> + <int value="2242" label="V8MediaCapabilitiesInfo_Smooth_AttributeGetter"/> + <int value="2243" + label="V8MediaCapabilitiesInfo_PowerEfficient_AttributeGetter"/> + <int value="2244" label="WindowEventInV0ShadowTree"/> + <int value="2245" label="HTMLAnchorElementDownloadInSandboxWithUserGesture"/> + <int value="2246" + label="HTMLAnchorElementDownloadInSandboxWithoutUserGesture"/> + <int value="2247" label="WindowOpenRealmMismatch"/> + <int value="2248" label="GridRowTrackPercentIndefiniteHeight"/> + <int value="2249" label="VRGetDisplaysSupportsPresent"/> + <int value="2250" label="DuplicatedAttribute"/> + <int value="2251" label="DuplicatedAttributeForExecutedScript"/> + <int value="2252" label="V8RTCPeerConnection_GetSenders_Method"/> + <int value="2253" label="V8RTCPeerConnection_GetReceivers_Method"/> + <int value="2254" label="V8RTCPeerConnection_AddTrack_Method"/> + <int value="2255" label="V8RTCPeerConnection_RemoveTrack_Method"/> + <int value="2256" label="LocalCSSFile"/> + <int value="2257" label="LocalCSSFileExtensionRejected"/> + <int value="2258" label="UserMediaDisableHardwareNoiseSuppression"/> + <int value="2259" label="CertificateTransparencyRequiredErrorOnResourceLoad"/> + <int value="2260" label="CSSSelectorPseudoWebkitAnyLink"/> + <int value="2261" label="AudioWorkletAddModule"/> + <int value="2262" label="AudioWorkletGlobalScopeRegisterProcessor"/> + <int value="2263" label="AudioWorkletNodeConstructor"/> + <int value="2264" label="HTMLMediaElementEmptyLoadWithFutureData"/> + <int value="2265" label="CSSValueDisplayContents"/> + <int value="2266" label="CSSSelectorPseudoAnyLink"/> + <int value="2267" label="FileAccessedCache"/> + <int value="2268" label="FileAccessedCookies"/> + <int value="2269" label="FileAccessedDatabase"/> + <int value="2270" label="FileAccessedFileSystem"/> + <int value="2271" label="FileAccessedLocalStorage"/> + <int value="2272" label="FileAccessedLocks"/> + <int value="2273" label="FileAccessedServiceWorker"/> + <int value="2274" label="FileAccessedSessionStorage"/> + <int value="2275" label="FileAccessedSharedWorker"/> + <int value="2276" label="V8MediaKeys_GetStatusForPolicy_Method"/> + <int value="2277" label="V8DeoptimizerDisableSpeculation"/> + <int value="2278" label="CSSSelectorCue"/> + <int value="2279" label="CSSSelectorWebkitCalendarPickerIndicator"/> + <int value="2280" label="CSSSelectorWebkitClearButton"/> + <int value="2281" label="CSSSelectorWebkitColorSwatch"/> + <int value="2282" label="CSSSelectorWebkitColorSwatchWrapper"/> + <int value="2283" label="CSSSelectorWebkitDateAndTimeValue"/> + <int value="2284" label="CSSSelectorWebkitDatetimeEdit"/> + <int value="2285" label="CSSSelectorWebkitDatetimeEditAmpmField"/> + <int value="2286" label="CSSSelectorWebkitDatetimeEditDayField"/> + <int value="2287" label="CSSSelectorWebkitDatetimeEditFieldsWrapper"/> + <int value="2288" label="CSSSelectorWebkitDatetimeEditHourField"/> + <int value="2289" label="CSSSelectorWebkitDatetimeEditMillisecondField"/> + <int value="2290" label="CSSSelectorWebkitDatetimeEditMinuteField"/> + <int value="2291" label="CSSSelectorWebkitDatetimeEditMonthField"/> + <int value="2292" label="CSSSelectorWebkitDatetimeEditSecondField"/> + <int value="2293" label="CSSSelectorWebkitDatetimeEditText"/> + <int value="2294" label="CSSSelectorWebkitDatetimeEditWeekField"/> + <int value="2295" label="CSSSelectorWebkitDatetimeEditYearField"/> + <int value="2296" label="CSSSelectorWebkitDetailsMarker"/> + <int value="2297" label="CSSSelectorWebkitFileUploadButton"/> + <int value="2298" label="CSSSelectorWebkitInnerSpinButton"/> + <int value="2299" label="CSSSelectorWebkitInputPlaceholder"/> + <int value="2300" label="CSSSelectorWebkitMediaSliderContainer"/> + <int value="2301" label="CSSSelectorWebkitMediaSliderThumb"/> + <int value="2302" label="CSSSelectorWebkitMediaTextTrackContainer"/> + <int value="2303" label="CSSSelectorWebkitMediaTextTrackDisplay"/> + <int value="2304" label="CSSSelectorWebkitMediaTextTrackRegion"/> + <int value="2305" label="CSSSelectorWebkitMediaTextTrackRegionContainer"/> + <int value="2306" label="CSSSelectorWebkitMeterBar"/> + <int value="2307" label="CSSSelectorWebkitMeterEvenLessGoodValue"/> + <int value="2308" label="CSSSelectorWebkitMeterInnerElement"/> + <int value="2309" label="CSSSelectorWebkitMeterOptimumValue"/> + <int value="2310" label="CSSSelectorWebkitMeterSuboptimumValue"/> + <int value="2311" label="CSSSelectorWebkitProgressBar"/> + <int value="2312" label="CSSSelectorWebkitProgressInnerElement"/> + <int value="2313" label="CSSSelectorWebkitProgressValue"/> + <int value="2314" label="CSSSelectorWebkitSearchCancelButton"/> + <int value="2315" label="CSSSelectorWebkitSliderContainer"/> + <int value="2316" label="CSSSelectorWebkitSliderRunnableTrack"/> + <int value="2317" label="CSSSelectorWebkitSliderThumb"/> + <int value="2318" label="CSSSelectorWebkitTextfieldDecorationContainer"/> + <int value="2319" label="CSSSelectorWebkitUnknownPseudo"/> + <int value="2320" label="FilterAsContainingBlockMayChangeOutput"/> + <int value="2321" label="DispatchMouseUpDownEventOnDisabledFormControl"/> + <int value="2322" label="CSSSelectorPseudoMatches"/> + <int value="2323" label="V8RTCRtpSender_ReplaceTrack_Method"/> + <int value="2324" label="InputTypeFileSecureOriginOpenChooser"/> + <int value="2325" label="InputTypeFileInsecureOriginOpenChooser"/> + <int value="2326" label="BasicShapeEllipseNoRadius"/> + <int value="2327" label="BasicShapeEllipseOneRadius"/> + <int value="2328" label="BasicShapeEllipseTwoRadius"/> + <int value="2329" label="TemporalInputTypeChooserByTrustedClick"/> + <int value="2330" label="TemporalInputTypeChooserByUntrustedClick"/> + <int value="2331" label="TemporalInputTypeIgnoreUntrustedClick"/> + <int value="2332" label="ColorInputTypeChooserByTrustedClick"/> + <int value="2333" label="ColorInputTypeChooserByUntrustedClick"/> + <int value="2334" label="CSSTypedOMStylePropertyMap"/> + <int value="2335" label="ScrollToFragmentRequested"/> + <int value="2336" label="ScrollToFragmentSucceedWithRaw"/> + <int value="2337" label="ScrollToFragmentSucceedWithASCII"/> + <int value="2338" label="ScrollToFragmentSucceedWithUTF8"/> + <int value="2339" label="ScrollToFragmentSucceedWithIsomorphic"/> + <int value="2340" label="ScrollToFragmentSucceedWithMixed"/> + <int value="2341" label="ScrollToFragmentFailWithASCII"/> + <int value="2342" label="ScrollToFragmentFailWithUTF8"/> + <int value="2343" label="ScrollToFragmentFailWithIsomorphic"/> + <int value="2344" label="ScrollToFragmentFailWithMixed"/> + <int value="2345" label="ScrollToFragmentFailWithInvalidEncoding"/> + <int value="2346" label="RTCPeerConnectionWithActiveCsp"/> + <int value="2347" label="ImageDecodingAttribute"/> + <int value="2348" label="ImageDecodeAPI"/> + <int value="2349" label="V8HTMLElement_Autocapitalize_AttributeGetter"/> + <int value="2350" label="V8HTMLElement_Autocapitalize_AttributeSetter"/> + <int value="2351" label="CSSLegacyAlignment"/> + <int value="2352" label="SRISignatureCheck"/> + <int value="2353" label="SRISignatureSuccess"/> + <int value="2354" label="CSSBasicShape"/> + <int value="2355" label="CSSGradient"/> + <int value="2356" label="CSSPaintFunction"/> + <int value="2357" label="WebkitCrossFade"/> + <int value="2358" label="DisablePictureInPictureAttribute"/> + <int value="2359" + label="CertificateTransparencyNonCompliantSubresourceInMainFrame"/> + <int value="2360" + label="CertificateTransparencyNonCompliantResourceInSubframe"/> + <int value="2361" label="V8AbortController_Constructor"/> + <int value="2362" label="ReplaceCharsetInXHRIgnoringCase"/> + <int value="2363" label="HTMLIFrameElementGestureMedia"/> </enum> <enum name="FeedbackSource"> @@ -16401,6 +17823,15 @@ <int value="4" label="Navigate"/> </enum> +<enum name="FetchResponseType"> + <int value="0" label="Basic"/> + <int value="1" label="CORS"/> + <int value="2" label="Default"/> + <int value="3" label="Error"/> + <int value="4" label="Opaque"/> + <int value="5" label="OpaqueRedirect"/> +</enum> + <enum name="FFmpegCodecHashes"> <int value="-2140893972" label="bfi"/> <int value="-2126016986" label="vp3"/> @@ -16427,6 +17858,8 @@ <int value="-1920272933" label="mlp"/> <int value="-1913457333" label="smackvideo"/> <int value="-1910182388" label="dds"/> + <int value="-1909815814" label="xma2"/> + <int value="-1900731082" label="scte_35"/> <int value="-1877492821" label="ws_vqa"/> <int value="-1868061100" label="avrp"/> <int value="-1866047250" label="brender_pix_deprecated"/> @@ -16446,6 +17879,7 @@ <int value="-1746190470" label="adpcm_ima_amv"/> <int value="-1742178896" label="cinepak"/> <int value="-1722959117" label="cook"/> + <int value="-1704969006" label="pcm_f24le"/> <int value="-1694324852" label="adpcm_ima_rad"/> <int value="-1653946850" label="mp3on4"/> <int value="-1638592334" label="msmpeg4v3"/> @@ -16467,18 +17901,23 @@ <int value="-1493473944" label="mp1"/> <int value="-1488471023" label="aac_latm"/> <int value="-1471896197" label="adpcm_4xm"/> + <int value="-1471717594" label="atrac3al"/> <int value="-1458812472" label="vble"/> <int value="-1452408746" label="bin_data"/> <int value="-1437754593" label="tqi"/> + <int value="-1400052876" label="fits"/> <int value="-1398094744" label="brender_pix"/> <int value="-1396201900" label="lagarith"/> <int value="-1394735166" label="s302m"/> + <int value="-1382236305" label="truemotion2rt"/> <int value="-1366158780" label="mvc2"/> + <int value="-1351352498" label="srgc"/> <int value="-1346295474" label="dfa"/> <int value="-1335819014" label="adpcm_ea_r3"/> <int value="-1333697928" label="rv10"/> <int value="-1328796639" label="pcm_s32le_planar_deprecated"/> <int value="-1326344691" label="wmalossless"/> + <int value="-1308771510" label="atrac3pal"/> <int value="-1276285619" label="subviewer1"/> <int value="-1267322736" label="evrc"/> <int value="-1253653962" label="cljr"/> @@ -16499,15 +17938,18 @@ <int value="-1146321910" label="adpcm_sbpro_4"/> <int value="-1124358604" label="qdraw"/> <int value="-1094512964" label="hevc"/> + <int value="-1088817241" label="dst"/> <int value="-1082894560" label="y41p"/> <int value="-1069291012" label="roq"/> <int value="-1055791926" label="wmv2"/> + <int value="-1055192910" label="adpcm_ima_dat4"/> <int value="-1052495685" label="adpcm_ea_xas"/> <int value="-1050536726" label="fic"/> <int value="-1050267191" label="theora"/> <int value="-1047975380" label="aura"/> <int value="-1038298513" label="iac"/> <int value="-1033247386" label="pcm_u24be"/> + <int value="-1030939519" label="bitpacked"/> <int value="-1030131048" label="ra_288"/> <int value="-1011667768" label="sgirle"/> <int value="-1010059925" label="cdgraphics"/> @@ -16521,6 +17963,7 @@ <int value="-961342190" label="truespeech"/> <int value="-955936385" label="qdm2"/> <int value="-937993216" label="cyuv"/> + <int value="-919523138" label="dolby_e"/> <int value="-908137771" label="mss2"/> <int value="-898663359" label="paf_video"/> <int value="-891450332" label="qcelp"/> @@ -16532,7 +17975,7 @@ <int value="-853586131" label="eac3"/> <int value="-839127813" label="adpcm_adx"/> <int value="-820705472" label="timed_id3"/> - <int value="-816209197" label="vima"/> + <int value="-816209197" label="vima_deprecated"/> <int value="-815578090" label="ssa"/> <int value="-804708185" label="vb"/> <int value="-799004205" label="thp"/> @@ -16541,6 +17984,7 @@ <int value="-780629337" label="adpcm_ima_oki"/> <int value="-777478450" label="iff_byterun1"/> <int value="-776406198" label="hdmv_pgs_subtitle"/> + <int value="-775674438" label="cfhd"/> <int value="-773314651" label="adpcm_thp_le"/> <int value="-755809410" label="xface"/> <int value="-750906124" label="sonic"/> @@ -16548,6 +17992,8 @@ <int value="-728484627" label="vp6f"/> <int value="-711076000" label="ilbc"/> <int value="-693682032" label="png"/> + <int value="-686461436" label="m101"/> + <int value="-680421267" label="xpm"/> <int value="-665301881" label="kgv1"/> <int value="-651841063" label="musepack7"/> <int value="-644671397" label="pcm_s16le"/> @@ -16570,8 +18016,10 @@ <int value="-478544739" label="mxpeg"/> <int value="-469833042" label="sgi"/> <int value="-462654404" label="pbm"/> + <int value="-458233175" label="rscc"/> <int value="-450113811" label="vp8"/> <int value="-449164482" label="smv"/> + <int value="-443982307" label="pcm_s64be"/> <int value="-434097103" label="8svx_fib"/> <int value="-431043877" label="rv30"/> <int value="-418117523" label="exr_deprecated"/> @@ -16579,6 +18027,7 @@ <int value="-411871512" label="4xm"/> <int value="-351638235" label="mace6"/> <int value="-335532805" label="v308"/> + <int value="-331242415" label="interplayacm"/> <int value="-321063470" label="cavs"/> <int value="-312812574" label="dsicinaudio"/> <int value="-305868762" label="ptx"/> @@ -16587,15 +18036,18 @@ <int value="-268375107" label="indeo2"/> <int value="-262604522" label="qpeg"/> <int value="-259187129" label="interplay_dpcm"/> + <int value="-235507784" label="mscc"/> <int value="-235472313" label="pjs"/> <int value="-197551526" label="vp7_deprecated"/> <int value="-195649673" label="mmvideo"/> <int value="-194494447" label="sanm"/> <int value="-179123055" label="hnm4video"/> + <int value="-178584929" label="adpcm_aica"/> <int value="-166593824" label="bintext"/> <int value="-153142813" label="adpcm_ima_qt"/> <int value="-135875472" label="pcm_s24le_planar"/> <int value="-108909529" label="adpcm_ea"/> + <int value="-97649057" label="scpr"/> <int value="-96441857" label="escape124"/> <int value="-92926716" label="indeo3"/> <int value="-92742166" label="adpcm_swf"/> @@ -16614,6 +18066,7 @@ <int value="123753" label="bethsoftvid"/> <int value="5678717" label="adpcm_vima"/> <int value="6153938" label="ffv1"/> + <int value="20173491" label="gdv"/> <int value="60024993" label="sol_dpcm"/> <int value="73149662" label="escape130_deprecated"/> <int value="76029796" label="mss1"/> @@ -16641,6 +18094,7 @@ <int value="284053917" label="sp5x"/> <int value="287849834" label="msvideo1"/> <int value="294769071" label="pcm_s16be_planar"/> + <int value="296667069" label="pcm_s64le"/> <int value="309105352" label="bmp"/> <int value="309392554" label="dsd_msbf"/> <int value="311400023" label="zlib"/> @@ -16648,6 +18102,7 @@ <int value="342736256" label="avrn"/> <int value="343186566" label="rpza"/> <int value="347789448" label="vplayer"/> + <int value="373372875" label="pcm_f16le"/> <int value="396111544" label="otf"/> <int value="412600562" label="pcm_u16be"/> <int value="429618670" label="jv"/> @@ -16663,7 +18118,11 @@ <int value="500576677" label="hap"/> <int value="503945275" label="motionpixels"/> <int value="525499602" label="vmnc"/> + <int value="536845270" label="av1"/> + <int value="539341854" label="magicyuv"/> + <int value="548057626" label="sdx2_dpcm"/> <int value="552661632" label="adpcm_xa"/> + <int value="553940120" label="adpcm_psx"/> <int value="558339021" label="jpeg2000"/> <int value="563328753" label="4gv"/> <int value="565711017" label="pcm_s24le"/> @@ -16672,6 +18131,7 @@ <int value="579930439" label="cmv"/> <int value="580364763" label="txd"/> <int value="588676310" label="pcm_s8_planar"/> + <int value="602113129" label="xma1"/> <int value="603287142" label="mpl2"/> <int value="610300309" label="v210x"/> <int value="634747673" label="avs"/> @@ -16684,6 +18144,7 @@ <int value="746742638" label="truehd"/> <int value="747771882" label="dts"/> <int value="753949422" label="indeo5"/> + <int value="776942197" label="ylc"/> <int value="781916095" label="ayuv"/> <int value="789960893" label="bmv_audio"/> <int value="802192292" label="adpcm_ima_dk4"/> @@ -16695,6 +18156,7 @@ <int value="865955000" label="smc"/> <int value="903853106" label="012v"/> <int value="913577987" label="wmav2"/> + <int value="930537867" label="clearvideo"/> <int value="944040689" label="ppm"/> <int value="944980366" label="idcin"/> <int value="946455966" label="aasc"/> @@ -16724,6 +18186,7 @@ <int value="1139877352" label="dnxhd"/> <int value="1158772651" label="anm"/> <int value="1165132763" label="opus_deprecated"/> + <int value="1185344399" label="svg"/> <int value="1194572884" label="g2m_deprecated"/> <int value="1210249397" label="avc"/> <int value="1213003867" label="hdmv_text_subtitle"/> @@ -16733,6 +18196,7 @@ <int value="1251286213" label="dxv"/> <int value="1258259575" label="pcm_lxf"/> <int value="1271374381" label="wmav1"/> + <int value="1278764780" label="gremlin_dpcm"/> <int value="1294385179" label="mp3"/> <int value="1299068647" label="truemotion1"/> <int value="1310993795" label="zerocodec"/> @@ -16747,6 +18211,7 @@ <int value="1397947482" label="dsd_lsbf"/> <int value="1411832541" label="pcm_f32be"/> <int value="1413182900" label="dvd_nav_packet"/> + <int value="1456197148" label="fmvc"/> <int value="1462568683" label="srt"/> <int value="1467359000" label="msa1"/> <int value="1468951708" label="comfortnoise"/> @@ -16776,7 +18241,9 @@ <int value="1724507916" label="ra_144"/> <int value="1729587546" label="pgmyuv"/> <int value="1730373804" label="pcm_alaw"/> + <int value="1739261970" label="pixlet"/> <int value="1741236466" label="subrip"/> + <int value="1768130043" label="wrapped_avframe"/> <int value="1771307928" label="flashsv2"/> <int value="1789213623" label="wavpack"/> <int value="1804125128" label="pcm_s24be"/> @@ -16794,7 +18261,9 @@ <int value="1951984033" label="v210"/> <int value="1961440145" label="vp6a"/> <int value="1965599083" label="sami"/> + <int value="1980641302" label="daala"/> <int value="1981484138" label="pcm_u32le"/> + <int value="1991949075" label="sheervideo"/> <int value="1997862473" label="interplayvideo"/> <int value="2002251246" label="tscc2"/> <int value="2005720882" label="atrac3"/> @@ -16802,8 +18271,10 @@ <int value="2032395845" label="pcm_u16le"/> <int value="2041774878" label="huffyuv"/> <int value="2047102762" label="sanm_deprecated"/> + <int value="2049828371" label="screenpresso"/> <int value="2053719989" label="r210"/> <int value="2071582326" label="xbin"/> + <int value="2080470405" label="speedhq"/> <int value="2080704511" label="pcm_s16be"/> <int value="2084073402" label="ljpeg"/> <int value="2086226415" label="pcm_s32le"/> @@ -16811,6 +18282,8 @@ <int value="2100540076" label="amr_wb"/> <int value="2118960502" label="mimic"/> <int value="2128505640" label="wnv1"/> + <int value="2134847163" label="adpcm_mtaf"/> + <int value="2142093799" label="psd"/> <int value="2146164868" label="v410"/> </enum> @@ -17225,6 +18698,15 @@ <int value="10" label="DRIVE_SHARED_WITH_ME"/> <int value="11" label="DRIVE_RECENT"/> <int value="12" label="MEDIA_VIEW"/> + <int value="13" label="RECENT"/> +</enum> + +<enum name="FileManagerTaskType"> + <int value="0" label="Unknown"/> + <int value="1" label="Browser"/> + <int value="2" label="Chrome App"/> + <int value="3" label="Drive App"/> + <int value="4" label="ARC App"/> </enum> <enum name="FileManagerVolumeType"> @@ -17246,6 +18728,13 @@ <int value="5" label="File has invalid contents."/> <int value="6" label="File could not be exclusively opened."/> <int value="7" label="File contents internally deleted."/> + <int value="8" label="File processing was postponed due to filtering."/> + <int value="9" label="File was skipped/deleted due to filtering."/> + <int value="10" label="File was older than maximum allowed age."/> + <int value="11" label="File made for too many files in the directory."/> + <int value="12" label="File made for too many bytes in the directory."/> + <int value="13" label="File was skipped because it belongs to this process."/> + <int value="14" label="File did not have required embedded profile."/> </enum> <enum name="FileMetricsProviderEmbeddedProfileResult"> @@ -17257,6 +18746,27 @@ label="File was dropped because no embedded profile was found."/> </enum> +<enum name="FileMetricsProviderHappening"> + <obsolete> + Deprecated February, 2018. + </obsolete> + <int value="0" label="OnDidCreateMetricsLog"/> + <int value="1" label="ScheduleSourcesCheck"/> + <int value="2" label="CheckAndMergeMetricSources"/> + <int value="3" label="RecordSourcesChecked"/> + <int value="4" label="CheckAndMapSource"/> + <int value="5" label="FinishedWithSource"/> + <int value="6" label="RecordSourceAsRead"/> + <int value="7" label="DeleteFileAsync"/> + <int value="8" label="MergeHistogramDeltasFromSource"/> + <int value="9" label="RecordHistogramSnapshotsFromSource"/> + <int value="10" label="ProvideIndependentMetrics"/> + <int value="11" label="ScheduleSourcesCheck Failed"/> + <int value="12" label="Old DeleteFile Failed"/> + <int value="13" label="Over DeleteFile Failed"/> + <int value="14" label="Async DeleteFile Failed"/> +</enum> + <enum name="FileReaderSyncWorkerType"> <int value="0" label="Other"/> <int value="1" label="Dedicated Worker"/> @@ -17328,6 +18838,35 @@ <int value="4" label="User left the page before first contentful paint"/> </enum> +<enum name="FirstRunLaunchSource"> + <summary> + External applications/promotions that triggered Chrome launch and First Run. + </summary> + <int value="0" label="Smart App Banner"/> + <int value="1" label="Mobile Safari"/> + <int value="2" label="Others"/> +</enum> + +<enum name="FirstRunSignInResult"> + <summary>Result states for the first-run sign-in flow.</summary> + <int value="0" label="Skipped Immediately"/> + <int value="1" label="Successful"/> + <int value="2" label="Gave Up"/> + <int value="3" label="Have SSO account, Skipped Immediately"/> + <int value="4" label="Have SSO account, Successful"/> + <int value="5" label="Have SSO account, Gave Up"/> +</enum> + +<enum name="FirstUserActionType"> + <summary> + Types of actions a user can perform upon startup or unbackgrounding. + </summary> + <int value="0" label="New Task"/> + <int value="1" label="Continuation"/> + <int value="2" label="Expiration"/> + <int value="3" label="Start on NTP"/> +</enum> + <enum name="FlashNavigateUsageType"> <int value="0" label="Rejected because of Authorization header."/> <int value="1" label="Rejected because of Cache-Control header."/> @@ -17386,6 +18925,29 @@ <int value="5" label="GNOME failure"/> </enum> +<enum name="FoundationFileSystemError"> + <int value="0" label="NSNoError"/> + <int value="4" label="NSFileNoSuchFileError"/> + <int value="255" label="NSFileLockingError"/> + <int value="256" label="NSFileReadUnknownError"/> + <int value="257" label="NSFileReadNoPermissionError"/> + <int value="258" label="NSFileReadInvalidFileNameError"/> + <int value="259" label="NSFileReadCorruptFileError"/> + <int value="260" label="NSFileReadNoSuchFileError"/> + <int value="261" label="NSFileReadInapplicableStringEncodingError"/> + <int value="262" label="NSFileReadUnsupportedSchemeError"/> + <int value="263" label="NSFileReadTooLargeError"/> + <int value="264" label="NSFileReadUnknownStringEncodingError"/> + <int value="512" label="NSFileWriteUnknownError"/> + <int value="513" label="NSFileWriteNoPermissionError"/> + <int value="514" label="NSFileWriteInvalidFileNameError"/> + <int value="516" label="NSFileWriteFileExistsError"/> + <int value="517" label="NSFileWriteInapplicableStringEncodingError"/> + <int value="518" label="NSFileWriteUnsupportedSchemeError"/> + <int value="640" label="NSFileWriteOutOfSpaceError"/> + <int value="642" label="NSFileWriteVolumeReadOnlyError"/> +</enum> + <enum name="FramebustPermissions"> <int value="0" label="Only permitted for framebusting, no user gesture"/> <int value="1" label="Only permitted for framebusting, user gesture"/> @@ -17514,40 +19076,64 @@ <int value="1615384" label="alert_notification_control_point"/> <int value="4531384" label="date_of_birth"/> + <int value="14295641" + label="PocketLab; f000aa1e-0452-4000-b000-000000000000"/> <int value="22829753" label="barometric_pressure_trend"/> + <int value="25010789" + label="PocketLab (from service 11); + f000aa17-0452-4000-b000-000000000000"/> <int value="33030714" label="scan_refresh"/> <int value="36624371" label="Anki OVERDRIVE cars; be15bee0-6186-407e-8381-0bd89c4d8df4"/> <int value="40437408" label="gender"/> <int value="42833873" label="42833873 (Unknown; not a 16bit UUID)"/> + <int value="46607535" + label="PocketLab 1; f000aa14-0451-4000-b000-000000000000"/> + <int value="61502349" + label="PocketLab; f000aa2c-0452-4000-b000-000000000000"/> <int value="64893984" label="local_east_coordinate.xml"/> <int value="67768539" label="alert_category_id_bit_mask"/> <int value="79560451" label="sc_control_point"/> + <int value="81699382" + label="PocketLab; f000aa1d-0452-4000-b000-000000000000"/> <int value="84948752" label="Eddystone Config ADV Slot Data; a3c8750a-8ed3-4bdf-8a39-a01bebede295"/> <int value="87432554" label="Parrot Drone; 9a66fd54-0800-9191-11e4-012d1540cb8e"/> + <int value="87889094" + label="PocketLab 1; f000aa21-0451-4000-b000-000000000000"/> <int value="89070880" label="blood_pressure_measurement"/> <int value="102699400" label="cycling_power_feature"/> <int value="107355463" label="konashi analogRead2; 229b300a-03fb-40da-98a7-b0def65c2d4b"/> + <int value="107684477" + label="PocketLab; f000aa2d-0452-4000-b000-000000000000"/> <int value="111826224" label="micro:bit client requirements; e95d23c4-251d-470a-a062-fa1922dfa9a8"/> <int value="121100653" label="Parrot Drone; 9a66fd22-0800-9191-11e4-012d1540cb8e"/> + <int value="129263762" + label="PocketLab; f000aa04-0452-4000-b000-000000000000"/> <int value="145478270" label="glucose_feature"/> <int value="162705488" label="manufacturer_name_string"/> <int value="164418508" label="weight_measurement"/> <int value="177223896" label="report_map"/> <int value="193202136" label="Anki OVERDRIVE cars; be15bee1-6186-407e-8381-0bd89c4d8df4"/> + <int value="197745578" + label="PocketLab 1; f000aa13-0451-4000-b000-000000000000"/> <int value="203698195" label="micro:bit event; e95d9775-251d-470a-a062-fa1922dfa9a8"/> <int value="203846063" label="ff0c"/> <int value="205016416" label="body_composition_measurement"/> <int value="235785246" label="irradiance"/> + <int value="241152428" + label="PocketLab; f000aa25-0452-4000-b000-000000000000"/> + <int value="244169154" + label="PocketLab (from service 31); + f000aa32-0452-4000-b000-000000000000"/> <int value="248349383" label="csc_measurement"/> <int value="254703207" label="true_wind_speed"/> <int value="257107525" label="intermediate_temperature"/> @@ -17559,6 +19145,8 @@ label="Wahoo Kickr trainer; a026e005-0a7d-4ab3-97fa-f1500f9feb8b"/> <int value="296670902" label="heart_rate_control_point"/> <int value="298186521" label="alert_category_id"/> + <int value="305375377" + label="PocketLab 1; f000aa62-0451-4000-b000-000000000000"/> <int value="307449363" label="plx_features"/> <int value="310983691" label="cycling_power_measurement"/> <int value="312578485" label="navigation"/> @@ -17582,21 +19170,34 @@ label="micro:bit requirements; e95db84c-251d-470a-a062-fa1922dfa9a8"/> <int value="372306057" label="Bleno Pizza Example; 13333333-3333-3333-3333-333333330001"/> + <int value="384581502" + label="PocketLab; f000aa07-0452-4000-b000-000000000000"/> <int value="404638811" label="konashi pwmParameter; 229b3005-03fb-40da-98a7-b0def65c2d4b"/> <int value="405569435" label="boot_keyboard_output_report"/> <int value="409618715" label="cycling_power_vector"/> <int value="416059854" label="konashi uartRxNotification; 229b3013-03fb-40da-98a7-b0def65c2d4b"/> + <int value="416715482" + label="PocketLab (from service 11); + f000aa19-0452-4000-b000-000000000000"/> <int value="419477741" label="body_composition_feature"/> + <int value="426120542" + label="PocketLab; f000aa3b-0452-4000-b000-000000000000"/> <int value="440009071" label="konashi pwmDuty; 229b3006-03fb-40da-98a7-b0def65c2d4b"/> <int value="448606809" label="448606809 (Unknown; not a 16bit UUID)"/> + <int value="449334956" + label="PocketLab; f000aa3d-0452-4000-b000-000000000000"/> + <int value="450021248" + label="PocketLab 1; f000aa34-0451-4000-b000-000000000000"/> <int value="469191968" label="Playbulb Candle Color; fffc"/> <int value="473092981" label="Eddystone Config Advertising Interval; a3c87503-8ed3-4bdf-8a39-a01bebede295"/> <int value="486368335" label="location_name"/> + <int value="501361244" + label="PocketLab; f000aa21-0452-4000-b000-000000000000"/> <int value="508191605" label="Parrot Drone; 9a66fb1b-0800-9191-11e4-012d1540cb8e"/> <int value="511033835" @@ -17620,14 +19221,29 @@ <int value="589575132" label="Sphero Robot; 22bb746f-2bbd-7554-2d6f-726568705327"/> <int value="589741087" label="model_number_string"/> + <int value="599786587" + label="PocketLab (from service 11); + f000aa1a-0452-4000-b000-000000000000"/> + <int value="602410094" + label="PocketLab; f000aa28-0452-4000-b000-000000000000"/> <int value="625191771" label="Parrot Drone; 9a66fa0a-0800-9191-11e4-012d1540cb8e"/> + <int value="628511213" + label="PocketLab; f000aa3a-0452-4000-b000-000000000000"/> <int value="638602429" label="new_alert"/> <int value="640013977" label="konashi uartBaudRate; 229b3011-03fb-40da-98a7-b0def65c2d4b"/> + <int value="640611109" + label="PocketLab (from service 11); + f000aa14-0452-4000-b000-000000000000"/> <int value="642925692" label="anaerobic_heart_rate_lower_limit"/> + <int value="645640295" + label="PocketLab (from service 11); + f000aa16-0452-4000-b000-000000000000"/> <int value="650507215" label="aerobic_heart_rate_lower_limit"/> <int value="653904148" label="cgm_session_run_time"/> + <int value="659248322" + label="PocketLab; f000aa29-0452-4000-b000-000000000000"/> <int value="675543714" label="aerobic_threshold"/> <int value="682327952" label="Parrot Drone; 9a66fa0b-0800-9191-11e4-012d1540cb8e"/> @@ -17636,23 +19252,39 @@ <int value="689682673" label="unread_alert_status"/> <int value="710863194" label="dew_point"/> <int value="713208266" label="apparent_wind_direction"/> + <int value="724409151" + label="PocketLab; f000aa1f-0452-4000-b000-000000000000"/> <int value="724796397" label="weight"/> + <int value="725361228" + label="PocketLab; f000aa10-0452-4000-b000-000000000000"/> <int value="735462059" label="konashi uartConfig; 229b3010-03fb-40da-98a7-b0def65c2d4b"/> <int value="747671909" label="reference_time_information"/> <int value="747737913" label="konashi pioOutput; 229b3002-03fb-40da-98a7-b0def65c2d4b"/> <int value="752820597" label="boot_mouse_input_report"/> + <int value="753456499" + label="PocketLab; f000aa27-0452-4000-b000-000000000000"/> <int value="762835818" label="tx_power_level"/> <int value="765862810" label="cgm_session_start_time"/> <int value="777276843" label="Bleno Pizza Example; 13333333-3333-3333-3333-333333330003"/> + <int value="784175223" + label="PocketLab; f000aa39-0452-4000-b000-000000000000"/> <int value="786588903" label="Parrot Drone; 9a66fd53-0800-9191-11e4-012d1540cb8e"/> <int value="788890283" label="Eddystone Config Factory reset; a3c8750b-8ed3-4bdf-8a39-a01bebede295"/> <int value="797118889" label="time_source"/> + <int value="806223105" + label="PocketLab; f000aa1c-0452-4000-b000-000000000000"/> + <int value="827298832" + label="PocketLab 1; f000aa41-0451-4000-b000-000000000000"/> + <int value="827651216" + label="PocketLab; f000aa20-0452-4000-b000-000000000000"/> + <int value="837013645" + label="PocketLab 1; f000aa64-0451-4000-b000-000000000000"/> <int value="839366223" label="user_index"/> <int value="842908520" label="rsc_measurement"/> <int value="845003775" @@ -17661,6 +19293,8 @@ label="Elite trainer; 347b0011-7635-408b-8918-8ff3949ce592"/> <int value="851655329" label="konashi analogRead0; 229b3008-03fb-40da-98a7-b0def65c2d4b"/> + <int value="853857776" + label="PocketLab; f000aa2a-0452-4000-b000-000000000000"/> <int value="859809200" label="resting_heart_rate"/> <int value="867296114" label="gust_factor"/> <int value="868427891" label="local_north_coordinate"/> @@ -17678,6 +19312,8 @@ <int value="922434244" label="ln_feature"/> <int value="928099812" label="system_id"/> <int value="928491064" label="last_name"/> + <int value="936278868" + label="PocketLab 1; f000aa53-0451-4000-b000-000000000000"/> <int value="941113050" label="konashi i2cReadParameter; 229b300e-03fb-40da-98a7-b0def65c2d4b"/> <int value="947971228" label="temperature_type"/> @@ -17688,9 +19324,18 @@ label="Eddystone Config Public ECDH Key; a3c87508-8ed3-4bdf-8a39-a01bebede295"/> <int value="976761505" label="local_time_information"/> + <int value="981442423" + label="PocketLab 1; f000aa63-0451-4000-b000-000000000000"/> <int value="987658962" label="glucose_measurement"/> <int value="1002619180" label="exact_time_256"/> + <int value="1005198408" + label="PocketLab 1; f000aa51-0451-4000-b000-000000000000"/> + <int value="1018346218" + label="PocketLab; f000aa03-0452-4000-b000-000000000000"/> <int value="1025676359" label="dst_offset"/> + <int value="1049176129" + label="PocketLab (from service 11); + f000aa15-0452-4000-b000-000000000000"/> <int value="1050948662" label="nRF UART TX; nrf52-Quadcopter; 6e400002-b5a3-f393-e0a9-e50e24dcca9e"/> @@ -17700,25 +19345,43 @@ <int value="1072163984" label="gap.reconnection_address"/> <int value="1077684177" label="Parrot Drone; 9a66fd52-0800-9191-11e4-012d1540cb8e"/> + <int value="1097514018" + label="PocketLab; f000aa06-0452-4000-b000-000000000000"/> <int value="1100640868" label="day_of_week"/> + <int value="1102386988" + label="PocketLab 1; f000aa42-0451-4000-b000-000000000000"/> + <int value="1108268178" + label="PocketLab 1; f000aa23-0451-4000-b000-000000000000"/> <int value="1115558005" label="konashi hardwareReset; 229b3014-03fb-40da-98a7-b0def65c2d4b"/> <int value="1117053056" label="Remote Lego; 7baf8dca-2bfc-47fb-af29-042fccc180eb"/> <int value="1125104414" label="gap.central_address_resolution_support"/> + <int value="1125757823" + label="PocketLab (from service 31); + f000aa33-0452-4000-b000-000000000000"/> <int value="1134538374" label="hip_circumference"/> <int value="1136624215" label="maximum_recommended_heart_rate"/> <int value="1136682523" label="date_time"/> + <int value="1142216738" + label="PocketLab 1; f000aa22-0451-4000-b000-000000000000"/> <int value="1154699367" label="konashi uartTx; 229b3012-03fb-40da-98a7-b0def65c2d4b"/> <int value="1161713439" label="Playbulb Candle Effect; fffb"/> <int value="1167525145" label="alert_status"/> + <int value="1167648736" + label="PocketLab (from service 11); + f000aa18-0452-4000-b000-000000000000"/> <int value="1169219288" label="1169219288 (Unknown; not a 16bit UUID)"/> <int value="1183399370" label="magnetic_flux_density_3D"/> <int value="1186677690" label="Eddystone Config Advertised Tx Power; a3c87505-8ed3-4bdf-8a39-a01bebede295"/> <int value="1193066711" label="uv_index"/> + <int value="1211834643" + label="PocketLab; f000aa02-0452-4000-b000-000000000000"/> + <int value="1212625023" + label="PocketLab 1; f000aa52-0451-4000-b000-000000000000"/> <int value="1214133688" label="vo2_max"/> <int value="1217613737" label="three_zone_heart_rate_limits"/> <int value="1225369773" @@ -17728,27 +19391,39 @@ <int value="1243630465" label="Sphero Robot; 22bb746f-2ba1-7554-2d6f-726568705327"/> <int value="1245615057" label="pnp_id"/> + <int value="1254514264" + label="PocketLab; f000aa05-0452-4000-b000-000000000000"/> <int value="1254532025" label="user_control_point"/> <int value="1266038031" label="1266038031 (Unknown; not a 16bit UUID)"/> <int value="1288236137" label="hid_control_point"/> + <int value="1293962119" + label="PocketLab 1; f000aa61-0451-4000-b000-000000000000"/> <int value="1307935876" label="Tacx trainer; 6e40fec3-b5a3-f393-e0a9-e50e24dcca9e"/> <int value="1320278204" label="Eddystone Config Radio Tx Power; a3c87504-8ed3-4bdf-8a39-a01bebede295"/> + <int value="1324040850" + label="PocketLab 1; f000aa11-0451-4000-b000-000000000000"/> <int value="1329901812" label="Eddystone Config Lock State; a3c87506-8ed3-4bdf-8a39-a01bebede295"/> <int value="1333242790" label="longitude"/> <int value="1334750659" label="konashi i2cWrite; 229b300d-03fb-40da-98a7-b0def65c2d4b"/> + <int value="1345855767" + label="PocketLab 1; f000aa24-0451-4000-b000-000000000000"/> <int value="1352512695" label="1352512695 (Unknown; not a 16bit UUID)"/> <int value="1358488787" label="sport_type_for_aerobic_and_anaerobic_thresholds"/> <int value="1359562687" label="PowerUp RC plane; 75b64e51-f184-4ed1-921a-476090d80ba7"/> + <int value="1366194038" + label="PocketLab; f000aa22-0452-4000-b000-000000000000"/> <int value="1370497910" label="position_quality"/> <int value="1370779343" label="apparent_wind_speed"/> + <int value="1378697826" + label="PocketLab; f000aa2f-0452-4000-b000-000000000000"/> <int value="1399905251" label="elevation"/> <int value="1403230035" label="konashi analogDrive; 229b3007-03fb-40da-98a7-b0def65c2d4b"/> @@ -17759,11 +19434,19 @@ <int value="1418868404" label="gap.peripheral_preferred_connection_parameters"/> <int value="1419696114" label="record_access_control_point"/> + <int value="1423142122" + label="PocketLab; f000aa01-0452-4000-b000-000000000000"/> <int value="1426243900" label="time_update_state"/> <int value="1443769073" label="Parrot Drone; 9a66fb0e-0800-9191-11e4-012d1540cb8e"/> <int value="1445812935" label="current_time"/> <int value="1448457670" label="cgm_feature"/> + <int value="1451886110" + label="PocketLab; f000aa38-0452-4000-b000-000000000000"/> + <int value="1463907405" + label="PocketLab; f000aa2b-0452-4000-b000-000000000000"/> + <int value="1477417345" + label="PocketLab; f000aa23-0452-4000-b000-000000000000"/> <int value="1479031407" label="five_zone_heart_rate_limits"/> <int value="1480262218" label="height"/> <int value="1482584061" @@ -17786,23 +19469,39 @@ <int value="1547112406" label="Eddystone Config Active Slot; a3c87502-8ed3-4bdf-8a39-a01bebede295"/> + <int value="1547439596" + label="PocketLab 1; f000aa31-0451-4000-b000-000000000000"/> <int value="1548291582" label="konashi analogRead1; 229b3009-03fb-40da-98a7-b0def65c2d4b"/> + <int value="1551090056" + label="PocketLab; f000aa35-0452-4000-b000-000000000000"/> <int value="1556918420" label="supported_new_alert_category"/> <int value="1562359952" label="bond_management_control_point"/> <int value="1581120657" label="Parrot Drone; 9a66fb1c-0800-9191-11e4-012d1540cb8e"/> + <int value="1588237112" + label="PocketLab; f000aa3f-0452-4000-b000-000000000000"/> <int value="1594190447" label="anaerobic_threshold"/> <int value="1594284383" label="time_accuracy"/> <int value="1599786113" label="sensor_location"/> + <int value="1611458228" + label="PocketLab; f000aa34-0452-4000-b000-000000000000"/> + <int value="1620145835" + label="PocketLab 1; f000aa54-0451-4000-b000-000000000000"/> <int value="1650767660" label="protocol_mode"/> <int value="1655824245" label="pressure"/> <int value="1658559118" label="digital"/> + <int value="1667674937" + label="PocketLab 1; f000aa33-0451-4000-b000-000000000000"/> <int value="1669829174" label="Purple Eye; 00005200-0000-1000-8000-00805f9b34fb"/> <int value="1676607014" label="konashi i2cConfig; 229b300b-03fb-40da-98a7-b0def65c2d4b"/> <int value="1704141710" label="true_wind_direction"/> + <int value="1717192545" + label="PocketLab 1; f000aa12-0451-4000-b000-000000000000"/> + <int value="1719495127" + label="PocketLab; f000aa00-0452-4000-b000-000000000000"/> <int value="1732815395" label="alert_level"/> <int value="1735563923" label="rsc_feature"/> <int value="1748731133" label="intermediate_blood_pressure"/> @@ -17830,26 +19529,47 @@ label="Parrot Drone; 9a66fd24-0800-9191-11e4-012d1540cb8e"/> <int value="1865494132" label="konashi i2cRead; 229b300f-03fb-40da-98a7-b0def65c2d4b"/> + <int value="1866335371" + label="PocketLab; f000aa36-0452-4000-b000-000000000000"/> + <int value="1873367042" + label="PocketLab; f000aa3c-0452-4000-b000-000000000000"/> <int value="1875571028" label="PowerUp RC plane; 75b64e51-f185-4ed1-921a-476090d80ba7"/> <int value="1881531610" label="descriptor_value_changed"/> <int value="1899652799" label="pollen_concentration"/> <int value="1904364134" label="aerobic_heart_rate_upper_limit"/> + <int value="1934342765" + label="PocketLab; f000aa30-0452-4000-b000-000000000000"/> <int value="1936155204" label="gap.device_name"/> <int value="1940300093" label="Tacx trainer; 6e40fec2-b5a3-f393-e0a9-e50e24dcca9e"/> + <int value="1945497075" + label="PocketLab; f000aa24-0452-4000-b000-000000000000"/> <int value="1954594648" label="temperature"/> <int value="1970019437" label="gap.peripheral_privacy_flag"/> + <int value="1974805193" + label="PocketLab; f000aa26-0452-4000-b000-000000000000"/> <int value="1981651466" label="wind_chill"/> <int value="1984759904" label="1984759904 (Unknown; not a 16bit UUID)"/> + <int value="1995515788" + label="PocketLab (from service 11); + f000aa1b-0452-4000-b000-000000000000"/> + <int value="1995890588" + label="PocketLab 1; f000aa43-0451-4000-b000-000000000000"/> <int value="1999174392" label="glucose_measurement_context"/> <int value="2000824522" label="waist_circumference"/> <int value="2010182602" label="csc_feature"/> + <int value="2010559917" + label="PocketLab; f000aa2e-0452-4000-b000-000000000000"/> + <int value="2020665772" + label="PocketLab; f000aa3e-0452-4000-b000-000000000000"/> <int value="2022949018" label="cgm_status"/> <int value="2025615830" label="aggregate"/> <int value="2025816471" label="Eddystone Config Unlock; a3c87507-8ed3-4bdf-8a39-a01bebede295"/> <int value="2031294873" label="uncertainty"/> + <int value="2040106786" + label="PocketLab 1; f000aa44-0451-4000-b000-000000000000"/> <int value="2041423305" label="email_address"/> <int value="2042267197" label="age"/> <int value="2047173546" label="boot_keyboard_input_report"/> @@ -17857,18 +19577,32 @@ label="nrf52-Quadcopter; 6e400004-b5a3-f393-e0a9-e50e24dcca9e"/> <int value="2055293976" label="Remote Lego; b394673e-dea0-4044-a189-86f1c85ce22e"/> + <int value="2066621778" + label="PocketLab; f000aa37-0452-4000-b000-000000000000"/> <int value="2083994430" label="two_zone_heart_rate_limit"/> <int value="2084445069" label="ringer_control_point"/> + <int value="2088370773" + label="PocketLab (from service 11); + f000aa13-0452-4000-b000-000000000000"/> <int value="2091220203" label="konashi pioInputNotification; 229b3003-03fb-40da-98a7-b0def65c2d4b"/> <int value="2091531878" label="weight_scale_feature"/> + <int value="2093050338" + label="PocketLab; f000aa08-0452-4000-b000-000000000000"/> <int value="2100140560" label="2100140560 (Unknown; not a 16bit UUID)"/> <int value="2101185135" label="time_zone"/> + <int value="2103247472" + label="PocketLab; f000aa09-0452-4000-b000-000000000000"/> <int value="2105952193" label="heart_rate_max"/> <int value="2110830087" label="Printer; 00002af1-0000-1000-8000-00805f9b34fb"/> + <int value="2118241351" + label="PocketLab 1; f000aa32-0451-4000-b000-000000000000"/> <int value="2118566262" label="database_change_increment"/> + <int value="2122016879" + label="PocketLab (from service 11); + f000aa12-0452-4000-b000-000000000000"/> <int value="2125906618" label="gap.appearance"/> <int value="2140490935" label="gatt.service_changed"/> </enum> @@ -17921,6 +19655,8 @@ <!-- Hash values can be produced using tool: bluetooth_metrics_hash --> <int value="7464675" label="pulse_oximeter"/> + <int value="14295641" + label="PocketLab; f000aa1e-0452-4000-b000-000000000000"/> <int value="26695985" label="fe20"/> <int value="35226455" label="fe44"/> <int value="35347197" label="fe26"/> @@ -17932,17 +19668,27 @@ <int value="48912332" label="micro:bit event; e95d93af-251d-470a-a062-fa1922dfa9a8"/> <int value="56938056" label="feb9"/> + <int value="61502349" + label="PocketLab; f000aa2c-0452-4000-b000-000000000000"/> <int value="62669585" label="feff"/> <int value="70653353" label="fe37"/> <int value="81094401" label="link_loss"/> + <int value="81699382" + label="PocketLab; f000aa1d-0452-4000-b000-000000000000"/> <int value="85709298" label="fe38"/> + <int value="87242598" + label="PocketLab 1; f000aa40-0451-4000-b000-000000000000"/> <int value="91953454" label="fe7b"/> + <int value="107684477" + label="PocketLab; f000aa2d-0452-4000-b000-000000000000"/> <int value="109066436" label="Printer; 18f0"/> <int value="117033282" label="fe1e"/> <int value="119232939" label="fe16"/> <int value="124193922" label="nrf52-Quadcopter; 6e400020-b5a3-f393-e0a9-e50e24dcca9e"/> <int value="126220948" label="fec4"/> + <int value="129263762" + label="PocketLab; f000aa04-0452-4000-b000-000000000000"/> <int value="130754956" label="fe0d"/> <int value="134110769" label="fecf"/> <int value="141942246" label="fe1d"/> @@ -17958,16 +19704,24 @@ <int value="229725863" label="Juggglow; 624e957f-cb42-4cd6-bacc-84aeb898f69b"/> <int value="239745754" label="fe22"/> + <int value="241152428" + label="PocketLab; f000aa25-0452-4000-b000-000000000000"/> + <int value="244169154" + label="PocketLab; f000aa32-0452-4000-b000-000000000000"/> <int value="252638028" label="fe9c"/> <int value="253001319" label="fe84"/> <int value="267848299" label="fe3e"/> <int value="270670950" label="fe62"/> + <int value="272049750" + label="PocketLab 1; f000aa30-0451-4000-b000-000000000000"/> <int value="272218751" label="automation_io"/> <int value="273356483" label="fe68"/> <int value="278860884" label="fe5c"/> <int value="289754407" label="fe01"/> <int value="291870040" label="fe6d"/> <int value="295205583" label="fe27"/> + <int value="298938019" + label="PocketLab 1; f000aa20-0451-4000-b000-000000000000"/> <int value="310654399" label="fe54"/> <int value="314884784" label="fe65"/> <int value="315044617" label="fea9"/> @@ -17981,22 +19735,32 @@ <int value="353919198" label="fe41"/> <int value="367801999" label="fe19"/> <int value="381944619" label="continuous_glucose_monitoring"/> + <int value="384581502" + label="PocketLab; f000aa07-0452-4000-b000-000000000000"/> <int value="393442080" label="fe47"/> <int value="404751265" label="fe34"/> <int value="406443827" label="fe08"/> <int value="406667138" label="fe1b"/> <int value="408422717" label="fe12"/> <int value="411422080" label="feaf"/> + <int value="426120542" + label="PocketLab; f000aa3b-0452-4000-b000-000000000000"/> <int value="428955508" label="fed8"/> <int value="436040838" label="fe49"/> <int value="442258066" label="fec6"/> <int value="448479874" label="fe13"/> + <int value="449334956" + label="PocketLab; f000aa3d-0452-4000-b000-000000000000"/> <int value="452749537" label="fe6f"/> <int value="486403409" label="fe7e"/> <int value="493187195" label="Insight cards; 13630000-aeb9-10cf-ef69-81e145a91113"/> <int value="499379297" label="fe0c"/> + <int value="501361244" + label="PocketLab; f000aa21-0452-4000-b000-000000000000"/> <int value="517314925" label="fe0e"/> + <int value="525609715" + label="PocketLab 1; f000aa10-0451-4000-b000-000000000000"/> <int value="534472233" label="feea"/> <int value="535574137" label="feb1"/> <int value="540487861" @@ -18016,17 +19780,23 @@ <int value="599398840" label="feb4"/> <int value="601952480" label="PowerUp RC plane; 75b64e51-f181-4ed1-921a-476090d80ba7"/> + <int value="602410094" + label="PocketLab; f000aa28-0452-4000-b000-000000000000"/> <int value="603143198" label="fef5"/> <int value="604112254" label="fee4"/> <int value="612248808" label="612248808 (Unknown; not a 16bit UUID)"/> <int value="617434027" label="fe59"/> <int value="621358948" label="fec7"/> <int value="626013607" label="FIDO authentication service (fffd)"/> + <int value="628511213" + label="PocketLab; f000aa3a-0452-4000-b000-000000000000"/> <int value="633977000" label="fedf"/> <int value="634740644" label="Purple Eye; 00005100-0000-1000-8000-00805f9b34fb"/> <int value="642914459" label="fe3d"/> <int value="643543662" label="fefe"/> + <int value="659248322" + label="PocketLab; f000aa29-0452-4000-b000-000000000000"/> <int value="661885353" label="Remote Lego; 40480f29-7bad-4ea5-8bf8-499405c9b324"/> <int value="675211143" label="fe4a"/> @@ -18044,19 +19814,33 @@ <int value="712814660" label="Eddystone-URL Beacon Configuration; ee0c2080-8786-40ba-ab96-99b91ac981d8"/> + <int value="724409151" + label="PocketLab; f000aa1f-0452-4000-b000-000000000000"/> + <int value="725361228" + label="PocketLab; f000aa10-0452-4000-b000-000000000000"/> <int value="739317418" label="fe05"/> <int value="741183887" label="fe78"/> <int value="749323131" label="fece"/> + <int value="753456499" + label="PocketLab; f000aa27-0452-4000-b000-000000000000"/> <int value="762562796" label="fe5e"/> <int value="775377708" label="fe2b"/> <int value="780195705" label="fead"/> + <int value="784175223" + label="PocketLab; f000aa39-0452-4000-b000-000000000000"/> <int value="786171562" label="fe0a"/> <int value="803680658" label="fea3"/> <int value="805645044" label="glucose"/> + <int value="806223105" + label="PocketLab; f000aa1c-0452-4000-b000-000000000000"/> <int value="807272540" label="fe1a"/> <int value="817497010" label="fe18"/> + <int value="827651216" + label="PocketLab; f000aa20-0452-4000-b000-000000000000"/> <int value="836214784" label="cycling_power"/> <int value="841972234" label="feeb"/> + <int value="853857776" + label="PocketLab; f000aa2a-0452-4000-b000-000000000000"/> <int value="869059214" label="next_dst_change"/> <int value="869682406" label="fe60"/> <int value="876407493" label="location_and_navigation"/> @@ -18083,7 +19867,11 @@ <int value="963656436" label="fe77"/> <int value="978815669" label="CoolBeans Serial; a495ff10-c5b1-4b44-b512-1370f02d74de"/> + <int value="988476177" + label="PocketLab 1; f000aa50-0451-4000-b000-000000000000"/> <int value="1001310815" label="fe75"/> + <int value="1018346218" + label="PocketLab; f000aa03-0452-4000-b000-000000000000"/> <int value="1024550252" label="feda"/> <int value="1029767622" label="internet_protocol_support"/> <int value="1035129135" label="fe74"/> @@ -18099,6 +19887,8 @@ <int value="1088150526" label="feb2"/> <int value="1091337779" label="fefb"/> <int value="1096286291" label="fed6"/> + <int value="1097514018" + label="PocketLab; f000aa06-0452-4000-b000-000000000000"/> <int value="1102290958" label="fe56"/> <int value="1103440256" label="fee9"/> <int value="1107293675" label="cycling_speed_and_cadence"/> @@ -18108,6 +19898,8 @@ <int value="1122138707" label="fed2"/> <int value="1122276223" label="fe67"/> <int value="1122861451" label="Playbulb Candle; ff02"/> + <int value="1125757823" + label="PocketLab; f000aa33-0452-4000-b000-000000000000"/> <int value="1132318862" label="fe6a"/> <int value="1133574029" label="fede"/> <int value="1134418737" label="fed9"/> @@ -18118,6 +19910,8 @@ <int value="1188875912" label="phone_alert_status"/> <int value="1204532270" label="fea1"/> <int value="1205730714" label="fe81"/> + <int value="1211834643" + label="PocketLab; f000aa02-0452-4000-b000-000000000000"/> <int value="1213218283" label="feb7"/> <int value="1219993345" label="device_information"/> <int value="1225001939" label="fe6c"/> @@ -18126,6 +19920,8 @@ <int value="1239202871" label="generic_attribute"/> <int value="1244946418" label="fe61"/> <int value="1250531601" label="fe15"/> + <int value="1254514264" + label="PocketLab; f000aa05-0452-4000-b000-000000000000"/> <int value="1257014053" label="fe33"/> <int value="1262008705" label="fef2"/> <int value="1265172773" label="indoor_positioning"/> @@ -18149,9 +19945,13 @@ label="Physical Web Light Switch; ba42561b-b1d2-440a-8d04-0cefb43faece"/> <int value="1362860533" label="fe9a"/> <int value="1366014117" label="fe2c"/> + <int value="1366194038" + label="PocketLab; f000aa22-0452-4000-b000-000000000000"/> <int value="1369789354" label="current_time"/> <int value="1376579922" label="fef0"/> <int value="1377872916" label="fe51"/> + <int value="1378697826" + label="PocketLab; f000aa2f-0452-4000-b000-000000000000"/> <int value="1380007534" label="fe96"/> <int value="1382767841" label="fe93"/> <int value="1394327958" label="fe24"/> @@ -18161,10 +19961,18 @@ <int value="1416866355" label="fe3b"/> <int value="1422100109" label="Sphero Robot; 22bb746f-2ba0-7554-2d6f-726568705327"/> + <int value="1423142122" + label="PocketLab; f000aa01-0452-4000-b000-000000000000"/> <int value="1424865940" label="alert_notification"/> <int value="1432421356" label="fe14"/> <int value="1433847022" label="fefa"/> + <int value="1451886110" + label="PocketLab; f000aa38-0452-4000-b000-000000000000"/> + <int value="1463907405" + label="PocketLab; f000aa2b-0452-4000-b000-000000000000"/> <int value="1465794357" label="feb0"/> + <int value="1477417345" + label="PocketLab; f000aa23-0452-4000-b000-000000000000"/> <int value="1482395712" label="Bleno Pizza Example; 13333333-3333-3333-3333-333333333337"/> <int value="1484296385" label="fe30"/> @@ -18176,17 +19984,23 @@ <int value="1548928839" label="fec5"/> <int value="1549672811" label="nRF candy machine; b6c31337-6c07-453e-961a-d8a8a41bf368"/> + <int value="1551090056" + label="PocketLab; f000aa35-0452-4000-b000-000000000000"/> <int value="1553614739" label="fe6b"/> <int value="1563543855" label="fe72"/> <int value="1569655226" label="generic_access"/> <int value="1573199922" label="fe71"/> <int value="1578535968" label="Makeblock mBot; 0000ffe1-0000-1000-8000-00805f9b34fb"/> + <int value="1588237112" + label="PocketLab; f000aa3f-0452-4000-b000-000000000000"/> <int value="1594426590" label="fe4e"/> <int value="1600490722" label="fe46"/> <int value="1604724337" label="fe88"/> <int value="1606985074" label="feed"/> <int value="1607594729" label="fe0f"/> + <int value="1611458228" + label="PocketLab; f000aa34-0452-4000-b000-000000000000"/> <int value="1618872680" label="fe9b"/> <int value="1631386264" label="fefd"/> <int value="1635890706" label="fe9e"/> @@ -18195,6 +20009,8 @@ <int value="1648320092" label="fe7f"/> <int value="1651126525" label="fe25"/> <int value="1651610232" label="fe52"/> + <int value="1655806770" + label="PocketLab Voyager; f000aa11-0452-4000-b000-000000000000"/> <int value="1660904097" label="immediate_alert"/> <int value="1663141542" label="battery_service"/> <int value="1671670551" label="fe5a"/> @@ -18212,6 +20028,8 @@ <int value="1712085581" label="MiP Robot; Magic Blue Bulb; 0000ffe5-0000-1000-8000-00805f9b34fb"/> <int value="1714031075" label="fe10"/> + <int value="1719495127" + label="PocketLab; f000aa00-0452-4000-b000-000000000000"/> <int value="1724509641" label="fe8b"/> <int value="1729966097" label="Anki OVERDRIVE cars; be15beef-6186-407e-8381-0bd89c4d8df4"/> @@ -18234,6 +20052,10 @@ <int value="1852765173" label="1852765173 (Unknown; not a 16bit UUID)"/> <int value="1855849484" label="iHealth Edge; 636f6d2e-6a69-7561-6e2e-414d56313100"/> + <int value="1866335371" + label="PocketLab; f000aa36-0452-4000-b000-000000000000"/> + <int value="1873367042" + label="PocketLab; f000aa3c-0452-4000-b000-000000000000"/> <int value="1891274929" label="fee2"/> <int value="1891804450" label="fe58"/> <int value="1905398969" label="fee6"/> @@ -18242,23 +20064,33 @@ <int value="1922152740" label="fe8a"/> <int value="1922853101" label="fe28"/> <int value="1925022679" label="fe57"/> + <int value="1934342765" + label="PocketLab; f000aa30-0452-4000-b000-000000000000"/> <int value="1940012814" label="fe2a"/> <int value="1942373991" label="Eddystone-URL Beacon Configuration v2; a3c87500-8ed3-4bdf-8a39-a01bebede295"/> + <int value="1945497075" + label="PocketLab; f000aa24-0452-4000-b000-000000000000"/> <int value="1946977319" label="fec1"/> <int value="1953707948" label="fe9f"/> <int value="1960388103" label="fecb"/> <int value="1969478137" label="fe63"/> <int value="1970234661" label="reference_time_update"/> <int value="1971997463" label="fe07"/> + <int value="1974805193" + label="PocketLab; f000aa26-0452-4000-b000-000000000000"/> <int value="1976176123" label="fe4c"/> <int value="1983035069" label="fec9"/> <int value="1984351068" label="fea6"/> + <int value="2010559917" + label="PocketLab; f000aa2e-0452-4000-b000-000000000000"/> <int value="2016025023" label="febd"/> <int value="2017827114" label="fe4f"/> <int value="2018026941" label="konashi; 229bff00-03fb-40da-98a7-b0def65c2d4b"/> + <int value="2020665772" + label="PocketLab; f000aa3e-0452-4000-b000-000000000000"/> <int value="2021054861" label="Tacx trainer; 6e40fec1-b5a3-f393-e0a9-e50e24dcca9e"/> <int value="2022676622" label="fe35"/> @@ -18266,13 +20098,23 @@ <int value="2055825405" label="fedc"/> <int value="2058080782" label="fecc"/> <int value="2061595680" label="fea5"/> + <int value="2066621778" + label="PocketLab; f000aa37-0452-4000-b000-000000000000"/> <int value="2069612985" label="fee5"/> <int value="2070392722" label="fec2"/> <int value="2075745564" label="heart_rate"/> + <int value="2081202638" + label="PocketLab 1; f000aa60-0451-4000-b000-000000000000"/> <int value="2081534039" label="fe83"/> <int value="2086529225" label="tx_power"/> + <int value="2093050338" + label="PocketLab; f000aa08-0452-4000-b000-000000000000"/> + <int value="2095670709" + label="PocketLab Voyager; f000aa31-0452-4000-b000-000000000000"/> <int value="2097896377" label="fee8"/> <int value="2100033855" label="fef7"/> + <int value="2103247472" + label="PocketLab; f000aa09-0452-4000-b000-000000000000"/> <int value="2107223399" label="fee7"/> <int value="2108894990" label="fe2f"/> <int value="2110412550" label="fe43"/> @@ -18389,6 +20231,13 @@ <int value="1" label="ERROR_SECURITY_EXCEPTION"/> </enum> +<enum name="GCMRegistrationCacheStatus"> + <int value="0" label="Registration not found"/> + <int value="1" label="Registration found; Token fresh"/> + <int value="2" label="Registration found; Token stale"/> + <int value="3" label="Registration found but senders don't match"/> +</enum> + <enum name="GCMRegistrationRequestStatus"> <int value="0" label="Success (this is not logged currently)"/> <int value="1" label="Invalid parameters"/> @@ -18476,6 +20325,12 @@ <int value="32770" label="PDF"/> </enum> +<enum name="GeolocationAuthorizationAction"> + <int value="0" label="Location authorized"/> + <int value="1" label="Location permanently denied (Don't Allow)"/> + <int value="2" label="Location denied at this prompt (Not Now)"/> +</enum> + <enum name="GeolocationDisclosureResult"> <int value="0" label="Ignored"/> <int value="1" label="Settings clicked"/> @@ -18538,6 +20393,17 @@ <int value="44" label="Not using HTTPS"/> </enum> +<enum name="GeolocationHeaderSentOrNot"> + <int value="0" label="Location disabled for Google domain"/> + <int value="1" label="Location preference not set for Google domain"/> + <int value="2" label="Location not available"/> + <int value="3" label="Location stale"/> + <int value="4" label="Header sent"/> + <int value="5" label="Location disabled for Chrome app"/> + <int value="6" label="iOS: Location disabled for Omnibox query"/> + <int value="7" label="Google domain does not accept locations"/> +</enum> + <enum name="GeolocationInfoBarDelegateAndroidEvent"> <obsolete> Deprecated 9/2014, and replaced by PermissionAction. @@ -18963,7 +20829,8 @@ </enum> <enum name="GpuDriverBugWorkaroundEntry"> -<!-- Generated from gpu/config/gpu_driver_bug_list.json --> +<!-- Generated from gpu/config/gpu_driver_bug_list.json. +Called by update_gpu_driver_bug_workaround_entries.py.--> <int value="0" label="0: Recorded once every time this histogram is updated."/> @@ -19257,8 +21124,7 @@ overflow"/> <int value="170" label="170: Zero copy DXGI video hangs on shutdown on Win < 8.1"/> - <int value="172" - label="172: Limited enabling of Chromium GL_INTEL_framebuffer_CMAA"/> + <int value="172" label="172: Use GL_INTEL_framebuffer_CMAA on ChromeOS"/> <int value="174" label="174: Adreno 4xx support for EXT_multisampled_render_to_texture is buggy on Android 7.0"/> @@ -19371,6 +21237,9 @@ label="216: Pack parameters work incorrectly with pack buffer bound"/> <int value="217" label="217: Alignment works incorrectly with unpack buffer bound"/> + <int value="218" + label="218: Certain Adreno 4xx and 5xx drivers often crash in + glProgramBinary."/> <int value="219" label="219: Zero-copy DXGI video hangs or displays incorrect colors on AMD drivers"/> @@ -19385,9 +21254,58 @@ <int value="223" label="223: Force integer or srgb cube map texture complete on Linux AMD"/> + <int value="224" + label="224: VPx decoding isn't supported well before Windows 10 + creators update."/> + <int value="225" + label="225: VPx decoding is too slow on Intel Broadwell, Skylake, and + CherryView"/> + <int value="226" + label="226: Accelerated VPx decoding is hanging on some videos."/> + <int value="227" label="227: Certain Apple devices leak stencil buffers"/> + <int value="228" label="228: Intel HD 3000 driver crashes frequently on Mac"/> + <int value="229" + label="229: Overlay sizes bigger than screen aren't accelerated on some + Intel drivers"/> + <int value="231" + label="231: Multisampled color renderbuffers can't be resized on + Qualcomm 4xx/5xx"/> + <int value="232" + label="232: Delayed copy NV12 crashes on Intel on Windows <= 8.1."/> + <int value="233" + label="233: Delayed copy NV12 displays incorrect colors on NVIDIA + drivers."/> + <int value="234" + label="234: Avoid using EGL_IMAGE_EXTERNAL_FLUSH_EXT with + eglCreateImageKHR on NVIDIA"/> + <int value="235" + label="235: Avoid waiting on a egl fence before pageflipping and rely + on implicit sync."/> + <int value="236" + label="236: glClearColor does not always work on Intel 6xxx Mac drivers"/> + <int value="237" + label="237: eglSwapBuffers intermittently fails on Android when app + goes to background"/> + <int value="239" + label="239: Reset TexImage2D base level to 0 on Intel Mac 10.12.4"/> + <int value="240" + label="240: glGetQueryObject(GL_QUERY_RESULT_AVAILABLE) blocks + unexpectedly on Adreno"/> + <int value="241" + label="241: On Intel GPUs MSAA performance is not acceptable for GPU + rasterization. Duplicate of 132 for Android"/> + <int value="242" + label="242: Code produced by local variable initialization often + triggers crashes in Marshmallow Adreno driver"/> + <int value="243" + label="243: Program binaries don't contain transform feedback varyings + on Mali GPUs"/> + <int value="244" + label="244: Rendering to IOSurfaces via OpenGL is broken on NVIDIA GPUs + on High Sierra"/> </enum> -<enum name="GpuImageDecodeState"> +<enum name="GpuImageUsageState"> <int value="0" label="Wasted, once"/> <int value="1" label="Used, once"/> <int value="2" label="Wasted, relocked"/> @@ -19587,47 +21505,73 @@ </enum> <enum name="HistogramNameHash"> + <summary> + These numbers are the lower 32 bits of the hash of the metric name. + </summary> <int value="-2055973512" label="Login.ConsumerNewUsersAllowed"/> + <int value="-2048378466" label="Sqlite.Vfs_Events"/> <int value="-2021219906" label="DataUse.MessageSize.AllServices.Downstream.Foreground.NotCellular"/> + <int value="-1724216561" + label="Extensions.Functions.SucceededTime.LessThan1ms"/> <int value="-1620411628" label="DataUse.MessageSize.AllServices.Downstream.Unknown.NotCellular"/> <int value="-1607339868" label="DataUse.MessageSize.AllServices.Upstream.Unknown.NotCellular"/> + <int value="-1459119846" + label="ServiceWorkerCache.Cache.Scheduler.QueueLength"/> <int value="-1390672863" label="DataUse.MessageSize.AllServices.Upstream.Background.NotCellular"/> + <int value="-1345388508" label="Renderer4.IdealContentsScale"/> + <int value="-1321341911" + label="DataUse.BackgroundToDataRecievedPerByte.User"/> <int value="-1286300074" label="Network.Shill.Wifi.ExpiredLeaseLengthSeconds"/> + <int value="-1189959109" label="RendererScheduler.TaskCountPerQueueType"/> + <int value="-983723378" label="RendererScheduler.TaskDurationPerThreadType"/> + <int value="-968816650" + label="PasswordManager.Android.PasswordExceptionEntry.Website"/> <int value="-847447887" label="DataUse.MessageSize.AllServices.Upstream.Foreground.NotCellular"/> - <summary> - These numbers are the lower 32 bits of the hash of the metric name. - </summary> <int value="-742109866" label="Stability.BrowserExitCodes"/> <int value="-657514887" label="DataUse.MessageSize.AllServices"/> <int value="-535820174" label="DataUse.MessageSize.AllServices.Downstream.Background.NotCellular"/> <int value="-355731177" label="UMA.SamplingRatePerMille"/> <int value="-141990989" label="DataUse.AllServices.Background"/> + <int value="-132932440" label="DataUse.ContentType.Services"/> + <int value="-48200749" label="DiskCache.0.TotalIOTime"/> <int value="0" label="Missing hash value"/> + <int value="61486329" label="RendererScheduler.TaskCountPerFrameType"/> + <int value="76333534" label="WorkerThread.Task.Time"/> <int value="149985012" label="DataUse.MessageSize.AllServices.Upstream.Unknown.Cellular"/> <int value="192918458" label="DataUse.MessageSize.AllServices.Downstream.Unknown.Cellular"/> <int value="424952287" label="Network.Shill.Wifi.LinkMonitorResponseTimeSample"/> + <int value="433324211" label="Extensions.FunctionCalls"/> <int value="628921860" label="Network.Shill.Ethernet.LinkMonitorResponseTimeSample"/> <int value="662206917" label="Network.Shill.Ethernet.ExpiredLeaseLengthSeconds"/> + <int value="705114606" + label="PasswordManager.Android.PasswordCredentialEntry.Website"/> <int value="757405826" label="DataUse.MessageSize.AllServices.Upstream.Foreground.Cellular"/> + <int value="761823979" label="Crashpad.HandlerLifetimeMilestone"/> + <int value="1264664660" label="DataUse.PageTransition.UserTraffic"/> <int value="1370064090" label="DataUse.MessageSize.AllServices.Upstream.Background.Cellular"/> + <int value="1514844119" label="DataUse.Sync.Upload.Bytes"/> + <int value="1525608243" + label="PasswordManager.Android.PasswordCredentialEntry.Username"/> <int value="1753226325" label="DataUse.MessageSize.AllServices.Downstream.Foreground.Cellular"/> + <int value="1864392953" label="AsyncDNS.HostsNotifyInterval"/> <int value="1977321258" label="DataUse.MessageSize.AllServices.Downstream.Background.Cellular"/> + <int value="2147480259" label="Sqlite.Vfs_Fetch"/> </enum> <enum name="HistoryFaviconsRecoveryEnum"> @@ -19779,6 +21723,12 @@ </int> </enum> +<enum name="HistoryUrlType"> + <int value="0" label="Empty"/> + <int value="1" label="Same as baseUrl"/> + <int value="2" label="Different from baseUrl"/> +</enum> + <enum name="HomedirEncryptionType"> <int value="1" label="Ecryptfs"/> <int value="2" label="Ext4 Dir Encryption"/> @@ -19899,11 +21849,36 @@ <int value="-2005270485" label="DXGI_ERROR_ACCESS_DENIED"/> <int value="-2005270484" label="DXGI_ERROR_NAME_ALREADY_EXISTS"/> <int value="-2005270483" label="DXGI_ERROR_SDK_COMPONENT_MISSING"/> + <int value="-2004287487" label="AUDCLNT_E_NOT_INITIALIZED"/> + <int value="-2004287486" label="AUDCLNT_E_ALREADY_INITIALIZED"/> + <int value="-2004287485" label="AUDCLNT_E_WRONG_ENDPOINT_TYPE"/> + <int value="-2004287484" label="AUDCLNT_E_DEVICE_INVALIDATED"/> + <int value="-2004287483" label="AUDCLNT_E_NOT_STOPPED"/> + <int value="-2004287482" label="AUDCLNT_E_BUFFER_TOO_LARGE"/> + <int value="-2004287481" label="AUDCLNT_E_OUT_OF_ORDER"/> <int value="-2004287480" label="AUDCLNT_E_UNSUPPORTED_FORMAT"/> + <int value="-2004287479" label="AUDCLNT_E_INVALID_SIZE"/> <int value="-2004287478" label="AUDCLNT_E_DEVICE_IN_USE"/> + <int value="-2004287477" label="AUDCLNT_E_BUFFER_OPERATION_PENDING"/> + <int value="-2004287476" label="AUDCLNT_E_THREAD_NOT_REGISTERED"/> + <int value="-2004287474" label="AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED"/> + <int value="-2004287473" label="AUDCLNT_E_ENDPOINT_CREATE_FAILED"/> + <int value="-2004287472" label="AUDCLNT_E_SERVICE_NOT_RUNNING"/> + <int value="-2004287471" label="AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED"/> + <int value="-2004287470" label="AUDCLNT_E_EXCLUSIVE_MODE_ONLY"/> + <int value="-2004287469" label="AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL"/> + <int value="-2004287468" label="AUDCLNT_E_EVENTHANDLE_NOT_SET"/> + <int value="-2004287467" label="AUDCLNT_E_INCORRECT_BUFFER_SIZE"/> + <int value="-2004287466" label="AUDCLNT_E_BUFFER_SIZE_ERROR"/> <int value="-2004287465" label="AUDCLNT_E_CPUUSAGE_EXCEEDED"/> + <int value="-2004287464" label="AUDCLNT_E_BUFFER_ERROR"/> + <int value="-2004287463" label="AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED"/> + <int value="-2004287456" label="AUDCLNT_E_INVALID_DEVICE_PERIOD"/> <int value="-1606219753" label="GOOPDATE_E_NON_BLOCKING_CALL_PENDING"/> <int value="-1606219747" label="GOOPDATE_E_APP_USING_EXTERNAL_UPDATER"/> + <int value="143196161" label="AUDCLNT_S_BUFFER_EMPTY"/> + <int value="143196162" label="AUDCLNT_S_THREAD_ALREADY_REGISTERED"/> + <int value="143196163" label="AUDCLNT_S_POSITION_STALLED"/> </enum> <enum name="HttpAuthCount"> @@ -19958,6 +21933,16 @@ <int value="15" label="Negotiate Secure Server"/> </enum> +<enum name="HttpCacheParallelWritingPattern"> + <int value="0" label="Initial value, headers phase"/> + <int value="1" label="Created Writers"/> + <int value="2" label="Joined Writers"/> + <int value="3" label="Not joined, range request"/> + <int value="4" label="Not joined, not GET"/> + <int value="5" label="Not joined, read-only"/> + <int value="6" label="Cache read, no Writers"/> +</enum> + <enum name="HttpCachePattern"> <int value="0" label="Undefined"/> <int value="1" label="Not Covered"/> @@ -20149,6 +22134,7 @@ label="Converged to an insufficiently accurate approximation of transfer function"/> <int value="9" label="Extracted an sRGB profile directly"/> + <int value="10" label="No profile specified"/> </enum> <enum name="IceCandidatePairTypes"> @@ -20228,6 +22214,9 @@ <int value="2" label="InternalsPage"> A forced close was requested from the indexeddb-internals page. </int> + <int value="3" label="CopyOrigin"> + The database is force closed so that it can be copied. + </int> </enum> <enum name="IDBException"> @@ -20557,73 +22546,81 @@ <int value="4" label="Open()"/> </enum> +<enum name="InfoBarClosingStates"> + <int value="0" label="Accepted survey"/> + <int value="1" label="Tapped close button"/> + <int value="2" label="Indirectly closed while visible"/> + <int value="3" label="Indirectly closed while hidden"/> +</enum> + <enum name="InfoBarIdentifier"> - <int value="-1" label="INVALID"/> - <int value="0" label="TEST_INFOBAR"/> - <int value="1" label="APP_BANNER_INFOBAR_DELEGATE_ANDROID"/> - <int value="2" label="APP_BANNER_INFOBAR_DELEGATE_DESKTOP"/> - <int value="3" label="ANDROID_DOWNLOAD_MANAGER_OVERWRITE_INFOBAR_DELEGATE"/> - <int value="4" label="CHROME_DOWNLOAD_MANAGER_OVERWRITE_INFOBAR_DELEGATE"/> - <int value="5" label="DOWNLOAD_REQUEST_INFOBAR_DELEGATE_ANDROID"/> - <int value="6" label="FULLSCREEN_INFOBAR_DELEGATE"/> + <int value="1" label="APP_BANNER_INFOBAR_DELEGATE"/> + <int value="2" label="APP_BANNER_INFOBAR_DELEGATE_DESKTOP (Obsolete)"/> + <int value="3" + label="ANDROID_DOWNLOAD_MANAGER_OVERWRITE_INFOBAR_DELEGATE (Obsolete)"/> + <int value="4" label="DUPLICATE_DOWNLOAD_INFOBAR_DELEGATE_ANDROID"/> + <int value="5" label="DOWNLOAD_REQUEST_INFOBAR_DELEGATE_ANDROID (Obsolete)"/> + <int value="6" label="FULLSCREEN_INFOBAR_DELEGATE (Obsolete)"/> <int value="7" label="HUNG_PLUGIN_INFOBAR_DELEGATE"/> - <int value="8" label="HUNG_RENDERER_INFOBAR_DELEGATE"/> - <int value="9" label="MEDIA_STREAM_INFOBAR_DELEGATE_ANDROID"/> - <int value="10" label="MEDIA_THROTTLE_INFOBAR_DELEGATE"/> - <int value="11" label="REQUEST_QUOTA_INFOBAR_DELEGATE"/> - <int value="12" label="DEV_TOOLS_CONFIRM_INFOBAR_DELEGATE"/> + <int value="8" label="HUNG_RENDERER_INFOBAR_DELEGATE_ANDROID"/> + <int value="9" label="MEDIA_STREAM_INFOBAR_DELEGATE_ANDROID (Obsolete)"/> + <int value="10" label="MEDIA_THROTTLE_INFOBAR_DELEGATE (Obsolete)"/> + <int value="11" label="REQUEST_QUOTA_INFOBAR_DELEGATE (Obsolete)"/> + <int value="12" label="DEV_TOOLS_INFOBAR_DELEGATE"/> <int value="13" label="EXTENSION_DEV_TOOLS_INFOBAR_DELEGATE"/> <int value="14" label="INCOGNITO_CONNECTABILITY_INFOBAR_DELEGATE"/> <int value="15" label="THEME_INSTALLED_INFOBAR_DELEGATE"/> - <int value="16" label="GEOLOCATION_INFOBAR_DELEGATE_ANDROID"/> + <int value="16" label="GEOLOCATION_INFOBAR_DELEGATE_ANDROID (Obsolete)"/> <int value="17" label="THREE_D_API_INFOBAR_DELEGATE"/> - <int value="18" label="INSECURE_CONTENT_INFOBAR_DELEGATE"/> - <int value="19" label="MIDI_PERMISSION_INFOBAR_DELEGATE_ANDROID"/> - <int value="20" label="PROTECTED_MEDIA_IDENTIFIER_INFOBAR_DELEGATE_ANDROID"/> + <int value="18" label="INSECURE_CONTENT_INFOBAR_DELEGATE (Obsolete)"/> + <int value="19" label="MIDI_PERMISSION_INFOBAR_DELEGATE_ANDROID (Obsolete)"/> + <int value="20" + label="PROTECTED_MEDIA_IDENTIFIER_INFOBAR_DELEGATE_ANDROID (Obsolete)"/> <int value="21" label="NACL_INFOBAR_DELEGATE"/> <int value="22" - label="OBSOLETE_DATA_REDUCTION_PROXY_INFOBAR_DELEGATE_ANDROID"/> - <int value="23" label="NOTIFICATION_PERMISSION_INFOBAR_DELEGATE"/> - <int value="24" label="AUTO_SIGNIN_FIRST_RUN_INFOBAR_DELEGATE"/> + label="DATA_REDUCTION_PROXY_INFOBAR_DELEGATE_ANDROID (Obsolete)"/> + <int value="23" label="NOTIFICATION_PERMISSION_INFOBAR_DELEGATE (Obsolete)"/> + <int value="24" label="AUTO_SIGNIN_FIRST_RUN_INFOBAR_DELEGATE (Obsolete)"/> <int value="25" label="GENERATED_PASSWORD_SAVED_INFOBAR_DELEGATE_ANDROID"/> - <int value="26" label="SAVE_PASSWORD_INFOBAR_DELEGATE"/> + <int value="26" label="SAVE_PASSWORD_INFOBAR_DELEGATE_MOBILE"/> <int value="27" label="PEPPER_BROKER_INFOBAR_DELEGATE"/> - <int value="28" label="PERMISSION_UPDATE_INFOBAR_DELEGATE"/> - <int value="29" label="DURABLE_STORAGE_PERMISSION_INFOBAR_DELEGATE_ANDROID"/> - <int value="30" label="NPAPI_REMOVAL_INFOBAR_DELEGATE"/> + <int value="28" label="PERMISSION_UPDATE_INFOBAR_DELEGATE_ANDROID"/> + <int value="29" + label="DURABLE_STORAGE_PERMISSION_INFOBAR_DELEGATE_ANDROID (Obsolete)"/> + <int value="30" label="NPAPI_REMOVAL_INFOBAR_DELEGATE (Obsolete)"/> <int value="31" label="OUTDATED_PLUGIN_INFOBAR_DELEGATE"/> - <int value="32" label="PLUGIN_METRO_MODE_INFOBAR_DELEGATE"/> + <int value="32" label="PLUGIN_METRO_MODE_INFOBAR_DELEGATE (Obsolete)"/> <int value="33" label="RELOAD_PLUGIN_INFOBAR_DELEGATE"/> - <int value="34" label="PLUGIN_OBSERVER"/> - <int value="35" label="SSL_ADD_CERTIFICATE"/> - <int value="36" label="SSL_ADD_CERTIFICATE_INFOBAR_DELEGATE"/> - <int value="37" label="POPUP_BLOCKED_INFOBAR_DELEGATE"/> - <int value="38" label="CHROME_SELECT_FILE_POLICY"/> - <int value="39" label="KEYSTONE_PROMOTION_INFOBAR_DELEGATE"/> + <int value="34" label="PLUGIN_OBSERVER_INFOBAR_DELEGATE"/> + <int value="35" label="SSL_ADD_CERTIFICATE (Obsolete)"/> + <int value="36" label="SSL_ADD_CERTIFICATE_INFOBAR_DELEGATE (Obsolete)"/> + <int value="37" label="POPUP_BLOCKED_INFOBAR_DELEGATE_MOBILE"/> + <int value="38" label="FILE_ACCESS_DISABLED_INFOBAR_DELEGATE"/> + <int value="39" label="KEYSTONE_PROMOTION_INFOBAR_DELEGATE_MAC"/> <int value="40" label="COLLECTED_COOKIES_INFOBAR_DELEGATE"/> <int value="41" label="INSTALLATION_ERROR_INFOBAR_DELEGATE"/> <int value="42" label="ALTERNATE_NAV_INFOBAR_DELEGATE"/> - <int value="43" label="BAD_FLAGS_PROMPT"/> + <int value="43" label="BAD_FLAGS_INFOBAR_DELEGATE"/> <int value="44" label="DEFAULT_BROWSER_INFOBAR_DELEGATE"/> <int value="45" label="GOOGLE_API_KEYS_INFOBAR_DELEGATE"/> <int value="46" label="OBSOLETE_SYSTEM_INFOBAR_DELEGATE"/> - <int value="47" label="SESSION_CRASHED_INFOBAR_DELEGATE"/> + <int value="47" label="SESSION_CRASHED_INFOBAR_DELEGATE_MAC_IOS"/> <int value="48" label="PAGE_INFO_INFOBAR_DELEGATE"/> - <int value="49" label="AUTOFILL_CC_INFOBAR_DELEGATE"/> - <int value="50" label="TRANSLATE_INFOBAR_DELEGATE"/> - <int value="51" label="IOS_CHROME_SAVE_PASSWORD_INFOBAR_DELEGATE"/> - <int value="52" label="NATIVE_APP_INSTALLER_INFOBAR_DELEGATE"/> - <int value="53" label="NATIVE_APP_LAUNCHER_INFOBAR_DELEGATE"/> - <int value="54" label="NATIVE_APP_OPEN_POLICY_INFOBAR_DELEGATE"/> - <int value="55" label="RE_SIGN_IN_INFOBAR_DELEGATE"/> - <int value="56" label="SHOW_PASSKIT_ERROR_INFOBAR_DELEGATE"/> - <int value="57" label="READER_MODE_INFOBAR_DELEGATE"/> - <int value="58" label="SYNC_ERROR_INFOBAR_DELEGATE"/> + <int value="49" label="AUTOFILL_CC_INFOBAR_DELEGATE_MOBILE"/> + <int value="50" label="TRANSLATE_INFOBAR_DELEGATE_NON_AURA"/> + <int value="51" label="IOS_CHROME_SAVE_PASSWORD_INFOBAR_DELEGATE (Obsolete)"/> + <int value="52" label="NATIVE_APP_INSTALLER_INFOBAR_DELEGATE (Obsolete)"/> + <int value="53" label="NATIVE_APP_LAUNCHER_INFOBAR_DELEGATE (Obsolete)"/> + <int value="54" label="NATIVE_APP_OPEN_POLICY_INFOBAR_DELEGATE (Obsolete)"/> + <int value="55" label="RE_SIGN_IN_INFOBAR_DELEGATE_IOS"/> + <int value="56" label="SHOW_PASSKIT_ERROR_INFOBAR_DELEGATE_IOS"/> + <int value="57" label="READER_MODE_INFOBAR_DELEGATE (Obsolete)"/> + <int value="58" label="SYNC_ERROR_INFOBAR_DELEGATE_IOS"/> <int value="59" label="UPGRADE_INFOBAR_DELEGATE"/> - <int value="60" label="CHROME_WINDOW_ERROR"/> - <int value="61" label="CONFIRM_DANGEROUS_DOWNLOAD"/> - <int value="62" label="WINDOWS_DESKTOP_SEARCH_INFOBAR_DELEGATE"/> - <int value="63" label="UPDATE_PASSWORD_INFOBAR_DELEGATE"/> + <int value="60" label="WINDOW_ERROR_INFOBAR_DELEGATE_ANDROID"/> + <int value="61" label="DANGEROUS_DOWNLOAD_INFOBAR_DELEGATE_ANDROID"/> + <int value="62" label="WINDOWS_DESKTOP_SEARCH_INFOBAR_DELEGATE (Obsolete)"/> + <int value="63" label="UPDATE_PASSWORD_INFOBAR_DELEGATE_MOBILE"/> <int value="64" label="DATA_REDUCTION_PROMO_INFOBAR_DELEGATE_ANDROID"/> <int value="65" label="AUTOFILL_CC_ASSIST_INFOBAR_DELEGATE"/> <int value="66" label="ADS_BLOCKED_INFOBAR_DELEGATE_ANDROID"/> @@ -20631,13 +22628,17 @@ <int value="68" label="DATA_REDUCTION_PROXY_PREVIEW_INFOBAR_DELEGATE"/> <int value="69" label="SCREEN_CAPTURE_INFOBAR_DELEGATE_ANDROID"/> <int value="70" label="GROUPED_PERMISSION_INFOBAR_DELEGATE_ANDROID"/> - <int value="71" label="OFFLINE_PAGE_INFOBAR_DELEGATE"/> - <int value="72" label="SEARCH_GEOLOCATION_DISCLOSURE_INFOBAR_DELEGATE"/> + <int value="71" label="OFFLINE_PAGE_INFOBAR_DELEGATE_ANDROID"/> + <int value="72" + label="SEARCH_GEOLOCATION_DISCLOSURE_INFOBAR_DELEGATE_ANDROID"/> <int value="73" label="AUTOMATION_INFOBAR_DELEGATE"/> <int value="74" label="VR_SERVICES_UPGRADE_ANDROID"/> <int value="75" label="READER_MODE_INFOBAR_ANDROID"/> <int value="76" label="VR_FEEDBACK_INFOBAR_ANDROID"/> <int value="77" label="FRAMEBUST_BLOCK_INFOBAR_ANDROID"/> + <int value="78" label="SURVEY_INFOBAR_ANDROID"/> + <int value="79" label="NEAR_OOM_INFOBAR_ANDROID"/> + <int value="80" label="PWA_AMBIENT_BADGE_INFOBAR_DELEGATE_ANDROID"/> </enum> <enum name="InfoBarResponse"> @@ -21226,10 +23227,26 @@ <int value="1" label="identical"/> </enum> +<enum name="InstantTethering_BluetoothAdvertisementResult"> + <int value="0" label="Success"/> + <int value="1" label="Error: Unsupported platform"/> + <int value="2" label="Error: Advertisement already exists"/> + <int value="3" label="Error: Advertisement does not exist"/> + <int value="4" label="Error: Advertisement invalid length"/> + <int value="5" label="Error: Invalid advertisement interval"/> + <int value="6" label="Error: Reset advertising"/> + <int value="7" label="Invalid advertisement error code"/> + <int value="8" label="Unknown result"/> +</enum> + <enum name="InstantTethering_ConnectionToHostResult_Failure"> <int value="0" label="Unknown error"/> <int value="1" label="Tethering timed out"/> <int value="2" label="Client connection error"/> + <int value="3" label="Tethering unsupported"/> + <int value="4" label="No cellular data"/> + <int value="5" label="Enabling hotspot failed"/> + <int value="6" label="Enabling hotspot timed out"/> </enum> <enum name="InstantTethering_ConnectionToHostResult_Failure_ClientConnection"> @@ -21254,9 +23271,9 @@ </enum> <enum name="InstantTethering_FeatureState"> - <int value="0" label="Other or unknown"/> + <int value="0" label="Shut down (deprecated)"/> <int value="1" label="BLE advertising not supported"/> - <int value="2" label="Screen locked"/> + <int value="2" label="Screen locked (deprecated)"/> <int value="3" label="No available hosts"/> <int value="4" label="Cellular disabled"/> <int value="5" label="Prohibited"/> @@ -21265,6 +23282,7 @@ <int value="8" label="Enabled"/> <int value="9" label="BLE not present"/> <int value="10" label="WiFi not present"/> + <int value="11" label="Suspended"/> </enum> <enum name="InstantTethering_HostScanResult"> @@ -21274,6 +23292,27 @@ <int value="3" label="Hosts found but no notification shown"/> </enum> +<enum name="InstantTethering_NotificationInteractionType"> + <int value="0" label="Notification body clicked: Single host nearby"/> + <int value="1" label="Notification body clicked: Multiple hosts nearby"/> + <int value="2" label="Notification body clicked: Setup required"/> + <int value="3" label="Notification body clicked: Connection failed"/> + <int value="4" label="Notification button clicked: Single host nearby"/> +</enum> + +<enum name="InstantTethering_SessionCompletionReason"> + <int value="0" label="Other"/> + <int value="1" label="User disconnected"/> + <int value="2" label="Connection dropped"/> + <int value="3" label="User logged out"/> + <int value="4" label="User closed lid"/> + <int value="5" label="Pref disabled"/> + <int value="6" label="Bluetooth disabled"/> + <int value="7" label="Cellular disabled"/> + <int value="8" label="Wi-Fi disabled"/> + <int value="9" label="Bluetooth controller disappeared"/> +</enum> + <enum name="IntelMaxMicroArchitecture"> <int value="0" label="Pentium"/> <int value="1" label="SSE"/> @@ -21346,6 +23385,12 @@ <int value="50" label="CRASH"/> </enum> +<enum name="InterstitialTypeEnum"> + <int value="0" label="Loud"/> + <int value="1" label="Quiet small"/> + <int value="2" label="Quiet giant"/> +</enum> + <enum name="InvalidationNetworkChannel"> <int value="0" label="PushClientChannel"/> <int value="1" label="GCMNetworkChannel"/> @@ -21357,11 +23402,40 @@ <int value="2" label="SubframeBlocked"/> </enum> +<enum name="IOSHandoffOrigin"> + <int value="0" label="Unknown Origin"/> + <int value="1" label="Chrome on iOS"/> + <int value="2" label="Chrome on Mac"/> +</enum> + +<enum name="IosLocationAuthorizationStatus"> + <int value="0" label="NotDetermined"/> + <int value="1" label="Restricted"/> + <int value="2" label="Denied"/> + <int value="3" label="Authorized"/> +</enum> + <enum name="IOSNTPImpression"> <int value="0" label="Local suggestions"/> <int value="1" label="Remote suggestions"/> </enum> +<enum name="IOSPageLoadCountNavigationType"> + <int value="0" label="Chrome URL Navigation"/> + <int value="1" label="Same Document Web Navigation"/> + <int value="2" label="Page Load Navigation"/> + <int value="3" label="Obsolete - Loading Started"/> +</enum> + +<enum name="IOSRepeatedExternalAppPromptResponse"> + <int value="0" label="Blocked"> + User selected to block the application for the current session. + </int> + <int value="1" label="Allowed"> + User selected to allow the application to run again. + </int> +</enum> + <enum name="IOSSearchExtensionAction"> <int value="0" label="No Action"/> <int value="1" label="New Search"/> @@ -21383,6 +23457,12 @@ <int value="3" label="Bookmark item"/> </enum> +<enum name="iOSSizeClassForReporting"> + <int value="0" label="Unspecified"/> + <int value="1" label="Compact"/> + <int value="2" label="Regular"/> +</enum> + <enum name="IOSSpotlightAction"> <int value="0" label="New Tab"/> <int value="1" label="New Incognito Tab"/> @@ -21390,6 +23470,19 @@ <int value="3" label="QR Code Scanner"/> </enum> +<enum name="IOSSpotlightAvailability"> + <int value="0" label="Unsupported"/> + <int value="1" label="Unavailable"/> + <int value="2" label="Available"/> +</enum> + +<enum name="IOSSpotlightOrigin"> + <int value="0" label="Unknown Origin"/> + <int value="1" label="Bookmark"/> + <int value="2" label="Top Sites"/> + <int value="3" label="Actions"/> +</enum> + <enum name="IPCAttachmentBrokerPrivilegedBrokerAttachmentError"> <int value="0" label="DESTINATION_FOUND"> The brokerable attachment had a valid destination. This is the success case. @@ -21523,6 +23616,10 @@ <int value="7" label="Tab navigated"> The user navigated the tab (e.g. back/forward, reload) </int> + <int value="8" label="Tab switched out"> + The page displaying the dialog was switched out of its tab (e.g. tab + discarding) + </int> </enum> <enum name="JumplisticonsDeleteCategory"> @@ -21943,6 +24040,12 @@ <int value="2" label="Keyboard was hidden by the user."/> </enum> +<enum name="KeyboardLockMethods"> + <int value="0" label="keyboardLock() requested for all keys"/> + <int value="1" label="keyboardLock() requested for a subset of keys"/> + <int value="2" label="keyboardUnlock()"/> +</enum> + <enum name="KeychainMigrationStatus"> <int value="0" label="Migration hasn't started"/> <int value="1" label="Migration succeeded"/> @@ -22507,6 +24610,23 @@ <int value="8026721" label="Zaza"/> </enum> +<enum name="LanguageSettingsActionType"> + <int value="0" label="Unknown"/> + <int value="1" label="Click on the 'Add Language' button"/> + <int value="2" label="Language added"/> + <int value="3" label="Language removed"/> + <int value="4" label="Disable global 'Offer to translate' by switch"/> + <int value="5" label="Enable global 'Offer to translate' by switch"/> + <int value="6" label="Disable 'Offer to translate' for single language"/> + <int value="7" label="Enable 'Offer to translate' for single language"/> + <int value="8" label="Language list reordered"/> +</enum> + +<enum name="LanguageSettingsPageType"> + <int value="0" label="Main"/> + <int value="1" label="Add Language"/> +</enum> + <enum name="LastSettingParsed"> <obsolete> Deprecated 2015-10-05 in Issue 433475. Histogram was used temorarily for @@ -22590,6 +24710,9 @@ <int value="9" label="External intent (WebAPK)"/> <int value="10" label="App banner (WebAPK)"/> <int value="11" label="Unknown (WebAPK)"/> + <int value="12" label="Trusted Web Activity"/> + <int value="13" label="WebShareTarget (WebAPK)"/> + <int value="14" label="External intent from Chrome (WebAPK)"/> </enum> <enum name="LaunchIntentFlags"> @@ -22625,6 +24748,30 @@ <int value="9" label="LM_USER_EXPERIMENT"> Launched from the installer as part of a retention experiment </int> + <int value="10" label="LM_OTHER_OS"> + Launch mode result bucket for OSes with no coverage + </int> + <int value="11" label="LM_MAC_UNDOCKED_DISK_LAUNCH"> + Mac - undocked launch from disk + </int> + <int value="12" label="LM_MAC_DOCKED_DISK_LAUNCH"> + Mac - docked launch from disk + </int> + <int value="13" label="LM_MAC_UNDOCKED_DMG_LAUNCH"> + Mac - undocked launch from a disk image + </int> + <int value="14" label="LM_MAC_DOCKED_DMG_LAUNCH"> + Mac - docked launch from a disk image + </int> + <int value="15" label="LM_MAC_DOCK_STATUS_ERROR"> + Mac - error determining Chrome's Dock status + </int> + <int value="16" label="LM_MAC_DMG_STATUS_ERROR"> + Mac - error determining Chrome's disk image status + </int> + <int value="17" label="LM_MAC_DOCK_DMG_STATUS_ERROR"> + Mac - error determining Chrome's Dock and disk image statuses + </int> </enum> <enum name="LazyCSSParseUsage"> @@ -22782,26 +24929,48 @@ <enum name="LinuxDistro"> <int value="0" label="Unknown"/> - <int value="1" label="Ubuntu Other"/> - <int value="2" label="Ubuntu 14.04"/> - <int value="3" label="Ubuntu 16.04"/> - <int value="4" label="Ubuntu 16.10"/> - <int value="5" label="Ubuntu 17.04"/> - <int value="6" label="Debian Other"/> - <int value="7" label="Debian 8"/> - <int value="8" label="openSUSE Other"/> - <int value="9" label="openSUSE Leap 42.2"/> - <int value="10" label="Fedora Other"/> - <int value="11" label="Fedora 24"/> - <int value="12" label="Fedora 25"/> - <int value="13" label="Fedora 26"/> - <int value="14" label="Debian 9"/> + <int value="1" label="(DEPRECATED) Ubuntu Other"/> + <int value="2" label="(DEPRECATED) Ubuntu 14.04"/> + <int value="3" label="(DEPRECATED) Ubuntu 16.04"/> + <int value="4" label="(DEPRECATED) Ubuntu 16.10"/> + <int value="5" label="(DEPRECATED) Ubuntu 17.04"/> + <int value="6" label="(DEPRECATED) Debian Other"/> + <int value="7" label="(DEPRECATED) Debian 8"/> + <int value="8" label="(DEPRECATED) openSUSE Other"/> + <int value="9" label="(DEPRECATED) openSUSE Leap 42.2"/> + <int value="10" label="(DEPRECATED) Fedora Other"/> + <int value="11" label="(DEPRECATED) Fedora 24"/> + <int value="12" label="(DEPRECATED) Fedora 25"/> + <int value="13" label="(DEPRECATED) Fedora 26"/> + <int value="14" label="(DEPRECATED) Debian 9"/> <int value="15" label="Arch"/> <int value="16" label="CentOS"/> <int value="17" label="elementary OS"/> <int value="18" label="Mint"/> <int value="19" label="RHEL"/> <int value="20" label="SUSE Linux Enterprise"/> + <int value="50" label="Debian Other"/> + <int value="51" label="Debian 8"/> + <int value="52" label="Debian 9"/> + <int value="53" label="Debian 10"/> + <int value="100" label="Fedora Other"/> + <int value="101" label="Fedora 24"/> + <int value="102" label="Fedora 25"/> + <int value="103" label="Fedora 26"/> + <int value="104" label="Fedora 27"/> + <int value="105" label="Fedora 28"/> + <int value="150" label="openSUSE Other"/> + <int value="151" label="openSUSE Leap 42.2"/> + <int value="152" label="openSUSE Leap 42.3"/> + <int value="153" label="openSUSE Leap 15"/> + <int value="200" label="Ubuntu Other"/> + <int value="201" label="Ubuntu 14.04"/> + <int value="202" label="Ubuntu 16.04"/> + <int value="203" label="Ubuntu 16.10"/> + <int value="204" label="Ubuntu 17.04"/> + <int value="205" label="Ubuntu 17.10"/> + <int value="206" label="Ubuntu 18.04"/> + <int value="207" label="Ubuntu 18.10"/> </enum> <enum name="LinuxGlibcVersion"> @@ -23000,6 +25169,13 @@ <int value="23" label="Unnamed"/> </enum> +<enum name="ListItemPosition"> + <int value="0" label="Only item"/> + <int value="1" label="First item"/> + <int value="2" label="Any middle item"/> + <int value="3" label="Last item"/> +</enum> + <enum name="LoadLibraryResultCategory"> <int value="0" label="LoadLibraryExW Succeeded"/> <int value="1" label="LoadLibraryExW Fail, LoadLibraryW Succeeded"/> @@ -23008,6 +25184,13 @@ <int value="4" label="LoadLibraryExW Unavailable, LoadLibraryW Fail"/> </enum> +<enum name="LoadRulesetResult"> + <int value="0" label="Load succeeded"/> + <int value="1" label="Load failed - Invalid path"/> + <int value="2" label="Load failed - File read error"/> + <int value="3" label="Load failed - Ruleset verification error"/> +</enum> + <enum name="LoadType"> <int value="0" label="UNDEFINED_LOAD">Not yet initialized</int> <int value="1" label="RELOAD">User pressed reload</int> @@ -23038,12 +25221,19 @@ <int value="4" label="Success"/> </enum> +<enum name="LocalStorageRendererAreaCacheHitEnum"> + <int value="0" label="Area was not present in cache"/> + <int value="1" label="Area with no references loaded from cache"/> + <int value="2" label="Area with references loaded"/> +</enum> + <enum name="LockScreenActionAvailability"> <int value="0" label="Available"/> <int value="1" label="Not available - no action handler app"/> <int value="2" label="Not available - app with no lock screen support"/> <int value="3" label="Not available - action not enabled on lock screen"/> <int value="4" label="Not available - disallowed by policy"/> + <int value="5" label="Not available (temporarily) - no lock screen profile"/> </enum> <enum name="LockScreenAppSessionState"> @@ -23055,6 +25245,12 @@ <int value="5" label="App window in background"/> </enum> +<enum name="LockScreenAppUnloadStatus"> + <int value="0" label="Unload reason other than termination"/> + <int value="1" label="Terminated, app reload can be attempted"/> + <int value="2" label="Terminated, number of reload attempts exceeded"/> +</enum> + <enum name="LockScreenDataItemOperationResult"> <int value="0" label="Success"/> <int value="1" label="Operation failed"/> @@ -23065,6 +25261,14 @@ <int value="6" label="Wrong encryption key"/> </enum> +<enum name="LockScreenNoteAppStatusOnLaunch"> + <int value="0" label="Enabled"/> + <int value="1" label="Terminated - reloaded"/> + <int value="2" label="Terminated - reload attempt failed"/> + <int value="3" label="Terminated - number of reload attempts exceeded"/> + <int value="4" label="Not loaded, not terminated"/> +</enum> + <enum name="LockScreenNoteTakingExitReason"> <int value="0" label="Session was unlocked"/> <int value="1" label="Session shutdown"/> @@ -23090,12 +25294,35 @@ <int value="4" label="Confirm pin"/> </enum> +<enum name="LockScreenUserClickTarget"> + <int value="0" label="Shut down button"/> + <int value="1" label="Restart button"/> + <int value="2" label="Sign out button"/> + <int value="3" label="Close note button"/> + <int value="4" label="System tray"/> + <int value="5" label="Virtual keyboard tray"/> + <int value="6" label="IME tray"/> + <int value="7" label="Notification tray"/> + <int value="8" label="Lock screen note action button"/> +</enum> + <enum name="LoginConsumerWhitelist"> <int value="0" label="ANY_USER_ALLOWED">Any user can sign in</int> <int value="1" label="ONLY_WHITELISTED_ALLOWED">Whitelisted users only</int> </enum> <enum name="LoginCustomFlags"> + <summary>Chrome flags that lead to Chrome restart on Chrome OS.</summary> +<!-- +Values in LoginCustomFlags are: value=(uint32_t)MD5(label). + +See "Flag Histograms" in README.md for information about how to update this +section. + +Don't remove entries when removing a flag; they are still used to decode data +from previous Chrome versions. +--> + <int value="-2146613579" label="V8Future:disabled"/> <int value="-2145472146" label="OfflinePagesResourceBasedSnapshot:disabled"/> <int value="-2143961262" label="D3DVsync:disabled"/> @@ -23107,6 +25334,8 @@ <int value="-2134333982" label="ShowArcFilesApp:enabled"/> <int value="-2134244069" label="HttpFormWarning:enabled"/> <int value="-2132591642" label="enable-input-view"/> + <int value="-2124839789" + label="OmniboxUIExperimentHideSteadyStateUrlSchemeAndSubdomains:enabled"/> <int value="-2122048316" label="DisplayPersistenceToggleInPermissionPrompts:enabled"/> <int value="-2119827860" label="ash-disable-maximize-mode-window-backdrop"/> @@ -23122,7 +25351,9 @@ <int value="-2097515669" label="disable-cast"/> <int value="-2091404586" label="TabStripKeyboardFocus:enabled"/> <int value="-2090484194" label="ContextualSearchUrlActions:disabled"/> + <int value="-2083998415" label="VrLaunchIntent:enabled"/> <int value="-2083195884" label="enable-firewall-hole-punching"/> + <int value="-2082462043" label="ViewPasswords:disabled"/> <int value="-2082042818" label="AutofillCreditCardLastUsedDateDisplay:enabled"/> <int value="-2077268643" label="disable-device-enumeration"/> @@ -23130,6 +25361,7 @@ <int value="-2075807193" label="enable-webusb-on-any-origin"/> <int value="-2075725205" label="disable-new-zip-unpacker"/> <int value="-2067166422" label="enable-slimming-paint-v2"/> + <int value="-2064164557" label="DownloadsForeground:disabled"/> <int value="-2063352474" label="enable-new-task-manager"/> <int value="-2063014275" label="enable-web-bluetooth"/> <int value="-2062872298" label="market-url-for-testing"/> @@ -23150,6 +25382,7 @@ <int value="-2036149591" label="FaviconsFromWebManifest:disabled"/> <int value="-2035126988" label="enabled-new-style-notification"/> <int value="-2033225430" label="NTPMostLikelyFaviconsFromServer:disabled"/> + <int value="-2030217301" label="password-export:disabled"/> <int value="-2029912304" label="StaleWhileRevalidate2:enabled"/> <int value="-2028232016" label="spurious-power-button-lid-angle-change"/> <int value="-2025367104" label="enable-material-design-ntp"/> @@ -23163,11 +25396,14 @@ <int value="-2005089558" label="BackgroundVideoTrackOptimization:disabled"/> <int value="-2003354337" label="enable-search-button-in-omnibox-for-str-or-iip"/> + <int value="-2000567059" label="SimplifyHttpsIndicator:enabled"/> <int value="-1999892428" label="force-ui-direction"/> <int value="-1998927516" label="enable-md-settings"/> <int value="-1989747818" label="TabStripKeyboardFocus:disabled"/> <int value="-1985025593" label="file-manager-enable-new-gallery"/> + <int value="-1983569861" label="WebXROrientationSensorDevice:disabled"/> <int value="-1980328793" label="trace-upload-url"/> + <int value="-1977496883" label="ViewPasswords:enabled"/> <int value="-1973722176" label="VoiceSearchOnLocalNtp:enabled"/> <int value="-1972383451" label="disable-pinch"/> <int value="-1972312724" label="OfflinePagesLoadSignalCollecting:enabled"/> @@ -23176,8 +25412,12 @@ <int value="-1964261747" label="WebVrVsyncAlign:disabled"/> <int value="-1963427770" label="EmojiHandwritingVoiceInput:disabled"/> <int value="-1963402827" label="enable-topchrome-md"/> + <int value="-1962588488" label="SpeculativePreconnect:disabled"/> <int value="-1961648833" label="show_summary"/> + <int value="-1961497025" label="tint-gl-composited-content"/> + <int value="-1961062505" label="VrBrowsingInCustomTab:disabled"/> <int value="-1960567385" label="KeepPrefetchedContentSuggestions:enabled"/> + <int value="-1957328398" label="MacSystemShareMenu:disabled"/> <int value="-1956349722" label="disable-smooth-scrolling"/> <int value="-1948540128" label="disable-webrtc-hw-encoding (deprecated)"/> <int value="-1946595906" label="enable-push-api-background-mode"/> @@ -23190,19 +25430,24 @@ <int value="-1940291343" label="SpeculativeResourcePrefetching:enabled"/> <int value="-1939016096" label="OmniboxUIExperimentHideSuggestionUrlTrivialSubdomains:enabled"/> + <int value="-1939003674" label="NetworkServiceInProcess:disabled"/> <int value="-1938263248" label="enable-extension-info-dialog"/> <int value="-1937077699" label="http-form-warning"/> <int value="-1933425042" label="OfflinePreviews:enabled"/> <int value="-1930720286" label="nacl-debug-mask"/> <int value="-1928198763" label="enable-async-dns"/> <int value="-1925117279" label="disable-quic-https"/> + <int value="-1916060206" label="enable-display-zoom-setting"/> <int value="-1915854488" label="enable-offline-pages"/> <int value="-1913801713" label="UploadCrashReportsUsingJobScheduler:disabled"/> <int value="-1912999136" label="enable-automatic-password-saving:enabled"/> + <int value="-1911316813" label="BlockTabUnders:disabled"/> <int value="-1911153473" label="enable-easy-signin"/> + <int value="-1909983714" label="ExperimentalTabController:disabled"/> <int value="-1909356390" label="OverlayScrollbarFlashAfterAnyScrollUpdate:enabled"/> + <int value="-1907565048" label="HtmlBaseUsernameDetector:disabled"/> <int value="-1907342706" label="ReadItLaterInMenu:disabled"/> <int value="-1892555086" label="disable-compositor-animation-timelines"/> <int value="-1892000374" label="SeccompSandboxAndroid:enabled"/> @@ -23210,17 +25455,18 @@ <int value="-1887862464" label="SpannableInlineAutocomplete:disabled"/> <int value="-1887053262" label="enable-zero-suggest-most-visited-without-serp"/> - <int value="-1884385890" label="AutofillUpstreamShowGoogleLogo:enabled"/> <int value="-1883170077" label="EnableHtmlBaseUsernameDetector:disabled"/> <int value="-1882330924" label="NTPArticleSuggestions:enabled"/> <int value="-1880355454" label="disable-topchrome-md"/> <int value="-1876881908" label="disable-infobar-for-protected-media-identifier"/> <int value="-1875383510" label="UseGoogleLocalNtp:disabled"/> + <int value="-1875168316" label="UseMonitorColorSpace:disabled"/> <int value="-1874908826" label="enable-instant-search-clicks"/> <int value="-1874141108" label="NewOmniboxAnswerTypes:enabled"/> <int value="-1872989945" label="enable-webview-based-signin"/> <int value="-1872867546" label="EnumerateAudioDevices:disabled"/> + <int value="-1871185948" label="VrLaunchIntents:disabled"/> <int value="-1870961970" label="enable-filemanager-mtp"/> <int value="-1869845022" label="force-show-update-menu-item"/> <int value="-1868978829" label="spurious-power-button-accel-count"/> @@ -23229,14 +25475,20 @@ <int value="-1867342522" label="MaterialDesignHistory:enabled"/> <int value="-1861814223" label="MidiManagerDynamicInstantiation:enabled"/> <int value="-1860481724" label="ChromeHomeExpandButton:enabled"/> + <int value="-1859095876" label="Previews:disabled"/> <int value="-1856902397" label="LoadingWithMojo:enabled"/> + <int value="-1854432127" label="ChromeHomePullToRefreshIphAtTop:disabled"/> + <int value="-1854372227" label="VrBrowsingExperimentalFeatures:enabled"/> <int value="-1849706663" label="enable-password-force-saving:disabled"/> + <int value="-1847888049" label="AutofillSendBillingCustomerNumber:enabled"/> <int value="-1847835522" label="disable-touch-adjustment"/> <int value="-1847776781" label="enable-loading-ipc-optimization-for-small-resources"/> + <int value="-1839874877" label="WebXROrientationSensorDevice:enabled"/> <int value="-1839637286" label="AutofillCreditCardBankNameDisplay:disabled"/> <int value="-1839496458" label="disable-file-manager-touch-mode"/> <int value="-1838482444" label="disable-settings-window"/> + <int value="-1837329460" label="NewEncodeCpuLoadEstimator:enabled"/> <int value="-1835975804" label="disable-offline-auto-reload"/> <int value="-1833149810" label="enable-accessibility-tab-switcher"/> <int value="-1832575380" label="show-saved-copy"/> @@ -23247,6 +25499,7 @@ <int value="-1811394154" label="disable-webrtc-hw-vp8-encoding"/> <int value="-1810294310" label="AndroidPaymentApps:enabled"/> <int value="-1808477331" label="MidiManagerCros:disabled"/> + <int value="-1807797669" label="google-doodle-url"/> <int value="-1804485171" label="disable-fullscreen-tab-detaching"/> <int value="-1802502753" label="enable-manual-password-generation:enabled"/> <int value="-1798337879" label="enable-md-downloads"/> @@ -23256,12 +25509,17 @@ <int value="-1784788154" label="NewRemotePlaybackPipeline:disabled"/> <int value="-1780306716" label="OmniboxSpeculativeServiceWorkerStartOnQueryInput:enabled"/> + <int value="-1779753607" label="VizDisplayCompositor:disabled"/> + <int value="-1778993296" label="ContextualSearchMlTapSuppression:disabled"/> <int value="-1772172557" label="enable-osk-overscroll"/> + <int value="-1768672408" label="ChromeDuplex:disabled"/> <int value="-1767470652" label="out-of-process-pdf"/> + <int value="-1755301960" label="ClearOldBrowsingData:enabled"/> <int value="-1751928267" label="disable-icon-ntp"/> <int value="-1749176684" label="PauseBackgroundTabs:disabled"/> <int value="-1746767834" label="ssl-interstitial-v2-gray"/> <int value="-1740519217" label="disable-software-rasterizer"/> + <int value="-1738416948" label="OptimizationHints:enabled"/> <int value="-1736075054" label="EnableFullscreenAppList:enabled"/> <int value="-1735643253" label="enable-display-list-2d-canvas"/> <int value="-1734254845" label="ash-enable-night-light"/> @@ -23271,14 +25529,19 @@ <int value="-1719833926" label="disable-answers-in-suggest"/> <int value="-1716654100" label="tab-capture-downscale-quality"/> <int value="-1714128884" label="disable-launcher-search-provider-api"/> + <int value="-1713564656" label="ProtectSyncCredentialOnReauth:enabled"/> <int value="-1711751318" label="enable-data-reduction-proxy-lo-fi-preview"/> <int value="-1703709912" label="enable-new-ntp"/> <int value="-1703308540" label="disable-webaudio"/> <int value="-1696366449" label="disable-permissions-bubbles"/> + <int value="-1694353093" label="ArcVpn:disabled"/> <int value="-1692384483" label="disambiguate-autofill-server-name-types"/> <int value="-1691892152" label="SafeSearchUrlReporting:disabled"/> <int value="-1691668194" label="enable-new-bookmark-apps"/> <int value="-1691281364" label="enable-notification-action-icons"/> + <int value="-1686782572" label="ChromeHomeInactivitySheetExpansion:disabled"/> + <int value="-1682843294" label="DataReductionProxyDecidesTransform:enabled"/> + <int value="-1677715989" label="UnifiedConsent:disabled"/> <int value="-1670137340" label="OptimizeLoadingIPCForSmallResources:disabled"/> <int value="-1669486359" label="ImportantSitesInCBD:enabled"/> @@ -23294,9 +25557,11 @@ <int value="-1648216169" label="NewOmniboxAnswerTypes:disabled"/> <int value="-1634878515" label="ChromeHomeModernLayout:enabled"/> <int value="-1634154256" label="ZeroSuggestRedirectToChrome:enabled"/> + <int value="-1633586675" label="TabModalJsDialog:enabled"/> <int value="-1631329950" label="ssl-version-max"/> <int value="-1630419335" label="enable-download-notification"/> <int value="-1624854957" label="enable-es3-apis"/> + <int value="-1620804800" label="NoScriptPreviews:disabled"/> <int value="-1620568042" label="FeaturePolicy:disabled"/> <int value="-1619757314" label="touch-scrolling-mode"/> <int value="-1618707999" label="enable-webfonts-intervention-v2"/> @@ -23306,31 +25571,37 @@ <int value="-1613583483" label="UseNewAcceptLanguageHeader:enabled"/> <int value="-1611305202" label="KeepPrefetchedContentSuggestions:disabled"/> <int value="-1607691647" label="MojoVideoEncodeAccelerator:disabled"/> + <int value="-1607297082" label="ash-enable-persistent-window-bounds"/> <int value="-1605567628" label="disable-overlay-scrollbar"/> <int value="-1604051051" label="SpecialLocale:disabled"/> + <int value="-1603404046" label="V8VmFuture:disabled"/> <int value="-1599538279" label="enable-md-policy-page"/> <int value="-1596559650" label="max-tiles-for-interest-area"/> <int value="-1594298767" label="FullscreenToolbarReveal:enabled"/> <int value="-1586642651" label="MaterialDesignExtensions:disabled"/> <int value="-1583728573" label="AutofillCreditCardSigninPromo:disabled"/> <int value="-1581724231" label="ModalPermissionPrompts:enabled"/> + <int value="-1580376019" label="ShowAllDialogsWithViewsToolkit:enabled"/> <int value="-1578295753" label="UserMediaScreenCapturing:disabled"/> - <int value="-1575984706" label="gl-composited-overlay-candidate-quad-border"/> <int value="-1575554415" label="AndroidPaymentAppsFilter:enabled"/> <int value="-1575430234" label="DontPrefetchLibraries:disabled"/> + <int value="-1575375861" label="enable-captive-portal-random-url"/> <int value="-1572010356" label="enable-privet-v3"/> <int value="-1571841513" label="enable-devtools-experiments"/> <int value="-1559789642" label="RunAllFlashInAllowMode:enabled"/> <int value="-1557527869" label="LoadingWithMojo:disabled"/> + <int value="-1555510175" label="PasswordImport:enabled"/> <int value="-1553477903" label="ash-disable-text-filtering-in-overview-mode"/> <int value="-1549871007" label="OneGoogleBarOnLocalNtp:disabled"/> <int value="-1546903171" label="enable-touch-drag-drop"/> + <int value="-1545595496" label="RendererSideResourceScheduler:enabled"/> <int value="-1544248549" label="ArcUseAuthEndpoint:enabled"/> <int value="-1543316040" label="DisplayPersistenceToggleInPermissionPrompts:disabled"/> <int value="-1536293422" label="SharedArrayBuffer:enabled"/> <int value="-1536242739" label="security-chip"/> <int value="-1532014193" label="disable-encryption-migration"/> + <int value="-1520855274" label="PWAFullCodeCache:disabled"/> <int value="-1515415104" label="top-document-isolation:disabled"/> <int value="-1514943439" label="ash-enable-swipe-to-close-in-overview-mode"/> <int value="-1514611301" label="enable-data-reduction-proxy-bypass-warnings"/> @@ -23338,6 +25609,7 @@ <int value="-1510839574" label="disable-sync-synced-notifications"/> <int value="-1508852757" label="CreditCardAutofillTouchBar:disabled"/> <int value="-1504305449" label="NTPPhysicalWebPageSuggestions:enabled"/> + <int value="-1498334893" label="ExperimentalVRFeatures:enabled"/> <int value="-1497338981" label="disable-accelerated-overflow-scroll"/> <int value="-1492589689" label="ContentSuggestionsCategories:enabled"/> <int value="-1491417046" label="enable-fullscreen-toolbar-reveal"/> @@ -23345,8 +25617,11 @@ <int value="-1490298774" label="enable-captive-portal-bypass-proxy-option"/> <int value="-1488744539" label="QuickUnlockFingerprint:enabled"/> <int value="-1487243228" label="NewUsbBackend:disabled"/> + <int value="-1486198877" label="VrIconInDaydreamHome:disabled"/> + <int value="-1482730792" label="stop-in-background:enabled"/> <int value="-1482685863" label="enable-request-tablet-site"/> <int value="-1480926949" label="MaterialDesignBookmarks:enabled"/> + <int value="-1480866718" label="ash-disable-login-dim-and-blur"/> <int value="-1478876902" label="disable-permission-action-reporting"/> <int value="-1473668019" label="token-binding:disabled"/> <int value="-1473136627" label="enable-web-payments"/> @@ -23357,11 +25632,16 @@ <int value="-1468126425" label="ResourceLoadScheduler:disabled"/> <int value="-1467332609" label="tab-management-experiment-type-anise"/> <int value="-1466990325" label="CrosCompUpdates:enabled"/> + <int value="-1466759286" label="TabModalJsDialog:disabled"/> <int value="-1463410070" label="IPH_DemoMode:enabled"/> <int value="-1461261930" label="OutOfBlinkCORS:disabled"/> <int value="-1460462432" label="disable-media-source"/> + <int value="-1457775295" label="PasswordSearchMobile:disabled"/> <int value="-1456004000" label="VrShell:disabled"/> + <int value="-1455852875" label="WebAuthentication:disabled"/> + <int value="-1454397907" label="OptimizationHints:disabled"/> <int value="-1450576851" label="OmniboxUIExperimentVerticalLayout:enabled"/> + <int value="-1446425986" label="ProtectSyncCredentialOnReauth:disabled"/> <int value="-1444051091" label="ash-disable-night-light"/> <int value="-1443796945" label="OfflinePagesSharing:disabled"/> <int value="-1440440375" label="WebVrAutopresent:enabled"/> @@ -23371,9 +25651,15 @@ <int value="-1433719718" label="enable-webrtc-stun-origin"/> <int value="-1433087548" label="enable-app-install-alerts"/> <int value="-1431563697" label="WebPaymentsMethodSectionOrderV2:enabled"/> + <int value="-1426817842" label="BlockTabUnders:enabled"/> + <int value="-1426150007" label="ignore-previews-blacklist"/> <int value="-1426034869" label="NoCreditCardAbort:enabled"/> + <int value="-1423348289" label="NupPrinting:disabled"/> <int value="-1419788257" label="enable-experimental-hotwording"/> + <int value="-1417122729" + label="AutofillCreditCardAblationExperiment:disabled"/> <int value="-1416754663" label="enable-mac-views-native-app-windows"/> + <int value="-1416184931" label="TranslateRankerEnforcement:enabled"/> <int value="-1411003295" label="disable-encrypted-media"/> <int value="-1409643943" label="enable-child-account-detection"/> <int value="-1408288176" label="enable-account-consistency"/> @@ -23387,7 +25673,9 @@ <int value="-1386966873" label="disable-mac-views-native-app-windows"/> <int value="-1382671832" label="OmniboxUIExperimentVerticalMargin:enabled"/> <int value="-1377186702" label="DesktopIOSPromotion:disabled"/> + <int value="-1376510363" label="ServiceWorkerScriptFullCodeCache:disabled"/> <int value="-1375111024" label="enable-fixed-position-compositing"/> + <int value="-1373705581" label="ManualSaving:enabled"/> <int value="-1365503870" label="enable-simplified-fullscreen-ui"/> <int value="-1363709707" label="MaterialDesignHistory:disabled"/> <int value="-1358669137" label="enable-supervised-user-blacklist"/> @@ -23399,18 +25687,27 @@ <int value="-1349532167" label="enable-wifi-credential-sync"/> <int value="-1346722635" label="gesture-selection"/> <int value="-1344375439" label="ServiceWorkerPaymentApps:disabled"/> + <int value="-1343259222" label="RegionalLocalesAsDisplayUI:disabled"/> <int value="-1341092934" label="enable-accelerated-overflow-scroll"/> <int value="-1340055960" label="enable-streamlined-hosted-apps"/> <int value="-1338306372" label="BrowserTouchBar:enabled"/> <int value="-1337185440" label="enable-webvr"/> + <int value="-1335017208" label="KeyboardLockAPI:enabled"/> <int value="-1334327410" label="ash-enable-touch-view-testing"/> <int value="-1327676774" label="disable-accelerated-mjpeg-decode"/> + <int value="-1325887476" label="NewPrintPreview:enabled"/> <int value="-1322882747" label="disable-datasaver-prompt"/> <int value="-1319688939" label="ignore-gpu-blacklist"/> + <int value="-1318914924" label="OverflowIconsForMediaControls:enabled"/> + <int value="-1314603238" label="ChromeHomePullToRefreshIphAtTop:enabled"/> + <int value="-1311133348" label="VrBrowsingNativeAndroidUi:enabled"/> <int value="-1310737697" label="MaterialDesignSettings:enabled"/> <int value="-1302904242" label="enable-navigation-tracing"/> <int value="-1294050129" label="ContentFullscreen:disabled"/> <int value="-1289678848" label="SystemDownloadManager:enabled"/> + <int value="-1288130734" label="OpenVR:disabled"/> + <int value="-1287511172" + label="OmniboxUIExperimentHideSteadyStateUrlSchemeAndSubdomains:disabled"/> <int value="-1285021473" label="save-page-as-mhtml"/> <int value="-1284637134" label="pull-to-refresh"/> <int value="-1276912933" label="enable-quick-unlock-pin"/> @@ -23419,14 +25716,21 @@ <int value="-1268836676" label="disable-out-of-process-pdf"/> <int value="-1267958145" label="disable-pdf-material-ui"/> <int value="-1262152606" label="disable-lock-screen-apps"/> + <int value="-1261263046" + label="RemoveUsageOfDeprecatedGaiaSigninEndpoint:disabled"/> + <int value="-1259901957" label="VrBrowserKeyboard:disabled"/> <int value="-1254070521" label="enable-slimming-paint-invalidation"/> <int value="-1251411236" label="disable-new-md-input-view"/> + <int value="-1248478422" label="enable-zip-archiver-packer"/> <int value="-1246840031" label="OptInImeMenu:disabled"/> + <int value="-1243358233" + label="AutofillUseNewSettingsNameInDropdown:enabled"/> <int value="-1241747717" label="enable-android-password-link"/> <int value="-1235586511" label="enable-datasaver-prompt"/> <int value="-1225198073" label="ReaderModeInCCT:disabled"/> <int value="-1224962996" label="PwaImprovedSplashScreen:disabled"/> <int value="-1218608640" label="disable-offline-load-stale-cache"/> + <int value="-1217425153" label="ChromeHomeClearUrlOnOpen:enabled"/> <int value="-1216837777" label="clear-data-reduction-proxy-data-savings"/> <int value="-1212855900" label="enable-all-bookmarks-view"/> <int value="-1212273428" label="enable-experimental-app-list"/> @@ -23437,12 +25741,14 @@ label="OmniboxUIExperimentHideSuggestionUrlScheme:disabled"/> <int value="-1203955801" label="enable-password-change-support:disabled"/> <int value="-1203742042" label="enable-gesture-selection"/> + <int value="-1201741587" label="DataReductionProxyDecidesTransform:disabled"/> <int value="-1201183153" label="enable-centered-app-list"/> <int value="-1197035323" label="ZeroSuggestRedirectToChrome:disabled"/> <int value="-1195194959" label="XGEOVisibleNetworks:disabled"/> <int value="-1190174011" label="enable-hdr"/> <int value="-1184904651" label="enable-npapi"/> <int value="-1184480269" label="LsdPermissionPrompt:enabled"/> + <int value="-1183009666" label="OfflinePagesLimitlessPrefetching:disabled"/> <int value="-1177802205" label="enable-hosted-app-quit-notification"/> <int value="-1176748003" label="FramebustingNeedsSameOriginOrUserGesture:disabled"/> @@ -23452,24 +25758,31 @@ <int value="-1172204005" label="enable-offline-auto-reload-visible-only"/> <int value="-1162944097" label="enable-color-correct-rendering"/> <int value="-1161409696" label="MediaRemotingEncrypted:enabled"/> + <int value="-1161384421" label="ContextualSuggestionsAboveArticles:enabled"/> + <int value="-1160941363" label="AffiliationBasedMatching:disabled"/> <int value="-1160026273" label="enable-web-notification-custom-layouts"/> <int value="-1159563774" label="enable-accessibility-script-injection"/> <int value="-1158993534" label="PrintScaling:enabled"/> + <int value="-1156179600" label="OmniboxRichEntitySuggestions:enabled"/> <int value="-1155543191" label="CopylessPaste:disabled"/> <int value="-1151766565" label="enable-fullscreen-tab-detaching"/> + <int value="-1145702446" label="ChromeHomeInactivitySheetExpansion:enabled"/> <int value="-1145246849" label="ThirdPartyDoodles:enabled"/> <int value="-1137442543" label="enable-slimming-paint"/> <int value="-1136627751" label="ignore-autocomplete-off-autofill"/> <int value="-1136509631" label="ssl-interstitial-v1"/> + <int value="-1134307340" label="stop-loading-in-background:enabled"/> <int value="-1132704128" label="AndroidPaymentAppsFilter:disabled"/> <int value="-1127996427" label="enable-files-details-panel"/> <int value="-1126217973" label="IdleTimeSpellChecking:disabled"/> <int value="-1125133283" label="disable-threaded-scrolling"/> + <int value="-1121931029" label="DownloadsForeground:enabled"/> <int value="-1119700637" label="ui-disable-partial-swap"/> <int value="-1112782121" label="AndroidSigninPromos:disabled"/> <int value="-1107762575" label="enable-data-reduction-proxy-config-client"/> <int value="-1102212525" label="enable-tcp-fastopen"/> <int value="-1099142083" label="V8Ignition:disabled"/> + <int value="-1099135056" label="AsyncDns:enabled"/> <int value="-1096595907" label="disable-new-virtual-keyboard-behavior"/> <int value="-1085492638" label="FetchKeepaliveTimeoutSetting:enabled"/> <int value="-1084055006" label="disable-web-notification-custom-layouts"/> @@ -23483,10 +25796,13 @@ <int value="-1067635248" label="SpeculativeResourcePrefetching:disabled"/> <int value="-1064733740" label="ui-show-composited-layer-borders"/> <int value="-1062119671" label="enable-password-force-saving"/> + <int value="-1060395248" label="PasswordSearchMobile:enabled"/> <int value="-1056310158" label="disable-memory-pressure-chromeos"/> <int value="-1052782474" label="enable-cloud-devices"/> <int value="-1052415111" label="malware-interstitial-v2"/> <int value="-1052219252" label="disable-captive-portal-bypass-proxy"/> + <int value="-1048901516" label="ChromeMemex:enabled"/> + <int value="-1046627610" label="password-import:enabled"/> <int value="-1045900007" label="NoCreditCardAbort:disabled"/> <int value="-1045882995" label="UseNewDoodleApi:enabled"/> <int value="-1041650038" label="enable-forced-migration-to-tabbed-mode"/> @@ -23496,14 +25812,17 @@ <int value="-1033738911" label="enable-mac-views-dialogs"/> <int value="-1029920490" label="IdleTimeSpellChecking:enabled"/> <int value="-1028733699" label="MacViewsWebUIDialogs:disabled"/> - <int value="-1027022706" label="ContentSuggestionsVideoOverlay:disabled"/> + <int value="-1027124889" label="NtlmV2Enabled:enabled"/> <int value="-1022971520" label="enable-search-button-in-omnibox-for-str"/> <int value="-1022165708" label="BreakingNewsPush:disabled"/> <int value="-1020450980" label="gesture-deletion"/> + <int value="-1019967332" label="VrBrowsing:enabled"/> <int value="-1016202433" label="disable-add-to-shelf"/> <int value="-1015006759" label="ImportantSitesInCBD:disabled"/> + <int value="-1014649471" label="committed-interstitials"/> <int value="-998255750" label="ExperimentalKeyboardLockUI:enabled"/> <int value="-996673716" label="enable-web-app-frame"/> + <int value="-994088375" label="VrBrowsingExperimentalRendering:enabled"/> <int value="-991253797" label="OmniboxSpeculativeServiceWorkerStartOnQueryInput:disabled"/> <int value="-984052166" label="DoodlesOnLocalNtp:enabled"/> @@ -23516,6 +25835,7 @@ <int value="-972737445" label="ArcUseAuthEndpoint:disabled"/> <int value="-972425050" label="gesture-editing"/> <int value="-968010468" label="SharedArrayBuffer:disabled"/> + <int value="-965842218" label="MultiDeviceApi:disabled"/> <int value="-964676765" label="enable-accelerated-mjpeg-decode"/> <int value="-951394314" label="top-chrome-md"/> <int value="-950793721" label="TranslateUI2016Q2:disabled"/> @@ -23525,13 +25845,14 @@ <int value="-933316841" label="enable-permissions-blacklist"/> <int value="-928138978" label="IPH_DemoMode:disabled"/> <int value="-926422468" label="disable-embedded-shared-worker"/> + <int value="-920204598" label="ScrollAnchorSerialization:enabled"/> <int value="-918900957" label="AutofillCreditCardAssist:disabled"/> <int value="-918618075" label="enable-service-worker"/> <int value="-914210146" label="enable-web-based-signin"/> <int value="-912456561" label="MidiManagerWinrt:enabled"/> - <int value="-909641013" label="DataReductionProxySiteBreakdown:enabled"/> <int value="-908421850" label="PointerEvent:enabled"/> <int value="-907234795" label="NewAudioRenderingMixingStrategy:disabled"/> + <int value="-905538983" label="SimplifyHttpsIndicator:disabled"/> <int value="-899393472" label="enable-new-app-menu-icon"/> <int value="-899334103" label="disable-fast-text-autosizing"/> <int value="-898594349" label="ash-enable-stable-overview-order"/> @@ -23540,14 +25861,18 @@ <int value="-894214299" label="fill-on-account-select:enabled"/> <int value="-894185031" label="HighDynamicRange:disabled"/> <int value="-891856063" label="MidiManagerAndroid:enabled"/> + <int value="-886912558" label="ChromeHomePromo:enabled"/> <int value="-885601782" label="enable-contextual-search"/> <int value="-884864731" label="WebPaymentsSingleAppUiSkip:enabled"/> <int value="-881854123" label="enable-heap-profiling"/> + <int value="-881447505" label="ash-disable-shelf-model-synchronization"/> <int value="-881054479" label="WebAssemblyStreaming:disabled"/> + <int value="-879055117" label="ClipboardContentSetting:enabled"/> <int value="-879031960" label="FetchKeepaliveTimeoutSetting:disabled"/> <int value="-876148583" label="ArcBootCompletedBroadcast:disabled"/> <int value="-867087281" label="enable-virtual-keyboard"/> <int value="-866993841" label="OfflinePagesCTV2:disabled"/> + <int value="-865390600" label="NativeSmb:enabled"/> <int value="-864266073" label="cros-regions-mode"/> <int value="-864234985" label="UseDdljsonApi:enabled"/> <int value="-864205629" label="enable-offline-load-stale-cache"/> @@ -23559,28 +25884,40 @@ <int value="-855130893" label="enable-touch-calibration-setting"/> <int value="-853594220" label="disable-new-avatar-menu"/> <int value="-848691867" label="DesktopPWAWindowing:enabled"/> + <int value="-847216521" label="ChromeDuplex:enabled"/> <int value="-844537521" label="HttpFormWarning:disabled"/> <int value="-844381918" label="ArcNativeBridgeExperiment:disabled"/> <int value="-842438090" label="enable-md-feedback"/> <int value="-836123854" label="wallet-service-use-sandbox"/> <int value="-835672415" label="PointerEventV1SpecCapturing:disabled"/> <int value="-834661509" label="ModalPermissionPrompts:disabled"/> + <int value="-833382237" label="ash-enable-docked-magnifier"/> <int value="-832561975" label="enable-picture-in-picture"/> + <int value="-828070439" label="NativeSmb:disabled"/> <int value="-825942229" label="tab-management-experiment-type-elderberry"/> <int value="-823165021" label="MaterialDesignUserMenu:enabled"/> <int value="-820041355" label="enable-transition-compositing"/> <int value="-816984237" label="OfflinePagesAsyncDownload:enabled"/> <int value="-814097014" label="disable-session-crashed-bubble"/> + <int value="-813753274" label="VrBrowsing:disabled"/> <int value="-813474479" label="site-per-process"/> <int value="-812461825" label="AutofillCreditCardSigninPromo:enabled"/> + <int value="-810684526" + label="AutofillToolkitViewsCreditCardDialogsMac:disabled"/> <int value="-802348444" label="disable-site-engagement-service"/> <int value="-798187384" label="try-supported-channel-layouts"/> + <int value="-795854288" label="enable-draw-occlusion"/> <int value="-795600188" label="disable-async-dns"/> + <int value="-793921836" label="ShowAllDialogsWithViewsToolkit:disabled"/> <int value="-790036192" label="overscroll-start-threshold"/> + <int value="-787426248" label="ChromeHomeSurvey:disabled"/> <int value="-780798969" label="disable-single-click-autofill"/> + <int value="-780599934" label="AutofillUpstreamSendPanFirstSix:enabled"/> + <int value="-778126349" label="DownloadsLocationChange:enabled"/> <int value="-776686417" label="SiteExplorationUi:disabled"/> <int value="-775321548" label="UseNewDoodleApi:disabled"/> <int value="-772679248" label="MojoVideoEncodeAccelerator:enabled"/> + <int value="-771080109" label="GrantNotificationsToDSE:disabled"/> <int value="-770319039" label="enable-touch-editing"/> <int value="-763759697" label="enable-audio-support-for-desktop-share"/> <int value="-759830869" label="enable-tab-discarding"/> @@ -23594,9 +25931,11 @@ <int value="-744159181" label="disable-spdy-proxy-dev-auth-origin"/> <int value="-743103250" label="enable-linkable-ephemeral-apps"/> <int value="-741806604" label="DownloadsUi:disabled"/> + <int value="-738957187" label="OmniboxUIExperimentSwapTitleAndUrl:disabled"/> <int value="-723224470" label="enable-password-force-saving:enabled"/> <int value="-722474177" label="browser-side-navigation:disabled"/> <int value="-718626298" label="SysInternals:enabled"/> + <int value="-717281513" label="ash-enable-keyboard-shortcut-viewer"/> <int value="-716953514" label="disable-password-separated-signin-flow"/> <int value="-715733307" label="force-effective-connection-type"/> <int value="-714712077" label="ClickToOpenPDFPlaceholder:disabled"/> @@ -23605,12 +25944,18 @@ <int value="-711991950" label="SiteExplorationUi:enabled"/> <int value="-711890895" label="enable-website-settings-manager"/> <int value="-709058455" label="ui-slow-animations"/> + <int value="-706733351" label="enable-floating-virtual-keyboard:enabled"/> + <int value="-704232562" label="UseMonitorColorSpace:enabled"/> <int value="-702477233" label="ContentFullscreen:enabled"/> <int value="-699767107" label="enable-sync-app-list"/> <int value="-697751423" label="disable-quickoffice-component-app"/> <int value="-684900739" label="disable-merge-key-char-events"/> <int value="-684223908" label="enable-android-wallpapers-app"/> + <int value="-680787130" label="ExperimentalVRFeatures:disabled"/> <int value="-680589442" label="MacRTL:disabled"/> + <int value="-674804217" label="SoleIntegration:enabled"/> + <int value="-671992446" label="TranslateRankerEnforcement:disabled"/> + <int value="-670188266" label="enable-zip-archiver-unpacker"/> <int value="-667517406" label="overscroll-history-navigation"/> <int value="-666508951" label="CrOSContainer:enabled"/> <int value="-663476391" label="enable-pixel-canvas-recording:enabled"/> @@ -23621,9 +25966,11 @@ <int value="-649956990" label="enable-harfbuzz-rendertext"/> <int value="-645455405" label="MacViewsNativeDialogs:enabled"/> <int value="-641719457" label="disable-compositor-touch-hit-testing"/> + <int value="-638952203" label="RendererSideResourceScheduler:disabled"/> <int value="-632030508" label="NativeWindowNavButtons:disabled"/> <int value="-631740127" label="inert-visual-viewport"/> <int value="-622685174" label="enable-pdf-material-ui"/> + <int value="-621382525" label="VizDisplayCompositor:enabled"/> <int value="-620030047" label="CrosCompUpdates:disabled"/> <int value="-617452890" label="media-router"/> <int value="-612480090" label="FasterLocationReload:enabled"/> @@ -23633,15 +25980,20 @@ <int value="-604269405" label="ContentSuggestionsFaviconsFromNewServer:enabled"/> <int value="-604068396" label="disable-input-ime-api"/> + <int value="-603649079" label="ContextualSearchRankerQuery:enabled"/> <int value="-601384286" label="disable-contextual-search"/> + <int value="-600792432" label="WebVrAutopresentFromIntent:disabled"/> <int value="-599932554" label="DoodlesOnLocalNtp:disabled"/> <int value="-598050737" label="disable-es3-apis"/> + <int value="-596337171" label="disable-ash-sidebar"/> + <int value="-593536514" label="ExperimentalTabController:enabled"/> <int value="-589096918" label="ash-enable-fullscreen-app-list"/> <int value="-579192400" label="disable-input-view"/> <int value="-572112724" label="DialogTouchBar:disabled"/> <int value="-567920515" label="disable-experimental-hotwording"/> <int value="-563980787" label="disable-webrtc"/> <int value="-562274241" label="enable-extension-action-redesign"/> + <int value="-561194974" label="AutofillExpandedPopupViews:enabled"/> <int value="-560551550" label="use-memory-pressure-chromeos"/> <int value="-560114351" label="OfflinePagesRenovations:disabled"/> <int value="-557742250" label="ContentSuggestionsCategories:disabled"/> @@ -23650,6 +26002,7 @@ <int value="-536289234" label="ssl-interstitial-v2-colorful"/> <int value="-535208779" label="enable-native-cups"/> <int value="-531810064" label="saveas-menu-label"/> + <int value="-531792555" label="UseModernMediaControls:disabled"/> <int value="-531651776" label="NewRemotePlaybackPipeline:enabled"/> <int value="-528927088" label="AutofillCreditCardPopupLayout:disabled"/> <int value="-528149352" label="WebRtcUseEchoCanceller3:enabled"/> @@ -23657,11 +26010,15 @@ <int value="-519960638" label="enable-site-engagement-service"/> <int value="-518104091" label="NewAudioRenderingMixingStrategy:enabled"/> <int value="-516845951" label="enable-embedded-extension-options"/> + <int value="-513305102" label="LanguagesPreference:enabled"/> <int value="-512971943" label="disable-one-copy"/> <int value="-510488450" label="disable-pnacl"/> <int value="-508143738" label="disable-accelerated-fixed-root-background"/> <int value="-506706655" label="respect-autocomplete-off-autofill"/> <int value="-505679399" label="FontCacheScaling:enabled"/> + <int value="-498740735" label="ArcUsbHost:disabled"/> + <int value="-498463128" label="MacSystemShareMenu:enabled"/> + <int value="-496119023" label="WebXR:enabled"/> <int value="-495585885" label="enable-spdy-proxy-dev-auth-origin"/> <int value="-494722408" label="ContentSuggestionsLargeThumbnail:enabled"/> <int value="-493551777" label="StaleWhileRevalidate2:disabled"/> @@ -23673,12 +26030,18 @@ <int value="-474806100" label="DataReductionProxyMainMenu:enabled"/> <int value="-474322576" label="disable-quick-unlock-pin"/> <int value="-472013317" label="WebRTC-H264WithOpenH264FFmpeg:disabled"/> + <int value="-471405972" label="ViewsProfileChooser:disabled"/> + <int value="-471085510" label="MultiDeviceApi:enabled"/> + <int value="-470948890" label="OfflinePagesDescriptivePendingStatus:enabled"/> <int value="-462205750" label="enable-service-worker-sync"/> <int value="-461292699" label="ContentSuggestionsCategoryOrder:enabled"/> <int value="-460313418" label="ProgressBarThrottle:enabled"/> <int value="-460081932" label="CustomFeedbackUi:disabled"/> + <int value="-457174225" label="Av1Decoder:enabled"/> <int value="-455203267" label="use_new_features_summary"/> <int value="-449465495" label="disable-browser-task-scheduler"/> + <int value="-436470115" label="TouchpadAndWheelScrollLatching:enabled"/> + <int value="-435914745" label="ClipboardContentSetting:disabled"/> <int value="-430360431" label="disable-password-generation"/> <int value="-428599163" label="NTPDownloadSuggestions:enabled"/> <int value="-418868128" label="enable-experimental-web-platform-features"/> @@ -23697,6 +26060,7 @@ <int value="-378180863" label="disable-panels"/> <int value="-378033324" label="disable-win32k-renderer-lockdown"/> <int value="-374657496" label="OmniboxEnableClipboardProvider:enabled"/> + <int value="-374423260" label="OmniboxTabSwitchSuggestions:disabled"/> <int value="-367474066" label="DialogTouchBar:enabled"/> <int value="-365920680" label="ImageCaptureAPI:disabled"/> <int value="-364587218" label="ResourceLoadScheduler:enabled"/> @@ -23704,6 +26068,7 @@ <int value="-364267715" label="disable-native-cups"/> <int value="-362022976" label="disable-quirks-client"/> <int value="-361948582" label="material-security-verbose"/> + <int value="-360453785" label="LeftToRightUrls:disabled"/> <int value="-360038744" label="invert-viewport-scroll-order"/> <int value="-354783358" label="NTPSaveToOffline:disabled"/> <int value="-353182790" label="ConsistentOmniboxGeolocation:disabled"/> @@ -23719,9 +26084,11 @@ <int value="-340622848" label="disable-javascript-harmony-shipping"/> <int value="-340255045" label="allow-nacl-socket-api"/> <int value="-340023285" label="WebNFC:enabled"/> + <int value="-338978205" label="NavigationMojoResponse:enabled"/> <int value="-329727402" label="disable-files-quick-view"/> <int value="-328361990" label="enable-experimental-extension-apis"/> <int value="-326083626" label="AppBanners:disabled"/> + <int value="-323964300" label="ArcVpn:enabled"/> <int value="-323831744" label="token-binding:enabled"/> <int value="-322937746" label="disable-desktop-capture-picker-new-ui"/> <int value="-322827131" label="tab-management-experiment-type-basil"/> @@ -23730,12 +26097,17 @@ <int value="-314910380" label="disable-distance-field-text"/> <int value="-314605926" label="protect-sync-credential-on-reauth:enabled"/> <int value="-311148335" label="v8-pac-mojo-out-of-process"/> + <int value="-305029910" label="AutofillUpstreamSendDetectedValues:disabled"/> <int value="-300018686" label="disable-cloud-import"/> <int value="-299841473" label="top-document-isolation:enabled"/> <int value="-297716805" label="CrossOriginMediaPlaybackRequiresUserGesture:disabled"/> <int value="-290672626" label="enable-asm-wasm"/> <int value="-288316828" label="enable-delegated-renderer"/> + <int value="-284547865" label="UnifiedConsent:enabled"/> + <int value="-283388027" label="ManualFallbacksFilling:disabled"/> + <int value="-281844827" label="AutofillCreditCardAblationExperiment:enabled"/> + <int value="-280111192" label="AutofillUpstreamSendDetectedValues:enabled"/> <int value="-279920685" label="affiliation-based-matching:enabled"/> <int value="-279493876" label="WebVRExperimentalRendering:enabled"/> <int value="-278347667" label="default-tile-height"/> @@ -23745,12 +26117,15 @@ <int value="-275619817" label="disable-proximity-auth-bluetooth-low-energy-discovery"/> <int value="-275164173" label="QuickUnlockPinSignin:enabled"/> + <int value="-271790049" label="ArcUsbHost:enabled"/> + <int value="-270626757" label="log-net-log"/> <int value="-268357961" label="enable-feature-policy"/> <int value="-254887599" label="google-profile-info"/> <int value="-250822813" label="PwaImprovedSplashScreen:enabled"/> <int value="-250721831" label="AndroidAutofillAccessibility:disabled"/> <int value="-248223420" label="AutofillKeyboardAccessory:disabled"/> <int value="-241353344" label="MidiManagerWinrt:disabled"/> + <int value="-240531943" label="ContextualSearchRankerQuery:disabled"/> <int value="-239616243" label="HighDynamicRange:enabled"/> <int value="-234966279" label="PointerEvent:disabled"/> <int value="-234687894" @@ -23771,29 +26146,41 @@ <int value="-192389983" label="NoStatePrefetch:enabled"/> <int value="-183246373" label="enable-multilingual-spellchecker"/> <int value="-181093956" label="ScrollAnchoring:enabled"/> + <int value="-174319545" label="BulkPrinters:enabled"/> + <int value="-171173736" label="VrBrowsingExperimentalFeatures:disabled"/> <int value="-170986053" label="EnableManualFallbacksFilling:enabled"/> <int value="-165756594" label="enable-touch-feedback"/> <int value="-159877930" label="MaterialDesignUserManager:disabled"/> + <int value="-159046738" + label="AutofillCreditCardDropdownGooglePayBranding:disabled"/> <int value="-158549277" label="enable-embeddedsearch-api"/> <int value="-152677714" label="AsmJsToWebAssembly:enabled"/> <int value="-147283486" label="enable-network-portal-notification"/> <int value="-146552997" label="enable-affiliation-based-matching"/> <int value="-144134779" label="AndroidPayIntegrationV2:disabled"/> <int value="-143382681" label="InstantTethering:enabled"/> + <int value="-141516902" label="UseModernMediaControls:enabled"/> <int value="-138983372" label="DesktopPWAWindowing:disabled"/> <int value="-138773929" label="PassiveDocumentEventListeners:enabled"/> + <int value="-135223364" label="AutofillShowTypePredictions:disabled"/> + <int value="-127231994" label="VrBrowsingNativeAndroidUi:disabled"/> <int value="-122492389" label="enable-browser-task-scheduler"/> <int value="-120521482" label="DirectManipulationStylus:enabled"/> <int value="-119055644" label="GenericSensor:enabled"/> + <int value="-112459802" label="WebXrRenderPath:enabled"/> + <int value="-110756896" + label="NTPArticleSuggestionsExpandableHeader:enabled"/> + <int value="-110726049" label="KeyboardLockAPI:disabled"/> + <int value="-110465424" label="PictureInPicture:enabled"/> <int value="-108881882" label="NTPCondensedTileLayout:enabled"/> <int value="-102537270" label="extension-content-verification"/> + <int value="-102227288" label="PasswordExport:disabled"/> <int value="-99781021" label="disable-roboto-font-ui"/> <int value="-89690053" label="MaterialDesignUserManager:enabled"/> <int value="-88822940" label="ssl-version-min"/> <int value="-88273414" label="ContentSuggestionsShowSummary:enabled"/> <int value="-86788587" label="allow-autofill-sync-credential"/> <int value="-80353187" label="disable-display-color-calibration"/> - <int value="-80222766" label="AutofillUpstreamShowNewUi:disabled"/> <int value="-78035185" label="custom_summary"/> <int value="-77872983" label="BookmarkAppsMac:disabled"/> <int value="-76631048" label="disable-offline-auto-reload-visible-only"/> @@ -23802,19 +26189,26 @@ <int value="-69427025" label="OfflinePagesPrefetchingUI:enabled"/> <int value="-68877684" label="BackgroundVideoTrackOptimization:enabled"/> <int value="-68225452" label="enable-translate-new-ux"/> + <int value="-67297229" label="OfflinePagesDescriptivePendingStatus:disabled"/> <int value="-59401847" label="ContentSuggestionsLargeThumbnail:disabled"/> <int value="-58242474" label="ash-disable-swipe-to-close-in-overview-mode"/> <int value="-57986995" label="DisablePostScriptPrinting:enabled"/> <int value="-55944747" label="disable-child-account-detection"/> <int value="-52483823" label="disable-new-video-renderer"/> <int value="-52241456" label="enable-single-click-autofill"/> + <int value="-50628385" + label="ContentSuggestionsThumbnailDominantColor:enabled"/> <int value="-50021298" label="ash-adjustable-large-cursor"/> <int value="-48920737" label="enable-smooth-scrolling"/> <int value="-45532639" label="enable-default-media-session"/> <int value="-45074716" label="SystemDownloadManager:disabled"/> + <int value="-45067971" label="NewPrintPreview:disabled"/> <int value="-29847483" label="MemoryAblation:enabled"/> + <int value="-23804418" + label="NTPArticleSuggestionsExpandableHeader:disabled"/> <int value="-23090520" label="disable-search-button-in-omnibox"/> <int value="-22544408" label="enable-video-player-chromecast-support"/> + <int value="-19354048" label="AutofillUpstreamSendPanFirstSix:disabled"/> <int value="-16824589" label="ash-shelf-color"/> <int value="-13918890" label="disable-download-notification"/> <int value="-11260186" label="enable-offline-pages-as-saved-pages"/> @@ -23827,22 +26221,13 @@ <int value="0" label="BAD_FLAG_FORMAT"> Command-line flag doesn't start with two dashes. </int> -<!-- -Values in LoginCustomFlags are: value=(uint32_t)MD5(label). -This enum is verified by AboutFlagsHistogramTest unit test. -To add a new entry, add it with any unique value and run test to compute valid -value. After that run tools/metrics/histograms/validate_format.py to find out -where the value should be inserted to maintain ordering. -Don't remove entries when removing a flag, they are still used to decode data -from previous Chrome versions. ---> - - <summary>Chrome flags that lead to Chrome restart on Chrome OS.</summary> <int value="7444737" label="NTPSuggestionsStandaloneUI:disabled"/> <int value="7533886" label="disable-offer-store-unmasked-wallet-cards"/> <int value="10458238" label="disable-print-preview-simplify"/> <int value="11698808" label="enable-dom-distiller-button-animation"/> + <int value="23556595" label="MarkHttpAs:enabled"/> <int value="27507364" label="apps-keep-chrome-alive"/> + <int value="28272521" label="ash-enable-display-move-window-accels"/> <int value="31848187" label="ViewsTaskManager:disabled"/> <int value="33778663" label="OriginTrials:enabled"/> <int value="37024318" label="disable-affiliation-based-matching"/> @@ -23853,14 +26238,23 @@ <int value="56723110" label="enable-webfonts-intervention"/> <int value="57639188" label="SoundContentSetting:disabled"/> <int value="57791920" label="MemoryCoordinator:enabled"/> + <int value="58099178" label="SecondaryUiMd:enabled"/> <int value="59784035" label="ImeThread:disabled"/> <int value="59964519" label="OmniboxEnableClipboardProvider:disabled"/> <int value="61205887" label="enable-text-input-focus-manager"/> + <int value="61466986" label="AsyncDns:disabled"/> <int value="64942701" label="OfflinePagesSvelteConcurrentLoading:disabled"/> + <int value="67639499" label="stop-loading-in-background:disabled"/> <int value="70878462" label="WebAssembly:disabled"/> + <int value="73929836" label="VrBrowsingInCustomTab:enabled"/> + <int value="75237697" label="ash-enable-new-overview-ui"/> <int value="75747474" label="disable-webview-signin-flow"/> <int value="78998551" label="disable-hosted-app-shim-creation"/> + <int value="79094339" label="VrLaunchIntents:enabled"/> <int value="79503461" label="disable-account-consistency"/> + <int value="79595680" label="OmniboxTabSwitchSuggestions:enabled"/> + <int value="83422372" + label="ChromeHomePersonalizedOmniboxSuggestions:enabled"/> <int value="84911198" label="ScanCardsInWebPayments:disabled"/> <int value="88437020" label="FeaturePolicy:enabled"/> <int value="91938915" label="enable-suggestions-service"/> @@ -23868,7 +26262,7 @@ <int value="103932290" label="show-autofill-type-predictions"/> <int value="105046382" label="ParallelDownloading:disabled"/> <int value="106840653" label="mus"/> - <int value="112420129" label="ContentSuggestionsVideoOverlay:enabled"/> + <int value="107900612" label="ChromeHomePersistentIph:disabled"/> <int value="118991027" label="enable-accelerated-fixed-root-background"/> <int value="119185738" label="OmniboxUIExperimentMaxAutocompleteMatches:disabled"/> @@ -23879,7 +26273,9 @@ <int value="125581289" label="WebRtcHWVP8Encoding:disabled"/> <int value="125934378" label="enable-password-link"/> <int value="131881947" label="D3DVsync:enabled"/> + <int value="147342055" label="ChromeHomeClearUrlOnOpen:disabled"/> <int value="147373243" label="enable-deferred-image-decoding"/> + <int value="151101719" label="HtmlBaseUsernameDetector:enabled"/> <int value="157217034" label="enable-tab-for-desktop-share"/> <int value="157318016" label="AutomaticTabDiscarding:enabled"/> <int value="173288154" label="PrintPdfAsImage:enabled"/> @@ -23887,11 +26283,14 @@ <int value="180074362" label="memory-pressure-thresholds"/> <int value="185991204" label="enable-webrtc-srtp-encrypted-headers"/> <int value="189728101" label="FasterLocationReload:disabled"/> + <int value="191737931" label="enable-mark-http-as"/> <int value="194573877" label="MacViewsNativeDialogs:disabled"/> <int value="194895489" label="passive-listeners-default"/> <int value="200347243" label="WebVRExperimentalRendering:disabled"/> <int value="201343576" label="enable-password-change-support:enabled"/> <int value="203776499" label="enable-virtual-keyboard-overscroll"/> + <int value="218890378" label="ManualSaving:disabled"/> + <int value="219117936" label="AllowReaderForAccessibility:enabled"/> <int value="223662457" label="BackgroundLoadingForDownloads:enabled"/> <int value="237964589" label="enable-manual-fallback-for-password-saving:disabled"/> @@ -23899,15 +26298,21 @@ <int value="244697230" label="enable-theme-color-in-tabbed-mode"/> <int value="259021228" label="OffMainThreadFetch:disabled"/> <int value="262382944" label="GuestViewCrossProcessFrames:disabled"/> + <int value="266322815" label="ChromeModernDesign:disabled"/> <int value="266702296" label="disable-plugin-power-saver"/> + <int value="268535107" + label="ash-new-touch-support-for-screen-magnification"/> <int value="270267831" label="enable-scripts-require-action"/> <int value="272631627" label="BookmarkAppsMac:enabled"/> <int value="274103741" label="enable-ntp-popular-sites"/> <int value="278756320" label="disable-app-list-app-info"/> <int value="280644887" label="mash"/> <int value="283232244" label="OmniboxUIExperimentNarrowDropdown:enabled"/> + <int value="293134455" label="AutofillSendBillingCustomerNumber:disabled"/> + <int value="293996306" label="ArrayPrototypeValues:disabled"/> <int value="301869874" label="NTPPhysicalWebPageSuggestions:disabled"/> <int value="303058039" label="AccountConsistency:disabled"/> + <int value="303252119" label="AutofillExpandedPopupViews:disabled"/> <int value="304901781" label="NewUsbBackend:enabled"/> <int value="313303258" label="WebPaymentsModifiers:disabled"/> <int value="316182183" label="MediaDocumentDownloadButton:disabled"/> @@ -23924,18 +26329,25 @@ <int value="341152650" label="SoundContentSetting:enabled"/> <int value="346711293" label="enable-save-password-bubble"/> <int value="348854923" label="v8-cache-strategies-for-cache-storage"/> + <int value="350399958" label="ModuleScriptsImportMetaUrl:disabled"/> <int value="352191859" label="disabled-new-style-notification"/> + <int value="352937987" label="OverflowIconsForMediaControls:disabled"/> + <int value="357138275" label="enable-floating-virtual-keyboard:disabled"/> <int value="358399482" label="enable-high-dpi-fixed-position-compositing"/> <int value="358493847" label="BackgroundLoader:disabled"/> <int value="360391863" label="NTPOfflineBadge:enabled"/> <int value="360599302" label="enable-gpu-rasterization"/> <int value="365467768" label="prefetch-search-results"/> + <int value="367063319" label="PasswordImport:disabled"/> <int value="368854020" label="ash-screen-rotation-animation"/> <int value="369352033" label="GenericSensorExtraClasses:enabled"/> + <int value="369635818" label="PasswordExport:enabled"/> <int value="370486304" label="enable-origin-chip-on-srp"/> <int value="371268743" label="OmniboxUIExperimentVerticalMargin:disabled"/> <int value="372460068" label="QuickUnlockFingerprint:disabled"/> + <int value="375785554" label="UserActivationV2:disabled"/> <int value="377093001" label="WebRtcHWH264Encoding:disabled"/> + <int value="378994579" label="Previews:enabled"/> <int value="379326303" label="enable-add-to-shelf"/> <int value="379428799" label="security-chip-animation"/> <int value="385969127" label="disable-win32k-lockdown"/> @@ -23946,6 +26358,7 @@ <int value="400322063" label="ash-disable-screen-orientation-lock"/> <int value="401983950" label="enable-spdy4"/> <int value="402143634" label="enable-search-button-in-omnibox-always"/> + <int value="403288255" label="enable-wheel-scroll-latching"/> <int value="405329388" label="FramebustingNeedsSameOriginOrUserGesture:enabled"/> <int value="411250226" label="AutoplayMutedVideos:disabled"/> @@ -23961,6 +26374,7 @@ <int value="434033638" label="PwaPersistentNotification:disabled"/> <int value="446316019" label="enable-threaded-compositing"/> <int value="451196246" label="disable-impl-side-painting"/> + <int value="452139294" label="VrShellExperimentalRendering:enabled"/> <int value="453102772" label="OfflinePagesLoadSignalCollecting:disabled"/> <int value="455698038" label="disable-gesture-requirement-for-media-playback"/> @@ -23981,6 +26395,7 @@ <int value="480544447" label="NonValidatingReloadOnRefreshContentV2:enabled"/> <int value="481506759" label="ServiceWorkerScriptStreaming:enabled"/> <int value="492113129" label="ExperimentalAppBanners:enabled"/> + <int value="492985975" label="use-monitor-color-space"/> <int value="493903641" label="disable-appcontainer"/> <int value="494733611" label="disable-drop-sync-credential"/> <int value="503245473" label="disable-translate-new-ux"/> @@ -23988,6 +26403,7 @@ <int value="506680761" label="WebNFC:disabled"/> <int value="510814146" label="OfflineBookmarks:enabled"/> <int value="513356954" label="InstantTethering:disabled"/> + <int value="513372959" label="ViewsProfileChooser:enabled"/> <int value="517568645" label="AnimatedAppMenuIcon:disabled"/> <int value="535131384" label="OmniboxTailSuggestions:enabled"/> <int value="535976218" label="enable-plugin-power-saver"/> @@ -23998,6 +26414,7 @@ <int value="550387510" label="NTPAssetDownloadSuggestions:disabled"/> <int value="558873715" label="SiteDetails:disabled"/> <int value="562979188" label="DesktopIOSPromotion:enabled"/> + <int value="564522013" label="Av1Decoder:disabled"/> <int value="567368307" label="enable-experimental-canvas-features"/> <int value="575394365" label="AndroidPaymentApps:disabled"/> <int value="576878329" label="enable-background-blur"/> @@ -24008,8 +26425,10 @@ <int value="586021329" label="VibrateRequiresUserGesture:enabled"/> <int value="592050831" label="disable-slimming-paint"/> <int value="593707592" label="disable-network-portal-notification"/> + <int value="595371145" label="OmniboxRichEntitySuggestions:disabled"/> <int value="596106994" label="CustomFeedbackUi:enabled"/> <int value="598827460" label="enable-roboto-font-ui"/> + <int value="598926697" label="VrLaunchIntent:disabled"/> <int value="600037637" label="AndroidSigninPromos:enabled"/> <int value="602117675" label="NTPBookmarkSuggestions:enabled"/> <int value="603326800" label="UsePasswordSeparatedSigninFlow:enabled"/> @@ -24025,15 +26444,18 @@ <int value="625273056" label="disable-boot-animation"/> <int value="628302973" label="NTPSnippets:enabled"/> <int value="628570445" label="AndroidAutofillAccessibility:enabled"/> + <int value="629549626" label="ContextualSearchMlTapSuppression:enabled"/> <int value="630244477" label="ServiceWorkerPaymentApps:enabled"/> <int value="630947363" label="touch-events"/> <int value="632340413" label="network-settings-config"/> + <int value="635076832" label="MarkHttpAs:disabled"/> <int value="635971109" label="PrintPdfAsImage:disabled"/> <int value="636425179" label="mhtml-generator-option"/> <int value="637396292" label="AllBookmarks:enabled"/> + <int value="637452937" label="ChromeHomeSurvey:enabled"/> + <int value="642037198" label="SoleIntegration:disabled"/> <int value="643725031" label="disable-touch-feedback"/> <int value="644189071" label="PermissionsBlacklist:enabled"/> - <int value="644674603" label="DataReductionProxySiteBreakdown:disabled"/> <int value="646252875" label="ReadItLaterInMenu:enabled"/> <int value="646738320" label="disable-gesture-editing"/> <int value="649111851" label="MidiManagerCros:enabled"/> @@ -24041,11 +26463,14 @@ <int value="651844675" label="EasyUnlockPromotions:enabled"/> <int value="652561231" label="CustomContextMenu:enabled"/> <int value="659086147" label="OverlayScrollbarFlashWhenMouseEnter:enabled"/> + <int value="665409384" + label="AutofillToolkitViewsCreditCardDialogsMac:enabled"/> <int value="679931272" label="DcheckIsFatal:enabled"/> <int value="684806628" label="TranslateLanguageByULP:disabled"/> <int value="685916283" label="enable-zip-archiver-on-file-manager"/> <int value="687838135" label="ThirdPartyDoodles:disabled"/> <int value="689489984" label="disable-zero-suggest"/> + <int value="689577480" label="vr-shell-experimental-rendering"/> <int value="690185633" label="NonValidatingReloadOnNormalReload:disabled"/> <int value="691020108" label="NTPCondensedTileLayout:disabled"/> <int value="693012666" label="QuickUnlockPin:disabled"/> @@ -24062,7 +26487,11 @@ <int value="719267310" label="KeepAliveRendererForKeepaliveRequests:disabled"/> <int value="721225492" label="PolicyTool:enabled"/> + <int value="723619383" label="TopSitesFromSiteEngagement:enabled"/> <int value="724208771" label="TabsInCBD:enabled"/> + <int value="725270017" label="ScrollAnchorSerialization:disabled"/> + <int value="727571565" label="PasswordForceSaving"/> + <int value="728656094" label="PasswordForceSaving:disabled"/> <int value="730024226" label="enable-out-of-process-pdf"/> <int value="730750097" label="PermissionsBlacklist:disabled"/> <int value="732703958" label="enable-gesture-tap-highlight"/> @@ -24072,14 +26501,21 @@ <int value="747847237" label="PhysicalWeb:enabled"/> <int value="752194066" label="enable-app-window-cycling"/> <int value="752939691" label="disable-tab-for-desktop-share"/> + <int value="760542355" label="ServiceWorkerScriptFullCodeCache:enabled"/> <int value="762700519" label="enable-checker-imaging"/> <int value="765306424" label="ModuleScriptsDynamicImport:disabled"/> + <int value="765803208" label="AutofillShowTypePredictions:enabled"/> + <int value="766898398" label="sampling-heap-profiler"/> + <int value="772272625" label="simplify-https-indicator"/> + <int value="772348426" label="AffiliationBasedMatching:enabled"/> <int value="773919225" label="disable-office-editing-component-extension"/> <int value="779086132" label="enable-data-reduction-proxy-alt"/> <int value="782167080" label="enable-new-qp-input-view"/> <int value="783270752" label="AndroidHistoryManager:enabled"/> + <int value="787385958" label="RegionalLocalesAsDisplayUI:enabled"/> <int value="803282885" label="PreferHtmlOverPlugins:disabled"/> <int value="806334184" label="AndroidSpellChecker:enabled"/> + <int value="807447752" label="ChromeMemex:disabled"/> <int value="807734471" label="tab-management-experiment-type-disabled"/> <int value="811374216" label="disable-new-bookmark-apps"/> <int value="820650704" label="disable-ntp-popular-sites"/> @@ -24092,16 +26528,21 @@ <int value="838887742" label="manual-enhanced-bookmarks"/> <int value="841276069" label="ChromeHomeDoodle:disabled"/> <int value="841343322" label="disable-new-korean-ime"/> + <int value="841779535" label="password-export:enabled"/> <int value="842432903" label="CaptureThumbnailOnNavigatingAway:enabled"/> + <int value="843896452" label="UserActivationV2:enabled"/> <int value="846951416" label="CopylessPaste:enabled"/> <int value="848324390" label="enable-lock-screen-apps"/> <int value="851085848" label="enable-settings-window"/> <int value="854730848" label="disable-app-info-dialog-mac"/> <int value="855746780" label="disable-physical-keyboard-autocorrect"/> <int value="857445869" label="enable-captive-portal-bypass-proxy"/> + <int value="860336036" label="ChromeModernDesign:enabled"/> <int value="862453793" label="TranslateUI2016Q2:enabled"/> <int value="867512869" label="mark-non-secure-as"/> <int value="869531646" label="enable-session-crashed-bubble"/> + <int value="871713352" label="ImprovedLanguageSettings:enabled"/> + <int value="878773995" label="ChromeHomeBottomNavLabels:disabled"/> <int value="879699575" label="disable-gesture-tap-highlight"/> <int value="879992337" label="disable-pull-to-refresh-effect"/> <int value="880510010" label="enable-permissions-bubbles"/> @@ -24117,19 +26558,23 @@ <int value="908523940" label="PassiveEventListenersDueToFling:disabled"/> <int value="909439558" label="disable-device-discovery"/> <int value="916316159" label="disable-new-app-list-mixer"/> + <int value="918046854" label="NtlmV2Enabled:disabled"/> <int value="926852901" label="DataReductionProxyMainMenu:disabled"/> <int value="929462705" label="disable-link-disambiguation-popup"/> <int value="935655516" label="password-import-export:disabled"/> <int value="936341613" label="OfflinePagesCT:disabled"/> <int value="936919953" label="bypass-app-banner-engagement-checks"/> <int value="938191241" label="VrShell:enabled"/> + <int value="939366135" label="DownloadsLocationChange:disabled"/> <int value="939554480" label="enable-credit-card-scan"/> <int value="939603162" label="BackgroundLoadingForDownloads:disabled"/> <int value="941036016" label="ContentSuggestionsSettings:disabled"/> <int value="943319566" label="enable-intent-picker"/> <int value="946688335" label="OmniboxSpareRenderer:disabled"/> <int value="952558794" label="enable-remote-assistance"/> + <int value="955340765" label="ChromeHomeOptOutSnackbar:enabled"/> <int value="963457392" label="ChromeHomeModernLayout:disabled"/> + <int value="975104092" label="show-taps"/> <int value="979445973" label="OmniboxSpareRenderer:enabled"/> <int value="980396200" label="enable-new-korean-ime"/> <int value="981818901" label="AppBanners:enabled"/> @@ -24138,12 +26583,17 @@ <int value="983311394" label="tab-management-experiment-type"/> <int value="986796748" label="AccountConsistency:enabled"/> <int value="988981463" label="ImageCaptureAPI:enabled"/> + <int value="989062160" label="ModuleScriptsImportMetaUrl:enabled"/> <int value="996797157" label="V8ContextSnapshot:enabled"/> <int value="1000706989" label="AutomaticTabDiscarding:disabled"/> <int value="1002585107" label="emphasize-titles-in-omnibox-dropdown"/> <int value="1003002105" label="MaterialDesignBookmarks:disabled"/> + <int value="1004909189" + label="ContentSuggestionsThumbnailDominantColor:disabled"/> + <int value="1005684777" label="PictureInPicture:disabled"/> <int value="1007444341" label="enable-prefixed-encrypted-media"/> <int value="1015895665" label="drop-sync-credential:enabled"/> + <int value="1017364362" label="VrIconInDaydreamHome:enabled"/> <int value="1018998019" label="memlog"/> <int value="1019623058" label="ash-enable-shelf-model-synchronization"/> <int value="1019857902" @@ -24153,6 +26603,7 @@ <int value="1033597574" label="disable-layer-squashing"/> <int value="1036068554" label="enable-android-pay-integration-v2"/> <int value="1043334401" label="disable-slimming-paint-invalidation"/> + <int value="1046878091" label="PasswordForceSaving:enabled"/> <int value="1049885154" label="OfflinePagesPrefetching:disabled"/> <int value="1050048304" label="enable-font-cache-scaling"/> <int value="1050321458" label="new-profile-management"/> @@ -24161,14 +26612,18 @@ <int value="1060319397" label="enable-data-reduction-proxy-carrier-test"/> <int value="1062357243" label="remember-cert-error-decisions"/> <int value="1064288458" label="OfflineRecentPages:enabled"/> + <int value="1067197792" label="memlog-keep-small-allocations"/> <int value="1067618884" label="enable-experimental-input-view-features"/> <int value="1067990299" label="enable-ui-devtools"/> <int value="1070164693" label="MidiManagerDynamicInstantiation:disabled"/> <int value="1070300488" label="disable-webgl"/> <int value="1070449228" label="ContextualSuggestionsCarousel:enabled"/> + <int value="1072010558" label="NTPModernLayout:disabled"/> <int value="1074359194" label="UseSuggestionsEvenIfFew:enabled"/> + <int value="1075637651" label="disable-tablet-splitview"/> <int value="1079032226" label="ParallelDownloading:enabled"/> <int value="1081546525" label="ash-enable-docked-windows"/> + <int value="1082405724" label="AutofillUpstreamUseGooglePayBranding:enabled"/> <int value="1087235172" label="file-manager-enable-new-audio-player"/> <int value="1090377940" label="enable-quic-https"/> <int value="1092896354" label="EnableFullscreenAppList:disabled"/> @@ -24187,9 +26642,10 @@ <int value="1126061778" label="CaptureThumbnailOnLoadFinished:enabled"/> <int value="1127183523" label="PassiveEventListenersDueToFling:enabled"/> <int value="1127427821" label="OmniboxEntitySuggestions:disabled"/> - <int value="1127900329" label="AutofillUpstreamShowNewUi:enabled"/> <int value="1129888794" label="ash-touch-hud"/> <int value="1133635187" label="force-gpu-rasterization"/> + <int value="1137429237" + label="AutofillCreditCardDropdownGooglePayBranding:enabled"/> <int value="1139226452" label="enable-nacl-debug"/> <int value="1139363314" label="disable-supervised-user-blacklist"/> <int value="1142515376" label="enable-nacl"/> @@ -24202,6 +26658,7 @@ <int value="1163255347" label="ash-enable-touch-view-touch-feedback"/> <int value="1166169237" label="disable-delay-agnostic-aec"/> <int value="1167613030" label="enable-permission-action-reporting"/> + <int value="1169418814" label="ManualFallbacksFilling:enabled"/> <int value="1174088940" label="enable-wasm"/> <int value="1179013979" label="OmniboxUIExperimentMaxAutocompleteMatches:enabled"/> @@ -24221,13 +26678,16 @@ <int value="1214455758" label="VideoRotateToFullscreen:disabled"/> <int value="1215531732" label="OmniboxUIExperiments:disabled"/> <int value="1217907443" label="spurious-power-button-keyboard-accel"/> + <int value="1219317631" label="ContextualSuggestionsAboveArticles:disabled"/> <int value="1219628795" label="PrintScaling:disabled"/> <int value="1219826373" label="ServiceWorkerNavigationPreload:enabled"/> <int value="1220171692" label="SpeculativeLaunchServiceWorker:enabled"/> + <int value="1220274247" label="AllowReaderForAccessibility:disabled"/> <int value="1220464509" label="enable-first-run-ui-transitions"/> <int value="1221559505" label="enable-spelling-feedback-field-trial"/> <int value="1222017136" label="WebRtcUseEchoCanceller3:disabled"/> <int value="1235800887" label="V8Ignition:enabled"/> + <int value="1235940786" label="ChromeHomePersistentIph:enabled"/> <int value="1237297772" label="no-pings"/> <int value="1240073971" label="ash-disable-smooth-screen-rotation"/> <int value="1242632259" label="ContentSuggestionsCategoryOrder:disabled"/> @@ -24237,6 +26697,7 @@ <int value="1253698118" label="ash-disable-stable-overview-order"/> <int value="1257980502" label="disable-accelerated-video-decode"/> <int value="1260186484" label="spurious-power-button-screen-accel"/> + <int value="1261713150" label="ChromeHomeOptOutSnackbar:disabled"/> <int value="1266886673" label="delay-reload-stop-button-change"/> <int value="1268470658" label="disable-android-password-link"/> <int value="1269940659" label="EnumerateAudioDevices:enabled"/> @@ -24246,6 +26707,7 @@ <int value="1276209777" label="ntp-switch-to-existing-tab"/> <int value="1279584261" label="enable-carrier-switching"/> <int value="1280614081" label="show-overdraw-feedback"/> + <int value="1283908088" label="ImprovedLanguageSettings:disabled"/> <int value="1283956865" label="force-tablet-mode"/> <int value="1283960113" label="disable-fixed-position-compositing"/> <int value="1284910808" label="disable-checker-imaging"/> @@ -24261,10 +26723,12 @@ <int value="1314681756" label="NoStatePrefetch:disabled"/> <int value="1317562265" label="SeccompSandboxAndroid:disabled"/> <int value="1318073661" label="MaterialDesignExtensions:enabled"/> + <int value="1319068611" label="SecondaryUiMd:disabled"/> <int value="1319725131" label="enable-distance-field-text"/> <int value="1320201920" label="enable-touchpad-three-finger-click"/> - <int value="1330029351" label="AutofillUpstreamShowGoogleLogo:disabled"/> <int value="1330264457" label="OmniboxUIExperimentVerticalLayout:disabled"/> + <int value="1333847867" label="NoScriptPreviews:enabled"/> + <int value="1339426771" label="TopSitesFromSiteEngagement:disabled"/> <int value="1340690624" label="WebPaymentsMethodSectionOrderV2:disabled"/> <int value="1344833841" label="ImeThread:enabled"/> <int value="1351830811" label="do-not-ignore-autocomplete-off"/> @@ -24294,11 +26758,15 @@ <int value="1389729816" label="data-reduction-proxy-lo-fi"/> <int value="1397069250" label="NetworkService:disabled"/> <int value="1405459667" label="enable-fast-text-autosizing"/> + <int value="1406046556" label="enable-slimming-paint-v175"/> <int value="1406354320" label="MacViewsWebUIDialogs:enabled"/> <int value="1407625309" label="disable-minimize-on-second-launcher-item-click"/> + <int value="1408139320" label="disable-zip-archiver-packer"/> <int value="1408331660" label="enhanced-bookmarks-experiment"/> + <int value="1409437197" label="OfflinePagesLimitlessPrefetching:enabled"/> <int value="1410697724" label="mediadrm-enable-non-compositing"/> + <int value="1413948819" label="NupPrinting:enabled"/> <int value="1416592483" label="ash-enable-mirrored-screen"/> <int value="1418054870" label="SpecialLocale:enabled"/> <int value="1421620678" label="simple-clear-browsing-data-support-string"/> @@ -24309,10 +26777,13 @@ <int value="1441897340" label="AndroidSpellCheckerNonLowEnd:enabled"/> <int value="1442798825" label="enable-quic"/> <int value="1442830837" label="MemoryAblation:disabled"/> + <int value="1449729378" + label="AutofillUseNewSettingsNameInDropdown:disabled"/> <int value="1452546183" label="PwaPersistentNotification:enabled"/> <int value="1454143461" label="CaptureThumbnailOnNavigatingAway:disabled"/> <int value="1454363479" label="disable-storage-manager"/> <int value="1454527518" label="ArcNativeBridgeExperiment:enabled"/> + <int value="1455881930" label="V8VmFuture:enabled"/> <int value="1458583431" label="arc-use-auth-endpoint"/> <int value="1459529277" label="disable-text-input-focus-manager"/> <int value="1460747747" label="GdiTextPrinting:enabled"/> @@ -24321,9 +26792,11 @@ <int value="1466380480" label="enable-device-discovery-notifications"/> <int value="1466502102" label="DelayNavigation:disabled"/> <int value="1469407485" label="disable-accelerated-2d-canvas"/> + <int value="1474861626" label="disable-multi-mirroring"/> <int value="1479248574" label="disable-voice-input"/> <int value="1481562816" label="disable-password-link"/> <int value="1486171015" label="disable-fill-on-account-select"/> + <int value="1488700164" label="password-import:disabled"/> <int value="1489915799" label="disable-permissions-blacklist"/> <int value="1490043732" label="enable-fill-on-account-select"/> <int value="1490255042" label="enable-overlay-scrollbar"/> @@ -24338,45 +26811,57 @@ <int value="1510659184" label="MacMDDownloadShelf:enabled"/> <int value="1511140997" label="OfflinePagesAsyncDownload:disabled"/> <int value="1511161758" label="BackgroundLoader:enabled"/> - <int value="1512249489" label="ModuleScripts:disabled"/> <int value="1514036945" label="OmniboxUIExperimentElideSuggestionUrlAfterHost:disabled"/> <int value="1514119870" label="enable-file-manager-touch-mode"/> <int value="1515196403" label="fast-user-switching"/> <int value="1517863401" label="history-entry-requires-user-gesture"/> <int value="1529979182" label="EnablePasswordSelection:enabled"/> + <int value="1530177325" label="LanguagesPreference:disabled"/> <int value="1533111748" label="Multidevice:enabled"/> + <int value="1536921097" label="NavigationMojoResponse:disabled"/> <int value="1538690515" label="OneGoogleBarOnLocalNtp:enabled"/> <int value="1541723759" label="ServiceWorkerNavigationPreload:disabled"/> <int value="1548776701" label="AllBookmarks:disabled"/> <int value="1548942246" label="PassiveDocumentEventListeners:disabled"/> <int value="1560188739" label="reader-mode-heuristics"/> + <int value="1563255033" label="memlog-stack-mode"/> + <int value="1567839560" + label="ChromeHomePersonalizedOmniboxSuggestions:disabled"/> <int value="1579461102" label="MemoryCoordinator:disabled"/> <int value="1586022426" label="AutofillCreditCardAssist:enabled"/> <int value="1589341623" label="disable-easy-unlock"/> + <int value="1591653786" label="SpeculativePreconnect:enabled"/> <int value="1594247626" label="ContentSuggestionsSettings:enabled"/> + <int value="1594664550" label="NTPModernLayout:enabled"/> <int value="1600926040" label="TranslateCompactUI:enabled"/> <int value="1605611615" label="enable-webrtc-srtp-aes-gcm"/> <int value="1612446645" label="enable-weak-memorycache"/> <int value="1612871297" label="WebPayments:disabled"/> <int value="1612974229" label="allow-insecure-localhost"/> + <int value="1615988672" label="GrantNotificationsToDSE:enabled"/> <int value="1617187093" label="enable-improved-a2hs"/> + <int value="1621298798" label="VrBrowserKeyboard:enabled"/> <int value="1622131033" label="ozone-test-single-overlay-support"/> <int value="1626824478" label="ExperimentalAppBanners:disabled"/> + <int value="1630988998" label="VrBrowsingExperimentalRendering:disabled"/> <int value="1632112977" label="ash-disable-tablet-autohide-titlebars"/> <int value="1633456034" label="chrome-home-swipe-logic"/> <int value="1634897915" label="password-import-export:enabled"/> + <int value="1634980726" label="VrShellExperimentalRendering:disabled"/> <int value="1636962093" label="disable-material-design-ntp"/> <int value="1646498561" label="OfflineBookmarks:disabled"/> <int value="1657713458" label="disable-virtual-keyboard-overscroll"/> <int value="1658644418" label="disable-app-list-voice-search"/> <int value="1659082220" label="EnableManualSaving:disabled"/> + <int value="1659372520" label="WebXrRenderPath:disabled"/> <int value="1661925474" label="silent-debugger-extension-api"/> <int value="1664401033" label="ColorCorrectRendering:enabled"/> <int value="1665349789" label="spurious-power-button-window"/> + <int value="1667584730" label="WebXR:disabled"/> <int value="1668611601" label="enable-encrypted-media"/> <int value="1670161209" label="ClickToOpenPDFPlaceholder:enabled"/> - <int value="1672878289" label="PwaMinimalUi:disabled"/> + <int value="1670799163" label="ChromeHomeShowGoogleGWhenUrlCleared:enabled"/> <int value="1673427566" label="ChromeHomeExpandButton:disabled"/> <int value="1689123607" label="enable-app-link"/> <int value="1689183477" label="enable-merge-key-char-events"/> @@ -24387,9 +26872,11 @@ <int value="1697189972" label="WebPaymentsSingleAppUiSkip:disabled"/> <int value="1700394127" label="OverlayScrollbar:disabled"/> <int value="1701972870" label="NTPSnippetsIncreasedVisibility:enabled"/> + <int value="1702090999" label="ClearOldBrowsingData:disabled"/> <int value="1702821235" label="WebAssembly:enabled"/> <int value="1705724232" label="use-android-midi-api"/> <int value="1713230497" label="ColorCorrectRendering:disabled"/> + <int value="1715338237" label="ContextualSearchSecondTap:disabled"/> <int value="1716104463" label="enable-fullscreen-app-list"/> <int value="1717987538" label="NTPTilesLowerResolutionFavicons:enabled"/> <int value="1719189460" label="EnablePasswordSelection:disabled"/> @@ -24401,6 +26888,7 @@ <int value="1731522433" label="enable-offer-store-unmasked-wallet-cards"/> <int value="1733390925" label="force-enable-stylus-tools"/> <int value="1735934914" label="OverlayScrollbarFlashWhenMouseEnter:disabled"/> + <int value="1739456903" label="PWAFullCodeCache:enabled"/> <int value="1747279677" label="disable-delegated-renderer"/> <int value="1752168018" label="enable-stale-while-revalidate"/> <int value="1762320532" label="AutofillKeyboardAccessory:enabled"/> @@ -24417,6 +26905,8 @@ <int value="1786386775" label="TranslateCompactUI:disabled"/> <int value="1789517771" label="MacV2Sandbox:enabled"/> <int value="1803465156" label="enable-zero-suggest-most-visited"/> + <int value="1809323887" + label="AutofillUpstreamUseGooglePayBranding:disabled"/> <int value="1809940714" label="SpeculativeLaunchServiceWorker:disabled"/> <int value="1812368073" label="enable-new-app-list-mixer"/> <int value="1814671708" label="disable-password-manager-reauthentication"/> @@ -24426,27 +26916,34 @@ <int value="1820317896" label="NTPShowGoogleGInOmnibox:disabled"/> <int value="1820451991" label="enable-offline-auto-reload"/> <int value="1821723343" label="disable-saml-signin"/> + <int value="1825940786" label="ChromeHomePromo:disabled"/> <int value="1827369558" label="AndroidPayIntegrationV1:disabled"/> <int value="1828660283" label="enable-webfonts-intervention-trigger"/> + <int value="1830460973" label="disable-network-settings-config"/> + <int value="1831593339" label="stop-in-background:disabled"/> <int value="1831835753" label="MaterialDesignIncognitoNTP:enabled"/> + <int value="1835523483" label="OmniboxUIExperimentSwapTitleAndUrl:enabled"/> <int value="1838990777" label="V8Future:enabled"/> <int value="1839740266" label="LocationHardReload:disabled"/> <int value="1844110073" label="enable-app-view"/> <int value="1847024354" label="enable-hotword-hardware"/> <int value="1849379463" label="OfflinePagesCTV2:enabled"/> - <int value="1851085023" label="PwaMinimalUi:enabled"/> + <int value="1851358497" label="enable-ash-sidebar"/> <int value="1852630189" label="NTPBookmarkSuggestions:disabled"/> <int value="1855524566" label="allow-insecure-websocket-from-https-origin"/> + <int value="1858385315" label="ChromeHomeBottomNavLabels:enabled"/> <int value="1860597983" label="AndroidSpellChecker:disabled"/> <int value="1861251313" label="enable-message-center-always-scroll-up-upon-notification-removal"/> <int value="1862207743" label="enable-android-spellchecker"/> + <int value="1863622457" label="WebAuthentication:enabled"/> <int value="1865068568" label="disable-audio-support-for-desktop-share"/> <int value="1865799183" label="javascript-harmony"/> <int value="1865963858" label="tls13-variant"/> <int value="1866079109" label="team-drives"/> <int value="1867085340" label="brotli-encoding:enabled"/> <int value="1872185826" label="LocationHardReload:enabled"/> + <int value="1874195462" label="ChromeHomeMenuItemsExpandSheet:disabled"/> <int value="1874604540" label="UseSuggestionsEvenIfFew:disabled"/> <int value="1878331098" label="GuestViewCrossProcessFrames:enabled"/> <int value="1881036528" label="disable-multilingual-spellchecker"/> @@ -24454,6 +26951,7 @@ <int value="1889076955" label="disable-app-link"/> <int value="1891210939" label="enable-blink-features"/> <int value="1892201400" label="enable-password-separated-signin-flow"/> + <int value="1892640848" label="third-party-doodle-url"/> <int value="1893317228" label="WebPayments:enabled"/> <int value="1893463366" label="EnableHtmlBaseUsernameDetector:enabled"/> <int value="1896456311" label="enable-password-save-in-page-navigation"/> @@ -24461,6 +26959,7 @@ <int value="1900529524" label="disable-touch-drag-drop"/> <int value="1905465678" label="ContextualSearchSingleActions:enabled"/> <int value="1906942630" label="enable-easy-unlock"/> + <int value="1907859249" label="ash-disable-trilinear-filtering"/> <int value="1910240042" label="enable-experimental-fullscreen-exit-ui"/> <int value="1913298816" label="OverlayScrollbar:enabled"/> <int value="1915178511" label="disable-blink-features"/> @@ -24469,13 +26968,16 @@ <int value="1928407249" label="NewPhotoPicker:enabled"/> <int value="1930901873" label="disable-sync-app-list"/> <int value="1931309368" label="fill-on-account-select:disabled"/> + <int value="1932732886" label="OpenVR:enabled"/> <int value="1936810062" label="WebVrVsyncAlign:enabled"/> <int value="1939413645" label="enable-invalid-cert-collection"/> <int value="1942911276" label="enable-grouped-history"/> <int value="1944156526" label="sync-url"/> <int value="1947350992" label="drop-sync-credential:disabled"/> + <int value="1949908940" label="disable-zip-archiver-unpacker"/> <int value="1951466218" label="enable-data-reduction-proxy-lite-page"/> <int value="1955677113" label="trace-export-events-to-etw"/> + <int value="1957358530" label="ContextualSearchSecondTap:enabled"/> <int value="1958387645" label="ScanCardsInWebPayments:enabled"/> <int value="1959148757" label="OffMainThreadFetch:enabled"/> <int value="1960169775" label="NewPhotoPicker:disabled"/> @@ -24483,11 +26985,13 @@ <int value="1964816410" label="AndroidPayIntegrationV2:enabled"/> <int value="1966730288" label="disable-threaded-compositing"/> <int value="1969604362" label="enable-pinch-virtual-viewport"/> + <int value="1971964569" label="NewEncodeCpuLoadEstimator:disabled"/> <int value="1980011075" label="debug-packed-apps"/> <int value="1980648371" label="PointerEventV1SpecCapturing:enabled"/> <int value="1988506961" label="EnableManualSaving:enabled"/> <int value="1989051182" label="view-passwords:enabled"/> <int value="1989877708" label="PostScriptPrinting:enabled"/> + <int value="1991771852" label="LeftToRightUrls:enabled"/> <int value="1991912338" label="ModuleScriptsDynamicImport:enabled"/> <int value="1992466116" label="enable-passive-event-listeners-due-to-fling"/> <int value="1993258379" label="enable-icon-ntp"/> @@ -24498,20 +27002,25 @@ <int value="2000091128" label="enable-touch-hover"/> <int value="2001562962" label="enable-manual-fallback-for-password-saving:enabled"/> + <int value="2002573873" label="ChromeHomeMenuItemsExpandSheet:enabled"/> + <int value="2003568209" label="TouchpadAndWheelScrollLatching:disabled"/> <int value="2003811018" label="enable-touch-support-for-screen-magnifier"/> <int value="2004483175" label="multi-instance-merge-tabs"/> <int value="2004829262" label="enable-webgl-draft-extensions"/> <int value="2005614493" label="tab-management-experiment-type-dill"/> <int value="2014331873" label="NTPDownloadSuggestions:disabled"/> <int value="2014629801" label="view-passwords:disabled"/> + <int value="2015547864" label="NetworkServiceInProcess:enabled"/> <int value="2020107447" label="AndroidPayIntegrationV1:enabled"/> + <int value="2032558514" + label="RemoveUsageOfDeprecatedGaiaSigninEndpoint:enabled"/> <int value="2037756154" label="enable-impl-side-painting"/> <int value="2043321329" label="OfflinePagesPrefetchingUI:disabled"/> <int value="2056572020" label="EnableUsernameCorrection:disabled"/> <int value="2059322877" label="new-avatar-menu"/> <int value="2063091429" label="OfflinePagesSharing:enabled"/> <int value="2067634730" label="LsdPermissionPrompt:disabled"/> - <int value="2067923510" label="ModuleScripts:enabled"/> + <int value="2067735898" label="WebVrAutopresentFromIntent:enabled"/> <int value="2071340353" label="progress-bar-completion"/> <int value="2071461362" label="disable-credit-card-scan"/> <int value="2076787478" label="OmniboxDisplayTitleForCurrentUrl:disabled"/> @@ -24519,11 +27028,15 @@ <int value="2077917024" label="enable-supervised-user-managed-bookmarks-folder"/> <int value="2079672348" label="ExperimentalKeyboardLockUI:disabled"/> + <int value="2085186092" label="BulkPrinters:disabled"/> <int value="2085438501" label="ChromeHome:enabled"/> <int value="2089897928" label="enable-audio-focus"/> + <int value="2092605092" label="ChromeHomeShowGoogleGWhenUrlCleared:disabled"/> <int value="2093235103" label="default-tile-width"/> + <int value="2093949489" label="ArrayPrototypeValues:enabled"/> <int value="2097048479" label="disable-auto-hiding-toolbar-threshold"/> <int value="2098714203" label="enable-generic-sensors"/> + <int value="2098907258" label="UseSurfaceLayerForVideo:disabled"/> <int value="2101151142" label="disable-direct-write"/> <int value="2104788328" label="use-winrt-midi-api"/> <int value="2119964154" label="enable-download-resumption"/> @@ -24534,9 +27047,11 @@ <int value="2123567684" label="OptimizeLoadingIPCForSmallResources:enabled"/> <int value="2126203058" label="force-show-update-menu-badge"/> <int value="2129184006" label="NTPOfflinePageDownloadSuggestions:enabled"/> + <int value="2129251171" label="memlog-sampling"/> <int value="2129929643" label="enable-use-zoom-for-dsf"/> <int value="2137347307" label="enable-drive-apps-in-app-list"/> <int value="2137599770" label="enable-win32k-renderer-lockdown"/> + <int value="2139048614" label="UseSurfaceLayerForVideo:enabled"/> <int value="2141463681" label="enable-offer-upload-credit-cards"/> <int value="2142979536" label="EnableManualFallbacksFilling:disabled"/> </enum> @@ -24670,6 +27185,16 @@ </int> </enum> +<enum name="LoginScreenUserClickTarget"> + <int value="0" label="Shut down button"/> + <int value="1" label="Restart button"/> + <int value="2" label="BrowseAsGuest"/> + <int value="3" label="AddUser"/> + <int value="4" label="System tray"/> + <int value="5" label="Virtual keyboard tray"/> + <int value="6" label="IME tray"/> +</enum> + <enum name="LoginStateKeyGenerationStatus"> <summary>The result of a state key generation operation.</summary> <int value="0" label="GENERATION_METHOD_IDENTIFIER_HASH"> @@ -24810,6 +27335,12 @@ </int> </enum> +<enum name="MalformedResponseResult"> + <int value="0" label="Success"/> + <int value="1" label="Malformed"/> + <int value="2" label="Other failure"/> +</enum> + <enum name="ManagedUserPasswordChange"> <int value="0" label="OK_MANAGER">Changed in manager session</int> <int value="1" label="OK_MANGED">Changed in supervised user session</int> @@ -24840,10 +27371,12 @@ <int value="0" label="Fetch succeeded"/> <int value="1" label="Fetch failed because of empty URL"/> <int value="2" label="Fetch failed (unspecified reason)"/> + <int value="3" label="Fetch failed because the document origin is unique"/> </enum> <enum name="MappedCSSProperties"> -<!-- Generated from third_party/WebKit/Source/core/frame/UseCounter.cpp --> +<!-- Generated from third_party/WebKit/Source/core/frame/UseCounter.cpp. +Called by update_use_counter_css.py.--> <int value="1" label="Total Pages Measured"/> <int value="2" label="color"/> @@ -25400,7 +27933,7 @@ <int value="553" label="min-block-size"/> <int value="554" label="max-inline-size"/> <int value="555" label="max-block-size"/> - <int value="556" label="alias-line-break"/> + <int value="556" label="line-break"/> <int value="557" label="place-content"/> <int value="558" label="place-items"/> <int value="559" label="transform-box"/> @@ -25417,21 +27950,24 @@ <int value="570" label="scroll-padding-inline"/> <int value="571" label="scroll-padding-inline-start"/> <int value="572" label="scroll-padding-inline-end"/> - <int value="573" label="scroll-snap-margin"/> - <int value="574" label="scroll-snap-margin-top"/> - <int value="575" label="scroll-snap-margin-right"/> - <int value="576" label="scroll-snap-margin-bottom"/> - <int value="577" label="scroll-snap-margin-left"/> - <int value="578" label="scroll-snap-margin-block"/> - <int value="579" label="scroll-snap-margin-block-start"/> - <int value="580" label="scroll-snap-margin-block-end"/> - <int value="581" label="scroll-snap-margin-inline"/> - <int value="582" label="scroll-snap-margin-inline-start"/> - <int value="583" label="scroll-snap-margin-inline-end"/> + <int value="573" label="scroll-margin"/> + <int value="574" label="scroll-margin-top"/> + <int value="575" label="scroll-margin-right"/> + <int value="576" label="scroll-margin-bottom"/> + <int value="577" label="scroll-margin-left"/> + <int value="578" label="scroll-margin-block"/> + <int value="579" label="scroll-margin-block-start"/> + <int value="580" label="scroll-margin-block-end"/> + <int value="581" label="scroll-margin-inline"/> + <int value="582" label="scroll-margin-inline-start"/> + <int value="583" label="scroll-margin-inline-end"/> <int value="584" label="scroll-snap-stop"/> - <int value="585" label="scroll-boundary-behavior"/> - <int value="586" label="scroll-boundary-behavior-x"/> - <int value="587" label="scroll-boundary-behavior-y"/> + <int value="585" label="overscroll-behavior"/> + <int value="586" label="overscroll-behavior-x"/> + <int value="587" label="overscroll-behavior-y"/> + <int value="588" label="font-variant-east-asian"/> + <int value="589" label="text-decoration-skip-ink"/> + <int value="590" label="scroll-customization"/> </enum> <enum name="MappedEditingCommands"> @@ -25579,11 +28115,20 @@ </enum> <enum name="MarkHttpAsStatus"> + <obsolete> + Deprecated 12/2017. + </obsolete> <int value="0" label="Neutral (deprecated February 2017)"/> - <int value="1" label="Non-Secure"/> - <int value="2" label="Neutral with a verbose warning on sensitive fields"/> - <int value="3" label="Neutral with a verbose warning after editing a form"/> - <int value="4" label="Neutral with a verbose warning in Incognito mode"/> + <int value="1" label="Dangerous"/> + <int value="2" + label="Neutral with a verbose warning on sensitive fields (deprecated + October 2017)"/> + <int value="3" + label="Neutral with a verbose warning after editing a form (deprecated + October 2017)"/> + <int value="4" + label="Neutral with a verbose warning in Incognito mode (deprecated + October 2017)"/> <int value="5" label="Neutral with a verbose warning after editing a form or in Incognito mode"/> @@ -25714,6 +28259,11 @@ <int value="21" label="Gesture requirement overridden by play method."/> </enum> +<enum name="MediaEngagementSessionEvent"> + <int value="0" label="Created"/> + <int value="1" label="Significant Playback"/> +</enum> + <enum name="MediaGalleriesUsageType"> <int value="0" label="Gallery added from permission dialog"/> <int value="1" label="Gallery permission added from permission dialog"/> @@ -25791,6 +28341,11 @@ <int value="1" label="Has errors"/> </enum> +<enum name="MediaRecorderVEAUsed"> + <int value="0" label="Not used"/> + <int value="1" label="Used"/> +</enum> + <enum name="MediaRouteProviderResult"> <int value="0" label="UnknownError"/> <int value="1" label="Ok"/> @@ -25840,11 +28395,24 @@ <int value="2" label="ErrorTooManyRetries"/> </enum> +<enum name="MediaRouterCastChannelError"> + <int value="0" label="Unknown"/> + <int value="1" label="Authentication"/> + <int value="2" label="Connect"/> + <int value="3" label="General Certificate"/> + <int value="4" label="Certificate timing"/> + <int value="5" label="Network"/> + <int value="6" label="Connect Timeout"/> + <int value="7" label="Ping Timeout"/> +</enum> + <enum name="MediaRouterCastSinkSource"> <int value="0" label="NetworkCache"/> <int value="1" label="mDNS"/> <int value="2" label="DIAL"/> <int value="3" label="Connection retry"/> + <int value="4" label="First by mDNS, then by DIAL"/> + <int value="5" label="First by DIAL, then by mDNS"/> </enum> <enum name="MediaRouterCreateRouteOutcome"> @@ -25930,8 +28498,19 @@ <int value="8" label="Seek forward"/> </enum> +<enum name="MediaSinkType"> + <int value="0" label="Cast"/> + <int value="1" label="Cast Audio Group"/> + <int value="2" label="Cast Audio"/> + <int value="3" label="Meeting"/> + <int value="4" label="Hangout"/> + <int value="5" label="Cast for Education"/> + <int value="6" label="Wired Display"/> + <int value="7" label="Generic"/> +</enum> + <enum name="MediaStreamRequestResult"> - <int value="0" label="Ok"/> + <int value="0" label="OK"/> <int value="1" label="Permission Denied"/> <int value="2" label="Permission Dismissed"/> <int value="3" label="Invalid State"/> @@ -25944,6 +28523,25 @@ <int value="10" label="Track Start Failure"/> <int value="11" label="Not Supported"/> <int value="12" label="Failed due to shutdown"/> + <int value="13" label="Kill Switch On"/> +</enum> + +<enum name="MediaStreamRequestResult2"> + <int value="0" label="OK"/> + <int value="1" label="Permission Denied (NotAllowedError)"/> + <int value="2" label="Permission Dismissed (NotAllowedError)"/> + <int value="3" label="Invalid State (NotAllowedError)"/> + <int value="4" label="No Hardware (NotFoundError)"/> + <int value="5" label="Invalid Security Origin (SecurityError)"/> + <int value="6" label="Tab Capture Failure (AbortError)"/> + <int value="7" label="Screen Capture Failure (AbortError)"/> + <int value="8" label="Capture Failure (AbortError)"/> + <int value="9" label="Constraint Not Satisfied (OverconstrainedError)"/> + <int value="10" label="Audio Track Start Failure (NotReadableError)"/> + <int value="11" label="Video Track Start Failure (NotReadableError)"/> + <int value="12" label="Not Supported (NotSupportedError)"/> + <int value="13" label="Failed Due To Shutdown (NotAllowedError)"/> + <int value="14" label="Kill Switch On (NotAllowedError)"/> </enum> <enum name="MediaStreamRequestState"> @@ -26141,6 +28739,20 @@ <int value="2" label="Suspended"/> </enum> +<enum name="MenuSourceType"> + <int value="0" label="None"/> + <int value="1" label="Mouse"/> + <int value="2" label="Keyboard"/> + <int value="3" label="Touch"/> + <int value="4" label="Touch Edit Menu"/> + <int value="5" label="Long Press"/> + <int value="6" label="Long Tap"/> + <int value="7" label="Touch Handle"/> + <int value="8" label="Stylus"/> + <int value="9" label="Adjust Selection"/> + <int value="10" label="Adjust Selection Reset"/> +</enum> + <enum name="MessageLoopProblems"> <int value="0" label="Message Post"/> <int value="1" label="Completion Post"/> @@ -26268,6 +28880,7 @@ <int value="2" label="Migrating"/> <int value="3" label="Migration failed"/> <int value="4" label="Not enough storage"/> + <int value="5" label="Migrating minimal"/> </enum> <enum name="MigrationUIUserChoice"> @@ -26312,6 +28925,7 @@ <int value="6" label="No external storage"/> <int value="7" label="Cannot determine download target"/> <int value="8" label="Cancelled by native for other reasons"/> + <int value="9" label="Cancelled by user action"/> </enum> <enum name="MobileDownloadDuplicateInfobar"> @@ -26347,6 +28961,12 @@ <int value="4" label="Storage permission failed due to missing WebContents"/> </enum> +<enum name="MobileFreLinkTappedStatus"> + <int value="0" label="Link successfully loaded."/> + <int value="1" label="Link failed to load."/> + <int value="2" label="Link load did not complete."/> +</enum> + <enum name="MobileFreProgress"> <int value="0" label="FRE started"/> <int value="1" label="Welcome shown"/> @@ -26378,6 +28998,22 @@ <int value="4" label="Infobar dismissed after tab closed"/> </enum> +<enum name="MobileSessionCallerApp"> + <int value="0" label="Google Search"/> + <int value="1" label="Gmail"/> + <int value="2" label="Google+"/> + <int value="3" label="Google Drive"/> + <int value="4" label="Google Earth"/> + <int value="5" label="Other Google Apps"/> + <int value="6" label="Other"/> + <int value="7" label="Mobile Safari"/> + <int value="8" label="Other Apple Apps"/> + <int value="9" label="YouTube"/> + <int value="10" label="Google Maps"/> + <int value="11" label="Information not available"/> + <int value="12" label="Chrome Today Extension"/> +</enum> + <enum name="MobileSessionShutdownType"> <int value="0" label="Shutdown in background"/> <int value="1" label="Shutdown in foreground; no log; no memory warning"/> @@ -26387,6 +29023,16 @@ <int value="5" label="First launch after upgrade"/> </enum> +<enum name="MobileSessionStartAction"> + <int value="0" label="Open http"/> + <int value="1" label="Open https"/> + <int value="2" label="Open file"/> + <int value="3" label="x-callback-url open"/> + <int value="4" label="x-callback-url other"/> + <int value="5" label="Other"/> + <int value="6" label="x-callback-url app-group-command"/> +</enum> + <enum name="MobileStartingAction"> <int value="0" label="No activity"/> <int value="1" label="Open new tab"/> @@ -26484,6 +29130,7 @@ <int value="11" label="AC3"/> <int value="12" label="DOLBYVISION"/> <int value="13" label="FLAC"/> + <int value="14" label="AV1"/> </enum> <enum name="MultiAccountUpdateBubbleUserAction"> @@ -26507,6 +29154,27 @@ <int value="2" label="SUCCESS">All operations succeeded.</int> </enum> +<enum name="MultiDisplayModeDisplayCountRanges"> + <summary> + Defines the ranges in which the number of displays connected in multi + display mode may reside. + </summary> + <int value="0" label="2 displays"/> + <int value="1" label="(2 to 4] displays"/> + <int value="2" label="(4 to 6] displays"/> + <int value="3" label="(6 to 8] displays"/> + <int value="4" label="More than 8 displays"/> +</enum> + +<enum name="MultiDisplayModes"> + <summary> + Defines the modes in which displays connected to the device are in. + </summary> + <int value="0" label="Extended mode"/> + <int value="1" label="Mirroring mode"/> + <int value="2" label="Unified mode"/> +</enum> + <enum name="MultiProfileSessionMode"> <int value="0" label="Single user mode"/> <int value="1" label="Side by side mode"/> @@ -26826,30 +29494,30 @@ <int value="5" label="Active network was unblocked"/> </enum> -<enum name="NegativeSampleReason"> - <int value="0" - label="Persistent sparse histogram had logged value but no active - sample."/> +<enum name="NearOomDetectionEndReason"> + <int value="0" label="OOM protected renderer is crashed"/> <int value="1" - label="Persistent sparse histogram active sample less than logged - value."/> - <int value="2" - label="Persistent sparse histogram added a negative count during - iteration."/> + label="Foreground renderer is gone for some reason other than OOM crash"/> + <int value="2" label="Foreground renderer navigates to other URL"/> +</enum> + +<enum name="NegativeSampleReason"> + <int value="0" label="Histogram had logged value but no active sample."/> + <int value="1" label="Histogram active sample less than logged value."/> + <int value="2" label="Histogram added a negative count during iteration."/> <int value="3" - label="Persistent sparse histogram added negative count that caused - negative value."/> + label="Histogram added negative count that caused negative value."/> <int value="4" - label="Persistent sparse histogram active sample overflowed and became - negative."/> - <int value="5" - label="Persistent sparse histogram accumulated a negative count."/> + label="Histogram active sample overflowed and became negative."/> + <int value="5" label="Histogram accumulated a negative count."/> <int value="6" - label="Persistent sparse histogram accumulated a negative count that - caused a negative value."/> + label="Histogram accumulated a negative count that caused a negative + value."/> <int value="7" - label="Persistent sparse histogram active sample overflowed during - accumulation and became negative."/> + label="Histogram active sample was negative after accumulation + (deprecated)."/> + <int value="8" + label="Histogram active sample wrapped 2^31 during accumulation."/> </enum> <enum name="NetCacheState"> @@ -26897,7 +29565,8 @@ </enum> <enum name="NetErrorCodes"> -<!-- Generated from net/base/net_error_list.h --> +<!-- Generated from net/base/net_error_list.h. +Called by update_net_error_codes.py.--> <int value="0" label="OK"/> <int value="1" label="IO_PENDING"/> @@ -27005,6 +29674,7 @@ <int value="173" label="WS_UPGRADE"/> <int value="174" label="READ_IF_READY_NOT_IMPLEMENTED"/> <int value="175" label="SSL_VERSION_INTERFERENCE"/> + <int value="176" label="NO_BUFFER_SPACE"/> <int value="200" label="CERT_COMMON_NAME_INVALID"/> <int value="201" label="CERT_DATE_INVALID"/> <int value="202" label="CERT_AUTHORITY_INVALID"/> @@ -27139,30 +29809,93 @@ </enum> <enum name="NetErrorPageEvents"> - <int value="0" label="Error Page Shown"/> - <int value="1" label="Reload Button Shown"/> - <int value="2" label="Reload Button Clicked"/> - <int value="3" label="Reload Button Click Load Error"/> - <int value="4" label="Show Saved Copy Button Shown"/> - <int value="5" label="Show Saved Copy Button Clicked"/> - <int value="6" label="Show Saved Copy Button Click Load Error"/> - <int value="7" label="More Button Clicked"/> - <int value="8" label="Browser Initiated Reload"/> - <int value="9" label="Both Buttons Shown"/> - <int value="10" label="Both Buttons Shown, Reload Clicked"/> - <int value="11" label="Both Buttons Shown, Show Saved Copy Clicked"/> - <int value="12" label="Easter egg activated"/> - <int value="13" label="Show Cached Copy button shown"/> - <int value="14" label="Show Cached Copy button clicked"/> - <int value="15" label="Show Cached Page button shown"/> - <int value="16" label="Show Cached Page button clicked"/> - <int value="17" label="Diagnose button clicked"/> - <int value="18" label="Show Offline Pages Button Shown"/> - <int value="19" label="Show Offline Pages Button Clicked"/> - <int value="20" label="Show Offline Copy Button Shown"/> - <int value="21" label="Show Offline Copy Button Clicked"/> - <int value="22" label="Download Button Shown"/> - <int value="23" label="Download Button Clicked"/> + <int value="0" label="Error Page Shown"> + An error page was shown. This bucket encompasses all others and works as a + total count for error pages (instead of the histogram's total sample count + which doesn't reflect that information). + </int> + <int value="1" label="Reload Button Shown"> + An error page was shown with at least a "Reload" button on it. + </int> + <int value="2" label="Reload Button Clicked"> + An error page was shown with at least a "Reload" button on it and + the user pressed that button. + </int> + <int value="3" label="Reload Button Click Load Error"> + An error page was previously loaded with a "Reload" button and + another load error happened as a result of the user pressing that button. + </int> + <int value="4" label="Show Saved Copy Button Shown"> + An error page was shown with at least a "Show Saved Copy" button + on it. + </int> + <int value="5" label="Show Saved Copy Button Clicked"> + An error page was shown with at least a "Show Saved Copy" button + on it and the user pressed that button. + </int> + <int value="6" label="Show Saved Copy Button Click Load Error"> + An error page was previously loaded with a "Show Saved Copy" + button and another load error happened as a result of the user pressing that + button. + </int> + <int value="7" label="More Button Clicked"> + An error page was shown with at least a "More" (aka + "Details") button on it and the user pressed that button. + </int> + <int value="8" label="Browser Initiated Reload"> + An error page was previously loaded and the user started a reload by + pressing the browser's reload button. + </int> + <int value="9" label="Both Reload And Show Saved Copy Buttons Shown"> + An error page was shown with at least a "Reload" and a "Show + Saved Copy" buttons on it. Note that this is not exclusive with the + respective individual button buckets. + </int> + <int value="10" + label="Both Reload And Show Saved Copy Buttons Shown, Reload Clicked"> + An error page was shown with at least a "Reload" and a "Show + Saved Copy" buttons on it and the user pressed the "Reload" + button. Note that this is not exclusive with the respective individual + button buckets. + </int> + <int value="11" + label="Both Reload And Show Saved Copy Buttons Shown, Show Saved Copy + Clicked"> + An error page was shown with at least a "Reload" and a "Show + Saved Copy" buttons on it and the user pressed the "Show Saved + Copy" button. Note that this is not exclusive with the respective + individual button buckets. + </int> + <int value="12" label="Easter egg activated"> + An error page was shown with the offline dino image and and the user + activated it (to play the dino game). + </int> + <int value="13" label="Show Cached Copy button shown"> + An error page was shown with at least a "Show Cached Copy" button + on it. + </int> + <int value="14" label="Show Cached Copy button clicked"> + An error page was shown with at least a "Show Cached Copy" button + on it and the user pressed that button. + </int> + <int value="15" label="Show Cached Page button shown">Obsolete.</int> + <int value="16" label="Show Cached Page button clicked">Obsolete.</int> + <int value="17" label="Diagnose button clicked"> + An error page was shown with at least a "Diagnose Error" button on + it and the user pressed that button. + </int> + <int value="18" label="Show Offline Pages Button Shown">Obsolete.</int> + <int value="19" label="Show Offline Pages Button Clicked">Obsolete.</int> + <int value="20" label="Show Offline Copy Button Shown">Obsolete.</int> + <int value="21" label="Show Offline Copy Button Clicked">Obsolete.</int> + <int value="22" label="Download Button Shown"> + An error page was shown with at least a "Download Page Later" + button on it. + </int> + <int value="23" label="Download Button Clicked"> + An error page was shown with at least a "Download Page Later" + button on it and the user pressed that button. + </int> </enum> <enum name="NetFilterType"> @@ -27225,6 +29958,993 @@ <int value="8" label="subresource and used"/> </enum> +<enum name="NetTrustAnchors"> +<!-- Generated from net/data/ssl/root_stores/root_stores.json. +Called by update_net_trust_anchors.py.--> + + <int value="0" label="Unknown or locally-installed trust anchor"/> + <int value="1" + label="1d75d0831b9e0885394d32c7a1bfdb3dbc1c28e2b0e8391fb135981dbc5ba936"/> + <int value="2" + label="4691cbfde84a6b6052ddbe152bb0c216ae25a86e5747813dbc0f147f338570be"/> + <int value="3" + label="c73afc2eba770d0cbc1ee41f252b52e8a93d12b72dccec031d8d839cbf818a79"/> + <int value="4" + label="a99972ce1f6c581d0097f62618062e53157b5276e1ec6651a3157057f057b339"/> + <int value="5" + label="628e3a1156f6faa92f94b409258d4cba3f2047480d30194faf3fbed05eaeb5b2"/> + <int value="6" + label="2b071c59a0a0ae76b0eadb2bad23bad4580b69c3601b630c2eaf0613afa83f92"/> + <int value="7" + label="8a27b5557b4bec7cc0305fbf3d53d1f71cd3f34910c5d65e27ecddb82077ba3d"/> + <int value="8" + label="cbe5ac15d88b5cac3f81e6df3bfb57bea60958813a47b77f3c5cb6b98191bdb5"/> + <int value="9" + label="e2d891efb738669105d530de5ed72e2b2ac3f4a67078b5349b3fdaca496f5eb8"/> + <int value="10" + label="563b3caf8cfef34c2335caf560a7a95906e8488462eb75ac59784830df9e5b2b"/> + <int value="11" + label="9dd55fc573f546cb6a3831d1112d8710a6f4f82dc87f5fae9d3a1a028dd36e4b"/> + <int value="12" + label="772fccca7d1646d60628134ff2e6e7f5ba095898be59698bce9d15f96f69a9f3"/> + <int value="13" + label="3c35e164bedd2cf12beb83ecff78b5e80da8158d2830217e4ebffce8928899a6"/> + <int value="14" + label="3b45918205c591298a1922a58b4921d01f648fa9d28bdddfad24aeec5942cfbf"/> + <int value="15" + label="a81293445db196a2030f9e455fe3c74a9a4f8317b02b01406027a8708174434c"/> + <int value="16" + label="eca0f181402ce7a8652b31b4d036df247e3a30b7f41a50d91ec4f90b006b43a1"/> + <int value="17" + label="8d767764b3cbda08929d072a22a561f4dcdd1bc57d3cbddc948c47d2b47f9122"/> + <int value="18" + label="706bb1017c855c59169bad5c1781cf597f12d2cad2f63d1a4aa37493800ffb80"/> + <int value="19" + label="ced43902ab5fb57b442322dc0e172a4fb55f7178b808f94e780a6fd6cc6bd818"/> + <int value="20" + label="6bcfc86c8ddc2af2e6a1180a2ddabb37b7ea3755316b64b9b8951bf0ca351f06"/> + <int value="21" + label="5632d97bfa775bf3c99ddea52fc2553410864016729c52dd6524c8a9c3b4489f"/> + <int value="22" + label="15f14ac45c9c7da233d3479164e8137fe35ee0f38ae858183f08410ea82ac4b4"/> + <int value="23" + label="bcfb44aab9ad021015706b4121ea761c81c9e88967590f6f94ae744dc88b78fb"/> + <int value="24" + label="acf65e1d62cb58a2bafd6ffab40fb88699c47397cf5cb483d42d69cad34cd48b"/> + <int value="25" + label="b03d87b056d08cc9d4e675ef19ca83ab53532168a8258598be72e6d85c7dd7c1"/> + <int value="26" + label="c3bc6100f57e320d8659f22584677e56860aab1014e0084a496fff8c880b6ba3"/> + <int value="27" + label="32d180ed31c935589ec9dbbb722123b883b5fc2dc10f9fca3a95d77e1bfcb534"/> + <int value="28" + label="fcf7da983603e88862030d96137d8e13031badfb4d56c1fd4cacc339f6bdbb2a"/> + <int value="29" + label="e42f24bd4d37f4aa2e56b979d83d1e65219fe0e9e3a382a1b3cb66c93955de75"/> + <int value="30" + label="7e8782c150ce3952f802e636023a5d3e95bb5d68e33e85adb2ba178125cebf15"/> + <int value="31" + label="aff988906dde12955d9bebbf928fdcc31cce328d5b9384f21c8941ca26e20391"/> + <int value="32" + label="ce24eb0626defd8168c96a7701f09301600fe5dd0dbce58e9c97b830af02ef28"/> + <int value="33" + label="63d9af9b47b1064d49a10e7b7fd566dbc8caa399459bfc2829c571ad8c6ef34a"/> + <int value="34" + label="942a6916a6e4ae527711c5450247a2a74fb8e156a8254ca66e739a11493bb445"/> + <int value="35" + label="40fcfc28875dccbfebcbdf6cd7433312da63c4efcf3bd7b1b505c22020ae0274"/> + <int value="36" + label="05570ae6eb0fceb4210e6db79486b7094caf200401e149b6677441b5f25e449b"/> + <int value="37" + label="05e77ef1fdfe05e2dca522cae64d8379a041b7b4f16c7cae36067a7f72a14872"/> + <int value="38" + label="1ea3c5e43ed66c2da2983a42a4a79b1e906786ce9f1b58621419a00463a87d38"/> + <int value="39" + label="1a7a3a1a68dd2361e3f3bb855f3b26fcd88b197d8dd4de06cf1b362ac89ec13b"/> + <int value="40" + label="15e7e717b428feee3af3afd9150dbad497008d3a3ff016964719907bdb01a645"/> + <int value="41" + label="cb6e91711ad6d55c8906f379cb071fb5c47933654a7415612eee6629f26fbcd7"/> + <int value="42" + label="76ee8590374c715437bbca6bba6028eadde2dc6dbbb8c3f610e851f11d1ab7f5"/> + <int value="43" + label="c746127c5f6b529ce9e2948efd9465444089319acf03f34d0bf37eadc77db22f"/> + <int value="44" + label="952c2039c0243eb515dd73d83fc3643184874feb0862a9837731ed9b4742e17a"/> + <int value="45" + label="1069fa47a0aa4f8cf7111b1caea365eeaed10bfff32660def6e0614bfae70875"/> + <int value="46" + label="d1de2ae61c8df2fa623966163d4c73d460bfc428e57585be6bfeb9a56323d1b6"/> + <int value="47" + label="4002fcd311d07331567e71bcd971e46048c8dce8d1659711753b3daa2a269afa"/> + <int value="48" + label="b2def5362ad3facd04bd29047a43844f767034ea4892f80e56bee690243e2502"/> + <int value="49" + label="9318226f8c83afe47f5f47c24f59ce12dba8c73b181bee6b2ea1f40a06bc1869"/> + <int value="50" + label="967b0cd93fcef7f27ce2c245767ae9b05a776b0649f9965b6290968469686872"/> + <int value="51" + label="44af8afcf1395d2a8e30ef812ce19ceb2e8948dfd21e00fbaa34689f9a24721f"/> + <int value="52" + label="17755a5c295f3d2d72e6f031a1f07f400c588b9e582b22f17eae31a1590d1185"/> + <int value="53" + label="86c13a3408dd1aa77ee8b6947c03958772f531248c1627befb2c4f4b04d04496"/> + <int value="54" + label="ff5680cd73a5703da04817a075fd462506a73506c4b81a1583ef549478d26476"/> + <int value="55" + label="006d7be7555dd82026442c4f1a27a80e89a1989cb87b34448ed2194c18196d5e"/> + <int value="56" + label="43cffc359f2e8caa57388ee9f6f1dbe93bf093682a699ac3852e6d1f8579e7f9"/> + <int value="57" + label="be3db7b79bfe579dcf9b07ca4cad75aff16975568e5b45cfcae4d61fb63175a8"/> + <int value="58" + label="5192438ec369d7ee0ce71f5c6db75f941efbf72e58441715e99eab04c2c8acee"/> + <int value="59" + label="25d4913cf587097414d29d26f6c1b1942cd6d64eaf45d0fcf81526adba96d324"/> + <int value="60" + label="f48badd7df6a06690d0ae31373b12855f8dedb14517f362a313101cc98cc6b35"/> + <int value="61" + label="25aeec63f3ccd73dd61cb4fbbd13603722e02cb54e03047737084211071d7850"/> + <int value="62" + label="10ba3485ca8bb6880ab9531a4063e4001555561c7f2e055165f49b2d74fc5f6b"/> + <int value="63" + label="1906c6124dbb438578d00e066d5054c6c37f0fa6028c05545e0994eddaec8629"/> + <int value="64" + label="23f2edff3ede90259a9e30f40af8f912a5e5b3694e6938440341f6060e014ffa"/> + <int value="65" + label="9adb99c93ab256ecca2b5350c75048a8584c12dfc248e3f60ea9354c34ebfcce"/> + <int value="66" + label="9736ac3b25d16c45a45418a964578156480a8cc434541ddc5dd59233229868de"/> + <int value="67" + label="a6e11ff15ec326a5e3f18ad33a056694dc84c699766d028a5ad0efe1a8e53ac7"/> + <int value="68" + label="b638cff05c8a832758edc3028af9e2d55514568bc6bb34ab36d140b97ac6b12d"/> + <int value="69" + label="023c81cce8e7c64fa942d3c15048707d35d9bb5b87f4f544c5bf1bc5643af2fa"/> + <int value="70" + label="a6f1f9bf8a0a9ddc080fb49b1efc3d1a1c2c32dc0e136a5b00c97316f2a3dc11"/> + <int value="71" + label="bd153ed7b0434f6886b17bce8bbe84ed340c7132d702a8f4fa318f756ecbd6f3"/> + <int value="72" + label="b1124142a5a1a5a28819c735340eff8c9e2f8168fee3ba187f253bc1a392d7e2"/> + <int value="73" + label="051cf9fa95e40e9b83edaeda6961f6168c7879c4660172479cdd51ab03cea62b"/> + <int value="74" + label="36ecc61fc7e5f1923d167e67dfde34608549b34a63c7c6e60ffd5c1840381f5c"/> + <int value="75" + label="87af34d66fb3f2fdf36e09111e9aba2f6f44b207f3863f3d0b54b25023909aa5"/> + <int value="76" + label="9392ae2149924ade37e645dba1ff4bdddcda2b291b6097669d2afa5c7a372619"/> + <int value="77" + label="8fd112c3c8370f147d5ccd3a7d865eb8dd540783bac69fc60088e3743ff33378"/> + <int value="78" + label="0656f5955204c8d2bc8b1ca475e2a4fa6e124d124512784157c858b55471141a"/> + <int value="79" + label="495a96ba6bad782407bd521a00bace657bb355555e4bb7f8146c71bba57e7ace"/> + <int value="80" + label="5a889647220e54d6bd8a16817224520bb5c78e58984bd570506388b9de0f075f"/> + <int value="81" + label="5955ae291574a931342cf7450e16652ede1e0fb3097e1571dfac11c915601564"/> + <int value="82" + label="b4a039eafc4310ba9bde093edb8f9d9d0b3d4c7c004d48288c35dbcc19467d18"/> + <int value="83" + label="2a29337c3d6224cc53f0bb5e5d5820c0d8848b04871328f090fee3cd6bf821b4"/> + <int value="84" + label="808d68b3fab4884a5f971ace7d10550d7a95a163774f3ec36afffb213fbe4c74"/> + <int value="85" + label="94072ad3f58f70f93098e5a5f6c04c96c710bd849d83184919ae90eb890ae400"/> + <int value="86" + label="7caa03465124590c601e567e52148e952c0cffe89000530fe0d95b6d50eaae41"/> + <int value="87" + label="dbc1e3a15238a0483bcdb8fdec616e03e705a48e2a501157cadf3b9c7311c5e5"/> + <int value="88" + label="1f4224cec84fc99ced881ff6fcfd3e21f8c519c547aa6a5dd3de247302ce50d1"/> + <int value="89" + label="e7ca91bbfbb18788057b3a8070446ea5291160194102f7dcc3b9848c63cb9cd5"/> + <int value="90" + label="56174d3ad971a8944964b189811f3008493a6a90422e3c5804ec838d4f94f622"/> + <int value="91" + label="0c7acaa710226720bbc940349ee2e6148652a89dbf406a232c895f6dc78ebb9a"/> + <int value="92" + label="702116ccd8bf23e16466f0e0dba0ed6a239a9c1cd6a8f5a66b39af3595020385"/> + <int value="93" + label="aa2630a7b617b04d0a294bab7a8caaa5016e6dbe604837a83a85719fab667eb5"/> + <int value="94" + label="36c22314131a5fbf1b70ea4ccf4bc13a777d938ec65e1da24e3c2cfd01d3d163"/> + <int value="95" + label="4905466623ab4178be92ac5cbd6584f7a1e17f27652d5a85af89504ea239aaaa"/> + <int value="96" + label="f463c54d9f1a047aed52656ac785e07ebec528e0207bfd3f55d893237668f6ae"/> + <int value="97" + label="62554c17005543b237215f04268dcd2fd1c470240ad3c8660e25ae2c59630f55"/> + <int value="98" + label="6544ff9adb642c4c3698a60d8143b6b93bcef01365b540f614dcc2a45ab94d31"/> + <int value="99" + label="927a1b8562280576d048c50321ada43d8703d2d9521a18c28b8c46cc6aae4efd"/> + <int value="100" + label="4eada9b5311e718199d98ea82b95005cba93198ab1f97efcbe8dc6201628f8af"/> + <int value="101" + label="3861d7b6961fcdb2120456ff6fc2eb7704b1a741b4bd933a8376f5e1915ca698"/> + <int value="102" + label="2a4212605aa3e8aecb0fc19806cf3b40b53b95f1a34dbbd6e3ed27230324abb3"/> + <int value="103" + label="d2a5f32f0e01b910ef4e3b46bf84e5af5fb5689e7d1507e929e368ac88c6cc76"/> + <int value="104" + label="67dc4f32fa10e7d01a79a073aa0c9e0212ec2ffc3d779e0aa7f9c0f0e1c2c893"/> + <int value="105" + label="bb4128ec9620f2d2a49ce8e2c4e257aebad93a0f11c56b5fa4b00e23759fa39d"/> + <int value="106" + label="a4003bd5bdd894e01a8e01e06b62c7aa82f03de5253133570aad4fd0e7d81d3c"/> + <int value="107" + label="b21d2a743318712ba16f39919d961a4bafba3bca9a43a75b1fcfe22c5d70caba"/> + <int value="108" + label="c444b5b66ce5d71e1b5e40f27385c95cbfd24a05b56f70cac0992f0f50c3379c"/> + <int value="109" + label="2bcee858158cf5465fc9d76f0dfa312fef25a4dca8501da9b46b67d1fbfa1b64"/> + <int value="110" + label="fea2b7d645fba73d753c1ec9a7870c40e1f7b0c561e927b985bf711866e36f22"/> + <int value="111" + label="92c46879626ef2cc1ecea50c72fb5e385844095f21cbf3b283cb82e6b9fc6a58"/> + <int value="112" + label="e5ca37bc7b6c361979bc6b123ca9a1db019046d7ff5f57dfb854b19d10b0682f"/> + <int value="113" + label="2a8f2d8af0eb123898f74c866ac3fa669054e23c17bc7a95bd0234192dc635d0"/> + <int value="114" + label="093db767888f6b1327555dbd42bb5c93fedec5044c7a84bc6ea32a578c2235c0"/> + <int value="115" + label="23849d094923d44a4881b63ab185e9be15aac8ef2c3044d934bc7f26e2d2cd69"/> + <int value="116" + label="2596904dc4d699ae20c2cef4dce47f285937d77464ac370746f52dea76ba0c28"/> + <int value="117" + label="6dbfae00d37b9cd73f8fb47de65917af00e0dddf42dbceac20c17c0275ee2095"/> + <int value="118" + label="f53c22059817dd96f400651639d2f857e21070a59abed9079400d9f695506900"/> + <int value="119" + label="fac95de3c24a174194800cffaa3ca51d7116630664a9b60c8758b4ef0dc58f88"/> + <int value="120" + label="a87443b3d896eb257ccce99b95ada9bc81b9db4e3142aa9a99af0942cb0a4a3a"/> + <int value="121" + label="567b8211fd20d3d283ee0cd7ce0672cb9d99bc5b487a58c9d54ec67f77d4a8f5"/> + <int value="122" + label="ab98495276adf1ecaff28f35c53048781e5c1718dab9c8e67a504f4f6a51328f"/> + <int value="123" + label="fd872d176617e50c266119d0fdb047b0732da2048b121af7b9860ca3e2f2f2be"/> + <int value="124" + label="c1ad1b1898ec395048df070bfa217e25c913bed8ca6b73de085528846a0103c1"/> + <int value="125" + label="3219b09114ff495a3eb6eb00c2efeab34002ae5f0a56c7679ea087a3fa037e4f"/> + <int value="126" + label="67ea193243ae383939b5ad9e356a6b2bf93a93bcdcf828a47082497883083f86"/> + <int value="127" + label="77290717614b25f12964ebdb38b5f83caadc0f6c36b0777f880fc6dee1d339cc"/> + <int value="128" + label="3b0d73b4be4a854adc3e51d7ef9fa48aefbb2cdd824d67bdc7d7d09a2abc2d43"/> + <int value="129" + label="effee1f1e5f39f42ff80d471c9c5a799a8c843f9b676315f9eab3f4c7a2f7fc8"/> + <int value="130" + label="3380709af3b096be3cc2a40548142c0a520028db09e2cb77ae2206616ab6cbb4"/> + <int value="131" + label="4bdc636f48d21fb68c5a3cd4a20685788043bdb524e7e84d4192c451ee3429b5"/> + <int value="132" + label="d0773adb60043e954309d9714fe053eaad8aa5b9586edba468e276df82065adf"/> + <int value="133" + label="ff342fb6c4c8bd30a4706f73489539f19e6e48cc05f46254654f6610dbc540e9"/> + <int value="134" + label="c7f43b4cf5b71568294f822b53762605f6ddd15cadece739e9e2c3cba61e9d67"/> + <int value="135" + label="9c6f6a123cbaa4ee34dbeceee24c97d738878cb423f3c2273903424f5d1f6dd5"/> + <int value="136" + label="052b687107ec84e8730382452ec2a27451745d7485a57d6f464e0da7a1b6af2a"/> + <int value="137" + label="6c464b9a5b233a5e874da765c26f045010d2ddcff45794f0b4c7e4aafa501495"/> + <int value="138" + label="3499f93fd394523bfb1ec4c3ad4dfb310131fbe9ee5476bde6295de808d5dd8f"/> + <int value="139" + label="9699225c5de52e56cdd32df2e96d1cfea5aa3ca0bb52cd8933c23b5c27443820"/> + <int value="140" + label="26c18dc6eea6f632f676bceba1d8c2b48352f29c2d5fcda878e09dcb832dd6e5"/> + <int value="141" + label="616167201433aea6c8e5e3070afcaf6749188f814bd1abb179ae8dad3abf26ec"/> + <int value="142" + label="b0f6f15b4817ebe6fe0b4bfcd7d3ace4c758b0ab6f8a9da2ed92e618239d9c98"/> + <int value="143" + label="3a803e7c0a43a29fd73672e3d0bb2c3653d948ede0b3cb1db4ce75a857e89af1"/> + <int value="144" + label="9ecc51368e86e3460f66c295e4942dd53080f27b1e410aff2d1aa9d4e6bc7e7c"/> + <int value="145" + label="8a2affbd1a1c5d1bdccbb7f548ba995f966806b3fd0c3a00fae2e52f3c853989"/> + <int value="146" + label="1528397da212890a830b0b95a59968cef234773779df5181cf10fa647534bb65"/> + <int value="147" + label="31de0cb19f2adbb0d1cd7b1b31ef8ee3eb59b74459aef94b480beeeeb85c64c9"/> + <int value="148" + label="cf0b474ace8469faba402f02eebdf9e1700d9cbe8be4e4348407b69dd3196e94"/> + <int value="149" + label="980922eee07f86bc7f5e5e95d57db8bdae68e17a421c4e72a96a708a87920124"/> + <int value="150" + label="3551de58a7d79cd980283df81790d63a982c1a63b30482ec5821db7661554ef9"/> + <int value="151" + label="6f3e077fe5504646c0191afce494e4eb68183e398f5a4dc05669f8b6e6e682fe"/> + <int value="152" + label="25b41b506e4930952823a6eb9f1d31def645ea38a5c6c6a96d71957e384df058"/> + <int value="153" + label="d8fb33e385c9c2da729a84706ba927dcbb79273e122ffd9673363b70b7f36cbb"/> + <int value="154" + label="510d20e5c47f63cf666b20f61af62bc099a42ac824ffa443a2da7c90b1808a91"/> + <int value="155" + label="4d40e7af4304a09de87fbf9896204c055141e3f809b2fe733bb2310fdf98a162"/> + <int value="156" + label="4462c107c485dd6a5443f5e7a1604416034a374c3f4d10875f1c3715027563af"/> + <int value="157" + label="04a6ea654b23658973c98198c64a3a691c0da72ebebd9aebf75324cde6960eaa"/> + <int value="158" + label="fc3b82796b572ca9731993635db8cf07c2bf01e199b2f273a3f953bd185de3c0"/> + <int value="159" + label="5e7673a17a08d61413cd51b57dbaacbebfe5acb915e3966e5321b13eb9efaaeb"/> + <int value="160" + label="ab5cdb3356397356d6e691973c25b8618b65d76a90486ea7a8a5c17767f4673a"/> + <int value="161" + label="2a8bed32ae680d2d187b9a7afd171d83fd0b935eaf9e2c1b43e80278d2063e39"/> + <int value="162" + label="1916f3508ec3fad795f8dc4bd316f9c6085a64de3c4153ac6d62d5ea19515d39"/> + <int value="163" + label="278a6391d3d36b49aa4080f56a36b3c10fba4e28aa6a9592a82e7535113a12d3"/> + <int value="164" + label="5f665b4060be9efaf6ad739f6b39a1db9847277eb8dc144045376de1009e3127"/> + <int value="165" + label="16d82d67a1ed8e89f9ab58f7d0fd3eb0d0017687fcaeecd40475f10083a5b593"/> + <int value="166" + label="81a98fc788c35f557645a95224e50cd1dac8ffb209dc1e5688aa29205f132218"/> + <int value="167" + label="c07135f6b452398264a4776dbd0a6a307c60a36f967bd26321dcb817b5c0c481"/> + <int value="168" + label="db15c0062b520f318a19dacfecd64f9e7a3fbe609fd586796f20ae028e8e3058"/> + <int value="169" + label="4a49edbd2f8f8230bd5592b313573fe1c172a45fa98011cc1eddbb36ade3fce5"/> + <int value="170" + label="86a68f050034126a540d39db2c5f917ef66a94fb9619fa1ecd827cea46ba0cb0"/> + <int value="171" + label="f1c6ba670cfc88e4df52973cae420f0a089dd474144fe5806c420064e1591229"/> + <int value="172" + label="d6a18443d348db994f934ccd8e635d833a27ac1e56f8afaf7c97cb4f43eab68b"/> + <int value="173" + label="59df317bfa9f4f0ab7ca514d7772296aa2c765b87664d08b96e57399e364729c"/> + <int value="174" + label="15eed339594b304f8cf847b477371d8d6fec61f4db2b01af589e7c53b35cae4c"/> + <int value="175" + label="8bb593a93be1d0e8a822bb887c547890c3e706aad2dab76254f97fb36b82fc26"/> + <int value="176" + label="6106c0e3a0a299831875127bd7d3cc1859803d511cac11eb6e0840dd166fc10e"/> + <int value="177" + label="f3438e23b3ce532522facf307923f58fd18608e9ba7addc30e952b43c49616c3"/> + <int value="178" + label="b94c198300cec5c057ad0727b70bbe91816992256439a7b32f4598119dda9c97"/> + <int value="179" + label="2021917e98263945c859c43f1d73cb4139053c414fa03ca3bc7ee88614298f3b"/> + <int value="180" + label="08b3a6335fce5ef48f8f0e543986c07fd18a3b1226129f61864bbd5bdd1f1cc9"/> + <int value="181" + label="7e0ead76bb6819dc2f54511a84354f6e8b307b9dd82058ea6c004f01d9dda5df"/> + <int value="182" + label="c784333d20bcd742b9fdc3236f4e509b8937070e73067e254dd3bf9c45bf4dde"/> + <int value="183" + label="82b5f84daf47a59c7ab521e4982aefa40a53406a3aec26039efa6b2e0e7244c1"/> + <int value="184" + label="4b72dfed3edccb5f4945682e295731a0864ac6b5b85b193ecd2f06b4900c1cfd"/> + <int value="185" + label="951ee046fa83316e6786c08c44f13b4ca2ead2d2644d63314391c0cc70887d0d"/> + <int value="186" + label="58dd61feb36ea7d258724371709149cb121337864cacb2d0999ad20739d06477"/> + <int value="187" + label="4223894003a881c5df6bab163db235c221a18d54bf759945820e670da82e3f39"/> + <int value="188" + label="4a2659666dc0203b916f53d80ad8f61ac30bea161f485cc7527e6a5937e49216"/> + <int value="189" + label="dd5ed1c090f9f448061baa94a6bb11017544e9eefaa20cc714ce6c633f5dc629"/> + <int value="190" + label="07e854f26a7cbd389927aa041bfef1b6cd21dd143818ad947dc655a9e587fe88"/> + <int value="191" + label="6b1a505e0246f2f60c490ff0c097a7be27210cbb7500237f88b0cd48298bc9b8"/> + <int value="192" + label="381a3fc7a8b082fa28613a4d07f2c7553f4e1918ee07caa9e8b7cede5a9ca06a"/> + <int value="193" + label="6e364b6133deefdcbb21273c5f445a20afbc05038d5b021c0c2153039016345b"/> + <int value="194" + label="6b3b57e9ec88d1bb3d01637ff33c7698b3c9758255e9f01ea9178f3e7f3b2b52"/> + <int value="195" + label="7aedddf36b18f8acb7379fe1ce183212b2350d0788abe0e82457be9badad6d54"/> + <int value="196" + label="149f2ee63b9a5e5803240a770dc991fc2e3445e62831c245a49bc4f1f738ff9c"/> + <int value="197" + label="ec9056fe9509411609763aee831ef37c832b75b3d727528fc7c75201c1ff28e6"/> + <int value="198" + label="675605f1567e25fbd2526befea2aefbdb2279f3e1baa3a303ae7555d1bda3ee4"/> + <int value="199" + label="891ff898e4a8d555140056e3176eea91f4d808ee7f6d1bfbcce6f84807639f91"/> + <int value="200" + label="0b9fa5a59eed715c26c1020c711b4f6ec42d58b0015e14337a39dad301c5afc3"/> + <int value="201" + label="bb52086d0639e8db332775ac8f4e8435d92ceb00f4e24f28fc0eabe240772e80"/> + <int value="202" + label="6d6f0c340971a218a31d10330ea9ae7c7a6550534c6eefeddd2118e114db473e"/> + <int value="203" + label="5375662628fa0a6840aec8c592bf5d8de564ed3efb62c7c932fca8d754d9bbd6"/> + <int value="204" + label="50cc86ba96db3263c79a43ead07553d9f56659e6907e72d8c026637a1cdc85dc"/> + <int value="205" + label="36abc32656acfc645c61b71613c4bf21c787f5cabbee48348d58597803d7abc9"/> + <int value="206" + label="2fc5667a4b9a2678ed6ac6ad25465fcbf6094bfcd9504097c7a8fa47ade5e888"/> + <int value="207" + label="b738290cc08547e79ac67f831ebb33547c4e7db4514e2d2988c23c441340eb41"/> + <int value="208" + label="f7ecded5c66047d28ed6466b543c40e0743abe81d109254dcf845d4c2c7853c5"/> + <int value="209" + label="7f4296fc5b6a4e3b35d3c369623e364ab1af381d8fa7121533c9d6c633ea2461"/> + <int value="210" + label="fbe3018031f9586bcbf41727e417b7d1c45c2f47f93be372a17b96b50757d5a2"/> + <int value="211" + label="b1be0f7a5e638b559d8b521fef6017ad8fa16eb0548e846b2ac4b41d89b41f14"/> + <int value="212" + label="e43dea894f42cecf4a1dd60ed1dab82f7c0a308ae32a3d49a7aa1a3e957015f7"/> + <int value="213" + label="c5697be91cd655539b560758e91b6e085461623741034c485e47d7e9d25a03c0"/> + <int value="214" + label="80dbfb97bdd3926baee41f73c5588faa17d707b03adf4907a2bc677f3ef1717c"/> + <int value="215" + label="eb4993efa9b089e593418aa893f8e93a7374d810e52fcbe01e7f1d7e92a6d024"/> + <int value="216" + label="674039e472561963c8cb00d21a97a90a18bb8a1c4c317ac67e382a652bb573c0"/> + <int value="217" + label="9b219d0fbff36a5fb32090571906bceea68617c833a3f61b81e962a8e64db8af"/> + <int value="218" + label="da8796be34cc81abee7304c4d2bca0ac984c5b24b61b13e2285e1d27ad8cebf0"/> + <int value="219" + label="ede4b1535a529bf1606bc6ff757b91470aa30aeaffd2d6df2eba340dae302fca"/> + <int value="220" + label="a7a8f039894f5f675e92a778e008e424c9417dba06a1738b45b4e08d36fc2d7c"/> + <int value="221" + label="659cb368ac56998bd07af2cafc5fb93f8e79474accc2a6cf1ac9f2192d136360"/> + <int value="222" + label="f8e5f905bc939911267b83d50814a90323b51e183629db52d4fc2d5468a5a578"/> + <int value="223" + label="98ca29f313386721afbf5d14f1abcaa1dc63cc8d1fd7dc361f6b01368938f24b"/> + <int value="224" + label="915086ccd4ed1ea749b427f6b0ceb4a0ef5b4a1cf18070539c0f2a758185a382"/> + <int value="225" + label="3fab784fc3c9ab9eedc12ecdc0db550f4c3dbfd3e86d78815333c5eba518cb9d"/> + <int value="226" + label="22076e5aef44bb9a416a28b7d1c44322d7059f60feffa5caf6c5be8447891303"/> + <int value="227" + label="7006a38311e58fb193484233218210c66125a0e4a826aed539ac561dfbfbd903"/> + <int value="228" + label="8ed5b4c041b6b293c0e6413015066d318483c901ff69e86a521d0cb25569f3e8"/> + <int value="229" + label="16a9e012d32329f282b10bbf57c7c0b42ae80f6ac9542eb409bc1c2cde50d322"/> + <int value="230" + label="da800b80b2a87d399e66fa19d72fdf49983b47d8cf322c7c79503a0c7e28feaf"/> + <int value="231" + label="68c3692214724d4b55a760f470b4fca8b5e0fe1d729cff22feb4ca88acd39809"/> + <int value="232" + label="c06c872fc2d0ac08d78d421981fbda4e35500d0946f79894edd21ac29dec0719"/> + <int value="233" + label="33af58b5589ecea7926252477838ba40247ab37b6fb39e34fcbd552cd5a8c66d"/> + <int value="234" + label="8adb238554a0cbfc3a11fecc183e3cd2c23d25e7894cf2bbae58eb70a44e7cf3"/> + <int value="235" + label="98b3f10a025041910f197cf17ca0fcdfed75fb2c8c14a843e04d5656c9ebac1a"/> + <int value="236" + label="dd9a6bfbf44e17a27f368ac8e067b307396269a747f92e8f2acf2b451e3ffc72"/> + <int value="237" + label="309f13d49ea66f523241b55524744464e28cc1b82ef79b64e4d581880dcd771f"/> + <int value="238" + label="98008e2edbb72bad42da2fcb06ac1aaa0b2e6e0c72e8ca204fbafd1bb4879441"/> + <int value="239" + label="8e8b56f5918a25bd85dce76663fd94cc23690f10ea9586613171c6f8378890d5"/> + <int value="240" + label="a25a7214c2b6c86142ada39dff2d73d865aa57843fdd2db77b3febf82683de2d"/> + <int value="241" + label="2896b4ddbe61457183cc7ed27bd78ac50a207f6901c5c52e53dc1676f9bb1e06"/> + <int value="242" + label="719cf5b36192e7bde650cc91341e6f649dbb8c3ee48bacaa97fa0e05b6374b41"/> + <int value="243" + label="bcce8e2bbaee71b6358ddd641cbbfc25de454003006271f75b50b726d67c3bc9"/> + <int value="244" + label="1c294bc25243768913ed4ad5ed61cb02bfbae0bce6e6e72e5f9658f346b42496"/> + <int value="245" + label="3bde97686e3af51d3f572c4888c12bd1d1e097f12f49ec3c92896551e36f0085"/> + <int value="246" + label="93a9b3c96aae1cd661215d0c2a065da963d7160d1c694621bcb28c406df64db2"/> + <int value="247" + label="f6146bc238e8fce0d47b7074c9a26b1aa0f883528510f06d9cfec41ff6ca1968"/> + <int value="248" + label="2dc9470be63ef4acf1bd828609402bb7b87bd99638a643934e88682d1be8c308"/> + <int value="249" + label="860a7f19210d5ead057a78532b80951453cb2907315f3ba7aa47b69897d70f3f"/> + <int value="250" + label="0bdd5abe940caaabe8b2bba88348fb6f4aa4cc84436f880bece66b48bda913d8"/> + <int value="251" + label="006cb226a772c7182d7772383e373f0f229e7dfe3444810a8d6e50905d20d661"/> + <int value="252" + label="aa1c2bedb1a508baad7fb3f5e02897b907c748dea9b7908904aadbd0497aab6a"/> + <int value="253" + label="d9c473cee25f94d1bc6062bd62911477276f064b827a944e064f85d0912d2c5e"/> + <int value="254" + label="31512680233f5f2a1f29437f56d4988cf0afc41cc6c5da6275928e9c0beade27"/> + <int value="255" + label="d2f91a04e3a61d4ead7848c8d43b5e1152d885727489bc65738b67c0a22785a7"/> + <int value="256" + label="3027a298fa57314dc0e3dd1019411b8f404c43c3f934ce3bdf856512c80aa15c"/> + <int value="257" + label="af207c61fd9c7cf92c2afe8154282dc3f2cbf32f75cd172814c52b03b7ebc258"/> + <int value="258" + label="809f2baae35afb4f36bd6476ce75c2001077901b6af5c4dab82e188c6b95c1a1"/> + <int value="259" + label="95735473bd67a3b95a8d5f90c5a21ace1e0d7947320674d4ab847972b91544d2"/> + <int value="260" + label="a51a2f3a050e838a5050696578dbbedaac1a107ee2d9d48fae505d18d0da5cf8"/> + <int value="261" + label="6b86de96a658a56820a4f35d90db6c3efdd574ce94b909cb0d7ff17c3c189d83"/> + <int value="262" + label="ab39a4b025955691a40269f353fa1d5cb94eaf6c7ea9808484bbbb62fd9f68f3"/> + <int value="263" + label="479d130bf3fc61dc2f1d508d239a13276ae7b3c9841011a02c1402c7e677bd5f"/> + <int value="264" + label="2dee5171596ab8f3cd3c7635fea8e6c3006aa9e31db39d03a7480ddb2428a33e"/> + <int value="265" + label="ab3876c3da5de0c9cf6736868ee5b88bf9ba1dff9c9d72d2fe5a8d2f78302166"/> + <int value="266" + label="47c7a149ca82fa7ba940a4d711d010625c6cb0b748b17016c46e25ce7acd2b0c"/> + <int value="267" + label="cc4997863c8c48a4cb5c3e6537dc06028d8638be49f5f8a2ba56f2f2c8a8c779"/> + <int value="268" + label="a86bdab8f480b6eb8942ab9170bdd0991971a7ad135dfbbcb7285f07a7d1e38a"/> + <int value="269" + label="2da8f9ea3454d21146464a3f9d028dc4c7fbb57b1c52c73c2b0572a2f599a2d3"/> + <int value="270" + label="0fe14c264b17bb6f0d653e7a70eb363dbf54be158039eddae5c25711df48c103"/> + <int value="271" + label="5efa073f49426344483ab0ddbbdda5e35972f9c47c74ddf98ec42290b251ca97"/> + <int value="272" + label="2e00915a9f7be06ab2370c7b7c200c0a96d5ac6a50ce1874dbefde4022d4de8e"/> + <int value="273" + label="85d26be90d934fccdb4ff7b38d8c79ca7652b816d6a52446ca8428a6b85dc57c"/> + <int value="274" + label="7f1dec8b0319548a056de5bb521bd93eb74e6a76f28dffb75b45a53b775af7ab"/> + <int value="275" + label="8a903b600a080b38dfe20dfb6acd23122f64620e5808b9fc8688952fc1a3559c"/> + <int value="276" + label="84aac093e08c49dbfff8e560759248dbe67135b372b23d2a881d5f99cbb191e8"/> + <int value="277" + label="6c5cbf02c1849166278f1cd1c83583a147fb7bc95e289b276366935e3153f302"/> + <int value="278" + label="482f76a2a9346dbb077619bbe1efecd54107e992ff4e8f4d70a39e2405d939d4"/> + <int value="279" + label="3a6c24e80f681d8b1047cec051c27594f885ba0887a26379092dfef506160e9b"/> + <int value="280" + label="30ab1bcd7bed1ff2679f71228820420a7063c6cead7ec30d4a016154876dddb5"/> + <int value="281" + label="ae56d847973d199390e66e4024c9f87d87371e8ba8876af83d1e644f54664738"/> + <int value="282" + label="93657f8530c596bf909e50da7d8d9cbb36b824cc16ab589137e1438011bc9901"/> + <int value="283" + label="01d0d8e07bc5a92da7e7b81e9a569fe3a2d63a997dac596002c5dc810cad17bd"/> + <int value="284" + label="4cc29758a2cb9b50109987f37537cf0c55ba2e6798937307a00296b01dffe44a"/> + <int value="285" + label="49b80685d332e072c0e7b720032647e842106104e0b1139ab9e811bfb11ec034"/> + <int value="286" + label="c5ea259c629803508649f02177f63c32fa85cc4ad5c35f0d541c45df10a49fd7"/> + <int value="287" + label="55e00be277ceb0545299f24fd9f877e2acf32852db43ffcd29bca74b39b4c9fa"/> + <int value="288" + label="ceb19411c65052c757f941eb826c96941e4d08d096c7db7e7ea3c4f8c13f1a13"/> + <int value="289" + label="ea87f462deefffbd7775aa2a4b7e0fcb91c22eee6df69ed90100ccc73b311476"/> + <int value="290" + label="c63d68c648a18b77641c427a669d61c9768a55f4fcd0322eac96c57700299cf1"/> + <int value="291" + label="7afe4b071a2f1f46f8ba944a26d584d5960b92fb48c3ba1b7cab84905f32aacd"/> + <int value="292" + label="d1c45377ebdcd618cd1651dc2e02c21d751e5aa9fcd1b3431ff6ecf6a31348fa"/> + <int value="293" + label="a320f4d534d7be97c1ae8dd0499735bc895c323add2d388bfccf662c23d7f99a"/> + <int value="294" + label="7cd67c248f69d83fc2f9bb01dcb1f7ad67a363d046043796d0984c3a231f6bb0"/> + <int value="295" + label="348767cdad3bdd28b2b8dd5351aec30c68cec5cd69d276df3827dbc4f5806464"/> + <int value="296" + label="5dee74cc343db93f8deaf9e41fbc65b334254b5b23b568fa2814db8b7321ac85"/> + <int value="297" + label="ea2f9e087eaebbdfc0569eca18364e5236254624854f92e37871b5ee36744883"/> + <int value="298" + label="805c6696266b96b147468a321eba9eb8b5968f2c477cdd95fdadd1fc63dd614b"/> + <int value="299" + label="991b5ed1b2fd364b9f634b624b305203f29908be318ef6399222d8a3ef7990e5"/> + <int value="300" + label="161e83ea32d47641e23cbe0eb413a3e0b06859922a49d1a20cfa05a41e280cfc"/> + <int value="301" + label="a7e39bd7df609bef3262bf3db4dc8f3814e0db5a7a52156a6d0c35b4dae8a6ad"/> + <int value="302" + label="06c7bd9553f710e058eb27b15d47dd62d7fd4352d91da96e1efc50e15354b8d7"/> + <int value="303" + label="3a0d885cb346d8f01fd300af1546f6355c00690e340ed98f346e77b574be3fd8"/> + <int value="304" + label="1a421223e89bd87c403b48fa616948470d0f2c21ce2ac7bdd22755061c62ba92"/> + <int value="305" + label="a5204dbb2754b97e3c8a104eacb374a6498a438773c75077f0063c2ceb25d2a2"/> + <int value="306" + label="7d434d1dada2a154d49f473e381310b83ee58d290a13455182d77f1962df55ee"/> + <int value="307" + label="a378419d1ae9ebd27b22948044c684ba29bc084b98f965be73262f0f6aaa1c6f"/> + <int value="308" + label="c954c2c0b189825bb65ddb3ddca080b7dbcfe6b17cade1022bada818336677d0"/> + <int value="309" + label="05ec0897b21995a4a9899f8fcb06601ade61c04389969d138fe32cd6cfc746ab"/> + <int value="310" + label="a12574f4eb7395cc630a15fec8db1c7c828f66699d984c8c897eca44c808f55d"/> + <int value="311" + label="2bb5c28a34c9a37dd9604500ca9b3038d00528b474773a2732aea79e4905c234"/> + <int value="312" + label="b9182f52af0dd18e3a99ebbae7883d4e4cc7fe2f81fad0d36ca661efc32d0a92"/> + <int value="313" + label="df530bac9fcd914c252c2fbdceddc6183d4ae8c680ad65f03e204861dd7b1c73"/> + <int value="314" + label="0d47e98588452cf0778af6af03d442721dc083660a4bb23c697441fe2bb84f9b"/> + <int value="315" + label="3c84d996722b3c1872f53ddd7717bb2fa50ebfa07b3f3b4a395335c56712fd69"/> + <int value="316" + label="96475b35acb1c9303a90bd1dbf57418f78e29af11c4de8c8cba2e5f9309e38d4"/> + <int value="317" + label="18cfa64518e916cafe985561513cab7a897a54bd23b8e26874c5c7cbd1249cfc"/> + <int value="318" + label="3c196f84e2a0c61fec18bacabd31783b574517aad8ebc6ce6d1d7dc82b3c50df"/> + <int value="319" + label="931f1cf03a6f84c30ff3ad869be3c21a410191cc98ac0afc9d4e8b89bd869ddc"/> + <int value="320" + label="522c3960328026a1e322389a8a08fedc1b86d9c2b59b33484b77f7ce790635d7"/> + <int value="321" + label="8991e219ce9f74479eafedb3535836121dd233ea768afb9d9ac8b4a22381a8d5"/> + <int value="322" + label="881a1b9edf69ade141839ae8673d31b4f4d47f126ca08a79ff065dc9a690f4a3"/> + <int value="323" + label="62a31a5c730dba674ddb25de33df143644375b49af07878a667b813491c73971"/> + <int value="324" + label="51b6ea6478687b47d963b6149059780cf08a4f02f042d61b5bd52639095ee910"/> + <int value="325" + label="6cae87c558d2441568e38270a8dd8ff484a259dc4f3ce94ccf434c1fa99811f6"/> + <int value="326" + label="d4af6c0a482310bd7c54bb7ab121916f86c0c07cd52fcac32d3844c26005115f"/> + <int value="327" + label="f6b59c8e2789a1fd5d5b253742feadc6925cb93edc345e53166e12c52ba2a601"/> + <int value="328" + label="4ba6031ca305b09e53bde3705145481d0332b651fe30370dd5254cc4d2cb32f3"/> + <int value="329" + label="0999bf900bd5c297865e21e1aade6cf6bb3a94d11ae5ea798442a4e2f813241f"/> + <int value="330" + label="1462009b2de65d6d4d39be892bd2c186490531ce6590e48fe196070d317b60b0"/> + <int value="331" + label="e26613a578e158c2a44e4fec41e6f37a0a991fe1a5fe736c303f4420a90fb50a"/> + <int value="332" + label="498bc0cd5a49b714071ec76a41661ce2f27fc39fe4168bc7b7799a0ae25f6528"/> + <int value="333" + label="9d98a1fb60538c4cc4857ff1a8c8034faf6fc592093f619994b2c813d250b864"/> + <int value="334" + label="a2dc98ca7cbbee1822b25b267bd5ca502fa7b0cf4fff0703ee6a416703f3c7ea"/> + <int value="335" + label="f5857d8862bc2ba3c9ddca3f84146dc8d81f4d579d2b387bf60065381ee641dd"/> + <int value="336" + label="9119e2f413579777954991703eee23a04523a312b5c65f7f9374aa3100ebd8e7"/> + <int value="337" + label="af6ab51b7bad1dedd533eb59332b6227d6557f20b4443216db735b92280c7a44"/> + <int value="338" + label="086dcd7bcf864aaad5ef8c1c577bb68a131e055c93f63b9c47ee26eef15be7ab"/> + <int value="339" + label="232cbe2d9e6994c1ceb7fbee23ab1657defb6b3564726f1e78951cef3a2b095d"/> + <int value="340" + label="431b79fd9355d10dc1b50dbf6a6b62d7a5b6d356541c27605255ca4ca79420c1"/> + <int value="341" + label="7c3b46d9be8f2741f980039521858e4cdd30774fb32b3b21ceea06aa79c6aac6"/> + <int value="342" + label="9dc38a9edcf82842b674da186b6d6215ab9e2ec6d72f57b08a892728c31431f3"/> + <int value="343" + label="283310819f5e09204995d8ad9ff6fc10746297b5c0ae06bdd1e1124b10a0d7ad"/> + <int value="344" + label="6046136879e56450400f7db2ecd0df1b88f667c1e3fffc52964ff9e2e48e85f5"/> + <int value="345" + label="e85fbf8b9a2ea4909dce0fb5b2fe5f5877343d27d58a410a8b237ab675a2ddaf"/> + <int value="346" + label="5aacf1b965e853010fcb2a110317d5fce3ee351e9cc95bf444a571d7b8ef9162"/> + <int value="347" + label="9546ce00e03dd61aca58c5c8dbf38a111bad6406c91d7422e7f4c40a0cb58f18"/> + <int value="348" + label="b4296d5fe60e52f3f0ff99da75af5e7e62599f99ebe0fa413f66e6b425c3d09f"/> + <int value="349" + label="7f7c88a77d4d3b44c33b3c030bc83f1a26c20d49177ca7745d91d9de17e08f14"/> + <int value="350" + label="faddde04bcf08ca8f4e22efd2afeade6bf3d850ae47be96a82d539494f120cbd"/> + <int value="351" + label="20e24a5a3393d6c3adc384faf95152e1f9aa7222774028b53c5a34ed0c6cb399"/> + <int value="352" + label="4697a5abea0070a395456fd358e91f72f227d5850933227f1e0bc79ff847bfac"/> + <int value="353" + label="463dbb9b0a26ed2616397b643125fbd29b66cf3a46fdb4384b209e78237a1aff"/> + <int value="354" + label="9e5a34b08929bc0a581c8936aafd6ab7517bb15188b4f6fc02c45906f71595b0"/> + <int value="355" + label="b3182e289ae34ddf2be643ab79c244301605fa0f1eaae6d10fb929600af84df0"/> + <int value="356" + label="a798d92f76c9c6755e5f55f86cd14aedcc0655371e27ccde0377745ce3c50013"/> + <int value="357" + label="004124ad6037fd5f3319e7a23d4d9c811f5598d66c4754155b0aaa9e8f00621f"/> + <int value="358" + label="c90d009c47eeb9f2a29ae848f5d930f2b41ef5edbc5c5695c1414345c1dd67b4"/> + <int value="359" + label="2a4f49ee7701a395ac932e444292671588ade21259ce296e194940368702ea7f"/> + <int value="360" + label="30b71c4f9122476e761e620eec42bfa5f84c493cd49bbb1834b26e555f60de40"/> + <int value="361" + label="ef53ffaf0ceb040d077f5bd80a9deef6d4507fdb6f9bcf8c3594bece7ebdb025"/> + <int value="362" + label="651bd66f5c3dc637957ef5185e4fa671c21654b1c0ea49384f44bcb256a5084c"/> + <int value="363" + label="f5e19c8e14fe755f551cec2b7113e7c98023b176ebe6c1abcf872b2a7b932304"/> + <int value="364" + label="a74b4b6a2eb55b9864c04ecb16003ff5db5b51e42cf859f95e9d0a1dd4644096"/> + <int value="365" + label="d92405c46d912a563e43287f56cd410a1cdf6367c57c9ea7c5cae039dcbcce50"/> + <int value="366" + label="86c84b1c3a66f4285af797052467e3ed236fd2986f033c02c4771be0b970482a"/> + <int value="367" + label="d1ecacca44012c3e1e6d1b39dd2968fc7fd3127aaa57ab5182a3beabccd7a3a9"/> + <int value="368" + label="3fb63c29f47bcc4e6aadb3577ce7ca8543e0bbaba553676b8fd161295bdb9011"/> + <int value="369" + label="e0ef882da48ab0b7efb0d9ba15b2717dd08f043c25ac09b56b8b57fceeb5a35d"/> + <int value="370" + label="8ab4e88556cbf864a5e9fd50171cd4ed8424e8f0801b99e236c810915950ae4b"/> + <int value="371" + label="a4b89bb70656ea498f2d9e00a497fdb9dcd20b81b8938e952bba2df9f65729c3"/> + <int value="372" + label="bedd8bc97ea86497195a078a999a237a060aebae07bc0a0b9b778982ba5f62f4"/> + <int value="373" + label="c42533d3af4998f5ad9f072521d85d472fa7ffdcfc588c8247b337dc77109389"/> + <int value="374" + label="d646f3ea2d7003fcaa77ad219136c78e024a6f2e2307dfb8cfa97a171373ecdf"/> + <int value="375" + label="8b49506a3461063ea8cc13ffce2b581de15a94b957092a93123467b89ed802e2"/> + <int value="376" + label="6d28f9e405148b69027da990815211c858841c543feced008c238021983c095a"/> + <int value="377" + label="ed1b229e0e0875021c1f1760c3407fb1d6608eda7add71a3e3275ced09690f7c"/> + <int value="378" + label="87157a7585f4d03b00a398461e164e4806e1b3f46d03afbdc9def4e4778be2e9"/> + <int value="379" + label="22050a92836481c2f3c1f8417d37447a167007ac9ba64ea228cb6a1e14c64b8b"/> + <int value="380" + label="f73be5eba536912c557fb855517ad1ee0487bd8f63498c3949164177ba06c5de"/> + <int value="381" + label="4ba24996ddee6f8e1fcec0aa9eccfd3aa5477b3ef8f5f85f0a06073f97522857"/> + <int value="382" + label="acf7ad98e6f065866e6f8cdf0ceb6f7481f6957b6dff823f6b94d79f01a61c39"/> + <int value="383" + label="ae2033b3082825a703e5a6adc3221a86854aa411db047dd5f53eb84aa14bdc01"/> + <int value="384" + label="8d775a4f93cd20c18306144f42b569fc2a897eaeaec3d3ea3cb025d1ad4d28e7"/> + <int value="385" + label="5094b73b736adf73a0cbf43e27bf14407b4a36aa363a457fce33949ceba8e649"/> + <int value="386" + label="af110f6b5ae8b767eac6e0aa273f3816e7a40a644edacb4398146356e77509d6"/> + <int value="387" + label="f7aff41b2709f175f8aba17e567b27046b2dd54bf6e7e263d3295873437b9cff"/> + <int value="388" + label="112432e4bb848c45549fcbf0c710c566d0082bbbc4e9b38e6c76ad46448128fc"/> + <int value="389" + label="7016270b60b28c6e177edebd718007dfd3310c64a737b7db01a07690c343bc27"/> + <int value="390" + label="ad304c884a5d376bd195209a14c39e07f0d3f5cf893d802b053e1b926e55d774"/> + <int value="391" + label="94b94bbf9a0726f17b0973af6d41e9fb2e7099651bcbefddd97b0a5f2aabb0dd"/> + <int value="392" + label="8a42eeadbc8b21a35c4b3aadd7dfbcbd2ed1b1da12e8c45a534da90607e564fd"/> + <int value="393" + label="ef4fa1c630f04950e0e2d10dc19f149d08ab46dec95da3131cbaea8af8ea3027"/> + <int value="394" + label="913119f2cd3f48aca74ea6443ee50e0de1202d9c54f336dc9300affe97d4577c"/> + <int value="395" + label="7e6acd853cacc6932e9b519fdad1beb515ed2a2d0025cfd398c3ac1f0dbb754b"/> + <int value="396" + label="979f6f6a8a41c421cc673473d58a6379817be73d2e524698c80ffb66a149d089"/> + <int value="397" + label="c7f584236d86395e8f6f82c010886a2c56e071a6a1c3ed2876b8a3a72c5efbb5"/> + <int value="398" + label="202665e4c5c380b4490a81773db5dba62a90db6f5be6e0e54d11992fb1e655fd"/> + <int value="399" + label="dc053d027fc186e7c41cd193af30fc09794eb9f3d9e6736dce041440d876a801"/> + <int value="400" + label="15bb28d9207e13f8bc9557dd785eba773bea944e04d7e08ff8aa55ef3194aa20"/> + <int value="401" + label="58a2a698d86fd8497d41f68e4caeb4a98874f433da913dd26c5ca44d08ff72fe"/> + <int value="402" + label="c9905b0ee01202293ca026e64f08412442c5504c06e44ca7e9726d61f20e4089"/> + <int value="403" + label="44a3d80d3f5348596d80a09842c23a39774439f8b0b919239d2a03dac5ce5213"/> + <int value="404" + label="bfe82909872e4434f115c51a56168019594d0e03dca363d9f3b4839d0babcde5"/> + <int value="405" + label="d5597ea3453a6261f5d42eb9caf5bdb4e38a1edebdb5bea6d7c0bc1a8abecab2"/> + <int value="406" + label="5143e47569a1d5fc867893e0cc412c41f55715da78e59e9f8e43770008ca42d2"/> + <int value="407" + label="9efd911d6ff46f1831111df3c54cd2611cae2398ff7386d1cb6b4f32e3337ed6"/> + <int value="408" + label="b656a4343831a2acf11eeabc3a44b97025fffba2b910da8714cf827d81be10c9"/> + <int value="409" + label="42a70984ffd399c4eaf0e702a44bef2ad8a79b8bf4648f6bb210e123fd075793"/> + <int value="410" + label="85a3d81d2ad0c79df0a79684e0e2666009a09de15760ea1d76cf0ee7b2825dbd"/> + <int value="411" + label="02376d0908ac23041cc7d666d9daf192554f7fc36317aa9cb800908616b28af8"/> + <int value="412" + label="b083ff536f7f48a9081e294a0187b53e819771402d9d4810306de031024e5f46"/> + <int value="413" + label="508f8c6178af329bb6bb753ab943d9023be796c3adbb6c5cd4664b66feeccae5"/> + <int value="414" + label="43c74262f7492662d2459bcc9899bac54a4ecc01e1a3f5e76558992b40152418"/> + <int value="415" + label="bf01c35f337113f167b4a50186765e7b1e3890af586328f185cd0d6bae813521"/> + <int value="416" + label="1eb9cf901f0858aa17c399babebbdd8cb303a4ef4e1220c493cca2f75a3f914e"/> + <int value="417" + label="19ad98de02155d7e33e9dd21f0e45610fd11d28044b8318bbebf9f6337888df0"/> + <int value="418" + label="8bea76ebd6137aff9f1ecc3c08caf1dec47db91690d5754c4e9f15232c0a2e78"/> + <int value="419" + label="1b8a89531701608c9ef3c65f5d60a948b1badb9753622a2e81c0a4a284be63cc"/> + <int value="420" + label="3ea7b5c045a99a9771e2dea8e8098ba2732d17ceee82279552feee905530f35f"/> + <int value="421" + label="6a7b1482127002f9005a87356e1dc3e00b70bbbfa795024ff8beff74c4259b75"/> + <int value="422" + label="2364d692dccae13da56ad4a07c1325dc575215ff1a071681dfca5dd6ed7c8452"/> + <int value="423" + label="816ba0bfdf5fd64d568ec0d052f71164d9e2ccae12e0219ed6cd81e7e845fb84"/> + <int value="424" + label="a1d45d06297341b1f3a735cfa38f283e6879fec06281a361e5f417cc70d29dc9"/> + <int value="425" + label="972fbc6d55bfefb1abe3758ad7d67a349bbef80c06f1d85001dfb9101b9abc1b"/> + <int value="426" + label="6a436b58d9d830e8d5b8a642505ad6b41406adcd6894d9414f7be0a1467badb7"/> + <int value="427" + label="2fcc99f5c9d00f9a20da6131dea5c027d92636d68cd9cdbe95290a3c408919e0"/> + <int value="428" + label="66b00539826a37484930191e028f62dab1cbc89b3acd472dc4e5905e47bf7364"/> + <int value="429" + label="689bf45b3083fdead55f147fd105e3cf218ad58edf3e4b301c0c5eeea6cf210d"/> + <int value="430" + label="b5ec35baab538884cfa8dd97376b102f03e53b482c64100c250722ae9b042cbc"/> + <int value="431" + label="9ea9fe274537f4f935642cde824fd77eb0e125cf118ab9b4c219f6cbf959b18d"/> + <int value="432" + label="b16cb1ba529a39e2dfd53b3ff5a79f1904614d83e31304f0278bb40b38cf7824"/> + <int value="433" + label="0f9c1299557598cf7521bcc8798420a155cec1bb23a57ac37f5120fc9a2057f8"/> + <int value="434" + label="99333c3a665cf0efbb7488b3807b8b65f87b5b29d6880f028edc28442eeae669"/> + <int value="435" + label="782d7e61e1323d2aafb877be34ee1de0c1345136d4fcb3c945937f6a67b412fe"/> + <int value="436" + label="3d8d061edcf7b3d45995ba4341328d1be7b7eb4e9d14fee70d2f18ad68bea7c5"/> + <int value="437" + label="78cf3d3c72daf91cc51b871357a551cf95b837d074c270b08facd463a8d39bb3"/> + <int value="438" + label="2d6d690c16b11853884bbea2723725267e3f9b54a6cf07ad4690ab1e7cfb75e8"/> + <int value="439" + label="8e15d426cd04898f218be2e5fe3784f375094cc435dc61ad86c4a3c01511dbe1"/> + <int value="440" + label="58044626c34c1a7b158ddb676d9e2e65443d818dab3116231e2d62ab6426a0b7"/> + <int value="441" + label="29e7fdda489e46ee486efd75acc48f251932dc9da1872b31753cd64719567aa5"/> + <int value="442" + label="111c24a243061da76e57e3b1243eda90879ffb750552395443fa8c34dc0ed737"/> + <int value="443" + label="c53dad9e53ae27ed95f0ea7a9203f7bf56eff0f8e1ce960cb4761b968342e34e"/> + <int value="444" + label="4376a99396769fd487240ee8b573ad49706a5b9473616acef38409e91586dc1e"/> + <int value="445" + label="e156445fa20c32ad00937b27d096b8963bcc863950333a877e68fa69707a03af"/> + <int value="446" + label="71ed918a7ac6d17b3849c20180b3e7334691bc5fb73377f0070afa0be789b2d1"/> + <int value="447" + label="439c19ff3edb265ef1a920f74a4802d3dd95ace024e21e5a6ce8e064dc1566cd"/> + <int value="448" + label="63f1a6f79d6e730d10432e6308194ff7bc28850adf2badf789d971385d8512ee"/> + <int value="449" + label="a4cbf48516af3160ebc62acac6e7f258609ed0891535010c16692493a9fe1fbf"/> + <int value="450" + label="b213a9cbaa9a8831ac0b3aa80e9d15856cd43a7cc2e0bac5fcb84a24751a8a78"/> + <int value="451" + label="abcadfa35ff835cb3a0a0b86400622b80d5e80c765bc027f1b1c4e0a620f5e1c"/> + <int value="452" + label="676b9ff303ede180fb95a4736fb4d3153032c014444f63a2074c41b98b51e0bd"/> + <int value="453" + label="a59d2f09c8b168cd9afa3bc3eb4db0d7a43588d523287f2b83a822eb33709170"/> + <int value="454" + label="4e6c1616637199b5077a80ad0c2248c725e576fc8a719989456bc9cafddb7524"/> + <int value="455" + label="a76e2949cb87f6236b5f68c690747587d6448ea21cfead7950084ac015190b25"/> + <int value="456" + label="0206ead163b10ea2f8620868ebd7a15f64a20250d16cd57d6e87c4fff1a2197c"/> + <int value="457" + label="49cbd83c03cabfa0713b97bc96481d035fd4ebe06f07fab5640ed9232d8110b2"/> + <int value="458" + label="33fa5a5300613d466e6f85c8051695bed5d1fad59f25e040acda0472a74f3c20"/> + <int value="459" + label="380739620e13335805eada8f9f8b81554d3bd3c0017f3632c2677669cac7a2bf"/> + <int value="460" + label="244803cfa35953385d06657ac4e5ab4f2bc0405277be662adb905e1498b1defd"/> + <int value="461" + label="3ec18dfeb894a9ea20eb2cd40c693e2a29144fe2ec60b4f7b89026040b39aebe"/> + <int value="462" + label="9962ab1699b0eb7c7e8a578bc79893042031c1158c633613199a90b9652a2a75"/> + <int value="463" + label="8e8046ec4cac015a507ce0d2d0154a4b40e8e42b3165cfa546571435112d17e5"/> + <int value="464" + label="57a742a88d3e18fc0bc611bc7976c22edc50011757512b1a7e2e1d069b3ecba0"/> + <int value="465" + label="b489ccb224b9a6b81dd274ceaf5209c252998c9a76af48e4f4c50a0728461825"/> + <int value="466" + label="42a807cec5ae9c0f03b40ca043ac70468b5219bd75cc5bbea51d921dd100156f"/> + <int value="467" + label="f42352c3cc3d84b8518989d647c88ca301c88fb991938bbcecc9ee60e565d377"/> + <int value="468" + label="5c41a73ab2c35dfcd771f6fd6e3e8fac9b469d386cadda56a95b646eb48cca34"/> + <int value="469" + label="1255cabe8152fa64df942f7a47417e29f96c1ce11bf8c84ecbe2815cc1280810"/> + <int value="470" + label="4ef7dacf77edb751f704035fb5c6c442351ec7220af90bdf82fd047bd3c24187"/> + <int value="471" + label="3329bfa13b6007ab5fc3713f0acb289426e2fbc99cc5c110a914b139571600b6"/> + <int value="472" + label="d3980aadd21638c70d74a4bb1f8ab5e11724e62ed408f9fa8d3d4d916900286b"/> + <int value="473" + label="7d6c3ebf9ea735d1854beea7cb941ab1e3503515e087bbb5be695d05f2f556e4"/> + <int value="474" + label="f2a4e6b263d0a552adff5d85dc96b5820fd66aa0b18228f48fdb087c8db34133"/> + <int value="475" + label="b89bcbb8acd474c1bea7dad65037f48dcecc9dfaa0612c3c2445956419df32fe"/> + <int value="476" + label="4f7162b974491c98585ec28fe759aa00c330d0b465190a896cc4b616231831fc"/> + <int value="477" + label="21ae412566324725ffefc1dccf88f16f8d6bf4dbbb37fe8caba47e8d66c2cdf9"/> + <int value="478" + label="9415b25dba3bbd711439e2a9964b7a5256aff3b05c772c8a34e6c93566aba63a"/> + <int value="479" + label="ac447dedd0432aab9c070f2cca01b6dab09bef07cf4ca6aaa755634f857b315a"/> + <int value="480" + label="67a84264d42e204a9a5b0a3667b951db22c505df95ed983b5e8c4d1fce77af43"/> + <int value="481" + label="3ee6b341402851b27e64021a3023aac7c1a0d2def27d5bce5c2dbeb0b22dcc71"/> + <int value="482" + label="5899d913ead119b9cdb7ba2f30efe0df68ad2cd225bdf493e8323a25aa4dbe23"/> + <int value="483" + label="871a9194f4eed5b312ff40c84c1d524aed2f778bbff25f138cf81f680a7adc67"/> + <int value="484" + label="55f77de41c03792428f8d518c55104225be43a5598d926a528ad653e1ccec7bf"/> + <int value="485" + label="4179edd981ef747477b49626408af43daa2ca7ab7f9e082c1060f84096774348"/> + <int value="486" + label="9847e5653e5e9e847516e5cb818606aa7544a19be67fd7366d506988e8d84347"/> + <int value="487" + label="682747f8ba621b87cdd3bc295ed5cabce722a1c0c0363d1d68b38928d2787f1e"/> + <int value="488" + label="e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"/> + <int value="489" + label="282fb5cfbaf01518d9704de7884d7a25ff01cf882e994290d5995d5eb6c44988"/> + <int value="490" + label="fd371bea9755ff60c8828c849b8e5215de532d61b009855fa0ad630d90eef82e"/> +</enum> + <enum name="Network3GGobiError"> <summary> These error indexes are produced by QCErrorToMetricIndex() in @@ -27825,7 +31545,7 @@ </enum> <enum name="NotStreamingReason"> - <int value="0" label="Already loaded"/> + <int value="0" label="DEPRECATED: Already loaded"/> <int value="1" label="Not HTTP"/> <int value="2" label="Reload"/> <int value="3" label="Context not valid"/> @@ -27833,6 +31553,7 @@ <int value="5" label="Thread busy"/> <int value="6" label="V8 cannot stream"/> <int value="7" label="Script too small"/> + <int value="8" label="No resource buffer"/> </enum> <enum name="NPAPIPluginStatus"> @@ -27994,6 +31715,28 @@ <int value="3" label="Too few URLs, didn't flip tiles 1 and 4"/> </enum> +<enum name="NTPTileTitleSource"> + <summary> + The source where the displayed title of an NTP tile originates from. + </summary> + <int value="0" label="Unknown"> + The title might be invalid, aggregated, user-set, extracted from history, + not loaded or simply not known. + </int> + <int value="1" label="Manifest"> + The site's manifest contained a usable "(short_)name" attribute. + </int> + <int value="2" label="MetaTag"> + The site provided a meta tag (e.g. OpenGraph's site_name). + </int> + <int value="3" label="TitleTag"> + The site's title is used as tile title, extracted from the title tag. + </int> + <int value="4" label="InferredTitle"> + The title was inferred from multiple signals (e.g. meta tags, url, title). + </int> +</enum> + <enum name="NTPTileVisualType"> <summary>The visual type of a most visited tile on the new tab page.</summary> <int value="0" label="None">The icon or thumbnail hasn't loaded yet.</int> @@ -28072,6 +31815,16 @@ <int value="3" label="User clicked notification settings (disabled on O+)"/> </enum> +<enum name="OfflinePagesAccessEntryPoint"> + <int value="0" label="Other"/> + <int value="1" label="NTP suggestions or bookmarks"/> + <int value="2" label="Downloads home"/> + <int value="3" label="Omnibox"/> + <int value="4" label="CCT"/> + <int value="5" label="Clicking link"/> + <int value="6" label="Reloading page"/> +</enum> + <enum name="OfflinePagesAggregatedRequestResult"> <int value="0" label="Show offline page on disconnected network"/> <int value="1" label="Page not found on disconnected network"/> @@ -28089,6 +31842,11 @@ <int value="13" label="Redirected on flaky network"/> <int value="14" label="Redirected on prohibitively slow network"/> <int value="15" label="Redirected on connected network"/> + <int value="16" label="Digest mismatch on disconnected network"/> + <int value="17" label="Digest mismatch on flaky network"/> + <int value="18" label="Digest mismatch on prohibitively slow network"/> + <int value="19" label="Digest mismatch on connected network"/> + <int value="20" label="File not found"/> </enum> <enum name="OfflinePagesBackgroundImmediateStartStatus"> @@ -28234,6 +31992,34 @@ <int value="3" label="Data parsing failed"/> </enum> +<enum name="OfflinePagesNamespaceEnumeration"> + <int value="0" label="Default">Namespace used as default.</int> + <int value="1" label="Bookmark"> + Namespace used when offline page is saved when bookmarking. + </int> + <int value="2" label="Last_N"> + Namespace used when offline page is saved as last_n page. + </int> + <int value="3" label="Async_loading"> + Namespace used when offline page is saved from save page later on dino page. + </int> + <int value="4" label="Custom_tabs"> + Namespace used when offline page is saved from custom tabs. + </int> + <int value="5" label="Download"> + Namespace used when offline page is saved as downloads. + </int> + <int value="6" label="NTP_suggestions"> + Namespace used when offline page is saved as NTP suggestions. + </int> + <int value="7" label="Suggested_articles"> + Namespace used when offline page is saved as suggested articles. + </int> + <int value="8" label="Browser_actions"> + Namespace used when offline page is saved from browser actions. + </int> +</enum> + <enum name="OfflinePagesOfflineUsage"> <int value="0" label="Not used">Not used at all during whole day.</int> <int value="1" label="Started, but no pages loaded successfully"> @@ -28248,6 +32034,21 @@ </int> </enum> +<enum name="OfflinePagesPrefetchUsage"> + <int value="0" label="Has prefetched pages"> + Reported when Offline Model DB is loaded. + </int> + <int value="1" label="Only fetched new pages"> + Reported when at least one page was prefetched in a day, but none opened. + </int> + <int value="2" label="Only opened prefetched page"> + User opened at least one prefetched page, but no new pages were prefetched. + </int> + <int value="3" label="Both fetched and opened prefetched pages"> + The pages were both prefetched and opened during the day. + </int> +</enum> + <enum name="OfflinePagesRedirectResult"> <obsolete> Deprecated 2016-08. @@ -28299,6 +32100,16 @@ Save operation failed because an interstitial page (i.e. page warning of expired certificates or improper dev signatures) was detected. </int> + <int value="11" label="Digest calculation failure"> + Failed to compute the digest of an archive file. + </int> + <int value="12" label="File move failed"> + Unable to move the file into a public directory while creating an offline + copy. + </int> + <int value="13" label="Download Manager registration failed"> + Unable to add the file to the system download manager + </int> </enum> <enum name="OfflinePagesSharedPageWasOffline"> @@ -28306,6 +32117,28 @@ <int value="1" label="Offline"/> </enum> +<enum name="OfflinePagesStoreEvent"> + <int value="0" label="Store opened first time"> + Store was opened for this first time during this session. + </int> + <int value="1" label="Store reopened"> + Store was opened after closing at least once during this session. + </int> + <int value="2" label="Store closed">Store was closed.</int> + <int value="3" label="Store closing skipped"> + Store closing was skipped, because it was not opened at the time of closing. + </int> +</enum> + +<enum name="OfflinePagesSyncOperationResult"> + <int value="0" label="Success"/> + <int value="1" label="Invalid database connection"/> + <int value="2" label="Error when transaction begins"/> + <int value="3" label="Error when transaction commits"/> + <int value="4" label="Error when executing database statements"/> + <int value="5" label="Error when executing file operations"/> +</enum> + <enum name="OfflinePagesTabRestoreType"> <int value="0" label="While online"> Tab was successfully restored while the device was online. Can help assess @@ -28434,6 +32267,9 @@ <int value="1000" label="STALE_AT_DOWNLOADING"> Entry became stale while at the DOWNLOADING state. </int> + <int value="1050" label="STALE_AT_IMPORTING"> + Entry became stale while at the IMPORTING state. + </int> <int value="1100" label="STALE_AT_UNKNOWN"> Entry became stale at an unknown state. </int> @@ -28449,6 +32285,10 @@ <int value="1500" label="MAXIMUM_CLOCK_BACKWARD_SKEW_EXCEEDED"> The clock was set backwards too far in time. </int> + <int value="1600" label="IMPORT_LOST"> + The importing was not completed probably due to that Chrome was killed + before it was done. + </int> </enum> <enum name="OfflinePrefetchItemState"> @@ -28512,6 +32352,14 @@ <int value="4" label="Offline item already exists"/> </enum> +<enum name="OfflinePrefetchRequestStatus"> + <summary>Return status of calls to the Offline Page Service.</summary> + <int value="0" label="Success"/> + <int value="1" label="Should retry without backoff"/> + <int value="2" label="Should retry with backoff"/> + <int value="3" label="Should suspend"/> +</enum> + <enum name="OfflineStatus"> <obsolete> Deprecated 4/2015. @@ -28791,6 +32639,11 @@ <int value="3" label="(non-invalidated) replies received"/> </enum> +<enum name="OomInterventionUserDecision"> + <int value="0" label="Declined"/> + <int value="1" label="Accepted"/> +</enum> + <enum name="OpenFileSystemResult"> <int value="0" label="OK."/> <int value="1" label="In incognito mode."/> @@ -28809,6 +32662,13 @@ <int value="1" label="Active other profiles."/> </enum> +<enum name="OptimizationGuideProcessHintsResult"> + <int value="0" label="Success"/> + <int value="1" label="FailedInvalidParameters"/> + <int value="2" label="FailedReadingFile"/> + <int value="3" label="FailedInvalidConfiguration"/> +</enum> + <enum name="OriginTrialEnableResult"> <obsolete> Obsolete as of M54 and replaced by OriginTrialTokenStatus. @@ -28848,45 +32708,6 @@ <int value="9" label="TokenDisabled"/> </enum> -<enum name="OSAgnosticErrno"> - <summary>Errno values with the same meanings on Mac/Win/Linux.</summary> - <int value="0" label="0">No error</int> - <int value="1" label="EPERM">Operation not permitted</int> - <int value="2" label="ENOENT">No such file or directory</int> - <int value="3" label="ESRCH">No such process</int> - <int value="4" label="EINTR">Interrupted function call</int> - <int value="5" label="EIO">Input/output error</int> - <int value="6" label="ENXIO">No such device or address</int> - <int value="7" label="E2BIG">Arg list too long</int> - <int value="8" label="ENOEXEC">Exec format error</int> - <int value="9" label="EBADF">Bad file descriptor</int> - <int value="10" label="ECHILD">No child processes</int> - <int value="11" label="EDEADLK">Resource deadlock avoided</int> - <int value="12" label="ENOMEM">Cannot allocate memory</int> - <int value="13" label="EACCES">Permission denied</int> - <int value="14" label="EFAULT">Bad address</int> - <int value="15" label="ENOTBLK">Not a block device</int> - <int value="16" label="EBUSY">Resource busy</int> - <int value="17" label="EEXIST">File exists</int> - <int value="18" label="EXDEV">Improper link</int> - <int value="19" label="ENODEV">Operation not supported by device</int> - <int value="20" label="ENOTDIR">Not a directory</int> - <int value="21" label="EISDIR">Is a directory</int> - <int value="22" label="EINVAL">Invalid argument</int> - <int value="23" label="ENFILE">Too many open files in system</int> - <int value="24" label="EMFILE">Too many open files</int> - <int value="25" label="ENOTTY">Inappropriate ioctl for device</int> - <int value="26" label="ETXTBSY">Text file busy</int> - <int value="27" label="EFBIG">File too large</int> - <int value="28" label="ENOSPC">Device out of space</int> - <int value="29" label="ESPIPE">Illegal seek</int> - <int value="30" label="EROFS">Read-only file system</int> - <int value="31" label="EMLINK">Too many links</int> - <int value="32" label="EPIPE">Broken pipe</int> - <int value="33" label="EDOM">Numerical argument out of domain</int> - <int value="34" label="ERANGE">Numerical result out of range</int> -</enum> - <enum name="OsSuite"> <int value="0" label="Windows Home Edition (or unknown)"/> <int value="1" label="Windows Professional/Ultimate Editions"/> @@ -28962,6 +32783,18 @@ </int> </enum> +<enum name="OSXFullscreenSource"> + <int value="0" label="BROWSER"> + The window entered fullscreen for the browser. + </int> + <int value="1" label="TAB_CONTENT"> + The window entered fullscreen for the tab contents. + </int> + <int value="2" label="EXTENSION"> + The window entered fullscreen for an extension. + </int> +</enum> + <enum name="OSXFullscreenStyle"> <int value="0" label="IMMERSIVE"> The window was fullscreened using the immersive mechanism. @@ -28976,6 +32809,14 @@ </int> </enum> +<enum name="OSXFullscreenToolbarStyle"> + <int value="0" label="PRESENT">The fullscreen toolbar is always shown.</int> + <int value="1" label="HIDDEN"> + The fullscreen toolbar only appears when the menubar drops down. + </int> + <int value="2" label="NONE">The fullscreen toolbar is not visible.</int> +</enum> + <enum name="OSXFullscreenWindowLocation"> <int value="0" label="PRIMARY_SINGLE_SCREEN"> The window was located on the primary screen, and there is only a single @@ -29040,6 +32881,24 @@ <int value="10" label="Hide for now"/> </enum> +<enum name="OutOfProcessHeapProfilingMode"> + <int value="0" label="None"/> + <int value="1" label="Minimal"/> + <int value="2" label="All"/> + <int value="3" label="Browser"/> + <int value="4" label="Gpu"/> + <int value="5" label="Renderer Sampling"/> + <int value="6" label="All renderers"/> + <int value="7" label="Manual"/> +</enum> + +<enum name="OutOfProcessHeapProfilingProcessType"> + <int value="0" label="Other"/> + <int value="1" label="Browser"/> + <int value="2" label="Renderer"/> + <int value="3" label="GPU"/> +</enum> + <enum name="OutputDeviceStatus"> <int value="0" label="Ok"/> <int value="1" label="Not found"/> @@ -29107,7 +32966,7 @@ </obsolete> <summary> Result for PAC script experiment as defined in - net/proxy/proxy_resolver_v8_tracing.h + net/proxy_resolution/proxy_resolver_v8_tracing.h </summary> <int value="0" label="SKIPPED_FALLBACK_BLOCKING_DNS"/> <int value="1" label="SUCCESS"/> @@ -29160,6 +33019,7 @@ <int value="14" label="Invalid order - first paint / first image paint"/> <int value="15" label="Invalid order - first paint / first contentful paint"/> <int value="16" label="Invalid order - first paint / first meaningful paint"/> + <int value="17" label="Invalid order - first meaningful paint / interactive"/> </enum> <enum name="PageScaleFactorRange"> @@ -29371,6 +33231,36 @@ <int value="3" label="Cookie contains both control chars and is invalid"/> </enum> +<enum name="PartnerBookmark.FaviconFetchResult"> + <int value="0" label="SUCCESS"> + Success - favicon found in local cache or fetched from server. + </int> + <int value="1" label="FAILURE_SERVER_ERROR"> + Received a server error fetching the favicon. + </int> + <int value="2" label="FAILURE_ICON_SERVICE_UNAVAILABLE"> + The icon service was unavailable. + </int> + <int value="3" label="FAILURE_NOT_IN_CACHE"> + There was nothing in the cache, but we opted out of retrieving from server. + </int> + <int value="4" label="FAILURE_CONNECTION_ERROR"> + Request sent out and a connection error occurred (no valid HTTP response + received). + </int> + <int value="5" label="SUCCESS_FROM_CACHE"> + Success fetching the favicon from the cache without reaching out to the + server. + </int> + <int value="6" label="SUCCESS_FROM_SERVER"> + Success fetching the favicon from server. + </int> + <int value="7" label="FAILURE_WRITING_FAVICON_CACHE"> + Failed to write the favicon to cache, likely from attempting to add a + duplicate. + </int> +</enum> + <enum name="PassiveForcedListenerResultType"> <int value="0" label="PreventDefaultNotCalled"/> <int value="1" label="DocumentLevelTouchPreventDefaultCalled"/> @@ -29397,6 +33287,15 @@ <int value="2" label="No thanks"/> </enum> +<enum name="PasswordCertificateError"> + <int value="0" label="No error"/> + <int value="1" label="Other error"/> + <int value="2" label="Authority invalid (e.g., self-signed certificates)"/> + <int value="3" label="Date invalid (e.g., expired)"/> + <int value="4" label="Common name invalid"/> + <int value="5" label="Weak signature algorithm"/> +</enum> + <enum name="PasswordFormQueryVolume"> <int value="0" label="New password query"/> <int value="1" label="Current query"/> @@ -29429,6 +33328,8 @@ <int value="10" label="Generated popup shown (limit once per page)"/> <int value="11" label="Editing popup shown (limit once per page)"/> <int value="12" label="Generation triggered by autocomplete attributes"/> + <int value="13" label="Generation item in the context menu accepted"/> + <int value="14" label="Generation item in the context menu shown"/> </enum> <enum name="PasswordImportFromCSVResult"> @@ -29862,6 +33763,7 @@ <int value="0" label="Viewed"/> <int value="1" label="Deleted"/> <int value="2" label="Cancelled"/> + <int value="3" label="ViewedAfterSearched"/> </enum> <enum name="PasswordManagerAndroidUsernameActions"> @@ -30385,6 +34287,13 @@ <int value="2" label="Has Bookmarks"/> </enum> +<enum name="PDFFormTypes"> + <int value="0" label="None"/> + <int value="1" label="AcroForm"/> + <int value="2" label="Full XFA"/> + <int value="3" label="Foreground XFA (XFAF)"/> +</enum> + <enum name="PeerConnectionCounters"> <int value="0" label="PeerConnection enabled with IPv4."/> <int value="1" label="PeerConnection enabled with Ipv6."/> @@ -30392,6 +34301,11 @@ <int value="3" label="IPv6 BestConnection."/> </enum> +<enum name="PeerConnectionKeyProtocol"> + <int value="0" label="DTLS"/> + <int value="1" label="SDES"/> +</enum> + <enum name="PeerConnectionRtcpMux"> <int value="0" label="Disabled"/> <int value="1" label="Enabled"/> @@ -30404,6 +34318,11 @@ <int value="2" label="Default"/> </enum> +<enum name="PepperBrokerAction"> + <int value="0" label="Create"/> + <int value="1" label="Connect"/> +</enum> + <enum name="PepperInterface"> <!-- Generated by ppapi/tools/pepper_hash_for_uma.cc --> @@ -30601,6 +34520,19 @@ <int value="2126196629" label="PPB_UDPSocket_Private;0.4"/> </enum> +<enum name="PerformanceMeasurePassedInParameterType"> + <int value="0" label="OBJECT_OBJECT"/> + <int value="1" label="UNLOAD_EVENT_START"/> + <int value="2" label="UNLOAD_EVENT_END"/> + <int value="3" label="DOM_INTERACTIVE"/> + <int value="4" label="DOM_CONTENT_LOADED_EVENT_START"/> + <int value="5" label="DOM_CONTENT_LOADED_EVENT_END"/> + <int value="6" label="DOM_COMPLETE"/> + <int value="7" label="LOAD_EVENT_START"/> + <int value="8" label="LOAD_EVENT_END"/> + <int value="9" label="OTHER"/> +</enum> + <enum name="PermissionAction"> <int value="0" label="GRANTED"/> <int value="1" label="DENIED"/> @@ -30634,6 +34566,8 @@ <int value="13" label="PERMISSION_MEDIASTREAM_MIC"/> <int value="14" label="PERMISSION_MEDIASTREAM_CAMERA"/> <int value="15" label="PERMISSION_ACCESSIBILITY_EVENTS"/> + <int value="16" label="PERMISSION_CLIPBOARD_READ"/> + <int value="17" label="PERMISSION_SECURITY_KEY_ATTESTATION"/> </enum> <enum name="PermissionStatus"> @@ -30681,6 +34615,7 @@ <int value="3" label="Mapped-File Failure"/> <int value="5" label="Mapped-File Already Exists"/> <int value="6" label="No Spare File"/> + <int value="7" label="Could Not Create Upload Directory"/> </enum> <enum name="PhotoEditorFileType"> @@ -30733,6 +34668,9 @@ </enum> <enum name="PhysicalWebInitialStateIosChrome"> + <obsolete> + Obsolete as of November 2017. + </obsolete> <int value="0" label="OPTOUT_BTOFF_LOCOFF_UNAUTH"/> <int value="1" label="OPTOUT_BTOFF_LOCOFF_AUTH"/> <int value="2" label="OPTOUT_BTOFF_LOCON_UNAUTH"/> @@ -30795,6 +34733,8 @@ <int value="18" label="CHUNK_DEMUXER_ERROR_EOS_STATUS_NETWORK_ERROR"/> <int value="19" label="AUDIO_RENDERER_ERROR"/> <int value="20" label="AUDIO_RENDERER_ERROR_SPLICE_FAILED"/> + <int value="21" label="PIPELINE_ERROR_EXTERNAL_RENDERER_FAILED"/> + <int value="22" label="DEMUXER_ERROR_DETECTED_HLS"/> </enum> <enum name="Platform.BootMode.FirmwareWriteProtect"> @@ -30973,19 +34913,84 @@ <int value="11" label="Bad Key Validation Signature"/> </enum> +<enum name="PopularOSErrno"> + <summary> + Popular errno values. See the descriptions on "*/*/*" labels for + the applicable OS, usually Linux/Mac/Windows. See + http://www.ioplex.com/~miallen/errcmp.html and + http://www.ioplex.com/~miallen/errcmpp.html for more info. + </summary> + <int value="0" label="0">No error</int> + <int value="1" label="EPERM">Operation not permitted</int> + <int value="2" label="ENOENT">No such file or directory</int> + <int value="3" label="ESRCH">No such process</int> + <int value="4" label="EINTR">Interrupted function call</int> + <int value="5" label="EIO">Input/output error</int> + <int value="6" label="ENXIO">No such device or address</int> + <int value="7" label="E2BIG">Arg list too long</int> + <int value="8" label="ENOEXEC">Exec format error</int> + <int value="9" label="EBADF">Bad file descriptor</int> + <int value="10" label="ECHILD">No child processes</int> + <int value="11" label="EAGAIN/EDEADLK/EAGAIN"> + Try again on Linux. Resource deadlock avoided on Mac. Resource temporarily + unavailable on Windows. + </int> + <int value="12" label="ENOMEM">Cannot allocate memory</int> + <int value="13" label="EACCES">Permission denied</int> + <int value="14" label="EFAULT">Bad address</int> + <int value="15" label="ENOTBLK">Not a block device</int> + <int value="16" label="EBUSY">Resource busy</int> + <int value="17" label="EEXIST">File exists</int> + <int value="18" label="EXDEV">Improper link</int> + <int value="19" label="ENODEV">Operation not supported by device</int> + <int value="20" label="ENOTDIR">Not a directory</int> + <int value="21" label="EISDIR">Is a directory</int> + <int value="22" label="EINVAL">Invalid argument</int> + <int value="23" label="ENFILE">Too many open files in system</int> + <int value="24" label="EMFILE">Too many open files</int> + <int value="25" label="ENOTTY">Inappropriate ioctl for device</int> + <int value="26" label="ETXTBSY">Text file busy</int> + <int value="27" label="EFBIG">File too large</int> + <int value="28" label="ENOSPC">Device out of space</int> + <int value="29" label="ESPIPE">Illegal seek</int> + <int value="30" label="EROFS">Read-only file system</int> + <int value="31" label="EMLINK">Too many links</int> + <int value="32" label="EPIPE">Broken pipe</int> + <int value="33" label="EDOM">Numerical argument out of domain</int> + <int value="34" label="ERANGE">Numerical result out of range</int> + <int value="35" label="EDEADLK/EAGAIN/EUCLEAN"> + Resource deadlock would occur on Linux. Resource temporarily unavailable on + Mac. Unknown error on Windows. + </int> + <int value="36" label="ENAMETOOLONG/EINPROGRESS/EDEADLK"> + File name too long on Linux. Operation now in progress on Mac. Resource + deadlock avoided on Windows. + </int> + <int value="45" label="EL2NSYNC/EOPNOTSUPP/_"> + Level 2 not synchronized on Linux. Operation not supported on Mac. Resource + deadlock avoided on Windows. + </int> + <int value="63" label="ENOSR/ENAMETOOLONG/_"> + Out of streams resources on Linux. File name too long on Mac. + </int> + <int value="69" label="ESRMNT/EDQUOT/_"> + Srmount error on Linux. Disk quota exceeded on Mac. + </int> + <int value="92" label="ENOPROTOOPT/EILSEQ/_"> + Protocol not supported on Linux. Illegal byte sequence on Mac. + </int> + <int value="95" label="EOPNOTSUPP/_/_"> + Operation not supported on transport endpoint on Linux. + </int> + <int value="122" label="EDQUOT/_/_">Quota exceeeded on Linux.</int> +</enum> + <enum name="PopupBlockerAction"> <int value="0" label="Popup initiated"/> <int value="1" label="Popup blocked"/> <int value="2" label="Popup clicked through"/> </enum> -<enum name="PopupPosition"> - <int value="0" label="Only popup"/> - <int value="1" label="First popup"/> - <int value="2" label="Any middle popup"/> - <int value="3" label="Last popup"/> -</enum> - <enum name="Ports"> <int value="80" label="Port 80"/> <int value="443" label="Port 443"/> @@ -31138,6 +35143,35 @@ <int value="2" label="VERSION_LATEST"/> </enum> +<enum name="PrefServiceReadError"> + <int value="0" label="PREF_READ_ERROR_NONE"/> + <int value="1" label="PREF_READ_ERROR_JSON_PARSE"/> + <int value="2" label="PREF_READ_ERROR_JSON_TYPE"/> + <int value="3" label="PREF_READ_ERROR_ACCESS_DENIED"/> + <int value="4" label="PREF_READ_ERROR_FILE_OTHER"/> + <int value="5" label="PREF_READ_ERROR_FILE_LOCKED"/> + <int value="6" label="PREF_READ_ERROR_NO_FILE"/> + <int value="7" label="PREF_READ_ERROR_JSON_REPEAT"/> + <int value="8" label="PREF_READ_ERROR_OTHER"/> + <int value="9" label="PREF_READ_ERROR_FILE_NOT_SPECIFIED"/> +</enum> + +<enum name="PreloadedListCheckResult"> + <int value="0" label="origin was found and allowed https only"/> + <int value="1" label="origin was not found"/> + <int value="2" label="check failed because list was empty"/> + <int value="3" label="check failed because list was not loaded"/> + <int value="4" label="origin was found and allowed http or https"/> + <int value="5" label="origin was found and allowed https only but was http"/> +</enum> + +<enum name="PreloadedListLoadResult"> + <int value="0" label="loaded"/> + <int value="1" label="file not found"/> + <int value="2" label="file read failed"/> + <int value="3" label="parse proto failed"/> +</enum> + <enum name="PrerenderCookieSendType"> <obsolete> Deprecated March 13 2015. @@ -31461,20 +35495,39 @@ <int value="10" label="Login action added, Subframe, pw empty"/> </enum> -<enum name="PresentationResult"> - <int value="0" label="Requested"/> - <int value="1" label="Success"/> - <int value="2" label="SuccessAlreadyPresenting"/> - <int value="3" label="VRDisplayCannotPresent"/> - <int value="4" label="PresentationNotSupportedByDisplay"/> - <int value="5" label="VRDisplayNotFound"/> - <int value="6" label="NotInitiatedByUserGesture"/> - <int value="7" label="InvalidNumberOfLayers"/> - <int value="8" label="InvalidLayerSource"/> - <int value="9" label="LayerSourceMissingWebGLContext"/> - <int value="10" label="InvalidLayerBounds"/> - <int value="11" label="ServiceInactive"/> - <int value="12" label="RequestDenied"/> +<enum name="PresentAddPassesDialogResult"> + <summary> + Defines the result of Add Passes dialog presentation. The presentation can + be successful or unsuccessful if another view controller is currently + presented. Unsuccessful presentation is a bug and if the number of + unsuccessful presentations is high, it means that Chrome has to queue the + dialogs to present those dialogs for every downloaded pkpass (PassKit file). + Currently Chrome simply ignores the download if the dialog is already + presented. + </summary> + <int value="0" label="Successful"> + The dialog was sucessesfully presented. + </int> + <int value="1" label="Another Add Passes View Controller Is Presented"> + The dialog cannot be presented, because another PKAddPassesViewController is + already presented. + </int> + <int value="2" label="Another View Controller Is Presented"> + The dialog cannot be presented, because another view controller is already + presented. Does not include items already counted in the more specific + bucket (Another Add Passes View Controller Is Presented). + </int> +</enum> + +<enum name="PresentationUrlType"> + <int value="0" label="Other"/> + <int value="1" label="Cast"/> + <int value="2" label="CastDial"/> + <int value="3" label="CastLegacy"/> + <int value="4" label="Dial"/> + <int value="5" label="Http"/> + <int value="6" label="Https"/> + <int value="7" label="RemotePlayback"/> </enum> <enum name="PreTapEvents"> @@ -31507,6 +35560,14 @@ shown on a reload."/> <int value="9" label="Host blacklisted by server rules provided to the client."/> + <int value="10" + label="Host not whitelisted by server rules provided to the client."/> + <int value="11" label="Preview Allowed without server rule check."/> + <int value="12" label="Committed Preview."/> + <int value="13" label="Received no-transform directive."> + Response header had Cache-Control:no-transform directive (developer + opt-out). + </int> </enum> <enum name="PreviewsInfoBarAction"> @@ -31530,6 +35591,29 @@ label="Timestamp shown indicating the page was just updated on reload"/> </enum> +<enum name="PreviewsProcessHintsResult"> + <int value="0" label="No hints found"> + Previews processed but no Previews hints found. + </int> + <int value="1" label="Hints found"> + Previews processed and Previews hints found. + </int> + <int value="2" label="Failed processing"> + Failed to finish processing same version previously so skipping to avoid + potential crash loop. + </int> +</enum> + +<enum name="PreviewsType"> + <int value="0" label="None"/> + <int value="1" label="Offline"/> + <int value="2" label="LoFi"/> + <int value="3" label="LitePage"/> + <int value="4" label="AMP Redirection"/> + <int value="5" label="NoScript"/> + <int value="6" label="Unspecified"/> +</enum> + <enum name="PreviewsUserOptedOut"> <int value="0" label="The user did not choose to reload the full page."/> <int value="1" label="The user chose to reload the full page."/> @@ -31544,6 +35628,7 @@ <int value="5" label="HyperText Transfer Protocol Secure (https)"/> <int value="6" label="App Socket (socket)"/> <int value="7" label="Line Print Daemon (lpd)"/> + <int value="8" label="IPP-over-USB (ippusb)"/> </enum> <enum name="PrinterServiceEventType"> @@ -31571,18 +35656,18 @@ <int value="2" label="Cancelled due to timeout"/> <int value="3" label="Cancelled by printer"/> <int value="4" label="Lost track of job"/> + <int value="5" label="Filter failed"/> </enum> <enum name="PrintPreviewFailureType"> <int value="0" label="No error"/> <int value="1" label="Bad settings from print preview tab"/> - <int value="2" label="Copy metadata failed (Deprecated)"/> - <int value="3" label="Metafile init failed"/> + <int value="2" label="Copy metadata failed"/> + <int value="3" label="Metafile init failed (Deprecated)"/> <int value="4" label="0-page preview"/> <int value="5" label="Mac draft metafile init failed (Deprecated)"/> - <int value="6" label="PreviewPageRendered with no metafile"/> - <int value="7" label="UpdatePrintSettings failed"/> - <int value="8" label="Received bad printer settings"/> + <int value="6" label="PreviewPageRendered with no metafile (Deprecated)"/> + <int value="7" label="Received bad printer settings"/> </enum> <enum name="PrintPreviewFontTypeType"> @@ -32149,6 +36234,51 @@ <int value="7" label="SAVING_ON_HTTP_AFTER_HTTPS"/> </enum> +<enum name="ProximityAuth_BleWeaveConnectionResult"> + <int value="0" label="Closed normally"/> + <int value="1" label="Timeout: Setting connection latency"/> + <int value="2" label="Timeout: Creating GATT connection"/> + <int value="3" label="Timeout: Starting notify session"/> + <int value="4" label="Timeout: Finding GATT characteristics"/> + <int value="5" label="Timeout: Waiting for connection response"/> + <int value="6" label="Error: Bluetooth device not available"/> + <int value="7" label="Error: Creating GATT connection"/> + <int value="8" label="Error: Starting notify session"/> + <int value="9" label="Error: Finding GATT characteristics"/> + <int value="10" label="Error: Writing GATT characteristics"/> + <int value="11" label="Error: GATT characteristics not available"/> + <int value="12" label="Error: Write queue out of sync"/> + <int value="13" label="Error: Device lost"/> + <int value="14" label="Error: Connection dropped"/> + <int value="15" label="Timeout: Waiting for message to send"/> +</enum> + +<enum name="ProximityAuth_BluetoothGattConnectionResult"> + <int value="0" label="Success"/> + <int value="1" label="Error: Auth canceled"/> + <int value="2" label="Error: Auth failed"/> + <int value="3" label="Error: Auth rejected"/> + <int value="4" label="Error: Auth timeout"/> + <int value="5" label="Error: Failed"/> + <int value="6" label="Error: In progress"/> + <int value="7" label="Error: Unknown"/> + <int value="8" label="Error: Unsupported device"/> + <int value="9" label="Unknown result"/> +</enum> + +<enum name="ProximityAuth_BluetoothGattServiceOperationResult"> + <int value="0" label="Success"/> + <int value="1" label="Error: Unknown"/> + <int value="2" label="Error: Failed"/> + <int value="3" label="Error: In progress"/> + <int value="4" label="Error: Invalid length"/> + <int value="5" label="Error: Not permitted"/> + <int value="6" label="Error: Not authorized"/> + <int value="7" label="Error: Not paired"/> + <int value="8" label="Error: Not supported"/> + <int value="9" label="Unknown result"/> +</enum> + <enum name="ProxyStatus"> <int value="0" label="PROXY_STATUS_IGNORED"/> <int value="1" label="PROXY_UNINITIALIZED"/> @@ -32415,6 +36545,16 @@ <int value="254" label="DOMAIN_SPIDEROAK_COM"/> </enum> +<enum name="PullDownGestureAction"> + <summary>The type of action performed on the overscroll UI.</summary> + <int value="0" label="NewTab">The user selected the new tab action.</int> + <int value="1" label="Refresh">The user selected the refresh action.</int> + <int value="2" label="CloseTab">The user selected the close tab action.</int> + <int value="3" label="Canceled"> + The user canceled the action by scrolling back up. + </int> +</enum> + <enum name="PushDeliveryStatus"> <int value="0" label="Successful"/> <int value="1" label="Message was invalid"/> @@ -32426,6 +36566,21 @@ <int value="7" label="Service Worker timeout while processing event"/> </enum> +<enum name="PushedStreamVaryResponseHeaderValues"> + <int value="0" label="There is no Vary header."/> + <int value="1" label="The value of Vary is empty."/> + <int value="2" label="The value of Vary is "*"."/> + <int value="3" + label="The value of Vary is "accept-encoding" (case + insensitive)."/> + <int value="4" + label="The value of Vary contains "accept-encoding" (case + insensitive) and some other field names as well."/> + <int value="5" + label="The value of Vary does not contain "accept-encoding", + is not empty, and is not "*"."/> +</enum> + <enum name="PushGetRegistrationStatus"> <int value="0" label="Successful"/> <int value="1" label="No push service"/> @@ -32507,6 +36662,11 @@ <int value="2" label="ALTERNATIVE_PROXY_USAGE_LOST_RACE"/> </enum> +<enum name="QuicAltSvcFormat"> + <int value="0" label="Google format"/> + <int value="1" label="IETF format"/> +</enum> + <enum name="QuicBadPacketLossEvents"> <int value="1" label="ONE_PACKET_LOST"/> <int value="2" label="TWO_PACKETS_LOST"/> @@ -32522,8 +36682,10 @@ <int value="3" label="TOO_MANY_CHANGES"/> <int value="4" label="SUCCESS"/> <int value="5" label="NON_MIGRATABLE_STREAM"/> - <int value="6" label="DISABLED"/> - <int value="7" label="MIGRATION_STATUS_NO_ALTERNATE_NETWORK"/> + <int value="6" label="NOT_ENABLED"/> + <int value="7" label="NO_ALTERNATE_NETWORK"/> + <int value="8" label="ON_PATH_DEGRADING_DISABLED"/> + <int value="9" label="DISABLED_BY_CONFIG"/> </enum> <enum name="QuicDisabledReason"> @@ -32662,6 +36824,9 @@ <int value="95" label="STREAM_SEQUENCER_INVALID_STATE"/> <int value="96" label="TOO_MANY_SESSIONS_ON_SERVER"/> <int value="97" label="HEADERS_STREAM_DATA_DECOMPRESS_FAILURE"/> + <int value="98" label="STREAM_LENGTH_OVERFLOW"/> + <int value="99" label="CONNECTION_MIGRATION_DISABLED_BY_CONFIG"/> + <int value="100" label="CONNECTION_MIGRATION_INTERNAL_ERROR"/> </enum> <enum name="QuicHandshakeFailureReason"> @@ -32786,6 +36951,14 @@ <int value="2" label="REF_COUNT"/> </enum> +<enum name="QuicPlatformNotification"> + <int value="0" label="NETWORK_CONNECTED"/> + <int value="1" label="NETWORK_MADE_DEFAULT"/> + <int value="2" label="NETWORK_DISCONNECTED"/> + <int value="3" label="NETWORK_SOON_TO_DISCONNECT"/> + <int value="4" label="NETWORK_IP_ADDRESS_CHANGED"/> +</enum> + <enum name="QuicRejectReasons"> <int value="1" label="CLIENT_NONCE_UNKNOWN_FAILURE"/> <int value="2" label="CLIENT_NONCE_INVALID_FAILURE"/> @@ -32907,6 +37080,12 @@ <int value="2" label="LOAD_CORRUPT_VALUE"/> </enum> +<enum name="RasterSourceClearType"> + <int value="0" label="No clear"/> + <int value="1" label="Full clear"/> + <int value="2" label="Border clear"/> +</enum> + <enum name="ReadingListContextMenuActions"> <int value="0" label="New Tab"/> <int value="1" label="New Incognito Tab"/> @@ -33038,6 +37217,50 @@ <int value="3" label="Audio and video"/> </enum> +<enum name="RendererSchedulerFrameType"> + <obsolete> + Superseded by RendererSchedulerFrameType2 as of 11/2017. + </obsolete> + <int value="0" label="MainFrame_OnScreen"/> + <int value="1" label="MainFrame_OffScreen"/> + <int value="2" label="MainFrame_Background"/> + <int value="3" label="MainFrame_Background_ThrottlingExempt"/> + <int value="4" label="SameOrigin_OnScreen"/> + <int value="5" label="SameOrigin_OffScreen"/> + <int value="6" label="SameOrigin_Background"/> + <int value="7" label="SameOrigin_Background_ThrottlingExempt"/> + <int value="8" label="CrossOrigin_OnScreen"/> + <int value="9" label="CrossOrigin_OffScreen"/> + <int value="10" label="CrossOrigin_Background"/> + <int value="11" label="CrossOrigin_Background_ThrottlingExempt"/> +</enum> + +<enum name="RendererSchedulerFrameType2"> + <int value="0" label="Non-frame"/> + <int value="1" label="Detached"/> + <int value="2" label="MainFrame_OnScreen"/> + <int value="3" label="MainFrame_OnScreen_ForcedForeground"/> + <int value="4" label="MainFrame_OffScreen"/> + <int value="5" label="MainFrame_OffScreen_ForcedForeground"/> + <int value="6" label="MainFrame_Background"/> + <int value="7" label="MainFrame_Background_ThrottlingExempt_Self"/> + <int value="8" label="MainFrame_Background_ThrottlingExempt_Other"/> + <int value="9" label="SameOrigin_OnScreen"/> + <int value="10" label="SameOrigin_OnScreen_ForcedForeground"/> + <int value="11" label="SameOrigin_OffScreen"/> + <int value="12" label="SameOrigin_OffScreen_ForcedForeground"/> + <int value="13" label="SameOrigin_Background"/> + <int value="14" label="SameOrigin_Background_ThrottlingExempt_Self"/> + <int value="15" label="SameOrigin_Background_ThrottlingExempt_Other"/> + <int value="16" label="CrossOrigin_OnScreen"/> + <int value="17" label="CrossOrigin_OnScreen_ForcedForeground"/> + <int value="18" label="CrossOrigin_OffScreen"/> + <int value="19" label="CrossOrigin_OffScreen_ForcedForeground"/> + <int value="20" label="CrossOrigin_Background"/> + <int value="21" label="CrossOrigin_Background_ThrottlingExempt_Self"/> + <int value="22" label="CrossOrigin_Background_ThrottlingExempt_Other"/> +</enum> + <enum name="RendererSchedulerTaskQueueType"> <int value="0" label="Control"/> <int value="1" label="Default"/> @@ -33051,6 +37274,58 @@ <int value="9" label="Idle"/> <int value="10" label="Test"/> <int value="11" label="FrameLoadingControl"/> + <int value="12" label="FrameThrottleable"/> + <int value="13" label="FrameDeferrable"/> + <int value="14" label="FramePausable"/> + <int value="15" label="FrameUnpausable"/> + <int value="16" label="V8"/> + <int value="17" label="IPC"/> + <int value="18" label="Input"/> +</enum> + +<enum name="RendererSchedulerTaskType"> + <int value="0" label="None"/> + <int value="1" label="DOMManipulation"/> + <int value="2" label="UserInteraction"/> + <int value="3" label="Networking"/> + <int value="4" label="NetworkingControl"/> + <int value="5" label="HistoryTraversal"/> + <int value="6" label="Embed"/> + <int value="7" label="MediaElementEvent"/> + <int value="8" label="CanvasBlobSerialization"/> + <int value="9" label="Microtask"/> + <int value="10" label="JavascriptTimer"/> + <int value="11" label="RemoteEvent"/> + <int value="12" label="WebSocket"/> + <int value="13" label="PostedMessage"/> + <int value="14" label="UnshippedPortMessage"/> + <int value="15" label="FileReading"/> + <int value="16" label="DatabaseAccess"/> + <int value="17" label="Presentation"/> + <int value="18" label="Sensor"/> + <int value="19" label="PerformanceTimeline"/> + <int value="20" label="WebGL"/> + <int value="21" label="IdleTask"/> + <int value="22" label="MiscPlatformAPI"/> + <int value="23" label="UnspecedTimer"/> + <int value="24" label="UnspecedLoading"/> + <int value="25" label="Unthrottled"/> + <int value="26" label="InternalTest"/> + <int value="27" label="InternalWebCrypto"/> + <int value="28" label="InternalIndexedDB"/> + <int value="29" label="InternalMedia"/> + <int value="30" label="InternalMediaRealTime"/> +</enum> + +<enum name="RendererSchedulerThreadType"> + <int value="0" label="MainThread"/> + <int value="1" label="UnspecifiedWorkerThread"/> + <int value="2" label="CompositorThread"/> + <int value="3" label="DedicatedWorkerThread"/> + <int value="4" label="SharedWorkerThread"/> + <int value="5" label="AnimationWorkletThread"/> + <int value="6" label="ServiceWorkerThread"/> + <int value="7" label="AudioWorkletThread"/> </enum> <enum name="RendererType"> @@ -33162,6 +37437,8 @@ <int value="87" label="IDC_CONTENT_CONTEXT_OPEN_WITH14"/> <int value="88" label="IDC_CONTENT_CONTEXT_EXIT_FULLSCREEN"/> <int value="89" label="IDC_CONTENT_CONTEXT_OPENLINKBOOKMARKAPP"/> + <int value="90" label="IDC_CONTENT_CONTEXT_SHOWALLSAVEDPASSWORDS"/> + <int value="91" label="IDC_CONTENT_CONTENT_PICTUREINPICTURE"/> </enum> <enum name="ReportingHeaderEndpointOutcome"> @@ -33177,6 +37454,9 @@ <int value="9" label="Removed (max-age = 0)"/> <int value="10" label="Set rejected by delegate (max-age > 0)"/> <int value="11" label="Set (max-age > 0)"/> + <int value="12" label="Discarded: priority not an integer"/> + <int value="13" label="Discarded: weight not an integer"/> + <int value="14" label="Discarded: weight not positive"/> </enum> <enum name="ReportingHeaderOutcome"> @@ -33258,6 +37538,8 @@ <int value="1" label="RESOLVE_FAIL"/> <int value="2" label="RESOLVE_SPECULATIVE_SUCCESS"/> <int value="3" label="RESOLVE_SPECULATIVE_FAIL"/> + <int value="4" label="RESOLVE_ABORT"/> + <int value="5" label="RESOLVE_SPECULATIVE_ABORT"/> </enum> <enum name="ResolutionUnspecWasteCategory"> @@ -33290,6 +37572,9 @@ </enum> <enum name="ResourceLoaderExpectedContentSizeResult"> + <obsolete> + Removed 10/2017. + </obsolete> <int value="0" label="EQ_RESPONSE_BODY"/> <int value="1" label="EQ_RESPONSE_BODY_GT_EQ_BUFFER_SIZE"/> <int value="2" label="GT_EQ_BUFFER_SIZE"/> @@ -33307,6 +37592,13 @@ <int value="5" label="HasContentEncoding"/> </enum> +<enum name="ResourceLoadSchedulerCircumstance"> + <int value="0" label="Main frame, throttled"/> + <int value="1" label="Main frame, not throttled"/> + <int value="2" label="Sub frame, throttled"/> + <int value="3" label="Sub frame, not throttled"/> +</enum> + <enum name="ResourcePrefetchPredictorMainFrameRequestStats"> <int value="0" label="MAIN_FRAME_REQUEST_STATS_TOTAL_REQUESTS"/> <int value="1" label="MAIN_FRAME_REQUEST_STATS_PROCESSED_REQUESTS"/> @@ -33433,6 +37725,17 @@ <int value="3" label="Load"/> </enum> +<enum name="RSAKeyUsage"> + <int value="0" label="Not an RSA key"/> + <int value="1" label="OK (no extension)"/> + <int value="2" label="OK (both bits present)"/> + <int value="3" label="OK (digitalSignature present)"/> + <int value="4" label="OK (keyEncipherment present)"/> + <int value="5" label="Missing digitalSignature"/> + <int value="6" label="Missing keyEncipherment"/> + <int value="7" label="Error parsing certificate"/> +</enum> + <enum name="RunningMode"> <obsolete> Removed 9/2016. @@ -34140,6 +38443,26 @@ <int value="286" label="XHT"/> <int value="287" label="XHTM"/> <int value="288" label="XHTML"/> + <int value="289" label="VDX"/> + <int value="290" label="VSX"/> + <int value="291" label="VTX"/> + <int value="292" label="VSDX"/> + <int value="293" label="VSSX"/> + <int value="294" label="VSTX"/> + <int value="295" label="VSDM"/> + <int value="296" label="VSSM"/> + <int value="297" label="VSTM"/> + <int value="298" label="BTAPP"/> + <int value="299" label="BTBTSKIN"/> + <int value="300" label="BTINSTALL"/> + <int value="301" label="BTKEY"/> + <int value="302" label="BTSEARCH"/> + <int value="303" label="DHTML"/> + <int value="304" label="DHTM"/> + <int value="305" label="DHT"/> + <int value="306" label="SHTML"/> + <int value="307" label="SHTM"/> + <int value="308" label="SHT"/> </enum> <enum name="SBClientDownloadIsSignedBinary"> @@ -34261,6 +38584,13 @@ <int value="9" label="Rollback: SBER2 absent so SBER1 must be cleared"/> </enum> +<enum name="ScrollAnchorRestorationStatus"> + <int value="0" label="SUCCESS"/> + <int value="1" label="FAILED_NO_MATCHES"/> + <int value="2" label="FAILED_NO_VALID_MATCHES"/> + <int value="3" label="FAILED_BAD_SELECTOR"/> +</enum> + <enum name="ScrollingThreadStatus"> <int value="0" label="SCROLLING_ON_COMPOSITOR"/> <int value="1" label="SCROLLING_ON_COMPOSITOR_BLOCKED_ON_MAIN"/> @@ -34276,6 +38606,8 @@ <int value="0" label="No valid STH"/> <int value="1" label="Requires newer STH"/> <int value="2" label="Can be checked for inclusion"/> + <int value="3" label="Queue is full"/> + <int value="4" label="No DNS lookup performed"/> </enum> <enum name="SCTOrigin"> @@ -34529,6 +38861,15 @@ <int value="11" label="SHOW_WHITEPAPER"/> </enum> +<enum name="SecurityLevel"> + <int value="0" label="None"/> + <int value="1" label="Non-secure with warning"/> + <int value="2" label="Secure with EV certificate"/> + <int value="3" label="Secure"/> + <int value="4" label="Secure with policy-installed certificate"/> + <int value="5" label="Dangerous"/> +</enum> + <enum name="SelectFileDialogScope"> <int value="0" label="Generic files"/> <int value="1" label="Images"/> @@ -34577,23 +38918,6 @@ <int value="11" label="SERVICE_UTILITY_FAILED_TO_START"/> </enum> -<enum name="ServiceWorkerCacheErrorType"> - <int value="0" label="OK"/> - <int value="1" label="Exists Error"/> - <int value="2" label="Storage Error"/> - <int value="3" label="Not Found Error"/> - <int value="4" label="Quota Exceeded Error"/> -</enum> - -<enum name="ServiceWorkerCacheResponseType"> - <int value="0" label="Basic"/> - <int value="1" label="CORS"/> - <int value="2" label="Default"/> - <int value="3" label="Error"/> - <int value="4" label="Opaque"/> - <int value="5" label="OpaqueRedirect"/> -</enum> - <enum name="ServiceWorkerContextRequestHandlerStatus"> <summary> The result of ServiceWorkerContextHandler handling a request for a service @@ -34752,6 +39076,7 @@ <int value="13" label="ForeignFetchMismatchedOrigin"/> <int value="14" label="RedirectedResponseForNotFollowRequest"/> <int value="15" label="DataPipeCreationFailed (insufficient resources)"/> + <int value="16" label="ResponseTypeCORSForRequestModeSameOrigin"/> </enum> <enum name="ServiceWorkerSite"> @@ -34972,6 +39297,7 @@ <int value="4" label="Recently prompted, no reset required"/> <int value="5" label="Other setting requires reset, no reset required"/> <int value="6" label="Policy detected, no reset required"/> + <int value="7" label="Overriden by extension, no reset required"/> </enum> <enum name="SettingsResetPromptSettingsReset"> @@ -35176,7 +39502,7 @@ </enum> <enum name="ShouldAllowOpenURLFailureScheme"> -<!-- Generated from chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc --> +<!-- Generated from chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc.--> <int value="0" label="SCHEME_UNKNOWN"/> <int value="1" label="SCHEME_EMPTY"/> @@ -35201,9 +39527,10 @@ </enum> <enum name="ShowAllSavedPasswordsContext"> - <int value="0" label="No Context"/> - <int value="1" label="Password Suggestions"/> - <int value="2" label="Manual Fallback"/> + <int value="0" label="None"/> + <int value="1" label="Under password suggestions"/> + <int value="2" label="Standalone suggestion"/> + <int value="3" label="Context menu"/> </enum> <enum name="ShutdownReason"> @@ -35293,12 +39620,21 @@ <int value="2" label="New Profile"/> </enum> +<enum name="SigninDiceMigrationStatus"> + <int value="0" label="Enabled"/> + <int value="1" label="Disabled, ready for migration"/> + <int value="2" label="Disabled, not ready for migration"/> +</enum> + <enum name="SigninDiceResponseHeader"> <int value="0" label="Signin"/> <int value="1" label="SignoutPrimary"> - Signout including the primary account. + Signout including the Chrome primary account. </int> - <int value="2" label="SignoutSecondary">Signout only secondary accounts.</int> + <int value="2" label="SignoutSecondary"> + Signout not including the Chrome primary accounts. + </int> + <int value="3" label="EnableSync">Enable Sync after signin.</int> </enum> <enum name="SigninDiceTokenFetchResult"> @@ -35367,6 +39703,8 @@ <int value="2" label="Reauthentication"/> <int value="3" label="Unlock profile"/> <int value="4" label="Typed URL with unknown reason"/> + <int value="5" + label="Signin primary account with force-sign-in policy enabled"/> </enum> <enum name="SigninReauthStates"> @@ -35473,6 +39811,12 @@ <int value="1" label="Empty stream 2 file removed"/> </enum> +<enum name="SimpleCache.FileDescriptorLimiterOp"> + <int value="0" label="Close file"/> + <int value="1" label="Reopen file successfully"/> + <int value="2" label="Fail to reopen file"/> +</enum> + <enum name="SimpleCache.FileDescriptorLimitStatus"> <int value="0" label="Unsupported"/> <int value="1" label="Supported but failed"/> @@ -35659,6 +40003,14 @@ <int value="4" label="Others"/> </enum> +<enum name="SiteIsolationResponseAction"> + <int value="0" label="Response started"/> + <int value="1" label="Response blocked without sniffing"/> + <int value="2" label="Response blocked after sniffing"/> + <int value="3" label="Response allowed without sniffing"/> + <int value="4" label="Response allowed after sniffing"/> +</enum> + <enum name="SkiaFilterQuality"> <int value="0" label="None"/> <int value="1" label="Low"/> @@ -35706,6 +40058,9 @@ <int value="18" label="TRANSLATE_ALWAYS"/> <int value="19" label="TRANSLATE_NEVER"/> <int value="20" label="TRANSLATE_NEVER_SITE"/> + <int value="21" label="SNIPPET_FETCH_FAILED"/> + <int value="22" label="CHROME_HOME_OPT_OUT_SURVEY"/> + <int value="23" label="SNIPPET_FETCH_NO_NEW_SUGGESTIONS"/> </enum> <enum name="SnippetOpenMethod"> @@ -35769,6 +40124,12 @@ <int value="4" label="Failed to save to file"/> </enum> +<enum name="SoftwareReporterCleanerSettingsPageActiveOnRebootRequired"> + <int value="0" label="No browser available"/> + <int value="1" label="Settings page not the active tab"/> + <int value="2" label="Settings page current active tab"/> +</enum> + <enum name="SoftwareReporterCleanupResult"> <int value="0" label="Succeeded"/> <int value="1" label="Reboot required"/> @@ -35781,8 +40142,9 @@ </enum> <enum name="SoftwareReporterExperimentError"> - <int value="1" label="Bad tag"/> - <int value="2" label="Bad parameters"/> + <int value="0" label="Bad tag"/> + <int value="1" label="Bad parameters"/> + <int value="2" label="Missing parameters"/> </enum> <enum name="SoftwareReporterIPCDisconnected"> @@ -35792,9 +40154,11 @@ </enum> <enum name="SoftwareReporterLogsUploadEnabled"> - <int value="0" label="Enabled"/> + <int value="0" label="SBER Enabled"/> <int value="1" label="SBER Disabled"/> <int value="2" label="Recently sent logs"/> + <int value="3" label="Disabled by user"/> + <int value="4" label="Enabled by user"/> </enum> <enum name="SoftwareReporterLogsUploadResult"> @@ -35840,6 +40204,23 @@ <int value="2" label="On browser window available"/> </enum> +<enum name="SoftwareReporterSequenceResult"> + <int value="1" label="Not scheduled"/> + <int value="2" label="Timed-out"/> + <int value="3" label="Component not available"/> + <int value="4" label="Process failed to launch"/> + <int value="5" label="General failure"/> + <int value="6" label="Nothing found"/> + <int value="7" label="Cleanup not offered"/> + <int value="8" label="Cleanup to be offered"/> +</enum> + +<enum name="SoftwareReporterSequenceType"> + <int value="1" label="Periodic run"/> + <int value="2" label="User-initiated with logs disabled"/> + <int value="3" label="User-initiated with logs enabled"/> +</enum> + <enum name="SpareWebContentsStatus"> <int value="0" label="Created"/> <int value="1" label="Used"/> @@ -36263,8 +40644,8 @@ <int value="2" label="RECOVERY_FAILED_VIRTUAL_TABLE_INIT"> Failed to initialize recover vtable subsystem for connection. </int> - <int value="3" label="RECOVERY_FAILED_VIRTUAL_TABLE_SYSTEM_SQLITE"> - USE_SYSTEM_SQLITE in force, recovery virtual table not available. + <int value="3" label="DEPRECATED_RECOVERY_FAILED_VIRTUAL_TABLE_SYSTEM_SQLITE"> + Deprecated: USE_SYSTEM_SQLITE is no longer supported. </int> <int value="4" label="RECOVERY_FAILED_WRITABLE_SCHEMA"> Failed to enable writable_schema. @@ -36434,6 +40815,9 @@ </enum> <enum name="SqliteVfsEvents"> + <obsolete> + Removed 2018/02/06. + </obsolete> <summary>I/O events from browser-process SQLite VFS wrapper.</summary> <int value="0" label="VFS_OPEN">Calls to xOpen().</int> <int value="1" label="VFS_DELETE">Calls to xDelete().</int> @@ -36460,6 +40844,10 @@ </enum> <enum name="SRTPromptUsage"> + <obsolete> + Deprecated as of 2017-11-01. Replaced with + SoftwareReporterPromptDialogResponse. + </obsolete> <int value="0" label="Shown"/> <int value="1" label="Accepted"/> <int value="2" label="Denied"/> @@ -36470,6 +40858,9 @@ </enum> <enum name="SSLAuthRootConsistency"> + <obsolete> + Deprecated as of 2018-01. + </obsolete> <summary> The results of comparing the built-in list of known Windows roots against programatically detecting the built-in status. @@ -36695,6 +41086,7 @@ <int value="9" label="CAPTIVE_PORTAL_CERT_FOUND"/> <int value="10" label="WWW_MISMATCH_FOUND_IN_SAN"/> <int value="11" label="SHOW_MITM_SOFTWARE_INTERSTITIAL"/> + <int value="12" label="OS_REPORTS_CAPTIVE_PORTAL"/> </enum> <enum name="SSLErrorTypes"> @@ -36877,6 +41269,12 @@ <int value="7" label="Protocol error"/> </enum> +<enum name="SSOPromoUserAction"> + <int value="0" label="ACTION_DISMISSED"/> + <int value="1" label="ACTION_ENABLED_SSO_ACCOUNT"/> + <int value="2" label="ACTION_ADDED_ANOTHER_ACCOUNT"/> +</enum> + <enum name="StarsLaunchLocation"> <int value="0" label="All Items"/> <int value="1" label="Uncategorized"/> @@ -36946,6 +41344,14 @@ <int value="1" label="Leave the current page"/> </enum> +<enum name="StrongPopupBlockerAction"> + <int value="0" label="Navigation commit"/> + <int value="1" label="Commit warn site"/> + <int value="2" label="Commit enforced site"/> + <int value="3" label="Popup considered"/> + <int value="4" label="Popup blocked"/> +</enum> + <enum name="StyleSheetCacheStatus"> <int value="0" label="No usable cache found"/> <int value="1" label="DiskCache served the CSS source"/> @@ -37346,6 +41752,26 @@ </int> </enum> +<enum name="SurveyDownloadResponseCodes"> + <int value="-1" label="Response code missing"/> + <int value="0" label="Survey downloaded"/> + <int value="1" label="No survey available"/> + <int value="2" label="Survey library version disabled"/> + <int value="3" label="Max surveys already shown"/> + <int value="4" label="Failed to download survey"/> + <int value="5" label="Unknown response code"/> +</enum> + +<enum name="SurveyFilteringResult"> + <int value="0" label="Survey info bar already displayed"/> + <int value="1" label="Chrome Home enabled for less than one week"/> + <int value="2" label="Force Survey On command present"/> + <int value="3" label="User already sampled today"/> + <int value="4" label="Max number is missing"/> + <int value="5" label="Rolled a non-zero number"/> + <int value="6" label="User selected for survey"/> +</enum> + <enum name="SuspendAttempt"> <int value="0" label="Attempted"/> </enum> @@ -37377,6 +41803,19 @@ <int value="4" label="Swap was unsuccessful (activation fails)"/> </enum> +<enum name="SwapThrashingLevel"> + <int value="0" label="No swap thrashing"/> + <int value="1" label="Suspiscion of swap thrashing"/> + <int value="2" label="Confirmed swap thrashing"/> +</enum> + +<enum name="SwapThrashingLevelChanges"> + <int value="0" label="None to Suspected"/> + <int value="1" label="Suspected to Confirmed"/> + <int value="2" label="Confirmed to Suspected"/> + <int value="3" label="Suspected to None"/> +</enum> + <enum name="SwReporterRunningTimeRegistryError"> <int value="0" label="No error"/> <int value="1" label="Registry key invalid"/> @@ -37386,21 +41825,21 @@ </enum> <enum name="SwReporterStep"> - <int value="0" label="Explicit request"/> - <int value="1" label="Startup retry"/> - <int value="2" label="Retried too many times"/> + <int value="0" label="Explicit request (deprecated)"/> + <int value="1" label="Startup retry (deprecated)"/> + <int value="2" label="Retried too many times (deprecated)"/> <int value="3" label="Start execution"/> <int value="4" label="Failed to start"/> - <int value="5" label="Registry exit code"/> - <int value="6" label="Reset retries"/> - <int value="7" label="Begin SRT download"/> + <int value="5" label="Registry exit code (deprecated)"/> + <int value="6" label="Reset retries (deprecated)"/> + <int value="7" label="Begin SRT download (deprecated)"/> <int value="8" label="No browser to show prompt"/> - <int value="9" label="No local state"/> + <int value="9" label="No local state (deprecated)"/> <int value="10" label="No prompt needed"/> <int value="11" label="No prompt field trial"/> <int value="12" label="Already prompted"/> - <int value="13" label="Daily run"/> - <int value="14" label="Added to menu"/> + <int value="13" label="Daily run (deprecated)"/> + <int value="14" label="Added to menu (deprecated)"/> </enum> <enum name="SyncAttachmentStoreResult"> @@ -37657,6 +42096,7 @@ <int value="0" label="Saved on Chrome sign-in"/> <int value="1" label="Saved in the content area"/> <int value="2" label="Cleared on Chrome sign-out"/> + <int value="3" label="Changed in the content area"/> </enum> <enum name="SyncPromoAction"> @@ -37664,6 +42104,15 @@ <int value="1" label="The user clicked the promo to sign in"/> </enum> +<enum name="SyncRequestType"> + <summary>Maps to values in sync_pb::ClientToServerMessage_Contents.</summary> + <int value="1" label="COMMIT"/> + <int value="2" label="GET_UPDATES"/> + <int value="3" label="AUTHENTICATE"/> + <int value="4" label="DEPRECATED_4"/> + <int value="5" label="CLEAR_SERVER_DATA"/> +</enum> + <enum name="SyncSimpleConflictResolutions"> <summary> Sync simple conflict resolutions. The codes are listed in @@ -37781,6 +42230,13 @@ label="Discarded a tab playing audio (included in the previous one)"/> </enum> +<enum name="TabForegroundState"> + <int value="0" label="Foreground (app in foreground)"/> + <int value="1" label="Background (app in foreground)"/> + <int value="2" label="Foreground (app in background)"/> + <int value="3" label="Background (app in background)"/> +</enum> + <enum name="TabLoadingState"> <int value="0" label="Tab is not loading"/> <int value="1" label="Tab is loading"/> @@ -37853,6 +42309,14 @@ <int value="1" label="Revisit"/> </enum> +<enum name="TabUnderAction"> + <int value="0" label="Navigation started"/> + <int value="1" label="Tab-under blocked"/> + <int value="2" label="Tab-under occurred"/> + <int value="3" label="Clicked through native UI"/> + <int value="4" label="Closed native UI without navigation"/> +</enum> + <enum name="TapDelayType"> <int value="0" label="Delayed Tap"/> <int value="1" label="Undelayed Tap"/> @@ -37892,6 +42356,14 @@ <int value="5" label="Flushing"/> </enum> +<enum name="TemporaryReferenceRemovedReason"> + <int value="0" label="Embedded"/> + <int value="1" label="Dropped"/> + <int value="2" label="Skipped"/> + <int value="3" label="Invalidated"/> + <int value="4" label="Expired"/> +</enum> + <enum name="TerminationStatus"> <summary> Return status values from GetTerminationStatus as defined in @@ -37982,6 +42454,20 @@ <int value="3" label="Infobar dismissed"/> </enum> +<enum name="ThumbnailCaptureOutcome"> + <int value="0" label="Success"/> + <int value="1" label="Not attempted: Navigation is pending"/> + <int value="2" label="Not attempted: Page hasn't painted yet"/> + <int value="3" label="Not attempted: Thumbnailing already in progress"/> + <int value="4" label="Not attempted: WebContents is being destroyed"/> + <int value="5" label="Not attempted: No valid URL"/> + <int value="6" label="Not attempted: Should not acquire for this page"/> + <int value="7" label="Not attempted: View not available for copy"/> + <int value="8" label="Not attempted: Empty copy rect"/> + <int value="9" label="Canceled"/> + <int value="10" label="Readback failed"/> +</enum> + <enum name="ThumbnailTopSitesEvent"> <int value="0" label="Not added: Failure"/> <int value="1" label="Not added: TopSites is full"/> @@ -37996,6 +42482,15 @@ <int value="1" label="Exceeded memory budget"/> </enum> +<enum name="TimeToInteractiveStatus"> + <int value="0" label="Recorded successfully"/> + <int value="1" label="Not recorded because the page was backgrounded"/> + <int value="2" label="Not recorded because of user interaction"/> + <int value="3" label="Not recorded because never reached quiescence"/> + <int value="4" + label="Not recorded because never reached first meaningful paint"/> +</enum> + <enum name="TimeZoneRequestEvent"> <int value="0" label="Request start"/> <int value="1" label="Response success"/> @@ -38275,6 +42770,23 @@ label="Bubbling Root-scroller, scrollable document, handled application"/> </enum> +<enum name="TPMFirmwareUpdateResult"> + <int value="0" label="Success"/> + <int value="1" label="Success after retry"/> + <int value="2" label="Failure but still booting"/> +</enum> + +<enum name="TPMFirmwareUpdateStatus"> + <int value="0" label="EXIT_CODE_SUCCESS"/> + <int value="1" label="EXIT_CODE_ERROR"/> + <int value="3" label="EXIT_CODE_NO_UPDATE"/> + <int value="4" label="EXIT_CODE_UPDATE_FAILED"/> + <int value="5" label="EXIT_CODE_LOW_BATTERY"/> + <int value="6" label="EXIT_CODE_NOT_UPDATABLE"/> + <int value="7" label="EXIT_CODE_MISSING_APPROVAL"/> + <int value="8" label="EXIT_CODE_SUCCESS_COLD_REBOOT"/> +</enum> + <enum name="TPMResultCodeEnum"> <int value="0" label="TPM_SUCCESS"/> <int value="1" label="TPM_E_AUTHFAIL"/> @@ -38382,20 +42894,216 @@ </enum> <enum name="TPMVersionFingerprint"> - <int value="305524852" label="IFX 4.32 build 0x36f variant 1"/> - <int value="368058567" label="STM 0xd08"/> - <int value="517482723" label="IFX 4.32 build 0x36f variant 2"/> - <int value="639195905" label="IFX 4.32 build 0x36f variant 3"/> +<!-- +Full version information for the fingerprint enum values: + + TPM family: 312e3200 + spec level: 0000000200000003 + manufacturer: 49465800 + tpm_model: ffffffff + firmware version: 0000000000000422 + vendor specific: 042203F20274706D3431FFFFFF + version fingerprint: 157181839 095e678f + + TPM family: 312e3200 + spec level: 0000000200000003 + manufacturer: 49465800 + tpm_model: ffffffff + firmware version: 0000000000000420 + vendor specific: 0420036F0074706D3431FFFFFF + version fingerprint: 305524852 1235f074 + + TPM family: 312e3200 + spec level: 0000000200000003 + manufacturer: 53544d20 + tpm_model: ffffffff + firmware version: 0000000000000d08 + vendor specific: 48 + version fingerprint: 368058567 15f020c7 + + TPM family: 312e3200 + spec level: 0000000200000003 + manufacturer: 49465800 + tpm_model: ffffffff + firmware version: 0000000000000422 + vendor specific: 042203F20274706D3338FFFFFF + version fingerprint: 487001745 1d070e91 + + TPM family: 312e3200 + spec level: 0000000200000003 + manufacturer: 49465800 + tpm_model: ffffffff + firmware version: 0000000000000420 + vendor specific: 0420036F0074706D3338FFFFFF + version fingerprint: 517482723 1ed828e3 + + TPM family: 312e3200 + spec level: 0000000200000003 + manufacturer: 49465800 + tpm_model: ffffffff + firmware version: 000000000000062b + vendor specific: 062B00F30074706D733135FFFF + version fingerprint: 545386023 2081ee27 + + TPM family: 312e3200 + spec level: 0000000200000003 + manufacturer: 49465800 + tpm_model: ffffffff + firmware version: 0000000000000420 + vendor specific: 0420036F0074706D3335FFFFFF + version fingerprint: 639195905 26195b01 + + TPM family: 312e3200 + spec level: 0000000200000003 + manufacturer: 49465800 + tpm_model: ffffffff + firmware version: 0000000000008521 + vendor specific: 852100E30274706D3738FFFFFF + version fingerprint: 847042924 327cd96c + + TPM family: 322e3000 + spec level: 0000000000000074 + manufacturer: 43524f53 + tpm_model: 00000001 + firmware version: 0dc5c85b01a68fe6 + vendor specific: 784347206654504D + version fingerprint: 987235505 3ad804b1 + + TPM family: 312e3200 + spec level: 0000000200000003 + manufacturer: 49465800 + tpm_model: ffffffff + firmware version: 0000000000000628 + vendor specific: 062800BE0074706D733135FFFF + version fingerprint: 987973414 3ae34726 + + TPM family: 312e3200 + spec level: 0000000200000003 + manufacturer: 57454300 + tpm_model: ffffffff + firmware version: 0000000000000345 + vendor specific: + version fingerprint: 1311411160 4e2a8bd8 + + TPM family: 312e3200 + spec level: 0000000200000002 + manufacturer: 49465800 + tpm_model: ffffffff + firmware version: 0000000000000312 + vendor specific: 0312000900 + version fingerprint: 1353576267 50adef4b + + TPM family: 312e3200 + spec level: 0000000200000003 + manufacturer: 49465800 + tpm_model: ffffffff + firmware version: 0000000000008520 + vendor specific: 852000500074706D3738FFFFFF + version fingerprint: 1437720528 55b1dfd0 + + TPM family: 312e3200 + spec level: 0000000200000002 + manufacturer: 49465800 + tpm_model: ffffffff + firmware version: 0000000000009312 + vendor specific: 9312000F00 + version fingerprint: 1451134301 567e8d5d + + TPM family: 312e3200 + spec level: 0000000200000003 + manufacturer: 49465800 + tpm_model: ffffffff + firmware version: 0000000000008520 + vendor specific: 852000500074706D3439FFFFFF + version fingerprint: 1490841853 58dc70fd + + TPM family: 312e3200 + spec level: 0000000200000003 + manufacturer: 49465800 + tpm_model: ffffffff + firmware version: 0000000000008520 + vendor specific: 852000500074706D3435FFFFFF + version fingerprint: 1716634300 6651c2bc + + TPM family: 312e3200 + spec level: 0000000200000003 + manufacturer: 49465800 + tpm_model: ffffffff + firmware version: 0000000000008521 + vendor specific: 852100E30274706D3439FFFFFF + version fingerprint: 1733077393 674ca991 + + TPM family: 312e3200 + spec level: 0000000200000003 + manufacturer: 49465800 + tpm_model: ffffffff + firmware version: 000000000000041f + vendor specific: 041F02C20074706D3332FFFFFF + version fingerprint: 1828625721 6cfe9d39 + + TPM family: 322e3000 + spec level: 0000000000000074 + manufacturer: 43524f53 + tpm_model: 00000001 + firmware version: 0fd788bd01a68fe6 + vendor specific: 784347206654504D + version fingerprint: 1887455524 70804924 + + TPM family: 312e3200 + spec level: 0000000200000003 + manufacturer: 49465800 + tpm_model: ffffffff + firmware version: 0000000000000422 + vendor specific: 042203F20274706D3335FFFFFF + version fingerprint: 1941011596 73b17c8c + + TPM family: 312e3200 + spec level: 0000000200000003 + manufacturer: 49465800 + tpm_model: ffffffff + firmware version: 0000000000008521 + vendor specific: 852100E30274706D3435FFFFFF + version fingerprint: 1953654937 74726899 + + TPM family: 312e3200 + spec level: 0000000200000003 + manufacturer: 49465800 + tpm_model: ffffffff + firmware version: 0000000000008521 + vendor specific: 852100E30074706D3738FFFFFF + version fingerprint: 1973986381 75a8a44d + + TPM family: 312e3200 + spec level: 0000000200000003 + manufacturer: 49465800 + tpm_model: ffffffff + firmware version: 0000000000000422 + vendor specific: 042203F20274706D3332FFFFFF + version fingerprint: 2024714959 78aeb2cf +--> + + <int value="157181839" label="IFX 9655 rev 41 fw 4.34 build 03f2"/> + <int value="305524852" label="IFX 9655 rev 41 fw 4.32 build 036f"/> + <int value="368058567" label="STM d08"/> + <int value="487001745" label="IFX 9655 rev 38 fw 4.34 build 03f2"/> + <int value="517482723" label="IFX 9655 rev 38 fw 4.32 build 036f"/> + <int value="545386023" label="IFX 9670 rev 15 fw 6.43 build 00f3"/> + <int value="639195905" label="IFX 9655 rev 35 fw 4.32 build 036f"/> + <int value="847042924" label="IFX 9645 rev 78 fw 133.33 build 00e3"/> <int value="987235505" label="CROS 0dc5c85b01a68fe6"/> - <int value="987973414" label="IFX 6.40 build 0xbe"/> - <int value="1311411160" label="WEC 0x345"/> - <int value="1353576267" label="IFX 3.18 build 0x9"/> - <int value="1437720528" label="IFX 133.32 build 0x5 variant 1"/> - <int value="1451134301" label="IFX 147.18 build 0xf"/> - <int value="1490841853" label="IFX 133.32 build 0x5 variant 2"/> - <int value="1716634300" label="IFX 133.32 build 0x5 variant 3"/> - <int value="1828625721" label="IFX 4.31 build 0x2c2"/> + <int value="987973414" label="IFX 9670 rev 15 fw 6.40 build 00be"/> + <int value="1311411160" label="WEC 345"/> + <int value="1353576267" label="IFX 9635 fw 3.18 build 0009"/> + <int value="1437720528" label="IFX 9645 rev 78 fw 133.32 build 0050"/> + <int value="1451134301" label="IFX 9635 147.18 build 000f"/> + <int value="1490841853" label="IFX 9645 rev 49 fw 133.32 build 0050"/> + <int value="1716634300" label="IFX 9645 rev 45 fw 133.32 build 0050"/> + <int value="1733077393" label="IFX 9645 rev 49 fw 133.33 build 00e3"/> + <int value="1828625721" label="IFX 9655 rev 32 fw 4.31 build 02c2"/> <int value="1887455524" label="CROS 0fd788bd01a68fe6"/> + <int value="1941011596" label="IFX 9655 rev 35 fw 4.34 build 03f2"/> + <int value="1953654937" label="IFX 9645 rev 45 fw 133.33 build 00e3"/> + <int value="2024714959" label="IFX 9655 rev 32 fw 4.34 build 03f2"/> </enum> <enum name="TrackedPreference"> @@ -38428,6 +43136,7 @@ <int value="26" label="kSettingsResetPromptLastTriggeredForDefaultSearch"/> <int value="27" label="kSettingsResetPromptLastTriggeredForStartupUrls"/> <int value="28" label="kSettingsResetPromptLastTriggeredForHomepage"/> + <int value="29" label="kMediaStorageIdSalt"/> </enum> <enum name="TranslateBubbleUiEvent"> @@ -38572,6 +43281,8 @@ <int value="9" label="FAILURE_SESSION_RATE"/> <int value="10" label="FAILURE_AVAILABILITY_MODEL_NOT_READY"/> <int value="11" label="FAILURE_AVAILABILITY_PRECONDITION_UNMET"/> + <int value="12" label="SUCCESS_TRACKING_ONLY"/> + <int value="13" label="FAILURE_DISPLAY_LOCK"/> </enum> <enum name="TrimMemoryLevel"> @@ -38631,6 +43342,7 @@ <int value="1" label="Recording disabled"/> <int value="2" label="Max hit"/> <int value="3" label="Not whitelisted"/> + <int value="4" label="Unsupported URL scheme"/> </enum> <enum name="UmaCleanExitConsistency"> @@ -38862,6 +43574,8 @@ <int value="48" label="kErrorCodeUserCanceled"/> <int value="49" label="kErrorCodeNonCriticalUpdateInOOBE"/> <int value="50" label="kErrorCodeOmahaUpdateIgnoredOverCellular"/> + <int value="51" label="kErrorCodePayloadTimestampError"/> + <int value="52" label="kErrorCodeUpdatedButNotActive"/> </enum> <enum name="UpdateEngineInstallDateProvisioningSource"> @@ -38911,6 +43625,7 @@ Called by update_traffic_annotation_histograms.py.--> <int value="485305" label="data_reduction_proxy_config"/> + <int value="516551" label="socket_bio_adapter"/> <int value="727478" label="metrics_report_ukm"/> <int value="727528" label="metrics_report_uma"/> <int value="1112842" label="oauth2_mint_token_flow"/> @@ -38920,21 +43635,25 @@ <int value="3989826" label="dom_distiller"/> <int value="4300475" label="gaia_cookie_manager_external_cc_result"/> <int value="4598626" label="gaia_auth_check_connection_info"/> + <int value="4986170" label="ui_devtools_server"/> <int value="5021348" label="sync_stop_reporter"/> <int value="5151071" label="extension_manifest_fetcher"/> <int value="5154306" label="blob_reader"/> <int value="5492492" label="google_url_tracker"/> + <int value="5576536" label="cast_udp_transport"/> <int value="5637379" label="gaia_oauth_client_get_tokens"/> <int value="6019475" label="safe_browsing_module_loader"/> <int value="7433837" label="refresh_token_annotation_request"/> <int value="7687691" label="omnibox_zerosuggest"/> <int value="8250451" label="data_reduction_proxy_warmup"/> <int value="8561691" label="safe_browsing_v4_get_hash"/> + <int value="8591273" label="chrome_apps_socket_api"/> <int value="9459438" label="external_policy_fetcher"/> <int value="13211343" label="suggestions_image_manager"/> <int value="13694792" label="desktop_ios_promotion"/> <int value="14257952" label="supervised_user_url_filter"/> <int value="15418154" label="ntp_snippets_fetch"/> + <int value="15952025" label="dial_get_app_info"/> <int value="16469669" label="background_fetch_context"/> <int value="16653985" label="content_suggestion_get_favicon"/> <int value="17188928" label="websocket_stream"/> @@ -38949,6 +43668,7 @@ <int value="22096011" label="test_partial"/> <int value="22265491" label="user_info_fetcher"/> <int value="22774132" label="devtools_free_data_source"/> + <int value="23472048" label="network_location_provider"/> <int value="24058523" label="CRD_relay_session_request"/> <int value="24978481" label="cloud_print_privet_register"/> <int value="25204343" label="cryptauth_toggle_easyunlock"/> @@ -38959,16 +43679,22 @@ <int value="26216847" label="gaia_auth_merge_sessions"/> <int value="26302604" label="webstore_data_fetcher"/> <int value="26372521" label="sync_attachment_downloader"/> + <int value="27071967" label="chrome_cleaner"/> <int value="27915688" label="oauth2_access_token_fetcher"/> + <int value="28406789" label="undefined-656607"/> + <int value="29188932" label="oauth2_api_call_flow"/> <int value="29865866" label="headless_url_request"/> <int value="30913825" label="family_info"/> <int value="32030464" label="persist_blob_to_indexed_db"/> + <int value="32197336" label="http_server_error_response"/> <int value="32585152" label="gaia_oauth_client_get_token_info"/> <int value="35370363" label="suggestions_service"/> <int value="35380758" label="download_manager_resume"/> <int value="35565745" label="gaia_auth_list_accounts"/> <int value="36859107" label="logo_tracker"/> + <int value="37249086" label="android_device_manager_socket"/> <int value="37531401" label="proxy_script_fetcher"/> + <int value="39356976" label="android_web_socket"/> <int value="39877119" label="gaia_auth_exchange_device_id"/> <int value="40534770" label="obsolete_favicon_component"/> <int value="41154842" label="doodle_service"/> @@ -38982,6 +43708,7 @@ <int value="46188932" label="network_time_component"/> <int value="47152935" label="sdch_dictionary_fetch"/> <int value="47815025" label="omnibox_suggest"/> + <int value="49160454" label="devtools_http_handler"/> <int value="49544361" label="remote_suggestions_provider"/> <int value="49601082" label="plugins_resource_service"/> <int value="49825319" label="CRD_ice_config_request"/> @@ -38991,6 +43718,8 @@ <int value="50816767" label="lib_address_input"/> <int value="50859288" label="cloud_print_proxy"/> <int value="51164680" label="profile_avatar"/> + <int value="51586722" label="websocket_basic_stream"/> + <int value="52821843" label="geo_language_provider"/> <int value="53695122" label="credenential_avatar"/> <int value="54836939" label="cryptauth_enrollment_flow_finish"/> <int value="56275203" label="save_file_manager"/> @@ -39001,6 +43730,7 @@ <int value="57276415" label="chrome_expect_ct_reporter"/> <int value="58963098" label="resource_dispather_host"/> <int value="59592717" label="extension_blacklist"/> + <int value="60071001" label="net_error_helper"/> <int value="60921996" label="ocsp_start_url_request"/> <int value="60946824" label="web_history_expire"/> <int value="61656965" label="gcm_registration"/> @@ -39030,6 +43760,8 @@ <int value="77673751" label="device_geolocation_request"/> <int value="78544924" label="supervised_users_blacklist"/> <int value="78917933" label="one_google_bar_service"/> + <int value="79227717" label="dns_transaction"/> + <int value="79442849" label="sigined_exchange_cert_fetcher"/> <int value="79957943" label="safe_browsing_chunk_backup_request"/> <int value="80832574" label="history_notice_utils_popup"/> <int value="81157007" label="resource_dispatcher_host"/> @@ -39037,22 +43769,29 @@ <int value="82462683" label="gaia_oauth_client_refresh_token"/> <int value="83476155" label="gaia_oauth_client_get_user_info"/> <int value="84045030" label="payment_manifest_downloader"/> + <int value="84165821" label="blink_extension_resource_loader"/> <int value="84212388" label="omnibox_suggest_deletion"/> <int value="84575287" label="background_performance_tracer"/> <int value="84889397" label="cryptauth_enrollment_flow_setup"/> + <int value="87558948" label="cast_message_handler"/> + <int value="87775794" label="adb_client_socket"/> <int value="88754904" label="captive_portal_service"/> <int value="88863520" label="autofill_query"/> <int value="89771989" label="asset_links"/> <int value="91597383" label="gaia_auth_login"/> <int value="93232258" label="mojo_context_state"/> + <int value="94099818" label="bluetooth_socket"/> + <int value="95075845" label="port_forwarding_controller_socket"/> <int value="95588446" label="payments_sync_cards"/> <int value="95682324" label="ranker_url_fetcher"/> <int value="95711309" label="ntp_contextual_suggestions_fetch"/> <int value="95910019" label="drag_download_file"/> <int value="96565489" label="cryptauth_device_sync_tickle"/> + <int value="96590038" label="network_location_request"/> <int value="97199008" label="doodle_fetcher"/> <int value="97978464" label="gaia_auth_fetch_for_uber"/> <int value="98123737" label="devtools_interceptor"/> + <int value="98658519" label="accounts_image_fetcher"/> <int value="99279418" label="rlz_ping"/> <int value="100545943" label="webui_content_scripts_download"/> <int value="101725581" label="cros_recovery_image_download"/> @@ -39061,8 +43800,10 @@ <int value="102819690" label="sync_file_system"/> <int value="102935425" label="safe_browsing_client_side_malware_detector"/> <int value="103133150" label="icon_cacher"/> + <int value="103172229" label="cast_channel_send"/> <int value="104798869" label="autofill_upload"/> <int value="105330607" label="profile_resetter_upload"/> + <int value="106124561" label="ssl_hmac_channel_authenticator"/> <int value="106980485" label="safe_browsing_backup_request"/> <int value="107267424" label="open_search"/> <int value="108804096" label="domain_reliability_report_upload"/> @@ -39075,11 +43816,14 @@ <int value="111565057" label="devtools_hard_coded_data_source"/> <int value="111712433" label="cloud_print"/> <int value="111904019" label="affiliation_lookup"/> + <int value="112189210" label="favicon_loader"/> <int value="112303907" label="blob_read"/> + <int value="113065062" label="tethering_handler_socket"/> <int value="113231892" label="url_fetcher_downloader"/> <int value="113553577" label="certificate_verifier"/> <int value="114468207" label="ssl_name_mismatch_lookup"/> <int value="115188287" label="chrome_variations_service"/> + <int value="115192205" label="cast_socket"/> <int value="115907811" label="safe_browsing_cache_collector"/> <int value="116426676" label="gaia_auth_log_out"/> <int value="116443055" label="renderer_initiated_download"/> @@ -39090,12 +43834,14 @@ <int value="119542033" label="gcm_unregistration"/> <int value="119677115" label="safe_search_url_reporter"/> <int value="120000562" label="cryptauth_find_eligible_unlock_devices"/> + <int value="120623198" label="pepper_tcp_socket"/> <int value="121068967" label="downloads_api_run_async"/> <int value="124950347" label="safe_browsing_incident"/> <int value="125522256" label="client_download_request"/> <int value="125596241" label="component_updater_utils"/> <int value="126122632" label="web_history_expire_between_dates"/> <int value="129652775" label="devtools_network_resource"/> + <int value="129872904" label="service_worker_navigation_preload"/> <int value="131180348" label="indexed_db_internals_handler"/> <int value="131236802" label="data_reduction_proxy_secure_proxy_check"/> <int value="131741641" label="permission_reporting"/> @@ -39106,6 +43852,7 @@ <int value="133982351" label="gaia_auth_revoke_token"/> <int value="134289752" label="gaia_auth_exchange_cookies"/> <int value="134729048" label="chrome_feedback_report_app"/> + <int value="134755844" label="cast_keep_alive_delegate"/> <int value="135118587" label="parallel_download_job"/> <int value="135251783" label="thumbnail_source"/> <int value="135636011" label="devtools_handle_front_end_messages"/> @@ -39168,6 +43915,14 @@ <int value="0" label="WiFi Scan"/> </enum> +<enum name="UsernameDetectionMethod"> + <int value="0" label="No username detected"/> + <int value="1" label="Base heuristic"/> + <int value="2" label="HTML based classifier"/> + <int value="3" label="'autocomplete' attribute"/> + <int value="4" label="Server-side prediction"/> +</enum> + <enum name="UserPodsDisplay"> <int value="0" label="Enabled by local settings"/> <int value="1" label="Enabled by domain policy"/> @@ -39198,6 +43953,79 @@ <int value="4" label="Locally Managed"/> <int value="5" label="Kiosk App"/> <int value="6" label="Regular Supervised"/> + <int value="7" label="ARC Kiosk"/> + <int value="8" label="Active Directory"/> +</enum> + +<enum name="V8CacheBehaviour"> + <int value="0" label="kProduceCodeCache"> + The compilation produced a code cache + </int> + <int value="1" label="kHitIsolateCacheWhenNoCache"> + The compilation hit V8's isolate's compilation cache when Blink did not + request a code cache + </int> + <int value="2" label="kConsumeCodeCache"> + The compilation consumed a code cache + </int> + <int value="3" label="kConsumeCodeCacheFailed"> + The compilation tried to consume a code cache, but failed (see + V8.CodeCacheRejectReason) + </int> + <int value="4" label="kNoCacheBecauseInlineScript"> + Blink did not request a code cache because this is an inline script + </int> + <int value="5" label="kNoCacheBecauseScriptTooSmall"> + Blink did not request a code cache because this script is too small + </int> + <int value="6" label="kNoCacheBecauseCacheTooCold"> + Blink did not request a code cache because the cached resource is too cold + </int> + <int value="7" label="kNoCacheNoReason"> + Blink did not request a code cache but gave no reason + </int> + <int value="8" label="kNoCacheBecauseNoResource"> + Blink did not request a code cache because there is no resource + </int> + <int value="9" label="kNoCacheBecauseInspector"> + Blink did not request a code cache because the script came from the + inspector + </int> + <int value="10" label="kNoCacheBecauseCachingDisabled"> + Blink did not request a code cache because caching is disabled + </int> + <int value="11" label="kNoCacheBecauseModule"> + Blink did not request a code cache because the script is a module + </int> + <int value="12" label="kNoCacheBecauseStreamingSource"> + Blink did not request a code cache because this is a streaming source + </int> + <int value="13" label="kNoCacheBecauseV8Extension"> + Blink did not request a code cache because it is compiling a V8 extension + </int> + <int value="14" label="kHitIsolateCacheWhenProduceCodeCache"> + The compilation hit V8's isolate's compilation cache and produced a code + cache + </int> + <int value="15" label="kHitIsolateCacheWhenConsumeCodeCache"> + The compilation hit V8's isolate's compilation cache instead of consuming a + code cache + </int> + <int value="16" label="kNoCacheBecauseModuleExtension"> + Blink did not request a code cache because it is compiling a module for an + extension + </int> + <int value="17" label="kNoCacheBecausePacScript"> + Blink did not request a code cache because it is compiling a PAC script + </int> + <int value="18" label="kNoCacheBecauseInDocumentWrite"> + Blink did not request a code cache because it is compiling a script created + by document.write + </int> + <int value="19" label="kNoCacheBecauseResourceWithNoCacheHandler"> + Blink did not request a code cache because it has a script resource without + a cache handler + </int> </enum> <enum name="V8CodeCacheRejectReason"> @@ -39258,6 +44086,11 @@ <int value="0" label="VAAPI_ERROR"/> </enum> +<enum name="VAJEAEncoderResult"> + <int value="0" label="VAAPI_SUCCESS"/> + <int value="1" label="VAAPI_ERROR"/> +</enum> + <enum name="ValidateMenuItemSelectorType"> <int value="0" label="The menu items' associated action is an unknown selector."/> @@ -39485,6 +44318,7 @@ <int value="7" label="kCodecVP9"/> <int value="8" label="kCodecHEVC"/> <int value="9" label="kCodecDolbyVision"/> + <int value="10" label="kCodecAV1"/> </enum> <enum name="VideoCodecProfile"> @@ -39512,6 +44346,7 @@ <int value="21" label="DolbyVision profile5"/> <int value="22" label="DolbyVision profile7"/> <int value="23" label="Theora"/> + <int value="24" label="AV1 Profile0"/> </enum> <enum name="VideoDecodeAcceleratorError"> @@ -39611,12 +44446,13 @@ <enum name="VideoPersistenceEndReason"> <int value="0" label="Resume"/> - <int value="1" label="Navigation"/> + <int value="1" label="(Obsolete) Navigation"/> <int value="2" label="Close"/> <int value="3" label="Crash"/> <int value="4" label="New tab"/> <int value="5" label="Reparent"/> <int value="6" label="Left fullscreen"/> + <int value="7" label="Left fullscreen (webcontents)"/> </enum> <enum name="VideoPixelFormat"> @@ -39641,7 +44477,7 @@ <int value="0" label="UNKNOWN"/> <int value="1" label="I420"/> <int value="2" label="YV12"/> - <int value="3" label="YV16"/> + <int value="3" label="I422"/> <int value="4" label="YV12A"/> <int value="5" label="YV24"/> <int value="6" label="NV12"/> @@ -39663,7 +44499,7 @@ <int value="22" label="YUV420P12"/> <int value="23" label="YUV422P12"/> <int value="24" label="YUV444P12"/> - <int value="25" label="Y8"/> + <int value="25" label="Y8 (Deprecated in M65)"/> <int value="26" label="Y16"/> </enum> @@ -39748,6 +44584,9 @@ <int value="57" label=".torrent"/> <int value="58" label=".txt"/> <int value="59" label=".zip"/> + <int value="60" label="directory"/> + <int value="61" label="no extension"/> + <int value="62" label="unknown extension"/> </enum> <enum name="VirtualKeyboardControllerState"> @@ -39899,7 +44738,9 @@ <enum name="VPNDriver"> <int value="0" label="OpenVPN"/> <int value="1" label="L2TP/IPSec"/> - <int value="2" label="Third Party"/> + <int value="2" label="Third Party (CrOS)"/> + <int value="3" label="Third Party (Android)"/> + <int value="4" label="PPTP"/> </enum> <enum name="VPNRemoteAuthenticationType"> @@ -39920,6 +44761,52 @@ <int value="6" label="L2TP/IPSec Username/Password"/> </enum> +<enum name="VRAssetsComponentUpdateStatus"> + <int value="1" + label="Failed to verify component (component version not known)."/> + <int value="2" + label="Component not compatible with Chrome (component version not + known)."/> + <int value="1000" + label="Successfully updated component (component version 0.1)."/> + <int value="1001" + label="Failed to verify component (component version 0.1)."/> + <int value="1002" + label="Component not compatible with Chrome (component version 0.1)."/> +</enum> + +<enum name="VRAssetsLoadStatus"> + <int value="1000" + label="Successfully loaded assets (component version 0.1)."/> + <int value="1001" + label="Failed to load assets from disk (component version 0.1)."/> + <int value="1002" + label="Assets have an invalid content (component version 0.1)."/> + <int value="1000003" + label="Assets file(s) not found (component version 1.0)."/> +</enum> + +<enum name="VRComponentStatus"> + <int value="0" label="Component is ready to use"/> + <int value="1" label="Component is not ready to use. Reason unknown."/> +</enum> + +<enum name="VRPresentationResult"> + <int value="0" label="Requested"/> + <int value="1" label="Success"/> + <int value="2" label="SuccessAlreadyPresenting"/> + <int value="3" label="VRDisplayCannotPresent"/> + <int value="4" label="PresentationNotSupportedByDisplay"/> + <int value="5" label="VRDisplayNotFound"/> + <int value="6" label="NotInitiatedByUserGesture"/> + <int value="7" label="InvalidNumberOfLayers"/> + <int value="8" label="InvalidLayerSource"/> + <int value="9" label="LayerSourceMissingWebGLContext"/> + <int value="10" label="InvalidLayerBounds"/> + <int value="11" label="ServiceInactive"/> + <int value="12" label="RequestDenied"/> +</enum> + <enum name="VRSuppressedElement"> <int value="0" label="File chooser was suppressed in VR"/> <int value="1" label="Bluetooth picker was suppressed in VR"/> @@ -39938,15 +44825,27 @@ <enum name="VRUnsupportedMode"> <int value="0" label="Unhandled code point in URL"/> - <int value="1" label="Could not elide URL"/> + <int value="1" label="Could not elide URL (obsolete)"/> <int value="2" label="Unhandled PageInfo"/> - <int value="3" label="URL contained strong RTL chars"/> + <int value="3" label="URL contained strong RTL chars (obsolete)"/> + <int value="4" label="Chrome needs audio permission for voice input"/> </enum> <enum name="VRViewerType"> - <int value="0" label="UNKNOWN_TYPE"/> - <int value="1" label="CARDBOARD"/> - <int value="2" label="DAYDREAM"/> + <int value="0" label="GVR_UNKNOWN"/> + <int value="1" label="GVR_CARDBOARD"/> + <int value="2" label="GVR_DAYDREAM"/> + <int value="10" label="ORIENTATION_SENSOR_DEVICE"/> + <int value="11" label="FAKE_DEVICE"/> + <int value="20" label="OPENVR_UNKNOWN"/> + <int value="21" label="OPENVR_VIVE"/> + <int value="22" label="OPENVR_RIFT_CV1"/> +</enum> + +<enum name="VRVoiceSearchEndState"> + <int value="0" label="Voice search in VR opened a search page"/> + <int value="1" label="Voice search in VR cancelled"/> + <int value="2" label="Voice search in VR didn't catch phrase or timed out"/> </enum> <enum name="VTVDAInitializationFailureType"> @@ -40124,6 +45023,30 @@ <int value="4" label="Failed"/> </enum> +<enum name="WebApkInstallGooglePlayErrorCode"> + <int value="192" label="STATUS_RUNNING"/> + <int value="194" label="STATUS_WAITING_TO_RETRY"/> + <int value="198" label="STATUS_INSUFFICIENT_SPACE_ERROR"/> + <int value="400" label="STATUS_BAD_REQUEST"/> + <int value="406" label="STATUS_NOT_ACCEPTABLE"/> + <int value="489" label="STATUS_CANNOT_RESUME"/> + <int value="490" label="STATUS_CANCELED"/> + <int value="491" label="STATUS_UNKNOWN_ERROR"/> + <int value="492" label="STATUS_FILE_ERROR"/> + <int value="495" label="STATUS_HTTP_DATA_ERROR"/> + <int value="907" label="ERROR_DOWNLOAD_INTERNAL_CONDITION_5"/> + <int value="908" label="ERROR_DOWNLOAD_INTERNAL_FREE_SPACE"/> + <int value="910" label="ERROR_INSTALL_INCOMPLETE"/> + <int value="919" label="ERROR_INSTALL_APK_VERIFICATION_SIZE"/> + <int value="920" label="ERROR_VOLLEY_AUTH_FAILURE"/> + <int value="922" label="ERROR_VOLLEY_DFE_SERVER"/> + <int value="923" label="ERROR_VOLLEY_NETWORK"/> + <int value="924" label="ERROR_VOLLEY_NO_CONNECTION"/> + <int value="927" label="ERROR_VOLLEY_TIMEOUT"/> + <int value="961" label="ERROR_INSTALL_APK_VERIFICATION_OTHER"/> + <int value="963" label="ERROR_INSTALL_APK_COPY_FAILURE"/> +</enum> + <enum name="WebApkInstallInfoBarShown"> <obsolete> Deprecated as of 8/2017 @@ -40143,6 +45066,14 @@ <int value="2" label="Activity for WebAPK not found."/> </enum> +<enum name="WebApkPermissionType"> + <int value="0" label="Other"/> + <int value="1" label="LOCATION"/> + <int value="2" label="MICROPHONE"/> + <int value="3" label="CAMERA"/> + <int value="4" label="STORAGE"/> +</enum> + <enum name="WebApkUpdateRequestQueued"> <int value="0" label="Queued for the first time"/> <int value="1" label="Queued for the second time"/> @@ -40150,9 +45081,10 @@ </enum> <enum name="WebApkUpdateRequestSent"> - <int value="0" label="Sent immediately after an update check"/> - <int value="1" label="Sent when WebAPK is moved to background"/> - <int value="2" label="Sent by forcing an update"/> + <int value="0" label="Sent immediately after an update check (deprecated)"/> + <int value="1" label="Sent when WebAPK is moved to background (deprecated)"/> + <int value="2" label="Sent by forcing an update (deprecated)"/> + <int value="3" label="Sent when WebAPK is closed"/> </enum> <enum name="WebApkUserAction"> @@ -40165,6 +45097,38 @@ <int value="3" label="Dismiss to open a newly installed WebAPK"/> </enum> +<enum name="WebAppDisplayMode"> + <summary> + The display mode of a web app (as defined in the Web App Manifest spec). + </summary> + <int value="0" label="Undefined"/> + <int value="1" label="Browser"/> + <int value="2" label="Minimal UI"/> + <int value="3" label="Standalone"/> + <int value="4" label="Fullscreen"/> +</enum> + +<enum name="WebAppInstallSource"> + <obsolete> + Removed from code Jan 2018. + </obsolete> + <int value="0" label="Installed via the automatically-triggered prompt"/> + <int value="1" label="Installed via the menu"/> + <int value="2" label="Installed via a developer-triggered API call"/> + <int value="3" label="Installed via the management API (not reported)"/> +</enum> + +<enum name="WebappInstallSource"> + <int value="0" label="Menu via a browser tab"/> + <int value="1" label="Menu via an Android Custom Tab"/> + <int value="2" label="Automatic prompt via a browser tab"/> + <int value="3" label="Automatic prompt via an Android Custom Tab"/> + <int value="4" label="Developer API prompt via a browser tab"/> + <int value="5" label="Developer API prompt via an Android Custom Tab"/> + <int value="6" label="Via a debug source"/> + <int value="7" label="Extensions management API (not reported)"/> +</enum> + <enum name="WebAudioAutoplayStatus"> <int value="0" label="The AudioContext failed to autoplay"/> <int value="1" label="Failed to autoplay but start() called on user gesture"/> @@ -40351,6 +45315,12 @@ <int value="2" label="WEB_HISTORY_QUERY_TIMED_OUT">Timed out</int> </enum> +<enum name="WebpDecodedFormat"> + <int value="1" label="JPEG"/> + <int value="2" label="PNG"/> + <int value="3" label="TIFF"/> +</enum> + <enum name="WebRTCAecDelayEstimateReliability"> <int value="0" label="None."/> <int value="1" label="Poor."/> @@ -40467,6 +45437,7 @@ <int value="-2081867874" label="/usbDevices"/> <int value="-2019732586" label="/printing"/> <int value="-1930329480" label="/signOut"/> + <int value="-1924511305" label="/help"/> <int value="-1915654604" label="/sound"/> <int value="-1836863301" label="/ads"/> <int value="-1820397898" label="/manageAccessibility"/> @@ -40636,7 +45607,7 @@ <int value="1354146226" label="chrome://tab-modal-confirm-dialog/"/> <int value="1371905827" label="chrome://flags/"/> <int value="1396129399" label="chrome://flash/"/> - <int value="1403605293" label="chrome://proxy-settings/"/> + <int value="1403605293" label="chrome://internet-detail-dialog/"/> <int value="1427179406" label="chrome://gcm-internals/"/> <int value="1454088830" label="chrome://uber-frame/"/> <int value="1457759734" label="chrome://user-manager/"/> @@ -40697,6 +45668,40 @@ <int value="2" label="Signature whitelist"/> </enum> +<enum name="WiFiAp80211kSupport"> + <int value="0" label="Does not support 802.11k"/> + <int value="1" label="Supports 802.11k neighbor lists"/> +</enum> + +<enum name="WiFiAp80211rSupport"> + <int value="0" label="Does not support 802.11r"/> + <int value="1" label="Supports Over-the-Air FT Roaming"/> + <int value="2" label="Supports Over-the-DS FT Roaming"/> +</enum> + +<enum name="WiFiAp80211vBSSMaxIdlePeriodSupport"> + <int value="0" label="Does not support 802.11v BSS Max idle period"/> + <int value="1" label="Supports BSS Max idle period"/> +</enum> + +<enum name="WiFiAp80211vBSSTransitionSupport"> + <int value="0" label="Does not support 802.11v BSS transition"/> + <int value="1" label="Supports BSS transition"/> +</enum> + +<enum name="WiFiAp80211vDMSSupport"> + <int value="0" label="Does not support 802.11v DMS"/> + <int value="1" label="Supports DMS"/> +</enum> + +<enum name="WiFiApChannelSwitch"> + <int value="0" label="Unknown frequency range"/> + <int value="1" label="2.4GHz -> 2.4GHz"/> + <int value="2" label="2.4GHz -> 5GHz"/> + <int value="3" label="5GHz -> 2.4GHz"/> + <int value="4" label="5GHz -> 5GHz"/> +</enum> + <enum name="WiFiApMode"> <int value="0" label="Unknown"/> <int value="1" label="Managed"/> @@ -40808,33 +45813,34 @@ <int value="1" label="content::RESULT_CODE_KILLED"/> <int value="2" label="content::RESULT_CODE_HUNG"/> <int value="3" label="content::RESULT_CODE_KILLED_BAD_MESSAGE"/> - <int value="4" label="chrome::RESULT_CODE_INVALID_CMDLINE_URL"/> - <int value="5" label="chrome::RESULT_CODE_BAD_PROCESS_TYPE"/> - <int value="6" label="chrome::RESULT_CODE_MISSING_DATA"/> - <int value="7" label="chrome::RESULT_CODE_SHELL_INTEGRATION_FAILED"/> - <int value="8" label="chrome::RESULT_CODE_MACHINE_LEVEL_INSTALL_EXISTS"/> - <int value="9" label="chrome::RESULT_CODE_UNINSTALL_CHROME_ALIVE"/> - <int value="10" label="chrome::RESULT_CODE_UNINSTALL_USER_CANCEL"/> - <int value="11" label="chrome::RESULT_CODE_UNINSTALL_DELETE_PROFILE"/> - <int value="12" label="chrome::RESULT_CODE_UNSUPPORTED_PARAM"/> - <int value="13" label="chrome::RESULT_CODE_IMPORTER_HUNG"/> - <int value="14" label="chrome::RESULT_CODE_RESPAWN_FAILED"/> - <int value="15" label="chrome::RESULT_CODE_NORMAL_EXIT_EXP1"/> - <int value="16" label="chrome::RESULT_CODE_NORMAL_EXIT_EXP2"/> - <int value="17" label="chrome::RESULT_CODE_NORMAL_EXIT_EXP3"/> - <int value="18" label="chrome::RESULT_CODE_NORMAL_EXIT_EXP4"/> - <int value="19" label="chrome::RESULT_CODE_NORMAL_EXIT_CANCEL"/> - <int value="20" label="chrome::RESULT_CODE_PROFILE_IN_USE"/> - <int value="21" label="chrome::RESULT_CODE_PACK_EXTENSION_ERROR"/> - <int value="22" label="chrome::RESULT_CODE_UNINSTALL_EXTENSION_ERROR"/> - <int value="23" label="chrome::RESULT_CODE_NORMAL_EXIT_PROCESS_NOTIFIED"/> - <int value="24" label="chrome::RESULT_CODE_NOTUSED_1"/> - <int value="25" label="chrome::RESULT_CODE_INSTALL_FROM_WEBSTORE_ERROR_2"/> - <int value="26" label="chrome::RESULT_CODE_NOTUSED_2"/> - <int value="27" label="chrome::RESULT_CODE_EULA_REFUSED"/> - <int value="28" label="chrome::RESULT_CODE_SXS_MIGRATION_FAILED"/> - <int value="29" label="chrome::RESULT_CODE_ACTION_DISALLOWED_BY_POLICY"/> - <int value="30" label="chrome::RESULT_CODE_INVALID_SANDBOX_STATE"/> + <int value="4" label="content::RESULT_CODE_GPU_DEAD_ON_ARRIVAL"/> + <int value="5" label="chrome::RESULT_CODE_INVALID_CMDLINE_URL"/> + <int value="6" label="chrome::RESULT_CODE_BAD_PROCESS_TYPE"/> + <int value="7" label="chrome::RESULT_CODE_MISSING_DATA"/> + <int value="8" label="chrome::RESULT_CODE_SHELL_INTEGRATION_FAILED"/> + <int value="9" label="chrome::RESULT_CODE_MACHINE_LEVEL_INSTALL_EXISTS"/> + <int value="10" label="chrome::RESULT_CODE_UNINSTALL_CHROME_ALIVE"/> + <int value="11" label="chrome::RESULT_CODE_UNINSTALL_USER_CANCEL"/> + <int value="12" label="chrome::RESULT_CODE_UNINSTALL_DELETE_PROFILE"/> + <int value="13" label="chrome::RESULT_CODE_UNSUPPORTED_PARAM"/> + <int value="14" label="chrome::RESULT_CODE_IMPORTER_HUNG"/> + <int value="15" label="chrome::RESULT_CODE_RESPAWN_FAILED"/> + <int value="16" label="chrome::RESULT_CODE_NORMAL_EXIT_EXP1"/> + <int value="17" label="chrome::RESULT_CODE_NORMAL_EXIT_EXP2"/> + <int value="18" label="chrome::RESULT_CODE_NORMAL_EXIT_EXP3"/> + <int value="19" label="chrome::RESULT_CODE_NORMAL_EXIT_EXP4"/> + <int value="20" label="chrome::RESULT_CODE_NORMAL_EXIT_CANCEL"/> + <int value="21" label="chrome::RESULT_CODE_PROFILE_IN_USE"/> + <int value="22" label="chrome::RESULT_CODE_PACK_EXTENSION_ERROR"/> + <int value="23" label="chrome::RESULT_CODE_UNINSTALL_EXTENSION_ERROR"/> + <int value="24" label="chrome::RESULT_CODE_NORMAL_EXIT_PROCESS_NOTIFIED"/> + <int value="25" label="chrome::RESULT_CODE_NOTUSED_1"/> + <int value="26" label="chrome::RESULT_CODE_INSTALL_FROM_WEBSTORE_ERROR_2"/> + <int value="27" label="chrome::RESULT_CODE_NOTUSED_2"/> + <int value="28" label="chrome::RESULT_CODE_EULA_REFUSED"/> + <int value="29" label="chrome::RESULT_CODE_SXS_MIGRATION_FAILED"/> + <int value="30" label="chrome::RESULT_CODE_ACTION_DISALLOWED_BY_POLICY"/> + <int value="31" label="chrome::RESULT_CODE_INVALID_SANDBOX_STATE"/> <int value="259" label="0x103 - STILL_ACTIVE."/> <int value="85436397" label="0x517a7ed - Crashpad simulated exception"/> <int value="1073807364" label="0x40010004 - DBG_TERMINATE_PROCESS"/> @@ -40852,6 +45858,7 @@ <int value="8" label="Windows 10 TH2"/> <int value="9" label="Windows 10 RS1"/> <int value="10" label="Windows 10 RS2"/> + <int value="11" label="Windows 10 RS3"/> </enum> <enum name="WindowType"> @@ -41440,6 +46447,11 @@ <int value="43" label="Exit"/> <int value="44" label="Upgrade browser"/> <int value="45" label="Cast"/> + <int value="46" label="Beta Forum"/> + <int value="47" label="Copy URL"/> + <int value="48" label="Open in Chrome"/> + <int value="49" label="Site Settings"/> + <int value="50" label="App Info"/> </enum> <enum name="XFrameOptions"> @@ -41472,6 +46484,14 @@ </int> </enum> +<enum name="XHRPageDismissalState"> + <int value="0" label="No page dismissal."/> + <int value="1" label="Page dismissal: beforeunload."/> + <int value="2" label="Page dismissal: pagehide."/> + <int value="3" label="Page dismissal: visibility change (during unload)."/> + <int value="4" label="Page dismissal: unload."/> +</enum> + <enum name="XMLHttpRequestHeaderValueCategoryInRFC7230"> <int value="0" label="Header Value Invalid"/> <int value="1" label="Header Value Affected By Normalization"/> @@ -41488,6 +46508,16 @@ <int value="1" label="Invalidated"/> </enum> +<enum name="XRRenderPath"> + <int value="0" label="ClientWait"/> + <int value="1" label="GpuFence"/> +</enum> + +<enum name="XRRuntimeAvailable"> + <int value="0" label="None"/> + <int value="1" label="OpenVR"/> +</enum> + <enum name="YoungGenerationHandling"> <int value="0" label="Regular Scavenge"/> <int value="1" label="Scavenge using fast promotion mode"/>
diff --git a/tools/metrics/histograms/find_unmapped_histograms.py b/tools/metrics/histograms/find_unmapped_histograms.py index 2725db6..2fb75b2 100644 --- a/tools/metrics/histograms/find_unmapped_histograms.py +++ b/tools/metrics/histograms/find_unmapped_histograms.py
@@ -91,7 +91,7 @@ 'MEMORY_KB', 'MEMORY_MB', 'MEMORY_LARGE_MB', 'PERCENTAGE', 'BOOLEAN', 'ENUMERATION', - 'CUSTOM_ENUMERATION', 'SPARSE_SLOWLY']) + 'CUSTOM_ENUMERATION']) OTHER_STANDARD_HISTOGRAMS = frozenset(['SCOPED_UMA_HISTOGRAM_TIMER', 'SCOPED_UMA_HISTOGRAM_LONG_TIMER']) # The following suffixes are not defined in //base/metrics but the first @@ -252,6 +252,8 @@ with open(filename, 'r') as f: contents = removeComments(f.read()) + # TODO(isherman): Look for histogram function calls like + # base::UmaHistogramSparse() in addition to macro invocations. for match in HISTOGRAM_REGEX.finditer(contents): line_number = contents[:match.start()].count('\n') + 1 if (match.group(2) not in all_suffixes and
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 0d776f6..0893dbd 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -70,7 +70,7 @@ If a <histogram> or a <suffix> element is only provided so that its name can be extended by <histogram_suffixes>, the element should be annotated with the -attribute base="true". This instructs tools not to treat the base name as a +attribute 'base="true"'. This instructs tools not to treat the base name as a distinct histogram. If two histogram_suffixes affect the same histogram, generated lists will be @@ -227,6 +227,44 @@ </summary> </histogram> +<histogram name="Accessibility.CrosSelectToSpeak.SpeechPitch" + enum="CrosSelectToSpeakSpeechPitch"> + <owner>katie@chromium.org</owner> + <summary> + The speech pitch setting when Select-to-Speak was activated. It is stored as + a sparse histogram with values (100 * speech_pitch). For example, a speech + pitch of 1.0 (default) will be seen as 100. + </summary> +</histogram> + +<histogram name="Accessibility.CrosSelectToSpeak.SpeechRate" + enum="CrosSelectToSpeakSpeechRate"> + <owner>katie@chromium.org</owner> + <summary> + The speech rate setting when Select-to-Speak was activated. It is stored as + a sparse histogram with values (100 * speech_rate). For example, a speech + rate of 1.0 (default) will be seen as 100. + </summary> +</histogram> + +<histogram name="Accessibility.CrosSelectToSpeak.StartSpeechMethod" + enum="CrosSelectToSpeakStartSpeechMethod"> + <owner>katie@chromium.org</owner> + <summary> + A user may activate Select-to-Speak by holding down 'search' and clicking or + dragging a region with the mouse, or by highlighting an area and using + search + s to read just the highlighted area. Track the methods here. + </summary> +</histogram> + +<histogram name="Accessibility.CrosSelectToSpeak.WordHighlighting" + enum="BooleanEnabled"> + <owner>katie@chromium.org</owner> + <summary> + Whether Select-to-Speak had per-word highlighting enabled when activated. + </summary> +</histogram> + <histogram name="Accessibility.CrosSpokenFeedback" enum="BooleanEnabled"> <owner>dmazzoni@chromium.org</owner> <owner>kenjibaheux@google.com</owner> @@ -613,6 +651,13 @@ <summary>Records that a specific background task has been canceled.</summary> </histogram> +<histogram name="Android.BackgroundTaskScheduler.TaskLoadedNative" + enum="BackgroundTaskId"> + <owner>fgorski@chromium.org</owner> + <owner>nyquist@chromium.org</owner> + <summary>Records that a specific background task has loaded native.</summary> +</histogram> + <histogram name="Android.BackgroundTaskScheduler.TaskScheduled.Failure" enum="BackgroundTaskId"> <owner>fgorski@chromium.org</owner> @@ -688,6 +733,133 @@ <summary>The reason the bottom sheet was opened.</summary> </histogram> +<histogram name="Android.ChromeHome.OpenSheetVelocity.Fail" + units="microseconds/dp"> + <owner>mdjones@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <summary> + Records the reciprocal of the velocity of a swipe that did not result in the + bottom sheet opening. This value is recorded in microseconds per dp traveled + and is only recorded if the "chrome-home-swipe-logic" experiment + is set to "velocity". + </summary> +</histogram> + +<histogram name="Android.ChromeHome.OpenSheetVelocity.Navigation" + units="microseconds/dp"> + <owner>mdjones@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <summary> + Records the reciprocal of the velocity of a swipe that resulted in the + bottom sheet opening and the user navigating to a URL or a different sheet + content. This value is recorded in microseconds per dp traveled. + </summary> +</histogram> + +<histogram name="Android.ChromeHome.OpenSheetVelocity.NoNavigation" + units="microseconds/dp"> + <owner>mdjones@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <summary> + Records the reciprocal of the velocity of a swipe that resulted in the + bottom sheet opening but the user taking no action (i.e. the next action is + the sheet closing). This value is recorded in microseconds per dp traveled. + </summary> +</histogram> + +<histogram name="Android.ChromeHome.OpenSheetVelocity.Success" + units="microseconds/dp"> + <owner>mdjones@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <summary> + Records the reciprocal velocity of a swipe that resulted in the bottom sheet + opening. This value is recorded in microseconds per dp traveled and is only + recorded if the "chrome-home-swipe-logic" experiment is set to + "velocity". + </summary> +</histogram> + +<histogram name="Android.ChromeHome.Promo.Result.Menu" + enum="ChromeHomePromoResult"> + <obsolete> + Deprecated 01/2018 with the removal of the first version of Chrome Home. + </obsolete> + <owner>mdjones@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <summary> + The result of showing the Chrome Home promo when launched from the overflow + menu. This action can only be performed if Chrome Home is enabled. + </summary> +</histogram> + +<histogram name="Android.ChromeHome.Promo.Result.NTP" + enum="ChromeHomePromoResult"> + <obsolete> + Deprecated 01/2018 with the removal of the first version of Chrome Home. + </obsolete> + <owner>mdjones@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <summary> + The result of showing the Chrome Home promo when launched from the NTP. This + action can only be performed if Chrome Home is disabled. + </summary> +</histogram> + +<histogram name="Android.ChromeHome.Promo.Result.Startup" + enum="ChromeHomePromoResult"> + <obsolete> + Deprecated 01/2018 with the removal of the first version of Chrome Home. + </obsolete> + <owner>mdjones@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <summary> + The result of showing the Chrome Home promo when launched from startup. This + action can only be performed if Chrome Home is disabled. + </summary> +</histogram> + +<histogram name="Android.ChromeHome.Promo.ShowReason" + enum="ChromeHomePromoShowReason"> + <obsolete> + Deprecated 01/2018 with the removal of the first version of Chrome Home. + </obsolete> + <owner>mdjones@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <summary>The reason the Chrome Home promo was shown.</summary> +</histogram> + +<histogram name="Android.ChromeHome.Survey.DownloadResponseCode" + enum="SurveyDownloadResponseCodes"> + <owner>danielpark@chromium.org</owner> + <summary>The response code of the completed survey download request.</summary> +</histogram> + +<histogram name="Android.ChromeHome.Survey.InfoBarClosingState" + enum="InfoBarClosingStates"> + <owner>danielpark@chromium.org</owner> + <summary> + If the infobar was visible when it was closed and if it was closed directly + or not. + </summary> +</histogram> + +<histogram name="Android.ChromeHome.Survey.ShowSurvey" enum="BooleanSuccess"> + <owner>danielpark@chromium.org</owner> + <summary> + Whether or not the survey was successfully shown after its download. + </summary> +</histogram> + +<histogram name="Android.ChromeHome.Survey.SurveyFilteringResults" + enum="SurveyFilteringResult"> + <owner>danielpark@chromium.org</owner> + <summary> + The result of the survey filtering process. Each enum represents a different + filter that caught the user. This is recorded on cold starts when we check + if a user qualifies for a survey. + </summary> +</histogram> + <histogram name="Android.ChromeHome.TimeBetweenCloseAndNextOpen" units="ms"> <owner>mdjones@chromium.org</owner> <owner>twellington@chromium.org</owner> @@ -706,6 +878,18 @@ </summary> </histogram> +<histogram name="Android.ChromeHome.UserPreference.Enabled" + enum="BooleanEnabled"> + <owner>mdjones@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <summary> + Records whether or not the user preference for Chrome Home is set to + enabled. This is recorded whenever the browser is restarted and the state of + Chrome Home is first checked. This metric is only recorded if the user's + preference is set. + </summary> +</histogram> + <histogram name="Android.CompressedResources.ExtractionBlockingTime" units="ms"> <owner>estevenson@chromium.org</owner> <owner>agrieve@chromium.org</owner> @@ -716,6 +900,16 @@ </summary> </histogram> +<histogram name="Android.CompressedResources.ExtractionStatus" + enum="AndroidResourceExtractionStatus"> + <owner>estevenson@chromium.org</owner> + <owner>agrieve@chromium.org</owner> + <summary> + Describes the result of Android resource extraction, and is recorded once + per browser start as part of deferred startup (not at time of extraction). + </summary> +</histogram> + <histogram name="Android.CompressedResources.ExtractionTime" units="ms"> <owner>estevenson@chromium.org</owner> <owner>agrieve@chromium.org</owner> @@ -754,6 +948,15 @@ </summary> </histogram> +<histogram name="Android.DownloadManager.ForegroundServiceLifecycle" + enum="DownloadNotificationForegroundLifecycle"> + <owner>jming@chromium.org</owner> + <summary> + Records instances where the foreground undergoes a lifecycle change (when + the foreground starts, changes pinned notification, or stops). + </summary> +</histogram> + <histogram name="Android.DownloadManager.InitialCount"> <owner>dfalcantara@chromium.org</owner> <owner>twellington@chromium.org</owner> @@ -780,6 +983,73 @@ <summary>Recorded when a download is opened.</summary> </histogram> +<histogram name="Android.DownloadManager.List.View.Action" + enum="Android.DownloadManager.List.View.Actions"> + <owner>dtrainor@chromium.org</owner> + <summary>The count of Download Home list entry actions taken.</summary> +</histogram> + +<histogram name="Android.DownloadManager.Menu.Action" + enum="Android.DownloadManager.Menu.Actions"> + <owner>dtrainor@chromium.org</owner> + <summary>The count of Download Home top level menu actions taken.</summary> +</histogram> + +<histogram name="Android.DownloadManager.Menu.Delete.SelectedCount"> + <owner>dtrainor@chromium.org</owner> + <summary> + The number of items selected when performing a multi-delete action. + </summary> +</histogram> + +<histogram name="Android.DownloadManager.Menu.Share.SelectedCount"> + <owner>dtrainor@chromium.org</owner> + <summary> + The number of items selected when performing a multi-share action. + </summary> +</histogram> + +<histogram name="Android.DownloadManager.NotificationInteraction" + enum="DownloadNotificationInteractions"> + <owner>jming@chromium.org</owner> + <summary> + Records instances where a user interacts with a download notification (ie. + clicks on, pauses, resumes, cancels). + </summary> +</histogram> + +<histogram name="Android.DownloadManager.NotificationLaunch" + enum="DownloadNotificationLaunchType"> + <owner>jming@chromium.org</owner> + <summary> + Records instances when a notification is being launched for the first time + or relaunched due to the need to dissociate the notification from the + foreground (only on API less than 24). + </summary> +</histogram> + +<histogram name="Android.DownloadManager.NotificationsCount.ForegroundDisabled" + units="notifications"> + <owner>jming@chromium.org</owner> + <summary> + Records the number of notifications that are already existing (presumably + displayed) when a new notification is being launched to help understand the + frequency of multiple downloads with downloads as a foreground service + disabled. + </summary> +</histogram> + +<histogram name="Android.DownloadManager.NotificationsCount.ForegroundEnabled" + units="notifications"> + <owner>jming@chromium.org</owner> + <summary> + Records the number of notifications that are already existing (presumably + displayed) when a new notification is being launched to help understand the + frequency of multiple downloads with downloads as a foreground service + enabled. + </summary> +</histogram> + <histogram name="Android.DownloadManager.OtherExtensions.InitialCount" enum="AndroidDownloadExtensionType"> <owner>dfalcantara@chromium.org</owner> @@ -820,6 +1090,36 @@ </summary> </histogram> +<histogram name="Android.DownloadManager.ServiceStopped.DownloadForeground" + enum="DownloadNotificationServiceStopped"> + <owner>jming@chromium.org</owner> + <summary> + Records instances of DownloadForegroundService stops. The number of + expected stops (stopped) and unexpected stops (task removed, low memory, + etc) can be compared to get a sense of how often the service crashes to see + how it handles restarts. For example, the number of times the service is + stopped because of low memory can be compared to the number of times the + service has been destroyed to see how frequently it occurs. Or, the number + of start sticky's will indicate how often the service is able to restart due + to an unexpected stop. + </summary> +</histogram> + +<histogram name="Android.DownloadManager.ServiceStopped.DownloadNotification" + enum="DownloadNotificationServiceStopped"> + <owner>jming@chromium.org</owner> + <summary> + Records instances of DownloadNotificationService stops. The number of + expected stops (stopped) and unexpected stops (task removed, low memory, + etc) can be compared to get a sense of how often the service crashes to see + how it handles restarts. For example, the number of times the service is + stopped because of low memory can be compared to the number of times the + service has been destroyed to see how frequently it occurs. Or, the number + of start sticky's will indicate how often the service is able to restart due + to an unexpected stop. + </summary> +</histogram> + <histogram name="Android.DownloadManager.Share.Count"> <owner>dfalcantara@chromium.org</owner> <owner>twellington@chromium.org</owner> @@ -901,6 +1201,15 @@ </summary> </histogram> +<histogram name="Android.InstantApps.DirectInstantAppsIntent" + enum="DirectIntentType"> + <owner>mariakhomenko@chromium.org</owner> + <summary> + Records events that occur when a user clicks on an intent:// URL that is + dispatched to instant apps. + </summary> +</histogram> + <histogram name="Android.InstantApps.FallbackDuration" units="ms"> <owner>mariakhomenko@chromium.org</owner> <summary> @@ -937,6 +1246,35 @@ </summary> </histogram> +<histogram + name="Android.MainActivity.ExplicitMainViewIntentDispatched.OnCreate" + enum="BooleanDispatched"> + <owner>dskiba@chromium.org</owner> + <summary> + Whether VIEW intent sent explicitly to .Main activity was dispatched by + onCreate(). + </summary> +</histogram> + +<histogram + name="Android.MainActivity.ExplicitMainViewIntentDispatched.OnNewIntent" + enum="BooleanDispatched"> + <owner>dskiba@chromium.org</owner> + <summary> + Whether VIEW intent sent explicitly to .Main activity was dispatched by + onNewIntent(). + </summary> +</histogram> + +<histogram name="Android.MainActivity.UndispatchedExplicitMainViewIntentSource" + enum="ClientAppId"> + <owner>dskiba@chromium.org</owner> + <summary> + Sources (ExternalAppId) of undispatched VIEW intents sent explicitly to + .Main activity alias. + </summary> +</histogram> + <histogram name="Android.ManageSpace.ActionTaken" enum="AndroidManageSpaceButton"> <owner>dmurph@chromium.org</owner> @@ -1032,6 +1370,30 @@ </summary> </histogram> +<histogram name="Android.PackageStats.CacheSize" units="MB"> + <owner>mariakhomenko@chromium.org</owner> + <summary> + Records the size of the user's cache at startup on Android O and above. + </summary> +</histogram> + +<histogram name="Android.PackageStats.CodeSize" units="MB"> + <owner>mariakhomenko@chromium.org</owner> + <summary> + At startup, records the space on disk taken by Chrome application including + APK resources, compiled libraries, and extracted native code. Only recorded + for Android O and above. + </summary> +</histogram> + +<histogram name="Android.PackageStats.DataSize" units="MB"> + <owner>mariakhomenko@chromium.org</owner> + <summary> + Records the size of the user's data directory at startup on Android O and + above. Does not include cache size. + </summary> +</histogram> + <histogram name="Android.PhotoPicker.BitmapScalerTask" units="ms"> <owner>finnur@chromium.org</owner> <owner>twellington@chromium.org</owner> @@ -1095,6 +1457,15 @@ </summary> </histogram> +<histogram name="Android.PhotoPicker.ExifOrientation" enum="ExifOrientation"> + <owner>finnur@chromium.org</owner> + <summary> + Records whether the EXIF orientation directive is present and what it is set + to. Collected once per decoded image, but only on Android N and above (and + when no IO error occurs). + </summary> +</histogram> + <histogram name="Android.PhotoPicker.ImageByteCount" units="KB"> <owner>finnur@chromium.org</owner> <owner>twellington@chromium.org</owner> @@ -1212,6 +1583,17 @@ </summary> </histogram> +<histogram name="Android.SelectFileDialogImgCount" units="images"> + <owner>finnur@chromium.org</owner> + <owner>peter@chromium.org</owner> + <summary> + Records the number of images selected in either the new Photo Picker or the + standard Android file picker. Note: Only recorded in situations determined + to warrant the new Photo Picker (not, for example, if mixed content, like + images and text files, was requested). + </summary> +</histogram> + <histogram name="Android.SelectFileDialogScope" enum="SelectFileDialogScope"> <owner>peter@chromium.org</owner> <summary> @@ -1352,6 +1734,16 @@ </summary> </histogram> +<histogram name="Android.SysUtilsLowEndMatches" enum="BooleanEqual"> + <owner>mariakhomenko@chromium.org</owner> + <summary> + Measures whether Chrome low-end detection logic based on RAM size matches + the Android system utility value for isLowRamDevice(). This is recorded once + per browser start and may be recorded in the renderer if isLowEndDevice() + bit is checked. + </summary> +</histogram> + <histogram name="Android.TabNavigationInterceptResult" enum="NavigationInterceptResult"> <owner>mariakhomenko@chromium.org</owner> @@ -1410,6 +1802,21 @@ </summary> </histogram> +<histogram name="AnimatedImage.NumOfFramesSkipped" units="count"> + <owner>khushalsagar@chromium.org</owner> + <summary> + If the frame rate for the image animation can not be reached, frames in the + animation are skipped to catch up to the desired frame. This metric tracks + the number of frames skipped during catch up, and can be used to assess the + smoothness of these animations. It records the number of frames skipped each + time the animation is ticked forward to draw the next frame. In the ideal + case, where the animation can be drawn at the desired rate, 0 frames should + be skipped. Note that skipping of frames can also be triggered if the + animation was intentionally paused (on becoming off-screen, or the tab being + hidden). + </summary> +</histogram> + <histogram name="AppBanners.BeforeInstallEvent" enum="AppBannersBeforeInstallEvent"> <owner>dominickn@chromium.org</owner> @@ -1657,6 +2064,10 @@ </histogram> <histogram name="Apps.AppLauncherPromo" enum="AppLauncherPromo"> + <obsolete> + Deprecated 11/2017 in issue 600915 with the removal of app list on platforms + other than Chrome OS. + </obsolete> <owner>mad@chromium.org</owner> <summary>Interactions with the App Launcher promo dialog.</summary> </histogram> @@ -1679,6 +2090,14 @@ </summary> </histogram> +<histogram name="Apps.AppListBadgedAppsCount" units="apps"> + <owner>vadimt@chromium.org</owner> + <summary> + Number of apps (including ones in folders) with Chrome badge, across all + Launcher pages. This is gathered per open-launcher event. + </summary> +</histogram> + <histogram name="Apps.AppListCreationTime" units="ms"> <owner>calamity@chromium.org</owner> <summary> @@ -1688,6 +2107,9 @@ </histogram> <histogram name="Apps.AppListDoodleAction" enum="AppListDoodleAction"> + <obsolete> + App list doesn't support doodles anymore. + </obsolete> <owner>calamity@chromium.org</owner> <summary> The number of user interactions with the app list doodle. This is logged @@ -1863,8 +2285,67 @@ <owner>newcomer@chromium.org</owner> <summary> The total number of apps in folders ignoring OEM folders. This is logged - each time the app list is initialized. The suffix denotes whether the - fullscreen app list feature has been enabled. + each time the app list is initialized. The + "FullscreenAppListDisabled" suffix has been deprecated. + </summary> +</histogram> + +<histogram base="true" name="Apps.ContextMenuExecuteCommand" + enum="ChromeOSUICommands"> +<!-- Name completed by histogram_suffixes + name="ContextMenuFromApp" --> + + <owner>=newcomer@chromium.org</owner> + <summary> + The number of times a certain command was executed by a context menu, split + by whether the context menu came from an app, or another part of the system + UI. + </summary> +</histogram> + +<histogram base="true" name="Apps.ContextMenuShowSource" enum="MenuSourceType"> +<!-- Name completed by histogram_suffixes + name="AppUIComponent" --> + + <owner>=newcomer@chromium.org</owner> + <summary> + The show source (touch, mouse, keyboard, etc) for a context menu. Split by + the component from which the context menu originated. + </summary> +</histogram> + +<histogram base="true" name="Apps.ContextMenuUserJourneyTime" units="ms"> +<!-- Name completed by histogram_suffixes + name="AppUIComponent" --> + + <owner>=newcomer@chromium.org</owner> + <summary> + The user journey time for a ContextMenu, defined as the time between + launching a context menu and the context menu's close callback being + activated. Not recorded whenever the context menu is not for an app icon on + the shelf. + </summary> +</histogram> + +<histogram name="Apps.LockScreen.AppsProfile.Creation.Duration" units="ms"> + <owner>tbarzic@chromium.org</owner> + <summary> + The amount of time needed to create a lock screen apps profile. This metric + is recorded only if the profile creation was successful. The lock screen + apps profile is created if the user has an app enabled on Chrome OS lock + screen, and is used as the context in which the app is launched on top of + the lock screen. + </summary> +</histogram> + +<histogram name="Apps.LockScreen.AppsProfile.Creation.Success" + units="BooleanSuccess"> + <owner>tbarzic@chromium.org</owner> + <summary> + Boolean indicating whether the lock screen apps profile creation succeeded. + The lock screen apps profile is created if the user has an app enabled on + Chrome OS lock screen, and is used as the context in which the app is + launched on top of the lock screen. </summary> </histogram> @@ -1923,6 +2404,17 @@ </summary> </histogram> +<histogram name="Apps.LockScreen.NoteTakingApp.AppStatusOnNoteLaunch" + enum="LockScreenNoteAppStatusOnLaunch"> + <owner>tbarzic@chromium.org</owner> + <summary> + Reported when a user attempts to launch a note taking app on the lock + screen. It reports the note taking app state in the lock screen apps profile + at the launch attempt time - for example, whether the app was enabled, or + whether the app had been terminated and an app reload was attempted. + </summary> +</histogram> + <histogram base="true" name="Apps.LockScreen.NoteTakingApp.AppWindowLifeTime" units="ms"> <owner>tbarzic@chromium.org</owner> @@ -1986,6 +2478,19 @@ </summary> </histogram> +<histogram name="Apps.LockScreen.NoteTakingApp.LockScreenAppUnloaded" + enum="LockScreenAppUnloadStatus"> + <owner>tbarzic@chromium.org</owner> + <summary> + Reported when a note taking app is unloaded from the lock screen apps + profile while lock screen note taking is available. Reports the unload + reason type, which can be used to deduce whether the app can be reloaded in + the profile. The app unload event is not reported if the app is unloaded due + to lock screen note taking becoming unavailble (e.g. when the user unlocks + the screen). + </summary> +</histogram> + <histogram name="Apps.LockScreen.NoteTakingApp.LockScreenInstallationDuration" units="ms"> <owner>tbarzic@chromium.org</owner> @@ -2006,6 +2511,16 @@ </summary> </histogram> +<histogram name="Apps.LockScreen.NoteTakingApp.ReloadCountOnAppTermination"> + <owner>tbarzic@chromium.org</owner> + <summary> + Reported when a note taking app is terminated in the lock screen apps + profile. It reports the number of times the app was reloaded in the lock + screen apps profile during the current lock screen session (prior to the + termination). + </summary> +</histogram> + <histogram name="Apps.LockScreen.NoteTakingApp.TimeToLoadAppWindowContents" units="ms"> <owner>tbarzic@chromium.org</owner> @@ -2057,15 +2572,52 @@ </summary> </histogram> +<histogram name="Apps.NumberOfFolders" units="folder(s)"> + <owner>newcomer@google.com</owner> + <summary> + The number of folders that users have in their Launcher. Includes the OEM + folder. This metric is recorded every time the launcher is shown. + </summary> +</histogram> + +<histogram name="Apps.PaginationTransition.AnimationSmoothness" units="%"> + <owner>wutao@chromium.org</owner> + <summary> + Relative smoothness of animations of launcher pagination transitions. 100% + represents ideally smooth 60 frames per second. 50% represents only 30 + frames per second is achieved during the animations. 0% should not happen. + This metric is recorded exactly once when the user starts the pagination + transition animation of the launcher. + </summary> +</histogram> + +<histogram name="Apps.StateTransition.AnimationSmoothness" units="%"> + <owner>vadimt@chromium.org</owner> + <summary> + Relative smoothness of animations of peeking launcher state transitions. + 100% represents ideally smooth 60 frames per second. 50% represents only 30 + frames per second is achieved during the animations. 0% should not happen. + This metric is recorded exactly once when the user switches states of the + launcher. + </summary> +</histogram> + +<histogram name="Apps.Window.Type" enum="AppsWindowType"> + <owner>stevenjb@chromium.org</owner> + <summary> + The type of app window opened (through the chrome.app.window API). + </summary> +</histogram> + <histogram name="Arc.AndroidBootTime" units="ms"> <owner>elijahtaylor@google.com</owner> - <owner>mitsuji@google.com</owner> + <owner>shihuis@google.com</owner> <summary>The time elapsed for booting up the ARC instance.</summary> </histogram> <histogram name="Arc.AppCount"> <owner>elijahtaylor@google.com</owner> - <owner>mitsuji@google.com</owner> + <owner>shihuis@google.com</owner> <summary> The number of ARC apps open at any given time. Collected every 5 minutes. This indicates both how many users are engaging with apps and, when they do @@ -2075,7 +2627,7 @@ <histogram name="Arc.AppsInstalledAtStartup" units="App Count"> <owner>elijahtaylor@google.com</owner> - <owner>mitsuji@google.com</owner> + <owner>shihuis@google.com</owner> <summary> Total number of ARC apps installed on a device measured at startup. Note: This includes launchable apps that are installed by default, such as Play @@ -2085,12 +2637,61 @@ <histogram name="Arc.boot_progress" units="ms"> <owner>elijahtaylor@google.com</owner> - <owner>mitsuji@google.com</owner> + <owner>shihuis@google.com</owner> <summary> The relative time of a boot progress event since the ARC starts. </summary> </histogram> +<histogram name="Arc.BootContinueCodeInstallationResult" + enum="ArcBootContinueCodeInstallationResult"> + <owner>elijahtaylor@google.com</owner> + <owner>xzhou@google.com</owner> + <summary>Code installation result for ARC boot continue.</summary> +</histogram> + +<histogram name="Arc.CodeIntegrityCheckingTotalTime" units="ms"> + <owner>elijahtaylor@google.com</owner> + <owner>xzhou@google.com</owner> + <summary> + Total time needed to check the integrity of host generated code. If + signature checking fails, it also includes the time to regenerate and sign + the code. + </summary> +</histogram> + +<histogram name="Arc.CodeRelocationResult" enum="ArcCodeRelocationResult"> + <owner>elijahtaylor@google.com</owner> + <owner>xzhou@google.com</owner> + <summary>Host code relocation result.</summary> +</histogram> + +<histogram name="Arc.CodeRelocationTime" units="ms"> + <owner>elijahtaylor@google.com</owner> + <owner>xzhou@google.com</owner> + <summary>Time needed to relocate boot*.art files.</summary> +</histogram> + +<histogram name="Arc.CodeSigningTime" units="ms"> + <owner>elijahtaylor@google.com</owner> + <owner>xzhou@google.com</owner> + <summary>Time needed to sign boot*.art files.</summary> +</histogram> + +<histogram name="Arc.CodeVerificationResult" enum="ArcCodeVerificationResult"> + <owner>elijahtaylor@google.com</owner> + <owner>xzhou@google.com</owner> + <summary> + Code verification result for host generated code for boot for login screen. + </summary> +</histogram> + +<histogram name="Arc.CodeVerificationTime" units="ms"> + <owner>elijahtaylor@google.com</owner> + <owner>xzhou@google.com</owner> + <summary>Time needed to verify host generated code.</summary> +</histogram> + <histogram name="Arc.ComplianceReportSinceUpdateNotificationTime" units="ms"> <owner>alexchau@google.com</owner> <owner>emaxx@google.com</owner> @@ -2100,9 +2701,28 @@ </summary> </histogram> +<histogram name="Arc.ContainerLifetimeEvent" enum="ArcContainerLifetimeEvent"> + <owner>elijahtaylor@google.com</owner> + <owner>yusukes@google.com</owner> + <summary> + The number of ARC container lifetime events. One START event and up to one + non-START event are recorded per ARC session, which ends when the user opts + out from ARC or signs out. + </summary> +</histogram> + +<histogram name="Arc.ContainerRestartAfterCrashCount"> + <owner>elijahtaylor@google.com</owner> + <owner>yusukes@google.com</owner> + <summary> + The number of times ARC container crashes and automatically restarts in one + ARC session, which ends when the user opts out from ARC or signs out. + </summary> +</histogram> + <histogram name="Arc.CumulativeUseTime" units="seconds"> <owner>elijahtaylor@google.com</owner> - <owner>mitsuji@google.com</owner> + <owner>shihuis@google.com</owner> <summary> ARC use time. The use time is incremented in regular intervals while android container is active. Reported at most once a day, at which point accumulated @@ -2151,14 +2771,14 @@ <histogram name="Arc.IntentHandlerAction" enum="ArcIntentHandlerAction"> <owner>elijahtaylor@google.com</owner> - <owner>mitsuji@google.com</owner> + <owner>shihuis@google.com</owner> <summary>ARC intent handler action taken by user.</summary> </histogram> <histogram name="Arc.IntentHandlerDestinationPlatform" enum="ArcIntentHandlerDestinationPlatform"> <owner>elijahtaylor@google.com</owner> - <owner>mitsuji@google.com</owner> + <owner>shihuis@google.com</owner> <summary> ARC intent handler destination platform. The destination may be specified due to the user explicit selection or a previously stored preference. @@ -2167,31 +2787,43 @@ <histogram name="Arc.LowMemoryKiller.Count"> <owner>elijahtaylor@google.com</owner> - <owner>mitsuji@google.com</owner> + <owner>shihuis@google.com</owner> <summary>Cumulative count of low memory kills in one user session.</summary> </histogram> <histogram name="Arc.LowMemoryKiller.FreedSize" units="KB"> <owner>elijahtaylor@google.com</owner> - <owner>mitsuji@google.com</owner> + <owner>shihuis@google.com</owner> <summary>The memory size freed by each low memory kill event.</summary> </histogram> <histogram name="Arc.LowMemoryKiller.TimeDelta" units="ms"> <owner>elijahtaylor@google.com</owner> - <owner>mitsuji@google.com</owner> + <owner>shihuis@google.com</owner> <summary>The elapsed time to last low memory kill event.</summary> </histogram> +<histogram name="Arc.NativeBridge" enum="ArcNativeBridgeType"> + <owner>elijahtaylor@google.com</owner> + <owner>levarum@google.com</owner> + <summary> + Native bridge used for ARC. Can be unknown and none. This is collected along + with Arc.State during every metrics recording interval, so it is in every + record uploaded to the server. This is required because this value is used + to categorize all other data in the dashboard as collected with specific + native bridge in use. + </summary> +</histogram> + <histogram name="Arc.OOMKills.Count" units="kills"> <owner>elijahtaylor@google.com</owner> - <owner>mitsuji@google.com</owner> + <owner>shihuis@google.com</owner> <summary>Cumulative count of OOM kills in one user session.</summary> </histogram> <histogram name="Arc.OOMKills.Score" units="badness score"> <owner>elijahtaylor@google.com</owner> - <owner>mitsuji@google.com</owner> + <owner>shihuis@google.com</owner> <summary> The oom_badness score of a OOM killed process as reported by kernel. </summary> @@ -2199,19 +2831,19 @@ <histogram name="Arc.OOMKills.TimeDelta" units="ms"> <owner>elijahtaylor@google.com</owner> - <owner>mitsuji@google.com</owner> + <owner>shihuis@google.com</owner> <summary>The elapsed time since last OOM kill event.</summary> </histogram> <histogram name="Arc.OptInAction" enum="ArcOptInAction"> <owner>elijahtaylor@google.com</owner> - <owner>mitsuji@google.com</owner> + <owner>shihuis@google.com</owner> <summary>Arc OptIn action taken by user.</summary> </histogram> <histogram name="Arc.OptInCancel" enum="ArcOptInCancel"> <owner>elijahtaylor@google.com</owner> - <owner>mitsuji@google.com</owner> + <owner>shihuis@google.com</owner> <summary>Arc OptIn cancelation reason.</summary> </histogram> @@ -2225,9 +2857,15 @@ <owner>elijahtaylor@google.com</owner> <summary> Arc Silent Auth Code status. This status is set during the ARC OptIn flow. - Retrieving Auth Code silently is optional feature. If it is not activated, - Disabled state is reported. Once it active, Auth code is retrieved silently. - In no error occurs, Success is reported. Otherwise specific error is sent. + </summary> +</histogram> + +<histogram name="Arc.OptInSilentAuthCode.Reauthorization" + enum="ArcOptInSilentAuthCode"> + <owner>khmel@google.com</owner> + <summary> + Arc Silent Auth Code status. This status is set during the ARC + reauthorization flow. </summary> </histogram> @@ -2290,6 +2928,16 @@ </summary> </histogram> +<histogram name="Arc.Provisioning.Result.RobotAccount" + enum="ArcProvisioningResult"> + <owner>alexchau@google.com</owner> + <owner>phweiss@google.com</owner> + <summary> + The result (success or the type of failure) of ARC provisioning on managed + devices with a robot account (Public Session or Kiosk). + </summary> +</histogram> + <histogram name="Arc.Provisioning.Result.Unmanaged" enum="ArcProvisioningResult"> <owner>alexchau@google.com</owner> @@ -2309,6 +2957,15 @@ </summary> </histogram> +<histogram name="Arc.Provisioning.TimeDelta.Failure.RobotAccount" units="ms"> + <owner>alexchau@google.com</owner> + <owner>phweiss@google.com</owner> + <summary> + Elapsed time from the signing in process start to call to onSignInFailed for + managed users with a robot account (Public Session or Kiosk). + </summary> +</histogram> + <histogram name="Arc.Provisioning.TimeDelta.Failure.Unmanaged" units="ms"> <owner>alexchau@google.com</owner> <owner>phweiss@google.com</owner> @@ -2327,6 +2984,16 @@ </summary> </histogram> +<histogram name="Arc.Provisioning.TimeDelta.Success.RobotAccount" units="ms"> + <owner>alexchau@google.com</owner> + <owner>phweiss@google.com</owner> + <summary> + Elapsed time from the signing in process start to successful call to + onSignInComplete for managed users with a robot account (Public Session or + Kiosk). + </summary> +</histogram> + <histogram name="Arc.Provisioning.TimeDelta.Success.Unmanaged" units="ms"> <owner>alexchau@google.com</owner> <owner>phweiss@google.com</owner> @@ -2336,6 +3003,33 @@ </summary> </histogram> +<histogram name="Arc.Reauthorization.Result.Managed" + enum="ArcProvisioningResult"> + <owner>khmel@google.com</owner> + <summary> + The result (success or the type of failure) of ARC reauthorization on + managed devices. + </summary> +</histogram> + +<histogram name="Arc.Reauthorization.Result.RobotAccount" + enum="ArcProvisioningResult"> + <owner>khmel@google.com</owner> + <summary> + The result (success or the type of failure) of ARC reauthorization on + managed devices with a robot account (Public Session or Kiosk). + </summary> +</histogram> + +<histogram name="Arc.Reauthorization.Result.Unmanaged" + enum="ArcProvisioningResult"> + <owner>khmel@google.com</owner> + <summary> + The result (success or the type of failure) of ARC reauthorization on + unmanaged devices. + </summary> +</histogram> + <histogram name="Arc.ShutdownTime" units="ms"> <owner>elijahtaylor@google.com</owner> <summary> @@ -2348,7 +3042,7 @@ <histogram name="Arc.State" enum="BooleanEnabled"> <owner>elijahtaylor@google.com</owner> - <owner>mitsuji@google.com</owner> + <owner>shihuis@google.com</owner> <summary> Whether ARC is enabled or not. Before M56 this was collected only on login and when ARC was enabled or disabled. From M56 forward this is collected @@ -2517,6 +3211,57 @@ </summary> </histogram> +<histogram name="Ash.DisplayColorManager.HasColorCorrectionMatrix" + enum="Boolean"> + <owner>mcasas@chromium.org</owner> + <owner>dcastagna@chromium.org</owner> + <summary> + Whether a display has a "CTM" matrix properties that can be used + to set a color transform matrix. Recorded every time there is a display + configuration update. + </summary> +</histogram> + +<histogram name="Ash.DisplayColorManager.IccFileDownloaded" + enum="BooleanDownloaded"> + <owner>mcasas@chromium.org</owner> + <owner>dcastagna@chromium.org</owner> + <summary> + This boolean keeps track if an ICC file was downloaded correctly (if true) + or a local file was reused instead. + </summary> +</histogram> + +<histogram name="Ash.DisplayColorManager.IccFileFound" enum="Boolean"> + <obsolete> + Deprecated 10/2017, replaced by Ash.DisplayColorManager.IccFileDownloaded + </obsolete> + <owner>mcasas@chromium.org</owner> + <owner>dcastagna@chromium.org</owner> + <summary> + This boolean keeps track if a request for an ICC for a specific product id + has been successful or not. + </summary> +</histogram> + +<histogram name="Ash.DisplayColorManager.ValidDisplayColorSpace" enum="Boolean"> + <owner>mcasas@chromium.org</owner> + <owner>dcastagna@chromium.org</owner> + <summary> + This boolean keeps track if a Display update (i.e. when connecting a new + one) carried valid ColorSpace information. + </summary> +</histogram> + +<histogram name="Ash.DisplayColorManager.ValidProductId" enum="Boolean"> + <owner>mcasas@chromium.org</owner> + <owner>dcastagna@chromium.org</owner> + <summary> + Whether we could parse a valid product id from a display EDID. Recorded + every time there is a display configuration update. + </summary> +</histogram> + <histogram name="Ash.Dock.Action" enum="DockedAction"> <owner>kuscher@google.com</owner> <owner>varkha@chromium.org</owner> @@ -2619,6 +3364,64 @@ </summary> </histogram> +<histogram name="Ash.Login.Lock.AuthMethod.Switched" + enum="AuthMethodSwitchType"> + <owner>xiaoyinh@google.com</owner> + <summary> + The count of auth method switching actions in ChromeOS lock screen. + </summary> +</histogram> + +<histogram name="Ash.Login.Lock.AuthMethod.Used.ClamShellMode" + enum="AuthMethod"> + <owner>xiaoyinh@google.com</owner> + <summary> + The usage of different auth methods (PIN / Password / Smartlock) in ChromeOS + lock screen clamshell mode. + </summary> +</histogram> + +<histogram name="Ash.Login.Lock.AuthMethod.Used.TabletMode" enum="AuthMethod"> + <owner>xiaoyinh@google.com</owner> + <summary> + The usage of different auth methods (PIN / Password / Smartlock) in ChromeOS + lock screen tablet mode. + </summary> +</histogram> + +<histogram name="Ash.Login.Lock.NumPasswordAttempts.UntilFailure" units="count"> + <owner>xiaoyinh@google.com</owner> + <summary> + The number of incorrect password entered in ChromeOS lock screen until the + user gives up (switch pods or user sign out the current session or shutdown + the device). + </summary> +</histogram> + +<histogram name="Ash.Login.Lock.NumPasswordAttempts.UntilSuccess" units="count"> + <owner>xiaoyinh@google.com</owner> + <summary> + The number of incorrect password entered in ChromeOS lock screen until a + successful attempt. + </summary> +</histogram> + +<histogram name="Ash.Login.Lock.UserClicks" enum="LockScreenUserClickTarget"> + <owner>xiaoyinh@google.com</owner> + <summary> + The numbers of times that users click on the shelf buttons, trays and lock + screen note on the ChromeOS lock screen. + </summary> +</histogram> + +<histogram name="Ash.Login.Login.UserClicks" enum="LoginScreenUserClickTarget"> + <owner>agawronska@google.com</owner> + <summary> + The numbers of times that users click on the shelf buttons and trays on the + ChromeOS login screen. + </summary> +</histogram> + <histogram name="Ash.NightLight.ScheduleType" enum="AshNightLightScheduleType"> <owner>afakhry@chromium.org</owner> <summary> @@ -2648,6 +3451,25 @@ </summary> </histogram> +<histogram name="Ash.PowerButtonScreenshot.DelayBetweenAccelKeyPressed" + units="ms"> + <owner>warx@chromium.org</owner> + <summary> + Record the delay when power button and volume down key are both pressed, + which indicates user might want to use accelerator to take screenshot. This + will help us determine the best chord delay among metrics. + </summary> +</histogram> + +<histogram name="Ash.ProcessCreationToFirstPresent" units="ms"> + <owner>sky@chromium.org</owner> + <summary> + The delta between when chrome main starts to when the Chrome OS system UI + (ash) is visible to the user (specifically the first time pixels are lit up + on the primary display showing the Chrome OS system UI). + </summary> +</histogram> + <histogram name="Ash.Rotation.AnimationSmoothness" units="%"> <owner>wutao@chromium.org</owner> <summary> @@ -2866,6 +3688,15 @@ </summary> </histogram> +<histogram name="Ash.SplitView.TimeInSplitView" units="ms"> + <owner>xdai@chromium.org</owner> + <summary> + The amount of time that the user spent in split view mode. The time is + measured from the moment a window is snapped to one side of the screen to + when split view mode is ended. + </summary> +</histogram> + <histogram name="Ash.StationaryTouchDuration" units="seconds"> <obsolete> Deprecated 02/2017 due to lack of usage. @@ -3048,6 +3879,9 @@ </histogram> <histogram name="Ash.Wallpaper.Apps" enum="WallpaperApps"> + <obsolete> + Deprecated as of 2/2018. Currently there is only one type of Wallpaper App. + </obsolete> <owner>xdai@chromium.org</owner> <summary> The Wallpaper App that the user is using right now on Chrome OS. It's the @@ -3438,6 +4272,9 @@ </histogram> <histogram name="AsyncDNS.ConfigParseResult" enum="BooleanSuccess"> + <obsolete> + Deprecated as of 9/2017. + </obsolete> <owner>mgersh@chromium.org</owner> <summary>Whether DnsConfig was parsed successfully.</summary> </histogram> @@ -3450,6 +4287,9 @@ </histogram> <histogram name="AsyncDNS.DNSChangerDetected" enum="BooleanSuccess"> + <obsolete> + Deprecated as of 9/2017. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Whether the first valid DnsConfig included a rogue nameserver. @@ -3536,6 +4376,9 @@ </histogram> <histogram name="AsyncDNS.JobQueueTime" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.JobQueueTime. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Time elapsed between the time the HostResolverImpl::Job was created and the @@ -3544,6 +4387,9 @@ </histogram> <histogram name="AsyncDNS.JobQueueTime_HIGHEST" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.JobQueueTime. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Time elapsed between the time the HostResolverImpl::Job was created and the @@ -3553,6 +4399,9 @@ </histogram> <histogram name="AsyncDNS.JobQueueTime_IDLE" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.JobQueueTime. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Time elapsed between the time the HostResolverImpl::Job was created and the @@ -3562,6 +4411,9 @@ </histogram> <histogram name="AsyncDNS.JobQueueTime_LOW" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.JobQueueTime. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Time elapsed between the time the HostResolverImpl::Job was created and the @@ -3571,6 +4423,9 @@ </histogram> <histogram name="AsyncDNS.JobQueueTime_LOWEST" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.JobQueueTime. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Time elapsed between the time the HostResolverImpl::Job was created and the @@ -3580,6 +4435,9 @@ </histogram> <histogram name="AsyncDNS.JobQueueTime_MEDIUM" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.JobQueueTime. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Time elapsed between the time the HostResolverImpl::Job was created and the @@ -3589,6 +4447,9 @@ </histogram> <histogram name="AsyncDNS.JobQueueTimeAfterChange" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.JobQueueTimeAfterChange. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Time elapsed between the last time the priority of a HostResolverImpl::Job @@ -3598,6 +4459,9 @@ </histogram> <histogram name="AsyncDNS.JobQueueTimeAfterChange_HIGHEST" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.JobQueueTimeAfterChange. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Time elapsed between the last time the priority of a HostResolverImpl::Job @@ -3608,6 +4472,9 @@ </histogram> <histogram name="AsyncDNS.JobQueueTimeAfterChange_IDLE" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.JobQueueTimeAfterChange. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Time elapsed between the last time the priority of a HostResolverImpl::Job @@ -3618,6 +4485,9 @@ </histogram> <histogram name="AsyncDNS.JobQueueTimeAfterChange_LOW" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.JobQueueTimeAfterChange. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Time elapsed between the last time the priority of a HostResolverImpl::Job @@ -3628,6 +4498,9 @@ </histogram> <histogram name="AsyncDNS.JobQueueTimeAfterChange_LOWEST" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.JobQueueTimeAfterChange. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Time elapsed between the last time the priority of a HostResolverImpl::Job @@ -3638,6 +4511,9 @@ </histogram> <histogram name="AsyncDNS.JobQueueTimeAfterChange_MEDIUM" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.JobQueueTimeAfterChange. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Time elapsed between the last time the priority of a HostResolverImpl::Job @@ -3667,6 +4543,9 @@ </histogram> <histogram name="AsyncDNS.PrefDefaultSource" enum="AsyncDNSPrefDefaultSource"> + <obsolete> + Deprecated as of 9/2017. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> The source of the async DNS preference's default. Logged at startup, when @@ -3675,6 +4554,9 @@ </histogram> <histogram name="AsyncDNS.PrefSource" enum="AsyncDNSPrefSource"> + <obsolete> + Deprecated as of 9/2017. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> The source of the async DNS preference's value. Logged at startup, when the @@ -3683,6 +4565,9 @@ </histogram> <histogram name="AsyncDNS.ResolveError" enum="NetErrorCodes"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.DnsTaskError. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Counts of specific error codes returned by DnsTask if a subsequent ProcTask @@ -3691,6 +4576,9 @@ </histogram> <histogram name="AsyncDNS.ResolveFail" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.DnsTaskFail. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Duration of time taken by DnsTask in resolutions that failed. Excludes time @@ -3699,6 +4587,9 @@ </histogram> <histogram name="AsyncDNS.ResolveStatus" enum="AsyncDNSResolveStatus"> + <obsolete> + Deprecated as of 9/2017. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Counts of the overall results of using asynchronous DNS in HostResolverImpl. @@ -3708,6 +4599,9 @@ </histogram> <histogram name="AsyncDNS.ResolveSuccess" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.DnsTaskSuccess. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Duration of time taken by DnsTask in resolutions that succeeded. @@ -3715,6 +4609,9 @@ </histogram> <histogram name="AsyncDNS.ResolveSuccess_FAMILY_IPV4" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.DnsTaskSuccess. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Same as AsyncDNS.ResolveSuccess, but limited to pure IPv4 lookups. @@ -3722,6 +4619,9 @@ </histogram> <histogram name="AsyncDNS.ResolveSuccess_FAMILY_IPV6" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.DnsTaskSuccess. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Same as AsyncDNS.ResolveSuccess, but limited to pure IPv6 lookups. @@ -3729,6 +4629,9 @@ </histogram> <histogram name="AsyncDNS.ResolveSuccess_FAMILY_UNSPEC" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.DnsTaskSuccess. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Same as AsyncDNS.ResolveSuccess, but limited to IPv4/IPv6 lookups. @@ -3785,6 +4688,9 @@ </histogram> <histogram name="AsyncDNS.ServerIsGood" enum="BooleanSuccess"> + <obsolete> + Deprecated as of 9/2017. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> The current server is "good" and does not have to be skipped. @@ -3891,6 +4797,9 @@ </histogram> <histogram name="AsyncDNS.TotalTime" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.TotalTime. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Duration of time since a HostResolverImpl::Resolve request to the time a @@ -3900,6 +4809,9 @@ </histogram> <histogram name="AsyncDNS.TotalTime_speculative" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.TotalTime_speculative. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Duration of time since a HostResolverImpl::Resolve request to the time a @@ -4454,7 +5366,16 @@ </summary> </histogram> -<histogram name="Autofill.AddressesSuppressedForDisuse"> +<histogram name="Autofill.AddressesDeletedForDisuse" units="addresses"> + <owner>wuandy@chromium.org</owner> + <summary> + The number of unverified autofill addresses deleted because they have not + been used for a long time, and are not used as billing addresses of valid + credit cards. Note the deletion only happens once per major version upgrade. + </summary> +</histogram> + +<histogram name="Autofill.AddressesSuppressedForDisuse" units="addresses"> <owner>rogerm@chromium.org</owner> <summary> The number of address suggestions not shown in the Autofill popup because @@ -4552,6 +5473,14 @@ </summary> </histogram> +<histogram name="Autofill.CreditCardsDeletedForDisuse"> + <owner>wuandy@chromium.org</owner> + <summary> + The number of credit card deleted during a major version upgrade because + they have not been used recently enough and are expired. + </summary> +</histogram> + <histogram name="Autofill.CreditCardsSuppressedForDisuse"> <owner>wuandy@chromium.org</owner> <summary> @@ -4803,12 +5732,21 @@ <summary>Tracks whether Autofill is enabled when Chrome launches.</summary> </histogram> -<histogram name="Autofill.KeyboardAccessoryButtonsIOS" +<histogram name="Autofill.KeyboardAccessoryButtonsIOS_ScreenReaderOff" enum="AutofillKeyboardAccessoryButtonsIOS"> - <owner>bondd@chromium.org</owner> + <owner>mahmadi@chromium.org</owner> <summary> [iOS] Measures the frequency of button presses on the iOS Autofill keyboard - accessory. + accessory view when VoiceOver is off. + </summary> +</histogram> + +<histogram name="Autofill.KeyboardAccessoryButtonsIOS_ScreenReaderOn" + enum="AutofillKeyboardAccessoryButtonsIOS"> + <owner>mahmadi@chromium.org</owner> + <summary> + [iOS] Measures the frequency of button presses on the iOS Autofill keyboard + accessory view when VoiceOver is on. </summary> </histogram> @@ -5081,6 +6019,15 @@ </summary> </histogram> +<histogram name="Autofill.RationalizationQuality.PhoneNumber" + enum="AutofillRationalizationQualityMetric"> + <owner>wuandy@chromium.org</owner> + <summary> + The quality of fields rationalization, putting rationalization result into + good/ok/bad categories. + </summary> +</histogram> + <histogram name="Autofill.SaveCreditCardPrompt" enum="AutofillSaveCreditCardPrompt"> <owner>jdonnelly@chromium.org</owner> @@ -5854,13 +6801,17 @@ <summary>Time spent on 2D canvas putImageData API call.</summary> </histogram> -<histogram name="Blink.Canvas.ToBlob.IdleEncodeDuration" units="microseconds"> +<histogram name="Blink.Canvas.ToBlob.CompleteEncodingDelay" + units="microseconds"> <owner>junov@chromium.org</owner> <owner>xlai@chromium.org</owner> <summary> - This metric measures the total time spent on encoding all the rows of an - image (jpeg or png), as part of a canvas.toBlob API call. Encoding occurs - during one or more idle periods on the main thread. + This metric measures the total time spent on completing encoding all the + rows of an image (jpeg or png), as part of a canvas.toBlob API call. + Encoding occurs during one or more idle periods on the main thread and the + waiting time of the next idle period is included in the measurement. If the + code has swtiched to force encoding path, we will not measure the delay in + this metric. This metric is useful in helping us adjust the IdleTaskCompleteTimeoutDelay in canvas.toBlob. When the encoding idle task is delayed for longer than @@ -5874,6 +6825,20 @@ </summary> </histogram> +<histogram name="Blink.Canvas.ToBlob.IdleEncodeDuration" units="microseconds"> + <obsolete> + Replaced with Blink.Canvas.ToBlob.CompleteEncodingDelay in 2017/12. + </obsolete> + <owner>junov@chromium.org</owner> + <owner>xlai@chromium.org</owner> + <summary> + This metric measures the total time spent on encoding all the rows of an + image (jpeg or png), excluding the waiting time of next idle periods. This + is part of a canvas.toBlob API call. Encoding occurs during one or more idle + periods on the main thread. + </summary> +</histogram> + <histogram name="Blink.Canvas.ToBlob.IdleTaskStatus" enum="IdleTaskStatus"> <owner>junov@chromium.org</owner> <owner>xlai@chromium.org</owner> @@ -5926,6 +6891,20 @@ <summary>Time spent on 2D canvas toDataURL API call.</summary> </histogram> +<histogram name="Blink.CheckerableImageCount" enum="CheckerableImageType"> + <owner>khushalsagar@chromium.org</owner> + <summary> + The number of images which could have been checkered (async decoded) for a + performance gain, split by the DOM element type on which they were used. + This is recorded each time an image for an element created by the page is + loaded, either from the network or the local cache. The browser heuristics + define an image to be checkerable if it is expected to have a long decode + duration. Since these images may be on the rendering critical path, decoding + them asychronously from painting other content can provide better + performance be reducing overall content checkerboarding. + </summary> +</histogram> + <histogram name="Blink.ColorGamut.Destination" enum="Gamut"> <owner>hubbe@chromium.org</owner> <summary>Gamut properties of destination color space.</summary> @@ -6064,10 +7043,16 @@ <histogram name="Blink.Compositing.UpdateTime" units="microseconds"> <owner>paint-dev@chromium.org</owner> <summary> - Time spent updating compositing in the Blink document lifecyce. + Time spent updating compositing in the Blink document lifecycle. </summary> </histogram> +<histogram name="Blink.CookieJar.SyncCookiesSetTime" units="microseconds"> + <owner>kinuko@chromium.org</owner> + <owner>dcheng@chromium.org</owner> + <summary>Microseconds per sync IPC call to set cookies.</summary> +</histogram> + <histogram name="Blink.CookieJar.SyncCookiesTime" units="microseconds"> <owner>kinuko@chromium.org</owner> <owner>dcheng@chromium.org</owner> @@ -6140,6 +7125,9 @@ </histogram> <histogram name="Blink.EventListenerDuration.Resize" units="microseconds"> + <obsolete> + Deprecated 01/2018. + </obsolete> <owner>bokan@chromium.org</owner> <summary> Time it takes to execute all the `resize` event listeners on a page when a @@ -6192,6 +7180,14 @@ </summary> </histogram> +<histogram name="Blink.KeyboardLock.MethodCalled" enum="KeyboardLockMethods"> + <owner>joedow@chromium.org</owner> + <owner>garykac@chromium.org</owner> + <summary> + Records each call to the navigator.keyboard{Lock|Unlock} methods. + </summary> +</histogram> + <histogram name="Blink.MediaDocument.DownloadButton" enum="MediaDocumentDownloadButtonType"> <obsolete> @@ -6266,6 +7262,27 @@ </summary> </histogram> +<histogram base="true" name="Blink.ResourceLoadScheduler.DecodedBytes" + units="bytes"> +<!-- Name completed by histogram_suffixes name="ResourceLoadScheduler.FrameType" --> + + <owner>toyoshim@chromium.org</owner> + <summary>Count received data size in bytes for each resource.</summary> +</histogram> + +<histogram name="Blink.ResourceLoadScheduler.DecodedBytes.KBPerFrameStatus" + enum="RendererSchedulerFrameType2"> + <owner>toyoshim@chromium.org</owner> + <owner>altimin@chromium.org</owner> + <summary> + Total decoded size of resources associated with frames of a particular type. + Recorded when a fetch has been completed. + + Each bucket of the histogram cointains the total size of all requests + associated with frames with a particular frame status in kilobytes. + </summary> +</histogram> + <histogram base="true" name="Blink.ResourceLoadScheduler.PeakRequests" units="requests"> <!-- Name completed by histogram_suffixes name="ResourceLoadScheduler.FrameType" --> @@ -6277,6 +7294,82 @@ </summary> </histogram> +<histogram name="Blink.ResourceLoadScheduler.RequestCount" + enum="ResourceLoadSchedulerCircumstance"> + <owner>toyoshim@chromium.org</owner> + <summary> + Count resource request circumstance, e.g. from the main frame vs sub-frames, + or in throttled state vs in not-throttled state, on each resource load + completion. + </summary> +</histogram> + +<histogram name="Blink.ResourceLoadScheduler.ThrottlingStateChangeCount" + units="changes"> + <owner>toyoshim@chromium.org</owner> + <summary> + Count how many times the scheduler has changed throttling status from the + frame creation until network activity quiets. + </summary> +</histogram> + +<histogram base="true" name="Blink.ResourceLoadScheduler.TotalDecodedBytes" + units="bytes"> +<!-- Name completed by histogram_suffixes name="ResourceLoadScheduler.FrameType" --> + + <owner>toyoshim@chromium.org</owner> + <summary> + Total received data size in bytes to load resources from the frame creation + until network activity quiets. + </summary> +</histogram> + +<histogram base="true" name="Blink.ResourceLoadScheduler.TotalRequestCount" + units="requests"> +<!-- Name completed by histogram_suffixes name="ResourceLoadScheduler.FrameType" --> + + <owner>toyoshim@chromium.org</owner> + <summary> + Total number of resource requests completed from the frame creation until + network activity quiets. + </summary> +</histogram> + +<histogram base="true" name="Blink.ResourceLoadScheduler.TotalTrafficBytes" + units="bytes"> +<!-- Name completed by histogram_suffixes name="ResourceLoadScheduler.FrameType" --> + + <owner>toyoshim@chromium.org</owner> + <summary> + Total traffic data in bytes transferred over networks to load resources from + the frame creation until network activity quiets. + </summary> +</histogram> + +<histogram base="true" name="Blink.ResourceLoadScheduler.TrafficBytes" + units="bytes"> +<!-- Name completed by histogram_suffixes name="ResourceLoadScheduler.FrameType" --> + + <owner>toyoshim@chromium.org</owner> + <summary> + Count traffic data size in bytes transferred over networks to load each + resource. + </summary> +</histogram> + +<histogram name="Blink.ResourceLoadScheduler.TrafficBytes.KBPerFrameStatus" + enum="RendererSchedulerFrameType2"> + <owner>toyoshim@chromium.org</owner> + <owner>altimin@chromium.org</owner> + <summary> + Total encoded size of resources associated with frames of a particular type. + Recorded when a fetch has been completed. + + Each bucket of the histogram cointains the total size of all requests + associated with frames with a particular frame status in kilobytes. + </summary> +</histogram> + <histogram name="Blink.RestoredCachedStyleSheet" enum="RestoredCachedStyleSheet"> <obsolete> @@ -6590,6 +7683,12 @@ </summary> </histogram> +<histogram name="BlinkGC.TimeForCoalesce" units="ms"> + <owner>haraken@chromium.org</owner> + <owner>hpayer@chromium.org</owner> + <summary>Duration of memory coalesce operation in the Blink GC.</summary> +</histogram> + <histogram name="BlinkGC.TimeForGlobalWeakProcessing" units="ms"> <owner>haraken@chromium.org</owner> <summary> @@ -6634,6 +7733,12 @@ <summary>Duration of time taken to run thread-local weak processing.</summary> </histogram> +<histogram name="BlinkGC.TimeForTotalCollectGarbage" units="ms"> + <owner>haraken@chromium.org</owner> + <owner>hpayer@chromium.org</owner> + <summary>Duration of total Blink garbage collection time.</summary> +</histogram> + <histogram name="BlinkGC.TotalAllocatedSpace" units="KB"> <owner>haraken@chromium.org</owner> <summary> @@ -7234,6 +8339,25 @@ </summary> </histogram> +<histogram name="BlueZ.AdapterLost" units="seconds"> + <owner>mcchou@chromium.org</owner> + <summary> + This is specific to Chrome OS. Records a duration of a Bluetooth adapter + being lost. This helps us better understand the Bluetooth controller drop + issue in the field. + </summary> +</histogram> + +<histogram name="BlueZ.NumberOfExistingAdvertisements" units="advertisements"> + <owner>mcchou@chromium.org</owner> + <summary> + This is specific to Chrome OS. Records the number of existing advertisements + when registering for a new advertisement. This helps us better understand + the common amount of advertisments used and the registration failures due to + the limited number of advertisement slots. + </summary> +</histogram> + <histogram name="BlueZ.ReasonOfDisconnection" enum="BlueZReasonOfDisconnection"> <owner>mcchou@chromium.org</owner> <summary> @@ -7356,6 +8480,15 @@ </summary> </histogram> +<histogram name="BookmarkManager.CommandMenuOpened" + enum="BookmarkManagerMenuSource"> + <owner>calamity@chromium.org</owner> + <summary> + Logs where the menu was opened from when a user action opens the command + menu in the bookmark manager. + </summary> +</histogram> + <histogram name="BookmarkManager.NumDragged" units="bookmarks"> <owner>calamity@chromium.org</owner> <summary> @@ -7424,6 +8557,14 @@ </summary> </histogram> +<histogram name="Bookmarks.OpenBookmarkType" enum="BookmarkType"> + <owner>wychen@chromium.org</owner> + <summary> + Logs whether the bookmark entry is a user bookmark or a partner bookmark + when it is opened. + </summary> +</histogram> + <histogram name="BootTime.Total" units="ms"> <obsolete> Replaced 08/2016 by BootTime.Total2 with larger range and more buckets. @@ -7464,6 +8605,22 @@ <summary>Maximal amount of memory allocated by decoder.</summary> </histogram> +<histogram name="BrowserActions.NumTabCreatedInBackground" units="tabNum"> + <owner>ltian@chromium.org</owner> + <summary> + The number of tabs currently opened when users tap "Open in new Chrome + tab" from Browser Actions context menu. This includes the new tab + created from the tap. + </summary> +</histogram> + +<histogram name="BrowserActions.SelectedOption" enum="BrowserActionsMenuOption"> + <owner>ltian@chromium.org</owner> + <summary> + The option that the user selected from a Browser Actions context menu. + </summary> +</histogram> + <histogram name="BrowserDialogs.ExternalProtocol.HandleState" enum="HandleStateType"> <owner>ramyasharma@chromium.org</owner> @@ -7540,6 +8697,13 @@ </summary> </histogram> +<histogram name="BrowserRenderProcessHost.OnChannelError" enum="BooleanHit"> + <owner>wfh@chromium.org</owner> + <summary> + Number of times BrowserRenderProcessHost::OnChannelError was called. + </summary> +</histogram> + <histogram name="Bubbles.Close.Accepted" enum="BubbleType"> <owner>hcarmona@chromium.org</owner> <summary>An open bubble was closed because the user accepted it.</summary> @@ -7630,6 +8794,9 @@ <histogram name="Canvas.DisplayListFallbackReason" enum="CanvasDisplayListFallbackReason"> + <obsolete> + Deprecated 11/2017 with removal of Display List Canvas 2D mode. + </obsolete> <owner>junov@chromium.org</owner> <summary> The reasons why a canvas initially set to display list mode had to fall back @@ -7680,6 +8847,17 @@ </summary> </histogram> +<histogram name="CaptivePortal.DetectionResultSincePortal" + enum="BooleanPresent"> + <owner>warx@chromium.org</owner> + <summary> + Within one minute of the default network reporting a portal network, if we + see an offline detection result, it is likely the client got blacklisted. + Record the boolean rate that Chrome observes offline vs non-offline + detection results. See go/bad-portal for client blacklisting problem. + </summary> +</histogram> + <histogram name="CaptivePortal.DetectResult" enum="CaptivePortalDetectResult"> <owner>meacer@chromium.org</owner> <summary>Records the result of a captive portal probe.</summary> @@ -7784,6 +8962,26 @@ </summary> </histogram> +<histogram name="CaptivePortal.Session.SecureConnectionFailed" + enum="CaptivePortalStatus"> + <owner>michaeldo@chromium.org</owner> + <summary> + The result of captive portal detection attempts performed in user session. + Detection result is recorded when portal detection is completed for a failed + secure connection. + </summary> +</histogram> + +<histogram name="CaptivePortal.Session.TimeoutDetectionResult" + enum="CaptivePortalStatus"> + <owner>michaeldo@chromium.org</owner> + <summary> + The result of captive portal detection attempts performed in user session. + Detection result is recorded when portal detection is completed for a + request which timed out or hadn't yet replied within eight seconds. + </summary> +</histogram> + <histogram name="Cast.Channel.Certificate" enum="CastCertificateStatus"> <owner>ryanchung@google.com</owner> <summary> @@ -8375,6 +9573,20 @@ </summary> </histogram> +<histogram name="Chrome.ProcessSingleton.ProcessTerminateErrorCode.Windows" + enum="WinGetLastError"> + <obsolete> + Deprecated as of 12/2017. + </obsolete> + <owner>aseren@yandex-team.ru</owner> + <owner>gab@chromium.org</owner> + <summary> + The error code of remote process termination on Windows in case when remote + process hung. This histogram has been replaced by + Chrome.ProcessSingleton.TerminateProcessErrorCode.Windows histogram. + </summary> +</histogram> + <histogram name="Chrome.ProcessSingleton.RemoteHungProcessTerminateReason" enum="RemoteHungProcessTerminateReason"> <owner>aseren@yandex-team.ru</owner> @@ -8393,7 +9605,7 @@ </histogram> <histogram name="Chrome.ProcessSingleton.TerminateProcessErrorCode.Posix" - enum="OSAgnosticErrno"> + enum="PopularOSErrno"> <owner>aseren@yandex-team.ru</owner> <owner>gab@chromium.org</owner> <summary> @@ -8565,18 +9777,18 @@ units="ms"> <owner>lizeb@chromium.org</owner> <summary> - In "Herb" mode shows the time between the intent arrival in a - Chrome generated custom tab and the first navigation start. Recorded when - the page has finished loading. + For Custom Tabs generated by Chrome itself instead of external apps, this + shows the time between the intent arrival in the CCT and the first + navigation start. Recorded when the page has finished loading. </summary> </histogram> <histogram name="ChromeGeneratedCustomTab.IntentToPageLoadedTime" units="ms"> <owner>lizeb@chromium.org</owner> <summary> - In "Herb" mode shows time between the intent arrival in a Chrome - generated custom tab and the first "page loaded" event, if the - navigation is successful. + For Custom Tabs generated by Chrome itself instead of external apps, this + shows time between the intent arrival in the CCT and the first "page + loaded" event, if the navigation is successful. </summary> </histogram> @@ -8593,6 +9805,33 @@ </summary> </histogram> +<histogram name="ChromeOS.DetachableBase.PairResult" + enum="DetachableBasePairResult"> + <obsolete> + Deprecated 10/2017 and replaced by Platform.DetachableBase.PairResult. + </obsolete> + <owner>kitching@google.com</owner> + <summary>Result of a Chrome OS detachable base pair operation.</summary> +</histogram> + +<histogram name="ChromeOS.DetachableBase.ROUpdateMetric" + enum="DetachableBaseROUpdateResult"> + <obsolete> + Deprecated 10/2017 and replaced by Platform.DetachableBase.ROUpdateMetric. + </obsolete> + <owner>kitching@google.com</owner> + <summary>Result of a Chrome OS detachable base RO firmware update.</summary> +</histogram> + +<histogram name="ChromeOS.DetachableBase.RWUpdateMetric" + enum="DetachableBaseRWUpdateResult"> + <obsolete> + Deprecated 10/2017 and replaced by Platform.DetachableBase.RWUpdateMetric. + </obsolete> + <owner>kitching@google.com</owner> + <summary>Result of a Chrome OS detachable base RW firmware update.</summary> +</histogram> + <histogram name="ChromeOS.Display.ColorProfile" enum="ChromeOSColorProfile"> <obsolete> Deprecated 8/2017. @@ -8605,6 +9844,18 @@ </summary> </histogram> +<histogram name="ChromeOS.GAIA.AuthenticatorContentWindowNull" enum="Boolean"> + <owner>wjmaclean@chromium.org</owner> + <summary> + Whether the GAIA Authenticator unexpectedly encountered a null contentWindow + value while handling WebView's onContentLoad event. This metric is only + enabled for AuthMode = DEFAULT, which indicates ChromeOS online login. This + is the only mode where the issue has been observed. Other modes not captured + here are OFFLINE (offline ChromeOS login) and DESKTOP (for online GAIA login + on desktop Chrome). + </summary> +</histogram> + <histogram name="ChromeOS.GAIA.WebViewFlow" enum="BooleanGAIAWebViewFlow"> <owner>achuith@chromium.org</owner> <summary> @@ -8755,7 +10006,7 @@ </histogram> <histogram name="Chromoting.Connections" enum="State"> - <owner>anandc@chromium.com</owner> + <owner>anandc@chromium.org</owner> <owner>sergeyu@chromium.org</owner> <summary> Recorded every time a Chromoting connection enters a new state. @@ -9252,6 +10503,23 @@ </summary> </histogram> +<histogram name="Compositing.Browser.CachedImagesCount" units="count"> + <owner>vmpstr@chromium.org</owner> + <summary> + The maximum number of images that were cached in the browser over the + lifetime of the image decode cache. This is recorded at the image cache + destruction. It is further split up by Software and Gpu rasterization. + </summary> +</histogram> + +<histogram name="Compositing.Browser.CompositorFrame.Quads" units="quads"> + <owner>ccameron@chromium.org</owner> + <summary> + The total number of quads in all render passes in a CompositorFrame. This is + logged as the CompositorFrame is submitted to its surface. + </summary> +</histogram> + <histogram name="Compositing.Browser.DisplayListRecordingSource.UpdateInvalidatedAreaPerMs" units="pixels/ms"> @@ -9290,13 +10558,24 @@ Tilings are used for decomposition of the layer's entire contents at a picture screenspace resolution to do threaded rasterization. - Team: threaded-rendering-dev@chromium.org. + Team: animations-dev@chromium.org. + </summary> +</histogram> + +<histogram name="Compositing.Browser.HitTestTimeToFindClosestLayer" + units="microseconds"> + <owner>yigu@chromium.org</owner> + <summary> + Time spent finding the closest matching layer to a given point whenever we + do hit testing on LayerTreeImpl (in a browser process). + + Team: animations-dev@chromium.org. </summary> </histogram> <histogram base="true" name="Compositing.Browser.LayersUpdateTime" units="microseconds"> - <owner>threaded-rendering-dev@chromium.org</owner> + <owner>animations-dev@chromium.org</owner> <summary> Time spent updating layers, in microseconds. Recorded when layers are updated (in a browser process). @@ -9457,6 +10736,42 @@ </summary> </histogram> +<histogram name="Compositing.Display.Draw.Occlusion.Calculation.Time" + units="microseconds"> + <owner>yiyix@chromium.org</owner> + <summary> + Time spent to remove invisible quads from the quad_list in CompositorFrame. + </summary> +</histogram> + +<histogram name="Compositing.Display.Draw.Occlusion.Drawing.Area.Saved" + units="px"> + <owner>yiyix@chromium.org</owner> + <summary> + It records the total drawing area skipped to show on screen as a result of + applying draw occlusion. This is logged once per frame, when the frame is + drawn. + </summary> +</histogram> + +<histogram name="Compositing.Display.Draw.Occlusion.Percentage.Saved" units="%"> + <owner>yiyix@chromium.org</owner> + <summary> + It records the percentage of total area drawing skipped by draw occlusion of + the total area of damage rects in a compositor frame. This is logged once + per frame, when the frame is drawn. + </summary> +</histogram> + +<histogram name="Compositing.Display.Draw.Quads" units="quads"> + <owner>ccameron@chromium.org</owner> + <summary> + This is logged once per frame, when the frame is drawn. The total number of + quads in all render passes in the CompositorFrame that is produced by + surface aggregation. + </summary> +</histogram> + <histogram name="Compositing.DisplayListRecordingSource.UpdateInvalidatedAreaPerMs" units="pixels/ms"> @@ -9497,6 +10812,15 @@ </summary> </histogram> +<histogram name="Compositing.MainFrameSynchronization.Duration" units="ms"> + <owner>fsamuel@chromium.org</owner> + <summary> + The amount of time it took for a main frame with unresolved dependencies to + activate. Note that some activations may be triggered due to a deadline + hitting. + </summary> +</histogram> + <histogram name="Compositing.NumActiveLayers"> <obsolete> Deprecated 04/2016, replaced by similar metrics under Compositing.Renderer @@ -9570,6 +10894,15 @@ </summary> </histogram> +<histogram name="Compositing.Renderer.CachedImagesCount" units="count"> + <owner>vmpstr@chromium.org</owner> + <summary> + The maximum number of images that were cached in the renderer over the + lifetime of the image decode cache. This is recorded at the image cache + destruction. It is further split up by Software and Gpu rasterization. + </summary> +</histogram> + <histogram name="Compositing.Renderer.CALayerResult" enum="CALayerResult"> <owner>ccameron@chromium.org</owner> <summary> @@ -9592,6 +10925,14 @@ </summary> </histogram> +<histogram name="Compositing.Renderer.CompositorFrame.Quads" units="quads"> + <owner>ccameron@chromium.org</owner> + <summary> + The total number of quads in all render passes in a CompositorFrame. This is + logged as the CompositorFrame is submitted to its surface. + </summary> +</histogram> + <histogram name="Compositing.Renderer.DisplayListRecordingSource.UpdateInvalidatedAreaPerMs" units="pixels/ms"> @@ -9630,13 +10971,24 @@ Tilings are used for decomposition of the layer's entire contents at a picture screenspace resolution to do threaded rasterization. - Team: threaded-rendering-dev@chromium.org. + Team: animations-dev@chromium.org. + </summary> +</histogram> + +<histogram name="Compositing.Renderer.HitTestTimeToFindClosestLayer" + units="microseconds"> + <owner>yigu@chromium.org</owner> + <summary> + Time spent finding the closest matching layer to a given point whenever we + do hit testing on LayerTreeImpl (in a renderer process). + + Team: animations-dev@chromium.org. </summary> </histogram> <histogram base="true" name="Compositing.Renderer.LayersUpdateTime" units="microseconds"> - <owner>threaded-rendering-dev@chromium.org</owner> + <owner>animations-dev@chromium.org</owner> <summary> Time spent updating layers, in microseconds. Recorded when layers are updated (in a renderer process). @@ -9830,6 +11182,16 @@ </summary> </histogram> +<histogram + name="Compositing.SurfaceAggregator.SurfaceDrawQuad.UsingFallbackSurface"> + <owner>fsamuel@chromium.org</owner> + <summary> + The number of SurfaceDrawQuads where the primary SurfaceId doe not have a + corresponding active CompositorFrame and so the fallback surface is used + instead. This is logged for each call to Aggregate(). + </summary> +</histogram> + <histogram name="Compositing.SurfaceAggregator.SurfaceDrawQuad.ValidSurface"> <owner>kylechar@chromium.org</owner> <summary> @@ -9838,7 +11200,28 @@ </summary> </histogram> +<histogram name="Compositing.SurfaceDependencyDeadline.DeadlineHit" + units="Boolean"> + <owner>fsamuel@chromium.org</owner> + <summary> + Tracks whether an activation of a surface was due to due to a deadline or + the resolution of dependencies. + </summary> +</histogram> + +<histogram name="Compositing.SurfaceDependencyDeadline.Duration" units="ms"> + <owner>fsamuel@chromium.org</owner> + <summary> + The amount of time it took for a Surface with unresolved dependencies to + activate. Note that some activations may be triggered due to a deadline + hitting. That is tracked in the DeadlineHit histogram. + </summary> +</histogram> + <histogram name="Compositing.SurfaceManager.NumOldTemporaryReferences"> + <obsolete> + Deprecated 2018/01/24. + </obsolete> <owner>kylechar@chromium.org</owner> <summary> The number of temporary references that have existed for at least 10 seconds @@ -9846,6 +11229,12 @@ </summary> </histogram> +<histogram name="Compositing.SurfaceManager.RemovedTemporaryReference" + enum="TemporaryReferenceRemovedReason"> + <owner>kylechar@chromium.org</owner> + <summary>Tracks the reason for removing a temporary reference.</summary> +</histogram> + <histogram name="Conflicts.ConfirmedBadModules" units="modules"> <owner>chrisha@chromium.org</owner> <summary> @@ -10061,6 +11450,12 @@ </summary> </histogram> +<histogram name="ContentSettings.DefaultSoundSetting" enum="ContentSetting"> + <owner>mlamouri@chromium.org</owner> + <owner>steimel@chromium.org</owner> + <summary>The default sound setting at profile open.</summary> +</histogram> + <histogram name="ContentSettings.DefaultSubresourceFilterSetting" enum="ContentSetting"> <owner>csharrison@chromium.org</owner> @@ -10126,6 +11521,13 @@ </summary> </histogram> +<histogram name="ContentSettings.ImagePressed" enum="ContentSettingImageType"> + <owner>calamity@chromium.org</owner> + <summary> + Counts which content setting buttons are pressed by the user. + </summary> +</histogram> + <histogram name="ContentSettings.LastSettingParsed" enum="LastSettingParsed"> <obsolete> Deprecated 2015-10-05 in Issue 433475. Histogram was used temorarily for @@ -10140,7 +11542,7 @@ <histogram name="ContentSettings.MixedScript" enum="ContentSettingMixedScriptAction"> - <owner>lgarron@chromium.org</owner> + <owner>estark@chromium.org</owner> <summary> Tracks whether the mixed content shield was shown, and how the user interacted with it. @@ -10310,7 +11712,7 @@ </histogram> <histogram name="ContentSettings.Popups.ClickThroughPosition" - enum="PopupPosition"> + enum="ListItemPosition"> <owner>csharrison@chromium.org</owner> <summary> The blocked popup list contains a list of links that Chrome has blocked via @@ -10323,6 +11725,9 @@ </histogram> <histogram name="ContentSettings.Popups.FirstDocumentEngagementTime" units="ms"> + <obsolete> + Deprecated in favor of ContentSettings.Popups.FirstDocumentEngagementTime2. + </obsolete> <owner>csharrison@chromium.org</owner> <summary> Measures the total duration a popup WebContents is visible / foregrounded @@ -10332,6 +11737,76 @@ </summary> </histogram> +<histogram name="ContentSettings.Popups.FirstDocumentEngagementTime2" + units="ms"> + <owner>csharrison@chromium.org</owner> + <summary> + Measures the total duration a popup WebContents is visible / foregrounded + for the duration of its first document load. This time is measured from the + first navigation commit to the time either the WebContents is destroyed or + when a new navigation commits. + </summary> +</histogram> + +<histogram name="ContentSettings.Popups.StrongBlocker.NumBlocked" + units="popups"> + <owner>csharrison@chromium.org</owner> + <summary> + The total number of popups blocked by the strong blocker for a given page + load. Logged when the page is navigated away from, or the tab is closed. + Only logged for pages which are triggered for strong popup blocking, aka + abusive experience enforcement. + </summary> +</histogram> + +<histogram name="ContentSettings.Popups.StrongBlockerActions" + enum="StrongPopupBlockerAction"> + <owner>csharrison@chromium.org</owner> + <summary> + Counts of various events related to the strong popup blocker (aka abusive + experience enforcement), that is triggered via safe browsing. + </summary> +</histogram> + +<histogram name="ContentSuggestions.FetchPendingPlaceholder.VisibleDuration" + units="ms"> + <obsolete> + Deprecated in favor of + ContentSuggestions.FetchPendingSpinner.VisibleDuration. + </obsolete> + <owner>dgn@chromium.org</owner> + <owner>ntp-dev+metrics@chromium.org</owner> + <summary> + Android: How long the content suggestion placeholder is shown. This is + tracked based on when the placeholder is enabled in the UI, not how long it + is actually visible on screen. Depending on the screen size, the used value + could be bigger. + </summary> +</histogram> + +<histogram name="ContentSuggestions.FetchPendingSpinner.VisibleDuration" + units="ms"> + <owner>dgn@chromium.org</owner> + <owner>ntp-dev+metrics@chromium.org</owner> + <summary> + Android: How long the content suggestion loading spinner is shown. This is + tracked based on when the spinner is enabled in the UI, not how long it is + actually visible on screen. Depending on the screen size, the used value + could be bigger. + </summary> +</histogram> + +<histogram name="ContextMenu.DOMElementFetchDuration" units="ms"> + <owner>michaeldo@chromium.org</owner> + <summary> + How long it takes to fetch the details of the DOM element the user is + selecting for the context menu. On iOS, JavaScript must be run in order to + get the details of the DOM element. If the element is not inside the main + frame, latency could be added due to the communication between frames. Only + logged on iOS. + </summary> +</histogram> + <histogram name="ContextMenu.SaveLinkType" enum="ContextMenuSaveLinkType"> <owner>qinmin@chromium.org</owner> <summary> @@ -10540,6 +12015,13 @@ <summary>Number of minutes until cookie expires when set.</summary> </histogram> +<histogram name="Cookie.HeaderLength" units="bytes"> + <owner>mkwst@chromium.org</owner> + <summary> + The size of each outgoing request's 'Cookie' header field's value, in bytes. + </summary> +</histogram> + <histogram name="Cookie.KillDatabaseResult" enum="BooleanSuccess"> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <summary> @@ -10701,7 +12183,6 @@ <obsolete> Deprecated as of 04/2015. The migration has finished for most users. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary>The amount of time (ms) to migrate a v4 database to v5.</summary> </histogram> @@ -10709,7 +12190,6 @@ <obsolete> Deprecated as of 04/2015. The migration has finished for most users. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary>The amount of time (ms) to migrate a v5 database to v6.</summary> </histogram> @@ -10717,7 +12197,6 @@ <obsolete> Deprecated as of 04/2015. The migration has finished for most users. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary>The amount of time (ms) to migrate a v6 database to v7.</summary> </histogram> @@ -10725,7 +12204,6 @@ <obsolete> Deprecated as of 04/2015. The migration has finished for most users. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary>The amount of time (ms) to migrate a v7 database to v8.</summary> </histogram> @@ -10852,12 +12330,18 @@ <histogram name="CrashExitCodes.Extension" enum="CrashExitCodes"> <owner>wfh@chromium.org</owner> - <summary>The exit codes for crashed extension processes.</summary> + <summary> + The exit codes for crashed extension processes. Note: Due to + https://crbug.com/805754, the enum labels are off by 1 for M56 and earlier. + </summary> </histogram> <histogram name="CrashExitCodes.Renderer" enum="CrashExitCodes"> <owner>wfh@chromium.org</owner> - <summary>The exit codes for crashed renderer processes.</summary> + <summary> + The exit codes for crashed renderer processes. Note: Due to + https://crbug.com/805754, the enum labels are off by 1 for M56 and earlier. + </summary> </histogram> <histogram name="Crashpad.CrashReportPending" enum="CrashpadReportPending"> @@ -11355,6 +12839,18 @@ </summary> </histogram> +<histogram base="true" name="CustomTab.SessionDuration" units="ms"> + <owner>ranj@chromium.org</owner> + <owner>yfriedman@chromium.org</owner> +<!-- Name completed by histogram_suffixes name="CustomTabOpenSource" --> + + <summary> + Records the time duration in CustomTab Activity from onStart/onResume to + onStop/onPause, if that activity is opened by Webapp/WebApk/Trusted Web + Activity. + </summary> +</histogram> + <histogram name="CustomTabs.ClientAppId" enum="ClientAppId"> <owner>yusufo@chromium.org</owner> <summary> @@ -11829,6 +13325,17 @@ </summary> </histogram> +<histogram name="DataReductionProxy.ConfigService.PersistedConfigIsExpired" + enum="BooleanExpired"> + <owner>tbansal@chromium.org</owner> + <owner>bengr@chromium.org</owner> + <summary> + Records whether the persisted client config for data saver proxies read from + the disk at the time of Chrome startup was expired or not. Recorded once at + the time of Chrome startup. + </summary> +</histogram> + <histogram name="DataReductionProxy.DaysSinceEnabled" units="days"> <owner>tbansal@chromium.org</owner> <owner>bengr@chromium.org</owner> @@ -11967,6 +13474,15 @@ </summary> </histogram> +<histogram name="DataReductionProxy.InvalidResponseHeadersReceived.NetError" + enum="NetErrorCodes"> + <owner>tbansal@chromium.org</owner> + <summary> + Net error codes observed when invalid response headers were received from + data reduction proxy. + </summary> +</histogram> + <histogram name="DataReductionProxy.LevelDBOpenStatus" enum="DataReductionProxyStoreStatus"> <owner>kundaji@chromium.org</owner> @@ -11996,6 +13512,9 @@ <histogram name="DataReductionProxy.LoFi.ImplicitOptOutAction" enum="DataReductionProxyLoFiImplicitOptOutAction"> + <obsolete> + Obsolete as of October 2017. + </obsolete> <owner>bengr@chromium.org</owner> <owner>megjablon@chromium.org</owner> <summary> @@ -12010,6 +13529,9 @@ <histogram name="DataReductionProxy.LoFi.SessionState" enum="DataReductionProxyLoFiSessionState"> + <obsolete> + Deprecated as of October 2017 per transition to blacklist. + </obsolete> <owner>bengr@chromium.org</owner> <owner>megjablon@chromium.org</owner> <summary> @@ -12081,8 +13603,16 @@ </summary> </histogram> +<histogram name="DataReductionProxy.NetworkProperties.CacheHit" + units="BooleanCacheHit"> + <owner>tbansal@chromium.org</owner> + <summary> + Records if the network properties of a network were found in the cache or + not. Recorded every time there is a change in the connection type. + </summary> +</histogram> + <histogram name="DataReductionProxy.Pingback.Attempted" enum="BooleanAttempted"> - <owner>bengr@chromium.org</owner> <owner>ryansturm@chromium.org</owner> <summary> Counts the number of times that pageload metrics were queued to be attempted @@ -12090,8 +13620,17 @@ </summary> </histogram> +<histogram name="DataReductionProxy.Pingback.CrashAction" + enum="DataReductionProxyPingbackCrashAction"> + <owner>ryansturm@chromium.org</owner> + <summary> + Counts various actions related to crash detection in the pingback client. + This is recorded only when a renderer crash occurs on a Data Reduction Proxy + page load. + </summary> +</histogram> + <histogram name="DataReductionProxy.Pingback.Succeeded" enum="BooleanSuccess"> - <owner>bengr@chromium.org</owner> <owner>ryansturm@chromium.org</owner> <summary> Counts the number of times that a batched pingback request succeeded or @@ -12192,6 +13731,9 @@ <histogram name="DataReductionProxy.Quic.OnAlternativeProxyBroken" units="count"> + <obsolete> + As of M66 this has been superceded by Net.AlternativeProxyFailed. + </obsolete> <owner>tbansal@chromium.org</owner> <summary> Number of times an alternative QUIC proxy was marked as broken. @@ -12422,6 +13964,12 @@ </summary> </histogram> +<histogram name="DataReductionProxy.WarmupURL.FetchAttemptEvent" + enum="DataReductionProxyWarmupURLFetchAttemptEvent"> + <owner>tbansal@chromium.org</owner> + <summary>Records the result of an attempt to fetch the warmup URL.</summary> +</histogram> + <histogram name="DataReductionProxy.WarmupURL.FetchInitiated" units="count"> <owner>tbansal@chromium.org</owner> <summary> @@ -12435,6 +13983,50 @@ <summary>Whether the warm up URL was fetched succesfully.</summary> </histogram> +<histogram name="DataReductionProxy.WarmupURL.HasViaHeader" enum="Boolean"> + <owner>tbansal@chromium.org</owner> + <summary> + Whether the response headers of the warm up URL had Chrome Proxy via header. + Recorded only when non-null response headers were available when the fetch + of warm up URL concludes. + </summary> +</histogram> + +<histogram name="DataReductionProxy.WarmupURL.HttpResponseCode" + enum="HttpResponseCode"> + <owner>tbansal@chromium.org</owner> + <summary> + HTTP response code of the warm up URL. Set to 1 when HTTP response headers + were unavailable. + </summary> +</histogram> + +<histogram name="DataReductionProxy.WarmupURL.NetError" enum="NetErrorCodes"> + <owner>tbansal@chromium.org</owner> + <summary> + Net error codes observed when the fetch of the warm up URL concludes. + </summary> +</histogram> + +<histogram name="DataReductionProxy.WarmupURL.ProxySchemeUsed" + enum="DataReductionProxyProxySchemeUsed"> + <owner>tbansal@chromium.org</owner> + <summary> + Proxy scheme of the proxy server via which the warm up URL was fetched. + Recorded only when non-null response headers were available when the fetch + of warm up URL concludes. + </summary> +</histogram> + +<histogram name="DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch" + enum="BooleanSuccess"> + <owner>tbansal@chromium.org</owner> + <summary> + Whether the warmup (or probe) URL was successfully fetched over a data saver + proxy. + </summary> +</histogram> + <histogram name="DataUsage.MatchingRulesCount.Invalid" units="count"> <owner>bengr@chromium.org</owner> <owner>rajendrant@chromium.org</owner> @@ -12630,6 +14222,19 @@ </histogram> <histogram name="DataUse.AllServices.Background" enum="DataUseServices"> + <obsolete> + Replaced by KB version in October, 2017. + </obsolete> + <owner>rajendrant@chromium.org</owner> + <owner>bengr@chromium.org</owner> + <summary> + The total background data use of Chrome's services broken down by service + name. It is logged only in Android when the URLRequest of a service + completes. + </summary> +</histogram> + +<histogram name="DataUse.AllServices.BackgroundKB" enum="DataUseServices"> <owner>rajendrant@chromium.org</owner> <owner>bengr@chromium.org</owner> <summary> @@ -12766,6 +14371,9 @@ </histogram> <histogram name="DataUse.Sync.Download.Bytes" enum="SyncModelTypes"> + <obsolete> + Deprecated 10/2017. + </obsolete> <owner>amohammadkhan@chromium.org</owner> <owner>bengr@chromium.org</owner> <summary> @@ -12776,6 +14384,9 @@ </histogram> <histogram name="DataUse.Sync.Download.Count" enum="SyncModelTypes"> + <obsolete> + Deprecated 10/2017. + </obsolete> <owner>amohammadkhan@chromium.org</owner> <owner>bengr@chromium.org</owner> <summary> @@ -12786,6 +14397,9 @@ </histogram> <histogram name="DataUse.Sync.ProgressMarker.Bytes" enum="SyncModelTypes"> + <obsolete> + Deprecated 10/2017. + </obsolete> <owner>amohammadkhan@chromium.org</owner> <owner>bengr@chromium.org</owner> <summary> @@ -12796,6 +14410,9 @@ </histogram> <histogram name="DataUse.Sync.Upload.Bytes" enum="SyncModelTypes"> + <obsolete> + Deprecated 10/2017. + </obsolete> <owner>amohammadkhan@chromium.org</owner> <owner>bengr@chromium.org</owner> <summary> @@ -12805,6 +14422,9 @@ </histogram> <histogram name="DataUse.Sync.Upload.Count" enum="SyncModelTypes"> + <obsolete> + Deprecated 10/2017. + </obsolete> <owner>amohammadkhan@chromium.org</owner> <owner>bengr@chromium.org</owner> <summary> @@ -13910,6 +15530,32 @@ </summary> </histogram> +<histogram name="Discarding.Urgent.NumAliveTabs" units="tabs"> + <owner>fdoray@chromium.org</owner> + <summary> + Number of tabs that are not pending load or discarded when an urgent discard + request is received. + </summary> +</histogram> + +<histogram name="Discarding.Urgent.TimeSinceLastUrgent" units="ms"> + <owner>fdoray@chromium.org</owner> + <summary> + Time between two consecutive urgent discard requests. Urgent discards are + undesirable; it is better to reduce memory usage before the system is in a + bad state. + </summary> +</histogram> + +<histogram name="Discarding.Urgent.TimeSinceStartup" units="ms"> + <owner>fdoray@chromium.org</owner> + <summary> + Time between Chrome startup and the first urgent discard request. Urgent + discards are undesirable; it is better to reduce memory usage before the + system is in a bad state. + </summary> +</histogram> + <histogram name="DiskBasedCertCache.CertIo" enum="CertificateChainPosition"> <obsolete> Deprecated as of 01/2016. CertCacheTrial has been removed. @@ -14025,6 +15671,46 @@ </summary> </histogram> +<histogram name="DisplayManager.MirroringDisplayCountRanges" + enum="MultiDisplayModeDisplayCountRanges"> + <owner>weidongg@chromium.org</owner> + <summary> + The number of displays connected to the device that are in software or + hardware mirror mode. This is emitted once when the normal or mixed mirror + mode is enabled through API call, or the display configuration changes (e.g. + adding or removing a display) when mirror mode is on. + </summary> +</histogram> + +<histogram name="DisplayManager.MirrorModeTypes" enum="DisplayMirrorModeTypes"> + <owner>weidongg@chromium.org</owner> + <summary> + The types of mirror mode in which the displays connected to the device are + in. This is emitted once when the normal or mixed mirror mode is enabled + through API call, or the display configuration changes ( e.g. adding or + removing a display) when mirror mode is on. + </summary> +</histogram> + +<histogram name="DisplayManager.MultiDisplayMode" enum="MultiDisplayModes"> + <owner>afakhry@chromium.org</owner> + <summary> + The mode in which the connected displays to the device are in. This is + emitted once when displays are added or removed, or when the user changes + the mode by e.g. enabling mirror or unified modes. + </summary> +</histogram> + +<histogram name="DisplayManager.UnifiedDesktopDisplayCountRange" + enum="MultiDisplayModeDisplayCountRanges"> + <owner>afakhry@chromium.org</owner> + <summary> + The number of displays connected to the device when Unified Desktop mode is + on. This is emitted when Unified Desktop mode is turned on, or the displays + are added or removed while in Unified Mode. + </summary> +</histogram> + <histogram name="DNS.AttemptCancelled"> <owner>mgersh@chromium.org</owner> <summary> @@ -14096,6 +15782,9 @@ </histogram> <histogram name="DNS.CacheEvicted" units="ms"> + <obsolete> + Deprecated as of 9/2017. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> The time left to expiration of an entry when it is removed while compacting @@ -14104,6 +15793,9 @@ </histogram> <histogram name="DNS.CacheExpired" units="ms"> + <obsolete> + Deprecated as of 9/2017. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> The time since expiration of an entry when it is removed while compacting @@ -14112,6 +15804,9 @@ </histogram> <histogram name="DNS.CacheExpiredOnGet" units="ms"> + <obsolete> + Deprecated as of 9/2017. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> The time since expiration of an entry when it is removed on lookup. @@ -14120,6 +15815,9 @@ <histogram name="DNS.EmptyAddressListAndNoError" enum="DNSEmptyAddressListAndNoError"> + <obsolete> + Deprecated as of 9/2017. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Error status when an empty address list was found in OnLookupComplete(). @@ -14239,6 +15937,9 @@ </histogram> <histogram name="DNS.IndependentFailedNavigation" units="ms"> + <obsolete> + Deprecated as of 9/2017. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> When either a pre-resolution was not done recently enough to provide @@ -14252,6 +15953,9 @@ </histogram> <histogram name="DNS.IndependentNavigation" units="ms"> + <obsolete> + Deprecated as of 9/2017. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> When either a pre-resolution was not done recently enough to provide @@ -14265,6 +15969,9 @@ </histogram> <histogram name="DNS.JobQueueTime" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.JobQueueTime. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Time elapsed between the time the HostResolverImpl::Job was created and the @@ -14274,6 +15981,9 @@ </histogram> <histogram name="DNS.JobQueueTime_HIGHEST" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.JobQueueTime. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Time elapsed between the time the HostResolverImpl::Job was created and the @@ -14283,6 +15993,9 @@ </histogram> <histogram name="DNS.JobQueueTime_IDLE" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.JobQueueTime. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Time elapsed between the time the HostResolverImpl::Job was created and the @@ -14292,6 +16005,9 @@ </histogram> <histogram name="DNS.JobQueueTime_LOW" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.JobQueueTime. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Time elapsed between the time the HostResolverImpl::Job was created and the @@ -14301,6 +16017,9 @@ </histogram> <histogram name="DNS.JobQueueTime_LOWEST" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.JobQueueTime. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Time elapsed between the time the HostResolverImpl::Job was created and the @@ -14310,6 +16029,9 @@ </histogram> <histogram name="DNS.JobQueueTime_MEDIUM" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.JobQueueTime. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Time elapsed between the time the HostResolverImpl::Job was created and the @@ -14319,6 +16041,9 @@ </histogram> <histogram name="DNS.JobQueueTimeAfterChange" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.JobQueueTimeAfterChange. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Time elapsed between the last time the priority of a HostResolverImpl::Job @@ -14328,6 +16053,9 @@ </histogram> <histogram name="DNS.JobQueueTimeAfterChange_HIGHEST" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.JobQueueTimeAfterChange. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Time elapsed between the last time the priority of a HostResolverImpl::Job @@ -14338,6 +16066,9 @@ </histogram> <histogram name="DNS.JobQueueTimeAfterChange_IDLE" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.JobQueueTimeAfterChange. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Time elapsed between the last time the priority of a HostResolverImpl::Job @@ -14348,6 +16079,9 @@ </histogram> <histogram name="DNS.JobQueueTimeAfterChange_LOW" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.JobQueueTimeAfterChange. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Time elapsed between the last time the priority of a HostResolverImpl::Job @@ -14358,6 +16092,9 @@ </histogram> <histogram name="DNS.JobQueueTimeAfterChange_LOWEST" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.JobQueueTimeAfterChange. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Time elapsed between the last time the priority of a HostResolverImpl::Job @@ -14368,6 +16105,9 @@ </histogram> <histogram name="DNS.JobQueueTimeAfterChange_MEDIUM" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.JobQueueTimeAfterChange. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Time elapsed between the last time the priority of a HostResolverImpl::Job @@ -14378,6 +16118,9 @@ </histogram> <histogram name="DNS.PrefetchCacheEviction" units="ms"> + <obsolete> + Deprecated as of 9/2017. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> The duration of time used (most recently) to pre-resolve a hostname, when @@ -14388,6 +16131,9 @@ </histogram> <histogram name="DNS.PrefetchCacheEvictionL" units="ms"> + <obsolete> + Deprecated as of 9/2017. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> The duration of time used (most recently) to pre-resolve a hostname, when @@ -14398,6 +16144,9 @@ </histogram> <histogram name="DNS.PrefetchFoundName"> + <obsolete> + Deprecated as of 9/2017. + </obsolete> <owner>mgersh@chromium.org</owner> <summary>Replaced by DNS.PrefetchFoundNameL.</summary> </histogram> @@ -14420,11 +16169,17 @@ </histogram> <histogram name="DNS.PrefetchNegativeHit"> + <obsolete> + Deprecated as of 9/2017. + </obsolete> <owner>mgersh@chromium.org</owner> <summary>Replaced by DNS.PrefetchNegativeHitL.</summary> </histogram> <histogram name="DNS.PrefetchNegativeHitL" units="ms"> + <obsolete> + Deprecated as of 9/2017. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> The duration of time saved due to DNS pre-resolving in the "name not @@ -14443,11 +16198,17 @@ </histogram> <histogram name="DNS.PrefetchPositiveHit"> + <obsolete> + Deprecated as of 9/2017. + </obsolete> <owner>mgersh@chromium.org</owner> <summary>Replaced by DNS.PrefetchPositiveHitL.</summary> </histogram> <histogram name="DNS.PrefetchPositiveHitL" units="ms"> + <obsolete> + Deprecated as of 9/2017. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> The duration of time saved due to DNS pre-resolving in the "name was @@ -14464,6 +16225,9 @@ </histogram> <histogram name="DNS.PrefetchQueue" units="ms"> + <obsolete> + Deprecated as of 9/2017. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> The duration of time spent by a proposed resolution waiting in the queue to @@ -14473,6 +16237,9 @@ </histogram> <histogram name="DNS.PrefetchReferredPositiveHit" units="ms"> + <obsolete> + Deprecated as of 9/2017. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> The duration of time saved due to DNS pre-resolving in the "name was @@ -14503,6 +16270,9 @@ </histogram> <histogram name="DNS.QueueRecycledDeltaOver2"> + <obsolete> + Deprecated as of 9/2017. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> When, due to congestion avoidance, a queued pre-resolution is abandoned @@ -14513,6 +16283,9 @@ </histogram> <histogram name="DNS.QueueRecycledUnder2"> + <obsolete> + Deprecated as of 9/2017. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> When, due to congestion avoidance, a queued pre-resolution is abandoned @@ -14523,6 +16296,9 @@ </histogram> <histogram name="DNS.ResolveCategory" enum="ResolutionCategory"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.ResolveCategory. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Counts of successes and failures of OS resolutions in various categories. @@ -14530,6 +16306,9 @@ </histogram> <histogram name="DNS.ResolveFail" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.ProcTaskFail. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Duration of time taken in OS resolutions for actual navigations. Note that @@ -14538,21 +16317,33 @@ </histogram> <histogram name="DNS.ResolveFail_FAMILY_IPV4" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.ProcTaskFail. + </obsolete> <owner>mgersh@chromium.org</owner> <summary>Same as DNS.ResolveFail, but limited to pure IPv4 lookups.</summary> </histogram> <histogram name="DNS.ResolveFail_FAMILY_IPV6" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.ProcTaskFail. + </obsolete> <owner>mgersh@chromium.org</owner> <summary>Same as DNS.ResolveFail, but limited to pure IPv6 lookups.</summary> </histogram> <histogram name="DNS.ResolveFail_FAMILY_UNSPEC" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.ProcTaskFail. + </obsolete> <owner>mgersh@chromium.org</owner> <summary>Same as DNS.ResolveFail, but limited to IPv4/IPv6 lookups.</summary> </histogram> <histogram name="DNS.ResolveSpeculativeFail" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.ProcTaskFail. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Duration of time taken in speculative OS resolutions. Note that cached OS @@ -14561,6 +16352,9 @@ </histogram> <histogram name="DNS.ResolveSpeculativeSuccess" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.ProcTaskSuccess. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Duration of time taken in speculative OS resolution that succeeded. Note @@ -14569,6 +16363,9 @@ </histogram> <histogram name="DNS.ResolveSuccess" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.ProcTaskSuccess. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Duration of time taken in OS resolutions that succeeded and were requested @@ -14578,6 +16375,9 @@ </histogram> <histogram name="DNS.ResolveSuccess_FAMILY_IPV4" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.ProcTaskSuccess. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Same as DNS.ResolveSuccess, but limited to pure IPv4 lookups. @@ -14585,6 +16385,9 @@ </histogram> <histogram name="DNS.ResolveSuccess_FAMILY_IPV6" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.ProcTaskSuccess. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Same as DNS.ResolveSuccess, but limited to pure IPv6 lookups. @@ -14592,6 +16395,9 @@ </histogram> <histogram name="DNS.ResolveSuccess_FAMILY_UNSPEC" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.ProcTaskSuccess. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Same as DNS.ResolveSuccess, but limited to IPv4/IPv6 lookups. @@ -14664,6 +16470,9 @@ </histogram> <histogram name="DNS.TotalTime" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.TotalTime. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Duration of time since a HostResolverImpl::Resolve request to the time a @@ -14673,6 +16482,9 @@ </histogram> <histogram name="DNS.TotalTime_speculative" units="ms"> + <obsolete> + Deprecated as of 9/2017. Replaced by Net.DNS.TotalTime_speculative. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> Duration of time since a HostResolverImpl::Resolve request to the time a @@ -14682,6 +16494,9 @@ </histogram> <histogram name="DNS.UnexpectedResolution"> + <obsolete> + Deprecated as of 9/2017. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> In some cases, such as when content arrives with embedded references to @@ -14700,6 +16515,9 @@ </histogram> <histogram name="DNS.UnexpectedResolutionL"> + <obsolete> + Deprecated as of 9/2017. + </obsolete> <owner>mgersh@chromium.org</owner> <summary> In some cases, such as when content arrives with embedded references to @@ -14859,6 +16677,14 @@ <summary>Result of DNS probes sent by the probe service.</summary> </histogram> +<histogram name="Document.BeforeUnloadDialog" enum="BeforeUnloadDialogResult"> + <owner>panicker@chromium.org</owner> + <summary> + Records result of invoking beforeunload handler, that determines whether to + show the dialog. + </summary> +</histogram> + <histogram name="Document.OutliveTimeAfterShutdown.DestroyedBeforeProcessDies"> <owner>hajimehoshi@chromium.org</owner> <owner>keishi@chromium.org</owner> @@ -14888,6 +16714,39 @@ </summary> </histogram> +<histogram name="DocumentEventTiming.BeforeUnloadDuration" units="microseconds"> + <owner>panicker@chromium.org</owner> + <summary>Microseconds spent in beforeunload.</summary> +</histogram> + +<histogram name="DocumentEventTiming.FreezeDuration" units="microseconds"> + <owner>panicker@chromium.org</owner> + <owner>fmeawad@chromium.org</owner> + <summary>Microseconds spent in onfreeze.</summary> +</histogram> + +<histogram name="DocumentEventTiming.PageHideDuration" units="microseconds"> + <owner>panicker@chromium.org</owner> + <summary>Microseconds spent in pagehide.</summary> +</histogram> + +<histogram name="DocumentEventTiming.PageVibilityHiddenDuration" + units="microseconds"> + <owner>panicker@chromium.org</owner> + <summary>Microseconds spent in vibilitychange (hidden).</summary> +</histogram> + +<histogram name="DocumentEventTiming.ResumeDuration" units="microseconds"> + <owner>panicker@chromium.org</owner> + <owner>fmeawad@chromium.org</owner> + <summary>Microseconds spent in onresume.</summary> +</histogram> + +<histogram name="DocumentEventTiming.UnloadDuration" units="microseconds"> + <owner>panicker@chromium.org</owner> + <summary>Microseconds spent in unload.</summary> +</histogram> + <histogram name="DocumentScan.ConverterResult" enum="BooleanSuccess"> <owner>pstew@chromium.org</owner> <summary> @@ -14905,6 +16764,9 @@ </histogram> <histogram name="DomainBoundCerts.DBLoadedCount"> + <obsolete> + Removed January 2018. + </obsolete> <owner>mattm@chromium.org</owner> <summary>Number of certs loaded from domain bound cert database.</summary> </histogram> @@ -14919,6 +16781,9 @@ </histogram> <histogram name="DomainBoundCerts.DBLoadTime" units="ms"> + <obsolete> + Removed January 2018. + </obsolete> <owner>mattm@chromium.org</owner> <summary>Time spent loading domain bound cert database.</summary> </histogram> @@ -14981,6 +16846,9 @@ <histogram name="DomainBoundCerts.GetDomainBoundCertResult" enum="DomainBoundCerts.GetCertResult"> + <obsolete> + Removed January 2018. + </obsolete> <owner>mattm@chromium.org</owner> <summary>Result of GetDomainBoundCert function.</summary> </histogram> @@ -14994,6 +16862,9 @@ </histogram> <histogram name="DomainBoundCerts.Support" enum="DomainBoundCerts.Support"> + <obsolete> + Removed January 2018. + </obsolete> <owner>mattm@chromium.org</owner> <summary> Counts of SSL client sockets broken down by support for Domain Bound @@ -15024,6 +16895,9 @@ </histogram> <histogram name="DomainReliability.BeaconInterval" units="ms"> + <obsolete> + Removed November 2017. + </obsolete> <owner>juliatuttle@chromium.org</owner> <summary> The time between successive Domain Reliability beacons being queued in the @@ -15032,6 +16906,9 @@ </histogram> <histogram name="DomainReliability.BeaconIntervalGlobal" units="ms"> + <obsolete> + Removed November 2017. + </obsolete> <owner>juliatuttle@chromium.org</owner> <summary> The time between successive Domain Reliability beacons being queued across @@ -15040,6 +16917,9 @@ </histogram> <histogram name="DomainReliability.BeaconReported" enum="BooleanReported"> + <obsolete> + Removed November 2017. + </obsolete> <owner>juliatuttle@chromium.org</owner> <summary> Whether a beacon added to a Domain Reliability context was saved to be @@ -15048,6 +16928,9 @@ </histogram> <histogram name="DomainReliability.OnBeaconDidEvict" enum="BooleanDidEvict"> + <obsolete> + Removed November 2017. + </obsolete> <owner>juliatuttle@chromium.org</owner> <summary> Whether adding a beacon to a Domain Reliability context caused it to evict @@ -15056,6 +16939,9 @@ </histogram> <histogram name="DomainReliability.ReportedBeaconError" enum="NetErrorCodes"> + <obsolete> + Removed November 2017. + </obsolete> <owner>juliatuttle@chromium.org</owner> <summary> The Chrome error code included in a beacon saved to be uploaded to the @@ -15065,6 +16951,9 @@ <histogram name="DomainReliability.ReportedBeaconError_HasServerIP" enum="NetErrorCodes"> + <obsolete> + Removed November 2017. + </obsolete> <owner>juliatuttle@chromium.org</owner> <summary> The Chrome error code included in a beacon with a non-empty server_ip field @@ -15073,6 +16962,9 @@ </histogram> <histogram name="DomainReliability.ReportedBeaconUploadDepth" units="levels"> + <obsolete> + Removed November 2017. + </obsolete> <owner>juliatuttle@chromium.org</owner> <summary> The upload depth included in a beacon saved to be uploaded to the collector. @@ -15083,6 +16975,9 @@ <histogram name="DomainReliability.SetConfigRecreatedContext" enum="BooleanCreated"> + <obsolete> + Removed November 2017. + </obsolete> <owner>juliatuttle@chromium.org</owner> <summary> When Domain Reliability receives a valid NEL configuration header for an @@ -15092,6 +16987,9 @@ </histogram> <histogram name="DomainReliability.UploadCollectorIndex"> + <obsolete> + Removed November 2017. + </obsolete> <owner>juliatuttle@chromium.org</owner> <summary> The index of the collector that a Domain Reliability upload was sent to. @@ -15100,6 +16998,9 @@ </histogram> <histogram name="DomainReliability.UploadCollectorRetryDelay" units="ms"> + <obsolete> + Removed November 2017. + </obsolete> <owner>juliatuttle@chromium.org</owner> <summary> After an upload to a collector finishes (successfully or not), the delay @@ -15130,6 +17031,9 @@ </histogram> <histogram name="DomainReliability.UploadInterval" units="ms"> + <obsolete> + Removed November 2017. + </obsolete> <owner>juliatuttle@chromium.org</owner> <summary> The time between successive Domain Reliability uploads being started in the @@ -15139,6 +17043,9 @@ </histogram> <histogram name="DomainReliability.UploadIntervalGlobal" units="ms"> + <obsolete> + Removed November 2017. + </obsolete> <owner>juliatuttle@chromium.org</owner> <summary> The time between successive Domain Reliability uploads being started across @@ -15221,7 +17128,11 @@ <histogram name="DomDistiller.InfoBarUsage" enum="BooleanUsage"> <owner>mdjones@chromium.org</owner> - <summary>Records if the infobar was used or closed.</summary> + <summary> + "Used" is recorded when the user clicks the infobar to enter + Reader Mode. "Not Used" is recorded when the user clicks the close + button. If there's no user action, nothing is recorded. + </summary> </histogram> <histogram name="DomDistiller.LongArticleScoreNMF.Negative" units="score"> @@ -15643,8 +17554,10 @@ <summary>Types of video files that are downloaded.</summary> </histogram> -<histogram name="Download.Counts" enum="DownloadCountType"> - <owner>asanka@chromium.org</owner> +<histogram base="true" name="Download.Counts" enum="DownloadCountType"> +<!-- Name completed by histogram_suffixes name="DownloadSource" --> + + <owner>xingliu@chromium.org</owner> <summary> Various individual counts in the download system; see DownloadCountType for details. @@ -15815,7 +17728,9 @@ </summary> </histogram> -<histogram name="Download.DownloadSize" units="KB"> +<histogram base="true" name="Download.DownloadSize" units="KB"> +<!-- Name completed by histogram_suffixes name="Download.Parallelizable" --> + <owner>asanka@chromium.org</owner> <summary>The size of successfully completed downloads.</summary> </histogram> @@ -15950,8 +17865,10 @@ </summary> </histogram> -<histogram name="Download.InterruptedReason" enum="InterruptReason"> - <owner>asanka@chromium.org</owner> +<histogram base="true" name="Download.InterruptedReason" enum="InterruptReason"> +<!-- Name completed by histogram_suffixes name="DownloadSource" --> + + <owner>xingliu@chromium.org</owner> <summary>The reason that a download was interrupted.</summary> </histogram> @@ -15993,7 +17910,15 @@ </summary> </histogram> -<histogram name="Download.IOSDownloadFileNetError" enum="NetErrorCodes"> +<histogram name="Download.IOSDownloadedFileAction" enum="DownloadedFileAction"> + <owner>bdibello@chromium.org</owner> + <summary> + The action that a user takes on a file after it has been successfully + downloaded on iOS. + </summary> +</histogram> + +<histogram name="Download.IOSDownloadedFileNetError" enum="NetErrorCodes"> <owner>mrefaat@chromium.org</owner> <summary> Positive net error codes that happens in the case of download content fetch @@ -16001,15 +17926,34 @@ </summary> </histogram> +<histogram name="Download.IOSDownloadedFileStatusCode"> + <owner>stkhapugin@chromium.org</owner> + <owner>eugenebut@chromium.org</owner> + <owner>stuartmorgan@chromium.org</owner> + <summary> + HTTP status code returned when file download completes on iOS. + </summary> +</histogram> + +<histogram name="Download.IOSDownloadFileResult" enum="DownloadFileResult"> + <owner>bdibello@chromium.org</owner> + <summary>Result when a user attempts to download a file on iOS.</summary> +</histogram> + <histogram name="Download.IOSDownloadPassKitResult" enum="DownloadPassKitResult"> <owner>gchatz@chromium.org</owner> <summary> - Result when a user attempts to download a PassKit file on iOS with - WKWebView. + Result when a user attempts to download a PassKit file on iOS. </summary> </histogram> +<histogram name="Download.IOSPresentAddPassesDialogResult" + enum="PresentAddPassesDialogResult"> + <owner>eugenebut@chromium.org</owner> + <summary>Result of an attempt to present Add Passes dialog on iOS.</summary> +</histogram> + <histogram name="Download.MaliciousDownloadClassified" enum="DownloadItem.DangerType"> <owner>asanka@chromium.org</owner> @@ -16188,6 +18132,28 @@ </summary> </histogram> +<histogram base="true" name="Download.PathGenerationEvent" + enum="DownloadPathGenerationEvent"> +<!-- Name completed by histogram_suffixes name="DownloadType" --> + + <owner>xingliu@chromium.org</owner> + <summary> + The download path generation behavior which happens before download path + validation in download target determination process. + </summary> +</histogram> + +<histogram base="true" name="Download.PathValidationResult" + enum="DownloadPathValidationResult"> +<!-- Name completed by histogram_suffixes name="DownloadType" --> + + <owner>xingliu@chromium.org</owner> + <summary> + The download path validation result before the final download target is + determined. + </summary> +</histogram> + <histogram name="Download.PotentialBandwidth" units="Bytes/second"> <obsolete> Deprecated January 2017. @@ -16257,6 +18223,31 @@ </summary> </histogram> +<histogram name="Download.Service.Entry.Event" + enum="Download.Service.EntryEvent"> + <owner>dtrainor@chromium.org</owner> + <summary>An action the download service took on an active download.</summary> +</histogram> + +<histogram name="Download.Service.Entry.ResumptionCount" units="attempts"> + <owner>dtrainor@chromium.org</owner> + <summary> + Records how many resumptions have taken place at the time of resumption for + a download in the Download Service. This differs from + Download.Service.Entry.RetryCount, which records restarts. + </summary> +</histogram> + +<histogram name="Download.Service.Entry.RetryCount" units="attempts"> + <owner>dtrainor@chromium.org</owner> + <summary> + Records how many attempts have taken place at the time of a retry for a + download in the Download Service. This differs from + Download.Service.Entry.ResumptionCount, which records resumptions not + complete restarts. + </summary> +</histogram> + <histogram name="Download.Service.Files.Cleanup.Attempts" units="attempts"> <owner>shaktisahu@chromium.org</owner> <summary> @@ -16365,6 +18356,15 @@ <summary>The completion type for downloads in download service.</summary> </histogram> +<histogram name="Download.Service.PauseReason" + enum="Download.Service.PauseReason"> + <owner>shaktisahu@chromium.org</owner> + <summary> + The reason for pausing an in-progress download. Every pause will result in + two entries in the histogram: ANY and a more specific reason. + </summary> +</histogram> + <histogram name="Download.Service.Recovery" enum="Download.Service.EntryStates"> <owner>xingliu@chromium.org</owner> <summary> @@ -16440,6 +18440,14 @@ </summary> </histogram> +<histogram name="Download.Shelf.DragEvent" enum="Download.Shelf.DragEvent"> + <owner>sdy@chromium.org</owner> + <summary> + Events related to dragging a completed download from the shelf, which + represents dragging a reference to the downloaded file. + </summary> +</histogram> + <histogram name="Download.ShelfInProgressSizeOnAutoClose"> <owner>asanka@chromium.org</owner> <summary> @@ -16480,7 +18488,10 @@ </histogram> <histogram name="Download.Sources" enum="DownloadSource"> - <owner>asanka@chromium.org</owner> + <obsolete> + Deprecated 1/2018, integrated into Download.Counts.DOWNLOAD_TRIGGERED_COUNT + </obsolete> + <owner>xingliu@chromium.org</owner> <summary> The initiation source (if initiated within the content layer of chrome) for a download. @@ -16488,7 +18499,7 @@ </histogram> <histogram name="Download.SourcesChrome" enum="ChromeDownloadSource"> - <owner>asanka@chromium.org</owner> + <owner>xingliu@chromium.org</owner> <summary> The initiation source (if initiated within the above-content layer of chrome) for a download. @@ -16565,6 +18576,54 @@ <summary>The write size for calls to BaseFile::AppendDataTofile().</summary> </histogram> +<histogram name="DownloadableStrings.InstallTime" units="ms"> + <obsolete> + Deprecated 2/2018 + </obsolete> + <owner>digit@chromium.org</owner> + <summary> + The time to succesfully download and install the DownloadableStrings + component on Android. + </summary> +</histogram> + +<histogram name="DownloadableStrings.SimCountryCode" + enum="DownloadableStrings.MobileCountryCode"> + <obsolete> + Deprecated 2/2018 + </obsolete> + <owner>digit@chromium.org</owner> + <summary> + The mobile country code (MCC) of the device's SIM card, if available (in the + [200..999] range), or 0 for "undetermined". This is collected on + Chrome startup. For devices with several SIM cards, this only reports the + code of the SIM card in use during startup. + </summary> +</histogram> + +<histogram name="DownloadableStrings.Status" + enum="DownloadableStrings.InstallStatus"> + <obsolete> + Deprecated 2/2018 + </obsolete> + <owner>digit@chromium.org</owner> + <summary> + The status code returned after trying to install and update the + DownloadableStrings component. + </summary> +</histogram> + +<histogram name="DownloadableStrings.Timeout" units="ms"> + <obsolete> + Deprecated 2/2018 + </obsolete> + <owner>digit@chromium.org</owner> + <summary> + The timeout reported by the component updater when trying to install the + DownloadableStrings component fails with a specific error. + </summary> +</histogram> + <histogram name="Drive.BatchUploadResponseCode" enum="HttpResponseCode"> <owner>hirono@chromium.org</owner> <summary>Respose code of batch upload request.</summary> @@ -17546,6 +19605,15 @@ </summary> </histogram> +<histogram name="Enterprise.InvalidDevicePolicyFiles" units="files"> + <owner>igorcov@chromium.org</owner> + <summary> + Chrome OS only. Number of policy files that turned out to be invalid when + reading the device policy data. In success scenario the latest policy file + read is successful and has valid data submitting zero for this statistic. + </summary> +</histogram> + <histogram name="Enterprise.IOSPolicies"> <owner>mnissler@chromium.org</owner> <summary> @@ -17908,6 +19976,14 @@ </summary> </histogram> +<histogram name="EnterpriseCheck.IsDomainJoined" enum="BooleanEnabled"> + <owner>mad@chromium.org</owner> + <summary> + Whether the machine is joined to an AD domain. This check is performed once + at start-up on Windows. + </summary> +</histogram> + <histogram name="EnterpriseCheck.IsEnterpriseUser" enum="BooleanEnabled"> <owner>rogerta@chromium.org</owner> <summary> @@ -17917,6 +19993,23 @@ </summary> </histogram> +<histogram name="EnterpriseCheck.IsLocalMachine" enum="Boolean"> + <owner>mad@chromium.org</owner> + <summary> + Whether the full machine name is the same as the short one, identifying a + local machine. This check is performed once at start-up on Windows. + </summary> +</histogram> + +<histogram name="EnterpriseCheck.IsLocalUser" enum="Boolean"> + <owner>mad@chromium.org</owner> + <summary> + Whether the currently logged in user is a local user or not, based on its + SAM compatible user name and machine name. This check is performed once at + start-up on Windows. + </summary> +</histogram> + <histogram name="EnterpriseCheck.IsManaged" enum="BooleanEnabled"> <owner>rogerta@chromium.org</owner> <summary> @@ -17925,6 +20018,15 @@ </summary> </histogram> +<histogram name="EnterpriseCheck.NetGetJoinInformationAddress" + enum="BooleanEnabled"> + <owner>rogerta@chromium.org</owner> + <summary> + Whether we could obtain the address of the NetGetJoinInformation function. + This check is performed once at start-up on Windows. + </summary> +</histogram> + <histogram name="EnterpriseCheck.OSType" enum="OsSuite"> <owner>mnissler@chromium.org</owner> <owner>pastarmovj@chromium.org</owner> @@ -17984,6 +20086,26 @@ </summary> </histogram> +<histogram name="Event.AsyncTargeting.ResponseTime" units="ms"> + <owner>riajiang@chromium.org</owner> + <summary> + Tracks how long it takes for a client to respond to an asynchronous request + to find a target for an input event. + + Team: event-targeting@chromium.org. + </summary> +</histogram> + +<histogram name="Event.AsyncTargeting.TimeInQueue" units="ms"> + <owner>riajiang@chromium.org</owner> + <summary> + Tracks how long an event has to wait in the queue while a previous event is + being targeted asynchronously. + + Team: event-targeting@chromium.org. + </summary> +</histogram> + <histogram name="Event.ClickNotFiredDueToDomManipulation" enum="BooleanHit"> <owner>nzolghadr@chromium.org</owner> <summary> @@ -18080,6 +20202,10 @@ <histogram name="Event.DownEventCount.PerDestination" enum="DownEventDestination"> + <obsolete> + Deprecated 01/2018 in favor of + Event.DownEventCount.PerInputFormFactorDestinationCombination. + </obsolete> <owner>xiaoyinh@chromium.org</owner> <owner>tbuckley@chromium.org</owner> <summary> @@ -18091,6 +20217,10 @@ </histogram> <histogram name="Event.DownEventCount.PerFormFactor" enum="DownEventFormFactor"> + <obsolete> + Deprecated 01/2018 in favor of + Event.DownEventCount.PerInputFormFactorDestinationCombination. + </obsolete> <owner>xiaoyinh@chromium.org</owner> <owner>tbuckley@chromium.org</owner> <summary> @@ -18099,6 +20229,10 @@ </histogram> <histogram name="Event.DownEventCount.PerInput" enum="DownEventSource"> + <obsolete> + Deprecated 01/2018 in favor of + Event.DownEventCount.PerInputFormFactorDestinationCombination. + </obsolete> <owner>xiaoyinh@chromium.org</owner> <owner>tbuckley@chromium.org</owner> <summary> @@ -18106,6 +20240,23 @@ </summary> </histogram> +<histogram name="Event.DownEventCount.PerInputFormFactorDestinationCombination" + enum="DownEventInputFormFactorDestinationCombination"> + <owner>xiaoyinh@chromium.org</owner> + <owner>tbuckley@chromium.org</owner> + <summary> + The number of down events received per input, form factor, and destination + combination. + + Input is down events generated by mouse/touch/stylus. Form factor is down + events generated by clamshell/touchviewLandscape/touchviewPortrait. + Destination: Every down event that is targeted to each destination will be + counted,including those that don't have an effect. For example: Tapping on a + disabled button inside the browser frame will be treated as down events on + browser window. + </summary> +</histogram> + <histogram name="Event.DragDrop.Cancel" enum="DragDropEventSource"> <owner>mfomitchev@chromium.org</owner> <summary> @@ -18866,6 +21017,14 @@ </summary> </histogram> +<histogram name="Event.Latency.EndToEnd.Mouse" units="microseconds"> + <owner>input-dev@chromium.org</owner> + <summary> + Time between the OS receiving a mouse event and the resulting GPU frame + swap. If no swap was induced by the event, no recording is made. + </summary> +</histogram> + <histogram name="Event.Latency.HitTest" units="microseconds"> <owner>dtapuska@chromium.org</owner> <summary> @@ -19061,6 +21220,34 @@ </summary> </histogram> +<histogram name="Event.Latency.Scroll.Wheel.TimeToHandled2" + units="microseconds"> + <owner>tdresser@chromium.org</owner> + <summary> + Time between initial creation of a wheel event and the generated + ScrollUpdate gesture event is handled on main/impl thread (specified by + suffix). If no swap was induced by the ScrollUpdate gesture event, no + recording is made. Unlike Event.Latency.ScrollUpdate.Wheel.TimeToHandled2 + this metric includes the first GSU of every scrolling sequence as well. + + Team: input-dev@chromium.org. + </summary> +</histogram> + +<histogram name="Event.Latency.Scroll.Wheel.TimeToScrollUpdateSwapBegin2" + units="microseconds"> + <owner>tdresser@chromium.org</owner> + <summary> + Time between initial creation of a wheel event and start of the frame swap + on the GPU service caused by the generated ScrollUpdate gesture event. If no + swap was induced by the event, no recording is made. Unlike + Event.Latency.ScrollUpdate.Wheel.TimeToScrollUpdateSwapBegin2 this metric + includes the first GSU of every scrolling sequence as well. + + Team: input-dev@chromium.org. + </summary> +</histogram> + <histogram name="Event.Latency.ScrollBegin.Touch.BrowserNotifiedToBeforeGpuSwap2" units="microseconds"> @@ -19316,6 +21503,9 @@ <histogram name="Event.Latency.ScrollUpdate.Touch.TimeToFirstScrollUpdateSwapBegin2" units="microseconds"> + <obsolete> + Replaced by Event.Latency.ScrollBegin.Touch.TimeToScrollUpdateSwapBegin2. + </obsolete> <owner>tdresser@chromium.org</owner> <summary> Time between initial creation of a touch event and the start of the frame @@ -19350,7 +21540,8 @@ <summary> Time between initial creation of a touch event and start of the frame swap on the GPU service caused by the generated ScrollUpdate gesture event. If no - swap was induced by the event, no recording is made. + swap was induced by the event, no recording is made. The first GSU of every + scrolling sequence is excluded from this metric. Team: input-dev@chromium.org. </summary> @@ -19420,6 +21611,9 @@ <histogram name="Event.Latency.ScrollUpdate.Wheel.TimeToFirstScrollUpdateSwapBegin2" units="microseconds"> + <obsolete> + Replaced by Event.Latency.ScrollBegin.Wheel.TimeToScrollUpdateSwapBegin2. + </obsolete> <owner>tdresser@chromium.org</owner> <summary> Time between initial creation of a wheel event and the start of the frame @@ -19442,7 +21636,21 @@ Time between initial creation of a wheel event and the generated ScrollUpdate gesture event is handled on main/impl thread (specified by suffix). If no swap was induced by the ScrollUpdate gesture event, no - recording is made. + recording is made. The first GSU of every scrolling sequence is excluded + from this metric. + + Team: input-dev@chromium.org. + </summary> +</histogram> + +<histogram name="Event.Latency.ScrollUpdate.Wheel.TimeToScrollUpdateSwapBegin2" + units="microseconds"> + <owner>tdresser@chromium.org</owner> + <summary> + Time between initial creation of a wheel event and start of the frame swap + on the GPU service caused by the generated ScrollUpdate gesture event. If no + swap was induced by the event, no recording is made. The first GSU of every + scrolling sequence is excluded from this metric. Team: input-dev@chromium.org. </summary> @@ -19493,6 +21701,9 @@ <histogram name="Event.Latency.TouchToFirstScrollUpdateSwapBegin" units="microseconds"> + <obsolete> + Replaced by Event.Latency.ScrollBegin.Touch.TimeToScrollUpdateSwapBegin2. + </obsolete> <owner>tdresser@chromium.org</owner> <summary> Time between initial creation of a touch event and the start of the frame @@ -19522,6 +21733,9 @@ <histogram name="Event.Latency.TouchToScrollUpdateSwapBegin" units="microseconds"> + <obsolete> + Replaced by Event.Latency.ScrollUpdate.Touch.TimeToScrollUpdateSwapBegin2. + </obsolete> <owner>tdresser@chromium.org</owner> <summary> Time between initial creation of a touch event and start of the frame swap @@ -19573,6 +21787,9 @@ <histogram name="Event.MainThreadEventQueue.Continuous.FreshnessTime" units="microseconds"> + <obsolete> + Deprecated 01/2018 due to lack of usage. + </obsolete> <owner>dtapuska@chromium.org</owner> <summary> Time between when a continuous event (touchmove, mousemove, mousewheel) was @@ -19585,6 +21802,9 @@ <histogram name="Event.MainThreadEventQueue.Continuous.QueueingTime" units="microseconds"> + <obsolete> + Deprecated 01/2018 due to lack of usage. + </obsolete> <owner>dtapuska@chromium.org</owner> <summary> Time between when a continuous event (touchmove, mousemove, mousewheel) was @@ -19607,6 +21827,9 @@ <histogram name="Event.MainThreadEventQueue.NonContinuous.QueueingTime" units="microseconds"> + <obsolete> + Deprecated 01/2018 due to lack of usage. + </obsolete> <owner>dtapuska@chromium.org</owner> <summary> Time between when a non-continuous event (not touchmove, mousemove, @@ -19706,6 +21929,9 @@ </histogram> <histogram name="Event.Scroll.ScrollerSize.OnLoad" units="pixels"> + <obsolete> + Deprecated 10/2017 due to the completion of the experiment. + </obsolete> <owner>yigu@chromium.org</owner> <summary> Record the area of a scroller upon page load. This is intended to help us @@ -19713,11 +21939,14 @@ the other two metrics which measure the size of scrollers on scroll, we may have a better idea of not compositing small scrollers. - Team: input-dev@chromium.org, threaded-rendering-dev@chromium.org. + Team: input-dev@chromium.org, animations-dev@chromium.org. </summary> </histogram> <histogram name="Event.Scroll.ScrollerSize.OnScroll" units="pixels"> + <obsolete> + Deprecated 10/2017 due to the completion of the experiment. + </obsolete> <owner>yigu@chromium.org</owner> <summary> Record the area of a scroller upon ScrollBegin. This is intended to help us @@ -19725,7 +21954,7 @@ For those small scrollers that users may rarely scroll, there is no need to composite them even if we are able to do so. - Team: input-dev@chromium.org, threaded-rendering-dev@chromium.org. + Team: input-dev@chromium.org, animations-dev@chromium.org. </summary> </histogram> @@ -19742,6 +21971,10 @@ </histogram> <histogram name="Event.TimestampHasValidTimebase" enum="EventTimestampValidity"> + <obsolete> + Deprecated as of 1/2018 in issue 650338 (http://crbug.com/650338). Using a + DCHECK instead. + </obsolete> <owner>majidvp@chromium.org</owner> <owner>caseq@chromium.org</owner> <summary> @@ -19806,6 +22039,28 @@ </summary> </histogram> +<histogram name="Event.Touch.TouchAdjustment.AdjustDistance" units="pixels"> + <owner>eirage@chromium.org</owner> + <summary> + Records the euclidean distance in dips from a gesture event's original tap + center to its adjusted touch point. 0 if not adjusted. This only records + GestureTap events and GestureLongPress events. + + Team: input-dev@chromium.org. + </summary> +</histogram> + +<histogram name="Event.Touch.TouchAdjustment.AdjustToSameNode" enum="Boolean"> + <owner>eirage@chromium.org</owner> + <summary> + Records if doing touch adjustment on touchstart have same hit test node as + doing touch adjustment on GestureTap. True for same node, false for + different node. This only records GestureTap events. + + Team: input-dev@chromium.org. + </summary> +</histogram> + <histogram name="Event.Touch.TouchDispositionsAfterPageLoad" enum="TouchEventDispatchResultType"> <obsolete> @@ -20801,7 +23056,7 @@ <owner>benwells@chromium.org</owner> <owner>cylee@chromium.org</owner> <summary> - The number of times times apps are launched grouped by + The number of times apps are launched grouped by extensions::AppLaunchSource. </summary> </histogram> @@ -20909,12 +23164,123 @@ </summary> </histogram> +<histogram name="Extensions.BookmarkApp.GetAppForCurrentURLDuration" units="ms"> + <owner>mgiuca@chromium.org</owner> + <owner>ortuno@chromium.org</owner> + <summary> + Time it takes to retrieve the app for the current URL during a navigation. + </summary> +</histogram> + +<histogram name="Extensions.BookmarkApp.GetAppForWindowDuration" units="ms"> + <owner>mgiuca@chromium.org</owner> + <owner>ortuno@chromium.org</owner> + <summary> + Time it takes to retrieve the app associated with the window during a + navigation. + </summary> +</histogram> + +<histogram name="Extensions.BookmarkApp.GetTargetAppDuration" units="ms"> + <owner>mgiuca@chromium.org</owner> + <owner>ortuno@chromium.org</owner> + <summary> + Time it takes to retrieve the app for the target url during a navigation. + </summary> +</histogram> + +<histogram name="Extensions.BookmarkApp.NavigationResult" + enum="BookmarkAppNavigationResult"> + <owner>mgiuca@chromium.org</owner> + <owner>ortuno@chromium.org</owner> + <summary> + Number of times navigations into and out of Bookmark Apps are processed, + grouped by their result. + </summary> +</histogram> + +<histogram name="Extensions.BookmarkApp.TimeBetweenOpenAppAndLastNavigation" + units="ms"> + <owner>mgiuca@chromium.org</owner> + <owner>ortuno@chromium.org</owner> + <summary> + The time between the last navigation in the context and us opening a new app + window in response to a new navigation. If it is very small, the context + probably redirected immediately, which is a bad user experience. + </summary> +</histogram> + <histogram name="Extensions.BookmarkAppLaunchContainer" enum="AppLaunchContainer"> <owner>benwells@chromium.org</owner> <summary>Records the container used for a bookmark app launch.</summary> </histogram> +<histogram name="Extensions.BookmarkAppLaunchSource" enum="AppLaunchSource"> + <owner>benwells@chromium.org</owner> + <owner>mgiuca@chromium.org</owner> + <owner>ortuno@chromium.org</owner> + <summary> + The number of times Bookmark Apps are launched, grouped by + extensions::AppLaunchSource. The equivalent histogram on Android is called + Launch.HomeScreenSource. + </summary> +</histogram> + +<histogram name="Extensions.BrowsingInstanceViolation.ExtensionType" + enum="ExtensionType"> + <owner>lukasza@chromium.org</owner> + <summary> + When an extension violates browsing instance boundaries, this metric records + the extension type. + + This is a temporary metric - probably okay to remove it in M66, after we've + gathered sufficient UMA data in M65. See also http://crbug.com/718489. + </summary> +</histogram> + +<histogram + name="Extensions.BrowsingInstanceViolation.IsBackgroundSourceOrTarget" + enum="ExtensionViewTypeIsBackground"> + <owner>lukasza@chromium.org</owner> + <summary> + When an extension violates browsing instance boundaries, this metric records + whether either the source or the target frame was of the extension view type + of VIEW_TYPE_BACKGROUND_CONTENTS. + + This is a temporary metric - probably okay to remove it in M66, after we've + gathered sufficient UMA data in M65. See also http://crbug.com/718489. + </summary> +</histogram> + +<histogram name="Extensions.BrowsingInstanceViolation.SourceExtensionViewType" + enum="ExtensionViewType"> + <owner>lukasza@chromium.org</owner> + <summary> + When an extension violates browsing instance boundaries, this metric records + the extension view type of the source frame. + + This is a temporary metric - probably okay to remove it in M66, after we've + gathered sufficient UMA data in M65. See also http://crbug.com/718489. + </summary> +</histogram> + +<histogram name="Extensions.BrowsingInstanceViolation.TargetExtensionViewType" + enum="ExtensionViewType"> + <owner>lukasza@chromium.org</owner> + <summary> + When an extension violates browsing instance boundaries, this metric records + the extension view type of the found frame. + + This metric should help confirm or deny the theory that violating browsing + instance boundaries is only needed for looking up background contents / + pages (of VIEW_TYPE_BACKGROUND_CONTENTS type). + + This is a temporary metric - probably okay to remove it in M66, after we've + gathered sufficient UMA data in M65. See also http://crbug.com/718489. + </summary> +</histogram> + <histogram name="Extensions.CheckForExternalUpdatesTime" units="ms"> <owner>rkaplow@chromium.org</owner> <summary> @@ -21081,6 +23447,17 @@ </summary> </histogram> +<histogram name="Extensions.DeclarativeNetRequest.CreateVerifiedMatcherTime" + units="ms"> + <owner>karandeepb@chromium.org</owner> + <summary> + Measures the time taken to load the indexed ruleset in the browser process + for an extension. This includes memory mapping the ruleset file and + verifying it. Emitted when an extension using the Declarative Net Request + API is loaded. + </summary> +</histogram> + <histogram name="Extensions.DeclarativeNetRequest.IndexAndPersistRulesTime" units="ms"> <owner>karandeepb@chromium.org</owner> @@ -21107,6 +23484,15 @@ </summary> </histogram> +<histogram name="Extensions.DeclarativeNetRequest.LoadRulesetResult" + enum="LoadRulesetResult"> + <owner>karandeepb@chromium.org</owner> + <summary> + Records the result of loading an extension ruleset for the Declarative Net + Request API. Emitted whenever an extension with a ruleset is loaded. + </summary> +</histogram> + <histogram name="Extensions.DeclarativeNetRequest.ManifestRulesCount" units="rules"> <owner>karandeepb@chromium.org</owner> @@ -21119,6 +23505,52 @@ </summary> </histogram> +<histogram + name="Extensions.DeclarativeNetRequest.ShouldBlockRequestTime.AllExtensions" + units="ms"> + <owner>karandeepb@chromium.org</owner> + <summary> + Time taken to evaluate whether a network request should be blocked as per + the Declarative Net Request API. This includes the time taken to evaluate + all the extension rulesets. Emitted whenever a non-sensitive network request + is seen by the Extension System. + </summary> +</histogram> + +<histogram + name="Extensions.DeclarativeNetRequest.ShouldBlockRequestTime.SingleExtension" + units="ms"> + <owner>karandeepb@chromium.org</owner> + <summary> + Time taken to evaluate whether a network request should be blocked for a + single extension ruleset. Emitted for each network request that is visible + to the extension. + </summary> +</histogram> + +<histogram + name="Extensions.DeclarativeNetRequest.ShouldRedirecRequestTime.SingleExtension" + units="ms"> + <owner>karandeepb@chromium.org</owner> + <summary> + Time taken to evaluate whether a network request should be redirected for a + single extension ruleset. Emitted for network requests visible to the + extension. + </summary> +</histogram> + +<histogram + name="Extensions.DeclarativeNetRequest.ShouldRedirectRequestTime.AllExtensions" + units="ms"> + <owner>karandeepb@chromium.org</owner> + <summary> + Time taken to evaluate whether a network request should be redirected as per + the Declarative Net Request API. This includes the time taken to evaluate + all the extension rulesets. Emitted for non-sensitive network requests seen + by the Extension System. + </summary> +</histogram> + <histogram name="Extensions.DeclarativeRulesStorageInitialization" units="ms"> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <summary>Time spent until rules storage delegate gets ready.</summary> @@ -21608,6 +24040,33 @@ <summary>An extension has been uninstalled.</summary> </histogram> +<histogram name="Extensions.ExtensionUpdaterUpdateCalls" units="extensions"> + <owner>mxnguyen@chromium.org</owner> + <summary> + The number of extensions that are passed over to the extension updater for + update check. Triggered when the extension updater starts doing update + check. + </summary> +</histogram> + +<histogram name="Extensions.ExtensionUpdaterUpdateFoundCount" + units="extensions"> + <owner>mxnguyen@chromium.org</owner> + <summary> + The number of extensions that have updates in an update check session. + Triggered when the extension updater found an update for an extension. + </summary> +</histogram> + +<histogram name="Extensions.ExtensionUpdaterUpdateResults" + enum="ExtensionUpdaterUpdateResult"> + <owner>mxnguyen@chromium.org</owner> + <summary> + Records the update results of extensions in an extension updater session, + grouped by ExtensionUpdaterUpdateResult. + </summary> +</histogram> + <histogram name="Extensions.ExternalExtensionEvent" enum="SideloadUIEvents"> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <summary> @@ -22428,6 +24887,15 @@ </summary> </histogram> +<histogram name="Extensions.Messaging.MessageSize" units="bytes"> + <owner>redevlin.cronin@chromium.org</owner> + <summary> + The size, in bytes, of a message sent from an extension using one of the + messaging APIs (e.g. chrome.runtime.sendMessage). All message sizes are + logged, but messages over 64 MB in size aren't sent. + </summary> +</histogram> + <histogram name="Extensions.Messaging.SetPortIdTime" units="ms"> <owner>rdevlin.cronin@chromium.org</owner> <summary> @@ -23433,6 +25901,9 @@ </histogram> <histogram name="Extensions.WebRequestEventFoundFrame" units="boolean"> + <obsolete> + Deprecated as of 11/2017. No longer relevant after refactoring. + </obsolete> <owner>rdevlin.cronin@chromium.org</owner> <summary> Whether or not the render frame lookup for a given webRequest event @@ -23515,6 +25986,17 @@ </summary> </histogram> +<histogram name="ExtensionService.ZipUnpackerDisabledReason" + enum="ExtensionDisableReason"> + <owner>yamaguchi@google.com</owner> + <summary> + Records the reason why the ZIP unpacker extension was disabled when the + service attempted to re-enable the extension upon startup. Each entry + indicates that the extension was disabled unintentionally and a fix was + attempted. + </summary> +</histogram> + <histogram name="ExtensionSettings.ShouldDoVerificationCheck" enum="Boolean"> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <summary> @@ -23605,6 +26087,9 @@ </histogram> <histogram name="Favicons.CandidatesCount"> + <obsolete> + Deprecated as of 12/2017. + </obsolete> <owner>fhorschig@chromium.org</owner> <summary> Records the number of favicon link tags on a page once the page has finished @@ -23613,6 +26098,9 @@ </histogram> <histogram name="Favicons.CandidatesWithDefinedSizesCount"> + <obsolete> + Deprecated as of 12/2017. + </obsolete> <owner>fhorschig@chromium.org</owner> <summary> Records the number of favicon link tags with a non empty sizes attribute @@ -23621,6 +26109,9 @@ </histogram> <histogram name="Favicons.CandidatesWithTouchIconsCount"> + <obsolete> + Deprecated as of 12/2017. + </obsolete> <owner>fhorschig@chromium.org</owner> <summary> Records the number of apple-touch-icon and apple-touch-icon-precomposed link @@ -23629,6 +26120,9 @@ </histogram> <histogram base="true" name="Favicons.DownloadAttempts" units="attempts"> + <obsolete> + Deprecated as of 12/2017. + </obsolete> <owner>fhorschig@chromium.org</owner> <summary> Records the number of icons requested until the best-fitting candidate was @@ -23639,6 +26133,9 @@ </histogram> <histogram name="Favicons.DownloadOutcome" enum="FaviconDownloadStatus"> + <obsolete> + Deprecated as of 12/2017. + </obsolete> <owner>fhorschig@chromium.org</owner> <summary> Records whether a download succeeded, failed or was skipped because it has @@ -23646,6 +26143,16 @@ </summary> </histogram> +<histogram name="Favicons.LargeIconService.BlacklistedURLMismatch" + units="BooleanError"> + <owner>mastiz@chromium.org</owner> + <summary> + Records the number of large icons that were fetched from the local cache + (e.g. during NTP impression), where the URL (of the page or the icon) + matches a hardcoded blacklist. Suspicious mismatches are reported as errors. + </summary> +</histogram> + <histogram name="Favicons.LargeIconService.DownloadedSize" units="pixels"> <owner>jkrcal@chromium.org</owner> <summary> @@ -23670,7 +26177,7 @@ <histogram name="FileBrowser.ChangeDirectory.RootType" enum="FileManagerRootType"> - <owner>yamaguchi@chromium.com</owner> + <owner>yamaguchi@chromium.org</owner> <summary> Chrome OS File Browser: Counts the number of directory-changed events, bucketed by the RootType of the directory newly displayed. @@ -23793,6 +26300,14 @@ </summary> </histogram> +<histogram name="FileBrowser.OpenFiles.RootType" enum="FileManagerRootType"> + <owner>fukino@chromium.org</owner> + <summary> + Chrome OS File Browser: The locations (root types) of files which are opened + by the file picker. + </summary> +</histogram> + <histogram name="FileBrowser.OpeningFileType" enum="FileType"> <obsolete> Deprecated 4/2013, and replaced by FileBrowser.ViewingFileType. @@ -23959,7 +26474,7 @@ </summary> </histogram> -<histogram name="FileBrowser.SuggestApps.Close" +<histogram name="FileBrowser.SuggestApps.CloseDialog" enum="SuggestAppsDialogCloseReason"> <owner>joshwoodward@google.com</owner> <summary> @@ -24001,6 +26516,21 @@ </summary> </histogram> +<histogram name="FileBrowser.ViewingRootType" enum="FileManagerRootType"> + <owner>nya@chromium.org</owner> + <summary> + Chrome OS File Browser: The locations (root types) of files which are opened + in stand-alone mode. This does not include files opened in file picker mode. + </summary> +</histogram> + +<histogram name="FileBrowser.ViewingTaskType" enum="FileManagerTaskType"> + <owner>nya@chromium.org</owner> + <summary> + Chrome OS File Browser: The type of the handler to be used to open files. + </summary> +</histogram> + <histogram name="FileBrowser.VolumeType" enum="FileManagerVolumeType"> <owner>kinaba@chromium.org</owner> <summary> @@ -24082,6 +26612,35 @@ </summary> </histogram> +<histogram name="FirstRun.LaunchSource" enum="FirstRunLaunchSource"> + <owner>olivierrobin@chromium.org</owner> + <summary> + Counts the number of times First Run experience was triggered by another + application launching Chrome. This metric measures the effectiveness of + Smart App Banner promotions on installation of Chrome. + </summary> +</histogram> + +<histogram name="FirstRun.SignIn" enum="FirstRunSignInResult"> + <owner>msarda@chromium.org</owner> + <summary>Result of the sign in flow during Mobile first run.</summary> +</histogram> + +<histogram name="FirstUserAction.BackgroundTime" units="minutes"> +<!-- Name completed by histogram_suffixes name="FirstUserActionType" and name="FirstUserActionTypeDevice" --> + + <owner>pkl@chromium.org</owner> + <summary> + WARNING: The list of actions used to identify new tasks hasn't been + attentively updated for several years (as of 2017). Some actions that + should likely be considered new tasks are probably missing. Take this + histogram with a grain of salt. + + The amount of time (in seconds) that the app was in the background before + the user started it + </summary> +</histogram> + <histogram base="true" name="FirstUserAction.BackgroundTime.MainIntent" units="minutes"> <owner>tedchoc@chromium.org</owner> @@ -24094,6 +26653,34 @@ </summary> </histogram> +<histogram name="FirstUserAction.HandsetUserActionType" + enum="FirstUserActionType"> + <owner>pkl@chromium.org</owner> + <summary> + WARNING: The list of actions used to identify new tasks hasn't been + attentively updated for several years (as of 2017). Some actions that + should likely be considered new tasks are probably missing. Take this + histogram with a grain of salt. + + On handsets, the type of the first user action performed after the app was + started or unbackgrounded. + </summary> +</histogram> + +<histogram name="FirstUserAction.TabletUserActionType" + enum="FirstUserActionType"> + <owner>pkl@chromium.org</owner> + <summary> + WARNING: The list of actions used to identify new tasks hasn't been + attentively updated for several years (as of 2017). Some actions that + should likely be considered new tasks are probably missing. Take this + histogram with a grain of salt. + + On tablets, the type of the first user action performed after the app was + started or unbackgrounded. + </summary> +</histogram> + <histogram name="GCM.AndroidGcmReceiverError" enum="GcmReceiverStatus"> <obsolete> Deprecated as of 01/2016. The error has been fixed by GCM. (crbug/580367) @@ -24364,6 +26951,14 @@ </summary> </histogram> +<histogram name="GCM.RegistrationCacheStatus" enum="GCMRegistrationCacheStatus"> + <owner>nator@chromium.org</owner> + <summary> + Reports the status of cached GCM registration. This is recorded when a new + registration request is considered on the GCM client. + </summary> +</histogram> + <histogram name="GCM.RegistrationCompleteTime" units="ms"> <owner>jianli@chromium.org</owner> <summary> @@ -24598,6 +27193,24 @@ </summary> </histogram> +<histogram name="Geolocation.AuthorizationActionExistingUser" + enum="GeolocationAuthorizationAction"> + <owner>mvanouwerkerk@chromium.org</owner> + <summary> + Records the action performed by an existing user when prompted to authorize + the use of location by Chrome. + </summary> +</histogram> + +<histogram name="Geolocation.AuthorizationActionNewUser" + enum="GeolocationAuthorizationAction"> + <owner>mvanouwerkerk@chromium.org</owner> + <summary> + Records the action performed by a new user when prompted to authorize the + use of location by Chrome. + </summary> +</histogram> + <histogram name="Geolocation.GeolocationDispatcherHostImpl.EnableHighAccuracy" enum="BooleanEnabled"> <owner>mvanouwerkerk@chromium.org</owner> @@ -24637,6 +27250,16 @@ </summary> </histogram> +<histogram name="Geolocation.HeaderSentOrNot" enum="GeolocationHeaderSentOrNot"> + <owner>kiyun@chromium.org</owner> + <owner>mvanouwerkerk@chromium.org</owner> + <owner>newt@chromium.org</owner> + <summary> + Reason why the X-Geo header was or was not included in a Google search from + the omnibox. + </summary> +</histogram> + <histogram name="Geolocation.InfoBarDelegate.Event" enum="GeolocationInfoBarDelegateEvent"> <obsolete> @@ -24755,6 +27378,9 @@ <histogram name="GeolocationDisclosure.PostDisclosureContentSetting" enum="ContentSetting"> + <obsolete> + Deprecated 2017/11. Use PostDisclosureDSESetting instead. + </obsolete> <owner>benwells@chromium.org</owner> <summary> Records the geolocation content setting for the default search engine's @@ -24788,6 +27414,9 @@ <histogram name="GeolocationDisclosure.PreDisclosureContentSetting" enum="ContentSetting"> + <obsolete> + Deprecated 2017/11. Use PreDisclosureDSESetting instead. + </obsolete> <owner>benwells@chromium.org</owner> <summary> Records the geolocation content setting for the default search engine's @@ -25192,15 +27821,6 @@ </summary> </histogram> -<histogram name="GPU.BlacklistFeatureTestResultsWin" - enum="GPUBlacklistFeatureTestResultsWin"> - <owner>vmiura@chromium.org</owner> - <summary> - Counts number of browser invocations for which a GPU feature is blacklisted - in various Windows sub-versions. - </summary> -</histogram> - <histogram name="GPU.BlacklistFeatureTestResultsWindows" enum="GPUBlacklistFeatureTestResultsWindows"> <owner>vmiura@chromium.org</owner> @@ -26125,6 +28745,15 @@ </summary> </histogram> +<histogram name="Histogram.PermanentNameChanged" enum="HistogramNameHash"> + <owner>asvitkine@chromium.org</owner> + <owner>bcwhite@chromium.org</owner> + <summary> + The hash codes of histograms of which the external name storage was altered + after the histogram was created. + </summary> +</histogram> + <histogram name="History.AttemptedToFixProfileError"> <owner>brettw@chromium.org</owner> <summary> @@ -26208,6 +28837,16 @@ </summary> </histogram> +<histogram name="History.ClearBrowsingData.SpannableStringAppliedCorrectly" + enum="Boolean"> + <owner>dullweber@chromium.org</owner> + <owner>msramek@chromium.org</owner> + <summary> + Track whether the SpannableString is applied correctly in + ClearBrowsingDataCheckbox.java. (crbug.com/783866) + </summary> +</histogram> + <histogram name="History.ClearBrowsingData.TaskQueueAtShutdown"> <owner>dullweber@chromium.org</owner> <owner>msramek@chromium.org</owner> @@ -26291,6 +28930,23 @@ </summary> </histogram> +<histogram name="History.ExpireVisits.GetRedirectsDurationPercentage" units="%"> + <owner>calamity@chromium.org</owner> + <summary> + The percentage of time taken in ExpireHistoryBackend::ExpireVisits for + calculating the redirect parent. + </summary> +</histogram> + +<histogram name="History.ExpireVisits.TotalDuration" units="ms"> + <owner>calamity@chromium.org</owner> + <summary> + The time taken to expire a list of visits. This is not scaled to the number + of visits deleted, but gives an idea of how long a single request to + ExpireHistoryBackend::ExpireVisits takes. + </summary> +</histogram> + <histogram name="History.FaviconDatabaseAdvancedMetricsTime" units="ticks"> <owner>rogerm@chromium.org</owner> <summary> @@ -26795,7 +29451,27 @@ </summary> </histogram> +<histogram name="HostedAppFrame.ContentSettings.ImagePressed" + enum="ContentSettingImageType"> + <owner>calamity@chromium.org</owner> + <summary> + Counts which content setting buttons in the hosted app frame are pressed by + the user. + </summary> +</histogram> + +<histogram name="HostedAppFrame.WrenchMenu.MenuAction" enum="WrenchMenuAction"> + <owner>calamity@chromium.org</owner> + <summary> + Number of times that each menu item is clicked from the hosted app window + menu button. + </summary> +</histogram> + <histogram name="Hotword.AudioLoggingEnabled" enum="BooleanEnabled"> + <obsolete> + Deprecated as of 10/2017. Feature removed with crbug/761426. + </obsolete> <owner>rlp@chromium.org</owner> <summary> The state of the hotword audio logging preference. This value is emitted @@ -26806,6 +29482,9 @@ </histogram> <histogram name="Hotword.Enabled" enum="HotwordPrefState"> + <obsolete> + Deprecated as of 10/2017. Feature removed with crbug/761426. + </obsolete> <owner>rlp@chromium.org</owner> <summary> The state of the hotword preference. This value is emitted during @@ -26814,6 +29493,9 @@ </histogram> <histogram name="Hotword.ExtensionAvailability" enum="HotwordAvailability"> + <obsolete> + Deprecated as of 10/2017. Feature removed with crbug/761426. + </obsolete> <owner>rlp@chromium.org</owner> <summary> Whether the external component hotword extension exists (i.e., not pending @@ -26824,6 +29506,9 @@ </histogram> <histogram name="Hotword.HotwordError" enum="HotwordError"> + <obsolete> + Deprecated as of 10/2017. Feature removed with crbug/761426. + </obsolete> <owner>rlp@chromium.org</owner> <summary> Errors reported by the hotword service when determining if hotwording is @@ -26834,6 +29519,9 @@ <histogram name="Hotword.HotwordMediaStreamResult" enum="HotwordMediaStreamResult"> + <obsolete> + Deprecated as of 10/2017. Feature removed with crbug/761426. + </obsolete> <owner>amistry@chromium.org</owner> <owner>rlp@chromium.org</owner> <owner>somast@chromium.org</owner> @@ -26845,6 +29533,9 @@ <histogram name="Hotword.HotwordNaClMessageTimeout" enum="HotwordNaClMessageTimeout"> + <obsolete> + Deprecated as of 10/2017. Feature removed with crbug/761426. + </obsolete> <owner>amistry@chromium.org</owner> <owner>rlp@chromium.org</owner> <owner>somast@chromium.org</owner> @@ -26857,6 +29548,9 @@ <histogram name="Hotword.HotwordNaClPluginLoadResult" enum="HotwordNaClPluginLoadResult"> + <obsolete> + Deprecated as of 10/2017. Feature removed with crbug/761426. + </obsolete> <owner>amistry@chromium.org</owner> <owner>rlp@chromium.org</owner> <owner>somast@chromium.org</owner> @@ -26866,6 +29560,9 @@ </histogram> <histogram name="Hotword.HotwordTriggerSource" enum="HotwordTriggerSource"> + <obsolete> + Deprecated as of 10/2017. Feature removed with crbug/761426. + </obsolete> <owner>amistry@chromium.org</owner> <owner>rlp@chromium.org</owner> <owner>somast@chromium.org</owner> @@ -26876,6 +29573,9 @@ </histogram> <histogram name="Hotword.SharedModuleReinstallLanguage" enum="LanguageCode"> + <obsolete> + Deprecated as of 10/2017. Feature removed with crbug/761426. + </obsolete> <owner>amistry@chromium.org</owner> <owner>rlp@chromium.org</owner> <owner>somast@chromium.org</owner> @@ -26886,13 +29586,21 @@ </histogram> <histogram name="HttpCache.AccessToDone" units="ms"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> For every http cache transaction with a pattern (see HttpCache.Pattern), the time from the first access to the disk cache until the transaction was done. </summary> </histogram> +<histogram base="true" name="HttpCache.AfterSend" units="ms"> + <owner>morlovich@chromium.org</owner> + <summary> + For http cache transactions in which a network request was sent, the time + elapsed between sending it over the network until the transaction was done. + </summary> +</histogram> + <histogram name="HttpCache.AsyncValidationDuration" units="ms"> <obsolete> Deprecated as of 3/2015. @@ -26908,7 +29616,7 @@ </histogram> <histogram name="HttpCache.BeforeSend" units="ms"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> For http cache transactions in which a network request was sent, the time elapsed between beginning the request and sending it over the network; this @@ -26925,9 +29633,20 @@ </summary> </histogram> +<histogram name="HttpCache.CantConditionalizeZeroFreshnessFromMemHint" + enum="Boolean"> + <owner>morlovich@chromium.org</owner> + <summary> + For each request with HttpCache.CantConditionalizeCause == Zero Freshness, + this is true iff the zero freshness status was determined by looking at + in-memory hints in disk cache index, rather than by opening the entry and + looking at headers. + </summary> +</histogram> + <histogram name="HttpCache.EntryLockWait" units="ms"> <owner>jkarlin@chromium.org</owner> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> The time spent waiting for write lock on a disk cache entry. </summary> @@ -26957,14 +29676,24 @@ </summary> </histogram> +<histogram name="HttpCache.ParallelWritingPattern" + enum="HttpCacheParallelWritingPattern"> + <owner>shivanisha@chromium.org</owner> + <summary> + Records whether a transaction either created a Writers object when one + didn't exist, or joined an existing Writers object, or why it failed to do + so (e.g., it's a range request, it's not a GET request, etc.). + </summary> +</histogram> + <histogram name="HttpCache.Pattern" enum="HttpCachePattern"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <owner>jkarlin@chromium.org</owner> <summary>For each http cache transaction, the recorded pattern.</summary> </histogram> <histogram name="HttpCache.PercentBeforeSend" units="%"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> For http cache transactions in which a network request was sent, the percentage of total request time that elapsed before sending the request @@ -27076,6 +29805,28 @@ </summary> </histogram> +<histogram name="Import.IncludesPasswords.Firefox" enum="BooleanChecked"> + <owner>vabr@chromium.org</owner> + <owner>hurims@gmail.com</owner> + <summary> + Whether or not the password checkbox is checked when importing a profile of + Firefox. Note that canceled imports could be counted also. + </summary> +</histogram> + +<histogram name="Import.NumberOfImportedPasswords.Firefox"> + <owner>vabr@chromium.org</owner> + <owner>hurims@gmail.com</owner> + <summary> + The number of passwords that are imported from Firefox. This is recorded + when importing a profile of Firefox with the password checkbox checked. Note + that the reported number of password could be slightly bigger than the + actual number of imported passwords because some incomplete or blacklisted + passwords that are dropped while importing might be included in the reported + value. + </summary> +</histogram> + <histogram name="Import.ShowDialog.FromBookmarkBarView" units="seconds"> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <summary> @@ -28311,16 +31062,58 @@ </summary> </histogram> +<histogram name="InstantTethering.BluetoothAdvertisementRegistrationResult" + enum="InstantTethering_BluetoothAdvertisementResult"> + <owner>hansberry@chromium.org</owner> + <summary> + Provides a breakdown of how many times each possible Bluetooth advertisement + registration result occurs. + + The bucket "Unknown result" indicates that the Bluetooth platform + returned an unknown error code; if it has any counts, the client code should + be changed to account for the new error code. + </summary> +</histogram> + +<histogram name="InstantTethering.BluetoothAdvertisementUnregistrationResult" + enum="InstantTethering_BluetoothAdvertisementResult"> + <owner>hansberry@chromium.org</owner> + <summary> + Provides a breakdown of how many times each possible Bluetooth advertisement + unregistration result occurs. + + The bucket "Unknown result" indicates that the Bluetooth platform + returned an unknown error code; if it has any counts, the client code should + be changed to account for the new error code. + </summary> +</histogram> + +<histogram name="InstantTethering.BluetoothDiscoverySessionStarted" + enum="BooleanSuccess"> + <owner>hansberry@chromium.org</owner> + <summary> + Provides the success rate of starting a Bluetooth discovery session. + </summary> +</histogram> + +<histogram name="InstantTethering.BluetoothDiscoverySessionStopped" + enum="BooleanSuccess"> + <owner>hansberry@chromium.org</owner> + <summary> + Provides the success rate of stopping a Bluetooth discovery session. + </summary> +</histogram> + <histogram name="InstantTethering.ConnectionToHostResult.Failure" enum="InstantTethering_ConnectionToHostResult_Failure"> - <owner>hansberry@chromium.com</owner> + <owner>hansberry@chromium.org</owner> <summary> Provides a top-level breakdown of the times a connection to a host has failed. An "unknown error" is caused by the host returning an "unknown error" response code. Tethering timing out and client - connection error and 3) are both broken down further in + connection error are both broken down further in InstantTethering.ConnectionToHostResult.Failure.TetheringTimeout and InstantTethering.ConnectionToHostResult.Failure.ClientConnection, respectively. @@ -28330,7 +31123,7 @@ <histogram name="InstantTethering.ConnectionToHostResult.Failure.ClientConnection" enum="InstantTethering_ConnectionToHostResult_Failure_ClientConnection"> - <owner>hansberry@chromium.com</owner> + <owner>hansberry@chromium.org</owner> <summary> Breaks down the reasons why the client failed to connect to the hotspot, and the number of times they occurred. @@ -28348,7 +31141,7 @@ <histogram name="InstantTethering.ConnectionToHostResult.Failure.TetheringTimeout" enum="InstantTethering_ConnectionToHostResult_Failure_TetheringTimeout"> - <owner>hansberry@chromium.com</owner> + <owner>hansberry@chromium.org</owner> <summary> Captures the number of times of whether or not first-time setup was required when tethering timed out. @@ -28394,31 +31187,81 @@ <histogram name="InstantTethering.ConnectionToHostResult.SuccessRate" enum="InstantTethering_ConnectionToHostResult_SuccessRate"> - <owner>hansberry@chromium.com</owner> + <owner>hansberry@chromium.org</owner> <summary> Captures the count of successful and failed connection attempts. + This metric counts the top-level user action from beginning to connect, all + the way through success or failure of the connection (excluding any + programmatic retries within the connection attempt). + This metric provides an immediate understanding of the Instant Tethering connection success rate. The counts of failure are broken down in InstantTethering.ConnectionToHostResult.Failure. </summary> </histogram> -<histogram name="InstantTethering.FinalFeatureState" +<histogram name="InstantTethering.FeatureState" enum="InstantTethering_FeatureState"> - <owner>hansberry@chromium.com</owner> + <owner>hansberry@chromium.org</owner> <summary> - Breaks down the state of Instant Tethering, at the end of each user session. - All states, except for 'Enabled', indicate that the feature was not active. - This histogram is emitted to at the end of each user session and should - roughly reflect if Instant Tethering was enabled during that session (and if - not, why). + Breaks down the state of Instant Tethering during user sessions. All states, + except for 'Enabled', indicate that the feature was not active. This + histogram is emitted to each time a condition affecting Instant Tethering's + state, e.g. the user enabling or disabling the feature, or Bluetooth + becoming enabled or disabled. + + Note: The "Screen locked" bucket is obsolete, and should not have + any reports. + </summary> +</histogram> + +<histogram + name="InstantTethering.GattConnectionAttempt.EffectiveSuccessRateWithRetries" + enum="BooleanSuccess"> + <owner>hansberry@chromium.org</owner> + <summary> + Captures the effective count of successful and failed GATT connection + attempts, including retries. This means that if a GATT connection attempt + fails but then succeeds on a future retry, this is counted as a single + success. In the context of this metric, a failure represents a GATT failure + in all retry attempts. + + An individual attempt is considered successful if a GATT connection was + created and authenticated successfully (i.e., the connection was ready for + Instant Tethering to exchange protocol messages). + </summary> +</histogram> + +<histogram name="InstantTethering.GattConnectionAttempt.SuccessRate" + enum="BooleanSuccess"> + <owner>hansberry@chromium.org</owner> + <summary> + Captures the count of successful and failed GATT connection attempts. + + An attempt is considered successful if a GATT connection was created and + authenticated successfully (i.e., the connection was ready for Instant + Tethering to exchange protocol messages). + </summary> +</histogram> + +<histogram name="InstantTethering.HostScanBatchDuration" units="ms"> + <owner>hansberry@chromium.org</owner> + <summary> + The duration of a batch of host scans. A batch is defined as a series of one + or host scans separated by no more than one minute. + + For example, if a scan occurs then stops and does not start back up again, + the metric logged would be the amount of time taken for that scan. However, + if a scan finishes and a new scan starts up again less than a minute after + the previous scan finished, the metric logged would be the time difference + between the start of the first scan and the finish of the second scan. </summary> </histogram> <histogram name="InstantTethering.HostScanResult" enum="InstantTethering_HostScanResult"> - <owner>hansberry@chromium.com</owner> + <owner>hansberry@chromium.org</owner> <summary> Provides a breakdown of the results of each host scan. This metric is recorded after each host scan. @@ -28433,6 +31276,24 @@ </summary> </histogram> +<histogram name="InstantTethering.HotspotUsageDuration" units="ms"> + <owner>hansberry@chromium.org</owner> + <summary> + The duration of time between the start and end of a Tether connection. + Timing starts when the device connects to the Wi-Fi hotspot and ends when + the device becomes disconnected from the Wi-Fi hotspot. + </summary> +</histogram> + +<histogram name="InstantTethering.NotificationInteractionType" + enum="InstantTethering_NotificationInteractionType"> + <owner>hansberry@chromium.org</owner> + <summary> + Counts the number of interactions a user has with each of the Instant + Tethering notifications. + </summary> +</histogram> + <histogram name="InstantTethering.Performance.AdvertisementToConnectionDuration" units="ms"> @@ -28462,6 +31323,15 @@ </summary> </histogram> +<histogram name="InstantTethering.Performance.ConnectToHostDuration" units="ms"> + <owner>hansberry@chromium.org</owner> + <summary> + The duration of time it takes for the client to connect to the host, from + the moment the user taps 'Connect', until the client connects to the host's + hotspot. This does not include timeouts. + </summary> +</histogram> + <histogram name="InstantTethering.Performance.ConnectToHotspotDuration" units="ms"> <owner>hansberry@chromium.org</owner> @@ -28501,6 +31371,37 @@ </summary> </histogram> +<histogram name="InstantTethering.SessionCompletionReason" + enum="InstantTethering_SessionCompletionReason"> + <owner>hansberry@chromium.org</owner> + <summary> + Provides a breakdown of how each Tether session ended. A session begins when + a device is first connected to a host's hotspot, and ends when the device is + no longer connected to the hotspot. This metric is recorded at the end of + each session. + </summary> +</histogram> + +<histogram name="InstantTethering.UserPreference.OnStartup" + enum="BooleanEnabled"> + <owner>hansberry@chromium.org</owner> + <summary> + Provides the count of the number of users who have the Instant Tethering + toggle enabled vs. disabled on startup. This metric is logged each time a + user logs into a Chromebook. + </summary> +</histogram> + +<histogram name="InstantTethering.UserPreference.OnToggle" + enum="BooleanEnabled"> + <owner>hansberry@chromium.org</owner> + <summary> + Provides the count of the number of times users have enabled or disabled the + user preference for Mobile data. This metric is logged each time the value + is toggled. + </summary> +</histogram> + <histogram name="interstitial.authority_invalid_time" units="ms"> <obsolete> Removed on 8/1/13. @@ -28722,6 +31623,9 @@ <histogram name="interstitial.ssl.expiration_and_decision.nonoverridable" enum="SSLIsExpiredAndDecision"> + <obsolete> + Deprecated Dec 2017 (M65). + </obsolete> <owner>jww@chromium.org</owner> <summary> Records when a user has made a decision to proceed on a nonoverridable SSL @@ -28732,6 +31636,9 @@ <histogram name="interstitial.ssl.expiration_and_decision.overridable" enum="SSLIsExpiredAndDecision"> + <obsolete> + Deprecated Dec 2017 (M65). + </obsolete> <owner>jww@chromium.org</owner> <summary> Records when a user has made a decision to proceed on an overridable SSL @@ -28741,6 +31648,9 @@ </histogram> <histogram name="interstitial.ssl.good_cert_seen" enum="SSLGoodCertSeenEvent"> + <obsolete> + Deprecated Nov 2017 (M64). + </obsolete> <owner>jww@chromium.org</owner> <summary> Emitted when a good certificate is seen, specifying whether the user already @@ -28748,6 +31658,17 @@ </summary> </histogram> +<histogram name="interstitial.ssl.good_cert_seen_type_is_frame" enum="Boolean"> + <obsolete> + Deprecated December 2017 (M65). + </obsolete> + <owner>jam@chromium.org</owner> + <summary> + Whether the resource type for a request that succeeded with a good cert and + revoked a certificate exception is for a frame (as opposed to subresource). + </summary> +</histogram> + <histogram name="interstitial.ssl.severity_score.authority_invalid" units="%"> <obsolete> Deprecated Jan 2015 (M42). @@ -28778,6 +31699,14 @@ </summary> </histogram> +<histogram name="interstitial.ssl.visited_site_after_warning" enum="Boolean"> + <owner>carlosil@chromium.org</owner> + <summary> + Records when a user visits a site after clicking through a certificate + warning. + </summary> +</histogram> + <histogram name="interstitial.ssl_accept_time" units="ms"> <obsolete> Removed on 8/1/13. @@ -28856,6 +31785,16 @@ <summary>Network channel used for invalidations.</summary> </histogram> +<histogram name="IOS.CanonicalURLResult" enum="CanonicalURLResult"> + <obsolete> + Deprecated 2018-01. As of M65 use Mobile.CanonicalURLResult. + </obsolete> + <owner>gchatz@chromium.org</owner> + <summary> + The result of the operation to retrieve the page's canonical URL. + </summary> +</histogram> + <histogram name="IOS.ContentExtension.DisplayCount" units="count"> <owner>olivierrobin@chromium.org</owner> <summary> @@ -28880,6 +31819,21 @@ </summary> </histogram> +<histogram name="IOS.Handoff.Origin" enum="IOSHandoffOrigin"> + <owner>erikchen@chromium.org</owner> + <summary> + This event is recorded each time a Handoff is received by Chrome on iOS. The + enumeration indicates the source of the Handoff. + </summary> +</histogram> + +<histogram name="IOS.IPHBubbleDismissalReason" enum="BubbleDismissalReason"> + <owner>gchatz@chromium.org</owner> + <summary> + Tracks the reason for why the In Product Help bubble was dismissed. + </summary> +</histogram> + <histogram name="IOS.MailtoURLRewritten" enum="Boolean"> <owner>pkl@chromium.org</owner> <summary> @@ -28896,6 +31850,50 @@ </summary> </histogram> +<histogram name="IOS.PageLoadCount.Counts" + enum="IOSPageLoadCountNavigationType"> + <owner>danyao@chromium.org</owner> + <summary>The number of navigation started events by navigation type.</summary> +</histogram> + +<histogram name="IOS.PageLoadCount.LoadingStarted"> + <owner>danyao@chromium.org</owner> + <summary> + The "true" value of this boolean histogram counts the number of + page loading started events. The "false" value will never be seen. + </summary> +</histogram> + +<histogram name="IOS.PageLoadCountMigration.Counts" + enum="IOSPageLoadCountNavigationType"> + <obsolete> + Deprecated 2017-11. + </obsolete> + <owner>danyao@chromium.org</owner> + <summary> + Counts different types of navigation and loading events that are relevant to + counting page loads. + </summary> +</histogram> + +<histogram name="IOS.PageLoadTiming.OmnibarToPageLoaded" units="ms"> + <owner>danyao@chromium.org</owner> + <summary> + Measures the time from the end of user input in the omnibox to when the page + is fully loaded. Only measures page loads initiated by user typing a URL or + selecting a suggested entry from the URL bar. + </summary> +</histogram> + +<histogram name="IOS.RepeatedExternalAppPromptResponse" + enum="IOSRepeatedExternalAppPromptResponse"> + <owner>mrefaat@chromium.org</owner> + <summary> + The user reaction to the prompt that appears when a website tries to open an + external application repeatedly. + </summary> +</histogram> + <histogram name="IOS.SearchExtension.Action" enum="IOSSearchExtensionAction"> <owner>olivierrobin@chromium.org</owner> <summary>The action selected by the user in the Search Extension.</summary> @@ -28939,11 +31937,46 @@ </summary> </histogram> +<histogram name="IOS.SharePageLatency" units="ms"> + <owner>gchatz@chromium.org</owner> + <summary> + The latency in milliseconds between the start of the Share Page operation + and when the UI is ready to be presented. + </summary> +</histogram> + <histogram name="IOS.Spotlight.Action" enum="IOSSpotlightAction"> <owner>olivierrobin@chromium.org</owner> <summary>The Spotlight Action pressed by the user.</summary> </histogram> +<histogram name="IOS.Spotlight.Availability" enum="IOSSpotlightAvailability"> + <owner>olivierrobin@chromium.org</owner> + <summary> + Tracks the availability of the Spotlight indexation on the device. It is + logged once at each cold start. Note: Spotlight may be available on the + device but disabled by the user. + </summary> +</histogram> + +<histogram name="IOS.Spotlight.BookmarksIndexingDuration" units="ms"> + <owner>olivierrobin@chromium.org</owner> + <summary>Time spent in Spotlight initial indexation of bookmarks.</summary> +</histogram> + +<histogram name="IOS.Spotlight.BookmarksInitialIndexSize"> + <owner>olivierrobin@chromium.org</owner> + <summary>Number of bookmarks indexed during initial indexation.</summary> +</histogram> + +<histogram name="IOS.Spotlight.Origin" enum="IOSSpotlightOrigin"> + <owner>olivierrobin@chromium.org</owner> + <summary> + This event is recorded each time a Chrome Spotlight entry is selected by the + user. The enumeration indicates the nature of the Spotlight entry. + </summary> +</histogram> + <histogram name="IPC.AttachmentBrokerPrivileged.BrokerAttachmentError" enum="IPCAttachmentBrokerPrivilegedBrokerAttachmentError"> <owner>erikchen@chromium.org</owner> @@ -28965,8 +31998,7 @@ <histogram name="JSDialogs.CharacterCount" units="characters"> <owner>avi@chromium.org</owner> <summary> - The count of the number of characters in JavaScript dialog messages grouped - by site engagement score. + The count of the number of characters in JavaScript dialog messages. </summary> </histogram> @@ -29016,7 +32048,7 @@ </summary> </histogram> -<histogram name="JSDialogs.DismissalCause" +<histogram base="true" name="JSDialogs.DismissalCause" enum="JavaScriptDialogDismissalCause"> <owner>avi@chromium.org</owner> <summary>The cause of dismissal of JavaScript dialogs.</summary> @@ -29052,7 +32084,7 @@ </summary> </histogram> -<histogram name="JSDialogs.IsForemost" enum="BooleanForemost"> +<histogram base="true" name="JSDialogs.IsForemost" enum="BooleanForemost"> <owner>avi@chromium.org</owner> <summary> For dialogs, whether or not they were spawned by a tab that was foremost. @@ -29067,7 +32099,15 @@ </summary> </histogram> +<histogram base="true" name="JSDialogs.Scheme" enum="NavigationScheme"> + <owner>avi@chromium.org</owner> + <summary>The scheme of the URL showing a JavaScript dialog.</summary> +</histogram> + <histogram name="JSDialogs.SiteEngagementOfBeforeUnload" units="%"> + <obsolete> + Deprecated 2017-10. + </obsolete> <owner>avi@chromium.org</owner> <summary> The site engagement values of sites showing onbeforeunload dialogs. Logged @@ -29075,7 +32115,7 @@ </summary> </histogram> -<histogram name="JSDialogs.SiteEngagementOfDialogs" units="%"> +<histogram base="true" name="JSDialogs.SiteEngagementOfDialogs" units="%"> <obsolete> Deprecated 2016-10. Site engagement needed to be measured in small buckets anyway so it was never high-resolution enough for use. @@ -29129,6 +32169,20 @@ </summary> </histogram> +<histogram name="LanguageSettings.Actions" enum="LanguageSettingsActionType"> + <owner>googleo@chromium.org</owner> + <summary> + The actions taken on languages settings, recorded every time they happen. + This histogram will record every single event that happens separately. + </summary> +</histogram> + +<histogram name="LanguageSettings.PageImpression" + enum="LanguageSettingsPageType"> + <owner>googleo@chromium.org</owner> + <summary>The type of panes which language settings loads.</summary> +</histogram> + <histogram name="LanguageUsage.AcceptLanguage" enum="LanguageCode"> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <summary>Accept languages.</summary> @@ -29200,6 +32254,14 @@ <summary>The different ways Chrome is launched.</summary> </histogram> +<histogram name="Launch.WebAppDisplayMode" enum="WebAppDisplayMode"> + <owner>piotrs@chromium.org</owner> + <summary> + Records the display mode (as defined in the Web App Manifest spec) at the + launch of the Added to Home screen or installed Web App (including WebAPKs). + </summary> +</histogram> + <histogram name="Layout.MicroSecondsPerComplexText" units="microseconds"> <owner>benjhayden@chromium.org</owner> <summary> @@ -29258,6 +32320,23 @@ </summary> </histogram> +<histogram name="Layout.ScrollAnchor.RestorationStatus" + enum="ScrollAnchorRestorationStatus"> + <owner>pnoland@chromium.org</owner> + <summary> + Records the status of attempts to restore a serialized scroll anchor. + </summary> +</histogram> + +<histogram name="Layout.ScrollAnchor.SerializedAnchorSelectorLength" + units="characters"> + <owner>pnoland@chromium.org</owner> + <summary> + The number of characters in the selector computed for a serialized scroll + anchor. Recorded when a scroll anchor is serialized. + </summary> +</histogram> + <histogram name="Layout.ScrollAnchor.SuppressedBySanaclap" enum="BooleanHit"> <owner>ymalik@chromium.org</owner> <summary> @@ -29266,16 +32345,59 @@ </summary> </histogram> +<histogram name="Layout.ScrollAnchor.TimeToComputeAnchorNodeSelector" + units="microseconds"> + <owner>pnoland@chromium.org</owner> + <summary> + The time it took to compute the selector of a serialized anchor element. + </summary> +</histogram> + <histogram name="Layout.ScrollAnchor.TimeToFindAnchor" units="microseconds"> <owner>ymalik@chromium.org</owner> <summary>The time it took to find a suitable anchor element.</summary> </histogram> +<histogram name="Layout.ScrollAnchor.TimeToRestoreAnchor" units="microseconds"> + <owner>pnoland@chromium.org</owner> + <summary> + The time it took to restore the scroll anchor using the serialized anchor + element. + </summary> +</histogram> + <histogram name="LevelDB.Open" enum="LevelDBStatus"> <owner>cmumford@chromium.org</owner> <summary>The result of an open attempt of a leveldb.</summary> </histogram> +<histogram name="LevelDB.SharedCache.BytesUsed" units="Bytes"> + <obsolete> + Deprecated 2017-10. Superceded by LevelDB.SharedCache.KBUsed. + </obsolete> + <owner>cmumford@chromium.org</owner> + <summary> + The estimated size (in bytes) of the leveldb shared cache. Recorded once per + UMA ping. + </summary> +</histogram> + +<histogram name="LevelDB.SharedCache.DBCount" units="count"> + <owner>cmumford@chromium.org</owner> + <summary> + The number of databases currently using the shared block cache. Recorded + once per UMA ping. + </summary> +</histogram> + +<histogram name="LevelDB.SharedCache.KBUsed" units="KB"> + <owner>cmumford@chromium.org</owner> + <summary> + The estimated size (in kilobytes) of the leveldb shared cache. Recorded once + per UMA ping. + </summary> +</histogram> + <histogram name="LevelDBEnv.All.SafeThreadAccess" units="accesses"> <obsolete> Deprecated 2013-10. No thread-unsafety was found. @@ -29315,7 +32437,7 @@ </summary> </histogram> -<histogram name="LevelDBEnv.IOError.NewLogger" enum="OSAgnosticErrno"> +<histogram name="LevelDBEnv.IOError.NewLogger" enum="PopularOSErrno"> <obsolete> Deprecated 2015-05. As of M43 use LevelDBEnv.IOError.BFE.NewLogger. </obsolete> @@ -29323,7 +32445,7 @@ <summary>Errno of errors encountered in NewLogger.</summary> </histogram> -<histogram name="LevelDBEnv.IOError.NewSequentialFile" enum="OSAgnosticErrno"> +<histogram name="LevelDBEnv.IOError.NewSequentialFile" enum="PopularOSErrno"> <obsolete> Deprecated 2015-05. As of M43 use LevelDBEnv.IOError.BFE.NewSequentialFile. </obsolete> @@ -29341,7 +32463,7 @@ </summary> </histogram> -<histogram name="LevelDBEnv.IOError.WritableFileAppend" enum="OSAgnosticErrno"> +<histogram name="LevelDBEnv.IOError.WritableFileAppend" enum="PopularOSErrno"> <obsolete> Deprecated 2015-05. As of M43 use LevelDBEnv.IOError.BFE.WritableFileAppend. </obsolete> @@ -29349,7 +32471,7 @@ <summary>Errno of errors encountered in WritableFileAppend.</summary> </histogram> -<histogram name="LevelDBEnv.IOError.WritableFileFlush" enum="OSAgnosticErrno"> +<histogram name="LevelDBEnv.IOError.WritableFileFlush" enum="PopularOSErrno"> <obsolete> Deprecated 2015-05. As of M43 use LevelDBEnv.IOError.BFE.WritableFileFlush. </obsolete> @@ -29721,6 +32843,15 @@ </summary> </histogram> +<histogram name="LocalStorage.RendererAreaCacheHit" + enum="LocalStorageRendererAreaCacheHitEnum"> + <owner>ssid@chromium.org</owner> + <summary> + The renderer side cache hit rate metrics for new HTML5 LocalStorage DB + opened. + </summary> +</histogram> + <histogram name="LocalStorage.RendererLocalStorageSizeInKB" units="KB"> <owner>michaeln@chromium.org</owner> <summary> @@ -29815,6 +32946,15 @@ </summary> </histogram> +<histogram name="LocalStorageContext.MigrationFixUpNeeded" enum="Boolean"> + <owner>mek@chromium.org</owner> + <summary> + Whether or not any fixes needed to be made to localstorage data, as a result + of bugs in the migration code in M61/M62. Recorded every time the browser + loads an initial snapshot of the localstorage data for an origin. + </summary> +</histogram> + <histogram name="LocalStorageContext.OpenError" enum="LocalStorageOpenError"> <owner>mek@chromium.org</owner> <summary> @@ -30325,6 +33465,15 @@ </summary> </histogram> +<histogram name="Media.Audio.Capture.InputStreamDuration" units="ms"> + <owner>maxmorin@chromium.org</owner> + <summary> + This histogram measures the duration of every input stream, as seen from the + renderer. It counts from when it has been successfully started, until it is + stopped. Streams that fail to start are not logged. + </summary> +</histogram> + <histogram name="Media.Audio.Capture.LargestGlitchMs" units="ms"> <owner>grunell@chromium.org</owner> <summary> @@ -30369,6 +33518,17 @@ </summary> </histogram> +<histogram name="Media.Audio.Capture.Win.InitError.FormatRelated" + enum="AudioStreamFormatRelatedInitError"> + <owner>grunell@chromium.org</owner> + <summary> + Errors from IAudioClient::Initialize() in + WASAPIAudioInputStream::InitializeAudioEngine on Windows that are related to + the audio format. Each error is split by whether format conversion was used + or not. + </summary> +</histogram> + <histogram name="Media.Audio.Capture.Win.Open" enum="AudioStreamOpenResult"> <owner>tommi@chromium.org</owner> <summary> @@ -30376,6 +33536,26 @@ </summary> </histogram> +<histogram name="Media.Audio.CoreAudioDispatchOverrideInitResult" + enum="CoreAudioDispatchOverrideInitResult"> + <owner>ossu@chromium.org</owner> + <summary> + Tracks support and initialization success/failure of the CoreAudio dispatch + override hotfix. Logged during initialization of AudioManagerMac. The fix is + not supported on macOS earlier than version 10.10. + </summary> +</histogram> + +<histogram name="Media.Audio.CoreAudioDispatchOverrideLookupEvent" + enum="CoreAudioDispatchOverrideLookupEvent"> + <owner>ossu@chromium.org</owner> + <summary> + Logged whenever the CoreAudio dispatch override hotfix needs to look up the + calling function using dladdr(). Once ResumeIO and PauseIO have been + identified, no more lookups should be performed during the session. + </summary> +</histogram> + <histogram name="Media.Audio.InputBufferSizeWasChangedAudioWorkedMac" enum="BooleanChanged"> <owner>henrika@chromium.org</owner> @@ -30401,6 +33581,10 @@ <histogram name="Media.Audio.InputDevicePropertyChangedMac" enum="AudioDevicePropertyResult"> + <obsolete> + Deprecated Feb 2018. Was put in place to debug missing callback issues that + have since been resolved. + </obsolete> <owner>henrika@chromium.org</owner> <summary> Lists device properties that have been changed during an audio input stream @@ -30412,6 +33596,10 @@ <histogram name="Media.Audio.InputDevicePropertyChangedStartupFailedMac" enum="AudioDevicePropertyResult"> + <obsolete> + Deprecated Feb 2018. Was put in place to debug missing callback issues that + have since been resolved. + </obsolete> <owner>henrika@chromium.org</owner> <summary> Lists device properties that have been changed during an audio input stream @@ -30509,6 +33697,18 @@ </summary> </histogram> +<histogram name="Media.Audio.OutputStreamsCanceledByBrowser" units="streams"> + <owner>maxmorin@chromium.org</owner> + <summary> + When a mojo audio stream factory is destructed, the streams it created are + also destructed. This is a potential source of stat differences between the + new mojo code and the old Chrome IPC code, where streams could potentially + stick around until the destruction of the owning RenderProcessHost. This + histogram measures how many output streams are destructed each time a mojo + output stream factory is destructed. + </summary> +</histogram> + <histogram name="Media.Audio.PhysicalProcessorsMac"> <owner>henrika@chromium.org</owner> <summary> @@ -30688,6 +33888,15 @@ </summary> </histogram> +<histogram name="Media.Audio.Render.OutputStreamDuration" units="ms"> + <owner>maxmorin@chromium.org</owner> + <summary> + This histogram measures the duration of every output stream, as seen from + the renderer. It counts from when it has been successfully started, until it + is stopped. Streams that fail to start are not logged. + </summary> +</histogram> + <histogram name="Media.Audio.Render.SinkCache.GetOutputDeviceInfoCacheUtilization" enum="GetOutputDeviceInfoCacheHit"> @@ -30788,6 +33997,9 @@ </histogram> <histogram name="Media.AudioCapturerRepetition" units="ms"> + <obsolete> + Deprecated as of Jan 2018. + </obsolete> <owner>minyue@chromium.org</owner> <summary> Captures bit-exact audio repetitions with pre-defined look back time. As @@ -30833,7 +34045,18 @@ <histogram name="Media.AudioInputControllerSessionSilenceReport" enum="AudioInputSilenceReport"> <owner>grunell@chromium.org</owner> - <summary>The silence report for an audio input device session.</summary> + <summary> + Every 15 seconds during the lifetime of an audio input stream, the sound + level is measured, see AudioInputController::CheckAudioPower(). If the level + is below a certain threshold, it's considered "silence". Otherwise + it's considered "audio". This metric shows whether there was only + silence, only audio, or both, during the lifetime of a stream. If logged + before the first measurement, i.e. if the lifetime is less than 15 seconds, + "no measurement" is reported. If there is no audio data provided + by the OS during the lifetime of the stream, for example because of a bug, + measurements will not be performed and "no measurement" is + reported. + </summary> </histogram> <histogram name="Media.AudioInputDeviceManager" units="ms"> @@ -30846,6 +34069,36 @@ <summary>Measures the time taken for AudioOutputController::</summary> </histogram> +<histogram name="Media.AudioOutputController.CallbackError" enum="BooleanError"> + <owner>maxmorin@chromium.org</owner> + <summary> + A boolean that reflects whether or not an error was reported during audio + rendering, reported after a stream has stopped, if it was started. + </summary> +</histogram> + +<histogram name="Media.AudioOutputController.ProxyStreamCreationResult" + enum="AudioOutputStreamCreationResult"> + <owner>maxmorin@chromium.org</owner> + <summary> + Whether an AudioOutputController succeeded in creating and opening an output + stream proxy. Only logged for the initial creation, subsequent re-creations + due to device change events are logged in the + Media.AudioOutputController.ProxyStreamCreationResultForDeviceChange + histogram. + </summary> +</histogram> + +<histogram + name="Media.AudioOutputController.ProxyStreamCreationResultForDeviceChange" + enum="AudioOutputStreamCreationResult"> + <owner>maxmorin@chromium.org</owner> + <summary> + Whether an AudioOutputController succeeded in creating and opening an output + stream proxy after receiving a default device change event. + </summary> +</histogram> + <histogram name="Media.AudioOutputControllerDataNotReady" units="ms"> <owner>dalecurtis@chromium.org</owner> <summary> @@ -30862,6 +34115,97 @@ </summary> </histogram> +<histogram name="Media.AudioOutputResampler.OpenLowLatencyStream" + enum="AudioOutputResamplerLowLatencyOpenStreamResult"> + <owner>olka@chromium.org</owner> + <summary> + Whether a low latency stream to be rendered through the resampler was opened + successfully or which type of fallback stream was used instead. In case a + fake fallback stream is used it means audio rendered through the resampler + will be muted. In case fallback fails entirely, renderer callback error will + be signalled. + </summary> +</histogram> + +<histogram + name="Media.AudioOutputStreamProxy.GetPreferredOutputStreamParametersWin.CreateClientResult" + enum="Hresult"> + <owner>marinaciocea@chromium.org</owner> + <summary> + This histogram is the 3nd potential failure step in + CoreAudioUtil::GetPreferredAudioParameters. The success% of this histogram + is input for + Media.AudioOutputStreamProxy.GetPreferredOutputStreamParametersWin.GetMixFormatResult + histogram. + </summary> +</histogram> + +<histogram + name="Media.AudioOutputStreamProxy.GetPreferredOutputStreamParametersWin.CreateDeviceEnumeratorResult" + enum="Hresult"> + <owner>marinaciocea@chromium.org</owner> + <summary> + This histogram is the 1st potential failure step in + CoreAudioUtil::GetPreferredAudioParameters. The success% of this histogram + is input for + Media.AudioOutputStreamProxy.GetPreferredOutputStreamParametersWin.CreateDeviceResult + histogram. + </summary> +</histogram> + +<histogram + name="Media.AudioOutputStreamProxy.GetPreferredOutputStreamParametersWin.CreateDeviceResult" + enum="Hresult"> + <owner>marinaciocea@chromium.org</owner> + <summary> + This histogram is the 2nd potential failure step in + CoreAudioUtil::GetPreferredAudioParameters. The success% of this histogram + is input for + Media.AudioOutputStreamProxy.GetPreferredOutputStreamParametersWin.CreateClientResult + histogram. + </summary> +</histogram> + +<histogram + name="Media.AudioOutputStreamProxy.GetPreferredOutputStreamParametersWin.GetDevicePeriodResult" + enum="Hresult"> + <owner>marinaciocea@chromium.org</owner> + <summary> + This histogram is the last potential failure step in + CoreAudioUtil::GetPreferredAudioParameters. + </summary> +</histogram> + +<histogram + name="Media.AudioOutputStreamProxy.GetPreferredOutputStreamParametersWin.GetMixFormatResult" + enum="Hresult"> + <owner>marinaciocea@chromium.org</owner> + <summary> + This histogram is the 4nd potential failure step in + CoreAudioUtil::GetPreferredAudioParameters. The success% of this histogram + is input for + Media.AudioOutputStreamProxy.GetPreferredOutputStreamParametersWin.GetDevicePeriodResult + histogram. + </summary> +</histogram> + +<histogram name="Media.AudioOutputStreamProxy.StreamFormat" + enum="AudioOutputProxyStreamFormat"> + <owner>olka@chromium.org</owner> + <summary> + Records format used by AudioManager to create audio output stream proxy. If + a fake stream is created it results in muted audio playback. + + On Windows, the failure reasons that can lead to fake stream creation are + tracked with the following histograms: + Media.AudioOutputStreamProxy.GetPreferredOutputStreamParametersWin.CreateDeviceEnumeratorResult + Media.AudioOutputStreamProxy.GetPreferredOutputStreamParametersWin.CreateDeviceResult + Media.AudioOutputStreamProxy.GetPreferredOutputStreamParametersWin.CreateClientResult + Media.AudioOutputStreamProxy.GetPreferredOutputStreamParametersWin.GetMixFormatResult + Media.AudioOutputStreamProxy.GetPreferredOutputStreamParametersWin.GetDevicePeriodResult + </summary> +</histogram> + <histogram name="Media.AudioRendererAudioGlitches" enum="AudioGlitchResult"> <owner>henrika@chromium.org</owner> <summary> @@ -31050,6 +34394,10 @@ <histogram name="Media.ChromeArcVideoDecodeAccelerator.InitializeResult" enum="ArcVideoDecodeAcceleratorResult"> + <obsolete> + Deprecated as of Dec 18, 2017. Replaced by + Media.GpuArcVideoDecodeAccelerator.InitializeResult. + </obsolete> <owner>johnylin@chromium.org</owner> <summary> Counts of status values returned from calls to @@ -31132,6 +34480,30 @@ </summary> </histogram> +<histogram name="Media.Controls.Overflow.TimeToAction" units="seconds"> + <owner>beccahughes@chromium.org</owner> + <owner>media-dev@chromium.org</owner> + <summary> + Records the amount of time the overflow menu is displayed until the user + clicked on a menu item. The overflow menu is shown by clicking the three + dots on the media controls and is used to show more controls when there is + not enough space. This histogram will record up to 100 seconds with accuracy + to the second. + </summary> +</histogram> + +<histogram name="Media.Controls.Overflow.TimeToDismiss" units="seconds"> + <owner>beccahughes@chromium.org</owner> + <owner>media-dev@chromium.org</owner> + <summary> + Records the amount of time the overflow menu is displayed until the user + dismissed the menu without clicking on a menu item. The overflow menu is + shown by clicking the three dots on the media controls and is used to show + more controls when there is not enough space. This histogram will record up + to 100 seconds with accuracy to the second. + </summary> +</histogram> + <histogram name="Media.Controls.Show" enum="MediaControlsShowReason"> <obsolete> Deprecated May 19 2016 in favor of Media.Controls.Show.{Audio,Video} @@ -31291,6 +34663,28 @@ </summary> </histogram> +<histogram base="true" name="Media.EME" enum="CdmPromiseResult"> + <owner>sandersd@chromium.org</owner> + <summary>Result of EME promises that were handled by Chromium code.</summary> +</histogram> + +<histogram base="true" name="Media.EME.addKey" enum="MediaKeyException"> + <obsolete> + Deprecated 02/2016 with removal of prefixed EME. + </obsolete> + <owner>xhwang@chromium.org</owner> + <summary>addKey result</summary> +</histogram> + +<histogram base="true" name="Media.EME.cancelKeyRequest" + enum="MediaKeyException"> + <obsolete> + Deprecated 02/2016 with removal of prefixed EME. + </obsolete> + <owner>xhwang@chromium.org</owner> + <summary>cancelKeyRequest result.</summary> +</histogram> + <histogram name="Media.EME.CdmFileIO.FileSizeKBOnError" units="KB"> <owner>xhwang@chromium.org</owner> <summary> @@ -31308,6 +34702,16 @@ </summary> </histogram> +<histogram name="Media.EME.CdmFileIO.ReadTime" units="ms"> + <owner>media-dev@chromium.org</owner> + <summary>The actual time spent by the CDM reading a file.</summary> +</histogram> + +<histogram name="Media.EME.CdmFileIO.WriteTime" units="ms"> + <owner>media-dev@chromium.org</owner> + <summary>The actual time spent by the CDM writing a file.</summary> +</histogram> + <histogram name="Media.EME.CdmHostVerificationStatus" enum="CdmHostVerificationStatus"> <owner>media-dev@chromium.org</owner> @@ -31325,66 +34729,43 @@ </summary> </histogram> -<histogram name="Media.EME.ClearKey" enum="CdmPromiseResult"> - <owner>sandersd@chromium.org</owner> +<histogram name="Media.EME.CdmLoadErrorCode" units="code"> + <owner>media-dev@chromium.org</owner> + <summary>The error code of a library CDM load failure.</summary> +</histogram> + +<histogram name="Media.EME.CdmLoadResult" enum="CdmLoadResult"> + <owner>media-dev@chromium.org</owner> + <summary>The result from an attempt to load a library CDM.</summary> +</histogram> + +<histogram name="Media.EME.CdmLoadTime" units="ms"> + <owner>media-dev@chromium.org</owner> + <summary>The time spent to load a library CDM.</summary> +</histogram> + +<histogram base="true" name="Media.EME.CreateCdm" enum="BooleanSuccess"> + <owner>xhwang@chromium.org</owner> <summary> - Result of promises for Clear Key key systems that were handled by Chromium - code. + Whether the CDM instance is created successfully. Reported each time a CDM + instance creation is attempted, usually as a result of Javascript call of + createMediaKeys(). </summary> </histogram> -<histogram name="Media.EME.ClearKey.addKey" enum="MediaKeyException"> - <obsolete> - Deprecated 02/2016 with removal of prefixed EME. - </obsolete> +<histogram base="true" name="Media.EME.CreateCdmTime" units="ms"> <owner>xhwang@chromium.org</owner> - <summary>addKey result using the Clear Key key system.</summary> + <summary>The time it takes to create the CDM instance.</summary> </histogram> -<histogram name="Media.EME.ClearKey.cancelKeyRequest" enum="MediaKeyException"> - <obsolete> - Deprecated 02/2016 with removal of prefixed EME. - </obsolete> - <owner>xhwang@chromium.org</owner> - <summary>cancelKeyRequest result using the Clear Key key system.</summary> -</histogram> - -<histogram name="Media.EME.ClearKey.CreateCdmTime" units="ms"> +<histogram name="Media.EME.EncryptedEvent" enum="BooleanEncryptedEvent"> <owner>xhwang@chromium.org</owner> <summary> - The time it takes to create the CDM instance for Clear Key key system. - </summary> -</histogram> - -<histogram name="Media.EME.ClearKey.generateKeyRequest" - enum="MediaKeyException"> - <obsolete> - Deprecated 02/2016 with removal of prefixed EME. - </obsolete> - <owner>xhwang@chromium.org</owner> - <summary>generateKeyRequest result using the Clear Key key system.</summary> -</histogram> - -<histogram name="Media.EME.ClearKey.KeyAdded"> - <obsolete> - Deprecated 02/2016 with removal of prefixed EME. - </obsolete> - <owner>xhwang@chromium.org</owner> - <summary>KeyAdded event count using the Clear Key key system.</summary> -</histogram> - -<histogram name="Media.EME.ClearKey.KeyError" enum="MediaKeyError"> - <obsolete> - Deprecated 02/2016 with removal of prefixed EME. - </obsolete> - <owner>xhwang@chromium.org</owner> - <summary>KeyError event count using the Clear Key key system.</summary> -</histogram> - -<histogram name="Media.EME.ClearKey.TimeTo" units="ms"> - <owner>xhwang@chromium.org</owner> - <summary> - The time it takes to resolve a CDM promise for Clear Key key system. + Whether EME encrypted event has been fired. Every time a WebMediaPlayerImpl + object is created a "false" value is reported to provide a + baseline. Every time an encrypted event is fired, a "true" value + will be reported. Note that it is possible to have multiple encrypted events + during the lifetime of a WebMediaPlayerImpl object. </summary> </histogram> @@ -31398,6 +34779,15 @@ </summary> </histogram> +<histogram base="true" name="Media.EME.generateKeyRequest" + enum="MediaKeyException"> + <obsolete> + Deprecated 02/2016 with removal of prefixed EME. + </obsolete> + <owner>xhwang@chromium.org</owner> + <summary>generateKeyRequest result.</summary> +</histogram> + <histogram name="Media.EME.IsIncognito" enum="BooleanIncognito"> <owner>xhwang@chromium.org</owner> <summary> @@ -31407,6 +34797,28 @@ </summary> </histogram> +<histogram base="true" name="Media.EME.KeyAdded"> + <obsolete> + Deprecated 02/2016 with removal of prefixed EME. + </obsolete> + <owner>xhwang@chromium.org</owner> + <summary>KeyAdded event count.</summary> +</histogram> + +<histogram base="true" name="Media.EME.KeyError" enum="MediaKeyError"> + <obsolete> + Deprecated 02/2016 with removal of prefixed EME. + </obsolete> + <owner>xhwang@chromium.org</owner> + <summary>KeyError event count.</summary> +</histogram> + +<histogram base="true" name="Media.EME.KeyStatusSystemCode" + enum="CdmSystemCode"> + <owner>media-dev@chromium.org</owner> + <summary>System code count associated with key status.</summary> +</histogram> + <histogram name="Media.EME.KeySystemSupport.Widevine" enum="MediaKeySystemSupportStatus"> <obsolete> @@ -31419,7 +34831,32 @@ </summary> </histogram> +<histogram base="true" name="Media.EME.LibraryCdmAvailable" + enum="BooleanAvailable"> + <owner>media-dev@chromium.org</owner> + <summary> + Whether the CDM is available for the key system or not. In normal cases, + this is reported once per render process if the EME API is used. In rare + cases it could be reported more than once if the CDM is not available and + then is component updated. + </summary> +</histogram> + +<histogram name="Media.EME.MojoCdm.ConnectionError" + enum="BooleanConnectionError"> + <owner>media-dev@chromium.org</owner> + <summary> + Whether connection error has happened for MojoCdm. Every time a MojoCdm + object is created a "false" value is reported to provide a + baseline. Every time a mojo connection error happened, a "true" + value will be reported, which typically means a remote CDM process crash. + </summary> +</histogram> + <histogram name="Media.EME.NeedKey"> + <obsolete> + Renamed to Media.EME.EncryptedEvent in 10/2017. + </obsolete> <owner>xhwang@chromium.org</owner> <summary>EME NeedKey event count.</summary> </histogram> @@ -31442,148 +34879,14 @@ </summary> </histogram> -<histogram name="Media.EME.Unknown" enum="CdmPromiseResult"> - <owner>sandersd@chromium.org</owner> - <summary> - Result of promises for unknown key systems that were handled by Chromium - code. - </summary> -</histogram> - -<histogram name="Media.EME.Unknown.addKey" enum="MediaKeyException"> - <obsolete> - Deprecated 02/2016 with removal of prefixed EME. - </obsolete> +<histogram base="true" name="Media.EME.SystemCode" enum="CdmSystemCode"> <owner>xhwang@chromium.org</owner> - <summary>addKey result using an unknown key system.</summary> + <summary>System code count in promise rejection.</summary> </histogram> -<histogram name="Media.EME.Unknown.cancelKeyRequest" enum="MediaKeyException"> - <obsolete> - Deprecated 02/2016 with removal of prefixed EME. - </obsolete> +<histogram base="true" name="Media.EME.TimeTo" units="ms"> <owner>xhwang@chromium.org</owner> - <summary>cancelKeyRequest result using an unknown key system.</summary> -</histogram> - -<histogram name="Media.EME.Unknown.CreateCdmTime" units="ms"> - <owner>xhwang@chromium.org</owner> - <summary> - The time it takes to create the CDM instance for an unknown key system. - </summary> -</histogram> - -<histogram name="Media.EME.Unknown.generateKeyRequest" enum="MediaKeyException"> - <obsolete> - Deprecated 02/2016 with removal of prefixed EME. - </obsolete> - <owner>xhwang@chromium.org</owner> - <summary>generateKeyRequest result using an unknown key system.</summary> -</histogram> - -<histogram name="Media.EME.Unknown.KeyAdded"> - <obsolete> - Deprecated 02/2016 with removal of prefixed EME. - </obsolete> - <owner>xhwang@chromium.org</owner> - <summary>KeyAdded event count using an unknown key system.</summary> -</histogram> - -<histogram name="Media.EME.Unknown.KeyError" enum="MediaKeyError"> - <obsolete> - Deprecated 02/2016 with removal of prefixed EME. - </obsolete> - <owner>xhwang@chromium.org</owner> - <summary>KeyError event count using an unknown key system.</summary> -</histogram> - -<histogram name="Media.EME.Unknown.SystemCode" units="system code"> - <owner>xhwang@chromium.org</owner> - <summary>System code count using an unknown key system.</summary> -</histogram> - -<histogram name="Media.EME.Unknown.TimeTo" units="ms"> - <owner>xhwang@chromium.org</owner> - <summary> - The time it takes to resolve a CDM promise for an unknown key system. - </summary> -</histogram> - -<histogram name="Media.EME.Widevine" enum="CdmPromiseResult"> - <owner>sandersd@chromium.org</owner> - <summary> - Result of promises for Widevine key systems that were handled by Chromium - code. - </summary> -</histogram> - -<histogram name="Media.EME.Widevine.addKey" enum="MediaKeyException"> - <obsolete> - Deprecated 02/2016 with removal of prefixed EME. - </obsolete> - <owner>xhwang@chromium.org</owner> - <summary>addKey result using the Widevine key system.</summary> -</histogram> - -<histogram name="Media.EME.Widevine.cancelKeyRequest" enum="MediaKeyException"> - <obsolete> - Deprecated 02/2016 with removal of prefixed EME. - </obsolete> - <owner>xhwang@chromium.org</owner> - <summary>cancelKeyRequest result using the Widevine key system.</summary> -</histogram> - -<histogram name="Media.EME.Widevine.CreateCdmTime" units="ms"> - <owner>xhwang@chromium.org</owner> - <summary> - The time it takes to create the CDM instance for the Widevine key system. - </summary> -</histogram> - -<histogram name="Media.EME.Widevine.generateKeyRequest" - enum="MediaKeyException"> - <obsolete> - Deprecated 02/2016 with removal of prefixed EME. - </obsolete> - <owner>xhwang@chromium.org</owner> - <summary>generateKeyRequest result using the Widevine key system.</summary> -</histogram> - -<histogram name="Media.EME.Widevine.KeyAdded"> - <obsolete> - Deprecated 02/2016 with removal of prefixed EME. - </obsolete> - <owner>xhwang@chromium.org</owner> - <summary>KeyAdded event count using the Widevine key system.</summary> -</histogram> - -<histogram name="Media.EME.Widevine.KeyError" enum="MediaKeyError"> - <obsolete> - Deprecated 02/2016 with removal of prefixed EME. - </obsolete> - <owner>xhwang@chromium.org</owner> - <summary>KeyError event count using the Widevine key system.</summary> -</histogram> - -<histogram name="Media.EME.Widevine.KeyStatusSystemCode" units="system code"> - <owner>media-dev@chromium.org</owner> - <summary> - System code count associated with key status using the Widevine key system. - </summary> -</histogram> - -<histogram name="Media.EME.Widevine.SystemCode" units="system code"> - <owner>xhwang@chromium.org</owner> - <summary> - System code count in promise rejection using the Widevine key system. - </summary> -</histogram> - -<histogram name="Media.EME.Widevine.TimeTo" units="ms"> - <owner>xhwang@chromium.org</owner> - <summary> - The time it takes to resolve a CDM promise for the Widevine key system. - </summary> + <summary>The time it takes to resolve a EME promise.</summary> </histogram> <histogram name="Media.EME.Widevine.VideoCapability.HasEmptyRobustness" @@ -31596,6 +34899,49 @@ </summary> </histogram> +<histogram name="Media.Engagement.PreloadedList.CheckResult" + enum="PreloadedListCheckResult"> + <owner>beccahughes@chromium.org</owner> + <owner>media-dev@chromium.org</owner> + <summary> + Recorded when the Media Engagement Preloaded List is checked whether a + string is present on that list. If the check was successful then the result + of the check is recorded in this histogram. If the check was not successful + then the reason for the check failing is recorded. + </summary> +</histogram> + +<histogram name="Media.Engagement.PreloadedList.LoadResult" + enum="PreloadedListLoadResult"> + <owner>beccahughes@chromium.org</owner> + <owner>media-dev@chromium.org</owner> + <summary> + Recorded when data is loaded into the Media Engagement Preloaded List. If + the load is successful then "loaded" is recorded to this + histogram. If the load was not successful then the reason why is recorded to + this histogram. + </summary> +</histogram> + +<histogram name="Media.Engagement.PreloadList.LoadTime" units="ms"> + <owner>mlamouri@chromium.org</owner> + <owner>media-dev@chromium.org</owner> + <summary> + Time taken to load the Media Engagement Preloaded List. It should be + recorded once per load of the list which will be once per start up with + additional loads when the list is updated while running. + </summary> +</histogram> + +<histogram name="Media.Engagement.PreloadList.LookupTime" units="ms"> + <owner>mlamouri@chromium.org</owner> + <owner>media-dev@chromium.org</owner> + <summary> + Time taken to lookup an entry in the Media Engagement Preloaded List. This + is recorded for every lookup, regardless of its success. + </summary> +</histogram> + <histogram name="Media.Engagement.ScoreAtPlayback" units="%"> <owner>beccahughes@chromium.org</owner> <owner>media-dev@chromium.org</owner> @@ -31617,6 +34963,28 @@ </summary> </histogram> +<histogram name="Media.Engagement.Session" enum="MediaEngagementSessionEvent"> + <owner>mlamouri@chromium.org</owner> + <owner>media-dev@chromium.org</owner> + <summary> + Records creation and playback status of a Media Engagement Session. This is + recorded at the same time as the data is commited into the content settings + database. + </summary> +</histogram> + +<histogram name="Media.Engagement.Session.Restored" + enum="MediaEngagementSessionEvent"> + <owner>mlamouri@chromium.org</owner> + <owner>media-dev@chromium.org</owner> + <summary> + Records creation and playback status of a restored Media Engagement Session. + This is recorded at the same time as the data is commited into the content + settings database. Restored information are recorded in addition of regular + ones (Media.Engagement.Session). + </summary> +</histogram> + <histogram name="Media.Engagement.SignificantPlayers.PlayerNotAdded.AfterFirstTime" enum="InsignificantPlaybackReason"> @@ -31667,6 +35035,18 @@ </summary> </histogram> +<histogram name="Media.Engagement.URLsDeletedScoreReduction" units="%"> + <owner>beccahughes@chromium.org</owner> + <owner>media-dev@chromium.org</owner> + <summary> + Recorded when the history is cleared and the media engagement data are + similarly cleared. It records the reduction in score for each affected + origin. The algorithm is made to reduce the score by 0.0 as much as possible + and if it fails, the score will actually become 0.0 so every reduction also + represent the value of the previous score. + </summary> +</histogram> + <histogram name="Media.FallbackHardwareAudioBitsPerChannel"> <owner>dalecurtis@chromium.org</owner> <summary> @@ -31709,7 +35089,8 @@ </summary> </histogram> -<histogram name="Media.FallbackToHighLatencyAudioPath" enum="BooleanSuccess"> +<histogram name="Media.FallbackToHighLatencyAudioPath" + enum="BooleanDidFallBack"> <owner>dalecurtis@chromium.org</owner> <summary> Whether Chrome had to fallback to the high latency audio path or not. @@ -31777,6 +35158,15 @@ </summary> </histogram> +<histogram name="Media.GpuArcVideoDecodeAccelerator.InitializeResult" + enum="ArcVideoDecodeAcceleratorResult"> + <owner>hiroh@chromium.org</owner> + <summary> + Counts of status values returned from calls to + GpuArcVideoDecodeAccelerator::Initialize(). + </summary> +</histogram> + <histogram name="Media.GpuVideoDecoderError" enum="VideoDecodeAcceleratorError"> <owner>sandersd@chromium.org</owner> <summary>Counts of video decode errors reported to GpuVideoDecoder.</summary> @@ -31952,6 +35342,19 @@ </summary> </histogram> +<histogram name="Media.MediaRecorder.VEAError" + enum="VideoDecodeAcceleratorError"> + <owner>shenghao@chromium.org</owner> + <owner>mcasas@chromium.org</owner> + <summary>The errors HW video encode encounters in MediaRecorder.</summary> +</histogram> + +<histogram name="Media.MediaRecorder.VEAUsed" enum="MediaRecorderVEAUsed"> + <owner>shenghao@chromium.org</owner> + <owner>mcasas@chromium.org</owner> + <summary>Whether HW video encode is used in MediaRecorder.</summary> +</histogram> + <histogram name="Media.MicrophoneMuted" enum="MicrophoneMuteResult"> <owner>henrika@chromium.org</owner> <summary> @@ -32019,6 +35422,14 @@ </summary> </histogram> +<histogram name="Media.MSE.DemuxerDestructionTime" units="ms"> + <owner>wolenetz@chromium.org</owner> + <summary> + Amount of time taken to destroy one ChunkDemuxer object, not including + initial background task scheduling delay. + </summary> +</histogram> + <histogram name="Media.MSE.DetectedTrackCount.Audio"> <owner>wolenetz@chromium.org</owner> <summary> @@ -32221,6 +35632,16 @@ </summary> </histogram> +<histogram name="Media.OutputStreamDuration" units="ms"> + <owner>maxmorin@chromium.org</owner> + <summary> + Duration of an audio output stream. Measured in AudioOutputController from + when a stream is started until it is stopped. A stream is stopped when it is + paused, closed (i.e. destructed), or when a device change event causes it to + be restarted. + </summary> +</histogram> + <histogram name="Media.Pepper.PlayedSound" enum="Boolean"> <owner>avayvod@chromium.org</owner> <owner>mlamouri@chromium.org</owner> @@ -32340,6 +35761,9 @@ </histogram> <histogram name="Media.Remoting.CapacityOverMediaBitrate" units="kbps"> + <obsolete> + Deprecated 11/2017 in issue 788940. + </obsolete> <owner>miu@chromium.org</owner> <summary> The difference between the estimated transmission capacity and the media @@ -32348,6 +35772,9 @@ </histogram> <histogram name="Media.Remoting.MediaBitrateOverCapacity" units="kbps"> + <obsolete> + Deprecated 11/2017 in issue 788940. + </obsolete> <owner>miu@chromium.org</owner> <summary> The difference between the media bitrate and the estimated transmission @@ -32391,11 +35818,23 @@ </histogram> <histogram name="Media.Remoting.SessionStopTrigger" enum="RemotingStopTrigger"> +<!-- Name completed by histogram_suffixes name="RemotingSessionDuration" --> + <owner>miu@chromium.org</owner> <summary>Tracks the trigger for stopping a remoting session.</summary> </histogram> +<histogram name="Media.Remoting.ShortSessionDuration" units="ms"> + <owner>miu@chromium.org</owner> + <summary> + Measures the duration of each remoting session shorter than 15 seconds. + </summary> +</histogram> + <histogram name="Media.Remoting.StartMediaBitrate" units="kbps"> + <obsolete> + Deprecated 11/2017 in issue 788940. + </obsolete> <owner>miu@chromium.org</owner> <summary> The estimated content bitrate (including both audio and video) when starting @@ -32426,6 +35865,9 @@ </histogram> <histogram name="Media.Remoting.TransmissionCapacity" units="kbps"> + <obsolete> + Deprecated 11/2017 in issue 788940. + </obsolete> <owner>miu@chromium.org</owner> <summary> The estimated transmission capacity when starting a remoting session. @@ -32688,6 +36130,24 @@ </summary> </histogram> +<histogram base="true" name="Media.TimeToFirstFrame" units="ms"> + <owner>dalecurtis@chromium.org</owner> + <owner>media-dev@chromium.org</owner> + <summary> + Time in milliseconds from when WebMediaPlayerImpl starts loading until the + first video frame has been shown. + </summary> +</histogram> + +<histogram base="true" name="Media.TimeToMetadata" units="ms"> + <owner>dalecurtis@chromium.org</owner> + <owner>media-dev@chromium.org</owner> + <summary> + Time in milliseconds from when WebMediaPlayerImpl starts loading until + metadata is known. + </summary> +</histogram> + <histogram name="Media.TimeToPipelineStarted" units="ms"> <obsolete> Removed from code 2014/6/18. @@ -32698,6 +36158,15 @@ </summary> </histogram> +<histogram base="true" name="Media.TimeToPlayReady" units="ms"> + <owner>dalecurtis@chromium.org</owner> + <owner>media-dev@chromium.org</owner> + <summary> + Time in milliseconds from when WebMediaPlayer starts loading until it has + buffered enough to start playback. + </summary> +</histogram> + <histogram name="Media.TotalMBytes" units="MB"> <owner>hajimehoshi@chromium.org</owner> <owner>kouhei@chromium.org</owner> @@ -32759,7 +36228,7 @@ </histogram> <histogram base="true" name="Media.UnderflowDuration2" units="ms"> -<!-- Name completed by histogram_suffixes name="MediaUnderflowDuration2" --> +<!-- Name completed by histogram_suffixes name="WebMediaPlayerImplTypes" --> <owner>dalecurtis@chromium.org</owner> <summary> @@ -32783,6 +36252,13 @@ </summary> </histogram> +<histogram name="Media.VAJEA.EncoderResult" enum="VAJEAEncoderResult"> + <owner>shenghao@chromium.org</owner> + <summary> + Result codes reported by jpeg encode using VA-API hardware jpeg encoder. + </summary> +</histogram> + <histogram name="Media.VAVDA.DecoderFailure" enum="VAVDADecoderFailure"> <owner>posciak@chromium.org</owner> <summary> @@ -33237,6 +36713,14 @@ </summary> </histogram> +<histogram name="Media.VideoDecodeStatsDB.OpSuccess" enum="BooleanSuccess"> + <owner>chcunningham@chromium.org</owner> + <summary> + Indicates whether we were successful performing some database operation. See + suffix VideoDecodeStatsDBOperations. + </summary> +</histogram> + <histogram name="Media.VideoFormat" enum="VideoFormat"> <obsolete> Replaced by Media.VideoFramePixelFormat 05/2015. @@ -33587,6 +37071,24 @@ <summary>Various usage counts for media galleries.</summary> </histogram> +<histogram name="MediaRouter.Cast.Channel.ConnectResult" enum="BooleanSuccess"> + <owner>zhaobin@chromium.org</owner> + <summary> + Whether opening Cast channel succeeds or not. Recorded when all opening + channel attempts (including retry attempts) finish. + </summary> +</histogram> + +<histogram name="MediaRouter.Cast.Channel.Error" + enum="MediaRouterCastChannelError"> + <owner>zhaobin@chromium.org</owner> + <summary> + Errors encountered on a Cast channel. Recorded when a Cast channel fails to + open, or when an opened channel fails to respond to keepalive ping request + and times out. + </summary> +</histogram> + <histogram name="MediaRouter.Cast.Discovery.CachedSinksAvailableCount" units="devices"> <owner>btolsch@chromium.org</owner> @@ -33619,6 +37121,22 @@ <summary>The source of discovery for a newly-created Cast sink.</summary> </histogram> +<histogram name="MediaRouter.Cast.Mdns.Channel.Open_Failure" units="ms"> + <owner>zhaobin@chromium.org</owner> + <summary> + Duration in milliseconds taken to fail to open a cast channel. Recorded when + one opening channel attempt fails. + </summary> +</histogram> + +<histogram name="MediaRouter.Cast.Mdns.Channel.Open_Success" units="ms"> + <owner>zhaobin@chromium.org</owner> + <summary> + Duration in milliseconds taken to successfully open a cast channel. Recorded + when one opening channel attempt succeeds. + </summary> +</histogram> + <histogram name="MediaRouter.Dial.AvailableDevicesCount" units="devices"> <owner>zhaobin@chromium.org</owner> <summary> @@ -33668,16 +37186,47 @@ </summary> </histogram> +<histogram name="MediaRouter.PresentationRequest.AvailabilityUrlType" + enum="PresentationUrlType"> + <owner>imcheng@chromium.org</owner> + <summary> + The type of Presentation URL used in a PresentationRequest by a web page. + </summary> +</histogram> + <histogram name="MediaRouter.Provider.CreateRoute.Result" enum="MediaRouteProviderResult"> <owner>imcheng@chromium.org</owner> - <summary>Result of a request to create a route.</summary> + <summary> + Result of a request to the extension (or an unknown) MediaRouteProvider to + create a route. + </summary> +</histogram> + +<histogram name="MediaRouter.Provider.CreateRoute.Result.WiredDisplay" + enum="MediaRouteProviderResult"> + <owner>takumif@chromium.org</owner> + <summary> + Result of a request to the wired display MediaRouteProvider to create a + route. + </summary> </histogram> <histogram name="MediaRouter.Provider.JoinRoute.Result" enum="MediaRouteProviderResult"> <owner>imcheng@chromium.org</owner> - <summary>Result of a request to join a route.</summary> + <summary> + Result of a request to the extension (or an unknown) MediaRouteProvider to + join a route. + </summary> +</histogram> + +<histogram name="MediaRouter.Provider.JoinRoute.Result.WiredDisplay" + enum="MediaRouteProviderResult"> + <owner>takumif@chromium.org</owner> + <summary> + Result of a request to the wired display MediaRouteProvider to join a route. + </summary> </histogram> <histogram name="MediaRouter.Provider.RouteControllerCreationOutcome" @@ -33692,7 +37241,19 @@ <histogram name="MediaRouter.Provider.TerminateRoute.Result" enum="MediaRouteProviderResult"> <owner>mfoltz@chromium.org</owner> - <summary>Result of a request to terminate a route.</summary> + <summary> + Result of a request to the extension (or an unknown) MediaRouteProvider to + terminate a route. + </summary> +</histogram> + +<histogram name="MediaRouter.Provider.TerminateRoute.Result.WiredDisplay" + enum="MediaRouteProviderResult"> + <owner>takumif@chromium.org</owner> + <summary> + Result of a request to the wired display MediaRouteProvider to terminate a + route. + </summary> </histogram> <histogram name="MediaRouter.Provider.Version" enum="MediaRouteProviderVersion"> @@ -33727,6 +37288,14 @@ </summary> </histogram> +<histogram name="MediaRouter.Sink.SelectedType" enum="MediaSinkType"> + <owner>takumif@chromium.org</owner> + <summary> + The type of the Media Sink that media is being Cast to. Recorded each time + the user selects a Media Sink to start Casting. + </summary> +</histogram> + <histogram name="MediaRouter.Source.CastingSource" enum="MediaRouterSourceTypes"> <owner>paezagon@chromium.org</owner> @@ -33846,6 +37415,15 @@ </summary> </histogram> +<histogram name="MediaRouter.WiredDisplay.AvailableDevicesCount"> + <owner>takumif@chromium.org</owner> + <summary> + The number of Media Sinks available for Casting a Presentation API URL to + local screens. Recorded at most once an hour, when the Wired Display Media + Route Provider reports an update on the sink count. + </summary> +</histogram> + <histogram name="MemCache.WriteResult" enum="MemCacheWriteResult"> <owner>jkarlin@chromium.org</owner> <summary>The outcome of Entry::WriteData in the memory cache.</summary> @@ -33895,6 +37473,9 @@ </histogram> <histogram name="Memory.Browser.Large2" units="MB"> + <obsolete> + Deprecated 11/2017 Replaced with Memory.Browser.PrivateMemoryFootprint. + </obsolete> <owner>bashi@chromium.org</owner> <owner>kouhei@chromium.org</owner> <summary> @@ -33911,6 +37492,22 @@ </summary> </histogram> +<histogram name="Memory.Browser.PrivateSwapFootprint" units="MB"> + <owner>mariakhomenko@chromium.org</owner> + <summary> + An amount of private memory of the browser process placed in swap (VmSwap). + Available only on Android and Linux. + </summary> +</histogram> + +<histogram name="Memory.Browser.SharedMemoryFootprint" units="MB"> + <owner>erikchen@chromium.org</owner> + <summary> + A rough estimate of the shared memory footprint of the browser process. + Recorded once per UMA ping. + </summary> +</histogram> + <histogram name="Memory.CachedFontAndDC"> <owner>hajimehoshi@chromium.org</owner> <owner>kenjibaheux@google.com</owner> @@ -33919,12 +37516,16 @@ </histogram> <histogram name="Memory.Chrome" units="KB"> + <obsolete> + Deprecated 11/2017. No direct replacement, but + Memory.Renderer.PrivateMemoryFootprint is similar. + </obsolete> <owner>hajimehoshi@chromium.org</owner> <owner>kenjibaheux@google.com</owner> <owner>kouhei@chromium.org</owner> <summary> The private working set used by each chrome:// renderer process. Each - process provides one sample. Recorded once per UMA ping. + process provides one sample. Recorded once per process per UMA ping. </summary> </histogram> @@ -34059,6 +37660,9 @@ <histogram name="Memory.Experimental.Browser.PrivateMemoryFootprint.MacOS" units="MB"> + <obsolete> + Deprecated 12/2017. Replaced by Memory.Browser.PrivateMemoryFootprint. + </obsolete> <owner>erikchen@chromium.org</owner> <summary> A rough estimate of the private memory footprint of the browser process. @@ -34145,6 +37749,9 @@ <histogram name="Memory.Experimental.Extension.PrivateMemoryFootprint.MacOS" units="MB"> + <obsolete> + Deprecated 12/2017. Replaced by Memory.Extension.PrivateMemoryFootprint. + </obsolete> <owner>erikchen@chromium.org</owner> <summary> A rough estimate of the private memory footprint of an extension process. @@ -34173,6 +37780,9 @@ <histogram name="Memory.Experimental.Gpu.PrivateMemoryFootprint.MacOS" units="MB"> + <obsolete> + Deprecated 12/2017. Replaced by Memory.Gpu.PrivateMemoryFootprint. + </obsolete> <owner>erikchen@chromium.org</owner> <summary> A rough estimate of the private memory footprint of the GPU process. @@ -34189,6 +37799,61 @@ </summary> </histogram> +<histogram name="Memory.Experimental.OomIntervention.InterventionStateOnCrash" + enum="OomInterventionUserDecision"> + <owner>bashi@chromium.org</owner> + <summary> + Records state of the intervention (accepted or declined) when the foreground + renderer is crashed after near-OOM intervention is triggered. + </summary> +</histogram> + +<histogram + name="Memory.Experimental.OomIntervention.NavigationAfterDetectionTime" + units="ms"> + <owner>bashi@chromium.org</owner> + <summary> + Records the time elapsed between a near-OOM detection and when a navigation + is started. + </summary> +</histogram> + +<histogram name="Memory.Experimental.OomIntervention.NearOomDetectionEndReason" + enum="NearOomDetectionEndReason"> + <owner>bashi@chromium.org</owner> + <summary> + Records the reason for stopping near-OOM detection. This isn't recorded when + a near-OOM situation was detected. + </summary> +</histogram> + +<histogram + name="Memory.Experimental.OomIntervention.OomProtectedCrashAfterDetectionTime" + units="ms"> + <owner>bashi@chromium.org</owner> + <summary> + Records the time elapsed between a near-OOM detection and when an OOM + protected renderer was crashed. + </summary> +</histogram> + +<histogram + name="Memory.Experimental.OomIntervention.RendererGoneAfterDetectionTime" + units="ms"> + <owner>bashi@chromium.org</owner> + <summary> + Records the time elapsed between a near-OOM detection and when a foreground + renderer process was gone. This histogram does not contain OOM protected + crashes. + </summary> +</histogram> + +<histogram name="Memory.Experimental.OomIntervention.UserDecision" + enum="OomInterventionUserDecision"> + <owner>bashi@chromium.org</owner> + <summary>Records user decisions on near-OOM intervention.</summary> +</histogram> + <histogram base="true" name="Memory.Experimental.Renderer" units="MB"> <!-- Name completed by histogram_suffixes name="RendererMemoryAllocator" --> @@ -34210,6 +37875,9 @@ <histogram name="Memory.Experimental.Renderer.PrivateMemoryFootprint.MacOS" units="MB"> + <obsolete> + Deprecated 12/2017. Replaced by Memory.Renderer.PrivateMemoryFootprint. + </obsolete> <owner>erikchen@chromium.org</owner> <summary> A rough estimate of the private memory footprint of a renderer process. @@ -34257,6 +37925,25 @@ </summary> </histogram> +<histogram name="Memory.Experimental.SwapThrashingLevel" + enum="SwapThrashingLevel"> + <owner>sebmarchand@chromium.org</owner> + <summary> + The swap thrashing level, which is recorded periodically. This shows the + cumulative number of seconds that systems spend in each of the swap + thrashing states. Only available on Windows. + </summary> +</histogram> + +<histogram name="Memory.Experimental.SwapThrashingLevelChanges" + enum="SwapThrashingLevelChanges"> + <owner>sebmarchand@chromium.org</owner> + <summary> + The number of swap-thrashing level state changes for each possible pairwise + state change. Only available on Windows. + </summary> +</histogram> + <histogram name="Memory.Experimental.Total2.PrivateMemoryFootprint" units="MB"> <owner>erikchen@chromium.org</owner> <summary> @@ -34265,12 +37952,15 @@ </histogram> <histogram name="Memory.Extension" units="KB"> + <obsolete> + Deprecated 11/2017. Replaced by Memory.Extension.PrivateMemoryFootprint. + </obsolete> <owner>hajimehoshi@chromium.org</owner> <owner>kenjibaheux@google.com</owner> <owner>kouhei@chromium.org</owner> <summary> The private working set used by each extension process. Each process - provides one sample. Recorded once per UMA ping. + provides one sample. Recorded once per process per UMA ping. </summary> </histogram> @@ -34278,7 +37968,15 @@ <owner>erikchen@chromium.org</owner> <summary> A rough estimate of the private memory footprint of the extension process. - Recorded once per UMA ping. + Recorded once per process per UMA ping. + </summary> +</histogram> + +<histogram name="Memory.Extension.SharedMemoryFootprint" units="MB"> + <owner>erikchen@chromium.org</owner> + <summary> + A rough estimate of the shared memory footprint of the extension process. + Recorded once per process per UMA ping. </summary> </histogram> @@ -34312,6 +38010,9 @@ </histogram> <histogram name="Memory.Gpu" units="KB"> + <obsolete> + Deprecated 11/2017. Replaced by Memory.Gpu.PrivateMemoryFootprint. + </obsolete> <owner>hajimehoshi@chromium.org</owner> <owner>jamescook@chromium.org</owner> <owner>kenjibaheux@google.com</owner> @@ -34330,6 +38031,22 @@ </summary> </histogram> +<histogram name="Memory.Gpu.PrivateSwapFootprint" units="MB"> + <owner>mariakhomenko@chromium.org</owner> + <summary> + An amount of private memory of the GPU process placed in swap (VmSwap). + Available only on Android and Linux. + </summary> +</histogram> + +<histogram name="Memory.Gpu.SharedMemoryFootprint" units="MB"> + <owner>erikchen@chromium.org</owner> + <summary> + A rough estimate of the shared memory footprint of the gpu process. Recorded + once per UMA ping. + </summary> +</histogram> + <histogram name="Memory.Graphics" units="MB"> <owner>hajimehoshi@chromium.org</owner> <owner>jamescook@chromium.org</owner> @@ -34351,22 +38068,28 @@ </histogram> <histogram name="Memory.NativeClient" units="KB"> + <obsolete> + Deprecated 11/2017. No direct replacement. + </obsolete> <owner>hajimehoshi@chromium.org</owner> <owner>kenjibaheux@google.com</owner> <owner>kouhei@chromium.org</owner> <summary> The private working set used by each Native Client loader process. Each - process provides one sample. Recorded once per UMA ping. + process provides one sample. Recorded once per process per UMA ping. </summary> </histogram> <histogram name="Memory.NativeClientBroker" units="KB"> + <obsolete> + Deprecated 11/2017. No direct replacement. + </obsolete> <owner>hajimehoshi@chromium.org</owner> <owner>kenjibaheux@google.com</owner> <owner>kouhei@chromium.org</owner> <summary> The private working set used by each Native Client broker process. Each - process provides one sample. Recorded once per UMA ping. + process provides one sample. Recorded once per process per UMA ping. </summary> </histogram> @@ -34477,30 +38200,39 @@ </histogram> <histogram name="Memory.PepperFlashPlugin" units="KB"> + <obsolete> + Deprecated 11/2017. No direct replacement. + </obsolete> <owner>thestig@chromium.org</owner> <summary> The private working set used by each Pepper Flash plugin process. Each - plugin process provides one sample. Recorded once per UMA ping. + plugin process provides one sample. Recorded once per process per UMA ping. </summary> </histogram> <histogram name="Memory.PepperPlugin" units="KB"> + <obsolete> + Deprecated 11/2017. No direct replacement. + </obsolete> <owner>hajimehoshi@chromium.org</owner> <owner>kenjibaheux@google.com</owner> <owner>kouhei@chromium.org</owner> <summary> The private working set used by each Pepper plugin process. Each plugin - process provides one sample. Recorded once per UMA ping. + process provides one sample. Recorded once per process per UMA ping. </summary> </histogram> <histogram name="Memory.PepperPluginBroker" units="KB"> + <obsolete> + Deprecated 11/2017. No direct replacement. + </obsolete> <owner>hajimehoshi@chromium.org</owner> <owner>kenjibaheux@google.com</owner> <owner>kouhei@chromium.org</owner> <summary> The private working set used by each Pepper plugin broker process. Each - process provides one sample. Recorded once per UMA ping. + process provides one sample. Recorded once per process per UMA ping. </summary> </histogram> @@ -34532,7 +38264,7 @@ <owner>kouhei@chromium.org</owner> <summary> The private working set used by each plugin process. Each plugin process - provides one sample. Recorded once per UMA ping. + provides one sample. Recorded once per process per UMA ping. </summary> </histogram> @@ -34600,7 +38332,7 @@ <owner>kouhei@chromium.org</owner> <summary> The total committed memory used by each renderer process. Each renderer - process provides one sample. Recorded once per UMA ping. + process provides one sample. Recorded once per process per UMA ping. </summary> </histogram> @@ -34615,11 +38347,14 @@ </histogram> <histogram name="Memory.Renderer.Large2" units="MB"> + <obsolete> + Deprecated 11/2017. Replaced by Memory.Renderer.PrivateMemoryFootprint. + </obsolete> <owner>bashi@chromium.org</owner> <owner>kouhei@chromium.org</owner> <summary> The private working set used by each renderer process. Each renderer - process provides one sample. Recorded once per UMA ping. + process provides one sample. Recorded once per process per UMA ping. </summary> </histogram> @@ -34627,11 +38362,23 @@ <owner>erikchen@chromium.org</owner> <summary> A rough estimate of the private memory footprint of the renderer process. - Recorded once per UMA ping. + Recorded once per process per UMA ping. + </summary> +</histogram> + +<histogram name="Memory.Renderer.SharedMemoryFootprint" units="MB"> + <owner>erikchen@chromium.org</owner> + <summary> + A rough estimate of the shared memory footprint of the renderer process. + Recorded once per process per UMA ping. </summary> </histogram> <histogram name="Memory.RendererAll" units="MB"> + <obsolete> + Deprecated 11/2017. No direct replacement, although + Memory.Total.PrivateMemoryFootprint is similar. + </obsolete> <owner>bashi@chromium.org</owner> <owner>hajimehoshi@chromium.org</owner> <owner>tasak@chromium.org</owner> @@ -34639,11 +38386,15 @@ The private working set used by each renderer process, including all renderer types, i.e. this includes Chrome renderer, extensions renderer, as well as regular renderer processes. Each renderer process provides one - sample. Recorded once per UMA ping. + sample. Recorded once per process per UMA ping. </summary> </histogram> <histogram name="Memory.RendererAll.Committed" units="MB"> + <obsolete> + Deprecated 01/2018. No direct replacement, although + Memory.Total.PrivateMemoryFootprint is similar. + </obsolete> <owner>bashi@chromium.org</owner> <owner>hajimehoshi@chromium.org</owner> <owner>tasak@chromium.org</owner> @@ -34651,7 +38402,7 @@ The total committed memory used by each renderer process, including all renderer types, i.e. this includes Chrome renderer, extensions renderer, as well as regular renderer processes. Each renderer process provides one - sample. Recorded once per UMA ping. + sample. Recorded once per process per UMA ping. </summary> </histogram> @@ -34699,12 +38450,15 @@ </histogram> <histogram name="Memory.SandboxHelper" units="KB"> + <obsolete> + Deprecated 11/2017. No direct replacement. + </obsolete> <owner>hajimehoshi@chromium.org</owner> <owner>kenjibaheux@google.com</owner> <owner>kouhei@chromium.org</owner> <summary> The private working set used by each sandbox helper process. Each sandbox - helper process provides one sample. Recorded once per UMA ping. + helper process provides one sample. Recorded once per process per UMA ping. </summary> </histogram> @@ -34871,7 +38625,7 @@ <owner>kouhei@chromium.org</owner> <summary> The swap used by each chrome:// renderer process. Each process provides one - sample. Recorded once per UMA ping if the system has swapped. + sample. Recorded once per process per UMA ping if the system has swapped. </summary> </histogram> @@ -34901,7 +38655,7 @@ <owner>kouhei@chromium.org</owner> <summary> The swap used by each extension process. Each process provides one sample. - Recorded once per UMA ping if the system has swapped. + Recorded once per process per UMA ping if the system has swapped. </summary> </histogram> @@ -34941,7 +38695,8 @@ <owner>kouhei@chromium.org</owner> <summary> The swap used by each Native Client loader process. Each process provides - one sample. Recorded once per UMA ping if the system has swapped. + one sample. Recorded once per process per UMA ping if the system has + swapped. </summary> </histogram> @@ -34951,7 +38706,8 @@ <owner>kouhei@chromium.org</owner> <summary> The swap used by each Native Client broker process. Each process provides - one sample. Recorded once per UMA ping if the system has swapped. + one sample. Recorded once per process per UMA ping if the system has + swapped. </summary> </histogram> @@ -34960,8 +38716,8 @@ <owner>kenjibaheux@google.com</owner> <owner>kouhei@chromium.org</owner> <summary> - The number of reads from swap. Recorded once per UMA ping if the system - has swapped. + The number of reads from swap. Recorded once per UMA ping if the system has + swapped. </summary> </histogram> @@ -34991,7 +38747,8 @@ <owner>kouhei@chromium.org</owner> <summary> The swap used by each Pepper plugin process. Each plugin process provides - one sample. Recorded once per UMA ping if the system has swapped. + one sample. Recorded once per process per UMA ping if the system has + swapped. </summary> </histogram> @@ -35001,7 +38758,8 @@ <owner>kouhei@chromium.org</owner> <summary> The swap used by each Pepper plugin broker process. Each process provides - one sample. Recorded once per UMA ping if the system has swapped. + one sample. Recorded once per process per UMA ping if the system has + swapped. </summary> </histogram> @@ -35014,7 +38772,7 @@ <owner>kouhei@chromium.org</owner> <summary> The swap used by each plugin process. Each plugin process provides one - sample. Recorded once per UMA ping if the system has swapped. + sample. Recorded once per process per UMA ping if the system has swapped. </summary> </histogram> @@ -35024,7 +38782,7 @@ <owner>kouhei@chromium.org</owner> <summary> The swap used by each renderer process. Each renderer process provides one - sample. Recorded once per UMA ping if the system has swapped. + sample. Recorded once per process per UMA ping if the system has swapped. </summary> </histogram> @@ -35034,7 +38792,8 @@ <owner>kouhei@chromium.org</owner> <summary> The swap used by each sandbox helper process. Each sandbox helper process - provides one sample. Recorded once per UMA ping if the system has swapped. + provides one sample. Recorded once per process per UMA ping if the system + has swapped. </summary> </histogram> @@ -35066,7 +38825,7 @@ <owner>kouhei@chromium.org</owner> <summary> The swap used by each utility process. Each utility process provides one - sample. Recorded once per UMA ping if the system has swapped. + sample. Recorded once per process per UMA ping if the system has swapped. </summary> </histogram> @@ -35076,7 +38835,7 @@ <owner>kouhei@chromium.org</owner> <summary> The swap used by each worker process. Each worker process provides one - sample. Recorded once per UMA ping if the system has swapped. + sample. Recorded once per process per UMA ping if the system has swapped. </summary> </histogram> @@ -35112,7 +38871,18 @@ </summary> </histogram> +<histogram name="Memory.Total.SharedMemoryFootprint" units="MB"> + <owner>erikchen@chromium.org</owner> + <summary> + A rough estimate of the shared memory footprint of all processes. Recorded + once per UMA ping. + </summary> +</histogram> + <histogram name="Memory.Total2" units="MiB"> + <obsolete> + Deprecated 11/2017. Replaced by Memory.Total.PrivateMemoryFootprint. + </obsolete> <owner>hajimehoshi@chromium.org</owner> <owner>kenjibaheux@google.com</owner> <owner>kouhei@chromium.org</owner> @@ -35124,12 +38894,15 @@ </histogram> <histogram name="Memory.Utility" units="KB"> + <obsolete> + Deprecated 11/2017. No direct replacement. + </obsolete> <owner>hajimehoshi@chromium.org</owner> <owner>kenjibaheux@google.com</owner> <owner>kouhei@chromium.org</owner> <summary> The private working set used by each utility process. Each utility process - provides one sample. Recorded once per UMA ping. + provides one sample. Recorded once per process per UMA ping. </summary> </histogram> @@ -35139,7 +38912,7 @@ <owner>kouhei@chromium.org</owner> <summary> The private working set used by each worker process. Each worker process - provides one sample. Recorded once per UMA ping. + provides one sample. Recorded once per process per UMA ping. </summary> </histogram> @@ -35153,12 +38926,15 @@ </histogram> <histogram name="Memory.Zygote" units="KB"> + <obsolete> + Deprecated 11/2017. No direct replacement. + </obsolete> <owner>hajimehoshi@chromium.org</owner> <owner>kenjibaheux@google.com</owner> <owner>kouhei@chromium.org</owner> <summary> The private working set used by the zygote process. Each zygote process - provides one sample. Recorded once per UMA ping. + provides one sample. Recorded once per process per UMA ping. </summary> </histogram> @@ -35255,6 +39031,13 @@ </summary> </histogram> +<histogram name="MemoryWarning.OccurrencesPerSession"> + <owner>justincohen@chromium.org</owner> + <summary> + The number of memory warnings during a given foreground session. + </summary> +</histogram> + <histogram name="MemoryWarning.ProtectedTabTimeSinceActive" units="ms"> <obsolete> Deprecated as of 10/2016. @@ -35274,6 +39057,14 @@ </summary> </histogram> +<histogram name="Mobile.CanonicalURLResult" enum="CanonicalURLResult"> + <owner>gchatz@chromium.org</owner> + <owner>tedchoc@chromium.org</owner> + <summary> + The result of the operation to retrieve the page's canonical URL. + </summary> +</histogram> + <histogram base="true" name="Mobile.DefaultBrowser.BrowserCount"> <!-- Name completed by histogram_suffixes name="Mobile.DefaultBrowser.Type" --> @@ -35408,6 +39199,10 @@ <histogram name="MobileDownload.Notification.FixingSummaryLeak" enum="BooleanForegroundNotification"> + <obsolete> + Deprecated 10/2017 in Issue 722320 with the removal of + DownloadNotificationService.hideDanglingSummaryNotification. + </obsolete> <owner>dtrainor@chromium.org</owner> <summary> Android: Records the situation where we try to fix a standalone downloads @@ -35438,6 +39233,16 @@ </summary> </histogram> +<histogram name="MobileFre.PrivacyLinkTappedStatus" + enum="MobileFreLinkTappedStatus"> + <owner>justincohen@chromium.org</owner> + <summary> + iOS: Records the status of the privacy page after user taps on the privacy + link on the first run welcome view. This metric is only recorded if and + after the TOS are accepted. This metric is specific to iOS. + </summary> +</histogram> + <histogram name="MobileFre.Progress" enum="MobileFreProgress"> <owner>gogerald@chromium.org</owner> <summary> @@ -35589,6 +39394,15 @@ </summary> </histogram> +<histogram name="MobileSignInPromo.SettingsManager.ImpressionsTilXButton" + units="impressions"> + <owner>jlebel@chromium.org</owner> + <summary> + Counts how many times the explicit "X"-to-close button is clicked + per impression. + </summary> +</histogram> + <histogram name="MobileStartup.IntentToCreationTime" units="ms"> <owner>twellington@chromium.org</owner> <summary> @@ -35649,6 +39463,8 @@ screen. This is measured from the time the last tab is closed until a Main intent is received. Has a minute level precision for first 10 minutes increasing exponentially till 30 days. + + Note: this metric is broken in M63 and below and only reliable in M64+. </summary> </histogram> @@ -36030,6 +39846,9 @@ </histogram> <histogram name="MPArch.RWH_HangMonitorUnresponsive" units="ms"> + <obsolete> + Deprecated 12/2017 due to lack of usage. + </obsolete> <owner>amaralp@chromium.org</owner> <summary> The length of time the renderer is unresponsive according to the hang @@ -36055,6 +39874,16 @@ <summary>The time spent inside RenderWidgetHost::OnMsgPaintRect.</summary> </histogram> +<histogram name="MPArch.RWH_OnMsgResizeOrRepaintACK"> + <owner>fsamuel@chromium.org</owner> + <owner>piman@chromium.org</owner> + <summary> + The time delta for processing a paint message. On platforms that don't + support asynchronous painting, this is equivalent to + MPArch.RWH_TotalPaintTime. + </summary> +</histogram> + <histogram name="MPArch.RWH_OnMsgScrollRect" units="ms"> <obsolete> Deprecated 04/2016 as doesn't have data nor owner. @@ -36064,6 +39893,9 @@ </histogram> <histogram name="MPArch.RWH_OnMsgUpdateRect"> + <obsolete> + Deprecated 10/2017. Replaced with MPArch.RWH_OnMsgResizeOrRepaintACK. + </obsolete> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <summary>TBD</summary> </histogram> @@ -36094,6 +39926,11 @@ </histogram> <histogram name="MultiProfile.DiscardedTabsPerUser"> + <obsolete> + Deprecated 11/2017. Analysis confirms that the number of discards increases + with the number of logged in users. No action will be taken based on this + information. + </obsolete> <owner>skuhne@chromium.org</owner> <summary> The relation of discarded tabs vs. the amount of simultaneous users. The @@ -36622,6 +40459,15 @@ </summary> </histogram> +<histogram name="NativeAppLauncher.InstallationDetected" + enum="BooleanInstalled"> + <owner>jif@chromium.org</owner> + <summary> + The number of times that Chrome detected that a request to download and + install another Google iOS app completed successfully. + </summary> +</histogram> + <histogram name="Navigation.BackForward.CacheFlags" enum="NavigationCacheEnum"> <owner>clamy@chromium.org</owner> <summary>The cache flags set on back-forward navigations.</summary> @@ -36761,6 +40607,14 @@ </summary> </histogram> +<histogram name="Navigation.Intercept.WillStart" units="microseconds"> + <owner>csharrison@chromium.org</owner> + <summary> + The microseconds it takes for the InterceptNavigationThrottle to determine + if the navigation should be ignored, at WillStartRequest time. + </summary> +</histogram> + <histogram name="Navigation.IOSWKWebViewSlowFastBackForward" enum="BackForwardNavigationType"> <owner>eugenebut@chromium.org</owner> @@ -36799,6 +40653,9 @@ <histogram name="Navigation.MainFrameScheme.DataUrl.MimeType" enum="DataUrlMimeType"> + <obsolete> + Removed from code October 2017. + </obsolete> <owner>meacer@chromium.org</owner> <summary> The mime type of the data: URL for each main-frame navigation. This only @@ -37005,6 +40862,30 @@ </summary> </histogram> +<histogram + name="Navigation.URLLoaderNetworkService.OnCompleteCertificateChainsSize" + units="KB"> + <owner>estark@chromium.org</owner> + <summary> + When the navigation URL loader receives an OnComplete message from the + network service that contains certificate chains, this histogram records the + size in KB of those pickled certificate chains. This histogram is recorded + by the navigation URLLoader for navigations that fetch from network, for + every request which contains an SSLInfo in its OnComplete notification. + </summary> +</histogram> + +<histogram name="Navigation.URLLoaderNetworkService.OnCompleteHasSSLInfo" + enum="BooleanPresent"> + <owner>estark@chromium.org</owner> + <summary> + Whether the network service's OnComplete message to the navigation URL + loader contains an SSLInfo, which should only be present for main-frame + requests with certificate errors. This histogram is recorded for every + request completion by the navigation URL loader that fetches from network. + </summary> +</histogram> + <histogram name="NCN.CellularConnectionSubtype" enum="ConnectionSubtype"> <owner>bmcquade@chromium.org</owner> <summary> @@ -37773,6 +41654,17 @@ </summary> </histogram> +<histogram name="Net.AlternativeProxyFailed" enum="NetErrorCodes"> + <owner>tbansal@chromium.org</owner> + <summary> + Positive net error codes that failed alternative proxy requests end with. + Recorded when an alternative job fails, whether or not the main job + succeeds. + + As of M66 this superceded DataReductionProxy.Quic.OnAlternativeProxyBroken. + </summary> +</histogram> + <histogram name="Net.AlternativeServiceServers.MoreOrEqualCacheEntries"> <owner>rch@chromium.org</owner> <summary> @@ -38021,7 +41913,6 @@ Part of a concluded experiment, 2016-08-02. </obsolete> <owner>ellyjones@chromium.org</owner> - <owner>rdsmith@chromium.org</owner> <summary>Counts of response bytes by cache state.</summary> </histogram> @@ -38030,7 +41921,6 @@ Part of a concluded experiment, 2016-08-02. </obsolete> <owner>ellyjones@chromium.org</owner> - <owner>rdsmith@chromium.org</owner> <summary> State of the cache for a request, delta-encoding eligible or otherwise. </summary> @@ -38041,7 +41931,6 @@ Part of a concluded experiment, 2016-08-02. </obsolete> <owner>ellyjones@chromium.org</owner> - <owner>rdsmith@chromium.org</owner> <summary> Counts of response bytes by cache state for delta-encoding eligible requests. @@ -38053,7 +41942,6 @@ Part of a concluded experiment, 2016-08-02. </obsolete> <owner>ellyjones@chromium.org</owner> - <owner>rdsmith@chromium.org</owner> <summary>State of the cache for a delta-encoding eligible request.</summary> </histogram> @@ -38148,6 +42036,26 @@ </summary> </histogram> +<histogram name="Net.Certificate.TrustAnchor.Request" enum="NetTrustAnchors"> + <owner>rsleevi@chromium.org</owner> + <summary> + The SHA-256 hash of the subjectPublicKeyInfo of the most-specific trust + anchor encountered in a successfully-verified certificate chain, during an + HTTP URL request. The associated root certificate can be looked up using + https://crt.sh/?spkisha256= . + </summary> +</histogram> + +<histogram name="Net.Certificate.TrustAnchor.Verify" enum="NetTrustAnchors"> + <owner>rsleevi@chromium.org</owner> + <summary> + The SHA-256 hash of the subjectPublicKeyInfo of the most-specific trust + anchor encountered in a successfully-verified certificate chain, during + verification time. The associated root certificate can be looked up using + https://crt.sh/?spkisha256= . + </summary> +</histogram> + <histogram name="Net.Certificate.VerificationSuccessAfterAIAFetchingNeeded" enum="BooleanSuccess"> <owner>estark@chromium.org</owner> @@ -38182,6 +42090,128 @@ </summary> </histogram> +<histogram name="Net.CertificateTransparency.ConnectionComplianceStatus.QUIC" + enum="CTComplianceStatus"> + <obsolete> + Deprecated Nov 2017, replaced with + Net.CertificateTransparency.ConnectionComplianceStatus2 + </obsolete> + <owner>estark@chromium.org</owner> + <summary> + The compliance of each QUIC connection with the Certificate Transparency + policy, recorded once on connection setup unless CT evaluation has been + disabled for that connection or the certificate is invalid. Connections can + be compliant, or they can be non-compliant for one of several reasons (not + enough Signed Certificate Timestamps [SCTs], not diverse enough SCTs, or the + build was old so CT compliance wasn't checked). + </summary> +</histogram> + +<histogram name="Net.CertificateTransparency.ConnectionComplianceStatus.SSL" + enum="CTComplianceStatus"> + <obsolete> + Deprecated Nov 2017, replaced with + Net.CertificateTransparency.ConnectionComplianceStatus2 + </obsolete> + <owner>estark@chromium.org</owner> + <summary> + The compliance of each SSL connection with the Certificate Transparency + policy, recorded once on connection setup unless CT evaluation has been + disabled for that connection or the certificate is invalid. Connections can + be compliant, or they can be non-compliant for one of several reasons (not + enough Signed Certificate Timestamps [SCTs], not diverse enough SCTs, or the + build was old so CT compliance wasn't checked). + </summary> +</histogram> + +<histogram base="true" + name="Net.CertificateTransparency.ConnectionComplianceStatus2" + enum="CTComplianceStatus"> +<!-- Name completed by histogram_suffixes name="CertificateTransparencyProtocol" --> + + <owner>estark@chromium.org</owner> + <summary> + The compliance of each connection with the Certificate Transparency policy, + recorded once on connection setup unless CT evaluation has been disabled for + that connection or the certificate is invalid. Connections can be compliant, + or they can be non-compliant for one of several reasons (not enough Signed + Certificate Timestamps [SCTs], not diverse enough SCTs, or the build was old + so CT compliance wasn't checked). Not recorded for certificates that chain + to locally-installed roots. + </summary> +</histogram> + +<histogram + name="Net.CertificateTransparency.CTRequiredConnectionComplianceStatus" + enum="CTComplianceStatus"> + <obsolete> + Deprecated Nov 2017, replaced with + Net.CertificateTransparency.CTRequiredConnectionComplianceStatus2 + </obsolete> + <owner>estark@chromium.org</owner> + <summary> + The compliance of each QUIC connection with the Certificate Transparency + policy, for connections for which CT compliance is required for the + connection to succeed. (For example, CT compliance is required for certain + Certificate Authorities, or a site can opt in to having CT be required.) + Recorded once on connection setup for applicable connections unless CT + evaluation has been disabled for that connection or the certificate is + otherwise invalid. + </summary> +</histogram> + +<histogram + name="Net.CertificateTransparency.CTRequiredConnectionComplianceStatus.SSL" + enum="CTComplianceStatus"> + <obsolete> + Deprecated Nov 2017, replaced with + Net.CertificateTransparency.CTRequiredConnectionComplianceStatus2 + </obsolete> + <owner>estark@chromium.org</owner> + <summary> + The compliance of each SSL connection with the Certificate Transparency + policy, for connections for which CT compliance is required for the + connection to succeed. (For example, CT compliance is required for certain + Certificate Authorities, or a site can opt in to having CT be required.) + Recorded once on connection setup for applicable connections unless CT + evaluation has been disabled for that connection or the certificate is + otherwise invalid. Not recorded for certificates that chain to + locally-installed roots. + </summary> +</histogram> + +<histogram base="true" + name="Net.CertificateTransparency.CTRequiredConnectionComplianceStatus2" + enum="CTComplianceStatus"> +<!-- Name completed by histogram_suffixes name="CertificateTransparencyProtocol" --> + + <owner>estark@chromium.org</owner> + <summary> + The compliance of each connection with the Certificate Transparency policy, + for connections for which CT compliance is required for the connection to + succeed. (For example, CT compliance is required for certain Certificate + Authorities, or a site can opt in to having CT be required.) Recorded once + on connection setup for applicable connections unless CT evaluation has been + disabled for that connection or the certificate is otherwise invalid. Not + recorded for certificates that chain to locally-installed roots. + </summary> +</histogram> + +<histogram name="Net.CertificateTransparency.CTRequiredRequestComplianceStatus" + enum="CTComplianceStatus"> + <owner>estark@chromium.org</owner> + <summary> + The compliance of each HTTP request with the Certificate Transparency + policy, for requests on connections for which CT compliance is required for + the connection to succeed. (For example, CT compliance is required for + certain Certificate Authorities, or a site can opt in to having CT be + required.) Recorded once on request completion for requests on applicable + connections, unless CT evaluation has been disabled for that connection or + the certificate is otherwise invalid. Not recorded when the request's + certificate chains to a locally-installed root. + </summary> +</histogram> + <histogram name="Net.CertificateTransparency.DnsQueryDuration" units="ms"> <owner>robpercival@chromium.org</owner> <summary> @@ -38201,6 +42231,50 @@ </summary> </histogram> +<histogram name="Net.CertificateTransparency.EVCompliance.QUIC" + enum="CTComplianceStatus"> + <obsolete> + Deprecated Nov 2017, replaced with + Net.CertificateTransparency.EVCompliance2.QUIC + </obsolete> + <owner>estark@chromium.org</owner> + <summary> + The state of compliance with Certificate Transparency presence requirements + for each EV certificate. Recorded once on QUIC connection setup when the + connection uses an EV certificate unless CT evaluation has been disabled for + that connection or the certificate is invalid. + </summary> +</histogram> + +<histogram name="Net.CertificateTransparency.EVCompliance.SSL" + enum="CTComplianceStatus"> + <obsolete> + Deprecated Nov 2017, replaced with + Net.CertificateTransparency.EVCompliance2.SSL + </obsolete> + <owner>estark@chromium.org</owner> + <summary> + The state of compliance with Certificate Transparency presence requirements + for each EV certificate. Recorded once on SSL connection setup when the + connection uses an EV certificate unless CT evaluation has been disabled for + that connection or the certificate is invalid. + </summary> +</histogram> + +<histogram base="true" name="Net.CertificateTransparency.EVCompliance2" + enum="CTComplianceStatus"> +<!-- Name completed by histogram_suffixes name="CertificateTransparencyProtocol" --> + + <owner>estark@chromium.org</owner> + <summary> + The state of compliance with Certificate Transparency presence requirements + for each EV certificate. Recorded once on QUIC connection setup when the + connection uses an EV certificate unless CT evaluation has been disabled for + that connection or the certificate is invalid. Not recorded for certificates + that chain to locally-installed roots. + </summary> +</histogram> + <histogram name="Net.CertificateTransparency.InclusionCheckResult" enum="CTLogEntryInclusionCheckResult"> <owner>eranm@chromium.org</owner> @@ -38231,6 +42305,21 @@ </summary> </histogram> +<histogram name="Net.CertificateTransparency.RequestComplianceStatus" + enum="CTComplianceStatus"> + <owner>estark@chromium.org</owner> + <summary> + The compliance of each HTTP request with the Certificate Transparency + policy, recorded once on request completion unless CT evaluation has been + disabled for that request's connection or the certificate is otherwise + invalid. A request's connection can be compliant, or it can be non-compliant + for one of several reasons (not enough Signed Certificate Timestamps [SCTs], + not diverse enough SCTs, or the build was old so CT compliance wasn't + checked). Not recorded when the request's certificate chains to a + locally-installed root. + </summary> +</histogram> + <histogram name="Net.CertificateTransparency.SCTOrigin" enum="SCTOrigin"> <owner>eranm@chromium.org</owner> <summary> @@ -38527,7 +42616,6 @@ <obsolete> Obsoleted in favor of Net.ContentDecodingFailed2.FilterType below. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> For each CONTENT_DECODING_FAILED, record the filter that failed. </summary> @@ -39196,6 +43284,9 @@ </histogram> <histogram name="Net.DetachableResourceHandler.Duration" units="ms"> + <obsolete> + Removed in Chrome 64. + </obsolete> <owner>yhirano@chromium.org</owner> <summary> Duration of time that a request associated with DetachableResourceHandler @@ -39301,6 +43392,9 @@ </histogram> <histogram name="Net.DiskCache.Size" units="MB"> + <obsolete> + Removed in Chrome 65. + </obsolete> <owner>erikchen@chromium.org</owner> <summary> The sum of the size of all files in the HTTP cache directory. @@ -39312,6 +43406,150 @@ </summary> </histogram> +<histogram name="Net.DNS.DnsTask.ErrorBeforeFallback.Fast" enum="NetErrorCodes"> + <owner>mgersh@chromium.org</owner> + <summary> + Counts of specific error codes returned by DnsTask. Only counts failures + that took less than 10ms, which are probably local failures. + </summary> +</histogram> + +<histogram name="Net.DNS.DnsTask.ErrorBeforeFallback.Slow" enum="NetErrorCodes"> + <owner>mgersh@chromium.org</owner> + <summary> + Counts of specific error codes returned by DnsTask. Only counts failures + that took at least 10ms, which are probably remote failures or connectivity + problems. + </summary> +</histogram> + +<histogram name="Net.DNS.DnsTask.Errors" enum="NetErrorCodes"> + <owner>mgersh@chromium.org</owner> + <summary> + Counts of specific error codes returned by DnsTask if a subsequent ProcTask + succeeded. + </summary> +</histogram> + +<histogram name="Net.DNS.DnsTask.FailureTime" units="ms"> + <owner>mgersh@chromium.org</owner> + <summary> + Duration of time taken by DnsTask in resolutions that failed. Excludes time + spent in the subsequent fallback. + </summary> +</histogram> + +<histogram name="Net.DNS.DnsTask.SuccessTime" units="ms"> + <owner>mgersh@chromium.org</owner> + <summary> + Duration of time taken by DnsTask in resolutions that succeeded. + </summary> +</histogram> + +<histogram name="Net.DNS.JobQueueTime" units="ms"> + <owner>mgersh@chromium.org</owner> + <summary> + Time elapsed between the time the HostResolverImpl::Job was created and the + time the Job was started. + </summary> +</histogram> + +<histogram name="Net.DNS.JobQueueTimeAfterChange" units="ms"> + <owner>mgersh@chromium.org</owner> + <summary> + Time elapsed between the last time the priority of a HostResolverImpl::Job + changed (when a Request was attached or detached) and the time the Job was + started. + </summary> +</histogram> + +<histogram name="Net.DNS.ProcTask.FailureTime" units="ms"> + <owner>mgersh@chromium.org</owner> + <summary> + Duration of time taken by ProcTask in resolutions that failed. + </summary> +</histogram> + +<histogram name="Net.DNS.ProcTask.SuccessTime" units="ms"> + <owner>mgersh@chromium.org</owner> + <summary> + Duration of time taken by ProcTask in resolutions that succeeded. + </summary> +</histogram> + +<histogram name="Net.DNS.ResolveCategory" enum="ResolutionCategory"> + <owner>mgersh@chromium.org</owner> + <summary> + Whether a DNS resolution (single HostResolverImpl::Job) succeeded or failed, + and whether it was speculative. + </summary> +</histogram> + +<histogram name="Net.DNS.ResolveError.Fast" enum="NetErrorCodes"> + <owner>mgersh@chromium.org</owner> + <summary> + For DNS resolutions that failed after less than 10 ms, which are probably + local failures, what error code the jobs failed with. + </summary> +</histogram> + +<histogram name="Net.DNS.ResolveError.Slow" enum="NetErrorCodes"> + <owner>mgersh@chromium.org</owner> + <summary> + For DNS resolutions that failed after at least 10 ms, which are probably + remote failures or connectivity problems, what error code the jobs failed + with. + </summary> +</histogram> + +<histogram name="Net.DNS.ResolveFailureTime" units="ms"> + <owner>mgersh@chromium.org</owner> + <summary> + Duration of time taken by HostResolverImpl::Job in resolutions that failed. + This is the time to resolve a hostname from start to finish. The main + histogram and by-priority versions exclude speculative requests. + </summary> +</histogram> + +<histogram name="Net.DNS.ResolveSuccessTime" units="ms"> + <owner>mgersh@chromium.org</owner> + <summary> + Duration of time taken by HostResolverImpl::Job in resolutions that + succeeded. This is the time to resolve a hostname from start to finish. The + main histogram and by-priority versions exclude speculative requests. + </summary> +</histogram> + +<histogram name="Net.DNS.ResultAfterMalformedResponse" + enum="MalformedResponseResult"> + <owner>mgersh@chromium.org</owner> + <summary> + When DnsUDPAttempt gets a malformed response, it returns an error but + continues running. This histogram records all attempt outcomes that are + returned to the transaction once a malformed response has been received, + including the original malformed response. + </summary> +</histogram> + +<histogram name="Net.DNS.TotalTime" units="ms"> + <owner>mgersh@chromium.org</owner> + <summary> + Duration of time since a HostResolverImpl::Resolve request to the time a + result is posted. Excludes canceled, evicted, and aborted requests. Includes + cache hits (recorded as 0). Excludes speculative requests. + </summary> +</histogram> + +<histogram name="Net.DNS.TotalTimeNotCached" units="ms"> + <owner>mgersh@chromium.org</owner> + <summary> + Duration of time since a HostResolverImpl::Resolve request to the time a + result is posted. Excludes canceled, evicted, and aborted requests and + requests that returned synchronously (such as cache hits). Excludes + speculative requests. + </summary> +</histogram> + <histogram name="Net.DNS_Resolution_And_TCP_Connection_Latency"> <obsolete> Deprecated- see Net.DNS_Resolution_And_TCP_Connection_Latency2 @@ -39577,8 +43815,10 @@ <owner>rdsmith@chromium.org</owner> <owner>ellyjones@chromium.org</owner> <summary> - Counts of various events that can occur on the network error page. See the - histogram for details. + Counts of various events that can occur on the network error page. Note that + this histogram enum buckets are not mutually exclusive and so a single error + page load might report samples into multiple ones. Each bucket has + descriptions that further explain the context of their samples. </summary> </histogram> @@ -39623,6 +43863,42 @@ </summary> </histogram> +<histogram name="Net.ExpectCTHeader.ParseSuccess" enum="BooleanSuccess"> + <owner>estark@chromium.org</owner> + <summary> + Sites can send an Expect-CT header to Chrome to indicate that they intend + their sites to comply with Chrome's Certificate Transparency policy. This + histogram is recorded whenever an Expect-CT header is processed on a + connection. True indicates that the header parsed successfully, and false + indicates that there was a parse failure. + </summary> +</histogram> + +<histogram name="Net.ExpectCTHeader.PolicyComplianceOnConnectionSetup" + enum="CTComplianceStatus"> + <owner>estark@chromium.org</owner> + <summary> + Sites can send an Expect-CT header to Chrome to indicate that they intend + their sites to comply with Chrome's Certificate Transparency policy. This + histogram is recorded on connection setup, whenever Chrome connects to an + Expect-CT site using a publicly trusted root. The histogram records the CT + policy compliance status of the connection. + </summary> +</histogram> + +<histogram name="Net.ExpectCTHeader.PolicyComplianceOnHeaderProcessing" + enum="CTComplianceStatus"> + <owner>estark@chromium.org</owner> + <summary> + Sites can send an Expect-CT header to Chrome to indicate that they intend + their sites to comply with Chrome's Certificate Transparency policy. This + histogram is recorded whenever an Expect-CT header is successfully parsed on + a connection that chains to a publicly trusted root. The histogram records + the CT policy compliance status of the connection on which the header was + received. + </summary> +</histogram> + <histogram name="Net.ExpectCTHeaderResult" enum="ExpectCTHeaderResult"> <obsolete> Deprecated 04/2017. @@ -40419,24 +44695,36 @@ <histogram name="Net.HttpStreamFactoryJob.Alt.NextState" enum="HttpStreamFactoryJobState"> + <obsolete> + Deprecated as of 1/2018. + </obsolete> <owner>xunjieli@chromium.org</owner> <summary>Reports the next state that the Alternative Job is in.</summary> </histogram> <histogram name="Net.HttpStreamFactoryJob.Alt.State" enum="HttpStreamFactoryJobState"> + <obsolete> + Deprecated as of 1/2018. + </obsolete> <owner>xunjieli@chromium.org</owner> <summary>Reports the state that the Alternative Job is in.</summary> </histogram> <histogram name="Net.HttpStreamFactoryJob.Main.NextState" enum="HttpStreamFactoryJobState"> + <obsolete> + Deprecated as of 1/2018. + </obsolete> <owner>xunjieli@chromium.org</owner> <summary>Reports the next state that the Main Job is in.</summary> </histogram> <histogram name="Net.HttpStreamFactoryJob.Main.State" enum="HttpStreamFactoryJobState"> + <obsolete> + Deprecated as of 1/2018. + </obsolete> <owner>xunjieli@chromium.org</owner> <summary>Reports the state that the Main Job is in.</summary> </histogram> @@ -40564,6 +44852,9 @@ <histogram name="Net.JobControllerSet.CountOfJobController" units="job_controllers"> + <obsolete> + Deprecated 01/2018. + </obsolete> <owner>zhongyi@chromium.org</owner> <summary> This counts number of all the job controllers that are still alive if the @@ -40574,6 +44865,9 @@ <histogram name="Net.JobControllerSet.CountOfJobController.NonPreconnect.PendingRequest" units="job_controllers"> + <obsolete> + Deprecated 01/2018. + </obsolete> <owner>zhongyi@chromium.org</owner> <summary> This counts number of JobControllers that are still alive, not created for @@ -40584,6 +44878,9 @@ <histogram name="Net.JobControllerSet.CountOfJobController.NonPreconnect.RequestGone" units="job_controllers"> + <obsolete> + Deprecated 01/2018. + </obsolete> <owner>zhongyi@chromium.org</owner> <summary> This counts number of job controllers that are still alive, not created for @@ -40593,6 +44890,9 @@ <histogram name="Net.JobControllerSet.CountOfJobController.Preconnect" units="job_controllers"> + <obsolete> + Deprecated 01/2018. + </obsolete> <owner>zhongyi@chromium.org</owner> <summary> This counts number of job controllers which are used for preconnect and are @@ -40602,6 +44902,9 @@ <histogram name="Net.JobControllerSet.CountOfJobControllerAtShutDown" units="job_controllers"> + <obsolete> + Deprecated 01/2018. + </obsolete> <owner>zhongyi@chromium.org</owner> <summary> This counts number of all the job controllers that are still alive. @@ -40652,6 +44955,24 @@ </summary> </histogram> +<histogram name="Net.KeepaliveStatisticsRecorder.PeakInflightRequests" + units="requests"> + <owner>yhirano@chromium.org</owner> + <summary> + The peak number of concurrent outstanding requests with keepalive specified. + </summary> +</histogram> + +<histogram + name="Net.KeepaliveStatisticsRecorder.PeakInflightRequestsPerProcess" + units="requests"> + <owner>yhirano@chromium.org</owner> + <summary> + The peak number of concurrent outstanding requests with keepalive specified + per render process. + </summary> +</histogram> + <histogram name="Net.LoadPrefetch.Pattern" enum="PrefetchStatus"> <owner>droger@chromium.org</owner> <owner>mattcary@chromium.org</owner> @@ -40845,7 +45166,7 @@ </histogram> <histogram name="Net.OSErrorsForGetAddrinfo" enum="ErrorCodesGetaddrinfo_All"> - <owner>Please list the metric's owners. Add more owner tags as needed.</owner> + <owner>mgersh@chromium.org</owner> <summary> Positive error code that was returned by the system library "getaddrinfo()". This error code is platform specific, so when @@ -40855,7 +45176,7 @@ <histogram name="Net.OSErrorsForGetAddrinfo_Linux" enum="ErrorCodesGetaddrinfo_Linux"> - <owner>Please list the metric's owners. Add more owner tags as needed.</owner> + <owner>mgersh@chromium.org</owner> <summary> Positive error code that was returned by the system library "getaddrinfo()". @@ -40864,7 +45185,7 @@ <histogram name="Net.OSErrorsForGetAddrinfo_Mac" enum="ErrorCodesGetaddrinfo_Mac"> - <owner>Please list the metric's owners. Add more owner tags as needed.</owner> + <owner>mgersh@chromium.org</owner> <summary> Positive error code that was returned by the system library "getaddrinfo()". @@ -40873,7 +45194,7 @@ <histogram name="Net.OSErrorsForGetAddrinfo_Win" enum="ErrorCodesGetaddrinfo_Win"> - <owner>Please list the metric's owners. Add more owner tags as needed.</owner> + <owner>mgersh@chromium.org</owner> <summary> Positive error code that was returned by the system library "getaddrinfo()". @@ -41601,6 +45922,9 @@ </histogram> <histogram name="Net.PushedStreamAlreadyHasResponseHeaders" enum="Boolean"> + <obsolete> + Deprecated 11/2017. + </obsolete> <owner>bnc@chromium.org</owner> <summary> Records whether HTTP/2 response headers have already arrived on a pushed @@ -41609,6 +45933,15 @@ </summary> </histogram> +<histogram name="Net.PushedStreamVaryResponseHeader" + enum="PushedStreamVaryResponseHeaderValues"> + <owner>bnc@chromium.org</owner> + <summary> + Information about the value of the Vary response header in HTTP/2 pushed + streams. + </summary> +</histogram> + <histogram name="Net.QuicActiveSessions"> <owner>rch@chromium.org</owner> <summary> @@ -41625,6 +45958,14 @@ </summary> </histogram> +<histogram name="Net.QuicAltSvcFormat" enum="QuicAltSvcFormat"> + <owner>wangyix@chromium.org</owner> + <summary> + Tracks the number of QUIC alt-svc advertisements parsed by Chrome in Google + format vs in IETF format. + </summary> +</histogram> + <histogram name="Net.QuicClientHelloRejectReasons" enum="QuicRejectReasons"> <owner>rch@chromium.org</owner> <summary> @@ -42008,6 +46349,14 @@ </summary> </histogram> +<histogram name="Net.QuicSession.CertVerificationResult" enum="NetErrorCodes"> + <owner>rch@chromium.org</owner> + <summary> + The network error code returned to a QUIC session from the CertVerifier when + a certification verification is attempted. + </summary> +</histogram> + <histogram name="Net.QuicSession.CertVerifierJob.CompleteTime" units="Milliseconds"> <owner>rch@chromium.org</owner> @@ -42192,7 +46541,6 @@ </histogram> <histogram name="Net.QuicSession.CreationError" enum="QuicSessionErrorCodes"> - <owner>jar@chromium.org</owner> <owner>rch@chromium.org</owner> <summary> Count of errors during attempts to create a QUIC session (before even using @@ -42215,6 +46563,15 @@ </summary> </histogram> +<histogram name="Net.QuicSession.GapBetweenWriteErrorAndNetworkDisconnection" + units="ms"> + <owner>zhongyi@chromium.org</owner> + <summary> + This measures the time gap between the most recent write error and the + network disconnection. + </summary> +</histogram> + <histogram name="Net.QuicSession.GoAwayReceivedForConnectionMigration" enum="BooleanReceived"> <owner>zhongyi@chromium.org</owner> @@ -42471,6 +46828,14 @@ </summary> </histogram> +<histogram name="Net.QuicSession.PlatformNotification" + enum="QuicPlatformNotification"> + <owner>zhongyi@chromium.org</owner> + <summary> + The platform notification received by QUIC when network change happens. + </summary> +</histogram> + <histogram name="Net.QuicSession.PreferAesGcm" enum="BooleanPreferred"> <owner>rch@chromium.org</owner> <summary> @@ -42478,6 +46843,23 @@ </summary> </histogram> +<histogram name="Net.QuicSession.ProbingRetryCountUntilSuccess" units="retries"> + <owner>zhongyi@chromium.org</owner> + <summary> + Number of retries to send connectivity probing packet on new path until + success. + </summary> +</histogram> + +<histogram name="Net.QuicSession.ProbingTimeInMillisecondsUntilSuccess" + units="ms"> + <owner>zhongyi@chromium.org</owner> + <summary> + The wait time to receive a matched probing response to mark connectivity + probing as successful. + </summary> +</histogram> + <histogram name="Net.QuicSession.PublicResetAddressMismatch" enum="QuicAddressMismatch"> <owner>wtc@chromium.org</owner> @@ -42557,6 +46939,24 @@ </summary> </histogram> +<histogram name="Net.QuicSession.RetryAfterWriteErrorCount" units="retries"> + <obsolete> + Deprecated 11/2017. Use Net.QuicSession.RetryAfterWriteErrorCount2. + </obsolete> + <owner>rch@chromium.org</owner> + <summary> + The number of consecutive times a packet was retried after a write error. + </summary> +</histogram> + +<histogram name="Net.QuicSession.RetryAfterWriteErrorCount2" units="retries"> + <owner>rch@chromium.org</owner> + <summary> + The number of consecutive times a packet was retried after a write error, + using exponential backoff. + </summary> +</histogram> + <histogram name="Net.QuicSession.RstStreamErrorCodeClient" enum="QuicRstStreamErrorCodes"> <owner>rch@chromium.org</owner> @@ -42785,6 +47185,15 @@ </summary> </histogram> +<histogram name="Net.QuicSession.WriteError.NetworkDisconnected" + enum="NetErrorCodes"> + <owner>zhongyi@chromium.org</owner> + <summary> + The most recent network error code when attempting to write to a QUIC + connection when the network gets disconnected. + </summary> +</histogram> + <histogram name="Net.QuicSession.WritePacketNotReusableReason" enum="QuicNotReusableReason"> <owner>ckrasic@chromium.org</owner> @@ -42909,7 +47318,6 @@ <obsolete> Replaced by Net.RequestTime2 due to bug in original implementation. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> The amount of time between request initiation and request completion for success and various different errors. @@ -42920,7 +47328,6 @@ <obsolete> Unused, so removed from Chromium as of 2017/8/31. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> The amount of time between request initiation and request completion for success and various different errors. @@ -42985,6 +47392,22 @@ </summary> </histogram> +<histogram name="Net.RequestTime2Success.MainFrame" units="ms"> + <owner>csharrison@chromium.org</owner> + <summary> + The amount of time between request initiation and request completion for + success for main frame resources. + </summary> +</histogram> + +<histogram name="Net.RequestTime2Success.Subresource" units="ms"> + <owner>csharrison@chromium.org</owner> + <summary> + The amount of time between request initiation and request completion for + success for non-main frame resources. + </summary> +</histogram> + <histogram name="Net.ResourceDispatcherHost.OutstandingRequests.PerProcess" units="requests"> <owner>xunjieli@chromium.org</owner> @@ -43016,6 +47439,9 @@ <histogram name="Net.ResourceLoader.ExpectedContentSizeResult" enum="ResourceLoaderExpectedContentSizeResult"> + <obsolete> + Removed 10/2017. + </obsolete> <owner>maksim.sisov@intel.com</owner> <owner>mmenke@chromium.org</owner> <summary> @@ -43052,7 +47478,18 @@ </summary> </histogram> +<histogram name="Net.ResourceLoader.TimeToURLRequestStart" units="ms"> + <owner>csharrison@chromium.org</owner> + <summary> + The time elapsed from URLRequest creation to when a ResourceLoader actually + calls Start on it. + </summary> +</histogram> + <histogram name="Net.ResponseSizeByProcess.Browser" units="KB"> + <obsolete> + The code to record this histogram was removed November 2017. + </obsolete> <owner>juliatuttle@chromium.org</owner> <summary> Count of (post-SSL/proxy, pre-filter) kilobytes received per request made by @@ -43061,6 +47498,9 @@ </histogram> <histogram name="Net.ResponseSizeByProcess.Renderer" units="KB"> + <obsolete> + The code to record this histogram was removed November 2017. + </obsolete> <owner>juliatuttle@chromium.org</owner> <summary> Count of (post-SSL/proxy, pre-filter) kilobytes received per request made by @@ -43069,6 +47509,9 @@ </histogram> <histogram name="Net.ResponseSizeByProcess.Unknown" units="KB"> + <obsolete> + The code to record this histogram was removed November 2017. + </obsolete> <owner>juliatuttle@chromium.org</owner> <summary> Count of (post-SSL/proxy, pre-filter) kilobytes received per request made by @@ -43170,7 +47613,6 @@ <obsolete> Replaced by Net.SocketUnchangeableReceiveBuffer 3/31/2014. </obsolete> - <owner>jar@chromium.org</owner> <summary> The size of a socket's receive buffer when the attempt to change it via setsockopt failed. @@ -43295,7 +47737,7 @@ </histogram> <histogram name="Net.SocketUnchangeableReceiveBuffer" units="Bytes"> - <owner>jar@chromium.org</owner> + <owner>rch@chromium.org</owner> <summary> The size of a socket's receive buffer when the attempt to change it via setsockopt failed. @@ -43303,7 +47745,7 @@ </histogram> <histogram name="Net.SocketUnchangeableSendBuffer" units="Bytes"> - <owner>jar@chromium.org</owner> + <owner>rch@chromium.org</owner> <summary> The size of a socket's send buffer when the attempt to change it via setsockopt failed. @@ -43765,6 +48207,10 @@ </histogram> <histogram name="Net.SSL_AuthRootConsistency" enum="SSLAuthRootConsistency"> + <obsolete> + Deprecated 2018-01 with the transition to a unified root list with OS + fallback. + </obsolete> <owner>rsleevi@chromium.org</owner> <summary> The results of comparing the built-in list of known Windows roots against @@ -44083,6 +48529,19 @@ <summary>Time to complete a certificate verification (error case).</summary> </histogram> +<histogram name="Net.SSLDraftDowngradeTLS13Experiment" enum="BooleanDowngrade"> + <owner>davidben@chromium.org</owner> + <summary> + For each HTTPS connection to the TLS 1.3 experiment server set, whether the + TLS 1.3 anti-downgrade mechanism would have fired. This is to measure the + effects of non-compliant middleboxes on this otherwise safe security + feature. The numbers are only valid while the TLS 1.3 experiment set deploys + a TLS 1.3 draft version compatible with the corresponding Chrome version and + implement the our draft anti-downgrade signal. See + https://crbug.com/boringssl/226. + </summary> +</histogram> + <histogram name="Net.SSLFallbackErrorCode" enum="NetErrorCodes"> <obsolete> Removed June 2016. @@ -44179,6 +48638,9 @@ </histogram> <histogram name="Net.SSLRecordSizeRead" units="bytes"> + <obsolete> + Removed in January 2018. + </obsolete> <owner>davidben@chromium.org</owner> <owner>svaldez@chromium.org</owner> <summary> @@ -44186,6 +48648,22 @@ </summary> </histogram> +<histogram name="Net.SSLRSAKeyUsage.KnownRoot" enum="RSAKeyUsage"> + <owner>davidben@chromium.org</owner> + <summary> + For each TLS connection which uses a known root, an RSA key, and TLS 1.2 or + below, what the result of checking the RSA key usage would have been. + </summary> +</histogram> + +<histogram name="Net.SSLRSAKeyUsage.UnknownRoot" enum="RSAKeyUsage"> + <owner>davidben@chromium.org</owner> + <summary> + For each TLS connection which uses a unknown root, an RSA key, and TLS 1.2 + or below, what the result of checking the RSA key usage would have been. + </summary> +</histogram> + <histogram name="Net.SSLServerKeyExchangeHash" enum="SSLHashAlgorithm"> <obsolete> Replaced by Net.SSLSignatureAlgorithm. @@ -44198,6 +48676,9 @@ </histogram> <histogram name="Net.SSLSessionConcurrentLookupCount"> + <obsolete> + Removed on 2017-10-02. + </obsolete> <owner>nharper@chromium.org</owner> <summary> For each SSL connection where we resume a session and negotiate HTTP/2, the @@ -44653,22 +49134,28 @@ </histogram> <histogram name="Net.UdpSocketBindErrorFromPosix" units="PosixError"> + <obsolete> + Deprecated as of 10/2017. + </obsolete> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <summary>Posix error code from call to bind() UDP socket.</summary> </histogram> <histogram name="Net.UdpSocketBindErrorFromWinOS" units="WinError"> + <obsolete> + Deprecated as of 10/2017. + </obsolete> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <summary>Windows error code from call to bind() UDP socket.</summary> </histogram> <histogram name="Net.UdpSocketRandomBindErrorCode" enum="NetErrorCodes"> - <owner>Please list the metric's owners. Add more owner tags as needed.</owner> + <owner>mgersh@chromium.org</owner> <summary>Chromium error code from call to RandomBind() UDP socket.</summary> </histogram> <histogram name="Net.UDPSocketWinClose" units="ms"> - <owner>Please list the metric's owners. Add more owner tags as needed.</owner> + <owner>rch@chromium.org</owner> <summary>The time spent in closesocket call in UDPSocketWin::Close.</summary> </histogram> @@ -44691,7 +49178,9 @@ </histogram> <histogram name="Net.URLRequestContext.OutstandingRequests" units="count"> - <owner>xunjieli@chromium.org</owner> + <obsolete> + Deprecated 1/1/2018. No longer tracked. + </obsolete> <summary> Indicates the number of URLRequests that are handed out by a URLRequestContext and are not yet destroyed. @@ -44700,7 +49189,9 @@ <histogram name="Net.URLRequestContext.OutstandingRequests.Type" enum="URLRequestAnnotationType"> - <owner>xunjieli@chromium.org</owner> + <obsolete> + Deprecated 1/1/2018. No longer tracked. + </obsolete> <summary> Records the annotation type of the URLRequest that is handed out by a URLRequestContext when Net.URLRequestContext.OutstandingRequests is @@ -45752,7 +50243,7 @@ <histogram name="Network.Shill.Cellular.3GPPRegistrationDelayedDrop" enum="NetworkCellular3GPPRegistrationDelayedDrop"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network diagnostic metric sampling the number of cellular network flakes. A network flake occurs when the signal strength goes below detection @@ -45761,7 +50252,7 @@ </histogram> <histogram name="Network.Shill.Cellular.AutoConnectTotalTime" units="ms"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network diagnostic metric sampling the total amount of time spent from the start of the first auto-connect request until when the cellular @@ -45770,7 +50261,7 @@ </histogram> <histogram name="Network.Shill.Cellular.AutoConnectTries"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network diagnostic metric sampling the number of auto-connect tries that were attempted before the cellular modem successfully connected @@ -45780,7 +50271,7 @@ <histogram name="Network.Shill.Cellular.DevicePresenceStatus" enum="BooleanPresent"> - <owner>zqiu@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network metric that tracks the presence of a Cellular device in the system. A sample is emitted once every 3 minutes. @@ -45792,7 +50283,7 @@ <obsolete> Deprecated 5/2014, and replaced by Network.Shill.DHCPOptionFailureDetected. </obsolete> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network metric that tracks the number of DHCP option failures encountered by Shill. This indicates that Shill is using minimal DHCP @@ -45803,7 +50294,7 @@ <histogram name="Network.Shill.Cellular.Disconnect" enum="NetworkDisconnectType"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network usage metric that tracks whether the cellular network was disconnected due to an error or was explicitly disconnected by the user. @@ -45811,7 +50302,7 @@ </histogram> <histogram name="Network.Shill.Cellular.Drop" enum="NetworkCellularTechnology"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS cellular network metric that tracks the number of drops based on the network technology. @@ -45820,7 +50311,22 @@ <histogram name="Network.Shill.Cellular.ExpiredLeaseLengthSeconds" units="seconds"> - <owner>quiche@chromium.org</owner> + <obsolete> + Deprecated since Chrome OS build 10010.0.0 and superceded by + Network.Shill.Cellular.ExpiredLeaseLengthSeconds2 due to change in number of + buckets (crosreview.com/557297, crosreview.com/703679). + </obsolete> + <owner>benchan@chromium.org</owner> + <summary> + Chrome OS network performance metric that tracks the length of a lease for a + cellular network at the time it expired without the DHCP client being able + to renew it. + </summary> +</histogram> + +<histogram name="Network.Shill.Cellular.ExpiredLeaseLengthSeconds2" + units="seconds"> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network performance metric that tracks the length of a lease for a cellular network at the time it expired without the DHCP client being able @@ -45830,7 +50336,7 @@ <histogram name="Network.Shill.Cellular.IPv6ConnectivityStatus" enum="IPv6ConnectivityStatus"> - <owner>zqiu@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network metric that tracks the presence of complete IPv6 configuration at the time when cellular connection is established. @@ -45839,7 +50345,7 @@ <histogram name="Network.Shill.Cellular.NetworkConnectionIPType" enum="NetworkConnectionIPType"> - <owner>zqiu@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network metric that tracks the types of IP configuration used for establishing cellular connections. @@ -45848,7 +50354,7 @@ <histogram name="Network.Shill.Cellular.OutOfCreditsReason" enum="NetworkCellularOutOfCreditsReason"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS cellular network metric that tracks the number of out-of-credits detected based on the cause that triggered the out-of-credits. @@ -45856,7 +50362,7 @@ </histogram> <histogram name="Network.Shill.Cellular.PortalAttempts"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network diagnostic metric sampling the number of portal detection attempts per pass for a cellular network. This includes failure, timeout and @@ -45865,7 +50371,7 @@ </histogram> <histogram name="Network.Shill.Cellular.PortalAttemptsToOnline"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network diagnostic metric sampling the total number of portal detection attempts performed for a cellular network between the Connected @@ -45875,7 +50381,7 @@ <histogram name="Network.Shill.Cellular.PortalResult" enum="NetworkPortalResult"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network diagnostic metric sampling the result of portal detections for a cellular network. @@ -45883,7 +50389,7 @@ </histogram> <histogram name="Network.Shill.Cellular.SignalStrengthBeforeDrop"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network metric sampling the signal strength (0-100) of the cellular modem before it dropped from the network. @@ -45891,7 +50397,7 @@ </histogram> <histogram name="Network.Shill.Cellular.TimeOnline" units="seconds"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network metric sampling the time spent using cellular to transport data. These data are mostly useful when summed and compared to TimeOnline @@ -45900,7 +50406,7 @@ </histogram> <histogram name="Network.Shill.Cellular.TimeToConfig" units="ms"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network performance metric sampling the time to join a cellular network and configure Layer 3 state. @@ -45908,7 +50414,7 @@ </histogram> <histogram name="Network.Shill.Cellular.TimeToConnect" units="ms"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network performance metric sampling the time to connect a cellular modem. @@ -45916,7 +50422,7 @@ </histogram> <histogram name="Network.Shill.Cellular.TimeToDisable" units="ms"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network performance metric sampling the time to disable a cellular modem. @@ -45924,7 +50430,7 @@ </histogram> <histogram name="Network.Shill.Cellular.TimeToEnable" units="ms"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network performance metric sampling the time to enable a cellular modem. @@ -45932,7 +50438,7 @@ </histogram> <histogram name="Network.Shill.Cellular.TimeToInitialize" units="ms"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network performance metric sampling the time to initialize a cellular modem. @@ -45940,7 +50446,7 @@ </histogram> <histogram name="Network.Shill.Cellular.TimeToOnline" units="ms"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network performance metric sampling the time to determine that a cellular network is online after configuring Layer 3 state. @@ -45948,7 +50454,7 @@ </histogram> <histogram name="Network.Shill.Cellular.TimeToPortal" units="ms"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network performance metric sampling the time to determine that a cellular network is in a captive portal after configuring Layer 3 state. @@ -45956,7 +50462,7 @@ </histogram> <histogram name="Network.Shill.Cellular.TimeToScan" units="ms"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network performance metric sampling the time to scan a cellular network and register a modem. @@ -45965,7 +50471,7 @@ <histogram name="Network.Shill.ConnectionDiagnosticsIssue" enum="ConnectionDiagnosticsIssue"> - <owner>samueltan@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network metric that tracks the connectivity issue diagnosed by the ConnectionDiagnostics class in Shill. This metric is logged each time a @@ -45975,7 +50481,7 @@ </histogram> <histogram name="Network.Shill.CorruptedProfile" enum="NetworkCorruptedProfile"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS cellular network metric that tracks the number of corrupted profiles encountered by Shill. @@ -45984,7 +50490,7 @@ <histogram name="Network.Shill.DarkResumeActionResult" enum="ShillSuspendTerminationDarkResumeActionResult"> - <owner>samueltan@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network diagnostic metric sampling the number of dark resume actions that successfully complete or fail when shill suspends. @@ -45992,7 +50498,7 @@ </histogram> <histogram name="Network.Shill.DarkResumeActionsTimeTaken" units="ms"> - <owner>samueltan@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network diagnostic metric sampling the time in milliseconds it takes dark resume actions to complete when shill suspends. @@ -46003,7 +50509,7 @@ <obsolete> Deprecated 01/2015. Migrated to Network.Shill.DarkResumeActionsTimeTaken. </obsolete> - <owner>samueltan@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network diagnostic metric sampling the time in milliseconds it takes dark resume actions to complete when shill suspends. @@ -46011,7 +50517,7 @@ </histogram> <histogram name="Network.Shill.DarkResumeScanNumRetries"> - <owner>samueltan@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network metric sampling the number of times a dark resume scan is retried in a single dark resume. @@ -46020,7 +50526,7 @@ <histogram name="Network.Shill.DarkResumeScanRetryResult" enum="DarkResumeScanRetryResult"> - <owner>samueltan@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network metric that tracks whether dark resume scan retries led to the system suspending from dark resume in a connected state. This metric is @@ -46030,7 +50536,7 @@ </histogram> <histogram name="Network.Shill.DeviceConnectionStatus" enum="ConnectionStatus"> - <owner>zqiu@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network performance metric that tracks the connection status of the device. A sample is emitted once every 3 minutes. @@ -46038,7 +50544,7 @@ </histogram> <histogram name="Network.Shill.DeviceRemovedEvent" enum="DeviceTechnologyType"> - <owner>zqiu@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network metric that tracks the network device removed events for each device type. @@ -46064,7 +50570,7 @@ <histogram name="Network.Shill.DHCPOptionFailureDetected" enum="NetworkTechnology"> - <owner>zqiu@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network metric that tracks the number of DHCP option failures encountered by Shill for each network technology. This indicates that Shill @@ -46075,7 +50581,7 @@ <histogram name="Network.Shill.Ethernet.DevicePresenceStatus" enum="BooleanPresent"> - <owner>zqiu@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network metric that tracks the presence of an Ethernet device in the system. A sample is emitted once every 3 minutes. @@ -46087,7 +50593,7 @@ <obsolete> Deprecated 5/2014, and replaced by Network.Shill.DHCPOptionFailureDetected. </obsolete> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network metric that tracks the number of DHCP option failures encountered by Shill. This indicates that Shill is using minimal DHCP @@ -46098,7 +50604,7 @@ <histogram name="Network.Shill.Ethernet.Disconnect" enum="NetworkDisconnectType"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network usage metric that tracks whether the Ethernet network was disconnected due to an error or was explicitly disconnected by the user. @@ -46107,7 +50613,22 @@ <histogram name="Network.Shill.Ethernet.ExpiredLeaseLengthSeconds" units="seconds"> - <owner>quiche@chromium.org</owner> + <obsolete> + Deprecated since Chrome OS build 10010.0.0 and superceded by + Network.Shill.Ethernet.ExpiredLeaseLengthSeconds2 due to change in number of + buckets (crosreview.com/557297, crosreview.com/703679). + </obsolete> + <owner>benchan@chromium.org</owner> + <summary> + Chrome OS network performance metric that tracks the length of a lease for + an Ethernet network at the time it expired without the DHCP client being + able to renew it. + </summary> +</histogram> + +<histogram name="Network.Shill.Ethernet.ExpiredLeaseLengthSeconds2" + units="seconds"> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network performance metric that tracks the length of a lease for an Ethernet network at the time it expired without the DHCP client being @@ -46116,7 +50637,7 @@ </histogram> <histogram name="Network.Shill.Ethernet.LinkMonitorBroadcastErrorsAtFailure"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network performance metric that tracks the number of LinkMonitor broadcast errors that were accrued on an Ethernet network at the time that @@ -46126,7 +50647,7 @@ <histogram name="Network.Shill.Ethernet.LinkMonitorFailure" enum="LinkMonitorFailureType"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS metric that signals the type of failure the LinkMonitor encountered which caused it to stop monitoring an Ethernet network. @@ -46135,7 +50656,7 @@ <histogram name="Network.Shill.Ethernet.LinkMonitorResponseTimeSample" units="ms"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network performance metric that tracks the number of milliseconds between an ARP request and a received reply on an Ethernet network. @@ -46144,7 +50665,7 @@ <histogram name="Network.Shill.Ethernet.LinkMonitorSecondsToFailure" units="seconds"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network performance metric that tracks the number of seconds from the start of the LinkMonitor until failure on an Ethernet network. @@ -46152,7 +50673,7 @@ </histogram> <histogram name="Network.Shill.Ethernet.LinkMonitorUnicastErrorsAtFailure"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network performance metric that tracks the number of LinkMonitor unicast errors that were accrued on an Ethernet network at the time that the @@ -46161,7 +50682,7 @@ </histogram> <histogram name="Network.Shill.Ethernet.PortalAttempts"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network diagnostic metric sampling the number of portal detection attempts per pass for an Ethernet network. This includes failure, timeout @@ -46170,7 +50691,7 @@ </histogram> <histogram name="Network.Shill.Ethernet.PortalAttemptsToOnline"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network diagnostic metric sampling the total number of portal detection attempts performed for an Ethernet network between the Connected @@ -46180,7 +50701,7 @@ <histogram name="Network.Shill.Ethernet.PortalResult" enum="NetworkPortalResult"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network diagnostic metric sampling the result of portal detections for an Ethernet network. @@ -46188,7 +50709,7 @@ </histogram> <histogram name="Network.Shill.Ethernet.TimeOnline" units="seconds"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network metric sampling the time spent using Ethernet to transport data. These data are mostly useful when summed and compared to TimeOnline @@ -46197,7 +50718,7 @@ </histogram> <histogram name="Network.Shill.Ethernet.TimeToConfig" units="ms"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network performance metric sampling the time to join a wired Ethernet network and configure Layer 3 state (typically acquire a DHCP @@ -46206,7 +50727,7 @@ </histogram> <histogram name="Network.Shill.Ethernet.TimeToInitialize" units="ms"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network performance metric sampling the time to initialize an Ethernet device. @@ -46214,7 +50735,7 @@ </histogram> <histogram name="Network.Shill.Ethernet.TimeToOnline" units="ms"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network performance metric sampling the time to determine that an Ethernet network is online after configuring Layer 3 state. @@ -46222,7 +50743,7 @@ </histogram> <histogram name="Network.Shill.Ethernet.TimeToPortal" units="ms"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network performance metric sampling the time to determine that an Ethernet network is in a captive portal after configuring Layer 3 state. @@ -46239,12 +50760,12 @@ </histogram> <histogram name="Network.Shill.ServiceErrors" enum="NetworkServiceError"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary>Chrome OS connection manager service errors seen.</summary> </histogram> <histogram name="Network.Shill.ServicesOnSameNetwork"> - <owner>zqiu@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network metric sampling the number of services that are connected to the currently connected network. @@ -46253,7 +50774,7 @@ <histogram name="Network.Shill.SuspendActionResult" enum="ShillSuspendTerminationDarkResumeActionResult"> - <owner>samueltan@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network diagnostic metric sampling the number of suspend actions that successfully complete or fail when shill suspends. @@ -46261,7 +50782,7 @@ </histogram> <histogram name="Network.Shill.SuspendActionsTimeTaken" units="ms"> - <owner>samueltan@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network diagnostic metric sampling the time in milliseconds it takes suspend actions to complete when shill suspends. @@ -46272,7 +50793,7 @@ <obsolete> Deprecated 01/2015. Migrated to Network.Shill.SuspendActionsTimeTaken. </obsolete> - <owner>samueltan@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network diagnostic metric sampling the time in milliseconds it takes suspend actions to complete when shill suspends. @@ -46281,7 +50802,7 @@ <histogram name="Network.Shill.TerminationActionResult" enum="ShillSuspendTerminationDarkResumeActionResult"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network diagnostic metric sampling the number of termination actions that successfully complete or fail when shill terminates. Previously @@ -46294,7 +50815,7 @@ <obsolete> Deprecated 10/2014. Migrated to Network.Shill.SuspendActionResult. </obsolete> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network diagnostic metric sampling the number of termination actions that successfully complete or fail when shill suspends. @@ -46306,7 +50827,7 @@ <obsolete> Deprecated 10/2014. Migrated to Network.Shill.TerminationActionResult. </obsolete> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network diagnostic metric sampling the number of termination actions that successfully complete or fail when shill terminates. @@ -46314,7 +50835,7 @@ </histogram> <histogram name="Network.Shill.TerminationActionsTimeTaken" units="ms"> - <owner>samueltan@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network diagnostic metric sampling the time in milliseconds it takes termination actions to complete when shill terminates. @@ -46325,7 +50846,7 @@ <obsolete> Deprecated 01/2015. Migrated to Network.Shill.TerminationActionsTimeTaken. </obsolete> - <owner>samueltan@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network diagnostic metric sampling the time in milliseconds it takes termination actions to complete when shill terminates. @@ -46336,7 +50857,7 @@ <obsolete> Deprecated 10/2014. Migrated to Network.Shill.SuspendActionTime. </obsolete> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network diagnostic metric sampling the time in milliseconds it takes termination actions to complete when shill suspends. @@ -46347,7 +50868,7 @@ <obsolete> Deprecated 10/2014. Migrated to Network.Shill.TerminationActionTime. </obsolete> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network diagnostic metric sampling the time in milliseconds it takes termination actions to complete when shill terminates. @@ -46355,7 +50876,7 @@ </histogram> <histogram name="Network.Shill.TimeToDrop" units="seconds"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network stability metric sampling the time in seconds between the networking going online to going offline. Offline events due to device @@ -46365,14 +50886,14 @@ </histogram> <histogram name="Network.Shill.UserInitiatedEvents" enum="UserInitiatedEvent"> - <owner>zqiu@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network metric that tracks the number of user-initiated events. </summary> </histogram> <histogram name="Network.Shill.Vpn.Driver" enum="VPNDriver"> - <owner>quiche@chromium.org</owner> + <owner>cernekee@chromium.org</owner> <summary> Chrome OS network usage metric sampled on each successful VPN connection that tracks the VPN connection type. @@ -46381,7 +50902,7 @@ <histogram name="Network.Shill.Vpn.RemoteAuthenticationType" enum="VPNRemoteAuthenticationType"> - <owner>quiche@chromium.org</owner> + <owner>cernekee@chromium.org</owner> <summary> Chrome OS network usage metric sampled on each successful VPN connection that tracks the remote authentication method. @@ -46389,7 +50910,7 @@ </histogram> <histogram name="Network.Shill.Vpn.TimeOnline" units="ms"> - <owner>quiche@chromium.org</owner> + <owner>cernekee@chromium.org</owner> <summary> Chrome OS network metric sampling the time spent using VPN to transport data. These data are mostly useful when summed and compared to TimeOnline @@ -46401,7 +50922,7 @@ </histogram> <histogram name="Network.Shill.Vpn.TimeToConfig" units="ms"> - <owner>quiche@chromium.org</owner> + <owner>cernekee@chromium.org</owner> <summary> Chrome OS network performance metric sampling the time to configure Layer 3 state on a VPN network (typically acquire a DHCP lease). @@ -46409,7 +50930,7 @@ </histogram> <histogram name="Network.Shill.Vpn.TimeToOnline" units="ms"> - <owner>quiche@chromium.org</owner> + <owner>cernekee@chromium.org</owner> <summary> Chrome OS network performance metric sampling the time to determine that a WiMax network is online after configuring Layer 3 state. @@ -46418,15 +50939,68 @@ <histogram name="Network.Shill.Vpn.UserAuthenticationType" enum="VPNUserAuthenticationType"> - <owner>quiche@chromium.org</owner> + <owner>cernekee@chromium.org</owner> <summary> Chrome OS network usage metric sampled on each successful VPN connection that tracks the user authentication method. </summary> </histogram> +<histogram name="Network.Shill.WiFi.Ap80211kSupport" enum="WiFiAp80211kSupport"> + <owner>matthewmwang@chromium.org</owner> + <summary> + Chrome OS network metric sampling the number of Wireless Access Points that + support the 802.11k standard, sampled on successful connections to an AP. + </summary> +</histogram> + +<histogram name="Network.Shill.WiFi.Ap80211rSupport" enum="WiFiAp80211rSupport"> + <owner>matthewmwang@chromium.org</owner> + <summary> + Chrome OS network metric sampling the number of Wireless Access Points that + support the 802.11r standard, sampled on successful connections to an AP. + </summary> +</histogram> + +<histogram name="Network.Shill.WiFi.Ap80211vBSSMaxIdlePeriodSupport" + enum="WiFiAp80211vBSSMaxIdlePeriodSupport"> + <owner>matthewmwang@chromium.org</owner> + <summary> + Chrome OS network metric sampling the number of Wireless Access Points that + support the 802.11v BSS Max Idle Period feature, sampled on successful + connections to an AP. + </summary> +</histogram> + +<histogram name="Network.Shill.WiFi.Ap80211vBSSTransitionSupport" + enum="WiFiAp80211vBSSTransitionSupport"> + <owner>matthewmwang@chromium.org</owner> + <summary> + Chrome OS network metric sampling the number of Wireless Access Points that + support the 802.11v BSS Transition feature, sampled on successful + connections to an AP. + </summary> +</histogram> + +<histogram name="Network.Shill.WiFi.Ap80211vDMSSupport" + enum="WiFiAp80211vDMSSupport"> + <owner>matthewmwang@chromium.org</owner> + <summary> + Chrome OS network metric sampling the number of Wireless Access Points that + support the 802.11v DMS feature, sampled on successful connections to an AP. + </summary> +</histogram> + +<histogram name="Network.Shill.WiFi.ApChannelSwitch" enum="WiFiApChannelSwitch"> + <owner>matthewmwang@chromium.org</owner> + <summary> + Chrome OS network usage metric sampled when an AP switches channels. Shows + the old frequency band and the new frequency band. + </summary> +</histogram> + <histogram name="Network.Shill.WiFi.ApDisconnectReason" enum="WiFiReasonCode"> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network usage metric. Reason code reported when the AP disconnects a WiFi connection. @@ -46434,7 +51008,7 @@ </histogram> <histogram name="Network.Shill.WiFi.ApDisconnectType" enum="WiFiStatusType"> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network usage metric. Broad category of reason AP disconnected a WiFi connection. @@ -46442,7 +51016,7 @@ </histogram> <histogram name="Network.Shill.Wifi.ApMode" enum="WiFiApMode"> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network usage metric. The AP mode setting for each successful WiFi connection. @@ -46450,7 +51024,7 @@ </histogram> <histogram name="Network.Shill.WiFi.AutoConnectableServices"> - <owner>zqiu@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network metric sampling the number of wifi services available for auto-connect when auto-connect is initiated for wifi device. @@ -46458,7 +51032,7 @@ </histogram> <histogram name="Network.Shill.WiFi.AvailableBSSesAtConnect"> - <owner>zqiu@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network metric sampling the number of BSSes (endpoints) available for the currently connecting wifi service. @@ -46466,7 +51040,7 @@ </histogram> <histogram name="Network.Shill.Wifi.Channel" enum="NetworkChannelType"> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network usage metric. The channel used for each successful WiFi connection. @@ -46475,7 +51049,7 @@ <histogram name="Network.Shill.WiFi.ClientDisconnectReason" enum="WiFiReasonCode"> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network usage metric. Reason code reported when the client disconnects a WiFi connection. @@ -46483,7 +51057,7 @@ </histogram> <histogram name="Network.Shill.WiFi.ClientDisconnectType" enum="WiFiStatusType"> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network usage metric. Broad category of reason client disconnected a WiFi connection. @@ -46492,7 +51066,7 @@ <histogram name="Network.Shill.WiFi.DarkResumeUnmatchedScanResultsReceived" enum="DarkResumeUnmatchedScanResultReceived"> - <owner>samueltan@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network metric that tracks whether any unmatched scan results are received during dark resume cycles. An unmatched scan result is a set of @@ -46503,14 +51077,14 @@ <histogram name="Network.Shill.WiFi.DarkResumeWakeReason" enum="DarkResumeWakeReason"> - <owner>samueltan@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network metric that tracks the wake reason for dark resume. </summary> </histogram> <histogram name="Network.Shill.Wifi.DevicePresenceStatus" enum="BooleanPresent"> - <owner>zqiu@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network metric that tracks the presence of a WiFi device in the system. A sample is emitted once every 3 minutes. @@ -46522,7 +51096,7 @@ <obsolete> Deprecated 5/2014, and replaced by Network.Shill.DHCPOptionFailureDetected. </obsolete> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network metric that tracks the number of DHCP option failures encountered by Shill. This indicates that Shill is using minimal DHCP @@ -46532,7 +51106,7 @@ </histogram> <histogram name="Network.Shill.Wifi.Disconnect" enum="NetworkDisconnectType"> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network usage metric that tracks whether an 802.11 wireless network was disconnected due to an error or was explicitly disconnected by @@ -46541,7 +51115,7 @@ </histogram> <histogram name="Network.Shill.Wifi.EapInnerProtocol" enum="EAPInnerProtocol"> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network usage metric sampled on each successful 802.1x wireless connection that tracks the configured inner authentication method. @@ -46549,7 +51123,7 @@ </histogram> <histogram name="Network.Shill.Wifi.EapOuterProtocol" enum="EAPOuterProtocol"> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network usage metric sampled on each successful 802.1x wireless connection that tracks the configured outer authentication method. @@ -46557,7 +51131,21 @@ </histogram> <histogram name="Network.Shill.Wifi.ExpiredLeaseLengthSeconds" units="seconds"> - <owner>quiche@chromium.org</owner> + <obsolete> + Deprecated since Chrome OS build 10010.0.0 and superceded by + Network.Shill.Wifi.ExpiredLeaseLengthSeconds2 due to change in number of + buckets (crosreview.com/557297, crosreview.com/703679). + </obsolete> + <owner>kirtika@chromium.org</owner> + <summary> + Chrome OS network performance metric that tracks the length of a lease for a + WiFi network at the time it expired without the DHCP client being able to + renew it. + </summary> +</histogram> + +<histogram name="Network.Shill.Wifi.ExpiredLeaseLengthSeconds2" units="seconds"> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network performance metric that tracks the length of a lease for a WiFi network at the time it expired without the DHCP client being able to @@ -46567,7 +51155,7 @@ <histogram name="Network.Shill.Wifi.FallbackDNSTestResult" enum="FallbackDNSTestResult"> - <owner>zqiu@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network performance metric that tracks the result of the fallback DNS test. The fallback DNS test is performed when portal detection failed @@ -46576,7 +51164,7 @@ </histogram> <histogram name="Network.Shill.WiFi.FrequenciesConnectedEver"> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS metric sampling the number of different frequencies (i.e. channels) on which a device has connected to a WiFi network. This value is @@ -46589,7 +51177,7 @@ <histogram name="Network.Shill.Wifi.IPv6ConnectivityStatus" enum="IPv6ConnectivityStatus"> - <owner>zqiu@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network metric that tracks the presence of complete IPv6 configuration at the time when WiFi connection is established. @@ -46597,7 +51185,7 @@ </histogram> <histogram name="Network.Shill.Wifi.LinkMonitorBroadcastErrorsAtFailure"> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network performance metric that tracks the number of LinkMonitor broadcast errors that were accrued on an 802.11 wireiless network at the @@ -46607,7 +51195,7 @@ <histogram name="Network.Shill.Wifi.LinkMonitorFailure" enum="LinkMonitorFailureType"> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS metric that signals the type of failure the LinkMonitor encountered which caused it to stop monitoring an 802.11 wireless network. @@ -46615,7 +51203,7 @@ </histogram> <histogram name="Network.Shill.Wifi.LinkMonitorResponseTimeSample" units="ms"> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network performance metric that tracks the number of milliseconds between an ARP request and a received reply on an 802.11 wireless network. @@ -46624,7 +51212,7 @@ <histogram name="Network.Shill.Wifi.LinkMonitorSecondsToFailure" units="seconds"> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network performance metric that tracks the number of seconds from the start of the LinkMonitor until failure on an 802.11 wireless network. @@ -46632,7 +51220,7 @@ </histogram> <histogram name="Network.Shill.Wifi.LinkMonitorUnicastErrorsAtFailure"> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network performance metric that tracks the number of LinkMonitor unicast errors that were accrued on an 802.11 wireless network at the time @@ -46642,7 +51230,7 @@ <histogram name="Network.Shill.Wifi.NetworkConnectionIPType" enum="NetworkConnectionIPType"> - <owner>zqiu@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network metric that tracks the types of IP configuration used for establishing WiFi connections. @@ -46651,7 +51239,7 @@ <histogram name="Network.Shill.Wifi.NetworkProblemDetected" enum="NetworkProblemType"> - <owner>zqiu@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network performance metric that tracks the network problems encountered by TrafficMonitor after WiFi connection is established. @@ -46659,7 +51247,7 @@ </histogram> <histogram name="Network.Shill.Wifi.PhyMode" enum="NetworkPhyModeType"> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network usage metric. The channel type used for each successful WiFi connection. @@ -46667,7 +51255,7 @@ </histogram> <histogram name="Network.Shill.Wifi.PortalAttempts"> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network diagnostic metric sampling the number of portal detection attempts per pass for an 802.11 wireless network. This includes failure, @@ -46676,7 +51264,7 @@ </histogram> <histogram name="Network.Shill.Wifi.PortalAttemptsToOnline"> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network diagnostic metric sampling the total number of portal detection attempts performed for an 802.11 wireless network between the @@ -46686,7 +51274,7 @@ </histogram> <histogram name="Network.Shill.Wifi.PortalResult" enum="NetworkPortalResult"> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network diagnostic metric sampling the result of portal detections for an 802.11 wireless network. @@ -46704,7 +51292,7 @@ </histogram> <histogram name="Network.Shill.WiFi.RememberedSystemNetworkCount"> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network metric sampling the number of 802.11 wireless networks configured from the system configuration profile. This metric is sampled @@ -46718,7 +51306,7 @@ </histogram> <histogram name="Network.Shill.WiFi.RememberedUserNetworkCount"> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network metric sampling the number of 802.11 wireless networks configured from a user configuration profile. This metric is sampled each @@ -46727,7 +51315,7 @@ </histogram> <histogram name="Network.Shill.WiFi.ScanResult" enum="WiFiScanResult"> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network usage metric describing, for a WiFi scan attempt, what scan method is used and whether it ends in a connection. @@ -46735,7 +51323,7 @@ </histogram> <histogram name="Network.Shill.WiFi.ScanTimeInEbusy" units="ms"> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network usage metric describing, for a WiFi scan attempt, how many milliseconds were spent waiting to talk to the kernel/drivers. @@ -46743,7 +51331,7 @@ </histogram> <histogram name="Network.Shill.Wifi.Security" enum="NetworkSecurityType"> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network usage metric. The security setting for each successful WiFi connection. @@ -46759,7 +51347,7 @@ </histogram> <histogram name="Network.Shill.Wifi.SignalStrength" units="negative dBm"> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network metric indicating the negative of the dBm received signal strength recorded at the time a successful WiFi connection started. @@ -46767,7 +51355,7 @@ </histogram> <histogram name="Network.Shill.WiFi.StoppedTxQueueLength" units="frames"> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network metric indicating the maximal length of any stopped mac80211 transmit queue. The metric is reported when a queue-status check @@ -46778,7 +51366,7 @@ <histogram name="Network.Shill.WiFi.StoppedTxQueueReason" enum="NetworkQueueStopReason"> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network metric indicating the reason that mac80211 transmit queues were stopped. The metric is reported when a queue-status check determines @@ -46841,7 +51429,7 @@ </histogram> <histogram name="Network.Shill.Wifi.TimeOnline" units="seconds"> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network metric sampling the time spent using WiFi to transport data. These data are mostly useful when summed and compared to TimeOnline @@ -46850,7 +51438,7 @@ </histogram> <histogram name="Network.Shill.Wifi.TimeResumeToReady" units="ms"> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network performance metric sampling the time from the resume event to the time when an 802.11 wireless network has configured its Layer 3 @@ -46859,7 +51447,7 @@ </histogram> <histogram name="Network.Shill.Wifi.TimeToConfig" units="ms"> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network performance metric sampling the time to configure Layer 3 state on an 802.11 wireless network (typically acquire a DHCP lease). @@ -46867,7 +51455,7 @@ </histogram> <histogram name="Network.Shill.Wifi.TimeToConnect" units="ms"> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network performance metric sampling the time to connect to a WiFi Basic Service Set (which consists of the access point and associated @@ -46876,7 +51464,7 @@ </histogram> <histogram name="Network.Shill.Wifi.TimeToInitialize" units="ms"> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network performance metric sampling the time to initialize an 802.11 wireless device. @@ -46884,7 +51472,7 @@ </histogram> <histogram name="Network.Shill.Wifi.TimeToJoin" units="ms"> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network performance metric sampling the time to join (associate plus authenticate) an 802.11 wireless network. @@ -46892,7 +51480,7 @@ </histogram> <histogram name="Network.Shill.Wifi.TimeToOnline" units="ms"> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network performance metric sampling the time to determine that an 802.11 wireless network is online after configuring Layer 3 state. @@ -46900,7 +51488,7 @@ </histogram> <histogram name="Network.Shill.Wifi.TimeToPortal" units="ms"> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network performance metric sampling the time to determine that an 802.11 wireless network is in a captive portal after configuring Layer 3 @@ -46909,7 +51497,7 @@ </histogram> <histogram name="Network.Shill.Wifi.TimeToScan" units="ms"> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network performance metric sampling the time to scan WiFi until a connection is found. @@ -46917,7 +51505,7 @@ </histogram> <histogram name="Network.Shill.Wifi.TimeToScanAndConnect" units="ms"> - <owner>quiche@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network performance metric sampling the time between the beginning of a WiFi scan (if the scan includes both a progressive scan and a full @@ -46927,7 +51515,7 @@ </histogram> <histogram name="Network.Shill.WiFi.TransmitBitrateMbps" units="Mbps"> - <owner>zqiu@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network performance metric that tracks the transmit bitrate in Mbps for the wifi device when it is connected to a network. The bitrate is @@ -46936,7 +51524,7 @@ </histogram> <histogram name="Network.Shill.Wifi.UnreliableLinkSignalStrength"> - <owner>zqiu@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network metric sampling the signal strength (0-100) of the wifi network when it becomes unreliable (experiencing multiple link failures in a @@ -46946,7 +51534,7 @@ <histogram name="Network.Shill.WiFi.UserInitiatedConnectionFailureReason" enum="ConnectionFailureReason"> - <owner>zqiu@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network performance metric that tracks the reasons of failed user-initiated WiFi connection attempts. The result of the user-initiated @@ -46957,7 +51545,7 @@ <histogram name="Network.Shill.WiFi.UserInitiatedConnectionResult" enum="ConnectionResult"> - <owner>zqiu@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network performance metric that tracks the result of user-initiated WiFi connection attempts. @@ -46966,7 +51554,7 @@ <histogram name="Network.Shill.WiFi.VerifyWakeOnWiFiSettingsResult" enum="VerifyWakeOnWiFiSettingsResult"> - <owner>samueltan@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network diagnostic metric sampling the number of times NIC wake on WiFi settings verification succeeds or fails in shill. This metric is @@ -46977,7 +51565,7 @@ <histogram name="Network.Shill.WiFi.WakeOnWiFiFeaturesEnabledState" enum="WakeOnWiFiFeaturesEnabledState"> - <owner>samueltan@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network usage metric that tracks the wake on WiFi features that are enabled in shill. Recorded once every 10 minutes. @@ -46986,7 +51574,7 @@ <histogram name="Network.Shill.WiFi.WakeOnWiFiThrottled" enum="WakeOnWiFiThrottled"> - <owner>samueltan@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network metric that tracks whether wake on WiFi was disabled during a period of system suspension because of too many dark resume wakes. @@ -46997,7 +51585,7 @@ <histogram name="Network.Shill.WiFi.WakeReasonReceivedBeforeOnDarkResume" enum="WakeReasonReceivedBeforeOnDarkResume"> - <owner>samueltan@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network metric that tracks whether a wake reason was received during dark resume before executing WakeOnWiFi::OnDarkResume. @@ -47006,7 +51594,7 @@ <histogram name="Network.Shill.WiFi.WiFiConnectionStatusAfterWake" enum="WiFiConnectionStatusAfterWake"> - <owner>samueltan@chromium.org</owner> + <owner>kirtika@chromium.org</owner> <summary> Chrome OS network usage metric that tracks the WiFi connection status after waking from suspend, both when wake on WiFi is enabled and disabled. @@ -47016,7 +51604,7 @@ <histogram name="Network.Shill.Wimax.DevicePresenceStatus" enum="BooleanPresent"> - <owner>zqiu@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network metric that tracks the presence of a WiMax device in the system. A sample is emitted once every 3 minutes. @@ -47028,7 +51616,7 @@ <obsolete> Deprecated 5/2014, and replaced by Network.Shill.DHCPOptionFailureDetected. </obsolete> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network metric that tracks the number of DHCP option failures encountered by Shill. This indicates that Shill is using minimal DHCP @@ -47038,7 +51626,22 @@ </histogram> <histogram name="Network.Shill.Wimax.ExpiredLeaseLengthSeconds" units="seconds"> - <owner>quiche@chromium.org</owner> + <obsolete> + Deprecated since Chrome OS build 10010.0.0 and superceded by + Network.Shill.Wimax.ExpiredLeaseLengthSeconds2 due to change in number of + buckets (crosreview.com/557297, crosreview.com/703679). + </obsolete> + <owner>benchan@chromium.org</owner> + <summary> + Chrome OS network performance metric that tracks the length of a lease for a + WiMax network at the time it expired without the DHCP client being able to + renew it. + </summary> +</histogram> + +<histogram name="Network.Shill.Wimax.ExpiredLeaseLengthSeconds2" + units="seconds"> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network performance metric that tracks the length of a lease for a WiMax network at the time it expired without the DHCP client being able to @@ -47047,7 +51650,7 @@ </histogram> <histogram name="Network.Shill.Wimax.TimeToConfig" units="ms"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network performance metric sampling the time to configure Layer 3 state on a WiMax network (typically acquire a DHCP lease). @@ -47055,7 +51658,7 @@ </histogram> <histogram name="Network.Shill.Wimax.TimeToInitialize" units="ms"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network performance metric sampling the time to initialize a WiMax device. @@ -47063,7 +51666,7 @@ </histogram> <histogram name="Network.Shill.Wimax.TimeToOnline" units="ms"> - <owner>quiche@chromium.org</owner> + <owner>benchan@chromium.org</owner> <summary> Chrome OS network performance metric sampling the time to determine that a WiMax network is online after configuring Layer 3 state. @@ -47131,6 +51734,22 @@ </summary> </histogram> +<histogram name="Network.URLLoader.BodyReadFromNetBeforePaused" units="bytes"> + <owner>yzshen@chromium.org</owner> + <summary> + How much, in bytes, of the response body has been read from network by a + URLLoader before it pauses reading, when it receives a + PauseReadingBodyFromNet() call. If there are multiple calls to + PauseReadingBodyFromNet(), only a single value is recorded for the last + call. This histogram is recorded by URLLoader implementations that fetch + from network. When SafeBrowsing indicates that a resource may be unsafe and + therefore a more time-consuming check is required to classify it, reading + response body from network is paused in order to reduce the chance of + writing unsafe contents into cache. This histogram is useful to evaluate how + much data is cached during this window. + </summary> +</histogram> + <histogram name="Network.Wifi.AuthMode" enum="NetworkAuthModeType"> <obsolete> Deprecated 04/2016 as doesn't have data nor owner. @@ -47419,7 +52038,7 @@ </histogram> <histogram name="NewTabPage.AnimatedLogoDownloadTime" units="ms"> - <owner>ianwen@chromium.org</owner> + <owner>treib@chromium.org</owner> <summary> The amount of time it takes to download the animated logo. Android only. </summary> @@ -47474,6 +52093,11 @@ <histogram name="NewTabPage.ContentSuggestions.BreakingNews.MessageReceived" enum="ContentSuggestionsBreakingNewsMessageContainsNews"> + <obsolete> + Deprecated in October 2017 (M64) and replaced by + NewTabPage.ContentSuggestions.BreakingNews.ReceivedMessageAction, when + adding support for push-to-refresh messages. + </obsolete> <owner>vitaliii@chromium.org</owner> <summary> Android: Number of received messages and whether they contain pushed news. A @@ -47484,6 +52108,17 @@ </histogram> <histogram + name="NewTabPage.ContentSuggestions.BreakingNews.ReceivedMessageAction" + enum="ContentSuggestionsBreakingNewsMessageAction"> + <owner>mamir@chromium.org</owner> + <summary> + Android: Action of a received message. An action can be either push-by-value + or push-to-refresh. A message with a missing or invalid action is recorded + as well. Recorded when a message is received. + </summary> +</histogram> + +<histogram name="NewTabPage.ContentSuggestions.BreakingNews.SubscriptionRequestStatus" enum="ContentSuggestionsStatusCode"> <owner>vitaliii@chromium.org</owner> @@ -47575,6 +52210,13 @@ <histogram name="NewTabPage.ContentSuggestions.CountOnNtpOpenedIfVisible.Articles.Prefetched.Offline"> + <obsolete> + Deprecated in October 2017 (M63) and replaced by + CountOnNtpOpenedIfVisible.Articles.Prefetched.Offline2, because + underreported. UI checked whether a URL is prefetched asynchronously. As a + result, there was a race condition and this metric could be reported before + all URLs are checked. + </obsolete> <owner>vitaliii@chromium.org</owner> <summary> Android: The number of prefetched suggestion cards that were available in @@ -47584,6 +52226,19 @@ </summary> </histogram> +<histogram + name="NewTabPage.ContentSuggestions.CountOnNtpOpenedIfVisible.Articles.Prefetched.Offline2" + units="suggestions"> + <owner>vitaliii@chromium.org</owner> + <summary> + Android: The number of prefetched suggestion cards that were available in + Articles category if it was visible at the time an NTP was opened and the + user was offline. Analogous to + NewTabPage.ContentSuggestions.CountOnNtpOpenedIfVisible, except that this + metric is reported after all URL prefetched asynchronous checks finish. + </summary> +</histogram> + <histogram name="NewTabPage.ContentSuggestions.DismissedUnvisited" units="index"> <owner>treib@chromium.org</owner> @@ -47839,6 +52494,13 @@ <histogram name="NewTabPage.ContentSuggestions.Shown.Articles.Prefetched.Offline" units="index"> + <obsolete> + Deprecated in October 2017 (M63) and replaced by + Shown.Articles.Prefetched.Offline2, because underreported. UI checked + whether a URL is prefetched asynchronously. As a result, there was a race + condition and for suggestions immediately visible on the suggestions surface + this metric could be reported before their URLs are actually checked. + </obsolete> <owner>vitaliii@chromium.org</owner> <summary> Android: The position of a prefetched suggestion card that was shown on the @@ -47852,6 +52514,24 @@ </summary> </histogram> +<histogram + name="NewTabPage.ContentSuggestions.Shown.Articles.Prefetched.Offline2" + units="index"> + <owner>vitaliii@chromium.org</owner> + <summary> + Android: The position of a prefetched suggestion card that was shown on the + NTP when offline. Analogous to NewTabPage.ContentSuggestions.Shown. That is + a card is considered shown when at least 1/3 of its height is visible on the + screen. For each card, at most one impression is recorded per NTP instance. + We track the position the card had in the list when it was first seen by the + user. This tracked position can be different from the position observed by + the user, e.g. when the user dismissed some suggestions from the list or + requested more that got inserted in the middle of the feed. This metric is + reported not immediately after the impression, but once the request to + Offline Page model to check the URL finishes. + </summary> +</histogram> + <histogram name="NewTabPage.ContentSuggestions.ShownAge" units="ms"> <owner>treib@chromium.org</owner> <summary> @@ -47976,6 +52656,15 @@ </summary> </histogram> +<histogram base="true" + name="NewTabPage.ContentSuggestions.TimeUntilStartupFetch" units="ms"> + <owner>jkrcal@chromium.org</owner> + <summary> + Android: The time since the last fetch, recorded upon a startup fetch. This + is used to understand what are the real soft fetching intervals in the wild. + </summary> +</histogram> + <histogram name="NewTabPage.ContentSuggestions.UIUpdateResult" enum="ContentSuggestionsUIUpdateResult"> <obsolete> @@ -48167,30 +52856,28 @@ </histogram> <histogram name="NewTabPage.LogoClick" enum="NewTabPageLogoClick"> - <owner>ianwen@chromium.org</owner> + <owner>treib@chromium.org</owner> <summary> - Histogram tracking how many users click on the static logo or animated logo - on NTP. Android and iOS only. + The number of clicks on the static/call-to-action/animated logo on the NTP. </summary> </histogram> <histogram name="NewTabPage.LogoDownloadOutcome" enum="NewTabPageLogoDownloadOutcome"> - <owner>ianwen@chromium.org</owner> + <owner>treib@chromium.org</owner> <summary> Outcome of downloading search provider's logos. It measures whether download/parsing is successful, revalidation and parsing work properly, etc. - Android and iOS only. </summary> </histogram> <histogram name="NewTabPage.LogoDownloadTime" units="ms"> - <owner>ianwen@chromium.org</owner> + <owner>treib@chromium.org</owner> <summary> The amount of time it took to download the static logo. This includes requests where there was no logo, or where an existing logo was revalidated (so no new image data was downloaded), but it does not include failed - requests. Android and iOS only. + requests. </summary> </histogram> @@ -48205,9 +52892,9 @@ <histogram name="NewTabPage.LogoShown" enum="NewTabPageLogoShown"> <owner>treib@chromium.org</owner> <summary> - The number of static logos and animated logos shown to users. Note that this - is recorded both for logos from the cache and for fresh (or revalidated) - logos, so it can be recorded twice per NTP impression. Android and iOS only. + The number of static logos and animated logos shown to users. Note that the + base version of this histogram is recorded both for logos from the cache and + for fresh logos, so it can be recorded twice per NTP impression. </summary> </histogram> @@ -48227,7 +52914,7 @@ <owner>treib@chromium.org</owner> <summary> The amount of time between opening an NTP and the logo appearing. Only - recorded when there is a logo, and only recorded once per NTP. Android only. + recorded when there is a logo, and only recorded once per NTP. </summary> </histogram> @@ -48274,6 +52961,14 @@ </summary> </histogram> +<histogram name="NewTabPage.MostVisitedAge" units="seconds"> + <owner>mastiz@chromium.org</owner> + <summary> + The age of the data at click time, that is, the elapsed time since the + suggestion was generated by a ranking algorithm. + </summary> +</histogram> + <histogram name="NewTabPage.MostVisitedScheme" enum="NtpMostVisitedScheme"> <obsolete> Deprecated 2016-05. @@ -48469,6 +53164,14 @@ </summary> </histogram> +<histogram name="NewTabPage.OneGoogleBar.ShownTime" units="ms"> + <owner>treib@chromium.org</owner> + <summary> + Histogram of the time, in milliseconds since navigation start, it took until + the OneGoogleBar showed up on the NTP. Recorded only on the local NTP. + </summary> +</histogram> + <histogram name="NewTabPage.OtherSessionsMenu" enum="OtherSessionsActions"> <obsolete> Deprecated 05/2015. Feature was removed. @@ -49028,6 +53731,14 @@ </summary> </histogram> +<histogram name="NewTabPage.SuggestionsImpressionAge" units="seconds"> + <owner>mastiz@chromium.org</owner> + <summary> + The age of the data at impression time, that is, the elapsed time since the + suggestion was generated by a ranking algorithm. + </summary> +</histogram> + <histogram name="NewTabPage.SuggestionsType" enum="NtpSuggestionsType"> <obsolete> Deprecated 2016-07. @@ -49107,6 +53818,26 @@ </summary> </histogram> +<histogram name="NewTabPage.TileFaviconType" enum="FaviconType"> + <owner>mastiz@chromium.org</owner> + <summary> + The favicon type that was chosen to represent a most visited tile displayed + on the new tab page, logged at impression time. Note that these values don't + involve an actual icon being displayed because a scrabble time might have + been displayed instead (see NewTabPage.TileType). + </summary> +</histogram> + +<histogram name="NewTabPage.TileFaviconTypeClicked" enum="FaviconType"> + <owner>mastiz@chromium.org</owner> + <summary> + The favicon type that was chosen to represent a most visited tile displayed + on the new tab page, logged when a tile is clicked. Note that these values + don't involve an actual icon being displayed (see + NewTabPage.TileTypeClicked). + </summary> +</histogram> + <histogram name="NewTabPage.TileOfflineAvailable" enum="MostVisitedTileIndex"> <owner>treib@chromium.org</owner> <summary> @@ -49126,6 +53857,22 @@ </summary> </histogram> +<histogram name="NewTabPage.TileTitle" enum="NTPTileTitleSource"> + <owner>fhorschig@chromium.org</owner> + <summary> + Records the source of the title for each most visited tiled displayed when + an NTP is opened, e.g. a short_name from a manifest, or the page title. + </summary> +</histogram> + +<histogram name="NewTabPage.TileTitleClicked" enum="NTPTileTitleSource"> + <owner>fhorschig@chromium.org</owner> + <summary> + Records the source for the name a most visited tile showed when the user + clicked it, e.g. a URL, or the page title. + </summary> +</histogram> + <histogram name="NewTabPage.TileType" enum="NTPTileVisualType"> <owner>mastiz@chromium.org</owner> <summary> @@ -49241,6 +53988,15 @@ </summary> </histogram> +<histogram name="Notifications.Android.JobStartDelay" units="ms"> + <owner>awdf@chromium.org</owner> + <summary> + Records the delay between scheduling a job with the JobScheduler (with a + desired latency of 0ms, in response to a notification click) and receiving + the onStartJob callback. Only measured on Android N and above. + </summary> +</histogram> + <histogram name="Notifications.AppNotificationStatus" enum="NotificationAppStatus"> <owner>peter@chromium.org</owner> @@ -49365,6 +54121,10 @@ </histogram> <histogram name="Notifications.Display" enum="NotifierType"> + <obsolete> + Deprecated October 2017 (fullscreen notifications feature enabled by + default). + </obsolete> <owner>bmalcolm@chromium.org</owner> <summary> Counts the number of times a notification was shown for the various types of @@ -49721,7 +54481,22 @@ </summary> </histogram> +<histogram name="NQE.ContentObserver.NetworkQualityMeaningfullyChanged" + enum="BooleanChanged"> + <owner>tbansal@chromium.org</owner> + <summary> + This metric is recorded when the network quality change notification is + received by content and before the network quality change is notified to the + renderers. Records true if the notified network quality change is + meaningfully different from the last network quality notified to the + renderers. + </summary> +</histogram> + <histogram name="NQE.Correlation.ResourceLoadTime.0Kb_128Kb"> + <obsolete> + Obsoleted in December 2017. + </obsolete> <owner>tbansal@chromium.org</owner> <owner>bengr@chromium.org</owner> <summary> @@ -50008,6 +54783,42 @@ </summary> </histogram> +<histogram name="NQE.RTT.HangingRequest" units="ms"> + <owner>tbansal@chromium.org</owner> + <summary> + HTTP RTT observation received by the network quality estimator. Recorded + when the request is detected as hanging. + </summary> +</histogram> + +<histogram name="NQE.RTT.NotAHangingRequest.HttpRTT" units="ms"> + <owner>tbansal@chromium.org</owner> + <summary> + HTTP RTT observation received by the network quality estimator. Recorded + when the request is detected as not hanging because it was comparable to the + HTTP RTT estimate. + </summary> +</histogram> + +<histogram name="NQE.RTT.NotAHangingRequest.MinHttpBound" units="ms"> + <owner>tbansal@chromium.org</owner> + <summary> + HTTP RTT observation received by the network quality estimator. Recorded + when the request is detected as not hanging because the RTT value was lower + than the minimum threshold RTT needed to be categorized as a hanging + request. + </summary> +</histogram> + +<histogram name="NQE.RTT.NotAHangingRequest.TransportRTT" units="ms"> + <owner>tbansal@chromium.org</owner> + <summary> + HTTP RTT observation received by the network quality estimator. Recorded + when the request is detected as not hanging because it was comparable to the + transport RTT estimate. + </summary> +</histogram> + <histogram name="NQE.RTT.ObservationSource" enum="NQEObservationSource"> <owner>tbansal@chromium.org</owner> <owner>bengr@chromium.org</owner> @@ -50049,6 +54860,42 @@ </summary> </histogram> +<histogram name="NQE.ThroughputAnalyzer.HangingRequests.Erased" units="count"> + <owner>tbansal@chromium.org</owner> + <summary> + Count of the requests that were marked as hanging by the heuristic algorithm + in the throughput analyzer in the network quality estimator. A sample is + recorded everytime the heuristic algorithm is run. + </summary> +</histogram> + +<histogram name="NQE.ThroughputAnalyzer.HangingRequests.NotErased" + units="count"> + <owner>tbansal@chromium.org</owner> + <summary> + Count of the requests that were not marked as hanging by the heuristic + algorithm in the throughput analyzer in the network quality estimator. A + sample is recorded everytime the heuristic algorithm is run. + </summary> +</histogram> + +<histogram name="NQE.ThroughputObservation.Hanging" units="Kbps"> + <owner>tbansal@chromium.org</owner> + <summary> + Throughput observation made by network quality estimator, and eventually + discarded because the window (over which the througput was computed) was + detected as hanging. + </summary> +</histogram> + +<histogram name="NQE.ThroughputObservation.NotHanging" units="Kbps"> + <owner>tbansal@chromium.org</owner> + <summary> + Throughput observation made by network quality estimator, and used when the + window (over which the througput was computed) was detected as not hanging. + </summary> +</histogram> + <histogram name="NQE.TransportRTT" units="ms"> <owner>bengr@chromium.org</owner> <owner>tbansal@chromium.org</owner> @@ -50322,6 +55169,31 @@ </summary> </histogram> +<histogram base="true" name="OfflinePages.AccessCount"> + <owner>jianli@chromium.org</owner> + <summary> + Number of accesses to the offline page since its creation. This is reported + when the offline page was deleted. + </summary> +</histogram> + +<histogram name="OfflinePages.AccessEntryPoint" + enum="OfflinePagesAccessEntryPoint"> + <owner>jianli@chromium.org</owner> + <summary> + Logs the UI location from which an offline page was launched. + </summary> +</histogram> + +<histogram name="OfflinePages.AccessPageCount" + enum="OfflinePagesNamespaceEnumeration"> + <owner>romax@chromium.org</owner> + <summary> + Counts the number of times an offline page is accessed. Events are reported + per offline pages namespace. + </summary> +</histogram> + <histogram name="OfflinePages.AggregatedRequestResult" enum="OfflinePagesAggregatedRequestResult"> <obsolete> @@ -50339,8 +55211,14 @@ <summary>Result of servicing requests that may contain offline page.</summary> </histogram> -<histogram name="OfflinePages.ArchiveManager.ArchiveDirsCreationResult" +<histogram base="true" + name="OfflinePages.ArchiveManager.ArchiveDirsCreationResult" enum="PlatformFileError"> + <obsolete> + Deprecated 2017-10, and replaced by + OfflinePages.ArchiveManager.ArchiveDirsCreationResult2 with suffixes for + temporary and persistent pages. + </obsolete> <owner>romax@chromium.org</owner> <summary> This is recorded every time the archive directory is being created. It @@ -50348,6 +55226,16 @@ </summary> </histogram> +<histogram name="OfflinePages.ArchiveManager.ArchiveDirsCreationResult2" + enum="PlatformFileError"> + <owner>romax@chromium.org</owner> + <summary> + This is recorded every time the archive directory is being created. It + doesn't include the case which the archive directory exists. It has suffixes + indicating results for temporary or persistent archives directories. + </summary> +</histogram> + <histogram name="OfflinePages.Background.BackgroundLoadingFailedCode" enum="NetErrorCodes"> <owner>chili@chromium.org</owner> @@ -50521,6 +55409,11 @@ </summary> </histogram> +<histogram name="OfflinePages.Background.SavePageFromCCT"> + <owner>chili@chromium.org</owner> + <summary>Whether the save page result came from chrome custom tabs.</summary> +</histogram> + <histogram name="OfflinePages.Background.ScheduledStart.AvailableRequestCount"> <owner>dougarnett@chromium.org</owner> <summary> @@ -50601,6 +55494,9 @@ </histogram> <histogram name="OfflinePages.BatchDelete.Count"> + <obsolete> + Deprecated 2/2018. No longer used. + </obsolete> <owner>jianli@chromium.org</owner> <summary>Number of offline pages that are deleted in a batch.</summary> </histogram> @@ -50634,20 +55530,68 @@ </histogram> <histogram name="OfflinePages.ClearStorageBatchSize" units="pages"> + <obsolete> + Deprecated as of Jan 2018, replaced by + OfflinePages.ClearTemporaryPages.BatchSize. + </obsolete> <owner>romax@chromium.org</owner> <summary> Number of pages deleted in a batch during one clear-storage request. </summary> </histogram> +<histogram name="OfflinePages.ClearStoragePreRunUsage" units="bytes"> + <obsolete> + Deprecated in Oct 2017 and replaced by OfflinePages.ClearStoragePreRunUsage2 + as it was reporting data in bytes instead of the expected MiB. + </obsolete> + <owner>petewil@chromium.org</owner> + <summary> + The total storage size used by all offline pages from a specific client + namespace. + </summary> +</histogram> + +<histogram name="OfflinePages.ClearStoragePreRunUsage2" units="KiB"> + <owner>carlosk@chromium.org</owner> + <summary> + The total disk storage size used by all offline pages from a specific client + namespace. + </summary> +</histogram> + <histogram name="OfflinePages.ClearStorageResult" enum="OfflinePagesClearStorageResult"> + <obsolete> + Deprecated as of Jan 2018, replaced by + OfflinePages.ClearTemporaryPages.Result. + </obsolete> <owner>romax@chromium.org</owner> <summary>Result of asking storage manager to clear storage.</summary> </histogram> +<histogram name="OfflinePages.ClearTemporaryPages.BatchSize" units="pages"> + <owner>romax@chromium.org</owner> + <summary> + Number of pages deleted in a batch in one clear storage task. + </summary> +</histogram> + +<histogram name="OfflinePages.ClearTemporaryPages.Result" + enum="OfflinePagesClearStorageResult"> + <owner>romax@chromium.org</owner> + <summary> + Result of clearing temporary pages to release storage space. + </summary> +</histogram> + <histogram name="OfflinePages.Consistency.DeleteOrphanedArchivesResult" enum="BooleanSuccess"> + <obsolete> + Deprecated 12/2017, replaced by + OfflinePages.ConsistencyCheck.Temporary.Result and + OfflinePages.ConsistencyCheck.Persistent.Result. + </obsolete> <owner>romax@chromium.org</owner> <summary> Whether an attempt to delete archive files without metadata was successful. @@ -50656,6 +55600,11 @@ <histogram name="OfflinePages.Consistency.DeletePagesMissingArchiveFileResult" enum="OfflinePagesDeletePageResult"> + <obsolete> + Deprecated 12/2017, replaced by + OfflinePages.ConsistencyCheck.Temporary.Result and + OfflinePages.ConsistencyCheck.Persistent.Result. + </obsolete> <owner>romax@chromium.org</owner> <summary> Whether an attempt to delete pages without archives was successful. @@ -50675,6 +55624,11 @@ </histogram> <histogram name="OfflinePages.Consistency.OrphanedArchivesCount"> + <obsolete> + Deprecated 12/2017, replaced by + OfflinePages.ConsistencyCheck.Temporary.PagesMissingDbEntryCount and + OfflinePages.ConsistencyCheck.Persistent.PagesMissingDbEntryCount. + </obsolete> <owner>romax@chromium.org</owner> <summary> Number of archives without metadata entry when checking consistency. @@ -50682,13 +55636,73 @@ </histogram> <histogram name="OfflinePages.Consistency.PagesMissingArchiveFileCount"> + <obsolete> + Deprecated 12/2017, replaced by + OfflinePages.ConsistencyCheck.Temporary.PagesMissingArchiveFileCount and + OfflinePages.ConsistencyCheck.Persistent.PagesMissingArchiveFileCount. + </obsolete> <owner>romax@chromium.org</owner> <summary> Number of offline pages without archive file when checking consistency. </summary> </histogram> +<histogram + name="OfflinePages.ConsistencyCheck.Persistent.PagesMissingArchiveFileCount" + units="pages"> + <owner>romax@chromium.org</owner> + <summary> + Number of persistent offline pages without archive file when checking + consistency. It will only be reported if the number is larger than 0. + </summary> +</histogram> + +<histogram + name="OfflinePages.ConsistencyCheck.Persistent.PagesMissingDbEntryCount" + units="pages"> + <owner>romax@chromium.org</owner> + <summary> + Number of archives without database entry when checking persistent page + consistency. It will only be reported if the number is larger than 0. + </summary> +</histogram> + +<histogram name="OfflinePages.ConsistencyCheck.Persistent.Result" + enum="OfflinePagesSyncOperationResult"> + <owner>romax@chromium.org</owner> + <summary>Result of persistent page consistency check.</summary> +</histogram> + +<histogram + name="OfflinePages.ConsistencyCheck.Temporary.PagesMissingArchiveFileCount" + units="pages"> + <owner>romax@chromium.org</owner> + <summary> + Number of temporary offline pages without archive file when checking + consistency. It will only be reported if the number is larger than 0. + </summary> +</histogram> + +<histogram + name="OfflinePages.ConsistencyCheck.Temporary.PagesMissingDbEntryCount" + units="pages"> + <owner>romax@chromium.org</owner> + <summary> + Number of archives without database entry when checking temporary page + consistency. It will only be reported if the number is larger than 0. + </summary> +</histogram> + +<histogram name="OfflinePages.ConsistencyCheck.Temporary.Result" + enum="OfflinePagesSyncOperationResult"> + <owner>romax@chromium.org</owner> + <summary>Result of temporary page consistency check.</summary> +</histogram> + <histogram name="OfflinePages.DeletePage.AccessCount"> + <obsolete> + Deprecated as of 12/2017. Replaced by OfflinePages.AccessCount. + </obsolete> <owner>jianli@chromium.org</owner> <summary> Number of accesses to the offline page since its creation. This is reported @@ -50697,6 +55711,10 @@ </histogram> <histogram name="OfflinePages.DeletePage.FreeSpaceMB" units="MB"> + <obsolete> + Deprecated 2/2018. No longer used, duplicate of + OfflinePages.SavePage.FreeSpaceMB. + </obsolete> <owner>jianli@chromium.org</owner> <summary> The amount of free space available, in megabytes, on the user's device after @@ -50718,6 +55736,9 @@ </histogram> <histogram name="OfflinePages.DeletePage.LastOpenToCreated" units="minutes"> + <obsolete> + Deprecated as of 01/2018. Replaced by OfflinePages.PageAccessInterval. + </obsolete> <owner>jianli@chromium.org</owner> <summary> Length of time between when an offline page was created and was opened last @@ -50726,11 +55747,17 @@ </histogram> <histogram name="OfflinePages.DeletePage.PageSize" units="KB"> + <obsolete> + Deprecated 2/2018. No longer used, duplicate of OfflinePages.PageSize. + </obsolete> <owner>jianli@chromium.org</owner> <summary>Size of the offline page, in kilobytes, that was deleted.</summary> </histogram> <histogram name="OfflinePages.DeletePage.TimeSinceLastOpen" units="minutes"> + <obsolete> + Deprecated as of 01/2018. Replaced by OfflinePages.PageAccessInterval. + </obsolete> <owner>jianli@chromium.org</owner> <summary> Length of time between when an offline page was last opened and was deleted. @@ -50755,6 +55782,15 @@ </summary> </histogram> +<histogram name="OfflinePages.DeletePageCount" + enum="OfflinePagesNamespaceEnumeration"> + <owner>romax@chromium.org</owner> + <summary> + Counts the number of times an offline page is deleted. Events are reported + per offline pages namespace. + </summary> +</histogram> + <histogram name="OfflinePages.DeletePageResult" enum="OfflinePagesDeletePageResult"> <owner>jianli@chromium.org</owner> @@ -50762,6 +55798,9 @@ </histogram> <histogram name="OfflinePages.DownloadDeletedPageDuplicateCount" units="pages"> + <obsolete> + Deprecated 2/2018. No longer used. + </obsolete> <owner>dewittj@chromium.org</owner> <owner>dimich@chromium.org</owner> <summary> @@ -50793,6 +55832,9 @@ </histogram> <histogram name="OfflinePages.DownloadSavedPageDuplicateCount" units="pages"> + <obsolete> + Deprecated 2/2018. No longer used. + </obsolete> <owner>dewittj@chromium.org</owner> <owner>dimich@chromium.org</owner> <summary> @@ -50803,6 +55845,9 @@ <histogram name="OfflinePages.DownloadSavedPageTimeSinceDuplicateSaved" units="seconds"> + <obsolete> + Deprecated 2/2018. No longer used. + </obsolete> <owner>dewittj@chromium.org</owner> <owner>dimich@chromium.org</owner> <summary> @@ -50884,6 +55929,9 @@ </histogram> <histogram name="OfflinePages.FirstOpenSinceCreated" units="minutes"> + <obsolete> + Deprecated 2/2018. Merged to OfflinePages.PageAccessInterval. + </obsolete> <owner>jianli@chromium.org</owner> <summary> The time elapsed between creation of the offline page and the first time it @@ -50928,6 +55976,9 @@ </histogram> <histogram name="OfflinePages.Model.ArchiveDirCreationTime" units="ms"> + <obsolete> + Deprecated 2/2018. No longer used. + </obsolete> <owner>dewittj@chromium.org</owner> <owner>jianli@chromium.org</owner> <summary> @@ -50945,6 +55996,9 @@ </histogram> <histogram name="OfflinePages.Model.FinalLoadSuccessful" enum="Boolean"> + <obsolete> + Deprecated 2/2018. No longer used. + </obsolete> <owner>dimich@chromium.org</owner> <summary> Whether the metadata database was successfully loaded, after possibly @@ -50953,6 +56007,9 @@ </histogram> <histogram name="OfflinePages.Model.InitAttemptsSpent" units="attempts"> + <obsolete> + Deprecated 2/2018. No longer used. + </obsolete> <owner>dimich@chromium.org</owner> <summary> The count of attempts spent to open the metadata database. In the best case, @@ -50993,22 +56050,60 @@ </histogram> <histogram name="OfflinePages.OpenSinceLastOpen" units="minutes"> + <obsolete> + Deprecated 2/2018. Merged to OfflinePages.PageAccessInterval. + </obsolete> <owner>jianli@chromium.org</owner> <summary>Length of time between two consecutive opens.</summary> </histogram> -<histogram name="OfflinePages.PageLifetime" units="minutes"> +<histogram base="true" name="OfflinePages.PageAccessInterval" units="minutes"> + <owner>romax@chromium.org</owner> + <summary> + Length of time between accesses to an offline page. This is the same time + period used for expiring temporary pages. This metric is recorded when an + offline page is accessed. + </summary> +</histogram> + +<histogram base="true" name="OfflinePages.PageLifetime" units="minutes"> <owner>jianli@chromium.org</owner> <summary> Length of time between when an offline page was created and was removed. </summary> </histogram> -<histogram name="OfflinePages.PageSize" units="KB"> +<histogram base="true" name="OfflinePages.PageSize" units="KB"> <owner>jianli@chromium.org</owner> <summary>Size of the saved copy of an offline page.</summary> </histogram> +<histogram name="OfflinePages.PageSizeOnAccess.Offline" units="KiB"> + <owner>carlosk@chromium.org</owner> + <summary> + Records the archive size of an offline page loaded during a navigation that + took place while the device was considered to be offline or with poor + connectivity. + </summary> +</histogram> + +<histogram name="OfflinePages.PageSizeOnAccess.Online" units="KiB"> + <owner>carlosk@chromium.org</owner> + <summary> + Records the archive size of an offline page loaded during a navigation that + took place while the device was considered to be online. + </summary> +</histogram> + +<histogram name="OfflinePages.PrefetchEnabled" enum="BooleanEnabled"> + <owner>dimich@chromium.org</owner> + <summary> + Whether the Offline Pages Prefetch was effectively enabled during the day. + Determined by a combination of flags and user preferences. Reported at the + same moment as OfflinePages.OfflineUsage. + </summary> +</histogram> + <histogram name="OfflinePages.Prefetching.ActionAttempts" units="attempts"> <owner>dewittj@chromium.org</owner> <summary> @@ -51099,7 +56194,25 @@ </summary> </histogram> -<histogram name="OfflinePages.Prefetching.StateCounts." +<histogram name="OfflinePages.Prefetching.ServiceGetOperationStatus" + enum="OfflinePrefetchRequestStatus"> + <owner>petewil@chromium.org</owner> + <summary> + Status returned by a request to the Offline Page Service's GetOperation + method. + </summary> +</histogram> + +<histogram name="OfflinePages.Prefetching.ServiceGetPageBundleStatus" + enum="OfflinePrefetchRequestStatus"> + <owner>petewil@chromium.org</owner> + <summary> + Status returned by a request to the Offline Page Service's GetPageBundle + method. + </summary> +</histogram> + +<histogram name="OfflinePages.Prefetching.StateCounts" enum="OfflinePrefetchItemState"> <owner>petewil@chromium.org</owner> <summary> @@ -51107,6 +56220,54 @@ </summary> </histogram> +<histogram name="OfflinePages.Prefetching.StuckItemState" + enum="OfflinePrefetchItemState"> + <owner>petewil@chromium.org</owner> + <summary> + A prefetch item was found in this state after more than 7 days since its + creation, time enough for it to have been finalized by the pipeline. + </summary> +</histogram> + +<histogram name="OfflinePages.Prefetching.UniqueUrlsAddedCount" units="urls"> + <owner>dewittj@chromium.org</owner> + <summary> + When receiving suggestions in the prefetch pipeline, emits the number of new + suggestions added to the database. If there is an error, nothing is emitted. + </summary> +</histogram> + +<histogram name="OfflinePages.PrefetchStore.StoreEvent" + enum="OfflinePagesStoreEvent"> + <owner>fgorski@chromium.org</owner> + <summary> + Counts when the offline pages prefetch store is opened or closed. + </summary> +</histogram> + +<histogram name="OfflinePages.PrefetchStore.TimeFromCloseToOpen" units="ms"> + <owner>fgorski@chromium.org</owner> + <summary> + Tracks the time between store closing and reopening again within a session. + The store is meant to close itself after a period of inactivity. We are + trying to assess how much time the store is unloaded from memory vs. time it + is loaded and not used. This event will be reported when the store is opened + after being closed within the same lifetime of Chrome. + </summary> +</histogram> + +<histogram name="OfflinePages.PrefetchUsage" enum="OfflinePagesPrefetchUsage"> + <owner>dimich@chromium.org</owner> + <summary> + Enum-based buckets reflect the number of days the Offline Pages Prefetch was + able to fetch new pages, and/or user was opening those pages. This data is + accumulated locally when fetch operations complete or when prefetched pages + are opened (often happens in background or while offline respectively), and + reported when connection is likely to succeed (usually after successful + online navigation). + </summary> +</histogram> + <histogram name="OfflinePages.RedirectResult" enum="OfflinePagesRedirectResult"> <obsolete> Deprecated 8/2016. Use OfflinePages.RequestResult instead. @@ -51152,6 +56313,13 @@ </summary> </histogram> +<histogram name="OfflinePages.RequestJob.RangeHeader" enum="BooleanExists"> + <owner>jianli@chromium.org</owner> + <summary> + Track whether the range header is provided when an offline page is served. + </summary> +</histogram> + <histogram name="OfflinePages.RequestJob.ReadFileErrorCode" enum="NetErrorCodes"> <owner>jianli@chromium.org</owner> @@ -51171,6 +56339,9 @@ </histogram> <histogram name="OfflinePages.SavedPageCount" units="pages"> + <obsolete> + Deprecated as of 2/2018. Replaced by OfflinePages.SavedPageCountUponQuery. + </obsolete> <owner>jianli@chromium.org</owner> <summary> Number of saved pages restored from the offline pages metadata store when it @@ -51178,6 +56349,15 @@ </summary> </histogram> +<histogram name="OfflinePages.SavedPageCountUponQuery" units="pages"> + <owner>carlosk@chromium.org</owner> + <summary> + Total number of saved offline pages recorded when they are all queried from + the store. This value is more meaningful when filtered by unique users as + that eliminates multiple reports from the same Chrome instance. + </summary> +</histogram> + <histogram name="OfflinePages.SavePage.FreeSpaceMB" units="MB"> <owner>jianli@chromium.org</owner> <summary> @@ -51209,12 +56389,22 @@ </summary> </histogram> -<histogram name="OfflinePages.SavePageResult" enum="OfflinePagesSavePageResult"> +<histogram name="OfflinePages.SavePageCount" + enum="OfflinePagesNamespaceEnumeration"> + <owner>romax@chromium.org</owner> + <summary> + Counts the number of times an offline page is saved. Events are reported per + offline pages namespace. + </summary> +</histogram> + +<histogram base="true" name="OfflinePages.SavePageResult" + enum="OfflinePagesSavePageResult"> <owner>jianli@chromium.org</owner> <summary>Result of saving an offline copy for a page.</summary> </histogram> -<histogram name="OfflinePages.SavePageTime" units="ms"> +<histogram base="true" name="OfflinePages.SavePageTime" units="ms"> <owner>jianli@chromium.org</owner> <summary> The amount of time taken to save an offline copy for a page. @@ -51248,6 +56438,26 @@ </summary> </histogram> +<histogram name="OfflinePages.SQLStorage.StoreEvent" + enum="OfflinePagesStoreEvent"> + <owner>fgorski@chromium.org</owner> + <summary> + Used as a counter to track different events related to offline page store + inner working. + </summary> +</histogram> + +<histogram name="OfflinePages.SQLStorage.TimeFromCloseToOpen" units="ms"> + <owner>fgorski@chromium.org</owner> + <summary> + Tracks the time between store closing and reopening again. The store is + meant to close itself after a period of inactivity. We are trying to assess + how much time the store is unloaded from memory vs. time it is loaded and + not used. This event will be reported when the store is opened after being + closed within the same lifetime of Chrome. + </summary> +</histogram> + <histogram name="OfflinePages.TabRestore" enum="OfflinePagesTabRestoreType"> <owner>carlosk@chromium.org</owner> <summary> @@ -51796,6 +57006,31 @@ </summary> </histogram> +<histogram name="Omnibox.QueryGeolocationAcquisitionTime" units="ms"> + <owner>stkhapugin@chromium.org</owner> + <summary> + The elapsed time to acquire the location sent in the X-Geo header for an + Omnibox query. + </summary> +</histogram> + +<histogram name="Omnibox.QueryGeolocationHorizontalAccuracy" units="meters"> + <owner>stkhapugin@chromium.org</owner> + <summary> + The estimated horizontal accuracy of the location sent in the X-Geo header + for an Omnibox query. + </summary> +</histogram> + +<histogram name="Omnibox.QueryIosLocationAuthorizationStatus" + enum="IosLocationAuthorizationStatus"> + <owner>kiyun@chromium.org</owner> + <summary> + For iOS, whether the application is authorized to use location services when + the user enters a search query into the Omnibox. + </summary> +</histogram> + <histogram name="Omnibox.QueryTime" units="ms"> <obsolete> Deprecated 2015-06-12. Replaced by Omnibox.QueryTime2. @@ -52160,6 +57395,36 @@ </summary> </histogram> +<histogram name="Omnibox.URLNavigationScheme" enum="NavigationScheme"> + <owner>mpearson@chromium.org</owner> + <summary> + The scheme of the destination URL for the selected omnibox suggestion. This + could be a what-you-typed suggestion (if the user fully typed a URL), an + inline autocompletion, or something in the dropdown, anything as long as + it's a URL navigation, not a search query. Excludes omnibox URL navigations + that are effectively reloads as well as cut-and-pastes of URLs. Also does + not take into account any redirects that destination URL may do before + finally serving a page. In other words, it's the scheme of the first request + in a possible chain. + </summary> +</histogram> + +<histogram name="Omnibox.URLNavigationTimeToRedirectToHTTPS" units="ms"> + <owner>cthomp@chromium.org</owner> + <summary> + The amount of time, in milliseconds, between the start of a typed URL + navigation in the omnibox (the user typing a URL to completion, or selecting + a URL from the inline autocomplete or dropdown) and the start of a redirect + upgrading the URL to HTTPS. This is only recorded when the upgraded URL is + the same except for the scheme and the addition/removal of a + "www." prefix. + + To calculate the percentage of HTTP URL navigations that have been upgraded + in this way, divide the count of this histogram by the count for HTTP in + Omnibox.URLNavigationScheme. + </summary> +</histogram> + <histogram name="Omnibox.UserTextCleared" enum="OmniboxUserTextCleared"> <owner>kenjibaheux@chromium.org</owner> <owner>mpearson@chromium.org</owner> @@ -52308,6 +57573,17 @@ <summary>Time spent on specific OOBE screen.</summary> </histogram> +<histogram name="OptimizationGuide.ProcessHintsResult" + enum="OptimizationGuideProcessHintsResult"> + <owner>dougarnett@chromium.org</owner> + <owner>sophiechang@chromium.org</owner> + <summary> + Whether processing the hints succeeded or failed at a particular step. + Recorded when the OptimizationGuideService receives a notification to + process hints. + </summary> +</histogram> + <histogram name="OriginChip.Pressed"> <obsolete> Deprecated with CL 731423002. OriginChip has been removed. @@ -52390,6 +57666,15 @@ </summary> </histogram> +<histogram name="OSX.Fullscreen.Enter.Source" enum="OSXFullscreenSource"> + <owner>spqchan@chromium.org</owner> + <summary> + This event is recorded each time a user triggers fullscreen for a browser + window. It indicates if the fullscreen is triggered for the browser or the + tab content. + </summary> +</histogram> + <histogram name="OSX.Fullscreen.Enter.Style" enum="OSXFullscreenStyle"> <owner>erikchen@chromium.org</owner> <summary> @@ -52409,6 +57694,14 @@ </summary> </histogram> +<histogram name="OSX.Fullscreen.ToolbarStyle" enum="OSXFullscreenToolbarStyle"> + <owner>spqchan@chromium.org</owner> + <summary> + This event is recorded each time a user triggers fullscreen and when the + fullscreen toolbar is updated with a new style. + </summary> +</histogram> + <histogram name="OSX.Handoff.Origin" enum="OSXHandoffOrigin"> <owner>erikchen@chromium.org</owner> <summary> @@ -52453,6 +57746,15 @@ </summary> </histogram> +<histogram name="OSX.NativeShare" units="BooleanSuccess"> + <owner>lgrey@chromium.org</owner> + <summary> + Whether the user successfully shared via a native sharing extensions after + selecting it from the share menu. False can indicate failure or + user-initiated cancellation. + </summary> +</histogram> + <histogram name="OSX.RendererHost.SurfaceWaitTime" units="ms"> <obsolete> Deprecated as of 11/2015. @@ -52511,6 +57813,42 @@ </summary> </histogram> +<histogram name="OutOfProcessHeapProfiling.ProfiledProcess.Type" + enum="OutOfProcessHeapProfilingProcessType"> + <owner>erikchen@chromium.org</owner> + <summary> + One metric is emitted every 24-hours after Chrome is launched for every + process that is being profiled. The timer is reset if Chrome exits. + </summary> +</histogram> + +<histogram name="OutOfProcessHeapProfiling.ProfilingMode" + enum="OutOfProcessHeapProfilingMode"> + <owner>erikchen@chromium.org</owner> + <summary> + One metric is emitted every 24-hours after Chrome is launched for every + Chrome instance that is using out of process heap profiling. The timer is + reset if Chrome exits. + </summary> +</histogram> + +<histogram name="OutOfProcessHeapProfiling.RecordTrace.Success" + enum="BooleanSuccess"> + <owner>erikchen@chromium.org</owner> + <summary> + The metric is emitted each time Chrome attempts to record a memory-infra + trace to upload an out-of-process heap-profiling memory dump. + </summary> +</histogram> + +<histogram name="OutOfProcessHeapProfiling.UploadTrace.Size" units="bytes"> + <owner>erikchen@chromium.org</owner> + <summary> + The metric is emitted each time Chrome uploads a trace. It reflects the + uncompressed size of the trace. + </summary> +</histogram> + <histogram name="Overscroll.Cancelled" enum="NavigationDirection"> <obsolete> Deprecated as of Chrome 59 in favour of Overscroll.Cancelled3. @@ -53427,6 +58765,24 @@ </summary> </histogram> +<histogram name="PageLoad.Clients.MultiTabLoading.NumTabsWithInflightLoad" + units="tabs"> + <owner>ksakamoto@chromium.org</owner> + <summary> + Records the number of tabs with inflight loading activities. Recorded when a + new page load starts. + </summary> +</histogram> + +<histogram name="PageLoad.Clients.ServiceWorker.PageTransition" + enum="CorePageTransition"> + <owner>falken@chromium.org</owner> + <summary> + The core transition type for main frame page loads controlled by a service + worker. + </summary> +</histogram> + <histogram name="PageLoad.Clients.SubresourceFilter.ActivationDecision" enum="SubresourceFilterActivationDecision"> <owner>bmcquade@chromium.org</owner> @@ -53674,6 +59030,9 @@ <histogram name="PageLoad.Experimental.Cache.RequestPercent.ParseStop" units="%"> + <obsolete> + Removed Jan 2018 + </obsolete> <owner>csharrison@chromium.org</owner> <summary> The percent of resources loaded from cache for the given page load. Recorded @@ -53683,6 +59042,9 @@ <histogram name="PageLoad.Experimental.Cache.TotalRequests.ParseStop" units="requests"> + <obsolete> + Removed Jan 2018 + </obsolete> <owner>csharrison@chromium.org</owner> <summary> The number of resources a given page finished loading from cache at parse @@ -53720,6 +59082,18 @@ </summary> </histogram> +<histogram name="PageLoad.Experimental.NavigationToInteractive" units="ms"> + <owner>dproy@chromium.org</owner> + <owner>tdresser@chromium.org</owner> + <summary> + Measures Time to Interactive, a metric based on main thread and network + heuristics to approximate the point in time when the page feels interactive + to the user. See https://goo.gl/TFw6xz for detailed explanation. This + histogram uses First Meaningful Paint as the lower bound for quiescent + windows. + </summary> +</histogram> + <histogram name="PageLoad.Experimental.PageTiming.FirstPaintToFirstBackground" units="ms"> <obsolete> @@ -53857,6 +59231,9 @@ <histogram name="PageLoad.Experimental.ParseDuration.CachedPercent.0-50" units="ms"> + <obsolete> + Removed Jan 2018 + </obsolete> <owner>csharrison@chromium.org</owner> <summary> The parse duration of the page load where 0-50% of all subresources (loaded @@ -53866,6 +59243,9 @@ <histogram name="PageLoad.Experimental.ParseDuration.CachedPercent.51-100" units="ms"> + <obsolete> + Removed Jan 2018 + </obsolete> <owner>csharrison@chromium.org</owner> <summary> The parse duration of the page load where 51-100% of all subresources @@ -53876,6 +59256,10 @@ <histogram name="PageLoad.Experimental.Renderer.FirstMeaningfulPaintDetector.FirstMeaningfulPaintOrdering" enum="FirstMeaningfulPaintOrdering"> + <obsolete> + Renamed to + PageLoad.Internal.Renderer.FirstMeaningfulPaintDetector.FirstMeaningfulPaintOrdering + </obsolete> <owner>ksakamoto@chromium.org</owner> <summary> Whether the two variants of First Meaningful Paint reported different @@ -53886,6 +59270,10 @@ <histogram name="PageLoad.Experimental.Renderer.FirstMeaningfulPaintDetector.HadNetworkQuiet" enum="NetworkQuietStatus"> + <obsolete> + Renamed to + PageLoad.Internal.Renderer.FirstMeaningfulPaintDetector.HadNetworkQuiet + </obsolete> <owner>ksakamoto@chromium.org</owner> <summary> Recorded when the page load reached network 0-quiet (no active network @@ -53897,8 +59285,22 @@ </summary> </histogram> +<histogram name="PageLoad.Experimental.TimeToInteractiveStatus" + enum="TimeToInteractiveStatus"> + <owner>tdresser@chromium.org</owner> + <owner>dproy@chromium.org</owner> + <summary> + Records whether the Time To Interactive metric was reported for the page + load, or why it wasn't if not. See https://goo.gl/TFw6xz for definition of + Time to Interactive. + </summary> +</histogram> + <histogram name="PageLoad.Experimental.TotalRequests.ParseStop" units="requests"> + <obsolete> + Removed Jan 2018 + </obsolete> <owner>csharrison@chromium.org</owner> <summary> The number of resources a given page finished loading at parse stop. @@ -53935,6 +59337,14 @@ </summary> </histogram> +<histogram name="PageLoad.InteractiveTiming.FirstInputDelay" units="ms"> + <owner>tdresser@chromium.org</owner> + <summary> + Measures the time from hardware timestamp until main thread processing of + the first click, keypress or tap event per navigation. + </summary> +</histogram> + <histogram name="PageLoad.Internal.ClientRedirect.FirstPaintToNavigation" units="ms"> <owner>bmcquade@chromium.org</owner> @@ -53996,6 +59406,19 @@ </summary> </histogram> +<histogram name="PageLoad.Internal.InteractiveToInteractiveDetection" + units="ms"> + <owner>dproy@chromium.org</owner> + <owner>tdresser@chromium.org</owner> + <summary> + Measures time delta between Time to Interactive and when we can detect TTI. + TTI cannot be detected in real time - we have to wait sufficiently long to + determine main thread and network quiescence. See https://goo.gl/TFw6xz for + detailed explanation of Time to Interactive. This histogram uses First + Meaningful Paint as the lower bound for quiescent windows. + </summary> +</histogram> + <histogram name="PageLoad.Internal.NavigationStartedInForeground" enum="BooleanForeground"> <owner>bmcquade@chromium.org</owner> @@ -54103,6 +59526,30 @@ </summary> </histogram> +<histogram + name="PageLoad.Internal.Renderer.FirstMeaningfulPaintDetector.FirstMeaningfulPaintOrdering" + enum="FirstMeaningfulPaintOrdering"> + <owner>ksakamoto@chromium.org</owner> + <summary> + Whether the two variants of First Meaningful Paint reported different + values, and if so, which one was reported first. + </summary> +</histogram> + +<histogram + name="PageLoad.Internal.Renderer.FirstMeaningfulPaintDetector.HadNetworkQuiet" + enum="NetworkQuietStatus"> + <owner>ksakamoto@chromium.org</owner> + <summary> + Recorded when the page load reached network 0-quiet (no active network + connection for 0.5 seconds), or network 2-quiet (no more than 2 active + network connections for 2 seconds). + PageLoad.Experimental.PaintTiming.FirstMeaningfulPaintSignalStatus2 + histogram gives the fraction of page loads that had network 2-quiet, so it + can be used as a baseline. + </summary> +</histogram> + <histogram name="PageLoad.Internal.Renderer.PaintTiming.SwapResult" enum="SwapResult"> <owner>panicker@chromium.org</owner> @@ -54826,6 +60273,94 @@ </summary> </histogram> +<histogram name="PartnerBookmark.Count" units="bookmarks"> + <obsolete> + Deprecated 2017-12 by PartnerBookmark.Count2. + </obsolete> + <owner>wychen@chromium.org</owner> + <summary> + The number of partner bookmark entries. Note that zero would be + under-represented because reading is throttled if the last result is zero. + Logged when using the bookmark, not skipped (PartnerBookmark.Skipped == + False), and at most once per cold start. Note that the distribution is + weighted by bookmark usage. + </summary> +</histogram> + +<histogram name="PartnerBookmark.Count2" units="bookmarks"> + <owner>wychen@chromium.org</owner> + <summary> + The number of partner bookmark entries. Logged when using the bookmark, and + at most once per cold start. Note that the distribution is weighted by + bookmark usage. + </summary> +</histogram> + +<histogram name="PartnerBookmark.FaviconThrottleFetchResult" + enum="PartnerBookmark.FaviconFetchResult"> + <owner>thildebr@chromium.org</owner> + <summary> + The response we got back from our favicon fetching throttler, once for each + bookmark at each cold start. Only recorded on Android. + </summary> +</histogram> + +<histogram name="PartnerBookmark.LoadingTime" units="ms"> + <owner>wychen@chromium.org</owner> + <summary> + The time spent on loading partner bookmarks, from kickOffReading() to + bookmarkModelLoaded() callback. + </summary> +</histogram> + +<histogram name="PartnerBookmark.Null" enum="BooleanNull"> + <owner>wychen@chromium.org</owner> + <summary> + Whether there's no partner bookmark provider. By default, the system image + contains a dummy partner bookmarks provider that provides zero entries. + Logged when using the bookmark, not skipped (PartnerBookmark.Skipped == + False), and at most once per cold start. + </summary> +</histogram> + +<histogram name="PartnerBookmark.Skipped" enum="BooleanSkipped"> + <owner>wychen@chromium.org</owner> + <summary> + Whether reading of partner bookmark is skipped. Logged when using the + bookmark, and at most once per cold start. + </summary> +</histogram> + +<histogram name="PartnerBookmark.TimeSinceLastEmptyRead" units="ms"> + <obsolete> + Deprecated 2017-12. Use PartnerBookmark.TimeSinceLastEmptyRead2. + </obsolete> + <owner>wychen@chromium.org</owner> + <summary> + When trying to load the partner bookmarks, if no partner bookmark is read + last time, record the time elapsed since then. It is recorded no matter + whether loading would be skipped. + </summary> +</histogram> + +<histogram name="PartnerBookmark.TimeSinceLastEmptyRead2" units="seconds"> + <owner>wychen@chromium.org</owner> + <summary> + When trying to load the partner bookmarks, if no partner bookmark is read + last time, record the time elapsed since then. It is recorded no matter + whether loading would be skipped. + </summary> +</histogram> + +<histogram name="PartnerBookmarksFaviconThrottle.NumEntries" units="entries"> + <owner>thildebr@chromium.org</owner> + <summary> + Number of elements read from the partner bookmarks favicon cache, recorded + once per cold start when reading partner bookmarks. Only recorded on + Android. + </summary> +</histogram> + <histogram name="PasswordBubble.DisplayDisposition" enum="PasswordBubbleDisplayDisposition"> <owner>vasilii@chromium.org</owner> @@ -55181,6 +60716,15 @@ </summary> </histogram> +<histogram name="PasswordManager.Android.PasswordSearchTriggered" + enum="Boolean"> + <owner>fhorschig@chromium.org</owner> + <summary> + Records whether a user triggered the search function while visiting the + password preferences page on Android. + </summary> +</histogram> + <histogram name="PasswordManager.AutocompletePopupSuppressedByGeneration" enum="BooleanSuppressed"> <owner>gcasto@chromium.org</owner> @@ -55207,6 +60751,20 @@ </summary> </histogram> +<histogram name="PasswordManager.CertificateErrorsWhileSeeingForms" + enum="PasswordCertificateError"> + <owner>battre@chromium.org</owner> + <owner>vabr@chromium.org</owner> + <summary> + When the password manager sees new forms on the page, it records in this + histogram whether there were any SSL certificate errors. The presence of SSL + errors likely means that the password manger will stop working, so the + reporting is done at the last point when password manager is still + guaranteed to be active. Some particular errors are distinguished, with the + rest being reported in a catch-all bucket. + </summary> +</histogram> + <histogram name="PasswordManager.EditsInSaveBubble" enum="PasswordManagerEditsInSaveBubbleEnum"> <owner>battre@chromium.org</owner> @@ -55294,11 +60852,20 @@ </histogram> <histogram name="PasswordManager.ExportedPasswordsPerUserInCSV"> - <owner>xunlu@chromium.org</owner> + <owner>cfroussios@chromium.org</owner> + <owner>ioanap@chromium.org</owner> <owner>vabr@chromium.org</owner> <summary>The number of passwords exported in CSV format per user.</summary> </histogram> +<histogram name="PasswordManager.ExportPasswordsToCSVResult" + enum="ExportPasswordsResult"> + <owner>cfroussios@chromium.org</owner> + <owner>ioanap@chromium.org</owner> + <owner>vabr@chromium.org</owner> + <summary>The success or error type of exporting passwords into CSV.</summary> +</histogram> + <histogram name="PasswordManager.FilledCredentialWasFromAndroidApp" enum="PasswordManagerFilledAndroidCredentials"> <owner>msramek@chromium.org</owner> @@ -55682,6 +61249,15 @@ </summary> </histogram> +<histogram name="PasswordManager.PasswordSavedWithManualFallback" + enum="BooleanPasswordSavedWithFallback"> + <owner>kolos@chromium.org</owner> + <summary> + Measures whether users save passwords with automatic prompt or manual + fallback. + </summary> +</histogram> + <histogram name="PasswordManager.PasswordSyncState" enum="PasswordSyncState"> <owner>gcasto@chromium.org</owner> <owner>rouslan@chromium.org</owner> @@ -55691,6 +61267,15 @@ </summary> </histogram> +<histogram name="PasswordManager.PasswordUpdatedWithManualFallback" + enum="BooleanPasswordSavedWithFallback"> + <owner>kolos@chromium.org</owner> + <summary> + Measures whether users update passwords with automatic prompt or manual + fallback. + </summary> +</histogram> + <histogram name="PasswordManager.ProvisionalSaveFailure" enum="ProvisionalSaveFailure"> <owner>vabr@chromium.org</owner> @@ -56015,6 +61600,15 @@ </summary> </histogram> +<histogram name="PasswordManager.TimeReadingExportedPasswords" units="ms"> + <owner>cfroussios@chromium.org</owner> + <owner>ioanap@chromium.org</owner> + <owner>vabr@chromium.org</owner> + <summary> + The time it takes to fetch and serialise the passwords for export. + </summary> +</histogram> + <histogram name="PasswordManager.TimesGeneratedPasswordUsed"> <obsolete> Deprecated as of 11/11/14. New statistic is @@ -56084,6 +61678,32 @@ </summary> </histogram> +<histogram name="PasswordManager.UsernameCorrectionFound" + enum="BooleanUsernameCorrectionVote"> + <owner>kolos@chromium.org</owner> + <summary> + Chrome saves locally all fields a user typed on a sign-up form. If Chrome + saved an incorrect username and the user changes the username on a sign-in + form to a value of another field from the sign-up form, then Chrome uploads + a username correction vote which points to the correct username field. This + histogram measures how many correction votes are uploaded. + </summary> +</histogram> + +<histogram name="PasswordManager.UsernameDetectionMethod" + enum="UsernameDetectionMethod"> + <owner>kolos@chromium.org</owner> + <summary> + Measures what method was used for username field detection in the renderer + code. The metric may be recorded several times for page visit because it is + recorded at every PasswordForm creation. If a site changes HTML attributes + of fields or server-side predictions is received, different values can be + recorded for the same form. If an outcome of HTML classifier or a + server-side prediction coincides with the outcome of base heuristic, the + metric points to base heuristic method. + </summary> +</histogram> + <histogram name="PasswordManager.UserStoredPasswordWithInvalidSSLCert" enum="Boolean"> <obsolete> @@ -56223,6 +61843,17 @@ </summary> </histogram> +<histogram name="PasswordProtection.UserClickedThroughSafeBrowsingInterstitial" + enum="BooleanClickedThroughSBInterstitial"> + <owner>jialiul@chromium.org</owner> + <owner>nparker@chromium.org</owner> + <summary> + Whether the user has clicked through the Safe Browsing interstitial before + the password protection ping is triggered on the same page. Logged right + before password protection ping is sent. + </summary> +</histogram> + <histogram name="PasswordProtection.Verdict" enum="PasswordProtectionVerdict"> <owner>jialiul@chromium.org</owner> <owner>nparker@chromium.org</owner> @@ -56504,6 +62135,26 @@ </summary> </histogram> +<histogram name="PDF.Actions" enum="ChromePDFViewerActions"> + <owner>hnakashima@chromium.org</owner> + <summary> + Tracks user actions in the PDF viewer. Logged when the document is opened + and when one of the relevant user actions is taken, such as opening the + bookmarks bar or setting the zoom mode to fit-to-page. The enum values that + are named "First" are logged only once per document, so that we + can measure in what percentage of documents a given action was performed at + least once. + </summary> +</histogram> + +<histogram name="PDF.AnnotationType" enum="ChromePDFViewerAnnotationType"> + <owner>hnakashima@chromium.org</owner> + <summary> + Tracks documents opened in the PDF viewer that displayed one or more pages + with the given annotation type. + </summary> +</histogram> + <histogram name="PDF.DocumentFeature" enum="PDFFeatures"> <owner>tsergeant@chromium.org</owner> <summary> @@ -56512,11 +62163,42 @@ </summary> </histogram> +<histogram name="PDF.FormType" enum="PDFFormTypes"> + <owner>rharrison@chromium.org</owner> + <summary> + Tracks what types of forms are present in PDF document, logged when the + document finishes loading. + </summary> +</histogram> + +<histogram name="PDF.HasAttachment" enum="Boolean"> + <owner>hnakashima@chromium.org</owner> + <summary> + Measures if PDFs opened in the PDF viewer have attachments. This is logged + whenever a document is opened in the PDF viewer. + </summary> +</histogram> + <histogram name="PDF.IsFontSubstituted" enum="Boolean"> <owner>npm@chromium.org</owner> <summary> - Tracks documents opened in the PDF viewer where substitute fonts need to be - used. + Measures if PDFs opened in the PDF viewer require fonts to be substituted. + This is logged whenever a document is opened in the PDF viewer. + </summary> +</histogram> + +<histogram name="PDF.IsLinearized" enum="Boolean"> + <owner>hnakashima@chromium.org</owner> + <summary> + Measures if PDFs opened in the PDF viewer are Linearized PDFs. This is + logged whenever a document is opened in the PDF viewer. + </summary> +</histogram> + +<histogram name="PDF.IsTagged" enum="BooleanIsTagged"> + <owner>hnakashima@chromium.org</owner> + <summary> + Tracks documents opened in the PDF viewer that are Tagged PDFs. </summary> </histogram> @@ -56529,6 +62211,20 @@ </summary> </histogram> +<histogram name="PDF.PageCount" units="pages"> + <owner>hnakashima@chromium.org</owner> + <summary> + Tracks the number of pages in PDF documents opened in the PDF viewer. + </summary> +</histogram> + +<histogram name="Pepper.BrokerAction" enum="PepperBrokerAction"> + <owner>raymes@chromium.org</owner> + <summary> + Counts various actions related to the Pepper Broker interface. + </summary> +</histogram> + <histogram name="Pepper.Graphics3DHasShareGroup" units="BooleanShareGroup"> <owner>jbauman@chromium.org</owner> <summary> @@ -56578,6 +62274,24 @@ </summary> </histogram> +<histogram name="Performance.PerformanceMeasurePassedInParameter.EndMark" + enum="PerformanceMeasurePassedInParameterType"> + <owner>maxlg@chromium.org</owner> + <summary> + The count of possible string of the endMark parameter in + performance.measure(). + </summary> +</histogram> + +<histogram name="Performance.PerformanceMeasurePassedInParameter.StartMark" + enum="PerformanceMeasurePassedInParameterType"> + <owner>maxlg@chromium.org</owner> + <summary> + The count of possible string of the startMark parameter in + performance.measure(). + </summary> +</histogram> + <histogram name="PerformanceMonitor.AverageCPU" units="PercentCPUUsage"> <owner>oysteine@chromium.org</owner> <summary> @@ -56596,6 +62310,24 @@ </summary> </histogram> +<histogram name="PerformanceMonitor.IdleWakeups" units="WakeupsPerSecond"> + <owner>lgrey@chromium.org</owner> + <summary> + The average CPU idle wakeups per second, sampled every two minutes. + </summary> +</histogram> + +<histogram name="PerformanceMonitor.PackageExitIdleWakeups" + units="WakeupsPerSecond"> + <owner>lgrey@chromium.org</owner> + <summary> + (Mac only) The average package exit idle wakeups per second, sampled every + two minutes. This is a subset of wakeups that indicate that the processor + complex was taken out of low-power state. For more info, see the + powermetrics man page on macOS. + </summary> +</histogram> + <histogram name="Permissions.Action" enum="PermissionAction"> <owner>dominickn@chromium.org</owner> <owner>kcarattini@chromium.org</owner> @@ -56682,6 +62414,46 @@ </summary> </histogram> +<histogram name="Permissions.BatteryLevel.Accepted.Geolocation" units="%"> + <owner>timloh@chromium.org</owner> + <summary> + Battery percentage when a geolocation permission prompt was accepted on + Android. + </summary> +</histogram> + +<histogram name="Permissions.BatteryLevel.Accepted.LocationSettingsDialog" + units="%"> + <owner>timloh@chromium.org</owner> + <summary> + Battery percentage when a location settings dialog was accepted. + </summary> +</histogram> + +<histogram name="Permissions.BatteryLevel.Denied.Geolocation" units="%"> + <owner>timloh@chromium.org</owner> + <summary> + Battery percentage when a geolocation permission prompt was denied on + Android. + </summary> +</histogram> + +<histogram name="Permissions.BatteryLevel.Denied.LocationSettingsDialog" + units="%"> + <owner>timloh@chromium.org</owner> + <summary> + Battery percentage when a location settings dialog was denied. + </summary> +</histogram> + +<histogram name="Permissions.BatteryLevel.Dismissed.Geolocation" units="%"> + <owner>timloh@chromium.org</owner> + <summary> + Battery percentage when a geolocation permission prompt was dismissed on + Android. + </summary> +</histogram> + <histogram name="Permissions.Engagement.Accepted" units="%"> <owner>dominickn@chromium.org</owner> <owner>kcarattini@chromium.org</owner> @@ -56729,6 +62501,9 @@ </histogram> <histogram name="Permissions.Prompt.Accepted.Persisted" enum="BooleanPersisted"> + <obsolete> + Persist toggle experiments ran from M56 to M59. + </obsolete> <owner>dominickn@chromium.org</owner> <owner>kcarattini@chromium.org</owner> <summary> @@ -56770,6 +62545,9 @@ </histogram> <histogram name="Permissions.Prompt.Denied.Persisted" enum="BooleanPersisted"> + <obsolete> + Persist toggle experiments ran from M56 to M59. + </obsolete> <owner>dominickn@chromium.org</owner> <owner>kcarattini@chromium.org</owner> <summary> @@ -56879,6 +62657,10 @@ <histogram name="Permissions.Prompt.MergedBubbleAccepted" enum="PermissionRequestType"> + <obsolete> + Redundant since M61 (bug 728483) as we now only merge Mic+Camera. The same + counts are available in Permissions.Prompt.Accepted. + </obsolete> <owner>dominickn@chromium.org</owner> <owner>kcarattini@chromium.org</owner> <summary> @@ -56889,6 +62671,10 @@ <histogram name="Permissions.Prompt.MergedBubbleDenied" enum="PermissionRequestType"> + <obsolete> + Redundant since M61 (bug 728483) as we now only merge Mic+Camera. The same + counts are available in Permissions.Prompt.Denied. + </obsolete> <owner>dominickn@chromium.org</owner> <owner>kcarattini@chromium.org</owner> <summary> @@ -56899,6 +62685,10 @@ <histogram name="Permissions.Prompt.MergedBubbleTypes" enum="PermissionRequestType"> + <obsolete> + Redundant since M61 (bug 728483) as we now only merge Mic+Camera. The same + counts are available in Permissions.Prompt.Shown. + </obsolete> <owner>dominickn@chromium.org</owner> <owner>kcarattini@chromium.org</owner> <summary> @@ -56908,6 +62698,10 @@ </histogram> <histogram name="Permissions.Prompt.RequestsPerPrompt"> + <obsolete> + Redundant since M61 (bug 728483) as we now only merge Mic+Camera. The same + counts are available in Permissions.Prompt.Shown. + </obsolete> <owner>dominickn@chromium.org</owner> <owner>kcarattini@chromium.org</owner> <summary> @@ -57299,6 +63093,58 @@ </summary> </histogram> +<histogram name="Platform.DetachableBase.ActivePercent" units="%"> + <owner>kitching@google.com</owner> + <summary> + Ratio of time a detachable base keyboard is active, i.e. when the USB + interface is not auto-suspended. Reported every 30 seconds when the base is + connected. + </summary> +</histogram> + +<histogram name="Platform.DetachableBase.AttachedOnBoot" enum="BooleanAttached"> + <owner>kitching@google.com</owner> + <summary> + For devices with a detachable base: whether or not the base is connected on + boot. Recorded by upstart task on boot. + </summary> +</histogram> + +<histogram name="Platform.DetachableBase.PairResult" + enum="DetachableBasePairResult"> + <owner>kitching@google.com</owner> + <summary>Result of a detachable base pair operation.</summary> +</histogram> + +<histogram name="Platform.DetachableBase.PendingRWUpdate" + enum="DetachableBasePendingRWUpdate"> + <owner>kitching@google.com</owner> + <summary> + Detachable base firmware updates can be configured to only occur on boot. In + this mode, any update will be considered "pending" until the + system is rebooted, at which point the update may take place. Every time a + detachable base is connected to the system, a metric representing the + pending update status is recorded. Its possible values are as follows: (0) + communication error; (1) no update available; (2) critical update available; + or (3) non-critical update available. The definition of + "critical" is up to the software performing updates, and would + typically be used in the case of a security issue, or broken functionality + in a previous firmware version. + </summary> +</histogram> + +<histogram name="Platform.DetachableBase.ROUpdateResult" + enum="DetachableBaseROUpdateResult"> + <owner>kitching@google.com</owner> + <summary>Result of a detachable base RO firmware update.</summary> +</histogram> + +<histogram name="Platform.DetachableBase.RWUpdateResult" + enum="DetachableBaseRWUpdateResult"> + <owner>kitching@google.com</owner> + <summary>Result of a detachable base RW firmware update.</summary> +</histogram> + <histogram name="Platform.DiskUsage.Cache_Avg" units="KB"> <obsolete> Deprecated 04/2016 as doesn't have data nor owner. @@ -58657,6 +64503,29 @@ </summary> </histogram> +<histogram name="Platform.TPM.FirmwareUpdate.Attempts" units="attempts"> + <owner>mnissler@chromium.org</owner> + <summary> + Number of attempts until a successful TPM firmware update. This is the total + sum of attempts, i.e. number of failed attempts + 1 for the final successful + attempt. Note that we're not in a position to report UMA after failed + attempts, so this will only be reported by devices that eventually see a + successful attempt. + </summary> +</histogram> + +<histogram name="Platform.TPM.FirmwareUpdate.Result" + enum="TPMFirmwareUpdateResult"> + <owner>mnissler@chromium.org</owner> + <summary>Status of a complete TPM firmware update attempt.</summary> +</histogram> + +<histogram name="Platform.TPM.FirmwareUpdate.Status" + enum="TPMFirmwareUpdateStatus"> + <owner>mnissler@chromium.org</owner> + <summary>Exit status of the TPM firmware updater script.</summary> +</histogram> + <histogram name="Platform.TPM.VersionFingerprint" enum="TPMVersionFingerprint"> <owner>mnissler@chromium.org</owner> <summary> @@ -58702,6 +64571,15 @@ </summary> </histogram> +<histogram name="Platform.WiFiDeviceCount" units="wifi devices"> + <owner>cernekee@chromium.org</owner> + <owner>semenzato@chromium.org</owner> + <summary> + Sample collected 10s after boot, showing how many WiFi interfaces are + present. + </summary> +</histogram> + <histogram name="Platform.WriteSectorsLong"> <owner>gwendal@google.com</owner> <summary> @@ -58784,7 +64662,7 @@ </summary> </histogram> -<histogram name="PlatformFile.UnknownErrors.Posix" enum="OSAgnosticErrno"> +<histogram name="PlatformFile.UnknownErrors.Posix" enum="PopularOSErrno"> <owner>dgrogan@chromium.org</owner> <summary> Errors returned by CreateFile on POSIX that PlatformFileError doesn't yet @@ -60086,6 +65964,9 @@ <histogram name="Plugin.AvailabilityStatus.WidevineCdm" enum="PluginAvailabilityStatus"> + <obsolete> + Deprecated as of 01/2017 (M65). + </obsolete> <owner>xhwang@chromium.org</owner> <summary> The availability status of Widevine CDM. In normal cases, this is reported @@ -60120,6 +66001,10 @@ </histogram> <histogram name="Plugin.Flash.Engagement"> + <obsolete> + Deprecated 12/2017 in Issue 781644 as we no longer use Site Engagement Index + as a signal for Flash display. + </obsolete> <owner>dominickn@chromium.org</owner> <summary> The engagement score of origins which have passed through a site engagement @@ -60666,6 +66551,45 @@ </summary> </histogram> +<histogram name="Power.IdleScreenDimCountDaily" units="count"> + <owner>derat@chromium.org</owner> + <summary> + Number of times that that the screen has been dimmed in response to user + inactivity, reported daily. The count is accumulated through the day, + spanning reboots, and sent once the system clock indicates that a full day + or more has passed since the last report. If the system is suspended or off + for more than a day, the current count will be reported immediately the next + time the system boots, but the skipped days will not be reported. Chrome OS + only. + </summary> +</histogram> + +<histogram name="Power.IdleScreenOffCountDaily" units="count"> + <owner>derat@chromium.org</owner> + <summary> + Number of times that that the screen has been turned off in response to user + inactivity, reported daily. The count is accumulated through the day, + spanning reboots, and sent once the system clock indicates that a full day + or more has passed since the last report. If the system is suspended or off + for more than a day, the current count will be reported immediately the next + time the system boots, but the skipped days will not be reported. Chrome OS + only. + </summary> +</histogram> + +<histogram name="Power.IdleSuspendCountDaily" units="count"> + <owner>derat@chromium.org</owner> + <summary> + Number of times that that the system has suspended in response to user + inactivity, reported daily. The count is accumulated through the day, + spanning reboots, and sent once the system clock indicates that a full day + or more has passed since the last report. If the system is suspended or off + for more than a day, the current count will be reported immediately the next + time the system boots, but the skipped days will not be reported. Chrome OS + only. + </summary> +</histogram> + <histogram name="Power.IdleTimeAfterDimOnAC" units="ms"> <owner>derat@chromium.org</owner> <summary> @@ -60763,6 +66687,27 @@ </summary> </histogram> +<histogram name="Power.LidClosedSuspendCountDaily" units="count"> + <owner>derat@chromium.org</owner> + <summary> + Number of times that that the system has suspended in response to its lid + being closed, reported daily. The count is accumulated through the day, + spanning reboots, and sent once the system clock indicates that a full day + or more has passed since the last report. If the system is suspended or off + for more than a day, the current count will be reported immediately the next + time the system boots, but the skipped days will not be reported. Chrome OS + only. + </summary> +</histogram> + +<histogram name="Power.MetricsDailyEventInterval" enum="DailyEventIntervalType"> + <owner>derat@chromium.org</owner> + <summary> + Reasons why power-management-related daily metrics were reported. Chrome OS + only. + </summary> +</histogram> + <histogram name="Power.MilliConsumptionPerHourIosOnActive"> <obsolete> Deprecated 04/2016 as doesn't have data nor owner. @@ -61386,12 +67331,26 @@ <summary>The amount of time that elapsed during CreateProfilePrefs.</summary> </histogram> +<histogram name="PrefService.NetworkPredictionEnabled" enum="BooleanEnabled"> + <owner>petewil@chromium.org</owner> + <summary> + Count events where Network Prediction was enabled or disabled. + </summary> +</histogram> + <histogram name="PrefService.PersistentLogRecallProtobufs" enum="PersistedLogsLogReadStatus"> <owner>holte@chromium.org</owner> <summary>The status when loading PersistedLogs from Prefs.</summary> </histogram> +<histogram name="PrefService.ReadError" enum="PrefServiceReadError"> + <owner>csharp@chromium.org</owner> + <summary> + Enumeration of errors that happened when reading Preferences files. + </summary> +</histogram> + <histogram name="PreloadScanner.Counts" units="preloads"> <obsolete> Deprecated 5/25/2016 in favor of PreloadScanner.Counts2 @@ -61414,11 +67373,17 @@ </histogram> <histogram name="PreloadScanner.Counts2" units="preloads"> + <obsolete> + Removed Feb 2018, no longer useful. + </obsolete> <owner>csharrison@chromium.org</owner> <summary>The number of preloads generated by the preload scanner.</summary> </histogram> <histogram name="PreloadScanner.Counts2.Miss" units="preloads"> + <obsolete> + Removed Feb 2018, no longer useful. + </obsolete> <owner>csharrison@chromium.org</owner> <summary> The number of unused preloads generated by the preload scanner. Note that @@ -61839,6 +67804,21 @@ </summary> </histogram> +<histogram name="Prerender.NoStatePrefetchRendererLifetimeExtension" units="ms"> + <owner>jam@chromium.org</owner> + <summary> + Time a prefetch renderer is kept alive after parsing to wait for + subresources to finish loading. + </summary> +</histogram> + +<histogram name="Prerender.NoStatePrefetchRendererParseTime" units="ms"> + <owner>jam@chromium.org</owner> + <summary> + Time between prefetch renderer startup and when parsing is complete. + </summary> +</histogram> + <histogram name="Prerender.NoStatePrefetchResponseTypes" enum="NoStatePrefetchResponseType"> <owner>droger@chromium.org</owner> @@ -62507,6 +68487,14 @@ </summary> </histogram> +<histogram name="Previews.CacheControlNoTransform.BlockedPreview" + enum="PreviewsType"> + <owner>dougarnett@chromium.org</owner> + <summary> + Blocked previews due to Cache-Control:no-transform directive. + </summary> +</histogram> + <histogram name="Previews.ContentLength" units="KB"> <owner>ryansturm@chromium.org</owner> <summary> @@ -62569,7 +68557,9 @@ When evaluating whether to show a user a preview, the preview might be disallowed for various reasons. If the preview is disallowed, then this reports the reason for disallowing it. If the preview is allowed, then this - reports "Previews Allowed". + generally reports "Previews Allowed". It may instead report + "Previews Allowed without server rule check" for a preview that + expects to check server rules but they are not enabled. </summary> </histogram> @@ -62601,6 +68591,15 @@ </summary> </histogram> +<histogram name="Previews.OptOut.SQLiteLoadError" enum="SqliteErrorCode"> + <owner>ryansturm@chromium.org</owner> + <summary> + The SQLite error code that the previews opt out store saw when trying to + open the SQLite database. This is logged when an unexpected error occurs + when trying to open the database file. + </summary> +</histogram> + <histogram name="Previews.OptOut.UserOptedOut" enum="PreviewsUserOptedOut"> <owner>ryansturm@chromium.org</owner> <summary> @@ -62615,6 +68614,15 @@ </summary> </histogram> +<histogram name="Previews.ProcessHintsResult" enum="PreviewsProcessHintsResult"> + <owner>dougarnett@chromium.org</owner> + <summary> + Whether processing the previews hints succeeded and if any previews hints + were found. Recorded when the PreviewsOptimizationGuide receives a + notification to process hints. + </summary> +</histogram> + <histogram name="PrinterService.PrinterServiceEvent" enum="PrinterServiceEventType"> <owner>vitalybuka@chromium.org</owner> @@ -62995,6 +69003,13 @@ </summary> </histogram> +<histogram name="ProductTour.IOSScreens" units="ms"> +<!-- Name completed by histogram_suffixes name="IOSProductTourScreens" --> + + <owner>mrefaat@google.com</owner> + <summary>The time spent in product tour screens for ios.</summary> +</histogram> + <histogram name="Profile.AddNewUser" enum="ProfileAddNewUser"> <owner>bcwhite@chromium.org</owner> <owner>rlp@chromium.org</owner> @@ -63143,6 +69158,14 @@ </summary> </histogram> +<histogram name="Profile.DiceUI.GaiaAccountsStale" enum="BooleanStale"> + <owner>tangltom@chromium.org</owner> + <summary> + This histogram tracks whether the accounts cached in the GAIA cookie service + manager are stale when presenting the user menu when DICE is enabled. + </summary> +</histogram> + <histogram name="Profile.ExtensionSize" units="MB"> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <summary>Size of the extension cookies database.</summary> @@ -63215,6 +69238,9 @@ <histogram name="Profile.NewAvatarMenu.NotYou" enum="ProfileNewAvatarMenuNotYou"> + <obsolete> + Deprecated 2017-10-16. No longer tracked. Feature removed. + </obsolete> <owner>mlerman@chromium.org</owner> <summary> Tracks user interactions with the 'Not You?' bubble that users can navigate @@ -63224,6 +69250,9 @@ <histogram name="Profile.NewAvatarMenu.Signin" enum="ProfileNewAvatarMenuSignin"> + <obsolete> + Deprecated 2017-10-19. No longer tracked. Feature removed. + </obsolete> <owner>mlerman@chromium.org</owner> <summary> Tracks user interactions with the signin bubble that appears in the New @@ -63234,6 +69263,9 @@ <histogram name="Profile.NewAvatarMenu.Upgrade" enum="ProfileNewAvatarMenuUpgrade"> + <obsolete> + Deprecated 2017-10-16. No longer tracked. Feature removed. + </obsolete> <owner>mlerman@chromium.org</owner> <summary> Tracks user interactions with the bubble that appears for users in the new @@ -63653,6 +69685,49 @@ </summary> </histogram> +<histogram name="ProximityAuth.BleWeaveConnectionResult" + enum="ProximityAuth_BleWeaveConnectionResult"> + <owner>hansberry@chromium.org</owner> + <summary> + Provides a breakdown of how often each BLE weave connection result occurs. + </summary> +</histogram> + +<histogram name="ProximityAuth.BluetoothGattConnectionResult" + enum="ProximityAuth_BluetoothGattConnectionResult"> + <owner>hansberry@chromium.org</owner> + <summary> + Provides a breakdown of how many times each possible Bluetooth GATT + connection result occurs. + + The bucket "Unknown result" indicates that the Bluetooth platform + returned an unknown error code; if it has any counts, the client code should + be changed to account for the new error code. + </summary> +</histogram> + +<histogram name="ProximityAuth.BluetoothGattNotifySessionResult" + enum="ProximityAuth_BluetoothGattServiceOperationResult"> + <owner>hansberry@chromium.org</owner> + <summary> + Provides a breakdown of how many times each possible Bluetooth GATT + "notify session" attempt result occurs. + + The bucket "Unknown result" indicates that the Bluetooth platform + returned an unknown error code; if it has any counts, the client code should + be changed to account for the new error code. + </summary> +</histogram> + +<histogram name="ProximityAuth.BluetoothGattWriteCharacteristicResult" + enum="ProximityAuth_BluetoothGattServiceOperationResult"> + <owner>hansberry@chromium.org</owner> + <summary> + Provides a breakdown of how many times each possible Bluetooth GATT + "write characteristic" attempt result occurs. + </summary> +</histogram> + <histogram name="ProxyOverriddenBubble.ExtensionCount" units="Extensions"> <obsolete> Deprecated 9/2016. Never added to histograms.xml and value is always 1. @@ -63772,6 +69847,9 @@ </histogram> <histogram name="PurgeAndSuspend.PendingTaskCount"> + <obsolete> + Deprecated Oct 2017. + </obsolete> <owner>tasak@google.com</owner> <summary> This records how many tasks are still in task queues when a backgrounded @@ -64635,6 +70713,17 @@ </summary> </histogram> +<histogram name="Renderer.WKWebViewCallbackAfterDestroy" enum="BooleanHit"> + <owner>michaeldo@chromium.org</owner> + <summary> + [iOS] Counts the number of times a WKNavigationDelegate callback was called + after the CRWWebController was closed. This is unexpected and could be the + cause of many crashes. If this histogram is ever logged, it means that + Chrome needs to gracefully handle the case when WKNavigationDelegate + callbacks are called for a destroyed web controller. Only logged on iOS. + </summary> +</histogram> + <histogram name="Renderer2.FinishDocToFinish"> <obsolete> Deprecated 04/2016 as doesn't have data nor owner. @@ -64874,6 +70963,11 @@ <histogram name="Renderer4.CompositorScrollHitTestResult" enum="CompositorScrollResult"> + <obsolete> + Deprecated in 12/2017. Renderer4.MainThreadGestureScrollReason and + Renderer4.MainThreadWheelScrollReason could track more detailed reasons of + main thread scrolling. + </obsolete> <owner>vollick@chromium.org</owner> <summary> It's possible for compositor hit testing to determine conclusively that @@ -64971,7 +71065,7 @@ </summary> </histogram> -<histogram name="Renderer4.GpuImageDecodeState" enum="GpuImageDecodeState"> +<histogram name="Renderer4.GpuImageDecodeState" enum="GpuImageUsageState"> <owner>vmpstr@chromium.org</owner> <summary> Gpu image decode usage statistics. Images are decoded and locked prior to @@ -64989,8 +71083,29 @@ </summary> </histogram> +<histogram name="Renderer4.GpuImageUploadState" enum="GpuImageUsageState"> + <owner>ericrk@chromium.org</owner> + <summary> + Gpu image upload usage statistics. Images are uploaded and locked prior to + use; this indicates how that upload is used during tile management. + </summary> +</histogram> + +<histogram name="Renderer4.GpuImageUploadState.FirstLockWasted" + enum="BooleanWasted"> + <owner>ericrk@chromium.org</owner> + <summary> + Indication whether the first lock of an image upload was wasted (image was + not used). Images are uploaded and locked prior to raster; this indicates + whether the upload was used or not during the first lock. + </summary> +</histogram> + <histogram name="Renderer4.GpuImageUploadState.FirstRefWasted" enum="BooleanWasted"> + <obsolete> + Deprecated as of 06/2017. No longer generated. + </obsolete> <owner>vmpstr@chromium.org</owner> <summary> Indication whether the first ref of a GPU image upload was wasted (not used @@ -65000,6 +71115,9 @@ </histogram> <histogram name="Renderer4.GpuImageUploadState.Used" enum="BooleanUsage"> + <obsolete> + Deprecated as of 06/2017. No longer generated. + </obsolete> <owner>vmpstr@chromium.org</owner> <summary> Indication whether the GPU image upload was used in raster. Images are @@ -65054,6 +71172,10 @@ </histogram> <histogram name="Renderer4.IdealContentsScale"> + <obsolete> + Deprecated 02/2018. The ideal content scale closely matches the default + device scale factor. + </obsolete> <owner>vmpstr@chromium.org</owner> <summary> The contents scale at which picture layer impl should be rasterized in order @@ -65085,7 +71207,8 @@ <histogram name="Renderer4.ImageDecodeTaskDurationUs.OutOfRaster" units="microseconds"> - <owner>vmpstr@chromium.org, khushalsagar@chromium.org</owner> + <owner>vmpstr@chromium.org</owner> + <owner>khushalsagar@chromium.org</owner> <summary> This metric records the duration of an image decode for out of raster path in the compositor. It is recorded every time we decode an image. It is @@ -65225,6 +71348,13 @@ </summary> </histogram> +<histogram name="Renderer4.RasterSourceClearType" enum="RasterSourceClearType"> + <owner>ericrk@chromium.org</owner> + <summary> + The type of clear which was needed for each cc::RasterSource rasterized. + </summary> +</histogram> + <histogram name="Renderer4.ReadyToDrawTileDrawStatus" enum="UsedInDraw"> <obsolete> Deprecated 02/2017 in Issue 675840. @@ -65274,6 +71404,16 @@ </summary> </histogram> +<histogram name="Renderer4.ReservedMemory" units="MB"> + <owner>bbudge@chromium.org</owner> + <owner>bradnelson@chromium.org</owner> + <summary> + The size of the contiguous memory block reserved in the renderer so that + large allocations are more likely to succeed. The reservation is currently + made in BlinkInitializer. + </summary> +</histogram> + <histogram name="Renderer4.ResourcePoolMemoryUsage" units="MB"> <owner>ericrk@chromium.org</owner> <summary> @@ -65439,6 +71579,17 @@ </summary> </histogram> +<histogram name="RendererScheduler.BackgroundedRendererTransition" + enum="BackgroundedRendererTransition"> + <owner>fmeawad@chromium.org</owner> + <owner>panicker@chromium.org</owner> + <summary> + Tracks the transitions of the renderer scheduler when it is backgrounded. + Once it is backgrounded, it can be stopped after a timeout, stopped due to + critical resources, resumed or foregrounded. + </summary> +</histogram> + <histogram name="RendererScheduler.BackgroundRendererMainThreadLoad" units="%"> <obsolete> Replaced with RendererScheduler.BackgroundRendererMainThreadLoad2 as of May @@ -65475,6 +71626,95 @@ </summary> </histogram> +<histogram base="true" + name="RendererScheduler.ExpectedQueueingTimeByFrameStatus" + units="microseconds"> + <obsolete> + Replaced with RendererScheduler.ExpectedQueueingTimeByFrameStatus2 as of Feb + 2018. Buckets were changed. + </obsolete> + <owner>npm@chromium.org</owner> + <owner>tdresser@chromium.org</owner> + <summary> + Expected queueing time split by tasks according to their frame status, in + microseconds. The sum of the split values will be equal to the total, + reported on RendererScheduler.ExpectedTaskQueueingDuration2. Recorded for + each 1000 ms window. + </summary> +</histogram> + +<histogram base="true" + name="RendererScheduler.ExpectedQueueingTimeByFrameStatus2" + units="microseconds"> + <owner>npm@chromium.org</owner> + <owner>tdresser@chromium.org</owner> + <summary> + Expected queueing time split by tasks according to their frame status, in + microseconds. The sum of the split values will be equal to the total, + reported on RendererScheduler.ExpectedTaskQueueingDuration3. Recorded for + each 1000 ms window. + </summary> +</histogram> + +<histogram base="true" name="RendererScheduler.ExpectedQueueingTimeByFrameType" + units="ms"> + <obsolete> + Replaced with RendererScheduler.ExpectedQueueingTimeByFrameStatus as of + December 2017. + </obsolete> + <owner>npm@chromium.org</owner> + <summary> + Expected queueing time split by tasks according to their frame type. The sum + of the split values should be equal to the total, reported on + RendererScheduler.ExpectedTaskQueueingDuration. Recorded for each 1000 ms + window. + </summary> +</histogram> + +<histogram base="true" name="RendererScheduler.ExpectedQueueingTimeByTaskQueue" + units="microseconds"> + <obsolete> + Replaced with RendererScheduler.ExpectedQueueingTimeByTaskQueue2 as of Feb + 2018. Buckets were changed. + </obsolete> + <owner>npm@chromium.org</owner> + <owner>tdresser@chromium.org</owner> + <summary> + Expected queueing time split by tasks according to the type of their task + queue, in microseconds. The sum of the split values should be equal to the + total, reported on RendererScheduler.ExpectedTaskQueueingDuration2. Recorded + for each 1000 ms window. + </summary> +</histogram> + +<histogram base="true" + name="RendererScheduler.ExpectedQueueingTimeByTaskQueue2" + units="microseconds"> + <owner>npm@chromium.org</owner> + <owner>tdresser@chromium.org</owner> + <summary> + Expected queueing time split by tasks according to the type of their task + queue, in microseconds. The sum of the split values should be equal to the + total, reported on RendererScheduler.ExpectedTaskQueueingDuration3. Recorded + for each 1000 ms window. + </summary> +</histogram> + +<histogram base="true" + name="RendererScheduler.ExpectedQueueingTimeByTaskQueueType" units="ms"> + <obsolete> + Replaced with RendererScheduler.ExpectedQueueingTimeByTaskQueue as of + December 2017. + </obsolete> + <owner>npm@chromium.org</owner> + <summary> + Expected queueing time split by tasks according to the type of their task + queue. The sum of the split values should be equal to the total, reported on + RendererScheduler.ExpectedTaskQueueingDuration. Recorded for each 1000 ms + window. + </summary> +</histogram> + <histogram name="RendererScheduler.ExpectedQueueingTimeWhenQueueingTime" units="ms"> <owner>tdresser@chromium.org</owner> @@ -65496,6 +71736,32 @@ </summary> </histogram> +<histogram name="RendererScheduler.ExpectedTaskQueueingDuration2" + units="microseconds"> + <obsolete> + Replaced with RendererScheduler.ExpectedTaskQueueingDuration3 as of Feb + 2018. Buckets were changed. + </obsolete> + <owner>tdresser@chromium.org</owner> + <owner>npm@chromium.org</owner> + <summary> + The estimated queueing duration which would be observed for additional high + priority tasks posted to the RendererScheduler, in microseconds. Recorded + for each 1000 ms window. + </summary> +</histogram> + +<histogram name="RendererScheduler.ExpectedTaskQueueingDuration3" + units="microseconds"> + <owner>tdresser@chromium.org</owner> + <owner>npm@chromium.org</owner> + <summary> + The estimated queueing duration which would be observed for additional high + priority tasks posted to the RendererScheduler, in microseconds. Recorded + for each 1000 ms window. + </summary> +</histogram> + <histogram name="RendererScheduler.ForegroundRendererMainThreadLoad" units="%"> <obsolete> Replaced with RendererScheduler.ForegroundRendererMainThreadLoad2 as of May @@ -65532,6 +71798,15 @@ </summary> </histogram> +<histogram name="RendererScheduler.IPC.FrameVisibility" enum="Boolean"> + <owner>altimin@chromium.org</owner> + <owner>lpy@chromium.org</owner> + <summary> + This boolean keeps track the count of the visibility change of a frame. + Recorded every time when the visibility of a frame is changed. + </summary> +</histogram> + <histogram name="RendererScheduler.MaxQueueingTime" units="ms"> <owner>maxlg@chromium.org</owner> <summary> @@ -65556,7 +71831,8 @@ <obsolete> Replaced with RendererScheduler.NumberOfTasksPerQueueType2 as of May 2017. </obsolete> - <owner>altimin@chromium.org,alexclarke@chromium.org</owner> + <owner>altimin@chromium.org</owner> + <owner>alexclarke@chromium.org</owner> <summary> The number of completed renderer tasks split per task queue type. Used to monitor usage of each type of task queue. Reported each time when task is @@ -65569,7 +71845,8 @@ <obsolete> Replaced with RendererScheduler.TaskCountPerQueueType as of July 2017. </obsolete> - <owner>altimin@chromium.org,alexclarke@chromium.org</owner> + <owner>altimin@chromium.org</owner> + <owner>alexclarke@chromium.org</owner> <summary> The number of completed renderer tasks split per task queue type. Used to monitor usage of each type of task queue. Reported each time when task is @@ -65645,6 +71922,18 @@ </summary> </histogram> +<histogram name="RendererScheduler.TaskCountPerFrameType" + enum="RendererSchedulerFrameType2"> + <owner>altimin@chromium.org</owner> + <summary> + The number of completed renderer tasks split per frame type. Used to monitor + usage of each type of frame. Reported each time when task is completed. + + Note that this metric discards tasks longer than 30 seconds because they are + considered to be a result of measurement glitch. + </summary> +</histogram> + <histogram name="RendererScheduler.TaskCountPerQueueType" enum="RendererSchedulerTaskQueueType"> <owner>altimin@chromium.org</owner> @@ -65658,12 +71947,72 @@ </summary> </histogram> +<histogram name="RendererScheduler.TaskCPUDurationPerTaskType.DedicatedWorker" + enum="RendererSchedulerTaskType" units="ms"> + <owner>altimin@chromium.org</owner> + <summary> + Total duration of dedicated worker tasks (thread time) split by per thread + type. Reported each time when task is completed and current accumulated + duration is longer than 1ms. + + Note that this metric discards tasks longer than 30 seconds because they are + considered to be a result of measurement glitch. + </summary> +</histogram> + +<histogram name="RendererScheduler.TaskCPUDurationPerThreadType" + enum="RendererSchedulerThreadType" units="ms"> + <owner>altimin@chromium.org</owner> + <summary> + Total cpu time of renderer tasks split by per thread type. Wall time is + tracked by RendererScheduler.TaskDurationPerThreadType histogram. This + histogram is used to compare CPU usage of tasks from different threads. + + Only 1% of randomly sampled tasks have cpu time measured and report duration + for this histogram. + + Note that this metric discards tasks longer than 30 seconds because they are + considered to be a result of measurement glitch. + </summary> +</histogram> + +<histogram name="RendererScheduler.TaskDurationPerFrameType" + enum="RendererSchedulerFrameType" units="ms"> + <obsolete> + Replaced with RendererScheduler.TaskDurationPerFrameType2 due to the + introduction of new types of frames as of 11/2017. + </obsolete> + <owner>altimin@chromium.org</owner> + <summary> + Total duration of renderer per-frame tasks split per frame type. Used to + monitor workload coming from different frames. Reported each time when task + is completed and current accumulated duration is longer than 1ms. + + This metric is susceptible to problematic outliers and should be analyzed + with custom scripts accounting for that rather than from a dashboard. + </summary> +</histogram> + +<histogram name="RendererScheduler.TaskDurationPerFrameType2" + enum="RendererSchedulerFrameType2" units="ms"> + <owner>altimin@chromium.org</owner> + <summary> + Total duration of renderer per-frame tasks split per frame type. Used to + monitor workload coming from different frames. Reported each time when task + is completed and current accumulated duration is longer than 1ms. + + This metric is susceptible to problematic outliers and should be analyzed + with custom scripts accounting for that rather than from a dashboard. + </summary> +</histogram> + <histogram name="RendererScheduler.TaskDurationPerQueueType" enum="RendererSchedulerTaskQueueType" units="ms"> <obsolete> Replaced with RendererScheduler.TaskDurationPerQueueType2 as of May 2017. </obsolete> - <owner>altimin@chromium.org,alexclarke@chromium.org</owner> + <owner>altimin@chromium.org</owner> + <owner>alexclarke@chromium.org</owner> <summary> Total duration of renderer tasks split per task queue type. Used to monitor usage of each type of task queues. Reported each time when task is completed @@ -65676,7 +72025,8 @@ <histogram name="RendererScheduler.TaskDurationPerQueueType2" enum="RendererSchedulerTaskQueueType" units="ms"> - <owner>altimin@chromium.org,alexclarke@chromium.org</owner> + <owner>altimin@chromium.org</owner> + <owner>alexclarke@chromium.org</owner> <summary> Total duration of renderer tasks split per task queue type. Used to monitor usage of each type of task queues. Reported each time when task is completed @@ -65690,6 +72040,47 @@ </summary> </histogram> +<histogram name="RendererScheduler.TaskDurationPerTaskType" + enum="RendererSchedulerTaskType" units="ms"> + <owner>altimin@chromium.org</owner> + <owner>hajimehoshi@chromium.org</owner> + <summary> + Total duration of renderer per-frame tasks split per task type. Used to + monitor usage of each task type. Reported each time when task is completed + and current accumulated duration is longer than 1ms. + + This metric is susceptible to problematic outliers and should be analyzed + with custom scripts accounting for that rather than from a dashboard. + </summary> +</histogram> + +<histogram name="RendererScheduler.TaskDurationPerTaskType.DedicatedWorker" + enum="RendererSchedulerTaskType" units="ms"> + <owner>altimin@chromium.org</owner> + <summary> + Total duration of dedicated worker tasks (wall time) split by per thread + type. Reported each time when task is completed and current accumulated + duration is longer than 1ms. + + Note that this metric discards tasks longer than 30 seconds because they are + considered to be a result of measurement glitch. + </summary> +</histogram> + +<histogram name="RendererScheduler.TaskDurationPerThreadType" + enum="RendererSchedulerThreadType" units="ms"> + <owner>altimin@chromium.org</owner> + <owner>lpy@chromium.org</owner> + <summary> + Total duration of renderer tasks split by per thread type. Used to compare + CPU usage of tasks from different threads. Reported each time when task is + completed and current accumulated duration is longer than 1ms. + + Note that this metric discards tasks longer than 30 seconds because they are + considered to be a result of measurement glitch. + </summary> +</histogram> + <histogram name="RendererScheduler.TaskQueueManager.DelayedTaskLateness" units="ms"> <obsolete> @@ -65788,6 +72179,14 @@ <summary>Time between subsequent gestures (scrolls and pinches).</summary> </histogram> +<histogram name="RendererScheduler.WebFramesPerScheduler" units="web frames"> + <owner>altimin@chromium.org</owner> + <summary> + Number of web frame schedulers per renderer scheduler. Recorded once per + navigation. + </summary> +</histogram> + <histogram name="RendererScheduler.WebViewsPerScheduler" units="web views"> <owner>altimin@chromium.org</owner> <summary> @@ -65803,6 +72202,171 @@ </summary> </histogram> +<histogram name="RenderFrameObservers.DidChangeScrollOffset" units="ms"> + <obsolete> + Deprecated 2/2018 + </obsolete> + <owner>joelhockey@chromium.org</owner> + <summary> + Cumulative time spent by all RenderFrameObservers in + RenderFrameImpl.DidChangeScrollOffset. + </summary> +</histogram> + +<histogram name="RenderFrameObservers.DidClearWindowObject" units="ms"> + <obsolete> + Deprecated 2/2018 + </obsolete> + <owner>joelhockey@chromium.org</owner> + <summary> + Cumulative time spent by all RenderFrameObservers in + RenderFrameImpl.DidClearWindowObject. + </summary> +</histogram> + +<histogram name="RenderFrameObservers.DidCommitProvisionalLoad" units="ms"> + <obsolete> + Deprecated 2/2018 + </obsolete> + <owner>joelhockey@chromium.org</owner> + <summary> + Cumulative time spent by all RenderFrameObservers in + RenderFrameImpl.DidCommitProvisionalLoad. + </summary> +</histogram> + +<histogram name="RenderFrameObservers.DidCreateScriptContext" units="ms"> + <obsolete> + Deprecated 2/2018 + </obsolete> + <owner>joelhockey@chromium.org</owner> + <summary> + Cumulative time spent by all RenderFrameObservers in + RenderFrameImpl.DidCreateScriptContext. + </summary> +</histogram> + +<histogram name="RenderFrameObservers.DidFailProvisionalLoad" units="ms"> + <obsolete> + Deprecated 2/2018 + </obsolete> + <owner>joelhockey@chromium.org</owner> + <summary> + Cumulative time spent by all RenderFrameObservers in + RenderFrameImpl.DidFailProvisionalLoad. + </summary> +</histogram> + +<histogram name="RenderFrameObservers.DidFinishDocumentLoad" units="ms"> + <obsolete> + Deprecated 2/2018 + </obsolete> + <owner>joelhockey@chromium.org</owner> + <summary> + Cumulative time spent by all RenderFrameObservers in + RenderFrameImpl.DidFinishDocumentLoad. + </summary> +</histogram> + +<histogram name="RenderFrameObservers.DidFinishLoad" units="ms"> + <obsolete> + Deprecated 2/2018 + </obsolete> + <owner>joelhockey@chromium.org</owner> + <summary> + Cumulative time spent by all RenderFrameObservers in + RenderFrameImpl.DidFinishLoad. + </summary> +</histogram> + +<histogram name="RenderFrameObservers.DidMeaningfulLayout" units="ms"> + <obsolete> + Deprecated 2/2018 + </obsolete> + <owner>joelhockey@chromium.org</owner> + <summary> + Cumulative time spent by all RenderFrameObservers in + RenderFrameImpl.DidMeaningfulLayout. + </summary> +</histogram> + +<histogram name="RenderFrameObservers.DidStartProvisionalLoad" units="ms"> + <obsolete> + Deprecated 2/2018 + </obsolete> + <owner>joelhockey@chromium.org</owner> + <summary> + Cumulative time spent by all RenderFrameObservers in + RenderFrameImpl.DidStartProvisionalLoad. + </summary> +</histogram> + +<histogram name="RenderFrameObservers.FocusedNodeChanged" units="ms"> + <obsolete> + Deprecated 2/2018 + </obsolete> + <owner>joelhockey@chromium.org</owner> + <summary> + Cumulative time spent by all RenderFrameObservers in + RenderFrameImpl.FocusedNodeChanged. + </summary> +</histogram> + +<histogram name="RenderFrameObservers.OnMessageReceived" units="ms"> + <obsolete> + Deprecated 2/2018 + </obsolete> + <owner>joelhockey@chromium.org</owner> + <summary> + Cumulative time spent by all RenderFrameObservers in + RenderFrameImpl.OnMessageReceived. + </summary> +</histogram> + +<histogram name="RenderFrameObservers.ScriptedPrint" units="ms"> + <obsolete> + Deprecated 2/2018 + </obsolete> + <owner>joelhockey@chromium.org</owner> + <summary> + Cumulative time spent by all RenderFrameObservers in + RenderFrameImpl.ScriptedPrint. + </summary> +</histogram> + +<histogram name="RenderFrameObservers.WillCommitProvisionalLoad" units="ms"> + <obsolete> + Deprecated 2/2018 + </obsolete> + <owner>joelhockey@chromium.org</owner> + <summary> + Cumulative time spent by all RenderFrameObservers in + RenderFrameImpl.WillCommitProvisionalLoad. + </summary> +</histogram> + +<histogram name="RenderFrameObservers.WillSendSubmitEvent" units="ms"> + <obsolete> + Deprecated 2/2018 + </obsolete> + <owner>joelhockey@chromium.org</owner> + <summary> + Cumulative time spent by all RenderFrameObservers in + RenderFrameImpl.WillSendSubmitEvent. + </summary> +</histogram> + +<histogram name="RenderFrameObservers.WillSubmitForm" units="ms"> + <obsolete> + Deprecated 2/2018 + </obsolete> + <owner>joelhockey@chromium.org</owner> + <summary> + Cumulative time spent by all RenderFrameObservers in + RenderFrameImpl.WillSubmitForm. + </summary> +</histogram> + <histogram name="RenderViewContextMenu.OpenLinkAsUser" enum="OpenLinkAsUser"> <owner>jochen@chromium.org</owner> <summary> @@ -66015,6 +72579,27 @@ </summary> </histogram> +<histogram name="ResourceCoordinator.IPCPerMinute.Frame" units="count/m"> + <owner>lpy@chromium.org</owner> + <summary> + The number of IPCs from frame to GRC. Recorded every 1 minute. + </summary> +</histogram> + +<histogram name="ResourceCoordinator.IPCPerMinute.Page" units="count/m"> + <owner>lpy@chromium.org</owner> + <summary> + The number of IPCs from page to GRC. Recorded every 1 minute. + </summary> +</histogram> + +<histogram name="ResourceCoordinator.IPCPerMinute.Process" units="count/m"> + <owner>lpy@chromium.org</owner> + <summary> + The number of IPCs from process to GRC. Recorded every 1 minute. + </summary> +</histogram> + <histogram name="ResourcePrefetchPredictor.CachePattern" enum="HttpCachePattern"> <owner>alexilin@chromium.org</owner> @@ -67230,6 +73815,14 @@ </summary> </histogram> +<histogram name="SafeBrowsing.Interstitial.Type" enum="InterstitialTypeEnum"> + <owner>ntfschr@chromium.org</owner> + <summary> + Which interstitial type is being displayed to the user? This currently + applies only to WebView (where we show Loud vs. Quiet interstitials). + </summary> +</histogram> + <histogram name="SafeBrowsing.ModuleBaseRelocation" units="BaseRelocationType"> <owner>csharp@chromium.org</owner> <owner>krstnmnlsn@chromium.org</owner> @@ -68030,6 +74623,16 @@ </summary> </histogram> +<histogram name="SafeBrowsing.WebView.Viewable" enum="BooleanVisible"> + <owner>ntfschr@chromium.org</owner> + <summary> + When encountering an unsafe resource, this indicates whether the WebView is + considered to be viewable or not. Currently, we define "viewable" + as getVisibility() == View.VISIBLE and attached to the Android View + hierarchy. + </summary> +</histogram> + <histogram name="SB.BloomFilter" units="ms"> <obsolete> Has not been generated for years (7/8/14). @@ -68328,7 +74931,28 @@ The time that SafeBrowsing actually delayed the browsing experience. It records the difference between the time when Chrome would have started reading the response for a URL and when the SafeBrowsing system completed - its check of that URL. + its check of that URL. This is the sum of .Mainframe and .Subresource + breakout metrics. + </summary> +</histogram> + +<histogram name="SB2.Delay.MainFrame" units="ms"> + <owner>vakh@chromium.org</owner> + <summary> + The time that SafeBrowsing actually delayed the browsing experience. It + records the difference between the time when Chrome would have started + reading the response for a URL and when the SafeBrowsing system completed + its check of that URL. Logged for main frame resources only. + </summary> +</histogram> + +<histogram name="SB2.Delay.Subresource" units="ms"> + <owner>vakh@chromium.org</owner> + <summary> + The time that SafeBrowsing actually delayed the browsing experience. It + records the difference between the time when Chrome would have started + reading the response for a URL and when the SafeBrowsing system completed + its check of that URL. Logged for non-main frame resources only. </summary> </histogram> @@ -68691,6 +75315,17 @@ </summary> </histogram> +<histogram name="SB2.NoUserActionResourceLoadingDelay" units="ms"> + <owner>yzshen@chromium.org</owner> + <summary> + The total delay, in milliseconds, caused by SafeBrowsing for a resource + load, if the SafeBrowsing interstitial page is not shown and therefore no + user action is involved. At most one value is reported for each resource + load. If SafeBrowsing causes delays at different stages of a load, the sum + of all the delays will be reported. + </summary> +</histogram> + <histogram name="SB2.OldDatabaseKilobytes" units="KB"> <obsolete> Deprecated 7/2014. No longer generated. @@ -68880,7 +75515,31 @@ </summary> </histogram> +<histogram name="SB2.RemoteCall.CheckDelta" units="microseconds"> + <owner>csharrison@chromium.org</owner> + <owner>vakh@chromium.org</owner> + <summary> + The microseconds between sending the Safe Browsing API call and receiving + the response. Logged in java code and does not include any thread hops or + extra work. Note that this does include task queue time to respond to the + IPC (and that queue time is often non-trivial). + </summary> +</histogram> + +<histogram name="SB2.RemoteCall.CheckDispatchTime" units="microseconds"> + <owner>csharrison@chromium.org</owner> + <owner>vakh@chromium.org</owner> + <summary> + Wall time in microseconds for calling + Java_SafeBrowsingApiBridge_startUriLookup. Logged at every Safe Browsing + check on Android. + </summary> +</histogram> + <histogram name="SB2.RemoteCall.ChecksPending" units="calls"> + <obsolete> + Deprecated in M64 (Nov 2017). No longer generated. + </obsolete> <owner>nparker@chromium.org</owner> <summary> Number of outstanding calls for URLs getting classified through @@ -69150,6 +75809,15 @@ </summary> </histogram> +<histogram name="SBClientDownload.DmgFileArchivedBinariesCount" units="count"> + <owner>nparker@chromium.org</owner> + <summary> + The original number of archived_binaries found in a DMG-like file when it's + scanned, if at least one is found. The actual number sent in the download + request may be capped below this value. + </summary> +</histogram> + <histogram name="SBClientDownload.DmgFileFailureByType" enum="SBClientDownloadExtensions"> <owner>nparker@chromium.org</owner> @@ -69406,6 +76074,15 @@ </summary> </histogram> +<histogram name="SBClientDownload.ZipFileArchivedBinariesCount" units="count"> + <owner>nparker@chromium.org</owner> + <summary> + The original number of archived_binaries found in a zip-like file when it's + scanned, if at least one is found. The actual number sent in the download + request may be capped below this value. + </summary> +</histogram> + <histogram name="SBClientDownload.ZipFileContainsAppDirectory" enum="Boolean"> <owner>jialiul@chromium.org</owner> <summary> @@ -69859,6 +76536,9 @@ </histogram> <histogram name="SBIRS.BLAHashTime" units="ms"> + <obsolete> + Blacklist Load analysis was removed in M63. + </obsolete> <owner>caitkp@google.com</owner> <summary> The elapsed time to compute the hash of a blacklisted module. @@ -69866,6 +76546,9 @@ </histogram> <histogram name="SBIRS.BLASignatureTime" units="ms"> + <obsolete> + Blacklist Load analysis was removed in M63. + </obsolete> <owner>caitkp@google.com</owner> <summary> The elapsed time to validate the signature of a blacklisted module. @@ -70001,7 +76684,7 @@ <summary>The elapsed time to upload a safe browsing incident report.</summary> </histogram> -<histogram name="SBIRS.StateStoreInitResult" enum="StateStoreInitResult"> +<histogram name="SBIRS.StateStoreInit" enum="StateStoreInitResult"> <owner>proberge@google.com</owner> <summary> The result of initializing the state store and comparing the preferences to @@ -70513,6 +77196,54 @@ </summary> </histogram> +<histogram name="Scheduling.DrawIntervalWithCompositedAnimations2" + units="microseconds"> + <owner>paint-dev@chromium.org</owner> + <summary> + The time delta between the draw times of back-to-back BeginImplFrames, + regardless of whether or not they result in a swap, when there is at least + one composited animation. + + The interval is only recorded when every BeginImplFrame wants to draw. + </summary> +</histogram> + +<histogram name="Scheduling.DrawIntervalWithMainThreadAnimations2" + units="microseconds"> + <owner>paint-dev@chromium.org</owner> + <summary> + The time delta between the draw times of back-to-back BeginImplFrames of new + active trees only, regardless of whether or not they result in a swap, when + there is at least one main thread animation. + + The interval is only recorded when every BeginImplFrame wants to draw. + </summary> +</histogram> + +<histogram name="Scheduling.DrawIntervalWithMainThreadCompositableAnimations2" + units="microseconds"> + <owner>paint-dev@chromium.org</owner> + <summary> + The time delta between the draw times of back-to-back BeginImplFrames of new + active trees only, regardless of whether or not they result in a swap, when + there is at least one main thread animation that could be composited but + not, due to running experiment. + + The interval is only recorded when every BeginImplFrame wants to draw. + </summary> +</histogram> + +<histogram name="Scheduling.ImageInvalidationUpdateDuration" + units="microseconds"> + <owner>khushalsagar@chromium.org</owner> + <summary> + Duration for updating animated images and invalidating layers for images + invalidated on the sync tree in the compositor. This interval is recorded + each time the sync tree is updated after a commit or an impl-side + invalidation. + </summary> +</histogram> + <histogram name="Scheduling.InvalidationToReadyToActivateDuration2" units="microseconds"> <owner>brianderson@chromium.org</owner> @@ -70655,7 +77386,6 @@ <obsolete> Deprecated 2017-9. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> The number of dictionaries advertised in an HTTP GET transaction that supports SDCH. Note that only non-zero advertisements are logged. @@ -70666,7 +77396,6 @@ <obsolete> Deprecated 2017-9. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> The reason why a blacklist blocking a request from advertising SDCH was implemented. There is one entry in this histogram per inhibited request. @@ -70677,7 +77406,6 @@ <obsolete> Deprecated 2017-9. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> Each sample is the byte count for a dictionary that is loaded by Chrome. A dictionary is loaded shortly after the first Google query performed in each @@ -70690,7 +77418,6 @@ <obsolete> Deprecated 2017-9. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> The fate, both on input and output, of dictionary requests. There is intended to be two entries in this histogram for each Get-Dictionary seen @@ -70702,7 +77429,6 @@ <obsolete> Deprecated 2017-9. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> The number of times a dictionary has been successfully used for decoding, recorded at the time it is evicted from the manager. @@ -70713,7 +77439,6 @@ <obsolete> Replaced by Sdch3.Experiment3_Holdback. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> Duration in time from when a request was made, until all bytes were received. During the running of an SDCH latency experiment, these packets @@ -70726,7 +77451,6 @@ <obsolete> Replaced by Sdch3.Experiment3_Holdback. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> Duration in time from when a request was made, until all bytes were received. During the running of an SDCH latency experiment, these packets @@ -70739,7 +77463,6 @@ <obsolete> Deprecated 2017-9. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> Duration in time from the first byte of a request was received, until all bytes were received. During the running of an SDCH latency experiment, @@ -70752,7 +77475,6 @@ <obsolete> Deprecated 2017-9. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> Duration in time from the first byte of a request was received, until all bytes were received. During the running of an SDCH latency experiment, @@ -70765,7 +77487,6 @@ <obsolete> Replaced by Sdch3.Experiment2_Decode. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> Duration in time from when a request was made, until all bytes were received. During the running of an SDCH latency experiment, these packets @@ -70778,7 +77499,6 @@ <obsolete> Replaced by Sdch3.Experiment2_Holdback. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> Duration in time from when a request was made, until all bytes were received. During the running of an SDCH latency experiment, these packets @@ -70791,7 +77511,6 @@ <obsolete> Deprecated 2016-11. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> Sampling only transmissions with 5 or more packets, the duration between receipt of the 1st **NON**-SDCH encoded packet to receipt of the 2nd packet, @@ -70809,7 +77528,6 @@ <obsolete> Deprecated 2016-11. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> The duration between receipt of the 1st holdback (non-SDCH encoded) packet and receipt of the last packet. Only groups that are part of the holdback @@ -70821,7 +77539,6 @@ <obsolete> Deprecated 2016-11. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> Sampling only transmissions with 5 or more packets, the duration between receipt of the 2nd **NON**-SDCH encoded packet to receipt of the 3rd packet, @@ -70839,7 +77556,6 @@ <obsolete> Deprecated 2016-11. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> Sampling only transmissions with 5 or more packets, the duration between receipt of the 3rd **NON**-SDCH encoded packet to receipt of the 4th packet, @@ -70857,7 +77573,6 @@ <obsolete> Deprecated 2016-11. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> Sampling only transmissions with 5 or more packets, the duration between receipt of the 4th **NON**-SDCH encoded packet to receipt of the 5th packet, @@ -70875,7 +77590,6 @@ <obsolete> Deprecated 2016-11. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> If SDCH decoding was disabled client side, this records how many URLs were processed by the SDCH filter before disabling this feature. The most common @@ -70892,7 +77606,6 @@ <obsolete> Deprecated 2017-9. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> The amount of time between creation/load of an SDCH dictionary and its first use. @@ -70903,7 +77616,6 @@ <obsolete> Deprecated 2016-11. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> Sampling only transmissions with 5 or more packets, the duration between receipt of the 1st SDCH encoded packet and receipt of the 2nd packet, for @@ -70918,7 +77630,6 @@ <obsolete> Deprecated 2016-11. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> The duration between receipt of the 1st SDCH encoded packet and receipt of the last packet, for processing by the SDCH filter. @@ -70929,7 +77640,6 @@ <obsolete> Deprecated 2016-11. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> Sampling only transmissions with 5 or more packets, the duration between receipt of the 2nd SDCH encoded packet and receipt of the 3rd packet, for @@ -70944,7 +77654,6 @@ <obsolete> Deprecated 2016-11. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> Sampling only transmissions with 5 or more packets, the duration between receipt of the 3rd SDCH encoded packet and receipt of the 4th packet, for @@ -70959,7 +77668,6 @@ <obsolete> Deprecated 2016-11. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> Sampling only transmissions with 5 or more packets, the duration between receipt of the 4th SDCH encoded packet and receipt of the 5th packet, for @@ -70974,7 +77682,6 @@ <obsolete> Deprecated 2016-11. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> (discontinued 7/29/2009, and replaced by Sdch3.Network_Decode_Bytes_Processed_b) The number of bytes processed @@ -70986,7 +77693,6 @@ <obsolete> Deprecated 2017-9. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> The number of bytes processed (received over the net or from cache) by the SDCH filter chain. @@ -70997,7 +77703,6 @@ <obsolete> Deprecated 2016-11. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> The number of bytes emitted after decoding by the SDCH filter. </summary> @@ -71007,7 +77712,6 @@ <obsolete> Deprecated 2016-11. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> The duration between putting the first byte of a request (such as a GET) on the wire, until the last by of compressed SDCH encoded content is received @@ -71021,7 +77725,6 @@ <obsolete> Deprecated 2016-11. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> An approximation to the total number of SDCH encoded packets received for processing by the SDCH filter. Packet count boundaries are calculated each @@ -71035,7 +77738,6 @@ <obsolete> Deprecated 2016-11. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> The ratio of the number of bytes read from the network (or cache) and fed to the filter chain (usually the gunzip filter) vs. the number of bytes emitted @@ -71048,7 +77750,6 @@ <obsolete> Deprecated 2016-11. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> Sampling only transmissions with 5 or more packets, the duration between receipt of the 1st **NON**-SDCH encoded packet to receipt of the 2nd packet, @@ -71063,7 +77764,6 @@ <obsolete> Deprecated 2016-11. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> The duration between receipt of the 1st **NON**-SDCH encoded packet to receipt of the last packet, for processing by the SDCH filter. @@ -71074,7 +77774,6 @@ <obsolete> Deprecated 2016-11. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> Sampling only transmissions with 5 or more packets, the duration between receipt of the 2nd **NON**-SDCH encoded packet to receipt of the 3rd packet, @@ -71089,7 +77788,6 @@ <obsolete> Deprecated 2016-11. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> Sampling only transmissions with 5 or more packets, the duration between receipt of the 3rd **NON**-SDCH encoded packet to receipt of the 4th packet, @@ -71104,7 +77802,6 @@ <obsolete> Deprecated 2016-11. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> Sampling only transmissions with 5 or more packets, the duration between receipt of the 4th **NON**-SDCH encoded packet to receipt of the 5th packet, @@ -71119,7 +77816,6 @@ <obsolete> Deprecated 2016-11. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> The duration between putting the first byte of a request (such as a GET) on the wire, until the last by gzip compressed content is received and @@ -71134,7 +77830,6 @@ <obsolete> Deprecated 2016-11. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> The total number of **NON**-SDCH encoded packets received for processing by the SDCH filter in one URL fetch. Packet count boundaries are calculated @@ -71170,7 +77865,6 @@ <obsolete> Deprecated 2016-11. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> If/when a ProblemCode INCOMPLETE_SDCH_CONTENT reports that the VCDIFF decoder still has internally buffered data that has never been read, this @@ -71184,7 +77878,6 @@ <obsolete> Deprecated 2016-11. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> If/when a ProblemCode INCOMPLETE_SDCH_CONTENT reports that the VCDIFF decoder still has internally buffered data that has never been read, this @@ -71197,7 +77890,6 @@ <obsolete> Deprecated 2016-11. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> If/when a ProblemCode INCOMPLETE_SDCH_CONTENT reports that the VCDIFF decoder still has internally buffered data that has never been read, this @@ -71211,7 +77903,6 @@ <obsolete> Deprecated 2017-9. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> Tracks failures that occur when reading in or writing out persisted dictionary information. @@ -71222,7 +77913,6 @@ <obsolete> Deprecated 2014-11. Sdch3.ProblemCodes_5 used instead. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary>Each sample is the report of a distinct problem code.</summary> </histogram> @@ -71230,7 +77920,6 @@ <obsolete> Deprecated 2014-11. Sdch3.ProblemCodes_5 used instead. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary>Each sample is the report of a distinct problem code.</summary> </histogram> @@ -71238,7 +77927,6 @@ <obsolete> Deprecated 2017-9. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary>Each sample is the report of a distinct problem code.</summary> </histogram> @@ -71247,7 +77935,6 @@ <obsolete> Deprecated 2017-9. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> Attempted SDCH decoding can fail at the Read() filter processing stage. In some of those cases, the request is corrupted enough that it must be either @@ -71261,7 +77948,6 @@ <obsolete> Deprecated 2017-9. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> Attempted SDCH decoding can fail at the Read() filter processing stage. In some of those cases, the request is corrupted enough that it must be either @@ -71286,7 +77972,6 @@ <obsolete> Deprecated 2016-11. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> If/when a ProblemCode UNFLUSHED_CONTENT reports that the SDCH filter is still buffering output of the VCDIFF decoder that has never been read, this @@ -71298,7 +77983,6 @@ <obsolete> Deprecated 2016-11. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> If/when a ProblemCode UNFLUSHED_CONTENT reports that the SDCH filter is still buffering output of the VCDIFF decoder that has never been read, this @@ -71312,7 +77996,6 @@ <obsolete> Deprecated 2016-11. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> If/when a ProblemCode UNFLUSHED_CONTENT reports that the SDCH filter is still buffering output of the VCDIFF decoder that has never been read, this @@ -71325,7 +78008,6 @@ <obsolete> Deprecated 2016-11. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> If/when a ProblemCode UNFLUSHED_CONTENT reports that the SDCH filter is still buffering output of the VCDIFF decoder that has never been read, this @@ -71338,7 +78020,6 @@ <obsolete> Use Sdch3.UsageInterval2 instead. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> The amount of time from the last time an SDCH dictionary was used. For the first use of a dictionary, the maximum time is used. @@ -71349,7 +78030,6 @@ <obsolete> Deprecated 2017-9. </obsolete> - <owner>rdsmith@chromium.org</owner> <summary> The amount of time from the last time an SDCH dictionary was used. Not recorded on first dictionary use. First use is recorded as @@ -71380,6 +78060,102 @@ </summary> </histogram> +<histogram name="Search.ContextualSearch.Ranker.Model.Status" + enum="RankerModelStatus"> + <owner>hamelphi@google.com</owner> + <summary>Tracks the outcome of attempts to download a Ranker Model.</summary> +</histogram> + +<histogram name="Search.ContextualSearch.Ranker.NotSuppressed.ResultsSeen" + enum="ContextualSearchResultsSeen"> + <owner>donnd@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <summary> + Records whether the user opened the panel when a tap was not suppressed by + Ranker. Recorded when the UX is hidden. Implemented for Android. + </summary> +</histogram> + +<histogram name="Search.ContextualSearch.Ranker.Recorded" enum="Boolean"> + <owner>donnd@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <summary> + Logs that features were recorded to Ranker and whether it was an outcome or + not. Recorded when the UX is shown or hidden. Implemented for Android. + </summary> +</histogram> + +<histogram name="Search.ContextualSearch.Ranker.RecordedNative" enum="Boolean"> + <owner>donnd@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <summary> + Logs that features were recorded to Ranker from native code and whether it + was an outcome or not. Recorded when the UX is shown or hidden. Implemented + for Android. + </summary> +</histogram> + +<histogram name="Search.ContextualSearch.Ranker.Suppressed" enum="Boolean"> + <owner>donnd@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <summary> + Records Ranker's prediction about whether a tap should be suppressed or not. + Recorded when the UX is hidden. Implemented for Android. + </summary> +</histogram> + +<histogram name="Search.ContextualSearch.Ranker.Timer.DownloadModel" units="ms"> + <owner>hamelphi@google.com</owner> + <summary> + Time taken for the Ranker Model Loader to download its model from the + configured URL, in ms. + </summary> +</histogram> + +<histogram name="Search.ContextualSearch.Ranker.Timer.ParseModel" units="ms"> + <owner>hamelphi@google.com</owner> + <summary> + Time taken for the Ranker Model Loader to parse its model, in ms. + </summary> +</histogram> + +<histogram name="Search.ContextualSearch.Ranker.Timer.ReadModel" units="ms"> + <owner>hamelphi@google.com</owner> + <summary> + Time taken for the Ranker Model Loader to read its model from local storage + (cache), in ms. + </summary> +</histogram> + +<histogram name="Search.ContextualSearch.Ranker.Timer.WriteModel" units="ms"> + <owner>hamelphi@google.com</owner> + <summary> + Time taken for the Ranker Model Loader to write its model to local storage, + in ms. + </summary> +</histogram> + +<histogram name="Search.ContextualSearch.Ranker.WasAbleToPredict" + enum="Boolean"> + <owner>donnd@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <summary> + Records whether Ranker was able to make a prediction about tap suppression. + Recorded when the UX is triggered by tap. Implemented for Android. + </summary> +</histogram> + +<histogram name="Search.ContextualSearch.Ranker.WouldSuppress.ResultsSeen" + enum="ContextualSearchResultsSeen"> + <owner>donnd@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <summary> + Records whether the user opened the panel when a tap would be suppressed by + Ranker if suppression was enforced. Recorded when the UX is hidden. + Implemented for Android. + </summary> +</histogram> + <histogram name="Search.ContextualSearchAllCapsResultsSeen" enum="ContextualSearchResultsSeen"> <obsolete> @@ -71394,6 +78170,16 @@ </summary> </histogram> +<histogram name="Search.ContextualSearchBarNoOverlap.PeekDuration" units="ms"> + <owner>donnd@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <summary> + The duration that the panel was peeking before being opened when triggered + by a tap that was in a part of the screen where it overlaps the Bar. Logged + when the panel is closed after being opened. Implemented for Android. + </summary> +</histogram> + <histogram name="Search.ContextualSearchBarOverlap" enum="ContextualSearchTapSuppression"> <owner>donnd@chromium.org</owner> @@ -71404,6 +78190,16 @@ </summary> </histogram> +<histogram name="Search.ContextualSearchBarOverlap.PeekDuration" units="ms"> + <owner>donnd@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <summary> + The duration that the panel was peeking before being opened when triggered + by a tap at the bottom of the screen where it overlaps the Bar. Logged when + the panel is closed after being opened. Implemented for Android. + </summary> +</histogram> + <histogram name="Search.ContextualSearchBarOverlapSeen" enum="ContextualSearchBarOverlapSeen"> <owner>donnd@chromium.org</owner> @@ -71673,6 +78469,17 @@ </summary> </histogram> +<histogram name="Search.ContextualSearchIPHShown" enum="Boolean"> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <summary> + The number of times the Contextual Search panel is opened, categorized by + whether In-Product Help for Contextual Search was shown before. Logged when + the panel is opened. Implemented for Android. + </summary> +</histogram> + <histogram name="Search.ContextualSearchLiteralSearchDuration" units="ms"> <owner>donnd@chromium.org</owner> <owner>twellington@chromium.org</owner> @@ -71723,7 +78530,21 @@ </summary> </histogram> +<histogram name="Search.ContextualSearchPanelOpenedIPHShown" enum="Boolean"> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <summary> + The number of times the Contextual Search panel is opened, categorized by + whether In-Product Help for opening the panel was shown before. Logged when + the panel is opened. Implemented for Android. + </summary> +</histogram> + <histogram name="Search.ContextualSearchPeekPromoCount" units="count"> + <obsolete> + Removed because the feature no longer exists. + </obsolete> <owner>donnd@chromium.org</owner> <owner>pedrosimonetti@chromium.org</owner> <owner>twellington@chromium.org</owner> @@ -71738,6 +78559,9 @@ <histogram name="Search.ContextualSearchPeekPromoCountUntilOpened" units="count"> + <obsolete> + Removed because the feature no longer exists. + </obsolete> <owner>donnd@chromium.org</owner> <owner>pedrosimonetti@chromium.org</owner> <owner>twellington@chromium.org</owner> @@ -71751,6 +78575,9 @@ <histogram name="Search.ContextualSearchPeekPromoOutcome" enum="ContextualSearchPeekPromoOutcome"> + <obsolete> + Removed because the feature no longer exists. + </obsolete> <owner>donnd@chromium.org</owner> <owner>pedrosimonetti@chromium.org</owner> <owner>twellington@chromium.org</owner> @@ -72064,8 +78891,20 @@ </summary> </histogram> +<histogram name="Search.ContextualSearchSecondTapMlOverrideSeen" enum="Boolean"> + <owner>donnd@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <summary> + Whether results were seen for a second tap that was allowed to override ML + Tap Suppression. Recorded when the UX is hidden. Implemented for Android. + </summary> +</histogram> + <histogram name="Search.ContextualSearchSecondTapSeen" enum="ContextualSearchResultsSeen"> + <obsolete> + Removed 11/2017 because the data is no longer valuable. + </obsolete> <owner>donnd@chromium.org</owner> <owner>twellington@chromium.org</owner> <summary> @@ -72171,6 +79010,17 @@ </summary> </histogram> +<histogram name="Search.ContextualSearchTapIPHShown" enum="Boolean"> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <summary> + The number of times the Contextual Search is triggered by tapping, + categorized by whether In-Product Help for tapping was shown before. Logged + when Contextual Search is triggered by tapping. Implemented for Android. + </summary> +</histogram> + <histogram name="Search.ContextualSearchTapLongDurationSeen" enum="ContextualSearchResultsSeen"> <owner>donnd@chromium.org</owner> @@ -72241,6 +79091,9 @@ <histogram name="Search.ContextualSearchTapSuppressionSeen" enum="ContextualSearchResultsSeen"> + <obsolete> + Removed 11/2017 because the data is no longer valuable. + </obsolete> <owner>donnd@chromium.org</owner> <owner>twellington@chromium.org</owner> <summary> @@ -72287,6 +79140,16 @@ </summary> </histogram> +<histogram name="Search.ContextualSearchTranslateCondition" enum="Boolean"> + <owner>donnd@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <summary> + For each contextual search that is triggered by tap, records whether the + translation conditions are met. Implemented for Android. + </summary> +</histogram> + <histogram name="Search.DefaultSearchChangeOrigin" enum="DefaultSearchChangeOrigin"> <owner>mathp@chromium.org</owner> @@ -72481,6 +79344,20 @@ </histogram> <histogram + name="Security.CertificateTransparency.MainFrameNavigationCompliance" + enum="CTComplianceStatus"> + <owner>estark@chromium.org</owner> + <summary> + The compliance of each main frame navigation's connection with the + Certificate Transparency policy. Recorded whenever a main-frame, + non-same-page navigation is committed. Connections can be compliant, or they + can be non-compliant for one of several reasons (not enough Signed + Certificate Timestamps [SCTs], not diverse enough SCTs, or the build was old + so CT compliance wasn't checked). + </summary> +</histogram> + +<histogram name="Security.HTTPBad.NavigationStartedAfterUserWarnedAboutSensitiveInput" units="ms"> <owner>estark@chromium.org</owner> @@ -72548,7 +79425,6 @@ <histogram name="Security.PageInfo.Action.HttpsUrl.Dangerous" enum="WebsiteSettingsAction"> <owner>estark@chromium.org</owner> - <owner>lgarron@chromium.org</owner> <summary> Tracks Page Info bubble actions that take place on an HTTPS URL that has been marked dangerous or not secure (such as for malware or broken HTTPS). @@ -72558,7 +79434,6 @@ <histogram name="Security.PageInfo.Action.HttpsUrl.Downgraded" enum="WebsiteSettingsAction"> <owner>estark@chromium.org</owner> - <owner>lgarron@chromium.org</owner> <summary> Tracks Page Info bubble actions that take place on a valid HTTPS URL that has a security issue (e.g. mixed content). @@ -72567,18 +79442,39 @@ <histogram name="Security.PageInfo.Action.HttpsUrl.Valid" enum="WebsiteSettingsAction"> + <obsolete> + Deprecated 2018-01-31, split into ValidEV and ValidNonEV. + </obsolete> <owner>estark@chromium.org</owner> - <owner>lgarron@chromium.org</owner> <summary> Tracks Page Info bubble actions that take place on a valid HTTPS URL with no security issues (e.g. no mixed content). </summary> </histogram> +<histogram name="Security.PageInfo.Action.HttpsUrl.ValidEV" + enum="WebsiteSettingsAction"> + <owner>estark@chromium.org</owner> + <summary> + Tracks Page Info bubble actions that take place on a valid HTTPS URL with no + security issues (e.g. no mixed content) and an Extended Validation + Certificate. + </summary> +</histogram> + +<histogram name="Security.PageInfo.Action.HttpsUrl.ValidNonEV" + enum="WebsiteSettingsAction"> + <owner>estark@chromium.org</owner> + <summary> + Tracks Page Info bubble actions that take place on a valid HTTPS URL with no + security issues (e.g. no mixed content), but no Extended Validation + Certificate. + </summary> +</histogram> + <histogram name="Security.PageInfo.Action.HttpUrl.Dangerous" enum="WebsiteSettingsAction"> <owner>estark@chromium.org</owner> - <owner>lgarron@chromium.org</owner> <summary> Tracks Page Info bubble actions that take place on an HTTP URL that has been marked dangerous (such as for malware). @@ -72588,7 +79484,6 @@ <histogram name="Security.PageInfo.Action.HttpUrl.Neutral" enum="WebsiteSettingsAction"> <owner>estark@chromium.org</owner> - <owner>lgarron@chromium.org</owner> <summary> Tracks Page Info bubble actions that take place on an HTTP URL that does not have an omnibox security indicator warning associated with it. @@ -72598,13 +79493,61 @@ <histogram name="Security.PageInfo.Action.HttpUrl.Warning" enum="WebsiteSettingsAction"> <owner>estark@chromium.org</owner> - <owner>lgarron@chromium.org</owner> <summary> Tracks Page Info bubble actions that take place on an HTTP URL that has been given a "Not secure" warning in the omnibox. </summary> </histogram> +<histogram name="Security.SecurityLevel.CryptographicScheme" + enum="SecurityLevel"> + <owner>estark@chromium.org</owner> + <summary> + Records the security level of a page with a cryptographic scheme (e.g. + https). This histogram is recorded once at navigation commit time, and can + be called again for the same document if the security level changes + dynamically. Note that the security level can change very quickly after + commit time, for example if the page includes mixed content on load (which + can downgrade the security level). This histogram should be analyzed with + care because each recorded security level is not necessarily user-visible: + in particular, a page may commit as a secure level (SECURE, EV_SECURE, + SECURE_WITH_POLICY_INSTALLED_CERT) but get quickly downgraded to NONE if it + shows mixed content on load. Therefore the histogram values should be + regarded as an upper-bound on what the user actually sees for these security + levels. + </summary> +</histogram> + +<histogram name="Security.SecurityLevel.FormSubmission" enum="SecurityLevel"> + <owner>carlosil@chromium.org</owner> + <owner>cthomp@chromium.org</owner> + <summary> + Records the security level of a page when submitting a form. This histogram + is recorded whenever a form submission navigation begins. The recorded + security level is the level of the page the form was submitted from, not the + one that the form targets. + </summary> +</histogram> + +<histogram name="Security.SecurityLevel.NoncryptographicScheme" + enum="SecurityLevel"> + <owner>estark@chromium.org</owner> + <summary> + Records the security level of a page with a non-cryptographic scheme (e.g. + http). This histogram is recorded once at navigation commit time, and can be + called again for the same document if the security level changes + dynamically. Note that the security level can change very quickly after + commit time, for example if the page includes a password field on load + (which can downgrade the security level). This histogram should be analyzed + with care because each recorded security level is not necessarily + user-visible: in particular, a page may commit as NONE or HTTP_SHOW_WARNING + but get quickly downgraded to HTTP_SHOW_WARNING or DANGEROUS, depending on + field trial configuration, if it shows a password field on load. Therefore + the histogram values should be regarded as an upper-bound on what the user + actually sees for the NONE and HTTP_SHOW_WARNING levels. + </summary> +</histogram> + <histogram name="Security.TreatInsecureOriginAsSecure"> <owner>mkwst@chromium.org</owner> <summary> @@ -72781,6 +79724,51 @@ </summary> </histogram> +<histogram name="ServiceWorker.CacheStorageInstalledScript.CachedMetadataSize" + units="bytes"> + <owner>horo@chromium.org</owner> + <summary> + The length of cached metadata of scripts which are stored to the + CacheStorage by the installing service worker. + </summary> +</histogram> + +<histogram + name="ServiceWorker.CacheStorageInstalledScript.CachedMetadataTotalSize" + units="bytes"> + <owner>horo@chromium.org</owner> + <summary> + The total length of cached metadata of scripts which are stored to the + CacheStorage by the installing service worker. + </summary> +</histogram> + +<histogram name="ServiceWorker.CacheStorageInstalledScript.Count" units="count"> + <owner>horo@chromium.org</owner> + <summary> + The counts of scripts which are stored to the CacheStorage by the installing + service worker. + </summary> +</histogram> + +<histogram name="ServiceWorker.CacheStorageInstalledScript.ScriptSize" + units="bytes"> + <owner>horo@chromium.org</owner> + <summary> + The length of scripts which are stored to the CacheStorage by the installing + service worker. + </summary> +</histogram> + +<histogram name="ServiceWorker.CacheStorageInstalledScript.ScriptTotalSize" + units="bytes"> + <owner>horo@chromium.org</owner> + <summary> + The total length of scripts which are stored to the CacheStorage by the + installing service worker. + </summary> +</histogram> + <histogram name="ServiceWorker.CanMakePaymentEvent.Time" units="ms"> <owner>jinho.bang@samsung.com</owner> <summary> @@ -73088,6 +80076,10 @@ <histogram name="ServiceWorker.MainFramePageLoad.CoreTransition" enum="CorePageTransition"> + <obsolete> + Deprecated 2018-01 in favor of + PageLoad.Clients.ServiceWorker.PageTransition. + </obsolete> <owner>horo@chromium.org</owner> <summary> The transition type for main frame page loads controlled by a service @@ -73097,6 +80089,9 @@ <histogram name="ServiceWorker.MainFramePageLoad.RedirectChainLength" units="urls"> + <obsolete> + Deprecated 2018-01. + </obsolete> <owner>horo@chromium.org</owner> <summary> Total length of the server redirects during main frame page loads controlled @@ -73755,7 +80750,7 @@ </histogram> <histogram name="ServiceWorkerCache.Cache.AddResponseType" - enum="ServiceWorkerCacheResponseType"> + enum="FetchResponseType"> <owner>nhiroki@chromium.org</owner> <summary> Records the response type to be added in the Cache by Cache.add()/addAll(). @@ -73763,7 +80758,7 @@ </histogram> <histogram name="ServiceWorkerCache.Cache.AllWritesResponseType" - enum="ServiceWorkerCacheResponseType"> + enum="FetchResponseType"> <owner>jkarlin@chromium.org</owner> <summary> Records the response type to be added in the Cache by all operations that @@ -73797,7 +80792,7 @@ </histogram> <histogram name="ServiceWorkerCache.InitBackendResult" - enum="ServiceWorkerCacheErrorType"> + enum="CacheStorageErrorType"> <owner>jkarlin@chromium.org</owner> <summary> The result of opening the backend in the ServiceWorker Cache API. @@ -74190,6 +81185,16 @@ </summary> </histogram> +<histogram name="SessionRestore.TabLoadTimeout" enum="BooleanTimedOut"> + <owner>zhenw@chromium.org</owner> + <summary> + The boolean indicates whether the tab load was initiated because a previous + tab load completed (including the tab was closed) or whether the tab load + was initiated because a timer fired to start the next load (true) during + session restore. + </summary> +</histogram> + <histogram name="SessionStorageDatabase.Commit" enum="LevelDBStatus"> <owner>cmumford@chromium.org</owner> <summary>The result of a commit to the sessionStorage database.</summary> @@ -74387,6 +81392,10 @@ </histogram> <histogram name="Settings.MachineIdGenerationSuccess" enum="BooleanSuccess"> + <obsolete> + Deprecated in Chrome 63, as we verified that machine id generation was not + flaky. + </obsolete> <owner>proberge@chromium.org</owner> <summary> Whether generation of the deterministic machine-specific device id was @@ -74816,6 +81825,9 @@ <histogram name="SettingsResetPrompt.NumberOfExtensionsDisabled" units="extensions"> + <obsolete> + Deprecated on 2018-01-16. + </obsolete> <owner>alito@chromium.org</owner> <summary> The number of extensions that were disabled after the user accepted the @@ -74825,6 +81837,9 @@ <histogram name="SettingsResetPrompt.NumberOfExtensionsToDisable" units="extensions"> + <obsolete> + Deprecated on 2018-01-16. + </obsolete> <owner>alito@chromium.org</owner> <summary> The number of extensions that will be disabled if the user accepts the @@ -74903,6 +81918,14 @@ </summary> </histogram> +<histogram name="Setup.Install.AddAppContainerAce" enum="Boolean"> + <owner>forshaw@chromium.org</owner> + <summary> + True if the the installer successfully added AppContainer ACEs to the + application directory during installation and updating. + </summary> +</histogram> + <histogram name="Setup.Install.ApplyArchivePatchTime" units="ms"> <owner>grt@chromium.org</owner> <summary> @@ -75334,6 +82357,13 @@ </summary> </histogram> +<histogram name="Signin.AndroidPopulateAccountCacheWaitingTime" units="ms"> + <owner>bsazonov@chromium.org</owner> + <summary> + The time UI thread spent waiting for the list of accounts to be populated. + </summary> +</histogram> + <histogram name="Signin.AndroidSigninPromoAction" enum="AndroidSigninPromoAction"> <obsolete> @@ -75345,6 +82375,16 @@ <summary>Track how a user interfacts with the android signin promo.</summary> </histogram> +<histogram name="Signin.AuthenticatedLaunchUserEvent" + enum="AuthenticatedLaunchUserEvent"> + <owner>zmin@chromium.org</owner> + <summary> + Records the UI event when user clicks a locked profile on UserManager. + Please note that if the local reauth failed, UserManager might show Gaia + Reauth dialog. + </summary> +</histogram> + <histogram name="Signin.AuthError" enum="GoogleServiceAuthError"> <owner>mlerman@chromium.org</owner> <summary> @@ -75353,6 +82393,17 @@ </summary> </histogram> +<histogram name="Signin.ChromePrimaryAccountStateOnWebSignout" + enum="ChromePrimaryAccountStateInGaiaCookies"> + <owner>droger@chromium.org</owner> + <summary> + Logs the state of the Chrome account when the user signs out on the web. + This assumes that a logout of the web is always a complete logout of all the + web accounts (e.g. single session signout is not supported). TODO(droger): + make this histogram obsolete when Dice is launched. + </summary> +</histogram> + <histogram name="Signin.CookieJar.ChromeAccountRelation" enum="AccountRelation"> <owner>skym@chromium.org</owner> <summary> @@ -75381,6 +82432,24 @@ <summary>The total number of accounts in the cookie jar.</summary> </histogram> +<histogram name="Signin.DiceEnabledForProfile" enum="Boolean"> + <obsolete> + Replaced by Signin.DiceMigrationStatus. Does not have any meaningful + information. + </obsolete> + <owner>droger@chromium.org</owner> + <summary> + Whether Dice is enabled for the current profile, recorded at startup. + </summary> +</histogram> + +<histogram name="Signin.DiceMigrationStatus" enum="SigninDiceMigrationStatus"> + <owner>droger@chromium.org</owner> + <summary> + The Dice migration status, recorded at startup for each profile. + </summary> +</histogram> + <histogram name="Signin.DiceResponseHeader" enum="SigninDiceResponseHeader"> <owner>droger@chromium.org</owner> <summary>Records Dice responses (signin and signout).</summary> @@ -75408,6 +82477,25 @@ </summary> </histogram> +<histogram name="Signin.ForceSigninVerificationRequest" enum="BooleanRequested"> + <owner>zmin@chromium.org</owner> + <summary> + The number profile load events that needs a force-sign-in verification + request. It's recorded when profile is loaded with an authentication token + and force-sign-in policy is enabled. + </summary> +</histogram> + +<histogram name="Signin.ForceSigninVerificationTime" units="ms"> + <owner>zmin@chromium.org</owner> + <summary> + Elapsed time of the force-sign-in verfication if it's finished. It includes + total network delay, retry delay and wait time due to no connection. The + verfication will not be recorded if it's not finished before profile is + signed out or removed from memory. + </summary> +</histogram> + <histogram name="Signin.InvestigatedScenario" enum="SigninInvestigatedScenario"> <owner>skym@chromium.org</owner> <summary> @@ -75537,6 +82625,9 @@ </histogram> <histogram name="Signin.RefreshTokenAnnotationRequest" enum="BooleanSuccess"> + <obsolete> + Removed this histogram along with the code that was logging it. + </obsolete> <owner>pavely@chromium.org</owner> <summary> Track when chrome successfully sends RefreshTokenAnnotationRequest. @@ -75679,7 +82770,7 @@ </histogram> <histogram base="true" name="SimpleCache.CheckCRCResult" enum="CheckCRCResult"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> Whether or not the CRC was checked at the moment when the last reference to a read-only entry stream is closed. @@ -75687,7 +82778,7 @@ </histogram> <histogram base="true" name="SimpleCache.CreationToIndex" units="ms"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> The time from the creation of the simple cache backend until the index has been loaded from disk. @@ -75695,7 +82786,7 @@ </histogram> <histogram base="true" name="SimpleCache.CreationToIndexFail" units="ms"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> The time from the creation of the simple cache backend until the index fails to load. @@ -75718,6 +82809,14 @@ </summary> </histogram> +<histogram base="true" name="SimpleCache.DiskDoomLatency" units="ms"> + <owner>morlovich@chromium.org</owner> + <summary> + The time to remove the cache entry on disk. Includes only individually + doomed entries, not entries bulk-erased during eviction. + </summary> +</histogram> + <histogram base="true" name="SimpleCache.DiskOpenLatency" units="ms"> <owner>rdsmith@chromium.org</owner> <summary> @@ -75726,6 +82825,23 @@ </summary> </histogram> +<histogram base="true" name="SimpleCache.DiskOpenStream2NonTinyLatency" + units="ms"> + <owner>morlovich@chromium.org</owner> + <summary> + The time to open the stream 2 file successfully on disk cache entry open + with known key, when the size of payload is greater than 32 bytes. + </summary> +</histogram> + +<histogram base="true" name="SimpleCache.DiskOpenStream2TinyLatency" units="ms"> + <owner>morlovich@chromium.org</owner> + <summary> + The time to open the stream 2 file successfully on disk cache entry open + with known key, when the size of payload is 32 bytes or less. + </summary> +</histogram> + <histogram base="true" name="SimpleCache.DiskWriteLatency" units="ms"> <owner>morlovich@chromium.org</owner> <summary> @@ -75736,7 +82852,13 @@ <histogram base="true" name="SimpleCache.EntryCreatedAndStream2Omitted" enum="SimpleCache.EntryCreatedAndStream2Omitted"> - <owner>gavinp@chromium.org</owner> + <obsolete> + Removed 2018-02. Not creating stream 2 on CreateEntry entries is indeed a + good idea, since stream 2 writes are done on things opened with OpenEntry. + (Which also means this metric wasn't good at evaluating the prevalence of + stream 2 in general). + </obsolete> + <owner>morlovich@chromium.org</owner> <summary> Whether, upon creation of a new cache entry, the file for stream 2 was omitted since that stream was empty. @@ -75745,7 +82867,7 @@ <histogram base="true" name="SimpleCache.EntryCreationResult" enum="BooleanSuccess"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> For entry creation operations that were sent to the disk, the result of creation. @@ -75753,13 +82875,13 @@ </histogram> <histogram base="true" name="SimpleCache.EntryCreationTime" units="ms"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary>The time, in ms, spent creating a new entry on disk.</summary> </histogram> <histogram base="true" name="SimpleCache.EntryOpenedAndStream2Removed" enum="SimpleCache.EntryOpenedAndStream2Removed"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> Whether, upon opening of an existing cache entry, stream 2 was empty and the file for that stream was therefore removed. @@ -75767,7 +82889,7 @@ </histogram> <histogram base="true" name="SimpleCache.EntryOperationsPending"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> At the time that operations are run, the number of pending operations on a particular entry. @@ -75778,17 +82900,17 @@ <obsolete> Deprecated 2013 in favour of SimpleCache.Eviction.CacheSizeOnStart2 </obsolete> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary>The size of the cache at the beginning of an eviction.</summary> </histogram> <histogram base="true" name="SimpleCache.Eviction.CacheSizeOnStart2" units="KB"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary>The size of the cache at the beginning of an eviction.</summary> </histogram> <histogram base="true" name="SimpleCache.Eviction.EntryCount"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary>The number of entries to be erased in an eviction.</summary> </histogram> @@ -75796,7 +82918,7 @@ <obsolete> Deprecated 2013 in favour of SimpleCache.Eviction.MaxCacheSizeOnStart2 </obsolete> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> The maximum allowed size of the cache at the beginning of an eviction. </summary> @@ -75804,14 +82926,14 @@ <histogram base="true" name="SimpleCache.Eviction.MaxCacheSizeOnStart2" units="KB"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> The maximum allowed size of the cache at the beginning of an eviction. </summary> </histogram> <histogram base="true" name="SimpleCache.Eviction.Result" enum="BooleanSuccess"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary>The result of an eviction.</summary> </histogram> @@ -75819,12 +82941,12 @@ <obsolete> Deprecated 2013 in favour of SimpleCache.Eviction.SizeOfEvicted2 </obsolete> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary>The number of bytes to be erased in an eviction.</summary> </histogram> <histogram base="true" name="SimpleCache.Eviction.SizeOfEvicted2" units="KB"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary>The amount of memory freed in an eviction.</summary> </histogram> @@ -75832,28 +82954,38 @@ <obsolete> Deprecated 2013 in favour of SimpleCache.Eviction.SizeWhenDone2 </obsolete> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary>The size of the cache after running an eviction.</summary> </histogram> <histogram base="true" name="SimpleCache.Eviction.SizeWhenDone2" units="KB"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary>The size of the cache after running an eviction.</summary> </histogram> <histogram base="true" name="SimpleCache.Eviction.TimeToDone" units="ms"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary>Time spent completing an eviction.</summary> </histogram> <histogram base="true" name="SimpleCache.Eviction.TimeToSelectEntries" units="ms"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary>Time spent selecting entries for eviction.</summary> </histogram> -<histogram base="true" name="SimpleCache.FileDescriptorLimitHard"> - <owner>gavinp@chromium.org</owner> +<histogram name="SimpleCache.FileDescriptorLimiterAction" + enum="SimpleCache.FileDescriptorLimiterOp"> + <owner>morlovich@chromium.org</owner> + <summary> + This even is emitted when SimpleCache is forced to either close some files + due to being over FD limit, or reopen files it had to close due to such + limit earlier. + </summary> +</histogram> + +<histogram name="SimpleCache.FileDescriptorLimitHard" units="file descriptors"> + <owner>morlovich@chromium.org</owner> <summary> The maximum limit of how many file descriptors a process can open. Emitted each time the browser is launched, if the limit could be retrieved. (This @@ -75861,8 +82993,8 @@ </summary> </histogram> -<histogram base="true" name="SimpleCache.FileDescriptorLimitSoft"> - <owner>gavinp@chromium.org</owner> +<histogram name="SimpleCache.FileDescriptorLimitSoft" units="file descriptors"> + <owner>morlovich@chromium.org</owner> <summary> The current limit of how many file descriptors a process can open. Emitted each time the browser is launched, if the limit could be retrieved. (We can @@ -75870,9 +83002,9 @@ </summary> </histogram> -<histogram base="true" name="SimpleCache.FileDescriptorLimitStatus" +<histogram name="SimpleCache.FileDescriptorLimitStatus" enum="SimpleCache.FileDescriptorLimitStatus"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> The result of trying to get the file descriptor limit. Emitted each time the browser is launched. @@ -75880,7 +83012,7 @@ </histogram> <histogram base="true" name="SimpleCache.GlobalOpenEntryCount"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> The number of open entries across all caches backed by the Simple Cache. An entry is opened whenever a caller asks to open it to read or write cache @@ -75890,7 +83022,7 @@ </histogram> <histogram base="true" name="SimpleCache.HeaderSize" units="bytes"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> The size of the header stream of a Simple Cache entry, emitted every time the headers are written or rewritten. @@ -75899,7 +83031,7 @@ <histogram base="true" name="SimpleCache.HeaderSizeChange" enum="SimpleCacheHeaderSizeChange"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> How the header size has changed in a Simple Cache entry, emitted every time a write operation occurs on the header stream. (This includes the initial @@ -75909,7 +83041,7 @@ <histogram base="true" name="SimpleCache.HeaderSizeDecreaseAbsolute" units="bytes"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> The absolute size decrease of the header stream of a Simple Cache entry, emitted every time the headers are rewritten with a smaller size. @@ -75918,7 +83050,7 @@ <histogram base="true" name="SimpleCache.HeaderSizeDecreasePercentage" units="%"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> The relative size decrease of the header stream of a Simple Cache entry, emitted every time the headers are rewritten with a smaller size. @@ -75927,7 +83059,7 @@ <histogram base="true" name="SimpleCache.HeaderSizeIncreaseAbsolute" units="bytes"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> The absolute size increase of the header stream of a Simple Cache entry, emitted every time the headers are rewritten with a larger size. @@ -75936,7 +83068,7 @@ <histogram base="true" name="SimpleCache.HeaderSizeIncreasePercentage" units="%"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> The relative size increase of the header stream of a Simple Cache entry, emitted every time the headers are rewritten with a larger size. @@ -75944,22 +83076,22 @@ </histogram> <histogram base="true" name="SimpleCache.IndexCorrupt" enum="BooleanCorrupt"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary>For each index load, whether the index file was corrupt.</summary> </histogram> <histogram base="true" name="SimpleCache.IndexCreatedEntryCount"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary>The number of entries in a newly created index file.</summary> </histogram> <histogram base="true" name="SimpleCache.IndexEntriesLoaded"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary>Number of entries loaded from the index file on start.</summary> </histogram> <histogram base="true" name="SimpleCache.IndexEntriesRestored"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> Number of entries restored from disk when there was no index or the index was corrupted. @@ -75968,14 +83100,14 @@ <histogram base="true" name="SimpleCache.IndexFileStateOnLoad" enum="SimpleIndexState"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> The state the index file is at when an attempt is made to load from it. </summary> </histogram> <histogram base="true" name="SimpleCache.IndexInitializationWaiters"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> At the time of index initialization, the number of enqueued jobs awaiting index initialization. @@ -75984,12 +83116,12 @@ <histogram base="true" name="SimpleCache.IndexInitializeMethod" enum="SimpleCacheIndexInitializeMethod"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary>The method used to initialize the simple cache index.</summary> </histogram> <histogram base="true" name="SimpleCache.IndexLoadTime" units="ms"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> Time (as measured on the worker pool) spent loading the index file. </summary> @@ -76004,12 +83136,12 @@ </histogram> <histogram base="true" name="SimpleCache.IndexNumEntriesOnWrite"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary>The number of entries written to the index on a flush.</summary> </histogram> <histogram base="true" name="SimpleCache.IndexRestoreTime" units="ms"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> Time (as measured on the worker pool) spent restoring the index file by iterating directory entries. @@ -76020,13 +83152,13 @@ <obsolete> Deprecated 07/2013, and replaced by IndexFileStateOnLoad. </obsolete> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary>For each index load, whether the index file was stale.</summary> </histogram> <histogram base="true" name="SimpleCache.IndexWriteInterval.Background" units="ms"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> The interval between index saves, for apps in the background. </summary> @@ -76034,7 +83166,7 @@ <histogram base="true" name="SimpleCache.IndexWriteInterval.Foreground" units="ms"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> The interval between index saves, for apps in the foreground. </summary> @@ -76042,7 +83174,7 @@ <histogram base="true" name="SimpleCache.IndexWriteReason" enum="SimpleCacheIndexWriteReason"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> The reason an index was written to disk. Recorded every time an index is saved. @@ -76051,7 +83183,7 @@ <histogram base="true" name="SimpleCache.IndexWriteReasonAtLoad" enum="SimpleCacheIndexWriteReason"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> Recorded immediately after loading a fresh index (INDEX_STATE_FRESH or INDEX_STATE_FRESH_CONCURRENT_UPDATES), the reason the loaded index was @@ -76065,7 +83197,7 @@ SimpleCache.SimpleIndexWriteToDiskTime.Background and SimpleCache.SimpleIndexWriteToDiskTime.Foreground. </obsolete> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> The amount of time spend writing the index file to disk, measured starting at the beginning of the write on the callback thread, and calculated using @@ -76075,7 +83207,7 @@ <histogram base="true" name="SimpleCache.IndexWriteToDiskTime.Background" units="ms"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> The amount of time spend writing the index file to disk, for apps in the background, measured starting at the beginning of the write on the callback @@ -76085,7 +83217,7 @@ <histogram base="true" name="SimpleCache.IndexWriteToDiskTime.Foreground" units="ms"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> The amount of time spend writing the index file to disk, for apps in the foreground, measured starting at the beginning of the write on the callback @@ -76099,14 +83231,17 @@ itself, so this result is now reported in the SimpleCache.x.SyncOpenResult histograms. </obsolete> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> For each call to OpenEntry, whether the key on disk matched the request key. </summary> </histogram> <histogram base="true" name="SimpleCache.LastClusterLossPercent" units="%"> - <owner>gavinp@chromium.org</owner> + <obsolete> + Deprecated 2018-01; not viewed as actionable. + </obsolete> + <owner>morlovich@chromium.org</owner> <summary> For each file in the Simple Cache, the percentage of disk space used by the cluster loss, the unused disk space in the last 4096 byte cluster of the @@ -76115,7 +83250,10 @@ </histogram> <histogram base="true" name="SimpleCache.LastClusterSize" units="bytes"> - <owner>gavinp@chromium.org</owner> + <obsolete> + Deprecated 2018-01; not viewed as actionable. + </obsolete> + <owner>morlovich@chromium.org</owner> <summary> For each file in the Simple Cache, the number of bytes in the last 4096 byte cluster when the entry is saved to disk. @@ -76130,9 +83268,18 @@ </summary> </histogram> +<histogram base="true" name="SimpleCache.NumOpsBlockedByPendingDoom" + units="Ops"> + <owner>morlovich@chromium.org</owner> + <summary> + Number of operations that were queued behind a particular doom operation + (with a mass doom counting as a single operation). + </summary> +</histogram> + <histogram base="true" name="SimpleCache.OpenEntryIndexState" enum="SimpleCacheOpenEntryIndexState"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> At the time that an entry is opened, the state of that entry in the index. </summary> @@ -76163,9 +83310,17 @@ </summary> </histogram> +<histogram base="true" name="SimpleCache.QueueLatency.PendingDoom" units="ms"> + <owner>morlovich@chromium.org</owner> + <summary> + Delay between when an operation is deferred due to a pending doom for its + key, and when it can resume execution. + </summary> +</histogram> + <histogram base="true" name="SimpleCache.ReadIsParallelizable" enum="SimpleCacheReadParallelizable"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> For each Read operation, whether it could have been issued in parallel of a previous Read operation. @@ -76174,7 +83329,7 @@ <histogram base="true" name="SimpleCache.ReadResult" enum="SimpleCacheReadResult"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary>The outcome of Entry::ReadData in the simple cache.</summary> </histogram> @@ -76190,7 +83345,7 @@ <histogram base="true" name="SimpleCache.StaleIndexExtraEntryCount" units="entries"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> Count of the number of entries recorded in the index, but not actually present in the cache. Recorded each time a stale index is found and a @@ -76200,7 +83355,7 @@ <histogram base="true" name="SimpleCache.StaleIndexMissedEntryCount" units="entries"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> Count of the number of entries present in a cache, but not recorded in the index. Recorded each time a stale index is found and a directory rescan is @@ -76210,7 +83365,7 @@ <histogram base="true" name="SimpleCache.StaleIndexQuality" enum="SimpleCacheStaleIndexQuality"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> The quality of a "stale" index compared to a full directory rescan. Recorded immediately after every directory scan for stale indexes. @@ -76219,7 +83374,7 @@ <histogram base="true" name="SimpleCache.SyncCheckEOFHasCrc" enum="BooleanHasCrc"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> For each EOFRecord found with a valid magic number, indicates if the record also contains a CRC. @@ -76228,7 +83383,7 @@ <histogram base="true" name="SimpleCache.SyncCheckEOFResult" enum="SimpleCacheSyncCheckEOFResult"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> The result, at the synchronous layer, of checking the EOF record of a cache entry. @@ -76237,7 +83392,7 @@ <histogram base="true" name="SimpleCache.SyncCloseResult" enum="SimpleCacheSyncCloseResult"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> The result, at the synchronous layer, of closing a cache entry. </summary> @@ -76245,7 +83400,7 @@ <histogram base="true" name="SimpleCache.SyncCreatePlatformFileError" enum="PlatformFileError"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> The platform error reported when attempting to create a new cache entry at the synchronous layer. @@ -76254,7 +83409,7 @@ <histogram base="true" name="SimpleCache.SyncCreateResult" enum="SimpleCacheSyncCreateResult"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> The result, at the synchronous layer, reported when attempting to create a new cache entry. @@ -76263,7 +83418,7 @@ <histogram base="true" name="SimpleCache.SyncKeySHA256Result" enum="SimpleCacheSyncSHA256Result"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> The result of the the key SHA256 check done when opening stream 0 for each entry. @@ -76279,7 +83434,7 @@ </histogram> <histogram base="true" name="SimpleCache.SyncOpenEntryAge" units="hours"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> The age of the entry (time since last modified), when opened at the synchronous layer. @@ -76288,7 +83443,7 @@ <histogram base="true" name="SimpleCache.SyncOpenPlatformFileError" enum="PlatformFileError"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> The platform error reported when attempting to create a new cache entry at the synchronous layer. @@ -76297,7 +83452,7 @@ <histogram base="true" name="SimpleCache.SyncOpenResult" enum="SimpleCacheSyncOpenResult"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> The result, at the synchronous layer, reported when attempting to open a new cache entry. @@ -76306,7 +83461,7 @@ <histogram base="true" name="SimpleCache.SyncWriteResult" enum="SimpleCacheSyncWriteResult"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> The result, at the synchronous layer, of writing to a cache entry. </summary> @@ -76314,7 +83469,7 @@ <histogram base="true" name="SimpleCache.WriteDependencyType" enum="SimpleCacheWriteDependencyType"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary> Shows whether a write operation depends on the previous operation in queue particularly in the aspect of its possibility to run in parallel. @@ -76326,13 +83481,13 @@ Replaced 2013/09/03 by WriteResult2, which adds "fast empty return", which previously showed up as "success". </obsolete> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary>The outcome of Entry::WriteData in the simple cache.</summary> </histogram> <histogram base="true" name="SimpleCache.WriteResult2" enum="SimpleCacheWriteResult"> - <owner>gavinp@chromium.org</owner> + <owner>morlovich@chromium.org</owner> <summary>The outcome of Entry::WriteData in the simple cache.</summary> </histogram> @@ -76607,6 +83762,24 @@ </summary> </histogram> +<histogram name="SiteIsolation.Flags.IsolateOrigins" enum="BooleanEnabled"> + <owner>alexmos@chromium.org</owner> + <summary> + True if the --isolate-origins mode was enabled from the command line, + about:flags, or enterprise policy. Recorded on browser startup and then + once every 24 hours. + </summary> +</histogram> + +<histogram name="SiteIsolation.Flags.SitePerProcess" enum="BooleanEnabled"> + <owner>alexmos@chromium.org</owner> + <summary> + True if the --site-per-process mode was enabled from the command line, + about:flags, or enterprise policy. Recorded on browser startup and then + once every 24 hours. + </summary> +</histogram> + <histogram name="SiteIsolation.IsolateAllSitesProcessCountEstimate"> <owner>creis@chromium.org</owner> <summary> @@ -76740,6 +83913,15 @@ </summary> </histogram> +<histogram name="SiteIsolation.IsolateOrigins.Size" units="origins"> + <owner>alexmos@chromium.org</owner> + <summary> + The number of currently enabled isolated origins. This includes origins + specified via the --isolate-origins command-line flag as well as those + configured via enterprise policy. Recorded on browser startup. + </summary> +</histogram> + <histogram name="SiteIsolation.OutOfProcessIframes"> <owner>nasko@chromium.org</owner> <summary> @@ -76781,6 +83963,72 @@ </summary> </histogram> +<histogram name="SiteIsolation.XSD.Browser.Action" + enum="SiteIsolationResponseAction"> + <owner>creis@chromium.org</owner> + <summary> + Various actions related to cross-site document blocking in the browser + process, indicating whether the response was blocked from the renderer. + Recorded as the response is processed in the network stack. + </summary> +</histogram> + +<histogram name="SiteIsolation.XSD.Browser.Blocked" enum="ContentResourceType2"> + <owner>creis@chromium.org</owner> + <summary> + The total count of responses that were blocked by the cross-site document + blocking logic in the browser process. Sampled with a resource type (0-17) + when the response is blocked; up to 1024 bytes of the response are + considered. This is also recorded with a suffix indicating the MIME type + category. + </summary> +</histogram> + +<histogram + name="SiteIsolation.XSD.Browser.Blocked.ContentLength.ValueIfAvailable" + units="bytes"> + <owner>creis@chromium.org</owner> + <summary> + For each responses blocked by the cross-site document blocking logic in the + browser process, logs network::ResourceResponseInfo::content_length of the + response (but only if the content length value was available - if the value + was not -1). + </summary> +</histogram> + +<histogram name="SiteIsolation.XSD.Browser.Blocked.ContentLength.WasAvailable" + enum="BooleanAvailable"> + <owner>creis@chromium.org</owner> + <summary> + For each responses blocked by the cross-site document blocking logic in the + browser process, logs whether network::ResourceResponseInfo::content_length + was available (i.e. value was 0 or greated) or not available (i.e. value was + equal to -1) if the value was available (i.e. the value was not -1). + </summary> +</histogram> + +<histogram name="SiteIsolation.XSD.Browser.BlockedForParserBreaker" + enum="ContentResourceType2"> + <owner>creis@chromium.org</owner> + <summary> + The total count of responses that were blocked by the cross-site document + blocking logic in the browser process, due to the presence of a Javascript + parser-breaker pattern (like "for(;;);", or ")]}'", or a + non-empty JSON dictionary like "{\"a\":". Sampled with a + resource type (0-17) when the response is blocked; up to 1024 bytes of the + response are considered. + </summary> +</histogram> + +<histogram name="SiteIsolation.XSD.Browser.BytesReadForSniffing" units="bytes"> + <owner>creis@chromium.org</owner> + <summary> + The number of bytes of the network response buffered for sniffing purposes, + when attempting to sniff the response to determine if it should be blocked + as a cross-site document. Recorded after sniffing is attempted. + </summary> +</histogram> + <histogram name="SiteIsolation.XSD.DataLength" units="byte"> <owner>creis@chromium.org</owner> <summary> @@ -77357,6 +84605,10 @@ <histogram name="SoftwareReporter.Cleaner.DownloadHttpResponseCode" enum="HttpResponseCode"> + <obsolete> + Deprecated as of 09/2017. Replaced with + SoftwareReporter.Cleaner.DownloadStatusErrorCode. + </obsolete> <owner>ftirelo@chromium.org</owner> <summary> The HTTP response code for the Chrome Cleanup Tool download request. @@ -77372,6 +84624,15 @@ </summary> </histogram> +<histogram name="SoftwareReporter.Cleaner.DownloadStatusErrorCode" + enum="CombinedHttpResponseAndNetErrorCode"> + <owner>ftirelo@chromium.org</owner> + <summary> + The HTTP response or net error code when trying to download the Chrome + Cleanup Tool. + </summary> +</histogram> + <histogram name="SoftwareReporter.Cleaner.HasCompleted" enum="SRTCompleted"> <owner>mad@chromium.org</owner> <summary> @@ -77389,6 +84650,18 @@ </summary> </histogram> +<histogram name="SoftwareReporter.Cleaner.NumberOfDownloadAttempts" + units="counts"> + <obsolete> + Deprecated on 2018-01-15. + </obsolete> + <owner>ftirelo@chromium.org</owner> + <summary> + The number of attempts to download the Chrome Cleanup tool until it either + succeeds or fails. + </summary> +</histogram> + <histogram name="SoftwareReporter.Cleaner.RebootResponse" enum="Boolean"> <owner>ftirelo@chromium.org</owner> <summary> @@ -77414,12 +84687,30 @@ </summary> </histogram> +<histogram name="SoftwareReporter.Cleaner.SettingsPageActiveOnRebootRequired" + enum="SoftwareReporterCleanerSettingsPageActiveOnRebootRequired"> + <owner>ftirelo@chromium.org</owner> + <summary> + Indicates if the Settings page was the active tab once a cleanup finished + with reboot required. + </summary> +</histogram> + +<histogram name="SoftwareReporter.Cleaner.TimeToCompleteDownload" units="ms"> + <owner>ftirelo@chromium.org</owner> + <summary> + The time between the first attempt to download the Chrome Cleanup tool and a + successful download or the last unsuccessful attempt to download without + retrying. + </summary> +</histogram> + <histogram name="SoftwareReporter.Cleaner.Version"> <owner>mad@chromium.org</owner> <summary>The build version of the software reporter cleaner tool.</summary> </histogram> -<histogram name="SoftwareReporter.CleanerLogsAcceptance" enum="Boolean"> +<histogram name="SoftwareReporter.CleanerLogsAcceptance" enum="BooleanAccepted"> <owner>ftirelo@chromium.org</owner> <summary> Whether the user accepted to upload logs from Chrome Cleanup Tool. This is @@ -77551,6 +84842,24 @@ </summary> </histogram> +<histogram name="SoftwareReporter.OnDemandUpdateRequired" + enum="BooleanRequired"> + <owner>ftirelo@chromium.org</owner> + <summary> + Whether an on-demand update of the Software Reporter component was needed + for a user-initiated cleanup. + </summary> +</histogram> + +<histogram name="SoftwareReporter.OnDemandUpdateSucceeded" + enum="BooleanSuccess"> + <owner>ftirelo@chromium.org</owner> + <summary> + Whether an on-demand update of the Software Reporter component succeeded, + when needed for a user-initiated cleanup. + </summary> +</histogram> + <histogram name="SoftwareReporter.PostCleanupSettingsReset" units="counts"> <owner>ftirelo@chromium.org</owner> <summary> @@ -77598,10 +84907,29 @@ </histogram> <histogram name="SoftwareReporter.PromptUsage" enum="SRTPromptUsage"> + <obsolete> + Deprecated as of 2017-11-01. Replaced with + SoftwareReporter.PromptDialogResponse. + </obsolete> <owner>mad@chromium.org</owner> <summary>Usage of the Software Removal Tool (SRT) Prompt.</summary> </histogram> +<histogram name="SoftwareReporter.ReporterSequenceResult" + enum="SoftwareReporterSequenceResult"> + <owner>ftirelo@chromium.org</owner> + <summary>Indicates the result of a reporter sequence once it ends.</summary> +</histogram> + +<histogram name="SoftwareReporter.ReporterSequenceType" + enum="SoftwareReporterSequenceType"> + <owner>ftirelo@chromium.org</owner> + <summary> + Indicates the type of a reporter sequence run on the user system. Logged + when the sequence is scheduled to start. + </summary> +</histogram> + <histogram name="SoftwareReporter.RunningTime" units="ms"> <owner>alito@chromium.org</owner> <summary> @@ -77628,6 +84956,15 @@ </summary> </histogram> +<histogram name="SoftwareReporter.ScannerLogsAcceptance" enum="BooleanAccepted"> + <owner>ftirelo@chromium.org</owner> + <summary> + Whether the user accepted to upload scanner logs from Chrome Cleanup Tool. + This is logged when the user starts a scan for the Settings page and is only + logged for user-initiated cleanups. + </summary> +</histogram> + <histogram name="SoftwareReporter.Step" enum="SwReporterStep"> <owner>mad@chromium.org</owner> <summary> @@ -77940,6 +85277,9 @@ </histogram> <histogram name="Sqlite.Vfs" units="bytes"> + <obsolete> + Removed 2018/02/06. + </obsolete> <owner>shess@chromium.org</owner> <summary> Buffer sizes passed to browser-process SQLite VFS functions. @@ -77947,6 +85287,9 @@ </histogram> <histogram name="Sqlite.Vfs_Events" enum="SqliteVfsEvents"> + <obsolete> + Removed 2018/02/06. + </obsolete> <owner>shess@chromium.org</owner> <summary> I/O operations measured by browser-process SQLite VFS wrapper. @@ -77981,6 +85324,18 @@ </summary> </histogram> +<histogram name="SSL.CertificateErrorReportOutcome" + enum="CertificateReportOutcome"> + <owner>meacer@chromium.org</owner> + <summary> + Users can opt in to send reports of certificate validation errors to Google. + This records the outcome whenever Chrome sends such a report. + + Some certificate validation reports might not be received because proxies, + firewalls or other content filters might filter report uploads. + </summary> +</histogram> + <histogram name="SSL.ExpectCTReportFailure" enum="NetErrorCodes"> <obsolete> Deprecated as of 07/2016. Replaced with SSL.ExpectCTReportFailure2. @@ -78015,7 +85370,7 @@ </histogram> <histogram name="SSL.InsecureContent" enum="InsecureContentType"> - <owner>lgarron@chromium.org</owner> + <owner>estark@chromium.org</owner> <summary> Keeps track of various insecure content events, such as loading an HTTP script from an HTTPS page. @@ -78023,6 +85378,12 @@ </histogram> <histogram name="SSL.MarkHttpAsStatus" enum="MarkHttpAsStatus"> + <obsolete> + Deprecated December 2017 (M65). This information in this histogram can be + found in LoginCustomFlags (for users who have set a flag) or by filtering to + users with the MarkHttpAs feature enabled (for seeing the field trial + breakdown). + </obsolete> <owner>estark@chromium.org</owner> <owner>felt@chromium.org</owner> <summary> @@ -78045,6 +85406,28 @@ </summary> </histogram> +<histogram name="SSORecallPromo.AccountsAvailable"> + <owner>msarda@chromium.org</owner> + <summary> + Number of accounts available for Single Sign On with the current device, + recorded at the time the SSO Promo is shown. + </summary> +</histogram> + +<histogram name="SSORecallPromo.PromoAction" enum="SSOPromoUserAction"> + <owner>msarda@chromium.org</owner> + <summary> + Action the user takes when the Single Sign On promotion is shown. + </summary> +</histogram> + +<histogram name="SSORecallPromo.PromoSeenCount"> + <owner>msarda@chromium.org</owner> + <summary> + Number of times the promotion has been seen on the current device. + </summary> +</histogram> + <histogram name="Stability.Android.PendingMinidumpsOnStartup" units="minidumps"> <obsolete> Deprecated in M60. Roughly 50% of Chrome startups that had *any* pending @@ -78153,7 +85536,8 @@ Records the exit code of the browser process (on Windows) from the previous launch. On crash, the exit code will indicate the exception code of the crash. This is emitted in stability data with the first report on a - subsequent launch. + subsequent launch. Note: Due to https://crbug.com/805754, the enum labels + for RESULT_CODE_* are off by 1 for M56 and earlier. </summary> </histogram> @@ -78184,6 +85568,14 @@ </summary> </histogram> +<histogram name="Stability.Internals.SystemCrashCount" units="crashes"> + <owner>siggi@chromium.org</owner> + <summary> + Number of times a browser crash was detected, where the browser was last + known to be alive in a Windows system session that terminated abnormally. + </summary> +</histogram> + <histogram name="Stability.Internals.VersionMismatchCount" units="counts"> <owner>manzagop@chromium.org</owner> <summary> @@ -78210,6 +85602,17 @@ </summary> </histogram> +<histogram name="Stability.RendererUnresponsiveBeforeTermination" + enum="BooleanUnresponsive"> + <owner>dtapuska@chromium.org</owner> + <summary> + If the renderer is considered unresponsive from the browser's perspective + before the process is terminated. This metric is being used to figure out + crash reports that have all idle threads and perhaps the process is being + terminated when it shouldn't be. crbug.com/615090. + </summary> +</histogram> + <histogram name="Stars.Goog_Related" units="%"> <owner>yefim@chromium.org</owner> <summary> @@ -78279,6 +85682,33 @@ </summary> </histogram> +<histogram name="Startup.Android.Experimental.Cold.TimeToFirstContentfulPaint" + units="ms"> + <owner>pasko@chromium.org</owner> + <owner>alexilin@chromium.org</owner> + <summary> + Android: The time from the earliest entry point in the browser process to + the first contentful paint of the first loaded page. It's not recorded when + the first loaded page is non http(s) page like a chrome error page, a new + tab page, a blank page. It's also not recorded if the application wasn't in + the foreground since the start till the end of event. + </summary> +</histogram> + +<histogram name="Startup.Android.Experimental.Cold.TimeToFirstNavigationCommit" + units="ms"> + <owner>pasko@chromium.org</owner> + <owner>alexilin@chromium.org</owner> + <summary> + Android: The time from the earliest entry point in the browser process to + the moment the first navigation is committed, i.e. when renderer gets the + first byte of the document. It's not recorded when the first loaded page is + non http(s) page like a chrome error page, a new tab page, a blank page. + It's also not recorded if the application wasn't in the foreground since the + start till the end of event. + </summary> +</histogram> + <histogram name="Startup.AppListFirstPaintColdStart" units="ms"> <owner>tapted@chromium.org</owner> <summary> @@ -78466,6 +85896,19 @@ </histogram> <histogram name="Startup.BrowserMessageLoopStartTimeFromMainEntry2" units="ms"> + <obsolete> + Deprecated 2018-01 in favor of + Startup.BrowserMessageLoopStartTimeFromMainEntry3 which does not involve a + conversion from Time to TimeTicks. + </obsolete> + <owner>fdoray@chromium.org</owner> + <owner>gab@chromium.org</owner> + <summary> + Time from main entry to the start of the main thread's message loop. + </summary> +</histogram> + +<histogram name="Startup.BrowserMessageLoopStartTimeFromMainEntry3" units="ms"> <owner>fdoray@chromium.org</owner> <owner>gab@chromium.org</owner> <summary> @@ -78526,6 +85969,22 @@ </summary> </histogram> +<histogram name="Startup.ColdStartWithExternalURLTime" units="ms"> + <owner>jif@chromium.org</owner> + <summary> + The duration of all initializations in a cold start triggered by an external + URL. + </summary> +</histogram> + +<histogram name="Startup.ColdStartWithoutExternalURLTime" units="ms"> + <owner>jif@chromium.org</owner> + <summary> + The duration of all initializations in a cold start not triggered by an + external URL. + </summary> +</histogram> + <histogram name="Startup.CreateFirstProfile" units="ms"> <owner>fdoray@chromium.org</owner> <summary> @@ -78618,6 +86077,10 @@ </histogram> <histogram name="Startup.FirstCommitNavigationTime3" units="ms"> + <obsolete> + Replaced with Startup.Android.Experimental.Cold.TimeToFirstNavigationCommit + on 11/2017 + </obsolete> <owner>pasko@chromium.org</owner> <owner>wnwen@chromium.org</owner> <summary> @@ -78878,6 +86341,21 @@ </summary> </histogram> +<histogram name="Startup.MobileSessionStartAction" + enum="MobileSessionStartAction"> + <owner>olivierrobin@chromium.org</owner> + <summary> + The action requested on the application startup when called from another app + or the OS. + </summary> +</histogram> + +<histogram name="Startup.MobileSessionStartFromApps" + enum="MobileSessionCallerApp"> + <owner>olivierrobin@chromium.org</owner> + <summary>The calling application (if any).</summary> +</histogram> + <histogram name="Startup.OSX.AwakeFromNib" units="ms"> <owner>erikchen@chromium.org</owner> <summary> @@ -79242,6 +86720,14 @@ </summary> </histogram> +<histogram name="Storage.Blob.GetBlobFromUUIDTime" units="ms"> + <owner>mek@chromium.org</owner> + <summary> + The amount of time taken to complete the synchronous + BlobRegistry.GetBlobFromUUID mojo call. + </summary> +</histogram> + <histogram name="Storage.Blob.InvalidReference" enum="RefcountOperation"> <owner>dmurph@chromium.org</owner> <summary> @@ -79729,6 +87215,19 @@ <histogram name="SubresourceFilter.IndexRuleset.Verify.WallDuration" units="microseconds"> + <obsolete> + Deprecated in favor of the Verify2 metric + </obsolete> + <owner>csharrison@chromium.org</owner> + <summary> + The total time it took to verify the indexed ruleset in the browser process. + Logged every time verification occurs, which usually occurs when the first + page with activation is navigated to. + </summary> +</histogram> + +<histogram name="SubresourceFilter.IndexRuleset.Verify2.WallDuration" + units="ms"> <owner>csharrison@chromium.org</owner> <summary> The total time it took to verify the indexed ruleset in the browser process. @@ -79783,6 +87282,12 @@ </histogram> <histogram name="SubresourceFilter.PageLoad.BlockedPopups" units="popups"> + <obsolete> + Metric is broken and will be replaced by + ContentSettings.Popups.StringBlocked.NumBlocked. This only logged values for + sites which are also activated for subresource filtering, when most sites + will probably only be marked for popup blocking. + </obsolete> <owner>csharrison@chromium.org</owner> <summary> Records the number of popups blocked per page load due to subresource filter @@ -79938,6 +87443,16 @@ </summary> </histogram> +<histogram name="SubresourceFilter.SafeBrowsing.CheckDispatchTime" + units="microseconds"> + <owner>csharrison@chromium.org</owner> + <summary> + The microseconds it took to dispatch the Safe Browsing check. This includes + IPC descheduling delays to communicate with SafetyNet on Android, and + synchronous db checks on desktop. + </summary> +</histogram> + <histogram name="SubresourceFilter.SafeBrowsing.CheckTime" units="ms"> <owner>csharrison@chromium.org</owner> <summary> @@ -79946,6 +87461,15 @@ </summary> </histogram> +<histogram name="SubresourceFilter.SafeBrowsing.TotalCheckTime" units="ms"> + <owner>csharrison@chromium.org</owner> + <summary> + The time an individual Safe Browsing URL check took before finishing, + including posting tasks to and from the IO thread. Measured on the UI + thread. + </summary> +</histogram> + <histogram name="SubresourceFilter.SubresourceLoad.Evaluation.CPUDuration" units="microseconds"> <owner>pkalinnikov@chromium.org</owner> @@ -81131,6 +88655,13 @@ <summary>Tracks the size of the local sync backend database file.</summary> </histogram> +<histogram name="Sync.Local.RequestTypeOnError" enum="SyncRequestType"> + <owner>skym@chromium.org</owner> + <summary> + Tracks the types of requests that caused errors inside of the local server. + </summary> +</histogram> + <histogram name="Sync.Local.RoamingProfileUnavailable" enum="BooleanError"> <owner>pastarmovj@chromium.org</owner> <summary> @@ -81688,6 +89219,15 @@ </summary> </histogram> +<histogram name="Sync.SesssionsDuplicateSyncId" units="count"> + <owner>skym@chromium.org</owner> + <summary> + https://crbug.com/639009, count of duplicate sync ids (tab node id) when any + are encountered. Likely caused from a persistence race between native tab + storage and sync db on Android. Should be trending to zero. + </summary> +</histogram> + <histogram name="Sync.Shutdown.BackendDestroyedTime" units="ms"> <owner>zea@chromium.org</owner> <summary> @@ -82284,6 +89824,14 @@ </summary> </histogram> +<histogram name="Tab.ExternalApplicationOpened" enum="ExternalLauncherOption"> + <owner>mrefaat@chromium.org</owner> + <summary> + Used on External App launcher Prompt to determine if the user clicked open + or cancel. + </summary> +</histogram> + <histogram name="Tab.FormActivityCountEvictedHistogram"> <obsolete> Deprecated as of 10/2016. @@ -82296,6 +89844,14 @@ </summary> </histogram> +<histogram name="Tab.HorizontalSizeClassUsed" enum="iOSSizeClassForReporting"> + <owner>lpromero@chromium.org</owner> + <summary> + Used on iOS 9+ iPad to report the usage of Compact or Regular horizontal + size class. This is logged at startup and on each size class change. + </summary> +</histogram> + <histogram name="Tab.LostTabAgeWhenSwitchedToForeground" units="ms"> <owner>pkotwicz@chromium.org</owner> <summary> @@ -82343,6 +89899,53 @@ </summary> </histogram> +<histogram name="Tab.OpenedPopup.PopupToCrossOriginRedirectTime" units="ms"> + <obsolete> + Deprecated in favor of Tab.TabUnder.PopupToTabUnderTime. + </obsolete> + <owner>csharrison@chromium.org</owner> + <summary> + Measures the time from when a tab opens a popup to when it navigates itself + cross-origin in the background. + </summary> +</histogram> + +<histogram name="Tab.OpenedPopup.VisibleTimeAfterCrossOriginRedirect" + units="ms"> + <obsolete> + Deprecated in favor of Tab.TabUnder.VisibleTime. + </obsolete> + <owner>csharrison@chromium.org</owner> + <summary> + Measures the total time a tab is visible after it navigates itself + cross-origin in the background. Measured at WebContents destruction. The tab + must have opened a popup (as classified by the popup blocker) before the + navigation. + </summary> +</histogram> + +<histogram name="Tab.PageLoadInHorizontalSizeClass" + enum="iOSSizeClassForReporting"> + <owner>lpromero@chromium.org</owner> + <summary> + Used on iOS 9+ iPad to report the usage of Compact or Regular horizontal + size class. Recorded on page load. + </summary> +</histogram> + +<histogram name="Tab.PageLoadInPortrait" enum="DeviceOrientation"> + <owner>jif@chromium.org</owner> + <summary>The orientation of the device. Recorded on page load.</summary> +</histogram> + +<histogram name="Tab.PageLoadsSinceLastSwitchToEvictedTab"> + <owner>lliabraa@chromium.org</owner> + <summary> + The number of page loads since the last switch to an evicted tab on Android. + This was sampled each time an evicted tab was reloaded. + </summary> +</histogram> + <histogram name="Tab.PerceivedRestoreTime" units="ms"> <owner>lliabraa@chromium.org</owner> <summary> @@ -82351,6 +89954,21 @@ </summary> </histogram> +<histogram name="Tab.PullDownGesture" enum="PullDownGestureAction"> + <owner>jbbegue@google.com</owner> + <summary> + Record the action executed when the user performs a pull down gesture. This + feature is currently iOS only. + </summary> + <details> + A pull down gesture is an action completed when the user scrolls past the + edge of the web page and continues scrolling in the same direction revealing + a specific UI on the header with multiple actions icons. The user can then + choose an action by scrolling left or right and lift the finger or cancel by + scrolling back up. This is currently an iOS specific feature. + </details> +</histogram> + <histogram name="Tab.Reactivation.Bookmarked" enum="Boolean"> <obsolete> Deprecated 11/2016. No longer useful after finding out that it has no effect @@ -82415,6 +90033,32 @@ </summary> </histogram> +<histogram name="Tab.RendererTermination.AliveRenderersCount" units="renderers"> + <owner>gchatz@chromium.org</owner> + <summary> + [iOS] A count of the number of alive renderers when a renderer termination + occurs. + </summary> +</histogram> + +<histogram name="Tab.RendererTermination.RecentlyAliveRenderersCount" + units="renderers"> + <owner>gchatz@chromium.org</owner> + <summary> + [iOS] The number of renderers which are either currently alive or recently + terminated at the time of a renderer termination. + </summary> +</histogram> + +<histogram name="Tab.RendererTermination.RecentlyReceivedMemoryWarning" + enum="BooleanWarningReceived"> + <owner>gchatz@chromium.org</owner> + <summary> + [iOS] Records whether a memory warning had recently been received before a + renderer termination. + </summary> +</histogram> + <histogram name="Tab.RestoreResult" enum="TabRestoreResult"> <owner>lliabraa@chromium.org</owner> <summary> @@ -82437,6 +90081,13 @@ </summary> </histogram> +<histogram name="Tab.StateAtRendererTermination" enum="TabForegroundState"> + <owner>stuartmorgan@chromium.org</owner> + <summary> + The state (foreground/background) of a tab when its renderer is terminated. + </summary> +</histogram> + <histogram name="Tab.StatusWhenDisplayed" enum="TabStatus"> <owner>lliabraa@chromium.org</owner> <summary> @@ -82513,6 +90164,56 @@ </summary> </histogram> +<histogram name="Tab.TabUnder.ClickThroughPosition" enum="ListItemPosition"> + <owner>csharrison@chromium.org</owner> + <summary> + The position of the URL in the framebust UI list (desktop only) when it is + clicked. Note that this UI surface is shared with the framebusting + intervention, so elements in the list could come from either features. This + metric will only be logged when a URL from the tab under intervention is + clicked. + </summary> +</histogram> + +<histogram name="Tab.TabUnder.PopupToTabUnderTime" units="ms"> + <owner>csharrison@chromium.org</owner> + <summary> + Measures the time from when a tab opens a popup to when it performs a + tab-under (i.e. navigates cross origin, in the background without a user + gesture). + </summary> +</histogram> + +<histogram name="Tab.TabUnder.VisibleTime" units="ms"> + <owner>csharrison@chromium.org</owner> + <summary> + Measures the total time a tab is visible after it navigates itself + cross-origin in the background, without a user gesture. The tab must have + opened a popup since the last user gesture in the tab. Measured at + WebContents destruction. The total visible time for the tab is the sum of + this metric and Tab.TabUnder.VisibleTimeBefore. + </summary> +</histogram> + +<histogram name="Tab.TabUnder.VisibleTimeBefore" units="ms"> + <owner>csharrison@chromium.org</owner> + <summary> + Measures the total time a tab is visible before it navigates itself + cross-origin in the background, without a user gesture. The tab must have + opened a popup since the last user gesture in the tab. Measured at + WebContents destruction. The total visible time for the tab is the sum of + this metric and Tab.TabUnder.VisibleTime. + </summary> +</histogram> + +<histogram name="Tab.TabUnderAction" enum="TabUnderAction"> + <owner>csharrison@chromium.org</owner> + <summary> + Various actions related to the tab under intervention, logged during main + frame navigation. + </summary> +</histogram> + <histogram name="Tab.TimeSinceActive" units="ms"> <obsolete> Deprecated as of 10/2016. @@ -82573,21 +90274,42 @@ </summary> </histogram> +<histogram name="Tab.VisibleTime" units="ms"> + <owner>csharrison@chromium.org</owner> + <summary> + Measures the total time a tab is visible. Measured at the WebContents layer + so this metric does not attempt to account for things like session restore. + Logged at WebContents destruction. + </summary> +</histogram> + +<histogram name="Tab.VisibleTimeAfterCrossOriginRedirect" units="ms"> + <obsolete> + This metric was deprecated in favor of just using Tab.TabUnder.VisibleTime + directly. Consider bringing it back if we care about visible time after a + suspicious redirect without an associated popup. + </obsolete> + <owner>csharrison@chromium.org</owner> + <summary> + Measures the total time a tab is visible after it navigates itself + cross-origin in the background. Measured at WebContents destruction. + </summary> +</histogram> + <histogram name="TabManager.BackgroundTabOpening.ForegroundTab.ExpectedTaskQueueingDuration" units="ms"> <owner>fmeawad@chromium.org</owner> <summary> - The expected queueing duration of tasks in a foreground tab when the browser - is in background tab opening session, which is the duration from the time - when the browser starts to open background tabs until the time when browser - has finished loading those tabs or paused loading due to memory pressure. A - new session starts when the browser resumes loading background tabs when - memory pressure returns to normal. The metric reflects the responsiveness of - a tab. A lower value means the tab will respond to inputs faster. This - metric is equal to RendererScheduler.ExpectedTaskQueueingDuration. It is - emitted once for all tasks in each 1000-ms window. The metric is not - recorded when the session overlaps with session restore. + The expected queueing duration of tasks in a foreground tab during a + background tab opening session (the duration of time from when the browser + starts to open background tabs until the time the browser has finished + loading those tabs or otherwise decided to stop loading them). The metric + reflects the responsiveness of a tab. A lower value means the tab will + respond to inputs faster. This metric is equivalent to + RendererScheduler.ExpectedTaskQueueingDuration. It is emitted once for all + tasks in each 1000-ms window. The metric is not recorded when the session + overlaps with session restore. </summary> </histogram> @@ -82595,17 +90317,15 @@ enum="TabLoadingState"> <owner>zhenw@chromium.org</owner> <summary> - The loading state of a tab at the time the user switches to it when the - browser is in background tab opening session, which is the duration from the - time when the browser starts to open background tabs until the time when - browser has finished loading those tabs or paused loading due to memory - pressure. A new session starts when the browser resumes loading background - tabs when memory pressure returns to normal. The metric is only recorded - when a tab is switched to from another tab within the same tabstrip. As a - result, the case when switching between different windows is not included, - either between two tabs in different browser windows, or when switching to a - different application and switching back to the browser. The metric is not - recorded when the session overlaps with session restore. + The loading state of a tab at the time the user switches to it during a + background tab opening session (the duration of time from when the browser + starts to open background tabs until the time the browser has finished + loading those tabs or otherwise decided to stop loading them). The metric is + only recorded when a tab is switched to from another tab within the same + tabstrip. As a result, the case when switching between different windows is + not included, either between two tabs in different browser windows, or when + switching to a different application and switching back to the browser. The + metric is not recorded when the session overlaps with session restore. </summary> </histogram> @@ -82613,13 +90333,11 @@ <owner>zhenw@chromium.org</owner> <summary> The max number of background tabs pending or loading when opening background - tabs. This is recorded at the end of background tab opening session, which - is defined as the duration from the time when the browser starts to open - background tabs until the time when browser has finished loading those tabs - or paused loading due to memory pressure. A new session starts when the - browser resumes loading background tabs when memory pressure returns to - normal. The metric is not recorded when the session overlaps with session - restore. + tabs. This is recorded at the end of the background tab opening session (the + duration of time from when the browser starts to open background tabs until + the time the browser has finished loading those tabs or otherwise decided to + stop loading them). The metric is not recorded when the session overlaps + with session restore. </summary> </histogram> @@ -82629,12 +90347,22 @@ <summary> The number of background tabs whose loading was triggered by TabManager automatically when opening background tabs. This is recorded at the end of - background tab opening session, which is defined as the duration from the - time when the browser starts to open background tabs until the time when - browser has finished loading those tabs or paused loading due to memory - pressure. A new session starts when the browser resumes loading background - tabs when memory pressure returns to normal. The metric is not recorded when - the session overlaps with session restore. + the background tab opening session (the duration of time from when the + browser starts to open background tabs until the time the browser has + finished loading those tabs or otherwise decided to stop loading them). The + metric is not recorded when the session overlaps with session restore. + </summary> +</histogram> + +<histogram name="TabManager.BackgroundTabOpening.TabLoadTimeout" + enum="BooleanTimedOut"> + <owner>zhenw@chromium.org</owner> + <summary> + Whether the tab load is timed out during background tab opening session (the + duration of time from when the browser starts to open background tabs until + the time the browser has finished loading those tabs or otherwise decided to + stop loading them). The metric is not recorded when the session overlaps + with session restore. </summary> </histogram> @@ -82645,13 +90373,11 @@ The number of background tabs whose loading was triggered by user action when opening background tabs. For example, when the user selects a background tab and brings it to foreground, that tab will start to load - immediately if not already loading. This is recorded at the end of - background tab opening session, which is defined as the duration from the - time when the browser starts to open background tabs until the time when - browser has finished loading those tabs or paused loading due to memory - pressure. A new session starts when the browser resumes loading background - tabs when memory pressure returns to normal. The metric is not recorded when - the session overlaps with session restore. + immediately if not already loading. This is recorded at the end of the + background tab opening session (the duration of time from when the browser + starts to open background tabs until the time the browser has finished + loading those tabs or otherwise decided to stop loading them). The metric is + not recorded when the session overlaps with session restore. </summary> </histogram> @@ -82659,13 +90385,12 @@ <owner>zhenw@chromium.org</owner> <summary> The max number of background tabs paused to load due to memory pressure when - opening background tabs. This is recorded at the end of background tab - opening session, which is defined as the duration from the time when the - browser starts to open background tabs until the time when browser has - finished loading those tabs or paused loading them all due to memory - pressure. A new session starts when the browser resumes loading background - tabs when memory pressure returns to normal. The metric is not recorded when - the session overlaps with session restore. + opening background tabs. This is recorded at the end of the background tab + opening session during a background tab opening session (the duration of + time from when the browser starts to open background tabs until the time the + browser has finished loading those tabs or otherwise decided to stop loading + them). The metric is not recorded when the session overlaps with session + restore. </summary> </histogram> @@ -82680,6 +90405,11 @@ </histogram> <histogram name="TabManager.Discarding.DiscardedEngagementScore"> + <obsolete> + Deprecated 11/2017. Analysis showed that MRU was as good as engagement score + to choose which tabs to discard. The new plan is to build a machine learning + model to choose which tabs to discard. + </obsolete> <owner>georgesak@chromium.org</owner> <summary> Site engagement score of a discarded tab. Recorded for each discard if the @@ -82741,6 +90471,11 @@ </histogram> <histogram name="TabManager.Discarding.ReloadedEngagementScore"> + <obsolete> + Deprecated 11/2017. Analysis showed that MRU was as good as engagement score + to choose which tabs to discard. The new plan is to build a machine learning + model to choose which tabs to discard. + </obsolete> <owner>georgesak@chromium.org</owner> <summary> Site engagement score of a reloaded tab. Recorded for each reload if the @@ -82763,16 +90498,14 @@ <owner>fmeawad@chromium.org</owner> <summary> The number of pages compressed per second when opening background tabs. This - is recorded at the end of background tab opening session as an average over - the entire period, which is defined as the duration from the time when the - browser starts to open background tabs until the time when browser has - finished loading those tabs or paused loading due to memory pressure. A new - session starts when the browser resumes loading background tabs when memory - pressure returns to normal. The metric is not recorded when the session - overlaps with session restore. Only recorded on macOS. Warning: This metric - is a ratio and the session interval differs for each session. It is hard to - tell if it is average rate for each second in the interval or it has a huge - spike. + is recorded at the end of the background tab opening session as an average + over the entire period (the duration of time from when the browser starts to + open background tabs until the time the browser has finished loading those + tabs or otherwise decided to stop loading them). The metric is not recorded + when the session overlaps with session restore. Only recorded on macOS. + Warning: This metric is a ratio and the session interval differs for each + session. It is hard to tell if it is average rate for each second in the + interval or it has a huge spike. </summary> </histogram> @@ -82782,16 +90515,14 @@ <owner>fmeawad@chromium.org</owner> <summary> The number of pages decompressed per second when opening background tabs. - This is recorded at the end of background tab opening session as an average - over the entire period, which is defined as the duration from the time when - the browser starts to open background tabs until the time when browser has - finished loading those tabs or paused loading due to memory pressure. A new - session starts when the browser resumes loading background tabs when memory - pressure returns to normal. The metric is not recorded when the session - overlaps with session restore. Only recorded on macOS. Warning: This metric - is a ratio and the session interval differs for each session. It is hard to - tell if it is average rate for each second in the interval or it has a huge - spike. + This is recorded at the end of the background tab opening session as an + average over the entire period (the duration of time from when the browser + starts to open background tabs until the time the browser has finished + loading those tabs or otherwise decided to stop loading them). The metric is + not recorded when the session overlaps with session restore. Only recorded + on macOS. Warning: This metric is a ratio and the session interval differs + for each session. It is hard to tell if it is average rate for each second + in the interval or it has a huge spike. </summary> </histogram> @@ -82800,15 +90531,13 @@ <owner>fmeawad@chromium.org</owner> <summary> The number of swap-ins per second when opening background tabs. This is - recorded at the end of background tab opening session as an average over the - entire period, which is defined as the duration from the time when the - browser starts to open background tabs until the time when browser has - finished loading those tabs or paused loading due to memory pressure. A new - session starts when the browser resumes loading background tabs when memory - pressure returns to normal. The metric is not recorded when the session - overlaps with session restore. Warning: This metric is a ratio and the - session interval differs for each session. It is hard to tell if it is - average rate for each second in the interval or it has a huge spike. + recorded at the end of the background tab opening session as an average over + the entire period (the duration of time from when the browser starts to open + background tabs until the time the browser has finished loading those tabs + or otherwise decided to stop loading them). The metric is not recorded when + the session overlaps with session restore. Warning: This metric is a ratio + and the session interval differs for each session. It is hard to tell if it + is average rate for each second in the interval or it has a huge spike. </summary> </histogram> @@ -82817,15 +90546,13 @@ <owner>fmeawad@chromium.org</owner> <summary> The number of swap-outs per second when opening background tabs. This is - recorded at the end of background tab opening session as an average over the - entire period, which is defined as the duration from the time when the - browser starts to open background tabs until the time when browser has - finished loading those tabs or paused loading due to memory pressure. A new - session starts when the browser resumes loading background tabs when memory - pressure returns to normal. The metric is not recorded when the session - overlaps with session restore. Warning: This metric is a ratio and the - session interval differs for each session. It is hard to tell if it is - average rate for each second in the interval or it has a huge spike. + recorded at the end of the background tab opening session as an average over + the entire period (the duration of time from when the browser starts to open + background tabs until the time the browser has finished loading those tabs + or otherwise decided to stop loading them). The metric is not recorded when + the session overlaps with session restore. Warning: This metric is a ratio + and the session interval differs for each session. It is hard to tell if it + is average rate for each second in the interval or it has a huge spike. </summary> </histogram> @@ -82838,20 +90565,19 @@ </obsolete> <owner>zhenw@chromium.org</owner> <summary> - The tab load time of a tab that is switched to when the browser is in - background tab opening session, which is the duration from the time when the - browser starts to open background tabs until the time when browser has - finished loading those tabs or paused loading due to memory pressure. A new - session starts when the browser resumes loading background tabs when memory - pressure returns to normal. Tab load time is defined as the time between - when the user switches to a backround tab, and the time when that tab - finishes loading in the foreground. If the user switches away before the tab - finishes loading, a metric will not be recorded unless the user switches - back, in which case the tab load time is measured from that point in time. - The metric is only recorded when a tab is switched to from another tab - within the same tabstrip. As a result, the initial forground tab is not - included in this metric since it was not switched to from another tab. The - metric is not recorded when the session overlaps with session restore. + The tab load time of a tab that is switched to during a background tab + opening session (the duration of time from when the browser starts to open + background tabs until the time the browser has finished loading those tabs + or otherwise decided to stop loading them). Tab load time is defined as the + time between when the user switches to a backround tab, and the time when + that tab finishes loading in the foreground. If the user switches away + before the tab finishes loading, a metric will not be recorded unless the + user switches back, in which case the tab load time is measured from that + point in time. The metric is only recorded when a tab is switched to from + another tab within the same tabstrip. As a result, the initial forground tab + is not included in this metric since it was not switched to from another + tab. The metric is not recorded when the session overlaps with session + restore. </summary> </histogram> @@ -82860,20 +90586,19 @@ units="ms"> <owner>zhenw@chromium.org</owner> <summary> - The tab load time of a tab that is switched to when the browser is in - background tab opening session, which is the duration from the time when the - browser starts to open background tabs until the time when browser has - finished loading those tabs or paused loading due to memory pressure. A new - session starts when the browser resumes loading background tabs when memory - pressure returns to normal. Tab load time is defined as the time between - when the user switches to a backround tab, and the time when that tab - finishes loading in the foreground. If the user switches away before the tab - finishes loading, a metric will not be recorded unless the user switches - back, in which case the tab load time is measured from that point in time. - The metric is only recorded when a tab is switched to from another tab - within the same tabstrip. As a result, the initial forground tab is not - included in this metric since it was not switched to from another tab. The - metric is not recorded when the session overlaps with session restore. + The tab load time of a tab that is switched to during a background tab + opening session (the duration of time from when the browser starts to open + background tabs until the time the browser has finished loading those tabs + or otherwise decided to stop loading them). Tab load time is defined as the + time between when the user switches to a backround tab, and the time when + that tab finishes loading in the foreground. If the user switches away + before the tab finishes loading, a metric will not be recorded unless the + user switches back, in which case the tab load time is measured from that + point in time. The metric is only recorded when a tab is switched to from + another tab within the same tabstrip. As a result, the initial forground tab + is not included in this metric since it was not switched to from another + tab. The metric is not recorded when the session overlaps with session + restore. </summary> </histogram> @@ -82917,7 +90642,6 @@ name="TabManager.Experimental.SessionRestore.ForegroundTab.FirstContentfulPaint" units="ms"> <owner>fmeawad@chromium.org</owner> - <owner>ducbui@google.com</owner> <summary> Elapsed time between the start of the loading and the first contentful paint of foreground tabs when the browser loads tabs in session restore. @@ -82928,7 +90652,6 @@ name="TabManager.Experimental.SessionRestore.ForegroundTab.FirstMeaningfulPaint" units="ms"> <owner>fmeawad@chromium.org</owner> - <owner>ducbui@google.com</owner> <summary> Elapsed time between the start of the loading and the first meaningful paint of foreground tabs when the browser loads tabs in session restore. @@ -82939,7 +90662,6 @@ name="TabManager.Experimental.SessionRestore.ForegroundTab.FirstPaint" units="ms"> <owner>fmeawad@chromium.org</owner> - <owner>ducbui@google.com</owner> <summary> Elapsed time between the start of the loading and the first paint of foreground tabs when the browser loads tabs in session restore. @@ -83088,12 +90810,10 @@ <summary> Whether background tab opening session is overlapped with other types of session, e.g., session restore. Background tab opening session is the - duration from the time when the browser starts to open background tabs until - the time when browser has finished loading those tabs or paused loading due - to memory pressure. A new background tab opening session starts when the - browser resumes loading background tabs when memory pressure returns to - normal. This metric helps to understand how often background tab opening has - overlap with other sessions. + duration of time from when the browser starts to open background tabs until + the time the browser has finished loading those tabs or otherwise decided to + stop loading them. This metric helps to understand how often background tab + opening has overlap with other sessions. </summary> </histogram> @@ -83208,6 +90928,33 @@ </summary> </histogram> +<histogram name="TabRestore.error_move_session_at_path_to_backup" + enum="FoundationFileSystemError"> + <owner>sky@chromium.org</owner> + <summary> + Error code returned by [moveItemAtPath:toPath:error:] when moving previous + session file to backup file before restoring. 0 in case of success. + </summary> +</histogram> + +<histogram name="TabRestore.error_remove_backup_at_path" + enum="FoundationFileSystemError"> + <owner>sky@chromium.org</owner> + <summary> + Error code returned by [removeItemAtPath:error:] when removing previous + session backup file. 0 in case of success. + </summary> +</histogram> + +<histogram name="TabRestore.error_remove_session_at_path" + enum="FoundationFileSystemError"> + <owner>sky@chromium.org</owner> + <summary> + Error code returned by [removeItemAtPath:error:] when removing previous + session file. 0 in case of success. + </summary> +</histogram> + <histogram name="Tabs.CountAtResume" units="tabs"> <owner>lliabraa@chromium.org</owner> <summary> @@ -83234,6 +90981,10 @@ </histogram> <histogram name="Tabs.Discard.DiscardInLastMinute" enum="BooleanTabDiscard"> + <obsolete> + Deprecated 11/2017. Average number of minutes between discard events is + available in Tabs.Discard.InitialTime2 and Tabs.Discard.IntervalTime2. + </obsolete> <owner>jamescook@chromium.org</owner> <summary> Whether or not a tab was discarded in the last minute of usage. Total count @@ -83255,6 +91006,11 @@ </histogram> <histogram name="Tabs.Discard.InitialTime2" units="seconds"> + <obsolete> + Deprecated 11/2017. Replaced with Discarding.Urgent.TimeSinceStartup which + is recorded when Chrome has to discard tabs or apps urgently (instead of + before an individual tab is urgently or proactively discarded). + </obsolete> <owner>jamescook@chromium.org</owner> <summary> Time in seconds between system startup and when the first tab is discarded @@ -83276,6 +91032,11 @@ </histogram> <histogram name="Tabs.Discard.IntervalTime2" units="ms"> + <obsolete> + Deprecated 11/2017. Replaced with Discarding.Urgent.TimeSinceLastUrgent + which is recorded before a set of tabs/apps are urgently discarded (instead + of before an individual tab is urgently or proactively discarded). + </obsolete> <owner>jamescook@chromium.org</owner> <summary> Time in milliseconds between tab discard events after the first one, @@ -83347,6 +91108,12 @@ </histogram> <histogram name="Tabs.Discard.TabCount" units="tabs"> + <obsolete> + Deprecated 11/2017. Replaced with Discarding.Urgent.NumAliveTabs which + records the number of tabs that are not pending load or discarded when an + urgent discard request is received (vs. this that records the total number + of tabs every time a tab is discarded, no matter the reason). + </obsolete> <owner>jamescook@chromium.org</owner> <summary> The number of tabs open across all browser windows when a tab was discarded @@ -83445,7 +91212,7 @@ <histogram name="Tabs.MaxWindowsInADay" units="tabs"> <owner>sebmarchand@chromium.org</owner> <summary> - The maximum number of windows opened at the same time over the course of a + The maximum number of windows existing at the same time over the course of a day. </summary> </histogram> @@ -83726,7 +91493,7 @@ </summary> </histogram> -<histogram name="Tabs.TabCountActiveWindow" units="Tabs"> +<histogram name="Tabs.TabCountActiveWindow" units="tabs"> <owner>bruthig@chromium.org</owner> <owner>tdanderson@chromium.org</owner> <summary> @@ -83734,7 +91501,7 @@ </summary> </histogram> -<histogram name="Tabs.TabCountPerLoad" units="Tabs"> +<histogram name="Tabs.TabCountPerLoad" units="tabs"> <owner>bruthig@chromium.org</owner> <owner>tdanderson@chromium.org</owner> <summary> @@ -83749,7 +91516,7 @@ </details> </histogram> -<histogram name="Tabs.TabCountPerWindow" units="Tabs"> +<histogram name="Tabs.TabCountPerWindow" units="tabs"> <owner>bruthig@chromium.org</owner> <owner>tdanderson@chromium.org</owner> <summary> @@ -83770,6 +91537,42 @@ </summary> </histogram> +<histogram base="true" name="Tabs.UnusedAndClosedInInterval.Count" units="tabs"> + <owner>sebmarchand@chromium.org</owner> + <summary> + The number of tabs that haven't been interacted with, visible or audible + over a given interval time, but which no longer exist at all at the end of + this interval. + </summary> +</histogram> + +<histogram base="true" name="Tabs.UnusedInInterval.Count" units="tabs"> + <owner>sebmarchand@chromium.org</owner> + <summary> + The number of tabs that haven't been interacted with, visible or audible or + visible during a given interval of time and still exist at the end of this + interval. + </summary> +</histogram> + +<histogram base="true" name="Tabs.UsedAndClosedInInterval.Count" units="tabs"> + <owner>sebmarchand@chromium.org</owner> + <summary> + The number of tabs that have been interacted with, visible or audible over a + given interval of time, but which no longer exist at all at the end of this + interval. + </summary> +</histogram> + +<histogram base="true" name="Tabs.UsedInInterval.Count" units="tabs"> + <owner>sebmarchand@chromium.org</owner> + <summary> + The number of tabs that have been interacted with, visible or audible during + a given interval of time, includes tabs that don't exist at the end of this + interval. + </summary> +</histogram> + <histogram name="TabsApi.RequestedWindowState" enum="RequestedWindowState"> <owner>afakhry@chromium.org</owner> <summary> @@ -83787,7 +91590,7 @@ </summary> </histogram> -<histogram name="TaskScheduler.DetachDuration" units="ms"> +<histogram base="true" name="TaskScheduler.DetachDuration" units="ms"> <owner>fdoray@chromium.org</owner> <owner>gab@chromium.org</owner> <owner>robliao@chromium.org</owner> @@ -83799,7 +91602,7 @@ </summary> </histogram> -<histogram name="TaskScheduler.NumTasksBeforeDetach" units="tasks"> +<histogram base="true" name="TaskScheduler.NumTasksBeforeDetach" units="tasks"> <owner>fdoray@chromium.org</owner> <owner>gab@chromium.org</owner> <owner>robliao@chromium.org</owner> @@ -83809,7 +91612,7 @@ </summary> </histogram> -<histogram name="TaskScheduler.NumTasksBetweenWaits" units="tasks"> +<histogram base="true" name="TaskScheduler.NumTasksBetweenWaits" units="tasks"> <owner>fdoray@chromium.org</owner> <owner>gab@chromium.org</owner> <owner>robliao@chromium.org</owner> @@ -83944,7 +91747,18 @@ </summary> </histogram> +<histogram name="ThirdPartyModules.InputMethodEditorsCount" units="counts"> + <owner>pmonette@chromium.org</owner> + <summary> + The number of registered input method editors found on the user's machine. + This is emitted shortly after startup when the IME enumeration takes place. + </summary> +</histogram> + <histogram name="ThirdPartyModules.InstalledPrograms.DataSize" units="KB"> + <obsolete> + Deprecated 12/2017. + </obsolete> <owner>pmonette@chromium.org</owner> <summary> Records the size of the in-memory representation of the installed @@ -84015,7 +91829,9 @@ <histogram name="ThirdPartyModules.ShellExtensionsCount" units="counts"> <owner>pmonette@chromium.org</owner> <summary> - The number of registered shell extensions found on the user's machine. + The number of registered shell extensions found on the user's machine. This + is emitted shortly after startup when the shell extensions enumeration takes + place. </summary> </histogram> @@ -84074,6 +91890,13 @@ </summary> </histogram> +<histogram name="Thumbnails.CaptureOutcome" enum="ThumbnailCaptureOutcome"> + <owner>treib@chromium.org</owner> + <summary> + The result of trying to capture a thumbnail of the current page. + </summary> +</histogram> + <histogram name="Thumbnails.CopyFromSurfaceTime" units="ms"> <owner>treib@chromium.org</owner> <summary> @@ -84291,7 +92114,7 @@ </histogram> <histogram name="TouchBar.Default.Metrics" enum="DefaultTouchBarActions"> - <owner>spqchan@chromium.com</owner> + <owner>spqchan@chromium.org</owner> <summary>Tracks the usage of the default touch bar buttons.</summary> </histogram> @@ -84437,6 +92260,9 @@ </histogram> <histogram name="TrackedObjects.GetRetiredOrCreateThreadData" units="ms"> + <obsolete> + Deprecated as of 09/2017. Code measured by this histogram no longer exists. + </obsolete> <owner>fdoray@chromium.org</owner> <summary> Time spent in base::ThreadData::GetRetiredOrCreateThreadData(). This method @@ -84498,6 +92324,14 @@ </summary> </histogram> +<histogram name="Translate.AcceptLanguages.CanBeAcceptDuration" units="ms"> + <owner>googleo@chromium.org</owner> + <summary> + Time taken for the TranslateAcceptLanguages to decide if a given language is + available as Accept-Languages. + </summary> +</histogram> + <histogram name="Translate.AlwaysTranslateLang"> <owner>kenjibaheux@google.com</owner> <summary> @@ -84520,6 +92354,9 @@ </histogram> <histogram name="Translate.CLD2.LanguageAccuracy" units="%"> + <obsolete> + Deprecated as of 11/2017, since cld2 is deprecated. + </obsolete> <owner>rkaplow@google.com</owner> <summary> Accuracy of the language detected by CLD2. Only recorded if the detection @@ -84528,6 +92365,9 @@ </histogram> <histogram name="Translate.CLD2.LanguageDetected" enum="CLD2LanguageCode"> + <obsolete> + Deprecated as of 11/2017, since cld2 is deprecated. + </obsolete> <owner>rkaplow@google.com</owner> <summary>Language of page detected by CLD2.</summary> </histogram> @@ -84790,6 +92630,17 @@ </summary> </histogram> +<histogram name="Translate.PageCaptured" units="ms"> + <obsolete> + Deprecated 2/2018 + </obsolete> + <owner>joelhockey@chromium.org</owner> + <summary> + The time spent capturing plain text from the DOM. This is reported by + ChromeRenderViewObserver when a page is loaded completely. + </summary> +</histogram> + <histogram name="Translate.PageScheme" enum="TranslateScheme"> <owner>kenjibaheux@google.com</owner> <summary>Counts translation target page schemes.</summary> @@ -85018,6 +92869,23 @@ <summary>Whether a scroll is executed on main thread.</summary> </histogram> +<histogram name="UI.CompositorResizeLock.Duration" units="ms"> + <owner>fsamuel@chromium.org</owner> + <summary> + The amount of time the CompositorResizeLock was held in milliseconds. This + is a measure of jank as UI will not generate new frames as long as the lock + is held. + </summary> +</histogram> + +<histogram name="UI.CompositorResizeLock.TimedOut" units="Boolean"> + <owner>fsamuel@chromium.org</owner> + <summary> + Tracks whether the CompositorResizeLock is being released due to timing out + or not. + </summary> +</histogram> + <histogram name="UI.DeviceScale" units="%"> <owner>bsep@chromium.org</owner> <summary> @@ -85027,6 +92895,17 @@ </summary> </histogram> +<histogram name="UI.WindowTreeHost.SurfaceSynchronizationDuration" units="ms"> + <owner>fsamuel@chromium.org</owner> + <summary> + The amount of time it took for UI's CompositorFrame to activate due to a + surface synchronization event. This a measure of jank as UI will not + generate new frames as long synchronization is in progress. This metric is + similar to UI.CompositorResizeLock.Duration but measures the new + synchronization code path. + </summary> +</histogram> + <histogram name="UKM.ActualLogUploadInterval" units="minutes"> <owner>holte@chromium.org</owner> <owner>rkaplow@chromium.org</owner> @@ -85108,12 +92987,30 @@ </summary> </histogram> -<histogram name="UKM.Sources.SerializedCount"> +<histogram name="UKM.Sources.KeptSourcesCount" units="sources"> + <owner>asvitkine@chromium.org</owner> + <owner>bmcquade@chromium.org</owner> + <summary> + Number of unsent UKM sources that were kept in-memory to be potentially + transmitted in the next log. + </summary> +</histogram> + +<histogram name="UKM.Sources.SerializedCount" units="sources"> <owner>holte@chromium.org</owner> <owner>rkaplow@chromium.org</owner> <summary>Number of serialized UKM sources when storing a UKM log.</summary> </histogram> +<histogram name="UKM.Sources.UnsentSourcesCount" units="sources"> + <owner>asvitkine@chromium.org</owner> + <owner>bmcquade@chromium.org</owner> + <summary> + Number of UKM sources that were not sent because they had no associated + entries. + </summary> +</histogram> + <histogram name="UKM.UnsentLogs.DroppedSize" units="bytes"> <owner>holte@chromium.org</owner> <owner>rkaplow@chromium.org</owner> @@ -85487,6 +93384,19 @@ </summary> </histogram> +<histogram name="UMA.FileMetricsProvider.Happening" + enum="FileMetricsProviderHappening"> + <obsolete> + This metrics was to provide information for crbug/760317 which has been + resolved. Removed February, 2018. + </obsolete> + <owner>bcwhite@chromium.org</owner> + <summary> + Records various happenings within the FileMetricsProvider for debugging + purposes. + </summary> +</histogram> + <histogram name="UMA.FileMetricsProvider.InitialAccessResult" enum="FileMetricsProviderAccessResult"> <owner>asvitkine@chromium.org</owner> @@ -85562,6 +93472,9 @@ </histogram> <histogram name="UMA.Histograms.Activity" enum="HistogramActivityReport"> + <obsolete> + Deprecated as of October 2017. No longer tracked. + </obsolete> <owner>asvitkine@chromium.org</owner> <owner>bcwhite@chromium.org</owner> <summary> @@ -85618,7 +93531,7 @@ </histogram> <histogram name="UMA.LocalPersistentMemoryAllocator.Failures.Posix" - enum="OSAgnosticErrno"> + enum="PopularOSErrno"> <owner>bcwhite@chromium.org</owner> <summary> Failures, as reported in errno, encountered while allocating local @@ -85682,7 +93595,17 @@ <owner>asvitkine@chromium.org</owner> <summary> HTTP response codes and network errors encountered by UMA when attempting to - upload logs to the server. + upload logs to the server through an HTTPS connection. + </summary> +</histogram> + +<histogram name="UMA.LogUpload.ResponseOrErrorCode.HTTP" + enum="CombinedHttpResponseAndNetErrorCode"> + <owner>holte@chromium.org</owner> + <owner>asvitkine@chromium.org</owner> + <summary> + HTTP response codes and network errors encountered by UMA when attempting to + upload logs to the server through an HTTP connection. </summary> </histogram> @@ -85720,7 +93643,36 @@ </summary> </histogram> +<histogram name="UMA.MetricsService.DeletedDirectorySize.Failure" units="KB"> + <obsolete> + This metrics was to provide information for crbug/760317 which has been + resolved. Removed February, 2018. + </obsolete> + <owner>bcwhite@chromium.org</owner> + <summary> + Records the size of the metrics directory size, after failing to be deleted. + This is a temporary metric that will be removed in M63 or M64. + </summary> +</histogram> + +<histogram name="UMA.MetricsService.DeletedDirectorySize.Success" units="KB"> + <obsolete> + This metrics was to provide information for crbug/760317 which has been + resolved. Removed February, 2018. + </obsolete> + <owner>bcwhite@chromium.org</owner> + <summary> + Records the size of the metrics directory size, after being successfully + deleted. This should always be zero unless there is a bug in the return + code. This is a temporary metric that will be removed in M63 or M64. + </summary> +</histogram> + <histogram name="UMA.MetricsService.RecordCurrentHistograms.Time" units="ms"> + <obsolete> + Removed February, 2018 because persistent metrics are fully launched with no + observable change in operation time. + </obsolete> <owner>asvitkine@chromium.org</owner> <owner>bcwhite@chromium.org</owner> <summary> @@ -86530,7 +94482,7 @@ <histogram name="UpgradeDetector.NotificationStage" enum="UpgradeNotificationStage"> - <owner>spqchan@chromium.com</owner> + <owner>spqchan@chromium.org</owner> <summary> Tracks the upgrade notification stage. This is recorded with every UMA log. </summary> @@ -86631,6 +94583,9 @@ </histogram> <histogram name="UrlFetcher.StringResponseSize" units="KB"> + <obsolete> + Removed 10/2017. + </obsolete> <owner>mmenke@chromium.org</owner> <summary> Size (in kilobytes) of response bodies retrieved as strings from URLFetcher. @@ -86767,6 +94722,13 @@ <summary>Array buffer sizes for which V8 failed to allocate memory.</summary> </histogram> +<histogram name="V8.AsmModuleSizeBytes" units="bytes"> + <owner>bradnelson@chromium.org</owner> + <owner>titzer@chromium.org</owner> + <owner>aseemgarg@chromium.org</owner> + <summary>Size of asm.js module (in asm.js format).</summary> +</histogram> + <histogram name="V8.AsmWasmTranslationMicroSeconds" units="microseconds"> <owner>bradnelson@chromium.org</owner> <owner>titzer@chromium.org</owner> @@ -86774,6 +94736,15 @@ <summary>Time to convert asm.js code to WebAssembly.</summary> </histogram> +<histogram name="V8.AsmWasmTranslationThroughput" units="MB/s"> + <owner>bradnelson@chromium.org</owner> + <owner>titzer@chromium.org</owner> + <owner>aseemgarg@chromium.org</owner> + <summary> + Throughput of translation of asm.js code to WebAssembly in MB/s. + </summary> +</histogram> + <histogram name="V8.ASTOptimization"> <obsolete> This histogram is no longer present in V8. @@ -86864,7 +94835,23 @@ <summary>Time spent in V8 compiler (full codegen) for eval.</summary> </histogram> +<histogram name="V8.CompileHeuristicsDecision" enum="CompileHeuristicsDecision"> + <obsolete> + This histogram has been replaced by V8.CompileTime.CacheBehaviour. + </obsolete> + <owner>kouhei@chromium.org</owner> + <summary> + V8 script compile function variant which was picked. This contains + information such as {if,why} v8 {code,parser} was + {produced,consumed,bypassed}. + </summary> +</histogram> + <histogram name="V8.CompileInlineScriptMicroSeconds" units="microseconds"> + <obsolete> + This histogram has been replaced by + V8.CompileTimeMicroSeconds.NoCache.InlineScript. + </obsolete> <owner>yangguo@chromium.org</owner> <summary>Time spent compiling an inline script.</summary> </histogram> @@ -86891,6 +94878,10 @@ </histogram> <histogram name="V8.CompileNoncacheableMicroSeconds" units="microseconds"> + <obsolete> + This histogram has been replaced by the subcategories of + V8.CompileTimeMicroSeconds.NoCache + </obsolete> <owner>yangguo@chromium.org</owner> <summary> Time spent compiling a script that cannot be subject to caching. @@ -86907,6 +94898,15 @@ </summary> </histogram> +<histogram name="V8.CompileScript.CacheBehaviour" enum="V8CacheBehaviour"> + <owner>leszeks@chromium.org</owner> + <summary> + The cache behaviour of compiling a V8 script, including whether we produced + or consumed a code cache, whether we hit V8's isolate's cache, and if we + didn't use the code cache, the reason why not. + </summary> +</histogram> + <histogram name="V8.CompileScriptMicroSeconds" units="microseconds"> <owner>yangguo@chromium.org</owner> <summary> @@ -86914,6 +94914,87 @@ </summary> </histogram> +<histogram name="V8.CompileScriptMicroSeconds.BackgroundThread" + units="microseconds"> + <owner>rmcilroy@chromium.org</owner> + <summary> + Total time spent in compiling a script (incl. parsing) on a background + thread. + </summary> +</histogram> + +<histogram name="V8.CompileScriptMicroSeconds.ConsumeCache" + units="microseconds"> + <owner>leszeks@chromium.org</owner> + <summary> + Total time spent in compiling a script when the 'compilation' is + deserializing it from the code cache. + </summary> +</histogram> + +<histogram name="V8.CompileScriptMicroSeconds.ConsumeCache.Failed" + units="microseconds"> + <owner>leszeks@chromium.org</owner> + <summary> + Total time spent in compiling a script (incl. parsing/caching) when the + compilation tried to deserialize it from the code cache, but failed. + </summary> +</histogram> + +<histogram name="V8.CompileScriptMicroSeconds.IsolateCacheHit" + units="microseconds"> + <owner>leszeks@chromium.org</owner> + <summary> + Total time spent in compiling a script (incl. parsing/caching) in the case + where the V8 isolate's compilation cache is hit. + </summary> +</histogram> + +<histogram name="V8.CompileScriptMicroSeconds.NoCache.CacheTooCold" + units="microseconds"> + <owner>leszeks@chromium.org</owner> + <summary> + Total time spent in compiling a script (incl. parsing) when the cache is too + cold to use. + </summary> +</histogram> + +<histogram name="V8.CompileScriptMicroSeconds.NoCache.InlineScript" + units="microseconds"> + <owner>leszeks@chromium.org</owner> + <summary> + Total time spent in compiling a script (incl. parsing) when the script is an + inline script. + </summary> +</histogram> + +<histogram name="V8.CompileScriptMicroSeconds.NoCache.Other" + units="microseconds"> + <owner>leszeks@chromium.org</owner> + <summary> + Total time spent in compiling a script (incl. parsing) when we do not want + to cache it. + </summary> +</histogram> + +<histogram name="V8.CompileScriptMicroSeconds.NoCache.ScriptTooSmall" + units="microseconds"> + <owner>leszeks@chromium.org</owner> + <summary> + Total time spent in compiling a script (incl. parsing) when the script is + too small to be cached. + </summary> +</histogram> + +<histogram name="V8.CompileScriptMicroSeconds.ProduceCache" + units="microseconds"> + <owner>leszeks@chromium.org</owner> + <summary> + Total time spent in compiling a script (incl. parsing) and serializing it + for the code cache. + </summary> +</histogram> + <histogram name="V8.CompileSerialize" units="ms"> <obsolete> This histogram has been replaced by V8.CompileSerializeMicroSeconds. @@ -86978,6 +95059,38 @@ </summary> </histogram> +<histogram name="V8.GC.ParallelTaskLatencyMicroSeconds" units="microseconds"> + <owner>gab@chromium.org</owner> + <summary> + Latency (post-to-schedule) of each parallel task posted during V8 garbage + collection. + </summary> +</histogram> + +<histogram name="V8.GCBackgroundMarking" units="ms"> + <owner>ulan@chromium.org</owner> + <summary> + Time spent in background tasks doing marking in one GC cycle. It is recorded + after each GC. + </summary> +</histogram> + +<histogram name="V8.GCBackgroundScavenger" units="ms"> + <owner>ulan@chromium.org</owner> + <summary> + Time spent in background tasks doing scavenging in one GC cycle. It is + recorded after each GC. + </summary> +</histogram> + +<histogram name="V8.GCBackgroundSweeping" units="ms"> + <owner>ulan@chromium.org</owner> + <summary> + Time spent in background tasks doing sweeping in one GC cycle. It is + recorded after each GC. + </summary> +</histogram> + <histogram name="V8.GCCompactor" units="ms"> <owner>hpayer@chromium.org</owner> <summary>Time spent in mark-sweep phase of GC.</summary> @@ -87113,6 +95226,9 @@ </histogram> <histogram name="V8.MemoryExternalFragmentationCellSpace" units="%"> + <obsolete> + This histogram has been replaced by V8.MemoryExternalFragmentationOldSpace. + </obsolete> <owner>hpayer@chromium.org</owner> <summary> External memory fragmentation in the cell space after each GC in percent. @@ -87186,6 +95302,9 @@ </histogram> <histogram name="V8.MemoryHeapFractionCellSpace" units="%"> + <obsolete> + Deprecated as of 09/2017. + </obsolete> <owner>hpayer@chromium.org</owner> <summary> Fraction of the total heap used by the cell space after each GC in percent. @@ -87193,6 +95312,9 @@ </histogram> <histogram name="V8.MemoryHeapFractionCodeSpace" units="%"> + <obsolete> + Deprecated as of 09/2017. + </obsolete> <owner>hpayer@chromium.org</owner> <summary> Fraction of the total heap used by the code space after each GC in percent. @@ -87200,6 +95322,9 @@ </histogram> <histogram name="V8.MemoryHeapFractionLoSpace" units="%"> + <obsolete> + Deprecated as of 09/2017. + </obsolete> <owner>hpayer@chromium.org</owner> <summary> Fraction of the total heap used by the lo space after each GC in percent. @@ -87207,6 +95332,9 @@ </histogram> <histogram name="V8.MemoryHeapFractionMapSpace" units="%"> + <obsolete> + Deprecated as of 09/2017. + </obsolete> <owner>hpayer@chromium.org</owner> <summary> Fraction of the total heap used by the map space after each GC in percent. @@ -87214,6 +95342,9 @@ </histogram> <histogram name="V8.MemoryHeapFractionNewSpace" units="%"> + <obsolete> + Deprecated as of 09/2017. + </obsolete> <owner>hpayer@chromium.org</owner> <summary> Fraction of the total heap used by the new space after each GC in percent. @@ -87222,7 +95353,7 @@ <histogram name="V8.MemoryHeapFractionOldDataSpace" units="%"> <obsolete> - This histogram has been replaced by V8.MemoryHeapFractionOldSpace. + Deprecated as of 09/2017. </obsolete> <owner>hpayer@chromium.org</owner> <summary> @@ -87233,7 +95364,7 @@ <histogram name="V8.MemoryHeapFractionOldPointerSpace" units="%"> <obsolete> - This histogram has been replaced by V8.MemoryHeapFractionOldSpace. + Deprecated as of 09/2017. </obsolete> <owner>hpayer@chromium.org</owner> <summary> @@ -87243,6 +95374,9 @@ </histogram> <histogram name="V8.MemoryHeapFractionOldSpace" units="%"> + <obsolete> + Deprecated as of 09/2017. + </obsolete> <owner>hpayer@chromium.org</owner> <summary> Fraction of the total heap used by the old space after each GC in percent. @@ -87250,6 +95384,9 @@ </histogram> <histogram name="V8.MemoryHeapSampleCellSpaceCommitted" units="KB"> + <obsolete> + Deprecated as of 09/2017. + </obsolete> <owner>hpayer@chromium.org</owner> <summary> The size of committed memory in the cell space after each GC in KB. @@ -87471,6 +95608,27 @@ <summary>Time to instantiate a WebAssembly module.</summary> </histogram> +<histogram name="V8.WasmLazyCompilationMicroSeconds" units="microseconds"> + <owner>bradnelson@chromium.org</owner> + <owner>titzer@chromium.org</owner> + <owner>aseemgarg@chromium.org</owner> + <summary> + Time for lazy compilation of WebAssembly functions. This is recorded per + function for the functions that are lazily compiled. + </summary> +</histogram> + +<histogram name="V8.WasmLazyCompilationThroughput" units="KB/s"> + <owner>bradnelson@chromium.org</owner> + <owner>titzer@chromium.org</owner> + <owner>aseemgarg@chromium.org</owner> + <summary> + Throughput of compilation of lazily compiled WebAssembly functions in KB/s + (size of function in wasm format divided by time to compile it). This is + recorded per function for functions that are lazily compiled. + </summary> +</histogram> + <histogram name="V8.WasmMaxMemPagesCount" units="pages"> <owner>bradnelson@chromium.org</owner> <owner>titzer@chromium.org</owner> @@ -87641,9 +95799,9 @@ <histogram name="Variations.LoadSeedSignature" enum="VariationSeedSignature"> <owner>asvitkine@chromium.org</owner> <summary> - The result of verifying the variations seed signature, recorded when the - variations seed is stored to Local State after being retrieved from the - server. + The result of verifying the latest variations seed's signature, recorded + when the seed is loaded from Local State. Not recorded when running in safe + mode. </summary> </histogram> @@ -87678,11 +95836,68 @@ </histogram> <histogram name="Variations.SafeMode.FellBackToSafeMode" enum="BooleanSafeMode"> + <obsolete> + Deprecated as of M66 / Jan 2018. Replaced by + Variations.SafeMode.FellBackToSafeMode2. + </obsolete> + <owner>isherman@chromium.org</owner> + <summary> + Whether or not the VariationsService /would/ fall back to Safe Mode, due to + either too many crashes or too many failures to fetch a new seed, given some + initial/unrefined heuristics. Recorded during Chrome startup, when the + VariationsService is created. + + This metric was only reported before Safe Mode was actually implemented, as + a sanity-check for the forthcoming implementation. + </summary> +</histogram> + +<histogram name="Variations.SafeMode.FellBackToSafeMode2" + enum="BooleanSafeMode"> <owner>isherman@chromium.org</owner> <summary> Whether or not the VariationsService fell back to Safe Mode, due to either too many crashes or too many failures to fetch a new seed. Recorded during - Chrome startup, when the VariationsService is created. + Chrome startup, immediately before field trials are created. Only recorded + if either a recent or a safe seed was loaded successfully. + </summary> +</histogram> + +<histogram name="Variations.SafeMode.LoadSafeSeed.Result" + enum="VariationsSeedLoadResult"> + <owner>isherman@chromium.org</owner> + <summary> + Records whether the safe variations seed was successfully read from local + state on startup. Records a detailed reason on read failure. Only recorded + when attempting to run in safe mode. + </summary> +</histogram> + +<histogram name="Variations.SafeMode.LoadSafeSeed.SignatureValidity" + enum="VariationSeedSignature"> + <owner>isherman@chromium.org</owner> + <summary> + The result of verifying the safe variations seed's signature, recorded when + the seed is loaded from Local State. Only recorded when attempting to run in + safe mode. + </summary> +</histogram> + +<histogram name="Variations.SafeMode.StoreSafeSeed.Result" + enum="VariationsSeedStoreResult"> + <owner>isherman@chromium.org</owner> + <summary> + Records the result of storing a safe variations seed (and all associated + metadata) to the seed store. + </summary> +</histogram> + +<histogram name="Variations.SafeMode.StoreSafeSeed.SignatureValidity" + enum="VariationSeedSignature"> + <owner>isherman@chromium.org</owner> + <summary> + The result of verifying the safe variations seed's signature, recorded when + the safe seed is stored to Local State. </summary> </histogram> @@ -87796,23 +96011,44 @@ <owner>asvitkine@chromium.org</owner> <summary> HTTP response codes and network error encountered by VariationsService when - attempting to fetch a variations seed from the server. + attempting to fetch a variations seed from the server over an HTTPS + connection. + </summary> +</histogram> + +<histogram name="Variations.SeedFetchResponseOrErrorCode.HTTP" + enum="CombinedHttpResponseAndNetErrorCode"> + <owner>asvitkine@chromium.org</owner> + <summary> + HTTP response codes and network error encountered by VariationsService when + attempting to fetch a variations seed from the server over an HTTP + connection. </summary> </histogram> <histogram name="Variations.SeedFreshness" units="minutes"> <owner>asvitkine@chromium.org</owner> <summary> - The time interval between when the variations seed was last downloaded and - when it was used. + The time interval between when the variations seed was downloaded and when + it was loaded for use. Not recorded for expired seeds, nor when the download + time is unknown (typically, for seeds imported via first run). </summary> </histogram> <histogram name="Variations.SeedLoadResult" enum="VariationsSeedLoadResult"> <owner>asvitkine@chromium.org</owner> <summary> - Records whether the variations seed was successfully read from local state - on startup. Records a detailed reason on read failure. + Records whether the latest variations seed was successfully read from local + state on startup. Records a detailed reason on read failure. Not recorded + when running in safe mode. + </summary> +</histogram> + +<histogram name="Variations.SeedProcessingTime" units="ms"> + <owner>gayane@chromium.org</owner> + <summary> + Records how long it takes to load and process variations seed. This metric + is recorded only when loading and processing of the seed is successful. </summary> </histogram> @@ -87930,7 +96166,8 @@ <owner>asvitkine@chromium.org</owner> <summary> The result of verifying the variations seed signature, recorded when the - variations seed is loaded from Local State. + variations seed is stored to Local State after being retrieved from the + server. </summary> </histogram> @@ -88133,6 +96370,13 @@ </summary> </histogram> +<histogram name="VoiceInteraction.OpenDuration" units="ms"> + <owner>xiaohuic@chromium.org</owner> + <summary> + Records the time between a voice interaction session start and end. + </summary> +</histogram> + <histogram name="VoiceInteraction.UserInteractionToRequestArrival" units="ms"> <owner>muyuanli@chromium.org</owner> <summary> @@ -88140,10 +96384,92 @@ </summary> </histogram> +<histogram name="VR.Component.Assets.DurationUntilReady.OnChromeStart" + units="ms"> + <obsolete> + Deprecated 02/2018 in issue 799074. + VR.Component.Assets.DurationUntilReady.OnRegisterComponent measures the + intended metric more accurately. + </obsolete> + <owner>tiborg@chromium.org</owner> + <summary> + Duration from starting Chrome until VR assets component is ready to use. + </summary> +</histogram> + +<histogram base="true" name="VR.Component.Assets.DurationUntilReady.OnEnter" + units="ms"> + <owner>tiborg@chromium.org</owner> + <summary> + Duration from entering a VR mode until the VR assets component is ready to + use. + </summary> +</histogram> + +<histogram name="VR.Component.Assets.DurationUntilReady.OnRegisterComponent" + units="ms"> + <owner>tiborg@chromium.org</owner> + <summary> + Duration from registering VR assets component until it is ready to use. + </summary> +</histogram> + +<histogram base="true" name="VR.Component.Assets.Status.OnEnter" + enum="VRComponentStatus"> + <owner>tiborg@chromium.org</owner> + <summary>Status of the VR assets component when entering a VR mode.</summary> +</histogram> + +<histogram name="VR.Component.Assets.VersionAndStatus.OnLoad" + enum="VRAssetsLoadStatus"> + <owner>tiborg@chromium.org</owner> + <summary> + The component version and status of loading the VR assets. The value is + encoded as (XXX)(YYY)(SSS) where XXX is the major component version, YYY the + minor component version and SSS the status. See + //chrome/browser/vr/assets_load_status.h for possible status values. + </summary> +</histogram> + +<histogram name="VR.Component.Assets.VersionAndStatus.OnUpdate" + enum="VRAssetsComponentUpdateStatus"> + <owner>tiborg@chromium.org</owner> + <summary> + The version and update status of the VR assets component. The value is + encoded as (XXX)(YYY)(SSS) where XXX is the major version, YYY the minor + version and SSS the status. See + //chrome/browser/vr/assets_component_update_status.h for possible status + values. + </summary> +</histogram> + +<histogram base="true" name="VR.NetworkConnectionType.OnEnter" + enum="NetworkConnectionType"> + <owner>tiborg@chromium.org</owner> + <summary>Network connection type when entering a VR mode.</summary> +</histogram> + +<histogram name="VR.NetworkConnectionType.OnRegisterComponent" + enum="NetworkConnectionType"> + <owner>tiborg@chromium.org</owner> + <summary> + Network connection type when registering the VR component(s). + </summary> +</histogram> + +<histogram name="VR.Session.VoiceSearch.StartedCount" units="searches"> + <owner>bshe@chromium.org</owner> + <summary> + Number of times voice search is started in a single VR session. Recorded + when a new disjoint session has begun or when the session has ended in a + non-continuable way. + </summary> +</histogram> + <histogram name="VR.Shell.EncounteredSuppressedUI" enum="VRSuppressedElement"> <owner>asimjour@chromium.org</owner> <summary> - We must suppress monocularly rendered ui elements in VR. This tracks which + We must suppress monocularly rendered ui elements in VR. This records which ui element suppressions are encountered in practice. </summary> </histogram> @@ -88151,11 +96477,26 @@ <histogram name="VR.Shell.EncounteredUnsupportedMode" enum="VRUnsupportedMode"> <owner>vollick@chromium.org</owner> <summary> - We must exit VR mode when browsing in certain situations. This tracks which + We must exit VR mode when browsing in certain situations. This records which situations are encountered in practice. </summary> </histogram> +<histogram name="VR.VoiceSearch.EndState" enum="VRVoiceSearchEndState"> + <owner>bshe@chromium.org</owner> + <summary>The end state of a voice search request in VR.</summary> +</histogram> + +<histogram name="VR.VoiceSearch.RecordAudioOsPermissionPromptChoice" + enum="BooleanContinueChoice"> + <owner>bshe@chromium.org</owner> + <summary> + Chrome shows a prompt when the OS's record audio permission is needed for + voice search. The prompt gives user two choices: CANCEL or CONTINUE. This + records the user's selection. + </summary> +</histogram> + <histogram name="VRAutopresentedWebVR" enum="Boolean"> <owner>ymalik@chromium.org</owner> <summary> @@ -88163,7 +96504,7 @@ </summary> </histogram> -<histogram name="VRDisplayPresentResult" enum="PresentationResult"> +<histogram name="VRDisplayPresentResult" enum="VRPresentationResult"> <owner>billorr@chromium.org</owner> <summary> The result of calls to VRDisplay::requestPresent(). Reported twice per @@ -88172,6 +96513,14 @@ </summary> </histogram> +<histogram name="VRFreNotComplete" enum="BooleanHit"> + <owner>ymalik@chromium.org</owner> + <summary> + Whether the user had been through the FRE when Chrome is launched in VR + mode. + </summary> +</histogram> + <histogram name="VRRuntimeVersion" units="normalized version"> <owner>tiborg@chromium.org</owner> <summary>The version of the runtime being used for VR.</summary> @@ -88193,6 +96542,15 @@ </summary> </histogram> +<histogram name="VRSessionTimeFromDLA" units="ms"> + <owner>ymalik@chromium.org</owner> + <summary> + The duration of a single VR session initiated via a deep-linked WebVR app. + Logged when a new disjoint session has begun, or when the session has ended + in a non-continuable way. + </summary> +</histogram> + <histogram name="VRSessionVideoCount"> <owner>billorr@chromium.org</owner> <summary> @@ -88343,7 +96701,7 @@ Deprecated 08/2016 because CertVerifier is not used for web view cert verification. </obsolete> - <owner>eugenebut@chromium.com</owner> + <owner>eugenebut@chromium.org</owner> <summary> [iOS] Reports certificate verification mismatch between SecTrust API and CertVerifier. SecTrust API is used for making load/no-load decision and @@ -88356,7 +96714,7 @@ <histogram name="Web.CurrentOriginEqualsLastCommittedOrigin" enum="BooleanEqual"> - <owner>eugenebut@chromium.com</owner> + <owner>eugenebut@chromium.org</owner> <summary> [iOS] Reports URL matches between the return value from the WebState's GetLastCommittedURL and GetCurrentURL methods. It is expected the origins @@ -88374,7 +96732,7 @@ Deprecated as of 9/2013, replaced by Web.CurrentOriginEqualsLastCommittedOrigin. </obsolete> - <owner>michaeldo@chromium.com</owner> + <owner>michaeldo@chromium.org</owner> <summary> [iOS] Reports URL matches between the return value from the WebState's GetLastCommittedURL and GetCurrentURL methods. It is expected the values @@ -88394,32 +96752,87 @@ <summary> Records the available space that can be used when installing a WebAPK from Google Play fails. The space recorded is the available space beyond the - system's minimum free space threshold, with a range between -1000 and 500 + system's minimum free space threshold, with a range between -1000 and 1000 MB. Negative values mean that there is less free space available than the system's minimum, by the given amount. </summary> </histogram> <histogram name="WebApk.Install.AvailableSpace.Success" units="MB"> + <obsolete> + Deprecated 2017-09. As of M64, this is no longer recorded. + </obsolete> <owner>hanxi@chromium.org</owner> <owner>ranj@chromium.org</owner> <owner>yfriedman@chromium.org</owner> <summary> Records the available space that can be used when installing a WebAPK from Google Play succeeds. The space recorded is the available space beyond the - system's minimum free space threshold, with a range between -1000 and 500 + system's minimum free space threshold, with a range between -1000 and 1000 MB. Negative values mean that there is less free space available than the system's minimum, by the given amount. </summary> </histogram> +<histogram name="WebApk.Install.AvailableSpaceAfterFreeUpAll.Fail" units="MB"> + <owner>hanxi@chromium.org</owner> + <owner>ranj@chromium.org</owner> + <owner>yfriedman@chromium.org</owner> + <summary> + Records the available space that can be used when installing a WebAPK from + Google Play fails after freeing up cache and unimportant storage. The space + recorded is the available space beyond the system's minimum free space + threshold, with a range between -1000 and 1000 MB. Negative values mean that + there is less free space available than the system's minimum, by the given + amount. + </summary> +</histogram> + +<histogram name="WebApk.Install.AvailableSpaceAfterFreeUpCache.Fail" units="MB"> + <owner>hanxi@chromium.org</owner> + <owner>ranj@chromium.org</owner> + <owner>yfriedman@chromium.org</owner> + <summary> + Records the available space that can be used when installing a WebAPK from + Google Play fails after freeing up cache. The space recorded is the + available space beyond the system's minimum free space threshold, with a + range between -1000 and 1000 MB. Negative values mean that there is less + free space available than the system's minimum, by the given amount. + </summary> +</histogram> + +<histogram + name="WebApk.Install.AvailableSpaceAfterFreeUpUnimportantStorage.Fail" + units="MB"> + <owner>hanxi@chromium.org</owner> + <owner>ranj@chromium.org</owner> + <owner>yfriedman@chromium.org</owner> + <summary> + Records the available space that can be used when installing a WebAPK from + Google Play fails after freeing up unimportant storage. The space recorded + is the available space beyond the system's minimum free space threshold, + with a range between -1000 and 1000 MB. Negative values mean that there is + less free space available than the system's minimum, by the given amount. + </summary> +</histogram> + +<histogram name="WebApk.Install.ChromeCacheSize.Fail" units="MB"> + <owner>hanxi@chromium.org</owner> + <owner>ranj@chromium.org</owner> + <owner>yfriedman@chromium.org</owner> + <summary> + Records the Chrome cache size when installing a WebAPK from Google Play + fails, with a range between 0 and 1000, rounded to the nearest 10MB. + </summary> +</histogram> + <histogram name="WebApk.Install.ChromeUnimportantStorage.Fail" units="MB"> <owner>hanxi@chromium.org</owner> <owner>ranj@chromium.org</owner> <owner>yfriedman@chromium.org</owner> <summary> Records the Chrome unimportant storage size when installing a WebAPK from - Google Play fails, with a range between 0 and 1000, round to the nearest + Google Play fails, with a range between 0 and 1000, rounded to the nearest 10MB. </summary> </histogram> @@ -88434,12 +96847,14 @@ </summary> </histogram> -<histogram name="WebApk.Install.GooglePlayErrorCode" units="code"> +<histogram name="WebApk.Install.GooglePlayErrorCode" + enum="WebApkInstallGooglePlayErrorCode"> <owner>hanxi@chromium.org</owner> <owner>pkotwicz@chromium.org</owner> <owner>yfriedman@chromium.org</owner> <summary> - Records the error code when installing a WebAPK from Google Play fails. + Records the error code when installing a WebAPK from Google Play fails. See + go/webapk-install-googleplayerrorcode. </summary> </histogram> @@ -88553,7 +96968,19 @@ </summary> </histogram> +<histogram name="WebApk.Launch.NetworkError" enum="NetErrorCodes"> + <owner>hanxi@chromium.org</owner> + <owner>pkotwicz@chromium.org</owner> + <owner>yfriedman@chromium.org</owner> + <summary> + Records the error codes when a WebAPK is launched with network failures. + </summary> +</histogram> + <histogram name="WebApk.LaunchInterval" units="ms"> + <obsolete> + Deprecated 2018-01. Replaced by WebApk.LaunchInterval2 + </obsolete> <owner>hanxi@chromium.org</owner> <owner>pkotwicz@chromium.org</owner> <owner>yfriedman@chromium.org</owner> @@ -88563,6 +96990,27 @@ </summary> </histogram> +<histogram name="WebApk.LaunchInterval2" units="minutes"> + <owner>hanxi@chromium.org</owner> + <owner>pkotwicz@chromium.org</owner> + <owner>yfriedman@chromium.org</owner> + <summary> + Records the amount of time since the user last launched the WebAPK from the + homescreen. Not recorded on first launch. + </summary> +</histogram> + +<histogram name="WebApk.Notification.Permission.Status" + enum="BooleanWebApkNotificationPermission"> + <owner>hanxi@chromium.org</owner> + <owner>ranj@chromium.org</owner> + <owner>yfriedman@chromium.org</owner> + <summary> + When a WebAPK receives a notification, log whether it has permission to + display that notification. + </summary> +</histogram> + <histogram name="WebApk.OpenFromMenu" enum="WebApkOpenResult"> <owner>hanxi@chromium.org</owner> <owner>pkotwicz@chromium.org</owner> @@ -88574,6 +97022,45 @@ </summary> </histogram> +<histogram name="WebApk.Permission.ChromePermissionDenied" + enum="WebApkPermissionType"> + <obsolete> + Deprecated 2017-11. This UMA logs extra requests. Replaced by + ChromePermissionDenied2. + </obsolete> + <owner>hanxi@chromium.org</owner> + <owner>pkotwicz@chromium.org</owner> + <owner>ranj@chromium.org</owner> + <owner>yfriedman@chromium.org</owner> + <summary> + The number of Android runtime permission requests that are denied for the + WebAPK because Chrome does not have access to that permission. + </summary> +</histogram> + +<histogram name="WebApk.Permission.ChromePermissionDenied2" + enum="WebApkPermissionType"> + <owner>hanxi@chromium.org</owner> + <owner>pkotwicz@chromium.org</owner> + <owner>ranj@chromium.org</owner> + <owner>yfriedman@chromium.org</owner> + <summary> + The number of Android runtime permission requests that are denied for the + WebAPK because Chrome does not have access to that permission. + </summary> +</histogram> + +<histogram name="WebApk.Permission.ChromeWithoutPermission" + enum="WebApkPermissionType"> + <owner>hanxi@chromium.org</owner> + <owner>pkotwicz@chromium.org</owner> + <owner>yfriedman@chromium.org</owner> + <summary> + Records the amount of requests of Android runtime permissions which haven't + been granted to Chrome when Chrome is running in WebAPK runtime. + </summary> +</histogram> + <histogram name="WebApk.Session.TotalDuration" units="ms"> <owner>hanxi@chromium.org</owner> <owner>pkotwicz@chromium.org</owner> @@ -88605,6 +97092,17 @@ </summary> </histogram> +<histogram name="WebApk.Update.NumStaleUpdateRequestFiles" units="files"> + <owner>hanxi@chromium.org</owner> + <owner>pkotwicz@chromium.org</owner> + <owner>yfriedman@chromium.org</owner> + <summary> + Records the number of zombie "WebAPK update request" files that + the update process failed to cleanup. Recorded for all WebAPKs whenever a + WebAPK or webapp is launched. + </summary> +</histogram> + <histogram name="WebApk.Update.RequestQueued" enum="WebApkUpdateRequestQueued"> <owner>hanxi@chromium.org</owner> <owner>pkotwicz@chromium.org</owner> @@ -88625,6 +97123,65 @@ </summary> </histogram> +<histogram name="WebApk.WebApkService.BindSuccess" enum="BooleanSuccess"> + <owner>hanxi@chromium.org</owner> + <owner>pkotwicz@chromium.org</owner> + <owner>yfriedman@chromium.org</owner> + <summary> + Records whether Chrome can bind to a WebAPK's "WebAPK service". + Recorded each time that Chrome attempts to bind to a WebAPK service. + </summary> +</histogram> + +<histogram name="Webapp.AddToHomescreenDialog.Timeout" units="ms"> + <owner>dominickn@chromium.org</owner> + <summary> + Records the number of milliseconds that the add to homescreen dialog + required to check installability eligibility. + </summary> +</histogram> + +<histogram name="Webapp.Engagement.EngagementType" + enum="SiteEngagementServiceEngagementType"> + <owner>calamity@chromium.org</owner> + <owner>mgiuca@chromium.org</owner> + <summary> + The type of engagement (navigation, user input, etc.) which led to an + accumulation in site engagement within a PWA app window. Should be collected + for a subset of SiteEngagementService.EngagementType, which is triggered for + all browsing contexts. Recorded at the time of engagement accumulation + (e.g., when mouse is clicked). + </summary> +</histogram> + +<histogram name="Webapp.Install.DisplayMode" enum="WebAppDisplayMode"> + <owner>piotrs@chromium.org</owner> + <summary> + Records the display mode (as defined in the Web App Manifest spec) at the + install time of a WebApp (including WebApks). + </summary> +</histogram> + +<histogram name="Webapp.Install.InstallEvent" enum="WebappInstallSource"> + <owner>dominickn@chromium.org</owner> + <owner>mcgreevy@chromium.org</owner> + <summary> + Records the mechanism and source from which a web app installation was + triggered, regardless of whether the installation was successful. + </summary> +</histogram> + +<histogram name="Webapp.Install.InstallSource" enum="WebAppInstallSource"> + <obsolete> + Deprecated 2018-01 in favour of Webapp.Install.InstallEvent. + </obsolete> + <owner>mcgreevy@chromium.org</owner> + <summary> + Records the mechanism by which a web app installation was triggered, + regardless of whether the installation was successful. + </summary> +</histogram> + <histogram name="Webapp.InstallabilityCheckStatus.AddToHomescreenTimeout" enum="AddToHomescreenTimeoutStatus"> <owner>dominickn@chromium.org</owner> @@ -88809,6 +97366,44 @@ </summary> </histogram> +<histogram name="WebAudio.AudioParam.ValueSetterConflictCount"> + <obsolete> + Removed 02/2018 in Issue 764396. Information no longer needed or recorded. + </obsolete> + <owner>rtoy@chromium.org</owner> + <owner>hongchan@chromium.org</owner> + <summary> + The number of times the AudioParam value setter was called that also + conflicts with an ongoing AudioParam automation. Updated when the realtime + AudioContext is closed. + </summary> +</histogram> + +<histogram name="WebAudio.AudioParam.ValueSetterConflictPercentage"> + <obsolete> + Removed 02/2018 in Issue 764396. Information no longer needed or recorded. + </obsolete> + <owner>rtoy@chromium.org</owner> + <owner>hongchan@chromium.org</owner> + <summary> + The percentage of number of calls to an AudioParam value setter that + conflicts with an ongoing AudioParam automation to the total number of calls + to the value setter. Updated once when an AudioContext is closed. + </summary> +</histogram> + +<histogram name="WebAudio.AudioParam.ValueSetterCount"> + <obsolete> + Removed 02/2018 in Issue 764396. Information no longer needed or recorded. + </obsolete> + <owner>rtoy@chromium.org</owner> + <owner>hongchan@chromium.org</owner> + <summary> + The number of times the AudioParam value setter was called per tab. Updated + when the realtime AudioContext is closed. + </summary> +</histogram> + <histogram name="WebAudio.Autoplay" enum="WebAudioAutoplayStatus"> <owner>mlamouri@chromium.org</owner> <owner>media-dev@chromium.org</owner> @@ -88829,6 +97424,9 @@ </histogram> <histogram name="WebAudio.BiquadFilter.Q.Highpass"> + <obsolete> + Removed in Issue 774526 on 2017/10; statistics aren't needed anymore. + </obsolete> <owner>rtoy@chromium.org</owner> <owner>hongchan@chromium.org</owner> <summary> @@ -88840,6 +97438,9 @@ </histogram> <histogram name="WebAudio.BiquadFilter.Q.Lowpass"> + <obsolete> + Removed in Issue 774526 on 2017/10; statistics aren't needed anymore. + </obsolete> <owner>rtoy@chromium.org</owner> <owner>hongchan@chromium.org</owner> <summary> @@ -89008,6 +97609,15 @@ </summary> </histogram> +<histogram name="WebController.WKWebViewHasCertForSecureConnection" + enum="BooleanHasCert"> + <owner>eugenebut@google.com</owner> + <summary> + Whether or not WKWebView has provided a valid -certificateChain when loaded + a page over a secure connection. + </summary> +</histogram> + <histogram name="WebCore.Animation.CSSProperties" enum="MappedCSSProperties"> <owner>ajuma@chromium.org</owner> <summary> @@ -89052,11 +97662,12 @@ </histogram> <histogram name="WebCore.FeatureObserver" enum="FeatureObserver"> + <obsolete> + As of M57 this has been superseded by Blink.UseCounter.Features which fixes + a number of issues. See https://crbug.com/676837. + </obsolete> <owner>rbyers@chromium.org</owner> <summary> - NOTE: As of M57 this has been superseded by Blink.UseCounter.Features which - fixes a number of issues. See https://crbug.com/676837. - Count of how many page loads use various features. The PageVisits bucket is incremented for each page load, and the other buckets incremented at most once per PageVisit via the WebCore::UseCounter class. @@ -89065,37 +97676,17 @@ <histogram name="WebCore.FeatureObserver.CSSProperties" enum="MappedCSSProperties"> + <obsolete> + As of M57 this has been superseded by Blink.UseCounter.CSSProperties which + fixes a number of issues. See https://crbug.com/676837. + </obsolete> <owner>mikelawther@chromium.org</owner> <summary> - NOTE: As of M57 this has been superseded by Blink.UseCounter.Features which - fixes a number of issues. See https://crbug.com/676837. - Records usage of CSS properties used on a page, either statically or dynamically, from the time the page is initialised to when it is closed or navigated away from. Each property is counted at most once per page per view. </summary> - <details> - Every time a CSS property is parsed on a page, that property is recorded as - having been used. The histogram is updated with this data whenever a page is - closed, or a page navigation happens. Each histogram bucket corresponds to a - CSS property (eg width, border-radius). The exception is the bucket numbered - '1' - this counts the number of pages that CSS properties were counted on. - - These numbers give the percentage of pages that use a CSS property. For - example, if the 'border-radius' histogram bucket has a count of 250, and the - page count bucket (i.e. bucket number 1) has a count of 1000 - this means - that 1000 pages were recorded, and border-radius was used on 25% of those - pages. - - Internally, each WebCore::Page has a WebCore::UseCounter instance, with - booleans recording use of each CSS property - one boolean per property. Upon - destruction of the WebCore::Page (e.g. by the user closing the tab), or a - page navigation happening, the histogram is updated. For each boolean that - is set to True, the corresponding histogram bucket for that CSS property is - incremented by 1. The page count bucket (i.e. bucket number 1) is always - incremented by 1 on each histogram update. - </details> </histogram> <histogram name="WebCore.Framebust" enum="FramebustPermissions"> @@ -89175,9 +97766,9 @@ </summary> </histogram> -<histogram name="WebCore.IndexedDB.Context.ForcedCloseReason" +<histogram name="WebCore.IndexedDB.Context.ForceCloseReason" enum="IDBContextForcedCloseReason"> - <owner>dgrogan@chromium.org</owner> + <owner>cmumford@chromium.org</owner> <summary>The reason that a forced-close of a backing store occurred.</summary> </histogram> @@ -89190,6 +97781,15 @@ </summary> </histogram> +<histogram name="WebCore.IndexedDB.DestroyCorruptBackingStoreStatus" + enum="LevelDBStatus"> + <owner>cmumford@chromium.org</owner> + <summary> + Count of the results when attempting to destroy a corrupt Indexed DB backing + store. + </summary> +</histogram> + <histogram name="WebCore.IndexedDB.FrontEndAPICalls" enum="IndexedDatabaseMethods"> <owner>dgrogan@chromium.org</owner> @@ -89294,7 +97894,7 @@ </histogram> <histogram name="WebCore.IndexedDB.LevelDBOpenErrors.Errno" - enum="OSAgnosticErrno"> + enum="PopularOSErrno"> <obsolete> Deprecated 2015-05. As of M43 use WebCore.IndexedDB.LevelDBOpenErrors.BFE. </obsolete> @@ -89350,7 +97950,7 @@ </histogram> <histogram name="WebCore.IndexedDB.LevelDBReadErrors.Errno" - enum="OSAgnosticErrno"> + enum="PopularOSErrno"> <obsolete> Deprecated 2015-05. As of M43 use WebCore.IndexedDB.LevelDBReadErrors.BFE. </obsolete> @@ -89407,7 +98007,7 @@ </histogram> <histogram name="WebCore.IndexedDB.LevelDBWriteErrors.Errno" - enum="OSAgnosticErrno"> + enum="PopularOSErrno"> <obsolete> Deprecated 2015-05. As of M43 use WebCore.IndexedDB.LevelDBWriteErrors.BFE. </obsolete> @@ -89569,6 +98169,114 @@ </summary> </histogram> +<histogram name="WebCore.IndexedDB.TombstoneSweeper.DeletedTombstonesSize" + units="bytes"> + <owner>dmurph@chromium.org</owner> + <summary> + Records the total size of tombstones deleted by the IndexedDB Tombstone + Sweeper. Recorded on the browser side (back end) when the sweeper has + completed scanning and it is in the 'deletion' mode. See + https://goo.gl/coKwA7. + </summary> +</histogram> + +<histogram + name="WebCore.IndexedDB.TombstoneSweeper.DeletionCommitTime.Complete" + units="ms"> + <owner>dmurph@chromium.org</owner> + <summary> + Records the time it takes for the IndexedDB Tombstone Sweeper to commit + tombstone deletions. Recorded on the browser side (back end) when the + sweeper has completed a round of sweeping and, it's in 'deletion' mode, and + it has tombstones to delete. See https://goo.gl/coKwA7. + </summary> +</histogram> + +<histogram name="WebCore.IndexedDB.TombstoneSweeper.DeletionTotalTime.Complete" + units="ms"> + <owner>dmurph@chromium.org</owner> + <summary> + Records the time it takes for the IndexedDB Tombstone Sweeper to fully sweep + the indexes. Recorded on the browser side (back end) when the sweeper has + completed sweeping all indexes (so partial sweeps are not recorded) and it + is in 'deletion' mode. See https://goo.gl/coKwA7. + </summary> +</histogram> + +<histogram name="WebCore.IndexedDB.TombstoneSweeper.DeletionWriteError" + units="LevelDBStatus"> + <owner>dmurph@chromium.org</owner> + <summary> + Records when an error occurs during deletion of index tombstones by the + IndexedDB Tombstone Sweeper. Recorded on the browser side (back end) when + the sweeper has completed a round of sweeping and, it's in 'deletion' mode, + and it has tombstones to delete. See https://goo.gl/coKwA7. + </summary> +</histogram> + +<histogram name="WebCore.IndexedDB.TombstoneSweeper.IndexScanPercent" + units="%/5"> + <owner>dmurph@chromium.org</owner> + <summary> + Recorded on the browser side (back end) when the IndexedDB Tombstone Sweeper + has completed scanning. Records the percentage of the indexes the scanner + fully scanned before it was stopped. To reduce the number of buckets, the + recorded value is the percentage divided by 5. See https://goo.gl/coKwA7. + </summary> +</histogram> + +<histogram name="WebCore.IndexedDB.TombstoneSweeper.NumDeletedTombstones" + units="Index Tombstones"> + <owner>dmurph@chromium.org</owner> + <summary> + Records the number of tombstones deleted by the IndexedDB Tombstone Sweeper. + Recorded on the browser side (back end) when the sweeper has completed + scanning and it is in 'deletion' mode. See https://goo.gl/coKwA7. + </summary> +</histogram> + +<histogram name="WebCore.IndexedDB.TombstoneSweeper.NumTombstones" + units="Index Tombstones"> + <owner>dmurph@chromium.org</owner> + <summary> + Records the number of tombstones encountered by the IndexedDB Tombstone + Sweeper. Recorded on the browser side (back end) when the sweeper has + completed scanning and it is in 'statistics' mode. See + https://goo.gl/coKwA7. + </summary> +</histogram> + +<histogram name="WebCore.IndexedDB.TombstoneSweeper.StatsTotalTime.Complete" + units="ms"> + <owner>dmurph@chromium.org</owner> + <summary> + Records the time it takes for the IndexedDB Tombstone Sweeper to fully scan + the indexes. Recorded on the browser side (back end) when the sweeper has + completed scanning all indexes (so partial scans are not recorded) and it is + in 'statistics' mode. See https://goo.gl/coKwA7. + </summary> +</histogram> + +<histogram name="WebCore.IndexedDB.TombstoneSweeper.SweepError" + enum="LevelDBStatus"> + <owner>dmurph@chromium.org</owner> + <summary> + Recorded on the browser side (back end) when the IndexedDB Tombstone Sweeper + encounters an error while sweeping. See https://goo.gl/coKwA7. + </summary> +</histogram> + +<histogram name="WebCore.IndexedDB.TombstoneSweeper.TombstonesSize" + units="bytes"> + <owner>dmurph@chromium.org</owner> + <summary> + Records the total size of tombstones encountered by the IndexedDB Tombstone + Sweeper. Recorded on the browser side (back end) when the sweeper has + completed scanning and it is in the 'statistics' mode. See + https://goo.gl/coKwA7. + </summary> +</histogram> + <histogram name="WebCore.IndexedDB.Transaction.ReadOnly.SizeOnCommit" units="KB"> <obsolete> @@ -89682,6 +98390,10 @@ </histogram> <histogram name="WebCore.PreloadDelayMs" units="ms"> + <obsolete> + Deprecated, preloads are issued on the main thread now, so this is less + useful. + </obsolete> <owner>csharrison@chromium.org</owner> <summary> The delay between when the preload scanner discovers a resource on the @@ -89755,6 +98467,9 @@ <histogram name="WebCore.ScriptedIdleTaskController.IdleCallbackDeadline" units="ms"> + <obsolete> + Deprecated November 2017. + </obsolete> <owner>rmcilroy@chromium.org</owner> <summary> The amount of time allotted to a requestIdleCallback callback, i.e., the @@ -90154,6 +98869,9 @@ </histogram> <histogram name="WebFont.InterventionResult" enum="WebFontInterventionResult"> + <obsolete> + Deprecated 10/2017. Related field trial has finished rolling out. + </obsolete> <owner>toyoshim@chromium.org</owner> <owner>kenjibaheux@chromium.org</owner> <summary> @@ -90166,6 +98884,9 @@ <histogram name="WebFont.InterventionResult.MissedCache" enum="WebFontInterventionResult"> + <obsolete> + Deprecated 10/2017. Related field trial has finished rolling out. + </obsolete> <owner>toyoshim@chromium.org</owner> <owner>kenjibaheux@chromium.org</owner> <summary> @@ -90406,6 +99127,14 @@ </summary> </histogram> +<histogram name="WebP.DecodedImageFormat" enum="WebpDecodedFormat"> + <owner>droger@chromium.org</owner> + <summary> + Histogram for the format of decoded WebP images on iOS, as Chrome re-encodes + WebP images on that platform. + </summary> +</histogram> + <histogram name="WebRTC.AecDelayBasedQuality" enum="DelayBasedEchoQuality"> <owner>hlundin@chromium.org</owner> <summary> @@ -90666,6 +99395,15 @@ </summary> </histogram> +<histogram name="WebRTC.Audio.EchoCanceller.Erl" units="dB (shifted)"> + <owner>gustaf@chromium.org</owner> + <summary> + This histogram logs the echo return loss achieved by the WebRTC echo + canceller as described in ITU G.168. When the echo canceller is being used, + one value is logged every 10 seconds per ongoing WebRTC call. + </summary> +</histogram> + <histogram name="WebRTC.Audio.EchoCanceller.ErlBand0" units="dB (shifted)"> <owner>peah@chromium.org</owner> <summary> @@ -90682,6 +99420,15 @@ </summary> </histogram> +<histogram name="WebRTC.Audio.EchoCanceller.Erle" units="dB"> + <owner>gustaf@chromium.org</owner> + <summary> + This histogram logs the echo return loss enhancement achieved by the WebRTC + echo canceller as described in ITU G.168. When the echo canceller is being + used, one value is logged every 10 seconds per ongoing WebRTC call. + </summary> +</histogram> + <histogram name="WebRTC.Audio.EchoCanceller.ErleBand0" units="dB (shifted)"> <owner>peah@chromium.org</owner> <summary> @@ -90825,6 +99572,33 @@ </summary> </histogram> +<histogram name="WebRTC.Audio.ReceiverDelayEstimateMs" units="ms"> + <owner>hlundin@chromium.org</owner> + <summary> + The sum of the jitter buffer delay and the sound card's buffering delay for + the receiving side. That is, the sum of the metrics + WebRTC.Audio.ReceiverDeviceDelayMs and + WebRTC.Audio.ReceiverJitterBufferDelayMs. Sampled once every 10 ms when + WebRTC audio is playing. + </summary> +</histogram> + +<histogram name="WebRTC.Audio.ReceiverDeviceDelayMs" units="ms"> + <owner>hlundin@chromium.org</owner> + <summary> + The sound card's buffering delay for the receiving side. Sampled once every + 10 ms when WebRTC audio is playing. + </summary> +</histogram> + +<histogram name="WebRTC.Audio.ReceiverJitterBufferDelayMs" units="ms"> + <owner>hlundin@chromium.org</owner> + <summary> + The jitter buffer delay for the receiving side. Sampled once every 10 ms + when WebRTC audio is playing. + </summary> +</histogram> + <histogram name="WebRTC.Audio.ResidualEchoDetector.EchoLikelihood" units="%"> <owner>hlundin@chromium.org</owner> <owner>ivoc@chromium.org</owner> @@ -90845,6 +99619,14 @@ </summary> </histogram> +<histogram name="WebRTC.Audio.TargetJitterBufferDelayMs" units="ms"> + <owner>hlundin@chromium.org</owner> + <summary> + The target jitter buffer delay for the receiving side. Sampled once every 10 + ms per WebRTC receive stream when WebRTC audio is playing. + </summary> +</histogram> + <histogram name="WebRTC.AudioCaptureTime" units="ms"> <obsolete> Removed from code 2014/2/25. @@ -91286,6 +100068,15 @@ </summary> </histogram> +<histogram name="WebRTC.PeerConnection.KeyProtocol" + enum="PeerConnectionKeyProtocol"> + <owner>hta@chromium.org</owner> + <summary> + What key exchange protocol (DTLS or SDES) is used to establish the crypto + keys for a PeerConnection's RTP transport. + </summary> +</histogram> + <histogram name="WebRTC.PeerConnection.RtcpMux" enum="PeerConnectionRtcpMux"> <owner>pthatcher@chromium.org</owner> <summary> @@ -91475,12 +100266,24 @@ <histogram name="WebRTC.UserMediaRequest.Result" enum="MediaStreamRequestResult"> + <obsolete> + Replaced by WebRTC.UserMediaRequest.Result2 in Feb 2018. + </obsolete> <owner>andresp@chromium.org</owner> <summary> Counters for UserMediaRequests results such as failure reasons. </summary> </histogram> +<histogram name="WebRTC.UserMediaRequest.Result2" + enum="MediaStreamRequestResult2"> + <owner>grunell@chromium.org</owner> + <summary> + Counters for UserMediaRequests results such as failure reasons. The standard + specification error names are in parenthesis. + </summary> +</histogram> + <histogram name="WebRTC.Video.AdaptChangesPerMinute" units="changes/minute"> <owner>asapersson@chromium.org</owner> <summary> @@ -91646,6 +100449,38 @@ </summary> </histogram> +<histogram name="WebRTC.Video.DroppedFrames.Capturer" units="frames"> + <owner>ilnik@chromium.org</owner> + <summary> + Total number of frames dropped by a capturer for a sent video stream. + Recorded when a stream is removed. + </summary> +</histogram> + +<histogram name="WebRTC.Video.DroppedFrames.Encoder" units="frames"> + <owner>ilnik@chromium.org</owner> + <summary> + Total number of frames dropped by an encoder's internal rate limiter for a + sent video stream. Recorded when a stream is removed. + </summary> +</histogram> + +<histogram name="WebRTC.Video.DroppedFrames.EncoderQueue" units="frames"> + <owner>ilnik@chromium.org</owner> + <summary> + Total number of frames dropped because encoder queue is full for a sent + video stream. Recorded when a stream is removed. + </summary> +</histogram> + +<histogram name="WebRTC.Video.DroppedFrames.Ratelimiter" units="frames"> + <owner>ilnik@chromium.org</owner> + <summary> + Total number of frames dropped by a WebRTC rate limiter (in MediaOpt) for a + sent video stream. Recorded when a stream is removed. + </summary> +</histogram> + <histogram name="WebRTC.Video.DuplicatedPacketsInPercent" units="%"> <owner>asapersson@chromium.org</owner> <summary> @@ -91783,6 +100618,14 @@ </summary> </histogram> +<histogram name="WebRTC.Video.InterframeDelay95PercentileInMs" units="ms"> + <owner>ilnik@chromium.org</owner> + <summary> + The 95th percentile of interframe delay for a received video stream. + Recorded when a stream is removed. + </summary> +</histogram> + <histogram name="WebRTC.Video.InterframeDelayInMs" units="ms"> <owner>ilnik@chromium.org</owner> <summary> @@ -92088,6 +100931,41 @@ </summary> </histogram> +<histogram name="WebRTC.Video.Screenshare.DroppedFrames.Capturer" + units="frames"> + <owner>ilnik@chromium.org</owner> + <summary> + Total number of frames dropped by a capturer for a sent screenshare stream. + Recorded when a stream is removed. + </summary> +</histogram> + +<histogram name="WebRTC.Video.Screenshare.DroppedFrames.Encoder" units="frames"> + <owner>ilnik@chromium.org</owner> + <summary> + Total number of frames dropped by an encoder's internal rate limiter for a + sent screenshare stream. Recorded when a stream is removed. + </summary> +</histogram> + +<histogram name="WebRTC.Video.Screenshare.DroppedFrames.EncoderQueue" + units="frames"> + <owner>ilnik@chromium.org</owner> + <summary> + Total number of frames dropped because encoder queue is full for a sent + screenshare stream. Recorded when a stream is removed. + </summary> +</histogram> + +<histogram name="WebRTC.Video.Screenshare.DroppedFrames.Ratelimiter" + units="frames"> + <owner>ilnik@chromium.org</owner> + <summary> + Total number of frames dropped by a WebRTC rate limiter (in MediaOpt) for a + sent screenshare stream. Recorded when a stream is removed. + </summary> +</histogram> + <histogram name="WebRTC.Video.Screenshare.EncodeTimeInMs" units="ms"> <owner>sprang@chromium.org</owner> <summary> @@ -92176,6 +101054,15 @@ </summary> </histogram> +<histogram name="WebRTC.Video.Screenshare.InterframeDelay95PercentileInMs" + units="ms"> + <owner>ilnik@chromium.org</owner> + <summary> + The 95th percentile of interframe delay for a received screenshare stream. + Recorded when a stream is removed. + </summary> +</histogram> + <histogram name="WebRTC.Video.Screenshare.InterframeDelayInMs" units="ms"> <owner>ilnik@chromium.org</owner> <summary> @@ -92592,7 +101479,7 @@ </histogram> <histogram name="WebsiteSettings.Action" enum="WebsiteSettingsAction"> - <owner>lgarron@chromium.org</owner> + <owner>estark@chromium.org</owner> <summary> Tracks actions with the website setting (a.k.a. page info / origin info) bubble, such as opening it up or clicking on the Connection tab. @@ -92605,7 +101492,7 @@ Security.PageInfo.Action.HttpsUrl.Dangerous, and Security.PageInfo.Action.HttpsUrl.Downgraded. </obsolete> - <owner>lgarron@chromium.org</owner> + <owner>estark@chromium.org</owner> <summary> Tracks WebsiteSettings actions that take place on an HTTPS URL. This completely disregards security status. @@ -92717,7 +101604,6 @@ Deprecated 12/2014 in Issue 433776, and replaced by WebsiteSettings.OriginInfo.PermissionChanged. </obsolete> - <owner>lgarron@chromium.org</owner> <owner>sashab@chromium.org</owner> <summary> Count of how often a specific content type (permission) is changed using the @@ -92836,6 +101722,14 @@ </summary> </histogram> +<histogram name="WebView.LoadDataWithBaseUrl.HistoryUrl" enum="HistoryUrlType"> + <owner>jamwalla@chromium.org</owner> + <summary> + Records whether the historyUrl parameter to loadDataWithBaseUrl is empty/ + null, the same as the baseUrl parameter, or different from baseUrl. + </summary> +</histogram> + <histogram name="Welcome.SignInPromptResult" enum="WelcomeSignInPromptOutcome"> <owner>tmartino@chromium.org</owner> <summary> @@ -92891,6 +101785,15 @@ </summary> </histogram> +<histogram name="WheelScrolling.WasLatched" enum="BooleanLatched"> + <owner>sahel@chromium.org</owner> + <summary> + Records whether or not a GSU event with wheel source is latched to the + current scrolling element. It is false for the first GSU event of every + scrolling sequence and true for the rest of the GSU events. + </summary> +</histogram> + <histogram name="Win8.PageLoad" enum="Win8PageLoadType"> <owner>zturner@chromium.org</owner> <summary> @@ -92952,6 +101855,14 @@ </summary> </histogram> +<histogram name="Windows.HasHighResolutionTimeTicks" enum="Boolean"> + <owner>gab@chromium.org</owner> + <summary> + The value of TimeTicks::IsHighResolution(). Reported once per browser + session, on startup. + </summary> +</histogram> + <histogram name="Windows.HighResolutionTimerUsage" units="%"> <owner>stanisc@chromium.org</owner> <summary> @@ -93372,6 +102283,9 @@ </histogram> <histogram name="WorkerThread.DebuggerTask.Time" units="ms"> + <obsolete> + Deprecated on 2018-02. + </obsolete> <owner>nhiroki@chromium.org</owner> <summary>The time taken for running a debugger task on WorkerThread.</summary> </histogram> @@ -93391,6 +102305,9 @@ </histogram> <histogram name="WorkerThread.Task.Time" units="ms"> + <obsolete> + Deprecated on 2018-02. The sample count was overflowing. crbug.com/809672. + </obsolete> <owner>nhiroki@chromium.org</owner> <summary>The time taken for running a worker task on WorkerThread.</summary> </histogram> @@ -93434,6 +102351,37 @@ </summary> </histogram> +<histogram name="XHR.Async.PageDismissal" enum="XHRPageDismissalState"> + <owner>panicker@chromium.org</owner> + <summary> + Records occurence of async XHR during page dismissal state (unload, + beforeunload, pagehide etc). + </summary> +</histogram> + +<histogram name="XHR.Sync.PageDismissal" enum="XHRPageDismissalState"> + <owner>panicker@chromium.org</owner> + <summary> + Records occurence of sync XHR during page dismissal state (unload, + beforeunload, pagehide etc). + </summary> +</histogram> + +<histogram name="XR.RuntimeAvailable" enum="XRRuntimeAvailable"> + <owner>billorr@chromium.org</owner> + <summary> + Indicates which VR APIs are installed. Recorded shortly after startup. + </summary> +</histogram> + +<histogram name="XR.WebXR.RenderPath.Used" enum="XRRenderPath"> + <owner>klausw@chromium.org</owner> + <summary> + Records the WebXR/WebVR render path used for presentation on presentation + start. The render path is affected by overrides and device capabilities. + </summary> +</histogram> + <histogram name="ZeroSuggest.AllResults"> <owner>hfung@chromium.org</owner> <summary> @@ -93656,6 +102604,19 @@ <affected-histogram name="Apps.AppsInFolders"/> </histogram_suffixes> +<histogram_suffixes name="AppUIComponent" separator="."> + <suffix name="Desktop" label="Desktop"/> + <suffix name="SearchResult" label="Launcher App Search Result"/> + <suffix name="Shelf" label="Shelf"/> + <suffix name="ShelfButton" label="ShelfButton"/> + <suffix name="SuggestedAppPeeking" label="Suggested App, Peeking Launcher"/> + <suffix name="SuggestedAppFullscreen" + label="Suggested App, Fullscreen Launcher"/> + <suffix name="AppGrid" label="App - Fullscreen Launcher"/> + <affected-histogram name="Apps.ContextMenuShowSource"/> + <affected-histogram name="Apps.ContextMenuUserJourneyTime"/> +</histogram_suffixes> + <histogram_suffixes name="ArcUserTypes" separator="."> <suffix name="Managed" label="User with forced Play Store feature"/> <suffix name="Unmanaged" label="User with optional Play Store feature"/> @@ -93728,6 +102689,18 @@ <affected-histogram name="Autofill.FieldPredictionQuality.ByFieldType"/> </histogram_suffixes> +<histogram_suffixes name="AutofillFormType" separator="."> + <suffix name="Address" label="Address form"/> + <suffix name="CreditCard" label="Credit card form"/> + <suffix name="Password" label="Password form"/> + <suffix name="Unknown" label="Unknown form type"/> + <affected-histogram + name="Autofill.FillDuration.FromInteraction.WithAutofill"/> + <affected-histogram + name="Autofill.FillDuration.FromInteraction.WithoutAutofill"/> + <affected-histogram name="Autofill.UserHappiness"/> +</histogram_suffixes> + <histogram_suffixes name="AutofillPayloadCompressionType" separator="."> <suffix name="Query" label="Query request compression"/> <suffix name="Upload" label="Upload request compression"/> @@ -93896,6 +102869,7 @@ <histogram_suffixes name="BlinkCanvasDrawImageType" separator="."> <suffix name="Canvas"/> <suffix name="ImageBitmap"/> + <suffix name="OffscreenCanvas"/> <suffix name="Others"/> <suffix name="SVG"/> <suffix name="Video"/> @@ -93904,10 +102878,15 @@ <histogram_suffixes name="BlinkCanvasDurationBySource" separator="."> <suffix name="CPU"/> - <suffix name="DisplayList"/> + <suffix name="DisplayList"> + <obsolete> + Deprecated 11/2017 with removal of Display List Canvas 2D mode. + </obsolete> + </suffix> <suffix name="GPU"/> <affected-histogram name="Blink.Canvas.DrawImage.Canvas"/> <affected-histogram name="Blink.Canvas.DrawImage.ImageBitmap"/> + <affected-histogram name="Blink.Canvas.DrawImage.OffscreenCanvas"/> <affected-histogram name="Blink.Canvas.DrawImage.Others"/> <affected-histogram name="Blink.Canvas.DrawImage.SVG"/> <affected-histogram name="Blink.Canvas.DrawImage.Video"/> @@ -93930,7 +102909,12 @@ <histogram_suffixes name="BlinkCanvasToBlobIdleEncodAndDelayType" separator="."> <suffix name="JPEG"/> <suffix name="PNG"/> - <affected-histogram name="Blink.Canvas.ToBlob.IdleEncodeDuration"/> + <affected-histogram name="Blink.Canvas.ToBlob.CompleteEncodingDelay"/> + <affected-histogram name="Blink.Canvas.ToBlob.IdleEncodeDuration"> + <obsolete> + Replaced with Blink.Canvas.ToBlob.CompleteEncodingDelay in 2017/12. + </obsolete> + </affected-histogram> <affected-histogram name="Blink.Canvas.ToBlob.InitiateEncodingDelay"/> </histogram_suffixes> @@ -93996,6 +102980,7 @@ <suffix name="Resident" label="Only counting resident memory."/> <suffix name="PrivateMemoryFootprint" label="Only counting private resident + swapped/compressed memory."/> + <suffix name="SharedMemoryFootprint" label="Only counting shared memory."/> <suffix name="Malloc" label="Constrained to malloc allocator."/> <affected-histogram name="Memory.Experimental.Browser2"/> </histogram_suffixes> @@ -94038,7 +103023,10 @@ <affected-histogram name="SimpleCache.CreationToIndexFail"/> <affected-histogram name="SimpleCache.DiskCloseLatency"/> <affected-histogram name="SimpleCache.DiskCreateLatency"/> + <affected-histogram name="SimpleCache.DiskDoomLatency"/> <affected-histogram name="SimpleCache.DiskOpenLatency"/> + <affected-histogram name="SimpleCache.DiskOpenStream2NonTinyLatency"/> + <affected-histogram name="SimpleCache.DiskOpenStream2TinyLatency"/> <affected-histogram name="SimpleCache.DiskWriteLatency"/> <affected-histogram name="SimpleCache.EntryCreatedAndStream2Omitted"/> <affected-histogram name="SimpleCache.EntryCreationResult"/> @@ -94057,9 +103045,21 @@ <affected-histogram name="SimpleCache.Eviction.SizeWhenDone2"/> <affected-histogram name="SimpleCache.Eviction.TimeToDone"/> <affected-histogram name="SimpleCache.Eviction.TimeToSelectEntries"/> - <affected-histogram name="SimpleCache.FileDescriptorLimitHard"/> - <affected-histogram name="SimpleCache.FileDescriptorLimitSoft"/> - <affected-histogram name="SimpleCache.FileDescriptorLimitStatus"/> + <affected-histogram name="SimpleCache.FileDescriptorLimitHard"> + <obsolete> + Removed January 2018, as the limit is independent of the backend type. + </obsolete> + </affected-histogram> + <affected-histogram name="SimpleCache.FileDescriptorLimitSoft"> + <obsolete> + Removed January 2018, as the limit is independent of the backend type. + </obsolete> + </affected-histogram> + <affected-histogram name="SimpleCache.FileDescriptorLimitStatus"> + <obsolete> + Removed January 2018, as the limit is independent of the backend type. + </obsolete> + </affected-histogram> <affected-histogram name="SimpleCache.GlobalOpenEntryCount"/> <affected-histogram name="SimpleCache.HeaderSize"/> <affected-histogram name="SimpleCache.HeaderSizeChange"/> @@ -94088,10 +103088,12 @@ <affected-histogram name="SimpleCache.LastClusterLossPercent"/> <affected-histogram name="SimpleCache.LastClusterSize"/> <affected-histogram name="SimpleCache.MaxCacheSizeOnInit"/> + <affected-histogram name="SimpleCache.NumOpsBlockedByPendingDoom"/> <affected-histogram name="SimpleCache.OpenEntryIndexState"/> <affected-histogram name="SimpleCache.PercentFullOnInit"/> <affected-histogram name="SimpleCache.QueueLatency.CreateEntry"/> <affected-histogram name="SimpleCache.QueueLatency.OpenEntry"/> + <affected-histogram name="SimpleCache.QueueLatency.PendingDoom"/> <affected-histogram name="SimpleCache.ReadIsParallelizable"/> <affected-histogram name="SimpleCache.ReadResult"/> <affected-histogram name="SimpleCache.ReadStream1FromPrefetched"/> @@ -94214,6 +103216,16 @@ <affected-histogram name="Canvas.RequestedImageMimeTypes"/> </histogram_suffixes> +<histogram_suffixes name="CertificateTransparencyProtocol" separator="."> + <suffix name="QUIC"/> + <suffix name="SSL"/> + <affected-histogram + name="Net.CertificateTransparency.ConnectionComplianceStatus2"/> + <affected-histogram + name="Net.CertificateTransparency.CTRequiredConnectionComplianceStatus2"/> + <affected-histogram name="Net.CertificateTransparency.EVCompliance2"/> +</histogram_suffixes> + <histogram_suffixes name="CertificateTypeAlgorithms" separator="."> <owner>rsleevi@chromium.org</owner> <suffix name="DH" label="DH"/> @@ -94316,6 +103328,19 @@ <affected-histogram name="SoftwareReporter.PromptDialog.TimeUntilDone"/> </histogram_suffixes> +<histogram_suffixes name="ChromeCleanerFetchCompletedReason" separator="_"> + <suffix name="DownloadFailure" + label="Download failed without an OK HTTP response code."/> + <suffix name="DownloadSuccess" label="Download succeeded."/> + <suffix name="NetworkError" label="Download failed due to a network error."/> + <affected-histogram name="SoftwareReporter.Cleaner.NumberOfDownloadAttempts"> + <obsolete> + Removed Jan 2018 + </obsolete> + </affected-histogram> + <affected-histogram name="SoftwareReporter.Cleaner.TimeToCompleteDownload"/> +</histogram_suffixes> + <histogram_suffixes name="ChromeContentBrowserClientMetricSuffixes" separator="."> <suffix name="search" @@ -94393,6 +103418,10 @@ <affected-histogram name="Scheduling.CommitToReadyToActivateDuration2"/> <affected-histogram name="Scheduling.DrawDuration2"/> <affected-histogram name="Scheduling.DrawInterval2"/> + <affected-histogram name="Scheduling.DrawIntervalWithCompositedAnimations2"/> + <affected-histogram name="Scheduling.DrawIntervalWithMainThreadAnimations2"/> + <affected-histogram + name="Scheduling.DrawIntervalWithMainThreadCompositableAnimations2"/> <affected-histogram name="Scheduling.InvalidationToReadyToActivateDuration2"/> <affected-histogram name="Scheduling.MainAndImplFrameTimeDelta2"/> <affected-histogram name="Scheduling.PrepareTilesDuration2"/> @@ -94405,6 +103434,7 @@ ordering="prefix"> <suffix name="Browser"/> <suffix name="Renderer"/> + <affected-histogram name="Scheduling.ImageInvalidationUpdateDuration"/> <affected-histogram name="Scheduling.PendingTreeDuration"/> <affected-histogram name="Scheduling.PendingTreeRasterDuration"/> </histogram_suffixes> @@ -94574,6 +103604,7 @@ <suffix name="protocol-handler" label="Protocol handler exceptions"/> <suffix name="push-messaging" label="Push messaging exceptions"/> <suffix name="site-engagement" label="Site engagement exceptions"/> + <suffix name="sound" label="Sound exceptions"/> <suffix name="ssl-cert-decisions" label="SSL cert decisions exceptions"/> <suffix name="subresource-filter" label="Subresource filter exceptions"/> <suffix name="usb-chooser-data" label="USB chooser data exceptions"/> @@ -94616,6 +103647,13 @@ <affected-histogram name="NewTabPage.ContentSuggestions.VisitDuration"/> </histogram_suffixes> +<histogram_suffixes name="ContextMenuFromApp" separator="."> + <suffix name="FromApp" label="The source of the context menu was an app."/> + <suffix name="NotFromApp" + label="The source of the context menu was shelf or wallpaper."/> + <affected-histogram name="Apps.ContextMenuExecuteCommand"/> +</histogram_suffixes> + <histogram_suffixes name="ContextMenuType" separator="."> <suffix name="Link" label="The context menu was shown for a (non-image) link"/> @@ -94649,6 +103687,8 @@ label="A VideoCapture GPU command buffer context"/> <suffix name="WebGL" label="A WebGL GPU command buffer context"/> <suffix name="Media" label="The media worker command buffer context"/> + <suffix name="MusClient" label="A mus client command buffer context"/> + <suffix name="UICompositor" label="The UI compositor command buffer context"/> <suffix name="BlimpRenderCompositor" label="BlimpCompositor compositor command buffer context"> <obsolete> @@ -94703,6 +103743,14 @@ <affected-histogram name="Tabs.StateTransfer.Time"/> </histogram_suffixes> +<histogram_suffixes name="CustomTabOpenSource" separator="."> + <affected-histogram name="CustomTab.SessionDuration"/> + <suffix name="TWA" label="CustomTab opened by Trusted Web Activity."/> + <suffix name="Webapp" label="CustomTab opened by Webapp."/> + <suffix name="WebApk" label="CustomTab opened by WebApk."/> + <suffix name="Other" label="CustomTab opened by other apps."/> +</histogram_suffixes> + <histogram_suffixes name="DataReductionProxy" separator="_"> <obsolete> Deprecated 9/2016. @@ -95099,6 +104147,20 @@ <affected-histogram name="Previews.OriginalContentLength"/> </histogram_suffixes> +<histogram_suffixes name="DataSaverProxyTypes" separator="."> + <owner>tbansal@chromium.org</owner> + <suffix name="SecureProxy.Core" + label="Over a secure, core data saver proxy."/> + <suffix name="SecureProxy.NonCore" + label="Over a secure, non-core data saver proxy."/> + <suffix name="InsecureProxy.Core" + label="Over an insecure, core data saver proxy."/> + <suffix name="InsecureProxy.NonCore" + label="Over an insecure, non-core data saver proxy."/> + <affected-histogram + name="DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch"/> +</histogram_suffixes> + <histogram_suffixes name="DataUsageReportSubmissionBytes" separator="."> <suffix name="Failed" label="Platform external data use observer reported the submission as @@ -95147,11 +104209,86 @@ <suffix name="Upstream.Unknown.Cellular"/> <suffix name="Downstream.Unknown.NotCellular"/> <suffix name="Downstream.Unknown.Cellular"/> - <affected-histogram name="DataUse.MessageSize.AllServices"/> <affected-histogram name="DataUse.TrafficSize.System"/> <affected-histogram name="DataUse.TrafficSize.User"/> </histogram_suffixes> +<histogram_suffixes name="DataUse.Dimensions.AllServices" separator="."> + <suffix name="Upstream.Background.NotCellularKB"/> + <suffix name="Upstream.Background.CellularKB"/> + <suffix name="Upstream.Foreground.NotCellularKB"/> + <suffix name="Upstream.Foreground.CellularKB"/> + <suffix name="Downstream.Background.NotCellularKB"/> + <suffix name="Downstream.Background.CellularKB"/> + <suffix name="Downstream.Foreground.NotCellularKB"/> + <suffix name="Downstream.Foreground.CellularKB"/> + <suffix name="Upstream.Unknown.NotCellularKB"/> + <suffix name="Upstream.Unknown.CellularKB"/> + <suffix name="Downstream.Unknown.NotCellularKB"/> + <suffix name="Downstream.Unknown.CellularKB"/> + <suffix name="Upstream.Background.NotCellular"> + <obsolete> + Replaced by KB version in October, 2017. + </obsolete> + </suffix> + <suffix name="Upstream.Background.Cellular"> + <obsolete> + Replaced by KB version in October, 2017. + </obsolete> + </suffix> + <suffix name="Upstream.Foreground.NotCellular"> + <obsolete> + Replaced by KB version in October, 2017. + </obsolete> + </suffix> + <suffix name="Upstream.Foreground.Cellular"> + <obsolete> + Replaced by KB version in October, 2017. + </obsolete> + </suffix> + <suffix name="Downstream.Background.NotCellular"> + <obsolete> + Replaced by KB version in October, 2017. + </obsolete> + </suffix> + <suffix name="Downstream.Background.Cellular"> + <obsolete> + Replaced by KB version in October, 2017. + </obsolete> + </suffix> + <suffix name="Downstream.Foreground.NotCellular"> + <obsolete> + Replaced by KB version in October, 2017. + </obsolete> + </suffix> + <suffix name="Downstream.Foreground.Cellular"> + <obsolete> + Replaced by KB version in October, 2017. + </obsolete> + </suffix> + <suffix name="Upstream.Unknown.NotCellular"> + <obsolete> + Replaced by KB version in October, 2017. + </obsolete> + </suffix> + <suffix name="Upstream.Unknown.Cellular"> + <obsolete> + Replaced by KB version in October, 2017. + </obsolete> + </suffix> + <suffix name="Downstream.Unknown.NotCellular"> + <obsolete> + Replaced by KB version in October, 2017. + </obsolete> + </suffix> + <suffix name="Downstream.Unknown.Cellular"> + <obsolete> + Replaced by KB version in October, 2017. + </obsolete> + </suffix> + <affected-histogram name="DataUse.MessageSize.AllServices"/> +</histogram_suffixes> + <histogram_suffixes name="DataUse.Service.Types" separator="."> <suffix name="NotTagged"/> <suffix name="Suggestions"/> @@ -95271,7 +104408,11 @@ <suffix name="externalrequest" label="Externally triggered prerender."/> <suffix name="externalrequestforced" label="Forced prerender regardless of network."/> - <suffix name="Instant" label="Instant search prerender."/> + <suffix name="Instant" label="Instant search prerender."> + <obsolete> + Deprecated October 2017 + </obsolete> + </suffix> <suffix name="localpredictor" label="Local predictor triggered prerender."> <obsolete> Deprecated April 2015 @@ -95290,7 +104431,11 @@ label="Link triggered prerender, rel=prerender, same domain."/> <suffix name="webnext" label="Link triggered prerender, rel=next."/> <suffix name="offline" - label="Prerender triggered for saving a page for offline use."/> + label="Prerender triggered for saving a page for offline use."> + <obsolete> + Deprecated October 2017 + </obsolete> + </suffix> <affected-histogram name="Prerender.FinalStatus_Prerender5minTTL"/> <affected-histogram name="Prerender.FinalStatus_PrerenderControl"/> <affected-histogram name="Prerender.FinalStatus_PrerenderEnabled"/> @@ -95632,6 +104777,11 @@ <affected-histogram name="Cookie.ReinstatedCookies"/> </histogram_suffixes> +<histogram_suffixes name="Download.Parallelizable" separator="."> + <suffix name="Parallelizable" label="Parallelizable download."/> + <affected-histogram name="Download.DownloadSize"/> +</histogram_suffixes> + <histogram_suffixes name="Download.Service.CleanUpReason" separator="."> <suffix name="Timeout" label="File is deleted after timeout."/> <suffix name="Orphaned" label="No client associated with the file."/> @@ -95644,6 +104794,8 @@ <histogram_suffixes name="Download.Service.Client" separator="."> <suffix name="OfflinePage" label="Offline page prefetch."/> + <suffix name="BackgroundFetch" label="Background fetch."/> + <suffix name="Debugging" label="Debugging client."/> <affected-histogram name="Download.Service.Request.ClientAction"/> <affected-histogram name="Download.Service.Request.StartResponse"/> <affected-histogram name="Download.Service.Request.StartResult"/> @@ -95680,6 +104832,14 @@ <affected-histogram name="Download.Service.TaskScheduler.Status"/> </histogram_suffixes> +<histogram_suffixes name="DownloadableStringsTimeouts" separator="."> + <suffix name="RetryLater" label="Failed with RETRY_LATER error."/> + <suffix name="ServiceError" label="Failed with SERVICE_ERROR error."/> + <suffix name="UpdateCheckError" + label="Failed with UPDATE_CHECK_ERROR error."/> + <affected-histogram name="DownloadableStrings.Timeout"/> +</histogram_suffixes> + <histogram_suffixes name="DownloadDangerPromptResponse" separator="."> <suffix name="Proceed" label="The user clicked through and recovered the download."/> @@ -95702,6 +104862,28 @@ <affected-histogram name="Download.DownloadDangerPrompt"/> </histogram_suffixes> +<histogram_suffixes name="DownloadSource" separator="."> + <suffix name="UnknownSource" label="UnknownSource."/> + <suffix name="Navigation" label="Navigation."/> + <suffix name="DragAndDrop" label="DragAndDrop."/> + <suffix name="FromRenderer" label="FromRenderer."/> + <suffix name="ExtensionAPI" label="ExtensionAPI."/> + <suffix name="ExtensionInstaller" label="ExtensionInstaller."/> + <suffix name="InternalAPI" label="InternalAPI."/> + <suffix name="WebContentsAPI" label="WebContentsAPI."/> + <suffix name="OfflinePage" label="OfflinePage."/> + <suffix name="ContextMenu" label="ContextMenu."/> + <affected-histogram name="Download.Counts"/> + <affected-histogram name="Download.InterruptedReason"/> +</histogram_suffixes> + +<histogram_suffixes name="DownloadType" separator="."> + <suffix name="Transient" label="Transient download."/> + <suffix name="UserDownload" label="User download."/> + <affected-histogram name="Download.PathGenerationEvent"/> + <affected-histogram name="Download.PathValidationResult"/> +</histogram_suffixes> + <histogram_suffixes name="DownloadWithUnsupportedScheme" separator="."> <suffix name="ContentScheme" label="downloads with content scheme"/> <suffix name="ContentIdScheme" label="downloads with cid scheme"/> @@ -95716,6 +104898,23 @@ <affected-histogram name="SBClientDownload.UnsupportedScheme"/> </histogram_suffixes> +<histogram_suffixes name="DrawQuadsType" separator="."> + <suffix name="" label=""/> + <suffix name="Resized" + label="Captures only draw quads that have changed size by draw + occlusion."/> + <suffix name="Skipped" + label="Captures only draw quads that are too small to apply draw + occlusion."/> + <suffix name="Smaller" + label="Captures only draw quads that are smaller than the layer + occlusion minimum size (160x160)."/> + <suffix name="With.Complex.Transform" + label="Captures only draw quads that need to go through no scale and no + translation transforms."/> + <affected-histogram name="Compositing.Display.Draw.Quads"/> +</histogram_suffixes> + <histogram_suffixes name="EmePromise" separator="."> <suffix name="CloseSession" label="CloseSession promises only."/> <suffix name="CreateSession" label="CreateSession promises only."> @@ -95763,6 +104962,8 @@ <suffix name="DeviceLocalAccount" label="DeviceLocalAccount policy fetch response."/> <suffix name="User" label="User policy fetch response."/> + <suffix name="UserDuringLogin" + label="User policy fetch response during login."/> <affected-histogram name="Enterprise.RetrievePolicyResponse"/> </histogram_suffixes> @@ -95910,6 +105111,9 @@ </histogram_suffixes> <histogram_suffixes name="FaviconIconType" separator="."> + <obsolete> + Deprecated as of 12/2017. + </obsolete> <suffix name="Favicons" label="Metrics for regular favicons."/> <suffix name="LargeIcons" label="Metrics for large non-touch icons."/> <suffix name="TouchIcons" label="Metrics for large touch icons."/> @@ -96005,6 +105209,27 @@ <affected-histogram name="Renderer4.LoadType"/> </histogram_suffixes> +<histogram_suffixes name="FirstUserActionType" separator=""> + <suffix name="Continuation" + label="and performed an user action indicating that they were + continuing a task from the last time they used the app"/> + <suffix name="Expiration" + label="and did not perform any user actions that indicate either a new + task or a continued task before some timeout expired"/> + <suffix name="NewTask" + label="and performed an user action indicating that they were beginning + a new task from the last time they used the app"/> + <affected-histogram name="FirstUserAction.BackgroundTime"/> +</histogram_suffixes> + +<histogram_suffixes name="FirstUserActionTypeDevice" separator=""> + <suffix name="Handset" label="(handset only)"/> + <suffix name="Tablet" label="(tablet only)"/> + <affected-histogram name="FirstUserAction.BackgroundTimeContinuation"/> + <affected-histogram name="FirstUserAction.BackgroundTimeExpiration"/> + <affected-histogram name="FirstUserAction.BackgroundTimeNewTask"/> +</histogram_suffixes> + <histogram_suffixes name="FirstUserActionTypes" separator="."> <suffix name="Backgrounded" label="The user sent Chrome to the background"/> <suffix name="Continuation" @@ -96144,11 +105369,11 @@ <histogram_suffixes name="GPUBlacklistPerFeature" separator="."> <owner>vmiura@chromium.org</owner> <suffix name="Accelerated2dCanvas" label="Accelerated2dCanvas"/> - <suffix name="AcceleratedCompositing" label="AcceleratedCompositing"/> + <suffix name="GpuCompositing" label="GpuCompositing"/> + <suffix name="GpuRasterization" label="GpuRasterization"/> <suffix name="Webgl" label="Webgl"/> - <suffix name="TextureSharing" label="TextureSharing"/> + <suffix name="Webgl2" label="Webgl2"/> <affected-histogram name="GPU.BlacklistFeatureTestResults"/> - <affected-histogram name="GPU.BlacklistFeatureTestResultsWin"/> <affected-histogram name="GPU.BlacklistFeatureTestResultsWindows"/> </histogram_suffixes> @@ -96156,6 +105381,7 @@ <suffix name="Resident" label="Only counting resident memory."/> <suffix name="PrivateMemoryFootprint" label="Only counting private resident + swapped/compressed memory."/> + <suffix name="SharedMemoryFootprint" label="Only counting shared memory."/> <suffix name="Malloc" label="Constrained to malloc allocator."/> <suffix name="CommandBuffer" label="Constrained to command buffer memory."/> <affected-histogram name="Memory.Experimental.Gpu2"/> @@ -96353,6 +105579,7 @@ label="A cached resource existed and was updated over the network."/> <suffix name="Validated" label="A cached resource existed and was validated over the network."/> + <affected-histogram name="HttpCache.AfterSend"/> <affected-histogram name="HttpCache.BeforeSend"/> <affected-histogram name="HttpCache.PercentBeforeSend"/> </histogram_suffixes> @@ -96634,6 +105861,14 @@ <affected-histogram name="Tabs.iOS_PostRedirectPLT"/> </histogram_suffixes> +<histogram_suffixes name="IOSProductTourScreens" separator=""> + <suffix name="VoiceSearch"/> + <suffix name="Sync"/> + <suffix name="Incognito"/> + <suffix name="Unknown"/> + <affected-histogram name="ProductTour.IOSScreens"/> +</histogram_suffixes> + <histogram_suffixes name="IPHDatabase" separator="."> <affected-histogram name="InProductHelp.Db.Init"/> <affected-histogram name="InProductHelp.Db.Load"/> @@ -96646,8 +105881,39 @@ <affected-histogram name="InProductHelp.NotifyEventReadyState"/> <affected-histogram name="InProductHelp.ShouldTriggerHelpUI"/> <suffix name="IPH_Bookmark" label="In product help bookmark."/> + <suffix name="IPH_ChromeHomeExpand" + label="In product help for Chrome Home shown on cold start."/> + <suffix name="IPH_ChromeHomeMenuHeader" + label="In product help for Chrome Home shown as a header in the app + menu."/> + <suffix name="IPH_ChromeHomePullToRefresh" + label="In product help for Chrome Home shown after a pull-to-refresh."/> <suffix name="IPH_DataSaverPreview" label="In product help data saver preview."/> + <suffix name="IPH_ContextualSearch"> + <obsolete> + Replaced with IPH_ContextualSearchWebSearch. + </obsolete> + </suffix> + <suffix name="IPH_ContextualSearchWebSearch" + label="In product help for contextual search for users who use web + search."/> + <suffix name="IPH_ContextualSearchTap"> + <obsolete> + Replaced with IPH_ContextualSearchPromoteTap. + </obsolete> + </suffix> + <suffix name="IPH_ContextualSearchPromoteTap" + label="In product help for tap trigger for contextual search."/> + <suffix name="IPH_ContextualSearchPanel"> + <obsolete> + Replaced with IPH_ContextualSearchPromotePanelOpen. + </obsolete> + </suffix> + <suffix name="IPH_ContextualSearchPromotePanelOpen" + label="In product help for opening the contextual search panel."/> + <suffix name="IPH_ContextualSearchOptIn" + label="In product help for opting-in for contextual search."/> <suffix name="IPH_DataSaverDetail" label="In product help data saver detail."/> <suffix name="IPH_DownloadPage" label="In product help download page."/> @@ -96682,15 +105948,20 @@ </histogram_suffixes> <histogram_suffixes name="JSDialogs.DialogType" separator="."> - <suffix name="Alert"/> - <suffix name="Confirm"/> - <suffix name="Prompt"/> + <suffix name="Alert" label="window.alert() dialog"/> + <suffix name="Confirm" label="window.confirm() dialog"/> + <suffix name="Prompt" label="window.prompt() dialog"/> + <suffix name="BeforeUnload" label="dialog caused by window.onbeforeunload"/> <affected-histogram name="JSDialogs.DismissalCause"/> <affected-histogram name="JSDialogs.IsForemost"/> + <affected-histogram name="JSDialogs.Scheme"/> <affected-histogram name="JSDialogs.SiteEngagementOfDialogs"/> </histogram_suffixes> <histogram_suffixes name="JSDialogs.EngagementList" separator="."> + <obsolete> + Deprecated 2017-10. + </obsolete> <suffix name="EngagementNone" label="site engagement = 0"/> <suffix name="EngagementLessThanOne" label="site engagement < 1"/> <suffix name="EngagementOneToFive" label="site engagement >= 1, < 5"/> @@ -96705,6 +105976,9 @@ </histogram_suffixes> <histogram_suffixes name="JSDialogs.LeaveStay" separator="."> + <obsolete> + Deprecated 2017-10. + </obsolete> <suffix name="Leave" label="user opted to leave the page"/> <suffix name="Stay" label="user opted to stay on the page"/> <affected-histogram name="JSDialogs.SiteEngagementOfBeforeUnload"/> @@ -96716,6 +105990,30 @@ <affected-histogram name="JSDialogs.CharacterCount"/> </histogram_suffixes> +<histogram_suffixes name="KeySystemPrefix" separator="." ordering="prefix,2"> + <suffix name="ClearKey" label="Clear Key key system"/> + <suffix name="Unknown" label="Unknown key system"/> + <suffix name="Widevine" label="Widevine key system"/> + <affected-histogram name="Media.EME.addKey"/> + <affected-histogram name="Media.EME.cancelKeyRequest"/> + <affected-histogram name="Media.EME.CreateCdm"/> + <affected-histogram name="Media.EME.CreateCdmTime"/> + <affected-histogram name="Media.EME.generateKeyRequest"/> + <affected-histogram name="Media.EME.KeyAdded"/> + <affected-histogram name="Media.EME.KeyError"/> + <affected-histogram name="Media.EME.KeyStatusSystemCode"/> + <affected-histogram name="Media.EME.LibraryCdmAvailable"/> + <affected-histogram name="Media.EME.SystemCode"/> + <affected-histogram name="Media.EME.TimeTo"/> +</histogram_suffixes> + +<histogram_suffixes name="KeySystemSuffix" separator="."> + <suffix name="ClearKey" label="Clear Key key system"/> + <suffix name="Unknown" label="Unknown key system"/> + <suffix name="Widevine" label="Widevine key system"/> + <affected-histogram name="Media.EME"/> +</histogram_suffixes> + <histogram_suffixes name="LateBindingExperiment" separator="_"> <suffix name="disable_late_binding" label="socket late binding is disabled"/> <suffix name="enable_late_binding" label="socket late binding is enabled"/> @@ -96857,7 +106155,7 @@ <affected-histogram name="LevelDBEnv.TimeUntilSuccessFor"/> </histogram_suffixes> -<histogram_suffixes name="LevelDBOpenResults" separator="_"> +<histogram_suffixes name="LevelDBOpenResults" separator="."> <suffix name="DomDistillerStore" label="Databases for DomDistillerStore"/> <suffix name="GCMKeyStore" label="Databases for GCMKeyStore"/> <suffix name="ImageManager" label="Databases for ImageManager"/> @@ -96875,6 +106173,21 @@ <affected-histogram name="LevelDB.Open"/> </histogram_suffixes> +<histogram_suffixes name="LevelDBSharedCache" separator="."> + <owner>cmumford@chromium.org</owner> + <suffix name="Browser" + label="Cache shared databases whose access pattern is dictated by + browser code."/> + <suffix name="Web" + label="whose access pattern is directly influenced by Web APIs, like + Indexed DB, etc."/> + <suffix name="Unified" label="Cache shared by both web and browser."/> + <suffix name="InMemory" label="Cache shared all in-memory databases."/> + <affected-histogram name="LevelDB.SharedCache.BytesUsed"/> + <affected-histogram name="LevelDB.SharedCache.DBCount"/> + <affected-histogram name="LevelDB.SharedCache.KBUsed"/> +</histogram_suffixes> + <histogram_suffixes name="LocalNetReqsLocalhostResources" separator="."> <suffix base="true" name="Localhost.DbRequests" label="Requests made to localhost on a database server port."/> @@ -97027,6 +106340,9 @@ </histogram_suffixes> <histogram_suffixes name="LowMemoryMargin" separator="_"> + <obsolete> + Deprecated 12/2017. The low memory margin is a per-platform constant. + </obsolete> <suffix name="default" label="Low memory margin set to the system default"/> <suffix name="off" label="Low memory notification disabled"/> <suffix name="0mb" label="Low memory margin set to 0MB"/> @@ -97111,6 +106427,9 @@ <suffix name="MuteButton" label="Mute button"/> <suffix name="MuteOverflowButton" label="Mute overflow button"/> <suffix name="OverflowButton" label="Overflow button"/> + <suffix name="PictureInPictureButton" label="Picture-in-Picture button"/> + <suffix name="PictureInPictureOverflowButton" + label="Picture-in-Picture overflow button"/> <suffix name="PlayOverlayButton" label="Play overlay button"/> <suffix name="PlayPauseButton" label="Play/pause button"/> <suffix name="PlayPauseOverflowButton" label="Play/pause overflow button"/> @@ -97205,17 +106524,6 @@ <affected-histogram name="Media.Timeline.SeekType"/> </histogram_suffixes> -<histogram_suffixes name="MediaUnderflowDuration2" separator="."> - <suffix name="EME" - label="Measures underflow state of Encrypted Media Extensions (EME) - based playbacks."/> - <suffix name="MSE" - label="Measures underflow state of Media Source Extensions (MSE) based - playbacks."/> - <suffix name="SRC" label="Measures underflow state for src= playbacks."/> - <affected-histogram name="Media.UnderflowDuration2"/> -</histogram_suffixes> - <histogram_suffixes name="MediaVideoCaptureManagerTime" separator="."> <suffix name="StartDeviceTime" label="Measures the time taken for DoStartDeviceOnDeviceThread()."/> @@ -97244,6 +106552,15 @@ <suffix name="Audio.Battery" label="Watch time for all media with only an audio track on battery power."/> + <suffix name="Audio.Discarded.SRC" + label="Watch time less than 7 seconds for SRC media with only an audio + track."/> + <suffix name="Audio.Discarded.MSE" + label="Watch time less than 7 seconds for MSE media with only an audio + track."/> + <suffix name="Audio.Discarded.EME" + label="Watch time less than 7 seconds for EME media with only an audio + track."/> <suffix name="Audio.MSE" label="Watch time for MSE media with only an audio track."/> <suffix name="Audio.NativeControlsOff" @@ -97259,6 +106576,23 @@ <suffix name="Audio.EmbeddedExperience" label="Watch time for downloaded media on Android with only an audio track."/> + <suffix name="Audio.Background.All" + label="Background watch time for all media with only an audio track."/> + <suffix name="Audio.Background.AC" + label="Background watch time for all media with only an audio track on + AC power."/> + <suffix name="Audio.Background.Battery" + label="Background watch time for all media with only an audio track on + battery power."/> + <suffix name="Audio.Background.MSE" + label="Background watch time for MSE media with only an audio track."/> + <suffix name="Audio.Background.SRC" + label="Background watch time for SRC media with only an audio track."/> + <suffix name="Audio.Background.EME" + label="Background watch time for EME media with only an audio track."/> + <suffix name="Audio.Background.EmbeddedExperience" + label="Background watch time for downloaded media on Android with only + an audio track."/> <suffix name="AudioVideo.All" label="Watch time for all media with both an audio and video track."/> <suffix name="AudioVideo.AC" @@ -97267,6 +106601,15 @@ <suffix name="AudioVideo.Battery" label="Watch time for all media with both an audio and video track on battery power."/> + <suffix name="AudioVideo.Discarded.SRC" + label="Watch time less than 7 seconds for SRC media with with both an + audio and video track."/> + <suffix name="AudioVideo.Discarded.MSE" + label="Watch time less than 7 seconds for MSE media with only with both + an audio and video track."/> + <suffix name="AudioVideo.Discarded.EME" + label="Watch time less than 7 seconds for EME media with only with both + an audio and video track."/> <suffix name="AudioVideo.DisplayFullscreen" label="Watch time for all media with both an audio and video track displayed in fullscreen."/> @@ -97566,6 +106909,36 @@ <affected-histogram name="Net.BidirectionalStream.TimeToSendStart"/> </histogram_suffixes> +<histogram_suffixes name="Net.DNS.AddressFamily" separator="."> + <suffix name="IPV4" label="Requests for ADDRESS_FAMILY_IPV4."/> + <suffix name="IPV6" label="Requests for ADDRESS_FAMILY_IPV6."/> + <suffix name="UNSPEC" label="Requests for ADDRESS_FAMILY_UNSPEC."/> + <affected-histogram name="Net.DNS.ResolveFailureTime"/> + <affected-histogram name="Net.DNS.ResolveSuccessTime"/> +</histogram_suffixes> + +<histogram_suffixes name="Net.DNS.Priorities" separator="."> + <suffix name="THROTTLED" label="Jobs with priority THROTTLED."/> + <suffix name="IDLE" label="Jobs with priority IDLE."/> + <suffix name="LOWEST" label="Jobs with priority LOWEST."/> + <suffix name="LOW" label="Jobs with priority LOW."/> + <suffix name="MEDIUM" label="Jobs with priority MEDIUM."/> + <suffix name="HIGHEST" label="Jobs with priority HIGHEST."/> + <affected-histogram name="Net.DNS.JobQueueTime"/> + <affected-histogram name="Net.DNS.JobQueueTimeAfterChange"/> +</histogram_suffixes> + +<histogram_suffixes name="Net.DNS.Speculative" separator="."> + <obsolete> + Deprecated 02/2018. + </obsolete> + <suffix name="Speculative" label="Speculative resolutions only."/> + <affected-histogram name="Net.DNS.ResolveFailureTime"/> + <affected-histogram name="Net.DNS.ResolveSuccessTime"/> + <affected-histogram name="Net.DNS.TotalTime"/> + <affected-histogram name="Net.DNS.TotalTimeNotCached"/> +</histogram_suffixes> + <histogram_suffixes name="Net.HttpJob.TotalTimeSuccess.Priorities" separator="."> <suffix name="Priority0" label="THROTTLED or MINIMUM_PRIORITY"/> @@ -98998,6 +108371,8 @@ label="Default gray box in place of a thumbnail/screenshot."/> <affected-histogram name="NewTabPage.MostVisited"/> <affected-histogram name="NewTabPage.SuggestionsImpression"/> + <affected-histogram name="NewTabPage.TileFaviconType"/> + <affected-histogram name="NewTabPage.TileFaviconTypeClicked"/> </histogram_suffixes> <histogram_suffixes name="NewTabPageLogoShownFromCache" separator="."> @@ -99050,7 +108425,11 @@ </obsolete> </suffix> <affected-histogram name="NewTabPage.MostVisited"/> + <affected-histogram name="NewTabPage.MostVisitedAge"/> <affected-histogram name="NewTabPage.SuggestionsImpression"/> + <affected-histogram name="NewTabPage.SuggestionsImpressionAge"/> + <affected-histogram name="NewTabPage.TileTitle"/> + <affected-histogram name="NewTabPage.TileTitleClicked"/> <affected-histogram name="NewTabPage.TileType"/> <affected-histogram name="NewTabPage.TileTypeClicked"/> </histogram_suffixes> @@ -99088,6 +108467,9 @@ </histogram_suffixes> <histogram_suffixes name="NotificationDisplayExperiment" separator="_"> + <obsolete> + Deprecated October 2017 (feature enabled by default). + </obsolete> <suffix name="Fullscreen.Shown" label="A notification sent by a fullscreen app or webpage that is displayed."/> @@ -99418,16 +108800,56 @@ </obsolete> </affected-histogram> <affected-histogram name="NQE.PeakKbps"/> - <affected-histogram name="NQE.RTT.Percentile0"/> - <affected-histogram name="NQE.RTT.Percentile10"/> - <affected-histogram name="NQE.RTT.Percentile100"/> - <affected-histogram name="NQE.RTT.Percentile50"/> - <affected-histogram name="NQE.RTT.Percentile90"/> - <affected-histogram name="NQE.TransportRTT.Percentile0"/> - <affected-histogram name="NQE.TransportRTT.Percentile10"/> - <affected-histogram name="NQE.TransportRTT.Percentile100"/> - <affected-histogram name="NQE.TransportRTT.Percentile50"/> - <affected-histogram name="NQE.TransportRTT.Percentile90"/> + <affected-histogram name="NQE.RTT.Percentile0"> + <obsolete> + Deprecated 01/2018. + </obsolete> + </affected-histogram> + <affected-histogram name="NQE.RTT.Percentile10"> + <obsolete> + Deprecated 01/2018. + </obsolete> + </affected-histogram> + <affected-histogram name="NQE.RTT.Percentile100"> + <obsolete> + Deprecated 01/2018. + </obsolete> + </affected-histogram> + <affected-histogram name="NQE.RTT.Percentile50"> + <obsolete> + Deprecated 01/2018. + </obsolete> + </affected-histogram> + <affected-histogram name="NQE.RTT.Percentile90"> + <obsolete> + Deprecated 01/2018. + </obsolete> + </affected-histogram> + <affected-histogram name="NQE.TransportRTT.Percentile0"> + <obsolete> + Deprecated 01/2018. + </obsolete> + </affected-histogram> + <affected-histogram name="NQE.TransportRTT.Percentile10"> + <obsolete> + Deprecated 01/2018. + </obsolete> + </affected-histogram> + <affected-histogram name="NQE.TransportRTT.Percentile100"> + <obsolete> + Deprecated 01/2018. + </obsolete> + </affected-histogram> + <affected-histogram name="NQE.TransportRTT.Percentile50"> + <obsolete> + Deprecated 01/2018. + </obsolete> + </affected-histogram> + <affected-histogram name="NQE.TransportRTT.Percentile90"> + <obsolete> + Deprecated 01/2018. + </obsolete> + </affected-histogram> </histogram_suffixes> <histogram_suffixes name="NQE.ObservationSources" separator="."> @@ -99478,6 +108900,13 @@ <affected-histogram name="SBOffDomainInclusion2.Abort"/> </histogram_suffixes> +<histogram_suffixes name="OfflinePagesArchiveDirectoryType" separator="."> + <suffix name="Temporary" label="Temporary archive directory"/> + <suffix name="Persistent" label="Persistent archive directory"/> + <affected-histogram + name="OfflinePages.ArchiveManager.ArchiveDirsCreationResult2"/> +</histogram_suffixes> + <histogram_suffixes name="OfflinePagesNamespace" separator="."> <suffix name="bookmark" label="Offline bookmark cache"/> <suffix name="last_n" label="Offline recent pages"/> @@ -99487,6 +108916,7 @@ <suffix name="ntp_suggestions" label="NTP suggestions offlined by the user"/> <suffix name="suggested_articles" label="Prefetched NTP suggestions"/> <suffix name="browser_actions" label="Offline Browser Actions pages"/> + <affected-histogram name="OfflinePages.AccessEntryPoint"/> <affected-histogram name="OfflinePages.Background.BackgroundLoadingFailedCode"/> <affected-histogram @@ -99497,10 +108927,13 @@ <affected-histogram name="OfflinePages.Background.LoadingErrorStatusCode"/> <affected-histogram name="OfflinePages.Background.OfflinerRequestStatus"/> <affected-histogram name="OfflinePages.Background.OffliningPreviewStatus"/> + <affected-histogram name="OfflinePages.Background.SavePageFromCCT"/> <affected-histogram name="OfflinePages.Background.TimeToCanceled"/> <affected-histogram name="OfflinePages.Background.TimeToSaved"/> <affected-histogram name="OfflinePages.Background.TimeToStart"/> <affected-histogram name="OfflinePages.Background.TimeToStart.Svelte"/> + <affected-histogram name="OfflinePages.ClearStoragePreRunUsage"/> + <affected-histogram name="OfflinePages.ClearStoragePreRunUsage2"/> <affected-histogram name="OfflinePages.DeletePage.AccessCount"/> <affected-histogram name="OfflinePages.DeletePage.LastOpenToCreated"/> <affected-histogram name="OfflinePages.DeletePage.PageSize"/> @@ -99509,8 +108942,11 @@ <affected-histogram name="OfflinePages.ExpirePage.TimeSinceLastAccess"/> <affected-histogram name="OfflinePages.FirstOpenSinceCreated"/> <affected-histogram name="OfflinePages.OpenSinceLastOpen"/> + <affected-histogram name="OfflinePages.PageAccessInterval"/> <affected-histogram name="OfflinePages.PageLifetime"/> <affected-histogram name="OfflinePages.PageSize"/> + <affected-histogram name="OfflinePages.PageSizeOnAccess.Offline"/> + <affected-histogram name="OfflinePages.PageSizeOnAccess.Online"/> <affected-histogram name="OfflinePages.SavePageResult"/> <affected-histogram name="OfflinePages.SavePageTime"/> </histogram_suffixes> @@ -99532,6 +108968,12 @@ <affected-histogram name="OfflinePages.Prefetching.ActionRetryAttempts"/> </histogram_suffixes> +<histogram_suffixes name="OffTheRecordType" separator="."> + <suffix name="OTR" label="Off-the-record profile"/> + <suffix name="NonOTR" label="Non off-the-record profile"/> + <affected-histogram name="Tab.TabUnderAction"/> +</histogram_suffixes> + <histogram_suffixes name="OmniboxPageContext" separator="."> <suffix name="INVALID_SPEC" label="invalid spec; shouldn't happen"/> <suffix name="NTP" @@ -100069,6 +109511,12 @@ <suffix name="Clients.MultiTabLoading" label="PageLoadMetrics for page loads that started while there are other loading tabs."/> + <suffix name="Clients.MultiTabLoading.2OrMore" + label="PageLoadMetrics for page loads that started while there are 2 or + more other loading tabs."/> + <suffix name="Clients.MultiTabLoading.5OrMore" + label="PageLoadMetrics for page loads that started while there are 5 or + more other loading tabs."/> <affected-histogram name="PageLoad.DocumentTiming.NavigationToDOMContentLoadedEventFired"/> <affected-histogram @@ -100083,6 +109531,23 @@ name="PageLoad.PaintTiming.NavigationToFirstContentfulPaint"/> </histogram_suffixes> +<histogram_suffixes name="PageLoadMetricsClientsNoScriptPreview" separator="." + ordering="prefix"> + <suffix name="Clients.NoScriptPreview" + label="PageLoadMetrics that are a result of a navigation that tirggered + the NoScript Preview intervention."/> + <affected-histogram + name="PageLoad.DocumentTiming.NavigationToLoadEventFired"/> + <affected-histogram name="PageLoad.Experimental.Bytes.Network"/> + <affected-histogram name="PageLoad.Experimental.CompletedResources.Network"/> + <affected-histogram + name="PageLoad.Experimental.PaintTiming.NavigationToFirstMeaningfulPaint"/> + <affected-histogram + name="PageLoad.PaintTiming.NavigationToFirstContentfulPaint"/> + <affected-histogram name="PageLoad.ParseTiming.ParseBlockedOnScriptLoad"/> + <affected-histogram name="PageLoad.ParseTiming.ParseDuration"/> +</histogram_suffixes> + <histogram_suffixes name="PageLoadMetricsClientsNoServiceWorkerSpecialApps" separator="."> <suffix name="search" @@ -100635,6 +110100,8 @@ name="PasswordProtection.NumberOfCachedVerdictBeforeShutdown"/> <affected-histogram name="PasswordProtection.PageInfoAction"/> <affected-histogram name="PasswordProtection.RequestOutcome"/> + <affected-histogram + name="PasswordProtection.UserClickedThroughSafeBrowsingInterstitial"/> <affected-histogram name="PasswordProtection.Verdict"/> </histogram_suffixes> @@ -100744,6 +110211,8 @@ <suffix name="WorkerProcess"/> <affected-histogram name="PerformanceMonitor.AverageCPU"/> <affected-histogram name="PerformanceMonitor.HighCPU"/> + <affected-histogram name="PerformanceMonitor.IdleWakeups"/> + <affected-histogram name="PerformanceMonitor.PackageExitIdleWakeups"/> </histogram_suffixes> <histogram_suffixes name="PermissionRequestGesture" separator="."> @@ -100768,6 +110237,7 @@ label="registerProtocolHandler permission"/> <suffix name="Quota" label="Quota permission"/> <suffix name="MultipleDownload" label="Multiple downloads permission"/> + <suffix name="SecurityKeyAttestation" label="Security Key attestation"/> <affected-histogram name="Permissions.Engagement.Accepted"/> <affected-histogram name="Permissions.Engagement.Denied"/> <affected-histogram name="Permissions.Engagement.Dismissed"/> @@ -100780,7 +110250,6 @@ <suffix name="Notifications" label="Notification permission actions"/> <suffix name="Geolocation" label="Geolocation permission actions"/> <suffix name="ProtectedMedia" label="Protected media permission actions"/> - <suffix name="DurableStorage" label="Durable Storage permission actions"/> <suffix name="AudioCapture" label="Microphone permission actions"/> <suffix name="VideoCapture" label="Camera permission actions"/> <suffix name="Flash" label="Flash permission actions"/> @@ -100933,6 +110402,9 @@ </histogram_suffixes> <histogram_suffixes name="PluginFlashEngagement" separator="."> + <obsolete> + Deprecated 12/2017 in Issue 781644. + </obsolete> <suffix name="ContentSettingAllowed" label="Engagement when Flash allowed."/> <suffix name="ContentSettingBlocked" label="Engagement when Flash blocked."/> <suffix name="NoSetting" label="Engagement when no content setting set."/> @@ -101151,12 +110623,20 @@ <suffix name="externalrequest" label="Externally triggered prerender."/> <suffix name="externalrequestforced" label="Forced prerender regardless of network."/> - <suffix name="Instant" label="Instant search prerender."/> + <suffix name="Instant" label="Instant search prerender."> + <obsolete> + Deprecated October 2017 + </obsolete> + </suffix> <suffix name="none" label="No origin; in the case of prefetch TTFCP this is when no prefetch was involved."/> <suffix name="omnibox" label="Triggered from the omnibox."/> - <suffix name="wash" label="Multiple sources could have triggered."/> + <suffix name="wash" label="Multiple sources could have triggered."> + <obsolete> + Deprecated April 2017 + </obsolete> + </suffix> <suffix name="web" label="Link triggered prerender."/> <suffix name="webcross" label="Link triggered prerender, rel=prerender, cross domain."/> @@ -101164,7 +110644,11 @@ label="Link triggered prerender, rel=prerender, same domain."/> <suffix name="webnext" label="Link triggered prerender, rel=next."/> <suffix name="offline" - label="Prerender triggered for saving a page for offline use."/> + label="Prerender triggered for saving a page for offline use."> + <obsolete> + Deprecated October 2017 + </obsolete> + </suffix> <affected-histogram name="Prerender.AbandonTimeUntilUsed"/> <affected-histogram name="Prerender.CookieSendType"/> <affected-histogram name="Prerender.CookieStatus"/> @@ -101224,6 +110708,7 @@ <suffix name="LitePage" label="Lite page previews"/> <suffix name="LoFi" label="Server LoFi previews"/> <suffix name="AMPRedirection" label="AMP Redirection previews"/> + <suffix name="NoScript" label="NoScript previews"/> <affected-histogram name="Previews.EligibilityReason"/> <affected-histogram name="Previews.InfoBarAction"/> <affected-histogram name="Previews.OptOut.UserOptedOut"/> @@ -101460,9 +110945,11 @@ <suffix name="" label="This metric includes both gpu and software raster."/> <suffix name="Gpu" label="This metric is for only gpu raster."/> <suffix name="Software" label="This metric is for only software raster."/> + <affected-histogram name="Compositing.Browser.CachedImagesCount"/> <affected-histogram name="Compositing.Browser.RasterTask.RasterPixelsPerMs"/> <affected-histogram name="Compositing.Browser.RasterTask.RasterPixelsPerMs2"/> <affected-histogram name="Compositing.Browser.RasterTask.RasterUs"/> + <affected-histogram name="Compositing.Renderer.CachedImagesCount"/> <affected-histogram name="Compositing.Renderer.RasterTask.RasterPixelsPerMs"/> <affected-histogram name="Compositing.Renderer.RasterTask.RasterPixelsPerMs2"/> @@ -101494,6 +110981,22 @@ <affected-histogram name="Startup.WarmStartTimeFromRemoteProcessStart"/> </histogram_suffixes> +<histogram_suffixes name="RemotingSessionDuration" separator="."> + <suffix name="Duration0To100MilliSec" + label="remoting sessions have duration in (0, 0.1] seconds"/> + <suffix name="Duration100MilliSecTo1Sec" + label="remoting sessions have duration in (0.1, 1] seconds"/> + <suffix name="Duration1To3Sec" + label="remoting sessions have duration in (1, 3] seconds"/> + <suffix name="Duration3To5Sec" + label="remoting sessions have duration in (3, 5] seconds"/> + <suffix name="Duration5To10Sec" + label="remoting sessions have duration in (5, 10] seconds"/> + <suffix name="Duration10To15Sec" + label="remoting sessions have duration in (10, 15] seconds"/> + <affected-histogram name="Media.Remoting.SessionStopTrigger"/> +</histogram_suffixes> + <histogram_suffixes name="RendererEventLatency" separator="."> <suffix name="Char" label="The Char event occurs on textual keyboard input."/> <suffix name="ContextMenu" label="For ContextMenu event."/> @@ -101622,10 +111125,14 @@ <suffix name="Resident" label="Only counting resident memory."/> <suffix name="PrivateMemoryFootprint" label="Only counting private resident + swapped/compressed memory."/> + <suffix name="SharedMemoryFootprint" label="Only counting shared memory."/> <suffix name="Malloc" label="Constrained to malloc allocator."/> <suffix name="PartitionAlloc" label="Constrained to partition allocator."/> <suffix name="BlinkGC" label="Constrained to blink GC allocator."/> <suffix name="V8" label="Constrained to v8 allocator."/> + <suffix name="PrivateSwapFootprint" + label="Only counting private swapped memory. Available only on Android + and Linux."/> <affected-histogram name="Memory.Experimental.Extension2"/> <affected-histogram name="Memory.Experimental.Renderer2"/> </histogram_suffixes> @@ -101636,6 +111143,9 @@ within the page."/> <suffix name="MainFrameDidFinishLoad" label="Recorded when DidFinishLoad is called for the main frame."/> + <suffix name="ServiceWorkerControlledMainFrameDidFinishLoad" + label="Recorded when DidFinishLoad is called for the main frame which + is controlled by a service worker."/> <suffix name="AfterBackgrounded.5min" label="Recorded 5 minutes after backgrounded."/> <suffix name="AfterBackgrounded.10min" @@ -101648,6 +111158,10 @@ <suffix name="MainFrame.PeakDuringLoad" label="In the main frame, polled each time CreateURLLoader is called, and the maximum value is recorded when DidFinishLoad is called."/> + <suffix name="ServiceWorkerControlledMainFrame.PeakDuringLoad" + label="In the main frame which is controlled by a service worker, + polled each time CreateURLLoader is called, and the maximum + value is recorded when DidFinishLoad is called."/> <affected-histogram name="Memory.Experimental.Renderer.BlinkGC"/> <affected-histogram name="Memory.Experimental.Renderer.Discardable"/> <affected-histogram name="Memory.Experimental.Renderer.Malloc"/> @@ -101660,6 +111174,58 @@ <affected-histogram name="Memory.Experimental.Renderer.V8MainThreadIsolate"/> </histogram_suffixes> +<histogram_suffixes name="RendererScheduler.ExpectedQueueingTime.FrameSplit" + separator="."> + <suffix name="CrossOriginBackground" + label="Expected Queueing Time from cross-origin backgrounded frames."/> + <suffix name="CrossOriginHidden" + label="Expected Queueing Time from cross-origin offscreen frames."/> + <suffix name="CrossOriginVisible" + label="Expected Queueing Time from cross-origin onscreen frames."/> + <suffix name="SameOriginBackground" + label="Expected Queueing Time from same-origin backgrounded frames."/> + <suffix name="SameOriginHidden" + label="Expected Queueing Time from same-origin offscreen frames."/> + <suffix name="SameOriginVisible" + label="Expected Queueing Time from same-origin onscreen frames."/> + <suffix name="MainFrameBackground" + label="Expected Queueing Time from backgrounded main frames."/> + <suffix name="MainFrameHidden" + label="Expected Queueing Time from offscreen main frames."/> + <suffix name="MainFrameVisible" + label="Expected Queueing Time from onscreen main frames."/> + <suffix name="Other" + label="Expected Queueing Time from events with detached or nonexistent + frames."/> + <affected-histogram + name="RendererScheduler.ExpectedQueueingTimeByFrameStatus"/> + <affected-histogram + name="RendererScheduler.ExpectedQueueingTimeByFrameStatus2"/> +</histogram_suffixes> + +<histogram_suffixes + name="RendererScheduler.ExpectedQueueingTime.TaskQueueSplit" separator="."> + <suffix name="Compositor" + label="Expected Queueing Time from the compositor task queue."/> + <suffix name="Default" + label="Expected Queueing Time from the default task queue."/> + <suffix name="DefaultLoading" + label="Expected Queueing Time from the default loading task queue."/> + <suffix name="FrameLoading" + label="Expected Queueing Time from the frame loading task queue."/> + <suffix name="FramePausable" + label="Expected Queueing Time from the frame pausable task queue."/> + <suffix name="FrameThrottleable" + label="Expected Queueing Time from the frame throttleable task queue."/> + <suffix name="Unthrottled" + label="Expected Queueing Time from the unthrottled task queue."/> + <suffix name="Other" + label="Expected Queueing Time from events in any other task queue."/> + <affected-histogram name="RendererScheduler.ExpectedQueueingTimeByTaskQueue"/> + <affected-histogram + name="RendererScheduler.ExpectedQueueingTimeByTaskQueue2"/> +</histogram_suffixes> + <histogram_suffixes name="RendererScheduler.MainThreadLoadSplit" separator="."> <suffix name="Extension" label="This only includes extension renderers"/> <suffix name="Background" @@ -101685,6 +111251,14 @@ <affected-histogram name="RendererScheduler.RendererMainThreadLoad5"/> </histogram_suffixes> +<histogram_suffixes name="RendererScheduler.ProcessVisibilityStateSplit" + separator="."> + <suffix name="Background"/> + <suffix name="Foreground"/> + <affected-histogram name="RendererScheduler.TaskCPUDurationPerThreadType"/> + <affected-histogram name="RendererScheduler.TaskDurationPerThreadType"/> +</histogram_suffixes> + <histogram_suffixes name="RendererScheduler.TaskCountPerTaskLength" separator="."> <suffix name="LongerThan16ms"/> @@ -101692,6 +111266,7 @@ <suffix name="LongerThan100ms"/> <suffix name="LongerThan150ms"/> <suffix name="LongerThan1s"/> + <affected-histogram name="RendererScheduler.TaskCountPerFrameType"/> <affected-histogram name="RendererScheduler.TaskCountPerQueueType"/> </histogram_suffixes> @@ -101748,6 +111323,13 @@ <affected-histogram name="RendererScheduler.TaskDurationPerQueueType2"/> </histogram_suffixes> +<histogram_suffixes name="RendererThreadType" separator="."> + <suffix name="Main" label="Measurement taken on the main/render thread."/> + <suffix name="Compositor" + label="Measurement taken on the compositor thread."/> + <affected-histogram name="AnimatedImage.NumOfFramesSkipped"/> +</histogram_suffixes> + <histogram_suffixes name="RequestMediaKeySystemAccessKeySystems" separator="."> <suffix name="ClearKey" label="Requests for the Clear Key key system."/> <suffix name="Unknown" @@ -101797,12 +111379,25 @@ <suffix name="MainframeThrottled" label="Main frame, throttled"/> <suffix name="MainframeNotThrottled" label="Main frame, not throttled"/> <suffix name="MainframePartiallyThrottled" - label="Main frame, partially throttled"/> + label="Main frame, partially throttled"> + <obsolete> + This experiment was turned down, see https://crbug.com/768325. + </obsolete> + </suffix> <suffix name="SubframeThrottled" label="Sub frame, throttled"/> <suffix name="SubframeNotThrottled" label="Sub frame, not throttled"/> <suffix name="SubframePartiallyThrottled" - label="Sub frame, partially throttled"/> + label="Sub frame, partially throttled"> + <obsolete> + This experiment was turned down, see https://crbug.com/768325. + </obsolete> + </suffix> + <affected-histogram name="Blink.ResourceLoadScheduler.DecodedBytes"/> <affected-histogram name="Blink.ResourceLoadScheduler.PeakRequests"/> + <affected-histogram name="Blink.ResourceLoadScheduler.TotalDecodedBytes"/> + <affected-histogram name="Blink.ResourceLoadScheduler.TotalRequestCount"/> + <affected-histogram name="Blink.ResourceLoadScheduler.TotalTrafficBytes"/> + <affected-histogram name="Blink.ResourceLoadScheduler.TrafficBytes"/> </histogram_suffixes> <histogram_suffixes name="ResourcePrefetchPredictorNetworkTypePrefetch" @@ -102049,8 +111644,10 @@ <suffix name="DownloadWhitelist"/> <suffix name="ExtensionBlacklist"/> <suffix name="IPBlacklist"/> + <suffix name="InclusionWhitelist"/> <suffix name="ModuleWhitelist"/> <suffix name="ResourceBlacklist"/> + <suffix name="Side-EffectFreeWhitelist"/> <suffix name="UwSList"/> <suffix name="UwSListPrefixSet"/> <affected-histogram name="SafeBrowsing.V4UnusedStoreFileExists.V3"/> @@ -102147,6 +111744,7 @@ <affected-histogram name="Startup.BrowserMessageLoopStartTime"/> <affected-histogram name="Startup.BrowserMessageLoopStartTimeFromMainEntry"/> <affected-histogram name="Startup.BrowserMessageLoopStartTimeFromMainEntry2"/> + <affected-histogram name="Startup.BrowserMessageLoopStartTimeFromMainEntry3"/> <affected-histogram name="Startup.BrowserOpenTabs"/> <affected-histogram name="Startup.BrowserWindowDisplay"/> <affected-histogram name="Startup.FirstWebContents.MainFrameLoad2"/> @@ -102223,6 +111821,7 @@ </histogram_suffixes> <histogram_suffixes name="ScrollUpdateHandledThread" separator="_"> + <affected-histogram name="Event.Latency.Scroll.Wheel.TimeToHandled2"/> <suffix name="Main" label="ScrollUpdate handled on main thread"/> <suffix name="Impl" label="ScrollUpdate handled on impl thread"/> <affected-histogram @@ -102685,6 +112284,14 @@ <affected-histogram name="Signin"/> </histogram_suffixes> +<histogram_suffixes name="Signin.ForceSigninVerificationResult" separator="."> + <suffix name="Success" label="The authenticaion token is valid"/> + <suffix name="Failure" + label="The authenticaion token can not be verified due to persisten + error"/> + <affected-histogram name="Signin.ForceSigninVerificationTime"/> +</histogram_suffixes> + <histogram_suffixes name="Signin.ObsoleteActions" separator="."> <obsolete> Deprecated as of 12/2014. @@ -102739,6 +112346,15 @@ <affected-histogram name="SimpleCache.SyncOpenResult"/> </histogram_suffixes> +<histogram_suffixes name="SiteIsolation.XSD.MIME" separator="."> + <suffix name="HTML" label="Classified as HTML MIME type."/> + <suffix name="XML" label="Classified as XML MIME type."/> + <suffix name="JSON" label="Classified as JSON MIME type."/> + <suffix name="Plain" label="Classified as plain text MIME type."/> + <suffix name="Others" label="Classified as other MIME types."/> + <affected-histogram name="SiteIsolation.XSD.Browser.Blocked"/> +</histogram_suffixes> + <histogram_suffixes name="SkiaDrawScaleFactorFilterQuality" separator="."> <suffix name="AnyFilterQuality" label="Any filter quality was used."/> <suffix name="HighFilterQuality" label="High filter quality was used."/> @@ -102800,6 +112416,12 @@ <affected-histogram name="SoftwareReporter.Step"/> </histogram_suffixes> +<histogram_suffixes name="SoftwareReporterInvocationType" separator="_"> + <suffix name="Periodic" label="Periodic run of the reporter."/> + <suffix name="UserInitiated" label="User-initiated run of the reporter."/> + <affected-histogram name="SoftwareReporter.ReporterSequenceResult"/> +</histogram_suffixes> + <histogram_suffixes name="SpdyCwnd" separator="_"> <obsolete> Deprecated as of 07/2014. @@ -102892,6 +112514,9 @@ </histogram_suffixes> <histogram_suffixes name="SqliteVfsOperations" separator="_"> + <obsolete> + Removed 2018-02-06. + </obsolete> <owner>shess@chromium.org</owner> <suffix name="Fetch" label="fetch"/> <suffix name="Read" label="read"/> @@ -102934,6 +112559,7 @@ <affected-histogram name="Startup.BrowserMessageLoopStartTimeFromMainEntry.FirstRun2"/> <affected-histogram name="Startup.BrowserMessageLoopStartTimeFromMainEntry2"/> + <affected-histogram name="Startup.BrowserMessageLoopStartTimeFromMainEntry3"/> <affected-histogram name="Startup.BrowserOpenTabs"/> <affected-histogram name="Startup.BrowserWindow.FirstPaint"/> <affected-histogram name="Startup.BrowserWindow.FirstPaint.CompositingEnded"/> @@ -103073,8 +112699,16 @@ <suffix name="PhishingInterstitial" label="phishing blacklist pattern"/> <suffix name="SubresourceFilterOnly" label="subresource filter only pattern"/> <suffix name="BetterAds" label="Better Ads Standard pattern"/> - <suffix name="AbusiveAds" label="Abusive Ads pattern"/> - <suffix name="AllAds" label="All Ads (BAS + Abusive) pattern"/> + <suffix name="AbusiveAds" label="Abusive Ads pattern"> + <obsolete> + Deprecated 11/17, no longer used. + </obsolete> + </suffix> + <suffix name="AllAds" label="All Ads (BAS + Abusive) pattern"> + <obsolete> + Deprecated 11/17, no longer used. + </obsolete> + </suffix> <affected-histogram name="SubresourceFilter.PageLoad.FinalURLMatch"/> <affected-histogram name="SubresourceFilter.PageLoad.RedirectChainLength"/> <affected-histogram @@ -103085,6 +112719,25 @@ </affected-histogram> </histogram_suffixes> +<histogram_suffixes name="SweeperCompletionTypes" separator="."> + <affected-histogram + name="WebCore.IndexedDB.TombstoneSweeper.DeletedTombstonesSize"/> + <affected-histogram + name="WebCore.IndexedDB.TombstoneSweeper.NumDeletedTombstones"/> + <suffix name="Complete" label="All indexes are scanned."/> + <suffix name="ConnectionOpened" + label="Scanning is interrupted by an new connection to the database."/> + <suffix name="TimeoutReached" label="Scanning is stopped by the timeout."/> + <suffix name="MaxIterations" + label="Scanning is stopped because the maximum record iteration count + was hit."/> + <suffix name="SweepError" + label="Scanning is stopped because a leveldb error was encountered + during sweeping."/> + <affected-histogram name="WebCore.IndexedDB.TombstoneSweeper.NumTombstones"/> + <affected-histogram name="WebCore.IndexedDB.TombstoneSweeper.TombstonesSize"/> +</histogram_suffixes> + <histogram_suffixes name="SyncModelType" separator="."> <suffix name="APP" label="APP"/> <suffix name="APP_LIST" label="APP_LIST"/> @@ -103215,14 +112868,42 @@ <affected-histogram name="Tabs.SwitchFromUserLatency"/> </histogram_suffixes> +<histogram_suffixes name="Tabs.TabUsageIntervalLength" separator="_"> + <suffix name="30" label="30 seconds"/> + <suffix name="60" label="1 minute"/> + <suffix name="600" label="10 minutes"/> + <suffix name="3600" label="1 hour"/> + <suffix name="18000" label="5 hours"/> + <suffix name="43200" label="12 hours"/> + <affected-histogram name="Tabs.UnusedAndClosedInInterval.Count"/> + <affected-histogram name="Tabs.UnusedInInterval.Count"/> + <affected-histogram name="Tabs.UsedAndClosedInInterval.Count"/> + <affected-histogram name="Tabs.UsedInInterval.Count"/> +</histogram_suffixes> + <histogram_suffixes name="TaskSchedulerMayBlock" separator="."> + <obsolete> + Deprecated 1/2018. Merged with TaskSchedulerTaskPriority into + TaskSchedulerTaskType to reduce suffixing. + </obsolete> <suffix name="MayBlock" label="Applies to tasks posted with MayBlock() or WithBaseSyncPrimitives()."/> - <affected-histogram name="TaskScheduler.TaskLatency.BackgroundTaskPriority"/> - <affected-histogram - name="TaskScheduler.TaskLatency.UserBlockingTaskPriority"/> - <affected-histogram name="TaskScheduler.TaskLatency.UserVisibleTaskPriority"/> + <affected-histogram name="TaskScheduler.TaskLatency.BackgroundTaskPriority"> + <obsolete> + Deprecated 4/2017. Units changed from milliseconds to microseconds. + </obsolete> + </affected-histogram> + <affected-histogram name="TaskScheduler.TaskLatency.UserBlockingTaskPriority"> + <obsolete> + Deprecated 4/2017. Units changed from milliseconds to microseconds. + </obsolete> + </affected-histogram> + <affected-histogram name="TaskScheduler.TaskLatency.UserVisibleTaskPriority"> + <obsolete> + Deprecated 4/2017. Units changed from milliseconds to microseconds. + </obsolete> + </affected-histogram> <affected-histogram name="TaskScheduler.TaskLatencyMicroseconds.BackgroundTaskPriority"/> <affected-histogram @@ -103231,14 +112912,36 @@ name="TaskScheduler.TaskLatencyMicroseconds.UserVisibleTaskPriority"/> </histogram_suffixes> +<histogram_suffixes name="TaskSchedulerName" separator="."> + <suffix base="true" name="Browser" + label="TaskScheduler for the browser process."/> + <suffix base="true" name="Renderer" + label="TaskSchedulers for renderer processes."/> + <suffix base="true" name="ContentChild" + label="TaskSchedulers for various instantiations of + content::ChildProcess."/> + <affected-histogram name="TaskScheduler.DetachDuration"/> + <affected-histogram name="TaskScheduler.NumTasksBeforeDetach"/> + <affected-histogram name="TaskScheduler.NumTasksBetweenWaits"/> + <affected-histogram name="TaskScheduler.TaskLatencyMicroseconds"/> +</histogram_suffixes> + <histogram_suffixes name="TaskSchedulerTaskPriority" separator="."> + <obsolete> + Deprecated 1/2018. Merged with TaskSchedulerMayBlock into + TaskSchedulerTaskType to reduce suffixing. + </obsolete> <suffix name="BackgroundTaskPriority" label="Applies to tasks posted with a BACKGROUND priority."/> <suffix name="UserVisibleTaskPriority" label="Applies to tasks posted with a USER_VISIBLE priority."/> <suffix name="UserBlockingTaskPriority" label="Applies to tasks posted with a USER_BLOCKING priority."/> - <affected-histogram name="TaskScheduler.TaskLatency"/> + <affected-histogram name="TaskScheduler.TaskLatency"> + <obsolete> + Deprecated 4/2017. Units changed from milliseconds to microseconds. + </obsolete> + </affected-histogram> <affected-histogram name="TaskScheduler.TaskLatency.BackgroundFileIOPool"> <obsolete> Deprecated 12/2016. Pool name removed from task latency histogram name. @@ -103262,6 +112965,31 @@ <affected-histogram name="TaskScheduler.TaskLatencyMicroseconds"/> </histogram_suffixes> +<histogram_suffixes name="TaskSchedulerTaskType" separator="."> + <suffix name="BackgroundTaskPriority" + label="Applies to tasks posted with a BACKGROUND priority and neither + of MayBlock() nor WithBaseSyncPrimitives()."/> + <suffix name="UserVisibleTaskPriority" + label="Applies to tasks posted with a USER_VISIBLE priority and neither + of MayBlock() nor WithBaseSyncPrimitives()."/> + <suffix name="UserBlockingTaskPriority" + label="Applies to tasks posted with a USER_BLOCKING priority and + neither of MayBlock() nor WithBaseSyncPrimitives()."/> + <suffix name="BackgroundTaskPriority_MayBlock" + label="Applies to tasks posted with a BACKGROUND priority and + MayBlock() or WithBaseSyncPrimitives()."/> + <suffix name="UserVisibleTaskPriority_MayBlock" + label="Applies to tasks posted with a USER_VISIBLE priority and + MayBlock() or WithBaseSyncPrimitives()."/> + <suffix name="UserBlockingTaskPriority_MayBlock" + label="Applies to tasks posted with a USER_BLOCKING priority and + MayBlock() or WithBaseSyncPrimitives()."/> + <affected-histogram name="TaskScheduler.TaskLatencyMicroseconds.Browser"/> + <affected-histogram + name="TaskScheduler.TaskLatencyMicroseconds.ContentChild"/> + <affected-histogram name="TaskScheduler.TaskLatencyMicroseconds.Renderer"/> +</histogram_suffixes> + <histogram_suffixes name="TaskSchedulerWorkerPool" separator="."> <suffix name="BackgroundBlockingPool" label="Applies to the BackgroundBlocking worker pool."/> @@ -103282,16 +113010,53 @@ </suffix> <suffix name="ForegroundPool" label="Applies to the Foreground worker pool."/> <suffix name="RendererBackgroundBlockingPool" - label="Applies to the RendererBackgroundBlocking worker pool."/> + label="Applies to the RendererBackgroundBlocking worker pool."> + <obsolete> + Deprecated 01/2018. In favor of TaskSchedulerName suffix. + </obsolete> + </suffix> <suffix name="RendererBackgroundPool" - label="Applies to the RendererBackground worker pool."/> + label="Applies to the RendererBackground worker pool."> + <obsolete> + Deprecated 01/2018. In favor of TaskSchedulerName suffix. + </obsolete> + </suffix> <suffix name="RendererForegroundBlockingPool" - label="Applies to the RendererForegroundBlocking worker pool."/> + label="Applies to the RendererForegroundBlocking worker pool."> + <obsolete> + Deprecated 01/2018. In favor of TaskSchedulerName suffix. + </obsolete> + </suffix> <suffix name="RendererForegroundPool" - label="Applies to the RendererForeground worker pool."/> - <affected-histogram name="TaskScheduler.DetachDuration"/> - <affected-histogram name="TaskScheduler.NumTasksBeforeDetach"/> - <affected-histogram name="TaskScheduler.NumTasksBetweenWaits"/> + label="Applies to the RendererForeground worker pool."> + <obsolete> + Deprecated 01/2018. In favor of TaskSchedulerName suffix. + </obsolete> + </suffix> + <affected-histogram name="TaskScheduler.DetachDuration"> + <obsolete> + Deprecated 01/2018. In favor of explicit .Browser suffix. + </obsolete> + </affected-histogram> + <affected-histogram name="TaskScheduler.DetachDuration.Browser"/> + <affected-histogram name="TaskScheduler.DetachDuration.ContentChild"/> + <affected-histogram name="TaskScheduler.DetachDuration.Renderer"/> + <affected-histogram name="TaskScheduler.NumTasksBeforeDetach"> + <obsolete> + Deprecated 01/2018. In favor of explicit .Browser suffix. + </obsolete> + </affected-histogram> + <affected-histogram name="TaskScheduler.NumTasksBeforeDetach.Browser"/> + <affected-histogram name="TaskScheduler.NumTasksBeforeDetach.ContentChild"/> + <affected-histogram name="TaskScheduler.NumTasksBeforeDetach.Renderer"/> + <affected-histogram name="TaskScheduler.NumTasksBetweenWaits"> + <obsolete> + Deprecated 01/2018. In favor of explicit .Browser suffix. + </obsolete> + </affected-histogram> + <affected-histogram name="TaskScheduler.NumTasksBetweenWaits.Browser"/> + <affected-histogram name="TaskScheduler.NumTasksBetweenWaits.ContentChild"/> + <affected-histogram name="TaskScheduler.NumTasksBetweenWaits.Renderer"/> <affected-histogram name="TaskScheduler.TaskLatency"> <obsolete> Deprecated 12/2016. Pool name removed from task latency histogram name. @@ -103311,7 +113076,16 @@ <affected-histogram name="ThreadWatcher.UnresponsiveThreads"/> </histogram_suffixes> +<histogram_suffixes name="ThumbnailCaptureTrigger" separator="."> + <suffix name="TabHidden" label="Triggered by the tab being hidden."/> + <suffix name="NavigatingAway" label="Triggered by navigating away."/> + <affected-histogram name="Thumbnails.CaptureOutcome"/> +</histogram_suffixes> + <histogram_suffixes name="TimestampTimebaseProcess" separator="."> + <obsolete> + Deprecated as of 11/2017 in Issue 650338. Using a DCHECK instead. + </obsolete> <suffix name="Browser"/> <suffix name="Renderer"/> <affected-histogram name="Event.TimestampHasValidTimebase"/> @@ -103424,6 +113198,8 @@ <affected-histogram name="NewTabPage.ContentSuggestions.TimeUntilPersistentFetch"/> <affected-histogram name="NewTabPage.ContentSuggestions.TimeUntilSoftFetch"/> + <affected-histogram + name="NewTabPage.ContentSuggestions.TimeUntilStartupFetch"/> </histogram_suffixes> <histogram_suffixes name="UserScriptRunLocation" separator="."> @@ -103473,6 +113249,14 @@ <affected-histogram name="WebRTC.Video.AdaptChangesPerMinute"/> </histogram_suffixes> +<histogram_suffixes name="VideoDecodeStatsDBOperations" separator="."> + <suffix name="Initialize" label="Success status for initializing the DB."/> + <suffix name="Read" label="Success status for reading from the DB"/> + <suffix name="Write" label="Success status for writing to the DB"/> + <suffix name="Destroy" label="Success status for destroying the DB"/> + <affected-histogram name="Media.VideoDecodeStatsDB.OpSuccess"/> +</histogram_suffixes> + <histogram_suffixes name="VideoEncodedQpStats" separator="."> <suffix name="H264" label="Video codec: H264. QP range: 0-51. No spatial layers."/> @@ -103495,6 +113279,23 @@ <affected-histogram name="WebRTC.Video.Encoded.Qp"/> </histogram_suffixes> +<histogram_suffixes name="VR.Mode" separator="."> + <suffix name="AllVR" label="Entered either VR Browsing or WebVR mode."/> + <suffix name="VRBrowsing" label="Entered VR Browsing Mode."/> + <suffix name="WebVRPresentation" + label="Entered WebVR presentation mode (also includes splash screen)."/> + <affected-histogram name="VR.Component.Assets.DurationUntilReady.OnEnter"/> + <affected-histogram name="VR.Component.Assets.Status.OnEnter"/> + <affected-histogram name="VR.NetworkConnectionType.OnEnter"/> +</histogram_suffixes> + +<histogram_suffixes name="VRFreNotCompleteType" separator="."> + <suffix name="VrBrowser" label="FRE not complete when starting Chrome"/> + <suffix name="WebVRAutopresent" + label="FRE not complete when starting WebVR auto-presentation"/> + <affected-histogram name="VRFreNotComplete"/> +</histogram_suffixes> + <histogram_suffixes name="VRRuntimeVersionGVRHeadset" separator="."> <suffix name="Cardboard" label="GVR version used with Carboard."/> <suffix name="Daydream" label="GVR version used with Daydream."/> @@ -103522,6 +113323,7 @@ label="The session is restricted to the period that browser is displaying WebVR contents."/> <affected-histogram name="VRSessionTime"/> + <affected-histogram name="VRSessionTimeFromDLA"/> <affected-histogram name="VRSessionVideoTime"/> </histogram_suffixes> @@ -103580,6 +113382,9 @@ <histogram_suffixes name="WebFontMissedCacheAndInterventionTriggeredOrNot" separator="." ordering="prefix"> + <obsolete> + Deprecated 10/2017. Related field trial has finished rolling out. + </obsolete> <owner>toyoshim@chromium.org</owner> <suffix name="MissedCacheAndInterventionNotTriggered" label="On missed cache and intervention not triggered"/> @@ -103589,6 +113394,26 @@ <affected-histogram name="WebFont.DownloadTime.1.10KBTo50KB"/> </histogram_suffixes> +<histogram_suffixes name="WebMediaPlayerImplTypes" separator="."> + <affected-histogram name="Media.TimeToFirstFrame"/> + <affected-histogram name="Media.TimeToMetadata"/> + <affected-histogram name="Media.TimeToPlayReady"/> + <suffix name="EME" + label="For Encrypted Media Extensions (EME) based playbacks."/> + <suffix name="MSE" + label="For Media Source Extensions (MSE) based playbacks."/> + <suffix name="SRC" label="For src= playbacks."/> + <affected-histogram name="Media.UnderflowDuration2"/> +</histogram_suffixes> + +<histogram_suffixes name="WebRTCEchoCancellerEstimate" separator="."> + <suffix name="Value" label="The last estimated value of the time interval"/> + <suffix name="Max" label="The maximum over the time interval"/> + <suffix name="Min" label="The minimum over the time interval"/> + <affected-histogram name="WebRTC.Audio.EchoCanceller.Erl"/> + <affected-histogram name="WebRTC.Audio.EchoCanceller.Erle"/> +</histogram_suffixes> + <histogram_suffixes name="WebRTCEchoCancellerStatisticType" separator="."> <suffix name="Average" label="The average over the time interval"/> <suffix name="Max" label="The maximum over the time interval"/> @@ -103617,12 +113442,14 @@ <suffix name="ExperimentGroup1"/> <suffix name="ExperimentGroup2"/> <suffix name="ExperimentGroup3"/> + <suffix name="ExperimentGroup4"/> <suffix name="S0"/> <suffix name="S1"/> <suffix name="S2"/> <affected-histogram name="WebRTC.Video.Decoded.Vp8.Qp"/> <affected-histogram name="WebRTC.Video.EndToEndDelayInMs"/> <affected-histogram name="WebRTC.Video.EndToEndDelayMaxInMs"/> + <affected-histogram name="WebRTC.Video.InterframeDelay95PercentileInMs"/> <affected-histogram name="WebRTC.Video.InterframeDelayInMs"/> <affected-histogram name="WebRTC.Video.InterframeDelayMaxInMs"/> <affected-histogram name="WebRTC.Video.KeyFramesReceivedInPermille"/> @@ -103632,6 +113459,8 @@ <affected-histogram name="WebRTC.Video.Screenshare.Decoded.Vp8.Qp"/> <affected-histogram name="WebRTC.Video.Screenshare.EndToEndDelayInMs"/> <affected-histogram name="WebRTC.Video.Screenshare.EndToEndDelayMaxInMs"/> + <affected-histogram + name="WebRTC.Video.Screenshare.InterframeDelay95PercentileInMs"/> <affected-histogram name="WebRTC.Video.Screenshare.InterframeDelayInMs"/> <affected-histogram name="WebRTC.Video.Screenshare.InterframeDelayMaxInMs"/> <affected-histogram @@ -103756,6 +113585,10 @@ </suffix> <suffix name="Cast"/> <suffix name="BetaForum"/> + <suffix name="CopyUrl"/> + <suffix name="OpenInChrome"/> + <suffix name="SiteSettings"/> + <suffix name="AppInfo"/> <affected-histogram name="WrenchMenu.TimeToAction"/> </histogram_suffixes>
diff --git a/tools/metrics/histograms/print_histogram_names.py b/tools/metrics/histograms/print_histogram_names.py new file mode 100755 index 0000000..9c93500 --- /dev/null +++ b/tools/metrics/histograms/print_histogram_names.py
@@ -0,0 +1,29 @@ +#!/usr/bin/env python +# Copyright 2018 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. + +"""Prints all histogram names.""" + +import os +import sys + +sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'common')) +import path_util + +import extract_histograms +import histogram_paths +import merge_xml + +def main(): + doc = merge_xml.MergeFiles(histogram_paths.ALL_XMLS) + histograms, had_errors = extract_histograms.ExtractHistogramsFromDom(doc) + if had_errors: + raise Error("Error parsing inputs.") + names = extract_histograms.ExtractNames(histograms) + for name in names: + print name + +if __name__ == '__main__': + main() +
diff --git a/tools/metrics/histograms/update_gpu_driver_bug_workaround_entries.py b/tools/metrics/histograms/update_gpu_driver_bug_workaround_entries.py index 1250dd7..7d3523cb 100755 --- a/tools/metrics/histograms/update_gpu_driver_bug_workaround_entries.py +++ b/tools/metrics/histograms/update_gpu_driver_bug_workaround_entries.py
@@ -47,7 +47,8 @@ update_histogram_enum.UpdateHistogramFromDict( 'GpuDriverBugWorkaroundEntry', ReadGpuDriverBugEntries(GPU_DRIVER_BUG_WORKAROUND_PATH), - GPU_DRIVER_BUG_WORKAROUND_PATH) + GPU_DRIVER_BUG_WORKAROUND_PATH, + os.path.basename(__file__)) if __name__ == '__main__':
diff --git a/tools/metrics/histograms/update_net_error_codes.py b/tools/metrics/histograms/update_net_error_codes.py index 37e53237..86b2acf 100755 --- a/tools/metrics/histograms/update_net_error_codes.py +++ b/tools/metrics/histograms/update_net_error_codes.py
@@ -49,12 +49,14 @@ update_histogram_enum.UpdateHistogramFromDict( 'NetErrorCodes', ReadNetErrorCodes(NET_ERROR_LIST_PATH, POSITIVE_ERROR_REGEX), - NET_ERROR_LIST_PATH) + NET_ERROR_LIST_PATH, + os.path.basename(__file__)) update_histogram_enum.UpdateHistogramFromDict( 'CombinedHttpResponseAndNetErrorCode', ReadNetErrorCodes(NET_ERROR_LIST_PATH, NEGATIVE_ERROR_REGEX), - NET_ERROR_LIST_PATH) + NET_ERROR_LIST_PATH, + os.path.basename(__file__)) if __name__ == '__main__': main()
diff --git a/tools/metrics/histograms/update_net_trust_anchors.py b/tools/metrics/histograms/update_net_trust_anchors.py new file mode 100755 index 0000000..95c4be79 --- /dev/null +++ b/tools/metrics/histograms/update_net_trust_anchors.py
@@ -0,0 +1,42 @@ +#!/usr/bin/env python +# Copyright 2017 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. + +"""Updates NetTrustAnchors enum in histograms.xml file with values read + from net/data/ssl/root_stores/root_stores.json. + +If the file was pretty-printed, the updated version is pretty-printed too. +""" + +import json +import os.path +import sys + +sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'common')) +import path_util + +import update_histogram_enum + +NET_ROOT_CERTS_PATH = 'net/data/ssl/root_stores/root_stores.json' + +def main(): + if len(sys.argv) > 1: + print >>sys.stderr, 'No arguments expected!' + sys.stderr.write(__doc__) + sys.exit(1) + + with open(path_util.GetInputFile(NET_ROOT_CERTS_PATH)) as f: + root_stores = json.load(f) + + spki_enum = {} + spki_enum[0] = 'Unknown or locally-installed trust anchor' + for spki, spki_data in sorted(root_stores['spkis'].items()): + spki_enum[int(spki_data['id'])] = spki + + update_histogram_enum.UpdateHistogramFromDict( + 'NetTrustAnchors', spki_enum, NET_ROOT_CERTS_PATH, + os.path.basename(__file__)) + +if __name__ == '__main__': + main()
diff --git a/tools/metrics/histograms/update_policies.py b/tools/metrics/histograms/update_policies.py index ec3487f..267013b 100644 --- a/tools/metrics/histograms/update_policies.py +++ b/tools/metrics/histograms/update_policies.py
@@ -36,22 +36,6 @@ return self.args[0] -def FlattenPolicies(policy_definitions, policy_list): - """Appends a list of policies defined in |policy_definitions| to - |policy_list|, flattening subgroups. - - Args: - policy_definitions: A list of policy definitions and groups, as in - policy_templates.json file. - policy_list: A list that has policy definitions appended to it. - """ - for policy in policy_definitions: - if policy['type'] == 'group': - FlattenPolicies(policy['policies'], policy_list) - else: - policy_list.append(policy) - - def UpdateHistogramDefinitions(policy_templates, doc): """Sets the children of <enum name="EnterprisePolicies" ...> node in |doc| to values generated from policy ids contained in |policy_templates|. @@ -80,8 +64,8 @@ policy_enum_node.appendChild(doc.createComment(comment)) # Add values generated from policy templates. - ordered_policies = [] - FlattenPolicies(policy_templates['policy_definitions'], ordered_policies) + ordered_policies = [x for x in policy_templates['policy_definitions'] + if x['type'] != 'group'] ordered_policies.sort(key=lambda policy: policy['id']) for policy in ordered_policies: node = doc.createElement('int')
diff --git a/tools/metrics/histograms/update_use_counter_css.py b/tools/metrics/histograms/update_use_counter_css.py index a4dd286..d1b7f99 100755 --- a/tools/metrics/histograms/update_use_counter_css.py +++ b/tools/metrics/histograms/update_use_counter_css.py
@@ -72,4 +72,4 @@ else: update_histogram_enum.UpdateHistogramFromDict( 'MappedCSSProperties', ReadCssProperties(USE_COUNTER_CPP_PATH), - USE_COUNTER_CPP_PATH) + USE_COUNTER_CPP_PATH, os.path.basename(__file__))
diff --git a/tools/metrics/metrics_python_tests.py b/tools/metrics/metrics_python_tests.py new file mode 100755 index 0000000..d619265 --- /dev/null +++ b/tools/metrics/metrics_python_tests.py
@@ -0,0 +1,33 @@ +#!/usr/bin/env python +# Copyright 2017 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 sys + +THIS_DIR = os.path.abspath(os.path.dirname(__file__)) +SRC_DIR = os.path.dirname(os.path.dirname(THIS_DIR)) +TYP_DIR = os.path.join(SRC_DIR, 'third_party', 'typ') + +if not TYP_DIR in sys.path: + sys.path.insert(0, TYP_DIR) + +import typ + + +def resolve(*paths): + return [os.path.join(THIS_DIR, *(p.split('/'))) for p in paths] + +sys.exit(typ.main(tests=resolve( + 'actions/extract_actions_test.py', + 'histograms/generate_expired_histograms_array_unittest.py', + 'ukm/pretty_print_test.py', + "../json_comment_eater/json_comment_eater_test.py", + "../json_to_struct/element_generator_test.py", + "../json_to_struct/struct_generator_test.py", + '../variations/fieldtrial_to_struct_unittest.py', + '../variations/fieldtrial_util_unittest.py', + '../../components/variations/service/' + 'generate_ui_string_overrider_unittest.py', + )))
diff --git a/tools/metrics/rappor/OWNERS b/tools/metrics/rappor/OWNERS index cdb260e..b96832d0 100644 --- a/tools/metrics/rappor/OWNERS +++ b/tools/metrics/rappor/OWNERS
@@ -1,3 +1,3 @@ # Metrics changes should always be reviewed by owners. -per-file rappor.xml=file://tools/metrics/OWNERS +per-file rappor.xml=file://base/metrics/OWNERS per-file rappor.xml=set noparent
diff --git a/tools/metrics/rappor/rappor.xml b/tools/metrics/rappor/rappor.xml index 0036c5d..740c60f 100644 --- a/tools/metrics/rappor/rappor.xml +++ b/tools/metrics/rappor/rappor.xml
@@ -292,6 +292,24 @@ </summary> </rappor-metric> +<rappor-metric name="BrowserActions.ServiceClient.PackageName" + type="UMA_RAPPOR_TYPE"> + <owner>ltian@chromium.org</owner> + <summary> + The package name for a client that requests for the Browser Actions context + menu. + </summary> +</rappor-metric> + +<rappor-metric name="BrowserActions.ServiceClient.PackageNameThirdParty" + type="UMA_RAPPOR_TYPE"> + <owner>ltian@chromium.org</owner> + <summary> + The package name for a client that requests for the Browser Actions context + menu, excluding Google Search App. + </summary> +</rappor-metric> + <rappor-metric name="Cast.Sender.MediaFrameUrl" type="ETLD_PLUS_ONE"> <owner>avayvod@chromium.org</owner> <owner>aberent@chromium.org</owner> @@ -303,7 +321,7 @@ <rappor-metric name="ContentSettings.MixedScript.DisplayedShield" type="ETLD_PLUS_ONE"> - <owner>lgarron@chromium.org</owner> + <owner>estark@chromium.org</owner> <summary> The eTLD+1 of a URL that displayed a mixed script shield. Note: this does *not* include pages with mixed scripts where the user has already clicked @@ -313,7 +331,7 @@ <rappor-metric name="ContentSettings.MixedScript.RanMixedScript" type="ETLD_PLUS_ONE"> - <owner>lgarron@chromium.org</owner> + <owner>estark@chromium.org</owner> <summary> The eTLD+1 of a URL that when mixed script actually ran. </summary> @@ -321,7 +339,7 @@ <rappor-metric name="ContentSettings.MixedScript.UserClickedAllow" type="ETLD_PLUS_ONE"> - <owner>lgarron@chromium.org</owner> + <owner>estark@chromium.org</owner> <summary> The eTLD+1 of a URL where the user clicked "Load unsafe scripts" on a mixed content shield. (This results in a page refresh. Mixed scripts @@ -344,6 +362,9 @@ <rappor-metric name="ContentSettings.PermissionActions_AudioCapture.Denied.Url2" type="LOW_FREQUENCY_ETLD_PLUS_ONE"> + <obsolete> + Removed in M64, see UMA or Permission Action Reporting data. + </obsolete> <owner>dominickn@chromium.org</owner> <owner>kcarattini@chromium.org</owner> <owner>miguelg@chromium.org</owner> @@ -369,6 +390,9 @@ <rappor-metric name="ContentSettings.PermissionActions_AudioCapture.Dismissed.Url2" type="LOW_FREQUENCY_ETLD_PLUS_ONE"> + <obsolete> + Removed in M64, see UMA or Permission Action Reporting data. + </obsolete> <owner>dominickn@chromium.org</owner> <owner>kcarattini@chromium.org</owner> <owner>miguelg@chromium.org</owner> @@ -394,6 +418,9 @@ <rappor-metric name="ContentSettings.PermissionActions_AudioCapture.Granted.Url2" type="LOW_FREQUENCY_ETLD_PLUS_ONE"> + <obsolete> + Removed in M64, see UMA or Permission Action Reporting data. + </obsolete> <owner>dominickn@chromium.org</owner> <owner>kcarattini@chromium.org</owner> <owner>miguelg@chromium.org</owner> @@ -419,6 +446,9 @@ <rappor-metric name="ContentSettings.PermissionActions_AudioCapture.Ignored.Url2" type="LOW_FREQUENCY_ETLD_PLUS_ONE"> + <obsolete> + Removed in M64, see UMA or Permission Action Reporting data. + </obsolete> <owner>dominickn@chromium.org</owner> <owner>kcarattini@chromium.org</owner> <owner>miguelg@chromium.org</owner> @@ -443,6 +473,9 @@ <rappor-metric name="ContentSettings.PermissionActions_AudioCapture.Revoked.Url2" type="LOW_FREQUENCY_ETLD_PLUS_ONE"> + <obsolete> + Removed in M64, see UMA or Permission Action Reporting data. + </obsolete> <owner>dominickn@chromium.org</owner> <owner>tsergeant@chromium.org</owner> <summary> @@ -462,6 +495,9 @@ <rappor-metric name="ContentSettings.PermissionActions_Flash.Denied.Url2" type="LOW_FREQUENCY_ETLD_PLUS_ONE"> + <obsolete> + Removed in M64, see UMA or Permission Action Reporting data. + </obsolete> <owner>dominickn@chromium.org</owner> <summary> The domain for which a Flash permission prompt was Denied. @@ -470,6 +506,9 @@ <rappor-metric name="ContentSettings.PermissionActions_Flash.Dismissed.Url2" type="LOW_FREQUENCY_ETLD_PLUS_ONE"> + <obsolete> + Removed in M64, see UMA or Permission Action Reporting data. + </obsolete> <owner>dominickn@chromium.org</owner> <summary> The domain for which a Flash permission prompt was Dismissed. @@ -478,6 +517,9 @@ <rappor-metric name="ContentSettings.PermissionActions_Flash.Granted.Url2" type="LOW_FREQUENCY_ETLD_PLUS_ONE"> + <obsolete> + Removed in M64, see UMA or Permission Action Reporting data. + </obsolete> <owner>dominickn@chromium.org</owner> <summary> The domain for which a Flash permission prompt was Granted. @@ -486,6 +528,9 @@ <rappor-metric name="ContentSettings.PermissionActions_Flash.Ignored.Url2" type="LOW_FREQUENCY_ETLD_PLUS_ONE"> + <obsolete> + Removed in M64, see UMA or Permission Action Reporting data. + </obsolete> <owner>dominickn@chromium.org</owner> <summary> The domain for which a Flash permission prompt was Ignored. @@ -504,6 +549,9 @@ <rappor-metric name="ContentSettings.PermissionActions_Geolocation.Denied.Url2" type="LOW_FREQUENCY_ETLD_PLUS_ONE"> + <obsolete> + Removed in M64, see UMA or Permission Action Reporting data. + </obsolete> <owner>dominickn@chromium.org</owner> <owner>miguelg@chromium.org</owner> <summary> @@ -525,6 +573,9 @@ <rappor-metric name="ContentSettings.PermissionActions_Geolocation.Dismissed.Url2" type="LOW_FREQUENCY_ETLD_PLUS_ONE"> + <obsolete> + Removed in M64, see UMA or Permission Action Reporting data. + </obsolete> <owner>dominickn@chromium.org</owner> <owner>miguelg@chromium.org</owner> <summary> @@ -545,6 +596,9 @@ <rappor-metric name="ContentSettings.PermissionActions_Geolocation.Granted.Url2" type="LOW_FREQUENCY_ETLD_PLUS_ONE"> + <obsolete> + Removed in M64, see UMA or Permission Action Reporting data. + </obsolete> <owner>dominickn@chromium.org</owner> <owner>miguelg@chromium.org</owner> <summary> @@ -565,6 +619,9 @@ <rappor-metric name="ContentSettings.PermissionActions_Geolocation.Ignored.Url2" type="LOW_FREQUENCY_ETLD_PLUS_ONE"> + <obsolete> + Removed in M64, see UMA or Permission Action Reporting data. + </obsolete> <owner>dominickn@chromium.org</owner> <owner>miguelg@chromium.org</owner> <summary> @@ -586,6 +643,9 @@ <rappor-metric name="ContentSettings.PermissionActions_Geolocation.Revoked.Url2" type="LOW_FREQUENCY_ETLD_PLUS_ONE"> + <obsolete> + Removed in M64, see UMA or Permission Action Reporting data. + </obsolete> <owner>dominickn@chromium.org</owner> <owner>jialiul@chromium.org</owner> <summary> @@ -617,6 +677,9 @@ <rappor-metric name="ContentSettings.PermissionActions_Notifications.Denied.Url2" type="LOW_FREQUENCY_ETLD_PLUS_ONE"> + <obsolete> + Removed in M64, see UMA or Permission Action Reporting data. + </obsolete> <owner>dominickn@chromium.org</owner> <owner>jialiul@chromium.org</owner> <summary> @@ -638,6 +701,9 @@ <rappor-metric name="ContentSettings.PermissionActions_Notifications.Dismissed.Url2" type="LOW_FREQUENCY_ETLD_PLUS_ONE"> + <obsolete> + Removed in M64, see UMA or Permission Action Reporting data. + </obsolete> <owner>dominickn@chromium.org</owner> <owner>jialiul@chromium.org</owner> <summary> @@ -659,6 +725,9 @@ <rappor-metric name="ContentSettings.PermissionActions_Notifications.Granted.Url2" type="LOW_FREQUENCY_ETLD_PLUS_ONE"> + <obsolete> + Removed in M64, see UMA or Permission Action Reporting data. + </obsolete> <owner>dominickn@chromium.org</owner> <owner>miguelg@chromium.org</owner> <summary> @@ -680,6 +749,9 @@ <rappor-metric name="ContentSettings.PermissionActions_Notifications.Ignored.Url2" type="LOW_FREQUENCY_ETLD_PLUS_ONE"> + <obsolete> + Removed in M64, see UMA or Permission Action Reporting data. + </obsolete> <owner>dominickn@chromium.org</owner> <owner>miguelg@chromium.org</owner> <summary> @@ -702,6 +774,9 @@ <rappor-metric name="ContentSettings.PermissionActions_Notifications.Revoked.Url2" type="LOW_FREQUENCY_ETLD_PLUS_ONE"> + <obsolete> + Removed in M64, see UMA or Permission Action Reporting data. + </obsolete> <owner>dominickn@chromium.org</owner> <owner>jialiul@chromium.org</owner> <summary> @@ -724,6 +799,9 @@ <rappor-metric name="ContentSettings.PermissionActions_VideoCapture.Denied.Url2" type="LOW_FREQUENCY_ETLD_PLUS_ONE"> + <obsolete> + Removed in M64, see UMA or Permission Action Reporting data. + </obsolete> <owner>dominickn@chromium.org</owner> <owner>kcarattini@chromium.org</owner> <owner>miguelg@chromium.org</owner> @@ -749,6 +827,9 @@ <rappor-metric name="ContentSettings.PermissionActions_VideoCapture.Dismissed.Url2" type="LOW_FREQUENCY_ETLD_PLUS_ONE"> + <obsolete> + Removed in M64, see UMA or Permission Action Reporting data. + </obsolete> <owner>dominickn@chromium.org</owner> <owner>kcarattini@chromium.org</owner> <owner>miguelg@chromium.org</owner> @@ -774,6 +855,9 @@ <rappor-metric name="ContentSettings.PermissionActions_VideoCapture.Granted.Url2" type="LOW_FREQUENCY_ETLD_PLUS_ONE"> + <obsolete> + Removed in M64, see UMA or Permission Action Reporting data. + </obsolete> <owner>dominickn@chromium.org</owner> <owner>kcarattini@chromium.org</owner> <owner>miguelg@chromium.org</owner> @@ -799,6 +883,9 @@ <rappor-metric name="ContentSettings.PermissionActions_VideoCapture.Ignored.Url2" type="LOW_FREQUENCY_ETLD_PLUS_ONE"> + <obsolete> + Removed in M64, see UMA or Permission Action Reporting data. + </obsolete> <owner>dominickn@chromium.org</owner> <owner>kcarattini@chromium.org</owner> <owner>miguelg@chromium.org</owner> @@ -823,6 +910,9 @@ <rappor-metric name="ContentSettings.PermissionActions_VideoCapture.Revoked.Url2" type="LOW_FREQUENCY_ETLD_PLUS_ONE"> + <obsolete> + Removed in M64, see UMA or Permission Action Reporting data. + </obsolete> <owner>dominickn@chromium.org</owner> <owner>tsergeant@chromium.org</owner> <summary> @@ -842,6 +932,9 @@ <rappor-metric name="ContentSettings.PermissionRequested.Geolocation.Url2" type="LOW_FREQUENCY_ETLD_PLUS_ONE"> + <obsolete> + Removed in M64, see UMA or Permission Action Reporting data. + </obsolete> <owner>dominickn@chromium.org</owner> <owner>miguelg@chromium.org</owner> <summary> @@ -860,6 +953,9 @@ <rappor-metric name="ContentSettings.PermissionRequested.Midi.Url2" type="LOW_FREQUENCY_ETLD_PLUS_ONE"> + <obsolete> + Removed in M64, see UMA or Permission Action Reporting data. + </obsolete> <owner>toyoshim@chromium.org</owner> <summary> The domain that requests using MIDI devices. @@ -878,6 +974,9 @@ <rappor-metric name="ContentSettings.PermissionRequested.Notifications.Url2" type="LOW_FREQUENCY_ETLD_PLUS_ONE"> + <obsolete> + Removed in M64, see UMA or Permission Action Reporting data. + </obsolete> <owner>dominickn@chromium.org</owner> <owner>miguelg@chromium.org</owner> <summary> @@ -887,6 +986,9 @@ <rappor-metric name="ContentSettings.PermissionRequested.ProtectedMedia.Url2" type="LOW_FREQUENCY_ETLD_PLUS_ONE"> + <obsolete> + Removed in M64, see UMA or Permission Action Reporting data. + </obsolete> <owner>xhwang@chromium.org</owner> <summary> The domain that issues a Protected Media Identifier permission prompt. @@ -1025,7 +1127,8 @@ The eTLD+1 of the website visited, along with the time between the initial creation of a touch event and the start of the frame swap on the GPU service caused by the generated ScrollUpdate gesture event. If no swap was induced - by the event, no recording is made. + by the event, no recording is made. The first GSU of every scrolling + sequence is excluded from this metric. </summary> <string-field name="Domain"> <summary> @@ -1039,6 +1142,30 @@ </uint64-field> </rappor-metric> +<rappor-metric + name="Event.Latency.ScrollUpdate.Wheel.TimeToScrollUpdateSwapBegin2" + type="UMA_RAPPOR_TYPE"> + <owner>nzolghadr@chromium.org</owner> + <owner>tdresser@chromium.org</owner> + <summary> + The eTLD+1 of the website visited, along with the time between the initial + creation of a wheel event and the start of the frame swap on the GPU service + caused by the generated ScrollUpdate gesture event. If no swap was induced + by the event, no recording is made. The first GSU of every scrolling + sequence is excluded from this metric. + </summary> + <string-field name="Domain"> + <summary> + The domain+registry of the URL. + </summary> + </string-field> + <uint64-field name="Latency"> + <summary> + Latency in microseconds representing Wheel.TimeToScrollUpdateSwapBegin2. + </summary> + </uint64-field> +</rappor-metric> + <rappor-metric name="Extensions.AffectedByIsolateExtensions" type="UMA_RAPPOR_TYPE"> <owner>nick@chromium.org</owner> @@ -1234,6 +1361,9 @@ </rappor-metric> <rappor-metric name="Media.OriginUrl.EME" type="ETLD_PLUS_ONE"> + <obsolete> + Superseded by media UKM metrics. No longer being logged. + </obsolete> <owner>xhwang@chromium.org</owner> <summary> The domain and registry of the URL that uses Encrypted Media Extensions @@ -1242,6 +1372,9 @@ </rappor-metric> <rappor-metric name="Media.OriginUrl.EME.Insecure" type="ETLD_PLUS_ONE"> + <obsolete> + Superseded by media UKM metrics. No longer being logged. + </obsolete> <owner>xhwang@chromium.org</owner> <summary> The domain and registry of the URL that uses Encrypted Media Extensions @@ -1511,6 +1644,9 @@ </rappor-metric> <rappor-metric name="Navigation.Scheme.Data" type="ETLD_PLUS_ONE"> + <obsolete> + No longer being logged. + </obsolete> <owner>meacer@chromium.org</owner> <summary> The domain and registry of the URL that resulted in a main frame navigation @@ -2297,6 +2433,15 @@ </summary> </rappor-metric> +<rappor-metric name="Tab.TabUnder.Opener" type="UMA_RAPPOR_TYPE"> + <owner>csharrison@chromium.org</owner> + <summary> + The domain and registry of the URL that attempted to initiate a + "tab-under" navigation. That is, a navigation which occurs in the + background without a user gesture, after the tab had already opened a popup. + </summary> +</rappor-metric> + <rappor-metric name="VR.FullScreenMode" type="ETLD_PLUS_ONE"> <owner>billorr@chromium.org</owner> <summary>
diff --git a/tools/metrics/ukm/.gitignore b/tools/metrics/ukm/.gitignore new file mode 100644 index 0000000..753bc09 --- /dev/null +++ b/tools/metrics/ukm/.gitignore
@@ -0,0 +1 @@ +ukm.old.xml
diff --git a/tools/metrics/ukm/OWNERS b/tools/metrics/ukm/OWNERS index 227946e..64076ca 100644 --- a/tools/metrics/ukm/OWNERS +++ b/tools/metrics/ukm/OWNERS
@@ -1,3 +1,3 @@ # Metrics changes should always be reviewed by owners. -per-file ukm.xml=file://tools/metrics/OWNERS +per-file ukm.xml=file://tools/metrics/ukm/PRIVACY_OWNERS per-file ukm.xml=set noparent
diff --git a/tools/metrics/ukm/PRIVACY_OWNERS b/tools/metrics/ukm/PRIVACY_OWNERS new file mode 100644 index 0000000..6a33d1c --- /dev/null +++ b/tools/metrics/ukm/PRIVACY_OWNERS
@@ -0,0 +1,10 @@ +# UKM metrics require additional privacy considerations, so they use +# a narrower set of reviewers than the rest of metrics codebase. +# +# Please make sure that your UKM collection proposal is approved by +# the privacy team before sending out your CL for review. + +asvitkine@chromium.org +bmcquade@chromium.org +holte@chromium.org +rkaplow@chromium.org
diff --git a/tools/metrics/ukm/builders_template.py b/tools/metrics/ukm/builders_template.py new file mode 100644 index 0000000..023d445b --- /dev/null +++ b/tools/metrics/ukm/builders_template.py
@@ -0,0 +1,89 @@ +# Copyright 2017 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. + +"""Templates for generating builder classes for UKM entries.""" + +import codegen + +HEADER = codegen.Template( +basename="ukm_builders.h", +file_template=""" +// Generated from gen_builders.py. DO NOT EDIT! +// source: ukm.xml + +#ifndef {file.guard_path} +#define {file.guard_path} + +#include <cstdint> + +#include "services/metrics/public/cpp/ukm_entry_builder_base.h" + +namespace ukm {{ +namespace builders {{ + +{event_code} + +}} // namespace builders +}} // namespace ukm + +#endif // {file.guard_path} +""", +event_template=""" +class {event.name} : public ::ukm::internal::UkmEntryBuilderBase {{ + public: + {event.name}(ukm::SourceId source_id); + ~{event.name}() override; + + static const char kEntryName[]; + static constexpr uint64_t kEntryNameHash = UINT64_C({event.hash}); + +{metric_code} +}}; +""", +metric_template=""" + static const char k{metric.name}Name[]; + static constexpr uint64_t k{metric.name}NameHash = UINT64_C({metric.hash}); + {event.name}& Set{metric.name}(int64_t value); +""") + +IMPL = codegen.Template( +basename="ukm_builders.cc", +file_template=""" +// Generated from gen_builders.py. DO NOT EDIT! +// source: ukm.xml + +#include "{file.dir_path}/ukm_builders.h" + +namespace ukm {{ +namespace builders {{ + +{event_code} + +}} // namespace builders +}} // namespace ukm +""", +event_template=""" +const char {event.name}::kEntryName[] = "{event.raw_name}"; + +{event.name}::{event.name}(ukm::SourceId source_id) : + ::ukm::internal::UkmEntryBuilderBase(source_id, kEntryNameHash) {{ +}} + +{event.name}::~{event.name}() = default; + +{metric_code} +""", +metric_template=""" +const char {event.name}::k{metric.name}Name[] = "{metric.raw_name}"; + +{event.name}& {event.name}::Set{metric.name}(int64_t value) {{ + AddMetric(k{metric.name}NameHash, value); + return *this; +}} +""") + + +def WriteFiles(outdir, relpath, data): + HEADER.WriteFile(outdir, relpath, data) + IMPL.WriteFile(outdir, relpath, data)
diff --git a/tools/metrics/ukm/codegen.py b/tools/metrics/ukm/codegen.py new file mode 100644 index 0000000..48c0ed3f --- /dev/null +++ b/tools/metrics/ukm/codegen.py
@@ -0,0 +1,85 @@ +# Copyright 2017 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. + +"""Objects for describing template code that can be generated from ukm.xml.""" + +import hashlib +import os +import re +import struct + +def sanitize_name(name): + s = re.sub('[^0-9a-zA-Z_]', '_', name) + return s + + +def HashName(name): + # This must match the hash function in base/metrics/metric_hashes.cc + # >Q: 8 bytes, big endian. + return struct.unpack('>Q', hashlib.md5(name).digest()[:8])[0] + + +class FileInfo(object): + def __init__(self, relpath, basename): + self.dir_path = relpath + self.guard_path = sanitize_name(os.path.join(relpath, basename)).upper() + + +class EventInfo(object): + def __init__(self, json_obj): + self.raw_name = json_obj['name'] + self.name = sanitize_name(json_obj['name']) + self.hash = HashName(json_obj['name']) + + +class MetricInfo(object): + def __init__(self, json_obj): + self.raw_name = json_obj['name'] + self.name = sanitize_name(json_obj['name']) + self.hash = HashName(json_obj['name']) + + +class Template(object): + """Template for producing code from ukm.xml.""" + + def __init__(self, basename, file_template, event_template, metric_template): + self.basename = basename + self.file_template = file_template + self.event_template = event_template + self.metric_template = metric_template + + def _StampMetricCode(self, file_info, event_info, metric): + return self.metric_template.format( + file=file_info, + event=event_info, + metric=MetricInfo(metric)) + + def _StampEventCode(self, file_info, event): + event_info = EventInfo(event) + metric_code = "".join(self._StampMetricCode(file_info, event_info, metric) + for metric in event['metrics']) + return self.event_template.format( + file=file_info, + event=event_info, + metric_code=metric_code) + + def _StampFileCode(self, relpath, data): + file_info = FileInfo(relpath, self.basename) + event_code = "".join(self._StampEventCode(file_info, event) + for event in data['events']) + return self.file_template.format( + file=file_info, + event_code=event_code) + + def WriteFile(self, outdir, relpath, data): + """Generates code and writes it to a file. + + Args: + relpath: The path to the file in the source tree. + rootdir: The root of the path the file should be written to. + data: The parsed ukm.xml data. + """ + output = open(os.path.join(outdir, self.basename), 'w') + output.write(self._StampFileCode(relpath, data)) + output.close()
diff --git a/tools/metrics/ukm/decode_template.py b/tools/metrics/ukm/decode_template.py new file mode 100644 index 0000000..298aed98b --- /dev/null +++ b/tools/metrics/ukm/decode_template.py
@@ -0,0 +1,69 @@ +# Copyright 2017 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 template for generating hash decoding code.""" + +import codegen + +HEADER = codegen.Template( +basename="ukm_decode.h", +file_template=""" +// Generated from gen_builders.py. DO NOT EDIT! +// source: ukm.xml + +#ifndef {file.guard_path} +#define {file.guard_path} + +#include <cstdint> +#include <map> + +namespace ukm {{ +namespace builders {{ + +{event_code} + +typedef std::map<uint64_t, const char*> DecodeMap; +DecodeMap CreateDecodeMap(); + +}} // namespace builders +}} // namespace ukm + +#endif // {file.guard_path} +""", +event_template="", +metric_template="") + +IMPL = codegen.Template( +basename="ukm_decode.cc", +file_template=""" +// Generated from gen_builders.py. DO NOT EDIT! +// source: ukm.xml + +#include "{file.dir_path}/ukm_decode.h" +#include "{file.dir_path}/ukm_builders.h" + +namespace ukm {{ +namespace builders {{ + +std::map<uint64_t, const char*> CreateDecodeMap() {{ + return {{ + {event_code} + }}; +}} + +}} // namespace builders +}} // namespace ukm +""", +event_template=""" + {{{event.name}::kEntryNameHash, {event.name}::kEntryName}}, + {metric_code} +""", +metric_template=""" + {{{event.name}::k{metric.name}NameHash, {event.name}::k{metric.name}Name}}, +""") + + +def WriteFiles(outdir, relpath, data): + HEADER.WriteFile(outdir, relpath, data) + IMPL.WriteFile(outdir, relpath, data)
diff --git a/tools/metrics/ukm/gen_builders.py b/tools/metrics/ukm/gen_builders.py index 000c602..80b0101 100755 --- a/tools/metrics/ukm/gen_builders.py +++ b/tools/metrics/ukm/gen_builders.py
@@ -10,178 +10,26 @@ entries and metrics. """ - import argparse -import logging -import os -import re import sys import model - - -HEADER = """ -// Generated from gen_builders.py. DO NOT EDIT! -// source: ukm.xml - -#ifndef SERVICES_METRICS_PUBLIC_CPP_UKM_BUILDERS_H -#define SERVICES_METRICS_PUBLIC_CPP_UKM_BUILDERS_H - -#include <map> - -#include "services/metrics/public/cpp/ukm_entry_builder_base.h" - -namespace ukm {{ -namespace builders {{ - -{decls} - -typedef std::map<uint64_t, const char*> DecodeMap; -DecodeMap CreateDecodeMap(); - -}} // namespace builders -}} // namespace ukm - -#endif // SERVICES_METRICS_PUBLIC_CPP_UKM_BUILDERS_H -""" - -BODY = """ -// Generated from gen_builders.py. DO NOT EDIT! -// source: ukm.xml - -#include "services/metrics/public/cpp/ukm_builders.h" - -#include "base/metrics/metrics_hashes.h" - -namespace ukm {{ -namespace builders {{ - -{impls} - -std::map<uint64_t, const char*> CreateDecodeMap() {{ - return {{ - {decodes} - }}; -}} - -}} // namespace builders -}} // namespace ukm -""" - -BUILDER_DECL = """ -class {name} : public ::ukm::internal::UkmEntryBuilderBase {{ - public: - {name}(ukm::SourceId source_id); - ~{name}() override; - - static const char kEntryName[]; - -{setters} -}}; -""" - -SETTER_DECL = """ - static const char k{metric}Name[]; - {name}& Set{metric}(int64_t value); -""" - -BUILDER_IMPL = """ -const char {name}::kEntryName[] = "{raw}"; - -{name}::{name}(ukm::SourceId source_id) : - ::ukm::internal::UkmEntryBuilderBase( - source_id, - base::HashMetricName(kEntryName)) {{ -}} - -{name}::~{name}() = default; - -{setters} -""" - -SETTER_IMPL = """ -const char {name}::k{metric}Name[] = "{raw}"; - -{name}& {name}::Set{metric}(int64_t value) {{ - AddMetric(base::HashMetricName(k{metric}Name), value); - return *this; -}} -""" - -ENTRY_DECODE = """ - {{base::HashMetricName({name}::kEntryName), {name}::kEntryName}}, - {metric_decodes} -""" - -METRIC_DECODE = """ - {{base::HashMetricName({name}::k{metric}Name), {name}::k{metric}Name}}, -""" +import builders_template +import decode_template parser = argparse.ArgumentParser(description='Generate UKM entry builders') parser.add_argument('--input', help='Path to ukm.xml') -parser.add_argument('--output', help='Path to generated directory') - -def sanitize_name(name): - s = re.sub('[^0-9a-zA-Z_]', '_', name) - return s - -def GetSetterDecl(builder_name, metric): - metric_name = sanitize_name(metric['name']) - return SETTER_DECL.format(name=builder_name, metric=metric_name) - -def GetBuilderDecl(event): - builder_name = sanitize_name(event['name']) - setters = "".join(GetSetterDecl(builder_name, metric) - for metric in event['metrics']) - return BUILDER_DECL.format(name=builder_name, setters=setters) - -def GetHeader(data): - decls = "\n".join(GetBuilderDecl(event) for event in data['events']) - return HEADER.format(decls=decls) - -def WriteHeader(outdir, data): - output = open(os.path.join(outdir, "ukm_builders.h"), 'w') - output.write(GetHeader(data)) - -def GetSetterImpl(builder_name, metric): - metric_name = sanitize_name(metric['name']) - return SETTER_IMPL.format(name=builder_name, metric=metric_name, - raw=metric['name']) - -def GetBuilderImpl(event): - builder_name = sanitize_name(event['name']) - setters = "\n".join(GetSetterImpl(builder_name, metric) - for metric in event['metrics']) - return BUILDER_IMPL.format(name=builder_name, raw=event['name'], - setters=setters) - -def WriteBody(outdir, data): - output = open(os.path.join(outdir, "ukm_builders.cc"), 'w') - output.write(GetBody(data)) - -def GetMetricDecode(builder_name, metric): - metric_name = sanitize_name(metric['name']) - return METRIC_DECODE.format(name=builder_name, metric=metric_name) - -def GetEntryDecode(event): - builder_name = sanitize_name(event['name']) - metric_decodes = "\n".join(GetMetricDecode(builder_name, metric) - for metric in event['metrics']) - return ENTRY_DECODE.format(name=builder_name, - metric_decodes=metric_decodes) - -def GetBody(data): - impls = "\n".join(GetBuilderImpl(event) for event in data['events']) - decodes = "\n".join(GetEntryDecode(event) for event in data['events']) - return BODY.format(impls=impls, decodes=decodes) +parser.add_argument('--output', help='Path to generated files.') def main(argv): args = parser.parse_args() data = model.UKM_XML_TYPE.Parse(open(args.input).read()) - WriteHeader(args.output, data) - WriteBody(args.output, data) + relpath = 'services/metrics/public/cpp/' + builders_template.WriteFiles(args.output, relpath, data) + decode_template.WriteFiles(args.output, relpath, data) return 0 + if '__main__' == __name__: sys.exit(main(sys.argv))
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml index 098d9f6..e17b387 100644 --- a/tools/metrics/ukm/ukm.xml +++ b/tools/metrics/ukm/ukm.xml
@@ -18,6 +18,18 @@ <ukm-configuration> +<event name="AbusiveExperienceHeuristic"> + <summary> + Various metrics recording experiences which are commonly used for abusive + purposes. + </summary> + <metric name="DidTabUnder"> + <summary> + True if the page attempted a tab-under navigation. + </summary> + </metric> +</event> + <event name="Autofill.CardUploadDecision"> <owner>sebsg@chromium.org</owner> <metric name="UploadDecision"> @@ -279,6 +291,125 @@ </metric> </event> +<event name="Blink.UpdateTime"> + <owner>vmpstr@chromium.org</owner> + <summary> + Metrics that measure various update times in Blink. This includes paint, + compositing, and layout update times. The metrics are recorded once per + second and at the destruction of the local frame root. + </summary> + <metric name="Compositing.Average"> + <summary> + The average time taken by the compositing phase in microseconds in the + event period. + </summary> + </metric> + <metric name="Compositing.WorstCase"> + <summary> + The longest single time taken by the compositing phase in microseconds in + the event period. + </summary> + </metric> + <metric name="Paint.Average"> + <summary> + The average time taken by the paint phase in microseconds in the event + period. + </summary> + </metric> + <metric name="Paint.WorstCase"> + <summary> + The longest single time taken by the paint phase in microseconds in the + event period. + </summary> + </metric> + <metric name="PrePaint.Average"> + <summary> + The average time taken by the pre-paint phase in microseconds in the event + period. + </summary> + </metric> + <metric name="PrePaint.WorstCase"> + <summary> + The longest single time taken by the pre-paint phase in microseconds in + the event period. + </summary> + </metric> + <metric name="StyleAndLayout.Average"> + <summary> + The average time taken by the style and layout phases in microseconds in + the event period. + </summary> + </metric> + <metric name="StyleAndLayout.WorstCase"> + <summary> + The longest single time taken by the style and layout phases in + microseconds in the event period. + </summary> + </metric> +</event> + +<event name="Blink.UseCounter"> + <owner>loonybear@chromium.org</owner> + <summary> + Collects data for a subset of UseCounter features. When UMA UseCounter data + shows a behaviour that is rare but too common to blindly change. This metric + should be used to reason about whether a breaking change is acceptable or + not. + </summary> + <metric name="Feature"> + <summary> + Opt-in UseCounter feature. + </summary> + </metric> +</event> + +<event name="Compositor.UserInteraction"> + <owner>khushalsagar@chromium.org</owner> + <summary> + Metrics related to user interaction handled by the compositor. This includes + user gestures like scrolling, pinch-zoom and page-scale animations triggered + in response to a double-tap event. The length of the user interaction is + defined as the time the compositor is running an animation resulting from + user input. + </summary> + <metric name="CheckerboardedContentArea"> + <summary> + The number of visible pixels per frame checkerboarded during this + interaction. + </summary> + </metric> + <metric name="CheckerboardedContentAreaRatio"> + <summary> + The percentage of visible pixels per frame checkerboarded during this + interaction. This value should be between [0, 100]. + </summary> + </metric> + <metric name="CheckerboardedImagesCount"> + <summary> + The number of images checker-imaged and re-rasterized during this + interaction. + </summary> + </metric> + <metric name="NumMissingTiles"> + <summary> + The number of visible tiles per frame checkerboarded during this + interaction. + </summary> + </metric> +</event> + +<event name="Compositor.Rendering"> + <owner>khushalsagar@chromium.org</owner> + <summary> + Metrics related to rendering in the compositor. + </summary> + <metric name="CheckerboardedImagesCount"> + <summary> + The number of images checker-imaged and re-rasterized on this page. + </summary> + </metric> +</event> + <event name="ContextualSearch"> <owner>donnd@chromium.org</owner> <summary> @@ -305,12 +436,38 @@ and punctuation. </summary> </metric> + <metric name="IsEntityEligible"> + <summary> + Emits a 1 or 0 to indicate whether the IsEntity boolean ever had a chance + of being true or not. When we're dealing with languages other than ones + where our simple entity-detection can work this signal is false. + </summary> + </metric> + <metric name="IsHttp"> + <summary> + Emits a 1 or 0 to indicate whether the base page is HTTP (insecure). + </summary> + </metric> + <metric name="IsLanguageMismatch"> + <summary> + Emits a 1 or 0 to indicate whether the language of the base page is a + mismatch from the list of languages the user knows, so they might want + translation. + </summary> + </metric> <metric name="IsLongWord"> <summary> Emits a 1 or 0 to indicate whether the word tapped was considered long (at least 10 chars in length). </summary> </metric> + <metric name="IsSecondTapOverride"> + <summary> + Emits a 1 or 0 to indicate whether the tap was an override of normal tap + suppression because it was considered a second tap on a word after the + first tap was suppressed. + </summary> + </metric> <metric name="IsShortWord"> <summary> Emits a 1 or 0 to indicate whether the word tapped was considered short @@ -323,6 +480,16 @@ word, rather than in the middle 50% of the word. </summary> </metric> + <metric name="OutcomeRankerDidPredict"> + <summary> + Emits a 1 or 0 to indicate whether Ranker was able to make a prediction. + </summary> + </metric> + <metric name="OutcomeRankerPrediction"> + <summary> + Emits a 1 or 0 to indicate what Ranker's prediction was for this record. + </summary> + </metric> <metric name="OutcomeWasCardsDataShown"> <summary> Emits a 1 or 0 to indicate whether any Contextual Cards data was shown in @@ -377,9 +544,9 @@ DPs. </summary> </metric> - <metric name="TapDuration"> + <metric name="TapDurationMs"> <summary> - The duration of the tap gesture expressed in milliseconds. + The duration of the tap gesture expressed as an integer in milliseconds. </summary> </metric> <metric name="WasScreenBottom"> @@ -390,17 +557,188 @@ </metric> </event> +<event name="CPUUsageMeasurement"> + <owner>matthalp@google.com</owner> + <owner>oysteine@chromium.org</owner> + <summary> + A CPU usage measurement that corresponds to a tick in a CPU usage + time-series The tick interval is set as a FieldTrial parameter, which can be + obtained by cross referencing the UKM entry with the FieldTrial it was + launched with. There is also some metadata stored to determine how faitful + the CPU usage measurement is (e.g. NumberOfCoresidentTabs). + </summary> + <metric name="CPUUsage"> + <summary> + CPU usage measurement. + </summary> + </metric> + <metric name="NumberOfCoresidentTabs"> + <summary> + Number of co-resident tabs in all of the render processes a tab is + associated with when the CPU usage measurement is taken. + </summary> + </metric> + <metric name="Tick"> + <summary> + Tick CPU Usage measurement was taken at. + </summary> + </metric> +</event> + +<event name="Document.OutliveTimeAfterShutdown"> + <owner>hajimehoshi@chromium.org</owner> + <owner>keishi@chromium.org</owner> + <summary> + Recorded when a Document object survives certain number of garbage + collections after detached. It is expected that regular Document objects are + destroyed soon after detached, and if a document outlives longer, probably + this can be leaked. + </summary> + <metric name="GCCount"> + <summary> + Measures the numbers of garbarge collection after the document is + detached. This is recorded when the number reached certain numbers like 5 + or 10. + </summary> + </metric> +</event> + +<event name="Download.Started"> + <owner>jming@chromium.org</owner> + <summary> + Metrics taken when a download begins. It has one Download.Ended and none to + multiple Download.Interrupted/Download.Resumed events associated with it. + </summary> + <metric name="DownloadId"> + <summary> + The id of the download that is used to associate separate events. + </summary> + </metric> + <metric name="DownloadSource"> + <summary> + The source of the download, expressed as an enum defined in DownloadEntry. + </summary> + </metric> + <metric name="FileType"> + <summary> + The type of file that is downloaded, expressed as an enum defined in + DownloadContentType. + </summary> + </metric> +</event> + +<event name="Download.Completed"> + <owner>jming@chromium.org</owner> + <summary> + Metrics taken when a download completes. Its parent event is + Download.Started. + </summary> + <metric name="DownloadId"> + <summary> + The id of the download that is used to associate separate events. + </summary> + </metric> + <metric name="ResultingFileSize"> + <summary> + The size of the file that is downloaded, expressed in kilobytes with + exponentially growing buckets. + </summary> + </metric> + <metric name="TimeSinceStart"> + <summary> + The difference in the time between when the download finished and when it + began, expressed in miliseconds. + </summary> + </metric> +</event> + +<event name="Download.Interrupted"> + <owner>jming@chromium.org</owner> + <summary> + Metrics taken when a download is interrupted. Its parent event is + Download.Started. + </summary> + <metric name="ChangeInFileSize"> + <summary> + The difference in the size of the file that is downloaded compared to the + initial reported size, expressed in kilobytes with exponentially growing + buckets. + </summary> + </metric> + <metric name="DownloadId"> + <summary> + The id of the download that is used to associate separate events. + </summary> + </metric> + <metric name="Reason"> + <summary> + The reason the download was interrupted, expressed as an enum defined in + DownloadInterruptReason. + </summary> + </metric> + <metric name="ResultingFileSize"> + <summary> + The size of the file that is downloaded, expressed in kilobytes with + exponentially growing buckets. + </summary> + </metric> + <metric name="TimeSinceStart"> + <summary> + The difference in the time between when the download interrupted and when + it began, expressed in miliseconds. + </summary> + </metric> +</event> + +<event name="Download.Resumed"> + <owner>jming@chromium.org</owner> + <summary> + Metrics taken when a download is resumed. Its parent event is + Download.Started. + </summary> + <metric name="DownloadId"> + <summary> + The id of the download that is used to associate separate events. + </summary> + </metric> + <metric name="Mode"> + <summary> + The mode by which the download was resumed, expressed as an enum defined + in ResumeMode. + </summary> + </metric> + <metric name="TimeSinceStart"> + <summary> + The difference in the time between when the download resumed and when it + began, expressed in miliseconds. + </summary> + </metric> +</event> + <event name="Event.ScrollUpdate.Touch"> <owner>nzolghadr@chromium.org</owner> <summary> Metrics related to a scroll action caused by the generated ScrollUpdate gesture event. </summary> + <metric name="IsMainThread"> + <summary> + Whether the event is handled on the main thread or not. + </summary> + </metric> + <metric name="TimeToHandled"> + <summary> + The time in microseconds between initial creation of a touch event and the + generated ScrollUpdate gesture event is handled on main/impl thread. If no + swap was induced by the ScrollUpdate gesture event, no recording is made. + </summary> + </metric> <metric name="TimeToScrollUpdateSwapBegin"> <summary> The time in microseconds between the initial creation of a touch event and the start of the frame swap on the GPU service. If no swap was induced by - the event, no recording is made. + the event, no recording is made. The first GSU of every scrolling sequence + is excluded from this metric. </summary> </metric> </event> @@ -411,6 +749,19 @@ Metrics related to first scroll action caused by the generated ScrollUpdate gesture event. </summary> + <metric name="IsMainThread"> + <summary> + Whether the event is handled on the main thread or not. + </summary> + </metric> + <metric name="TimeToHandled"> + <summary> + The time in microseconds between initial creation of a touch event and the + first generated ScrollUpdate gesture event in a given scroll gesture event + sequence is handled on main/impl thread. If no swap was induced by the + ScrollUpdate gesture event, no recording is made. + </summary> + </metric> <metric name="TimeToScrollUpdateSwapBegin"> <summary> The time in microseconds between initial creation of a touch event and the @@ -422,12 +773,55 @@ </metric> </event> +<event name="Event.ScrollUpdate.Wheel"> + <owner>nzolghadr@chromium.org</owner> + <owner>tdresser@chromium.org</owner> + <summary> + Metrics related to a scroll action caused by the generated ScrollUpdate + gesture event. + </summary> + <metric name="IsMainThread"> + <summary> + Whether the event is handled on the main thread or not. + </summary> + </metric> + <metric name="TimeToHandled"> + <summary> + The time in microseconds between initial creation of a wheel event and the + generated ScrollUpdate gesture event is handled on main/impl thread. If no + swap was induced by the ScrollUpdate gesture event, no recording is made. + The first GSU of every scrolling sequence is excluded from this metric. + </summary> + </metric> + <metric name="TimeToScrollUpdateSwapBegin"> + <summary> + The time in microseconds between the initial creation of a wheel event and + the start of the frame swap on the GPU service. If no swap was induced by + the event, no recording is made. The first GSU of every scrolling sequence + is excluded from this metric. + </summary> + </metric> +</event> + <event name="Event.ScrollBegin.Wheel"> <owner>nzolghadr@chromium.org</owner> <summary> Metrics related to first scroll action caused by the generated ScrollUpdate gesture event. </summary> + <metric name="IsMainThread"> + <summary> + Whether the event is handled on the main thread or not. + </summary> + </metric> + <metric name="TimeToHandled"> + <summary> + The time in microseconds between initial creation of a wheel event and the + first generated ScrollUpdate gesture event in a given scroll gesture event + sequence is handled on main/impl thread. If no swap was induced by the + ScrollBegin gesture event, no recording is made. + </summary> + </metric> <metric name="TimeToScrollUpdateSwapBegin"> <summary> The time in microseconds between the initial creation of a wheel event and @@ -514,6 +908,94 @@ </metric> </event> +<event name="Media.Autoplay.Attempt"> + <owner>mlamouri@chromium.org</owner> + <owner>media-dev@chromium.org</owner> + <summary> + Event recorded when there is an attempt to autoplay (ie. no user gesture). + It will be recorded regardless of the result of this attempt. + </summary> + <metric name="AudioTrack"> + <summary> + Whether the element had an audio track when autoplay was attempted. + </summary> + </metric> + <metric name="HighMediaEngagement"> + <summary> + Whether the document has a high media engagement. + </summary> + </metric> + <metric name="Muted"> + <summary> + Whether the element was muted when autoplay was attempted. + </summary> + </metric> + <metric name="Source"> + <summary> + Source of the autoplay attempt: 0 for attribute; 1 for play(). + </summary> + </metric> + <metric name="UserGestureRequired"> + <summary> + Whether a user gesture was required per autoplay rules at the time of + attempt. By definition there is no user gesture on the stack when the + attempt is registered. + </summary> + </metric> + <metric name="UserGestureStatus"> + <summary> + Reflects the current status of user gesture/activation. This is a bit + field with the following values: - 0b0001 if there is a user gesture on + the stack; - 0b0010 if there was a user gesture on the page (ie. was + activated); - 0b0100 if there was a user gesture propogated after a + navigation. + </summary> + </metric> + <metric name="VideoTrack"> + <summary> + Whether the element had a video track when autoplay was attempted. + </summary> + </metric> +</event> + +<event name="Media.Autoplay.Muted.UnmuteAction"> + <owner>mlamouri@chromium.org</owner> + <owner>media-dev@chromium.org</owner> + <summary> + Event recorded when there is an attempt to unmute an media that was + autoplaying following the rules of autoplay muted. + </summary> + <metric name="Result"> + <summary> + 0 means that the unmute failed because it happened without a user gesture. + 1 means that it succeeded because it had a user gesture. + </summary> + </metric> + <metric name="Source"> + <summary> + Similar to "Source" in "Media.Autoplay.Attempt" with + the addition of a value for both sources being used: 0 for attribute; 1 + for play(); 2 for both attempted. + </summary> + </metric> +</event> + +<event name="Media.Engagement.ShortPlaybackIgnored"> + <owner>beccahughes@chromium.org</owner> + <owner>media-dev@chromium.org</owner> + <summary> + The Media Engagement index stores the number of significant media playbacks + per origin and the number of audible players. From that we calculate a Media + Engagement Score. + + Media with a short playback length is ignored so we are logging any time the + player is ignored with the length in msec. This will allow us to identify + whether sites are being penalized or there is abuse and allow us to tweak + the length considered "short". + </summary> + <metric name="Length"/> +</event> + <event name="Media.Engagement.SessionFinished"> <owner>beccahughes@chromium.org</owner> <owner>media-dev@chromium.org</owner> @@ -529,10 +1011,30 @@ <metric name="Engagement.IsHigh"/> <metric name="Engagement.Score"/> <metric name="Playbacks.Delta"/> + <metric name="Playbacks.SecondsSinceLast"/> <metric name="Playbacks.Total"/> + <metric name="Player.Audible.Delta"/> + <metric name="Player.Audible.Total"/> + <metric name="Player.Significant.Delta"/> + <metric name="Player.Significant.Total"/> <metric name="Visits.Total"/> </event> +<event name="Media.SiteMuted" singular="True"> + <owner>steimel@chromium.org</owner> + <owner>media-dev@chromium.org</owner> + <summary> + Event recorded when a website tries to play audio but is muted by the sound + content setting. + </summary> + <metric name="MuteReason"> + <summary> + Enum value giving the reason the site was muted. Defined as + |SoundContentSettingObserver::MuteReason|. + </summary> + </metric> +</event> + <event name="Media.WatchTime"> <obsolete> Deprecated 8/2017 in favor Media.BasicPlayback @@ -584,14 +1086,76 @@ <metric name="AudioVideo.SRC"/> </event> +<event name="Media.WebMediaPlayerState"> + <owner>dalecurtis@chromium.org</owner> + <owner>media-dev@chromium.org</owner> + <summary> + Final state of WebMediaPlayerImpl instance. Records only immutable playback + properties. Contains a PlaybackID which links to Media.BasicPlayback events. + </summary> + <metric name="FinalPipelineStatus"> + <summary> + media::PipelineStatus enum value. Always 0 if the playback succeeded; all + other values indicate the playback ended in an error. + </summary> + </metric> + <metric name="IsEME"> + <summary> + Boolean value indicating if this event is for an EME playback. Note: EME + can be attached anytime during the lifecycle of a WebMediaPlayerImpl, but + once attached can't be removed. + </summary> + </metric> + <metric name="IsMSE"> + <summary> + Boolean value indicating if this event is for an MSE playback. If false it + means this was a SRC playback. + </summary> + </metric> + <metric name="IsTopFrame"> + <summary> + Flag indicating whether the report comes from the top frame or some inner + frame. For privacy, metrics from inner frames are recorded with the top + frame's origin, so this flag helps separate top frame vs. embedded + playbacks. + </summary> + </metric> + <metric name="PlayerID"> + <summary> + ID which corresponds to a given WebMediaPlayerImpl instance. May be linked + with Media.BasicPlayback events to understand a playback more deeply. + </summary> + </metric> + <metric name="TimeToFirstFrame"> + <summary> + Time in milliseconds from when WebMediaPlayerImpl starts loading until the + first video frame has been shown. + </summary> + </metric> + <metric name="TimeToMetadata"> + <summary> + Time in milliseconds from when WebMediaPlayerImpl starts loading until + metadata is known. + </summary> + </metric> + <metric name="TimeToPlayReady"> + <summary> + Time in milliseconds from when WebMediaPlayerImpl starts loading until it + has buffered enough to start playback. + </summary> + </metric> +</event> + <event name="Media.BasicPlayback"> <owner>dalecurtis@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> - Core metrics associated with a media playback. Only recorded if a playback - qualifies for WatchTime recording (see Media.WatchTime metrics). Reported at - the time of WebMediaPlayer destruction or render process termination; - whichever comes first. + Core metrics associated with a media playback through WebMediaPlayerImpl. + Reported at the time of WatchTimeRecorder destruction or render process + termination; whichever comes first. There will be multiple entries for a + given playback; one for every PlaybackProperties change as well as one for + foreground and background. Records may be aggregated based on PlayerID and + correlated with the Media.WebMediaPlayerState event. </summary> <metric name="AudioCodec"> <summary> @@ -599,6 +1163,12 @@ is true because we don't always know the codec. </summary> </metric> + <metric name="AudioDecoderName"> + <summary> + Enumeration of audio decoder names, zero if none or unknown (Cast, HLS, + etc). See WatchTimeRecorder::AudioDecoderName enum for expected values. + </summary> + </metric> <metric name="HasAudio"> <summary> Boolean value indicating the presence of audio. @@ -625,6 +1195,14 @@ means this was a SRC playback. </summary> </metric> + <metric name="IsTopFrame"> + <summary> + Flag indicating whether the report comes from the top frame or some inner + frame. For privacy, metrics from inner frames are recorded with the top + frame's origin, so this flag helps separate top frame vs. embedded + playbacks. + </summary> + </metric> <metric name="LastPipelineStatus"> <summary> media::PipelineStatus enum value. Always 0 if the playback succeeded; all @@ -638,6 +1216,12 @@ the number of rebuffering events. </summary> </metric> + <metric name="PlayerID"> + <summary> + ID which corresponds to a given WebMediaPlayerImpl instance. May be linked + with Media.WebMediaPlayerState events to understand playback more deeply. + </summary> + </metric> <metric name="RebuffersCount"> <summary> Integer count of the number of times playback experienced rebuffering. @@ -649,6 +1233,12 @@ is true because we don't always know the codec. </summary> </metric> + <metric name="VideoDecoderName"> + <summary> + Enumeration of video decoder names, zero if none or unknown (Cast, HLS, + etc). See WatchTimeRecorder::VideoDecoderName enum for expected values. + </summary> + </metric> <metric name="VideoNaturalHeight"> <summary> Integer value indicating the natural height of the playback. @@ -709,11 +1299,125 @@ </metric> </event> +<event name="Media.VideoDecodePerfRecord"> + <owner>chcunningham@chromium.org</owner> + <owner>media-dev@chromium.org</owner> + <summary> + A record of decoding performance metrics from a video playback with the + given stream characteristics (profile, resolution, fps). Also includes what + Media Capabilities API would claim for such a stream as a means of assessing + the API's accuracy. + </summary> + <metric name="Perf.ApiWouldClaimIsPowerEfficient"> + <summary> + Boolean signaling whether MediaCapabilities would classify streams with + these characteristics as power efficient prior to considering this latest + record. MediaCapabilities prediction is accurate when this value matches + RecordIsPowerEfficient. + </summary> + </metric> + <metric name="Perf.ApiWouldClaimIsSmooth"> + <summary> + Boolean signaling whether MediaCapabilities would classify streams with + these characteristics as smooth prior to considering this latest record. + MediaCapabilities prediction is accurate when this value matches + RecordIsSmooth. + </summary> + </metric> + <metric name="Perf.PastVideoFramesDecoded"> + <summary> + Integer count of past video frames decoded for the given video type. + </summary> + </metric> + <metric name="Perf.PastVideoFramesDropped"> + <summary> + Integer count of past video frames dropped for the given video type. + </summary> + </metric> + <metric name="Perf.PastVideoFramesPowerEfficient"> + <summary> + Integer count of past video frames power efficient for the given video + type. + </summary> + </metric> + <metric name="Perf.RecordIsPowerEfficient"> + <summary> + Boolean signaling whether MediaCapabilities would classify this isolated + playback record as power efficient. + </summary> + </metric> + <metric name="Perf.RecordIsSmooth"> + <summary> + Boolean signaling whether MediaCapabilities would classify this isolated + playback record as smooth. + </summary> + </metric> + <metric name="Perf.VideoFramesDecoded"> + <summary> + Integer count of the video frames decoded in this record. + </summary> + </metric> + <metric name="Perf.VideoFramesDropped"> + <summary> + Integer count of the video frames dropped in this record. Should not + exceed VideoFramesDecoded. + </summary> + </metric> + <metric name="Perf.VideoFramesPowerEfficient"> + <summary> + Integer count of the video frames decoded via power efficient means in + this record. Should not exceed VideoFramesDecoded. + </summary> + </metric> + <metric name="Video.CodecProfile"> + <summary> + media::VideoCodecProfile enum value. Can be VIDEO_CODEC_PROFILE_UNKNOWN if + we don't know the audio codec. + </summary> + </metric> + <metric name="Video.FramesPerSecond"> + <summary> + Integer representing video frames per second. This is the cadence of video + frames as described by stream timestamps multiplied by + HTMLMediaELement.playbackRate. + </summary> + </metric> + <metric name="Video.InTopFrame"> + <summary> + Flag indicating whether the record comes from the top frame or some inner + frame. For privacy, metrics from inner frames are recorded with the top + frame's origin, so this flag helps separate top frame vs. embedded + playbacks. + </summary> + </metric> + <metric name="Video.NaturalHeight"> + <summary> + Integer representing height of video natural size. + </summary> + </metric> + <metric name="Video.NaturalWidth"> + <summary> + Integer representing width of video natural size. + </summary> + </metric> + <metric name="Video.PlayerID"> + <summary> + ID which corresponds to a given WebMediaPlayerImpl instance. May be linked + with Media.WebMediaPlayerState events to understand playback more deeply. + </summary> + </metric> +</event> + <event name="Memory.Experimental"> <owner>erikchen@chromium.org</owner> <summary> Metrics associated with memory consumption, in MB. </summary> + <metric name="ArrayBuffer"> + <summary> + Measure of memory consumed by Array Buffer. + </summary> + </metric> <metric name="BlinkGC"> <summary> Measure of memory consumed by Oilpan. @@ -724,17 +1428,43 @@ Measure of memory consumed by GL command buffer. </summary> </metric> + <metric name="IsVisible"> + <summary> + Indicates whether the tab is visible or not at the time of metric + collection. + </summary> + </metric> <metric name="Malloc"> <summary> Measure of memory allocated by malloc. </summary> </metric> + <metric name="NumberOfDocuments"> + <summary> + The number of documents that the associated renderer owns. + </summary> + </metric> <metric name="NumberOfExtensions"> <summary> The number of extensions that are served from the associated renderer process. </summary> </metric> + <metric name="NumberOfFrames"> + <summary> + The number of frames that the associated renderer owns. + </summary> + </metric> + <metric name="NumberOfLayoutObjects"> + <summary> + The number of layout objects that the associated renderer owns. + </summary> + </metric> + <metric name="NumberOfNodes"> + <summary> + The number of nodes that the associated renderer owns. + </summary> + </metric> <metric name="PartitionAlloc"> <summary> Measure of memory allocated by PartitionAlloc. @@ -742,13 +1472,19 @@ </metric> <metric name="PrivateMemoryFootprint"> <summary> - Measure of total memory consumed by process. + Measure of total private memory consumed by process. + </summary> + </metric> + <metric name="PrivateSwapFootprint"> + <summary> + Measure of private swap memory consumed by a process. Available on Linux + and Android. </summary> </metric> <metric name="ProcessType"> <summary> Type of process (e.g. browser, renderer, GPU --- see - services/resource_coordinator/public/interfaces/memory_instrumentation/memory_instrumentation.mojom) + services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom) of associated metrics. </summary> </metric> @@ -757,9 +1493,31 @@ Size of process' working set. </summary> </metric> + <metric name="SharedMemoryFootprint"> + <summary> + Measure of total shared memory consumed by process. + </summary> + </metric> + <metric name="TimeSinceLastNavigation"> + <summary> + The time in seconds since the Tab navigated. Only emitted for tabs that + are not sharing a process. + </summary> + </metric> + <metric name="TimeSinceLastVisibilityChange"> + <summary> + The time in seconds since the Tab changed visibility. Only emitted for + tabs that are not sharing a process. + </summary> + </metric> <metric name="Total2.PrivateMemoryFootprint"> <summary> - Measure of total memory consumed by all processes. + Measure of total private memory consumed by all processes. + </summary> + </metric> + <metric name="Total2.SharedMemoryFootprint"> + <summary> + Measure of total shared memory consumed by all processes. </summary> </metric> <metric name="Uptime"> @@ -822,6 +1580,15 @@ start to the time the load event is fired, for main frame documents. </summary> </metric> + <metric name="Experimental.NavigationToInteractive"> + <summary> + Measures Time to Interactive, a metric based on main thread and network + heuristics to approximate the point in time when the page feels + interactive to the user. See https://goo.gl/TFw6xz for detailed + explanation. This histogram uses First Meaningful Paint as the lower bound + for quiescent windows. The unit of time is ms. + </summary> + </metric> <metric name="Experimental.PaintTiming.NavigationToFirstMeaningfulPaint"> <summary> Measures the time in milliseconds from navigation timing's navigation @@ -829,11 +1596,27 @@ frame documents. </summary> </metric> + <metric name="InteractiveTiming.FirstInputDelay"> + <summary> + Measures First Input Delay, the duration between the hardware timestamp + and the start of event processing on the main thread for the first + meaningful input per navigation. See + https://docs.google.com/document/d/1Tnobrn4I8ObzreIztfah_BYnDkbx3_ZfJV5gj2nrYnY/edit# + for a detailed explanation. In ms. + </summary> + </metric> <metric name="Navigation.PageTransition"> <summary> The |ui::PageTransition| for the main frame navigation of this page load. </summary> </metric> + <metric name="Net.CacheBytes"> + <summary> + The total number of body bytes loaded from cache for all resources on the + page. This is rounded down to the nearest exponential bucket (with a + bucket spacing factor of 1.3). + </summary> + </metric> <metric name="Net.DownstreamKbpsEstimate.OnNavigationStart"> <owner>tbansal@chromium.org</owner> <summary> @@ -869,6 +1652,13 @@ navigation for this page load was initiated. </summary> </metric> + <metric name="Net.NetworkBytes"> + <summary> + The total number of body bytes loaded from the network for all resources + on the page. This is rounded down to the nearest exponential bucket (with + a bucket spacing factor of 1.3). + </summary> + </metric> <metric name="Net.TransportRttEstimate.OnNavigationStart"> <summary> The transport round trip time estimate for this page load, at the time the @@ -1088,6 +1878,9 @@ </summary> </metric> <metric name="User.Action"> + <obsolete> + Deprecated. Use new user actions ("User.Action....") instead. + </obsolete> <summary> Records what the user does with all UI entry points of the password manager UI, like bubbles, context menus, forms, form fields, etc. in @@ -1096,6 +1889,36 @@ User.ActionSimplified, this metric is intended to be extended over time. </summary> </metric> + <metric name="User.Action.CorrectedUsernameInForm"> + <summary> + Counts how many times the user corrected a username in a password form. + This is only populated if events happened. + </summary> + </metric> + <metric name="User.Action.EditedUsernameInBubble"> + <summary> + Counts how many times the user edited a username in a password save/update + bubble. This is only populated if events happened. + </summary> + </metric> + <metric name="User.Action.SelectedDifferentPasswordInBubble"> + <summary> + Counts how many times the user selected a different password in a + save/update bubble. This is only populated if events happened. + </summary> + </metric> + <metric name="User.Action.TriggeredManualFallbackForSaving"> + <summary> + Counts how many times the user triggered the manual fallback for password + saving. This is only populated if events happened. + </summary> + </metric> + <metric name="User.Action.TriggeredManualFallbackForUpdating"> + <summary> + Counts how many times the user triggered the manual fallback for password + updating. This is only populated if events happened. + </summary> + </metric> <metric name="User.ActionSimplified"> <summary> Records what the user does with a form. Recorded values correspond to the @@ -1152,6 +1975,50 @@ </metric> </event> +<event name="Permission"> + <owner>timloh@chromium.org</owner> + <summary> + Metrics for when a user's permission actions. Currently we only log when a + permission prompt is resolved. Grouped (microphone+camera) permission + prompts are reported separately. + </summary> + <metric name="Action"> + <summary> + An enum of type PermissionAction. One of GRANTED, DENIED, DISMISSED or + IGNORED. + </summary> + </metric> + <metric name="Gesture"> + <summary> + An enum of type PermissionRequestGestureType, whether the prompt was + initiated by a user gesture. + </summary> + </metric> + <metric name="PermissionType"> + <summary> + An enum of type ContentSettingsType. + </summary> + </metric> + <metric name="PriorDismissals"> + <summary> + The number of dismissed prompts for the given (origin, permission) pair, + capped at 10 dismissals. + </summary> + </metric> + <metric name="PriorIgnores"> + <summary> + The number of ignored prompts for the given (origin, permission) pair, + capped at 10 ignores. + </summary> + </metric> + <metric name="Source"> + <summary> + An enum of type PermissionSourceUI. The UI surface for this action. + Currently we only record when this is PROMPT. + </summary> + </metric> +</event> + <event name="Plugins.FlashInstance"> <owner>tommycli@chromium.org</owner> <summary> @@ -1175,12 +2042,26 @@ Set to 1 when a user is shown a lite page in page load. </summary> </metric> + <metric name="noscript"> + <summary> + Set to 1 when a user is shown a NoScript preview on a page load. + </summary> + </metric> <metric name="opt_out"> <summary> Set to 1 when a user clicks "Show Original" on a preview page load. </summary> </metric> + <metric name="origin_opt_out"> + <summary> + Set to 1 when previews were enabled but no preview was attempted because + the origin provided a Cache-Control:no-transform header in the main frame + response. This is a directive from the origin to not perform any + transformation so in the context of the Previews feature, it is an opt-out + by the origin site (rather than the user). + </summary> + </metric> <metric name="server_lofi"> <summary> Set to 1 when a user is shown a server lo-fi image in a page load. @@ -1188,6 +2069,62 @@ </metric> </event> +<event name="ResponsivenessMeasurement"> + <owner>npm@chromium.org</owner> + <owner>tdresser@chromium.org</owner> + <summary> + Responsiveness metrics recorded once every 5 seconds. + </summary> + <metric name="ExpectedTaskQueueingDuration"> + <summary> + Duration in MS for expected task queueing duration. The metric reflects + the responsiveness of a tab. A lower value means the tab will respond to + inputs faster. This metric is equal to + RendererScheduler.ExpectedTaskQueueingDuration of the main frame process. + </summary> + </metric> +</event> + +<event name="Pepper.Broker" singular="True"> + <owner>raymes@chromium.org</owner> + <summary> + Event recorded when a flash instance connects to the broker, resulting in a + channel being opened to the broker process. + </summary> +</event> + +<event name="SiteIsolation.XSD.Browser.Blocked"> + <owner>creis@chromium.org</owner> + <owner>chrome-site-isolation@google.com</owner> + <summary> + Resource request response was blocked by the cross-site document blocking + logic in the browser process. + </summary> + <metric name="CanonicalMimeType"> + <summary> + Classification of the Content-Type HTTP response header into one of the + blockable document flavours: html, xml, json, plain. + </summary> + </metric> + <metric name="ContentResourceType"> + <summary> + content::ResourceType of the blocked resource (e.g. image / script / xhr / + etc.). + </summary> + </metric> + <metric name="HttpResponseCode"> + <summary> + The HTTP response code (e.g. 200 or 404) associated with the blocked + resource request. + </summary> + </metric> + <metric name="NeededSniffing"> + <summary> + Whether the HTTP response needed sniffing to confirm its MIME type. + </summary> + </metric> +</event> + <event name="SubresourceFilter" singular="True"> <owner>bmcquade@chromium.org</owner> <owner>csharrison@chromium.org</owner> @@ -1212,6 +2149,21 @@ </metric> </event> +<event name="Tab.RendererOOM"> + <owner>ssid@chromium.org</owner> + <summary> + Metrics about renderer OOM, recorded for each detected OOM of renderer + process. + </summary> + <metric name="TimeSinceLastNavigation"> + <summary> + Duration in MS from when the main frame navigation was triggered to when + the tab crashed with OOM. Recorded only on Windows, Android and Chrome OS. + We do not have a way to detect OOMs reliably on Linux and Mac. + </summary> + </metric> +</event> + <event name="Translate"> <owner>hamelphi@chromium.org</owner> <summary> @@ -1229,34 +2181,6 @@ <metric name="TargetLanguage" semantic_type="ST_DEMOGRAPHIC_INFO"/> </event> -<event name="CPUUsageMeasurement"> - <owner>matthalp@google.com</owner> - <owner>oysteine@chromium.org</owner> - <summary> - A CPU usage measurement that corresponds to a tick in a CPU usage - time-series The tick interval is set as a FieldTrial parameter, which can be - obtained by cross referencing the UKM entry with the FieldTrial it was - launched with. There is also some metadata stored to determine how faitful - the CPU usage measurement is (e.g. NumberOfCoresidentTabs). - </summary> - <metric name="CPUUsage"> - <summary> - CPU usage measurement. - </summary> - </metric> - <metric name="NumberOfCoresidentTabs"> - <summary> - Number of co-resident tabs in all of the render processes a tab is - associated with when the CPU usage measurement is taken. - </summary> - </metric> - <metric name="Tick"> - <summary> - Tick CPU Usage measurement was taken at. - </summary> - </metric> -</event> - <event name="TabManager.Background.FirstAlertFired"> <owner>chrisha@chromium.org</owner> <owner>lpy@chromium.org</owner> @@ -1343,4 +2267,576 @@ </metric> </event> +<event name="TabManager.Background.ForegroundedOrClosed"> + <owner>chrisha@chromium.org</owner> + <owner>lpy@chromium.org</owner> + <summary> + Collects the duration in MS from when the tab is backgrounded to when it is + brought to foreground or closed. + </summary> + <metric name="IsForegrounded"> + <summary> + Boolean value indicating whether or not it's triggered because the tab is + brought to foreground again. + </summary> + </metric> + <metric name="TimeFromBackgrounded"> + <summary> + Duration in MS from when the tab is backgrounded to when it is brought to + foreground or closed. + </summary> + </metric> +</event> + +<event + name="TabManager.BackgroundTabOpening.ForegroundTab.ExpectedTaskQueueingDurationInfo"> + <owner>zhenw@chromium.org</owner> + <summary> + Collects the expected queueing duration of tasks and metadata for the + foreground tab during a background tab opening session (the duration of time + from when the browser starts to open background tabs until the time the + browser has finished loading those tabs or otherwise decided to stop loading + them). The event is not recorded when the session overlaps with session + restore. This event is sampled when there is only one backgrounded loading + or pending tab and all events are collected when there are 2 or more + backgrounded loading or pending tabs. In this way, we cap the volume while + keeping all interesting data. Therefore, aggregated tab counts over multiple + events are invalid. + </summary> + <metric name="BackgroundTabLoadingCount"> + <summary> + Number of background tabs that are loading. + </summary> + </metric> + <metric name="BackgroundTabOpeningSessionId"> + <summary> + The ID of this background tab opening session. + </summary> + </metric> + <metric name="BackgroundTabPendingCount"> + <summary> + Number of background tabs that are pending. + </summary> + </metric> + <metric name="ExpectedTaskQueueingDuration"> + <summary> + Duration in MS for expected task queueing duration. The metric reflects + the responsiveness of a tab. A lower value means the tab will respond to + inputs faster. This metric is equal to + RendererScheduler.ExpectedTaskQueueingDuration. It is emitted once for all + tasks in each 1000-ms window. + </summary> + </metric> + <metric name="SequenceId"> + <summary> + The ID of this event's sequence in current background tab opening session. + </summary> + </metric> + <metric name="SystemTabCount"> + <summary> + Number of all tabs of the system, which includes all browser windows. + </summary> + </metric> +</event> + +<event name="TabManager.WindowMetrics"> + <owner>michaelpg@chromium.org</owner> + <summary> + Collects information about a browser or app window to associate with the + TabManager.TabMetrics entries for tabs in that window. + </summary> + <metric name="IsActive"> + <summary> + Whether the window is the active (frontmost) window. + </summary> + </metric> + <metric name="ShowState"> + <summary> + Enumeration of the window show state, such as fullscreen or minimized. + Values are enumerated in metrics::WindowMetricsEvent::ShowState. + </summary> + </metric> + <metric name="TabCount"> + <summary> + Number of tabs in the tab strip. Rounded down to the nearest exponential + bucket (with a bucket spacing factor of 1.5). Will be 1 for windows with + only one top-level WebContents, such as app windows. + </summary> + </metric> + <metric name="Type"> + <summary> + Enumeration for the type of the window. Values are enumerated in + metrics::WindowMetricsEvent::Type. + </summary> + </metric> + <metric name="WindowId"> + <summary> + Session ID of the browser or app window this entry represents, unique for + the browsing session. + </summary> + </metric> +</event> + +<event name="TabManager.Experimental.BackgroundTabOpening.TabSwitchLoadStopped" + singular="True"> + <owner>zhenw@chromium.org</owner> + <summary> + Collects data when a tab is switched to from another tab and then finishes + loading in the foreground during a background tab opening session (the + duration of time from when the browser starts to open background tabs until + the time the browser has finished loading those tabs or otherwise decided to + stop loading them). The event is only recorded when a tab is switched to + from another tab within the same tabstrip. As a result, the initial + foreground tab is not included in this event since it was not switched to + from another tab. The event is not recorded when the session overlaps with + session restore. + </summary> + <metric name="BackgroundTabLoadingCount"> + <summary> + Number of background tabs that are loading. + </summary> + </metric> + <metric name="BackgroundTabOpeningSessionId"> + <summary> + The ID of this background tab opening session. + </summary> + </metric> + <metric name="BackgroundTabPendingCount"> + <summary> + Number of background tabs that are pending. + </summary> + </metric> + <metric name="SequenceId"> + <summary> + The ID of this event's sequence in current background tab opening session. + </summary> + </metric> + <metric name="SystemTabCount"> + <summary> + Number of all tabs of the system, which includes all browser windows. + </summary> + </metric> + <metric name="TabSwitchLoadTime"> + <summary> + Tab switch load time in MS. It is defined as the time between when the + user switches to a backround tab, and the time when that tab finishes + loading in the foreground. If the user switches away before the tab + finishes loading, a metric will not be recorded unless the user switches + back, in which case the tab switch load time is measured from that point + in time. + </summary> + </metric> +</event> + +<event name="TabManager.Experimental.SessionRestore.ForegroundTab.PageLoad" + singular="True"> + <owner>zhenw@chromium.org</owner> + <summary> + Collects the tab counts for the foreground tab page load during session + restore. The event is not recorded when the session overlaps with background + tab opening. This event should be combined with PageLoad event for analysis. + </summary> + <metric name="SessionRestoreTabCount"> + <summary> + Number of tabs that are restored. + </summary> + </metric> + <metric name="SystemTabCount"> + <summary> + Number of all tabs of the system, which includes all browser windows. + </summary> + </metric> +</event> + +<event name="TabManager.Experimental.SessionRestore.TabSwitchLoadStopped" + singular="True"> + <owner>zhenw@chromium.org</owner> + <summary> + Collects data when a tab is switched to from another tab and then finishes + loading in the foreground during session restore The event is only recorded + when a tab is switched to from another tab within the same tabstrip. As a + result, the initial foreground tab is not included in this event since it + was not switched to from another tab. The event is not recorded when the + session overlaps with background tab opening. + </summary> + <metric name="SequenceId"> + <summary> + The ID of this event's sequence in current session restore session. + </summary> + </metric> + <metric name="SessionRestoreSessionId"> + <summary> + The ID of this session restore session. + </summary> + </metric> + <metric name="SessionRestoreTabCount"> + <summary> + Number of tabs that are restored. + </summary> + </metric> + <metric name="SystemTabCount"> + <summary> + Number of all tabs of the system, which includes all browser windows. + </summary> + </metric> + <metric name="TabSwitchLoadTime"> + <summary> + Tab switch load time in MS. It is defined as the time between when the + user switches to a background tab, and the time when that tab finishes + loading in the foreground. If the user switches away before the tab + finishes loading, a metric will not be recorded unless the user switches + back, in which case the tab switch load time is measured from that point + in time. + </summary> + </metric> +</event> + +<event + name="TabManager.SessionRestore.ForegroundTab.ExpectedTaskQueueingDurationInfo"> + <owner>zhenw@chromium.org</owner> + <summary> + Collects the expected queueing duration of tasks and metadata for the + foreground tab during session restore. The event is not recorded when the + session overlaps with background tab opening. The event is not recorded when + there is only one restored tab, in which case, there is no background + restored tab and we are not interested at that. In this way, we cap the + volume while keeping all interesting data. + </summary> + <metric name="ExpectedTaskQueueingDuration"> + <summary> + Duration in MS for expected task queueing duration. The metric reflects + the responsiveness of a tab. A lower value means the tab will respond to + inputs faster. This metric is equal to + RendererScheduler.ExpectedTaskQueueingDuration. It is emitted once for all + tasks in each 1000-ms window. + </summary> + </metric> + <metric name="SequenceId"> + <summary> + The ID of this event's sequence in current session restore session. + </summary> + </metric> + <metric name="SessionRestoreSessionId"> + <summary> + The ID of this session restore session. + </summary> + </metric> + <metric name="SessionRestoreTabCount"> + <summary> + Number of tabs that are restored. + </summary> + </metric> + <metric name="SystemTabCount"> + <summary> + Number of all tabs of the system, which includes all browser windows. + </summary> + </metric> +</event> + +<event name="TabManager.TabLifetime" singular="True"> + <owner>chrisha@chromium.org</owner> + <summary> + Collected when a tab is closed, at most once per source. + </summary> + <metric name="TimeSinceNavigation"> + <summary> + The time when the tab was closed, expressed as the amount of time in MS + that has elapsed since the main frame navigation providing the content of + the tab. + </summary> + </metric> +</event> + +<event name="UserActivity"> + <owner>jiameng@chromium.org</owner> + <summary> + Collects user activity events after staying idle for a short period of time. + </summary> + <metric name="BatteryPercent"> + <summary> + Percentage of battery, bucketed to 5 percents, i.e. [0, 5%) is mapped to + 0, [5%, 10%) is mapped to 5 etc. + </summary> + </metric> + <metric name="DeviceManagement"> + <summary> + An enum representing whether the device is managed, defined in + |chromeos::power::ml::UserActivityEvent::Features::ManagementType|. + </summary> + </metric> + <metric name="DeviceMode"> + <summary> + An enum representing the mode of the device, defined in + |chromeos::power::ml::UserActivityEvent::Feature::DeviceMode| + </summary> + </metric> + <metric name="DeviceType"> + <summary> + An enum representing the type of the device, defined in + |chromeos::power::ml::UserActivityEvent::Feature::DeviceType| + </summary> + </metric> + <metric name="EventLogDuration"> + <summary> + Time taken in seconds from when we start logging the features to the + moment when the event type is known and we finish logging the complete + event. + </summary> + </metric> + <metric name="EventReason"> + <summary> + An enum representing the reason of the event, defined in + |chromeos::power::ml::UserActivityEvent::Event::Reason|. + </summary> + </metric> + <metric name="EventType"> + <summary> + An enum representing the type of the event, defined in + |chromeos::power::ml::UserActivityEvent::Event::Type|. + </summary> + </metric> + <metric name="LastActivityDay"> + <summary> + An enum representing the last activity day of the week, defined in + |chromeos::power::ml::UserActivityEvent::Feature::DayOfWeek|. + </summary> + </metric> + <metric name="LastActivityTime"> + <summary> + Last activity time as hours since midnight in the local time zone. + </summary> + </metric> + <metric name="LastUserActivityTime"> + <summary> + Last user activity time as hours since midnight in the local time zone. + </summary> + </metric> + <metric name="OnBattery"> + <summary> + Boolean value to represent whether the device is currently on battery + power. + </summary> + </metric> + <metric name="RecentTimeActive"> + <summary> + Duration of activity in seconds up to last activity. + </summary> + </metric> + <metric name="ScreenDimDelay"> + <summary> + Delay after which the screen will be dimmed in seconds. + </summary> + </metric> + <metric name="ScreenDimToOffDelay"> + <summary> + Delay after which the screen will be turned off in seconds, as measured + from screen is dimmed. If dim is diabled, it is the delay from the start + of inactivity. + </summary> + </metric> + <metric name="TimeSinceLastKey"> + <summary> + Time from last key event in seconds. + </summary> + </metric> + <metric name="TimeSinceLastMouse"> + <summary> + Time from last mouse or touch event in seconds. + </summary> + </metric> +</event> + +<event name="UserActivityId"> + <owner>jiameng@chromium.org</owner> + <summary> + Records an activity that happened while a page was open. + </summary> + <metric name="ActivityId"> + <summary> + The ID of the activity that happened while a page was open. + </summary> + </metric> + <metric name="IsActive"> + <summary> + Boolean value representing whether this tab is selected in its containing + browser. + </summary> + </metric> + <metric name="IsBrowserFocused"> + <summary> + Boolean value representing whether the containing browser is in focus. + </summary> + </metric> + <metric name="IsBrowserVisible"> + <summary> + Boolean value representing whether the containing browser is visible. + </summary> + </metric> + <metric name="IsTopmostBrowser"> + <summary> + Boolean value representing whether the containing browser is the topmost + one on the screen. + </summary> + </metric> +</event> + +<event name="TabManager.TabMetrics"> + <owner>michaelpg@chromium.org</owner> + <summary> + Collects tab information for a tab after navigations, activations and close + events. + </summary> + <metric name="ContentType"> + <summary> + Enumeration for the MIME type of the page. Values are enumerated in + metrics::TabMetricsEvent::ContentType. + </summary> + </metric> + <metric name="DefaultProtocolHandler"> + <summary> + Schemes that a page from this page's origin is the default protocol + handler for, meaning the user has chosen to accept (or the handler was + preinstalled by Chrome). The metric is repeated, occurring for each such + protocol handler, and uses values from metrics::TabMetricsEvent::Scheme. + </summary> + </metric> + <metric name="HasBeforeUnloadHandler"> + <summary> + Boolean value indicating whether the page has a beforeunload JavaScript + event handler. + </summary> + </metric> + <metric name="HasFormEntry"> + <summary> + Boolean value indicating whether the page has any user-input text. + </summary> + </metric> + <metric name="IsExtensionProtected"> + <summary> + True if an extension has marked this tab as non-discardable via the + chrome.tabs.update() extension API. + </summary> + </metric> + <metric name="IsPinned"> + <summary> + Boolean value indicating whether the tab is pinned in the tabstrip. + </summary> + </metric> + <metric name="KeyEventCount"> + <summary> + Number of key events that were sent to the page. + </summary> + </metric> + <metric name="MouseEventCount"> + <summary> + Number of mouse events that were sent to the page. + </summary> + </metric> + <metric name="NavigationEntryCount"> + <summary> + Number of navigation entries in the tab's NavigationController. + Corresponds to the size of the tab's back/forward list. + </summary> + </metric> + <metric name="PageTransitionCoreType"> + <summary> + Type of the page transition for this navigation. Uses the core values from + ui::PageTransition. + </summary> + </metric> + <metric name="PageTransitionFromAddressBar"> + <summary> + True if the page transition came from interacting with the address bar, + such as by typing a URL or performing a search. + </summary> + </metric> + <metric name="PageTransitionIsRedirect"> + <summary> + True if the page transition type is a redirect, in which case the + PageTransition type may not be accurate. + </summary> + </metric> + <metric name="SequenceId"> + <summary> + The sequence of this event in the current session. Incremented by 1 each + time this event is logged to provide an ordering of events. + </summary> + </metric> + <metric name="SiteEngagementScore"> + <summary> + Site engagement score in the range [0, 100], rounded down to a multiple of + 10 to limit granularity. + </summary> + </metric> + <metric name="TouchEventCount"> + <summary> + Number of touch events that were sent to the page. + </summary> + </metric> + <metric name="WasRecentlyAudible"> + <summary> + Boolean value indicating whether the tab has played audio within the last + two seconds. + </summary> + </metric> + <metric name="WindowId"> + <summary> + WindowId of the WindowMetrics entry corresponding to the browser window + containing this tab. + </summary> + </metric> +</event> + +<event name="XR.WebXR" singular="True"> + <owner>billorr@chromium.org</owner> + <metric name="DidRequestAvailableDevices"> + <summary> + Boolean value that indicates that the API to enumerate devices was called. + </summary> + </metric> + <metric name="DidRequestPose"> + <summary> + Boolean value that indicates that poses were requested. + </summary> + </metric> + <metric name="DidRequestPresentation"> + <summary> + Boolean value that indicates that presentation was requested. + </summary> + </metric> + <metric name="ReturnedDevice"> + <summary> + Boolean value that indicates that a device was returned by the API to + enumerate devices. + </summary> + </metric> + <metric name="ReturnedPresentationCapableDevice"> + <summary> + Boolean value that indicates that a device was returned by the API to + enumerate devices, and that the device supports presentation. + </summary> + </metric> +</event> + +<event name="XR.PageSession" singular="True"> + <owner>offenwanger@chromium.org</owner> + <summary> + Records properties of page use in XR, including VR browsing and WebXR + presentation. + </summary> + <metric name="EnteredFullscreen"> + <summary> + A boolean that is set to 1 if the user requested fullscreen while in XR on + some element on the page. + </summary> + </metric> + <metric name="TimeOnPage"> + <summary> + The aproximate amount of time the user spends on a page in XR in seconds. + Times are reported accurately when low, for example, under a minute, and + get rounded to minutes and then hours as they get larger. + </summary> + </metric> +</event> + </ukm-configuration>
diff --git a/tools/msan/blacklist.txt b/tools/msan/blacklist.txt index 40ea4b8..feada5c1 100644 --- a/tools/msan/blacklist.txt +++ b/tools/msan/blacklist.txt
@@ -20,5 +20,5 @@ fun:unpack_RGB888 # False positives due to use of linux_syscall_support. http://crbug.com/394028 -src:*/breakpad/src/* +src:*/third_party/breakpad/breakpad/src/* src:*/components/crash/content/app/breakpad_linux.cc
diff --git a/tools/perf/BUILD.gn b/tools/perf/BUILD.gn index 55dacdd..39e01e25 100644 --- a/tools/perf/BUILD.gn +++ b/tools/perf/BUILD.gn
@@ -28,9 +28,6 @@ # For image_decoding.measurement "//chrome/test/data/image_decoding/", - # For indexeddb_perf - "//chrome/test/data/indexeddb/", - # For Pylib used by VR tests "//build/android/pylib/", ] @@ -44,3 +41,27 @@ flag_name = "--chromium-output-directory" } } + +# Temporary group for running benchmarks without building Chrome +# Will be removed as a part of crbug.com/758632 +group("perf_experimental") { + testonly = true + deps = [ + "//tools/perf/chrome_telemetry_build:telemetry_chrome_test_experimental", + ] + + data = [ + "//tools/perf/", + + # Field trial config + "//tools/variations/", + "//testing/variations/", + + # Field trial dependencies + "//tools/json_comment_eater/", + "//tools/json_to_struct/", + + # For Pylib used by benchmarks + "//build/android/pylib/", + ] +}
diff --git a/tools/perf/OWNERS b/tools/perf/OWNERS index 4620ea0..e89141fb 100644 --- a/tools/perf/OWNERS +++ b/tools/perf/OWNERS
@@ -2,9 +2,6 @@ nednguyen@google.com sullivan@chromium.org -# For test disabling changes. -rnephew@chromium.org - # For changes related to ChromeOS. achuith@chromium.org
diff --git a/tools/perf/PRESUBMIT.py b/tools/perf/PRESUBMIT.py index 37c1676..cabafbe7 100644 --- a/tools/perf/PRESUBMIT.py +++ b/tools/perf/PRESUBMIT.py
@@ -15,9 +15,11 @@ """Performs common checks, which includes running pylint.""" results = [] + _UpdatePerfData(input_api) + results.extend(_CheckNoUncommittedFiles(input_api, output_api)) + results.extend(_CheckWprShaFiles(input_api, output_api)) results.extend(_CheckJson(input_api, output_api)) - results.extend(_CheckPerfJsonUpToDate(input_api, output_api)) results.extend(_CheckExpectations(input_api, output_api)) results.extend(input_api.RunTests(input_api.canned_checks.GetPylint( input_api, output_api, extra_paths_list=_GetPathsToPrepend(input_api), @@ -67,17 +69,12 @@ 'Validating story expectation data failed.', long_text=out)) return results -def _CheckPerfJsonUpToDate(input_api, output_api): - results = [] + +def _UpdatePerfData(input_api): perf_dir = input_api.PresubmitLocalPath() - out, return_code = _RunArgs([ + _RunArgs([ input_api.python_executable, - input_api.os_path.join(perf_dir, 'generate_perf_data'), - '--validate-only'], input_api) - if return_code: - results.append(output_api.PresubmitError( - 'Validating Perf JSON configs failed.', long_text=out)) - return results + input_api.os_path.join(perf_dir, 'generate_perf_data')], input_api) def _CheckWprShaFiles(input_api, output_api): @@ -116,6 +113,18 @@ return [] +def _CheckNoUncommittedFiles(input_api, output_api): + """Ensures that uncommitted updated files will block presubmit.""" + results = [] + diff_text = _RunArgs(['git', 'diff', '--name-only'], input_api)[0] + + if diff_text != "": + results.append(output_api.PresubmitError( + ('Please add the following changed files to your git client: %s' % + diff_text))) + return results + + def CheckChangeOnUpload(input_api, output_api): report = [] report.extend(_CommonChecks(input_api, output_api))
diff --git a/tools/perf/benchmark.csv b/tools/perf/benchmark.csv index 537832c..a4c46a4 100644 --- a/tools/perf/benchmark.csv +++ b/tools/perf/benchmark.csv
@@ -1,7 +1,7 @@ AUTOGENERATED FILE DO NOT EDIT See //tools/perf/generate_perf_data.py to make changes Benchmark name,Individual owners,Component -angle_perftests,jmadill@chromium.org, +angle_perftests,"jmadill@chromium.org, chrome-gpu-perf-owners@chromium.org",Internals>GPU>ANGLE battor.steady_state,charliea@chromium.org, battor.trivial_pages,charliea@chromium.org, blink_perf.bindings,"jbroman@chromium.org, yukishiino@chromium.org, haraken@chromium.org", @@ -9,7 +9,7 @@ blink_perf.css,rune@opera.com, blink_perf.dom,"jbroman@chromium.org, yukishiino@chromium.org, haraken@chromium.org", blink_perf.events,hayato@chromium.org, -blink_perf.image_decoder,"cblume@chromium.org, reveman@chromium.org", +blink_perf.image_decoder,cblume@chromium.org, blink_perf.layout,eae@chromium.org, blink_perf.owp_storage,dmurph@chromium.org, blink_perf.paint,wangxianzhu@chromium.org, @@ -17,34 +17,27 @@ blink_perf.shadow_dom,hayato@chromium.org, blink_perf.svg,"kouhei@chromium.org, fs@opera.com", cc_perftests,enne@chromium.org, -dromaeo.domcoreattr,"jbroman@chromium.org, yukishiino@chromium.org, haraken@chromium.org", -dromaeo.domcoremodify,"jbroman@chromium.org, yukishiino@chromium.org, haraken@chromium.org", -dromaeo.domcorequery,"jbroman@chromium.org, yukishiino@chromium.org, haraken@chromium.org", -dromaeo.domcoretraverse,"jbroman@chromium.org, yukishiino@chromium.org, haraken@chromium.org", +dromaeo,"jbroman@chromium.org, yukishiino@chromium.org, haraken@chromium.org", dummy_benchmark.histogram_benchmark_1,"eakuefner@chromium.org, simonhatch@chromium.org", dummy_benchmark.noisy_benchmark_1,nednguyen@google.com, dummy_benchmark.stable_benchmark_1,nednguyen@google.com, -gpu_perftests,reveman@chromium.org, -jetstream,"bmeurer@chromium.org, mvstanton@chromium.org", -kraken,"bmeurer@chromium.org, mvstanton@chromium.org", +gpu_perftests,"reveman@chromium.org, chrome-gpu-perf-owners@chromium.org",Internals>GPU +jetstream,hablich@chromium.org, +kraken,hablich@chromium.org, load_library_perf_tests,, -loading.desktop,"kouhei@chormium.org, ksakamoto@chromium.org", +loading.desktop,"kouhei@chromium.org, ksakamoto@chromium.org", loading.mobile,"kouhei@chromium.org, ksakamoto@chromium.org", -media.android.tough_video_cases,"crouleau@chromium.org, videostack-eng@google.com",Internals>Media -media.android.tough_video_cases_tbmv2,"johnchen@chromium.org, crouleau@chromium.org",Internals>Media -media.media_cns_cases,"crouleau@chromium.org, videostack-eng@google.com",Internals>Media -media.mse_cases,"crouleau@chromium.org, videostack-eng@google.com",Internals>Media>Source -media.tough_video_cases,crouleau@chromium.org,Internals>Media -media.tough_video_cases_tbmv2,"johnchen@chromium.org, crouleau@chromium.org",Internals>Media +media.desktop,"johnchen@chromium.org, crouleau@chromium.org",Internals>Media +media.mobile,"johnchen@chromium.org, crouleau@chromium.org",Internals>Media media_perftests,crouleau@chromium.org, memory.desktop,erikchen@chromium.org, memory.long_running_idle_gmail_background_tbmv2,ulan@chromium.org, memory.long_running_idle_gmail_tbmv2,ulan@chromium.org, memory.top_10_mobile,perezju@chromium.org, net_perftests,xunjieli@chromium.org, -octane,"bmeurer@chromium.org, mvstanton@chromium.org", -oortonline,ulan@chromium.org, +octane,hablich@chromium.org, oortonline_tbmv2,ulan@chromium.org, +passthrough_command_buffer_perftests,"piman@chromium.org, chrome-gpu-perf-owners@chromium.org",Internals>GPU>ANGLE performance_browser_tests,miu@chromium.org, power.idle_platform,"charliea@chromium.org, rnephew@chromium.org", power.typical_10_mobile,perezju@chromium.org, @@ -52,8 +45,6 @@ rasterize_and_record_micro.top_25,"vmpstr@chromium.org, wkorman@chromium.org",Internals>Compositing>Rasterization resource_sizes,"agrieve@chromium.org, rnephew@chromium.org, perezju@chromium.org", scheduler.tough_scheduling_cases,"skyostil@chromium.org, brianderson@chromium.org", -service_worker.service_worker,horo@chromium.org, -service_worker.service_worker_micro_benchmark,horo@chromium.org, sizes (linux),thestig@chromium.org, sizes (mac),tapted@chromium.org, sizes (win),grt@chromium.org, @@ -85,12 +76,12 @@ smoothness.tough_texture_upload_cases,vmiura@chromium.org, smoothness.tough_webgl_ad_cases,skyostil@chromium.org, smoothness.tough_webgl_cases,"kbr@chromium.org, zmo@chromium.org", -speedometer,"bmeurer@chromium.org, mvstanton@chromium.org", -speedometer2,"verwaest@chromium.org, mvstanton@chromium.org", +speedometer,hablich@chromium.org, +speedometer-future,hablich@chromium.org, +speedometer2,hablich@chromium.org, +speedometer2-future,hablich@chromium.org, start_with_url.cold.startup_pages,pasko@chromium.org, start_with_url.warm.startup_pages,pasko@chromium.org, -storage.indexeddb_endure,cmumford@chromium.org, -storage.indexeddb_endure_tracing,cmumford@chromium.org, system_health.common_desktop,"charliea@chromium.org, nednguyen@chromium.org", system_health.common_mobile,"charliea@chromium.org, nednguyen@chromium.org", system_health.memory_desktop,perezju@chromium.org, @@ -107,10 +98,13 @@ thread_times.tough_scrolling_cases,tdresser@chromium.org, tracing.tracing_with_background_memory_infra,ssid@chromium.org, tracing_perftests,"kkraynov@chromium.org, primiano@chromium.org", -v8.browsing_desktop,ulan@chromium.org, -v8.browsing_mobile,ulan@chromium.org, +v8.browsing_desktop,"mythria@chromium.org, ulan@chromium.org", +v8.browsing_desktop-future,"mythria@chromium.org, ulan@chromium.org", +v8.browsing_mobile,"mythria@chromium.org, ulan@chromium.org", +v8.browsing_mobile-future,"mythria@chromium.org, ulan@chromium.org", v8.detached_context_age_in_gc,ulan@chromium.org, v8.runtime_stats.top_25,cbruni@chromium.org, -v8.runtimestats.browsing_desktop,mythria@chromium.org, -v8.runtimestats.browsing_mobile,mythria@chromium.org, +validating_command_buffer_perftests,"piman@chromium.org, chrome-gpu-perf-owners@chromium.org",Internals>GPU +views_perftests,tapted@chromium.org,Internals>Views +wasm,bradnelson@chromium.org, webrtc,"qiangchen@chromium.org, ehmaldonado@chromium.org, phoglund@chromium.org",
diff --git a/tools/perf/benchmarks/battor.py b/tools/perf/benchmarks/battor.py index a218be6..9ba586c1 100644 --- a/tools/perf/benchmarks/battor.py +++ b/tools/perf/benchmarks/battor.py
@@ -28,10 +28,6 @@ ['powerMetric', 'clockSyncLatencyMetric', 'cpuTimeMetric']) return options - @classmethod - def ShouldDisable(cls, possible_browser): - return not possible_browser.platform.HasBattOrConnected() - @benchmark.Owner(emails=['charliea@chromium.org']) class BattOrTrivialPages(_BattOrBenchmark): @@ -45,12 +41,6 @@ def Name(cls): return 'battor.trivial_pages' - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass - return StoryExpectations() - @benchmark.Owner(emails=['charliea@chromium.org']) class BattOrSteadyStatePages(_BattOrBenchmark): @@ -63,10 +53,3 @@ @classmethod def Name(cls): return 'battor.steady_state' - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableStory('http://abcnews.go.com/', [story.expectations.ALL], - 'crbug.com/505990') - return StoryExpectations()
diff --git a/tools/perf/benchmarks/benchmark_smoke_unittest.py b/tools/perf/benchmarks/benchmark_smoke_unittest.py index 6b967f7e..12b5d42 100644 --- a/tools/perf/benchmarks/benchmark_smoke_unittest.py +++ b/tools/perf/benchmarks/benchmark_smoke_unittest.py
@@ -13,16 +13,16 @@ import sys import unittest +from core import path_util + from telemetry import benchmark as benchmark_module from telemetry import decorators -from telemetry.internal.browser import browser_finder from telemetry.testing import options_for_unittests from telemetry.testing import progress_reporter from py_utils import discover from benchmarks import battor -from benchmarks import indexeddb_perf from benchmarks import jetstream from benchmarks import kraken from benchmarks import octane @@ -31,6 +31,9 @@ from benchmarks import v8_browsing +MAX_NUM_VALUES = 50000 + + def SmokeTestGenerator(benchmark, num_pages=1): """Generates a benchmark that includes first N pages from pageset. @@ -72,15 +75,25 @@ benchmark.SetArgumentDefaults(parser) options.MergeDefaultValues(parser.get_default_values()) + # Prevent benchmarks from accidentally trying to upload too much data to the + # chromeperf dashboard. The number of values uploaded is equal to (the + # average number of values produced by a single story) * (1 + (the number of + # stories)). The "1 + " accounts for values summarized across all stories. + # We can approximate "the average number of values produced by a single + # story" as the number of values produced by the first story. + # pageset_repeat doesn't matter because values are summarized across + # repetitions before uploading. + story_set = benchmark().CreateStorySet(options) + SinglePageBenchmark.MAX_NUM_VALUES = MAX_NUM_VALUES / len(story_set.stories) + benchmark.ProcessCommandLineArgs(None, options) benchmark_module.ProcessCommandLineArgs(None, options) - possible_browser = browser_finder.FindBrowser(options) - if SinglePageBenchmark.ShouldDisable(possible_browser): - self.skipTest('Benchmark %s has ShouldDisable return True' % - SinglePageBenchmark.Name()) + single_page_benchmark = SinglePageBenchmark() + with open(path_util.GetExpectationsPath()) as fp: + single_page_benchmark.AugmentExpectationsWithParser(fp.read()) - self.assertEqual(0, SinglePageBenchmark().Run(options), + self.assertEqual(0, single_page_benchmark.Run(options), msg='Failed: %s' % benchmark) return BenchmarkSmokeTest @@ -88,7 +101,6 @@ # The list of benchmark modules to be excluded from our smoke tests. _BLACK_LIST_TEST_MODULES = { - indexeddb_perf, # Always fails on Win7 & Android Tests builder. octane, # Often fails & take long time to timeout on cq bot. rasterize_and_record_micro, # Always fails on cq bot. speedometer, # Takes 101 seconds.
diff --git a/tools/perf/benchmarks/blink_perf.py b/tools/perf/benchmarks/blink_perf.py index e8a2d6d..dee404e 100644 --- a/tools/perf/benchmarks/blink_perf.py +++ b/tools/perf/benchmarks/blink_perf.py
@@ -239,18 +239,8 @@ options.AppendExtraBrowserArgs([ '--js-flags=--expose_gc', '--enable-experimental-web-platform-features', - # Note that both this flag: - '--ignore-autoplay-restrictions', - # and this flag: - '--disable-gesture-requirement-for-media-playback', - # should be used until every build from - # ToT to Stable switches over to one flag or another. This is to support - # reference builds. - # --disable-gesture-requirement-for-media-playback is the old one and - # can be removed after M60 goes to stable. - '--enable-experimental-canvas-features', - # TODO(qinmin): After fixing crbug.com/592017, remove this command line. - '--reduce-security-for-testing' + '--autoplay-policy=no-user-gesture-required', + '--enable-experimental-canvas-features' ]) def SetOptions(self, options): @@ -276,7 +266,9 @@ tab.browser.platform.tracing_controller.StartTracing(config) tab.EvaluateJavaScript('testRunner.scheduleTestRun()') tab.WaitForJavaScriptCondition('testRunner.isDone') - return tab.browser.platform.tracing_controller.StopTracing() + + trace_data = tab.browser.platform.tracing_controller.StopTracing()[0] + return trace_data def PrintAndCollectTraceEventMetrics(self, trace_cpu_time_metrics, results): @@ -364,24 +356,11 @@ tag = 'bindings' subdir = 'Bindings' - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations() - - @benchmark.Owner(emails=['rune@opera.com']) class BlinkPerfCSS(_BlinkPerfBenchmark): tag = 'css' subdir = 'CSS' - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations() - @benchmark.Owner(emails=['junov@chromium.org']) class BlinkPerfCanvas(_BlinkPerfBenchmark): @@ -400,22 +379,6 @@ page.skipped_gpus = [] return story_set - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableBenchmark([story.expectations.ANDROID_SVELTE], - 'crbug.com/593973') - self.DisableStory('putImageData.html', - [story.expectations.ANDROID_NEXUS6], 'crbug.com/738453') - # pylint: disable=line-too-long - self.DisableStory('draw-static-canvas-2d-to-hw-accelerated-canvas-2d.html', - [story.expectations.ANDROID_NEXUS6], 'crbug.com/765799') - return StoryExpectations() - - def SetExtraBrowserOptions(self, options): - options.AppendExtraBrowserArgs([ - '--enable-color-correct-rendering', - ]) @benchmark.Owner(emails=['jbroman@chromium.org', 'yukishiino@chromium.org', @@ -424,27 +387,14 @@ tag = 'dom' subdir = 'DOM' - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations() - @benchmark.Owner(emails=['hayato@chromium.org']) class BlinkPerfEvents(_BlinkPerfBenchmark): tag = 'events' subdir = 'Events' - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations() - -@benchmark.Owner(emails=['cblume@chromium.org', - 'reveman@chromium.org']) +@benchmark.Owner(emails=['cblume@chromium.org']) class BlinkPerfImageDecoder(_BlinkPerfBenchmark): tag = 'image_decoder' subdir = 'ImageDecoder' @@ -454,50 +404,24 @@ '--enable-blink-features=JSImageDecode', ]) - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations() - @benchmark.Owner(emails=['eae@chromium.org']) class BlinkPerfLayout(_BlinkPerfBenchmark): tag = 'layout' subdir = 'Layout' - def GetExpectations(self): - class Expectations(story.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableBenchmark([story.expectations.ANDROID_SVELTE], - 'crbug.com/551950') - return Expectations() - @benchmark.Owner(emails=['dmurph@chromium.org']) class BlinkPerfOWPStorage(_BlinkPerfBenchmark): tag = 'owp_storage' subdir = 'OWPStorage' - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations() - @benchmark.Owner(emails=['wangxianzhu@chromium.org']) class BlinkPerfPaint(_BlinkPerfBenchmark): tag = 'paint' subdir = 'Paint' - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableBenchmark([story.expectations.ANDROID_SVELTE], - 'crbug.com/574483') - return StoryExpectations() - @benchmark.Owner(emails=['jbroman@chromium.org', 'yukishiino@chromium.org', @@ -506,51 +430,14 @@ tag = 'parser' subdir = 'Parser' - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations() - @benchmark.Owner(emails=['kouhei@chromium.org', 'fs@opera.com']) class BlinkPerfSVG(_BlinkPerfBenchmark): tag = 'svg' subdir = 'SVG' - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableStory('Debian.html', [story.expectations.ANDROID_NEXUS5X], - 'crbug.com/736817') - self.DisableStory('FlowerFromMyGarden.html', - [story.expectations.ANDROID_NEXUS5X], - 'crbug.com/736817') - self.DisableStory('HarveyRayner.html', - [story.expectations.ANDROID_NEXUS5X], - 'crbug.com/736817') - self.DisableStory('SvgCubics.html', - [story.expectations.ANDROID_NEXUS5X], - 'crbug.com/736817') - self.DisableStory('SvgNestedUse.html', - [story.expectations.ANDROID_NEXUS5X], - 'crbug.com/736817') - self.DisableStory('Worldcup.html', [story.expectations.ANDROID_NEXUS5X], - 'crbug.com/736817') - self.DisableStory('CrawFishGanson.html', - [story.expectations.ANDROID_NEXUS5X], - 'crbug.com/736817') - return StoryExpectations() - @benchmark.Owner(emails=['hayato@chromium.org']) class BlinkPerfShadowDOM(_BlinkPerfBenchmark): tag = 'shadow_dom' subdir = 'ShadowDOM' - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableBenchmark([story.expectations.ANDROID_NEXUS5X], - 'crbug.com/702319') - return StoryExpectations()
diff --git a/tools/perf/benchmarks/blink_perf_unittest.py b/tools/perf/benchmarks/blink_perf_unittest.py index 51c3c0c9..eef36b3 100644 --- a/tools/perf/benchmarks/blink_perf_unittest.py +++ b/tools/perf/benchmarks/blink_perf_unittest.py
@@ -117,18 +117,33 @@ blob_requests = results.FindAllPageSpecificValuesNamed( 'BlobRequest') + blob_readers = results.FindAllPageSpecificValuesNamed( + 'BlobReader') self.assertEquals(len(blob_requests), 1) + self.assertEquals(len(blob_readers), 1) # simple-blob-measure-async.html specifies 6 iterationCount. self.assertEquals(len(blob_requests[0].values), 6) - self.assertGreater(blob_requests[0].GetRepresentativeNumber(), 0.001) + self.assertEquals(len(blob_readers[0].values), 6) - blob_request_read_raw_data = results.FindAllPageSpecificValuesNamed( - 'BlobRequest::ReadRawData') - self.assertEquals(len(blob_request_read_raw_data), 1) + # TODO(mek): Delete non-mojo code paths when blobs are always using mojo. + using_mojo = blob_readers[0].GetRepresentativeNumber() > 0.001 + if using_mojo: + self.assertEquals(blob_requests[0].GetRepresentativeNumber(), 0) + self.assertGreater(blob_readers[0].GetRepresentativeNumber(), 0.001) + else: + self.assertGreater(blob_requests[0].GetRepresentativeNumber(), 0.001) + self.assertEquals(blob_readers[0].GetRepresentativeNumber(), 0) + + if using_mojo: + read_data = results.FindAllPageSpecificValuesNamed( + 'BlobReader::ReadMore') + else: + read_data = results.FindAllPageSpecificValuesNamed( + 'BlobRequest::ReadRawData') + self.assertEquals(len(read_data), 1) # simple-blob-measure-async.html specifies 6 iterationCount. - self.assertEquals(len(blob_request_read_raw_data[0].values), 6) - self.assertGreater( - blob_request_read_raw_data[0].GetRepresentativeNumber(), 0.001) + self.assertEquals(len(read_data[0].values), 6) + self.assertGreater(read_data[0].GetRepresentativeNumber(), 0.001) # pylint: disable=protected-access
diff --git a/tools/perf/benchmarks/dromaeo.py b/tools/perf/benchmarks/dromaeo.py index 248fbfa..546f281 100644 --- a/tools/perf/benchmarks/dromaeo.py +++ b/tools/perf/benchmarks/dromaeo.py
@@ -14,23 +14,11 @@ from telemetry import story from telemetry.value import scalar -from metrics import power - class _DromaeoMeasurement(legacy_page_test.LegacyPageTest): def __init__(self): super(_DromaeoMeasurement, self).__init__() - self._power_metric = None - - def CustomizeBrowserOptions(self, options): - power.PowerMetric.CustomizeBrowserOptions(options) - - def WillStartBrowser(self, platform): - self._power_metric = power.PowerMetric(platform) - - def DidNavigateToPage(self, page, tab): - self._power_metric.Start(page, tab) def ValidateAndMeasurePage(self, page, tab, results): tab.WaitForJavaScriptCondition( @@ -59,9 +47,6 @@ tab.WaitForJavaScriptCondition('!!window.results_', timeout=600) - self._power_metric.Stop(page, tab) - self._power_metric.AddResults(tab, results) - score = json.loads(tab.EvaluateJavaScript('window.results_ || "[]"')) def Escape(k): @@ -104,10 +89,6 @@ """A base class for Dromaeo benchmarks.""" test = _DromaeoMeasurement - @classmethod - def Name(cls): - return 'dromaeo' - def CreateStorySet(self, options): """Makes a PageSet for Dromaeo benchmarks.""" # Subclasses are expected to define class members called query_param and @@ -128,85 +109,22 @@ @benchmark.Owner(emails=['jbroman@chromium.org', 'yukishiino@chromium.org', 'haraken@chromium.org']) -class DromaeoDomCoreAttr(_DromaeoBenchmark): - """Dromaeo DOMCore attr JavaScript benchmark. +class DromaeoBenchmark(_DromaeoBenchmark): - Tests setting and getting DOM node attributes. - """ - tag = 'domcoreattr' - query_param = 'dom-attr' + test = _DromaeoMeasurement @classmethod def Name(cls): - return 'dromaeo.domcoreattr' + return 'dromaeo' - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # http://dromaeo.com?dom-attr not disabled. - return StoryExpectations() - -@benchmark.Owner(emails=['jbroman@chromium.org', - 'yukishiino@chromium.org', - 'haraken@chromium.org']) -class DromaeoDomCoreModify(_DromaeoBenchmark): - """Dromaeo DOMCore modify JavaScript benchmark. - - Tests creating and injecting DOM nodes. - """ - tag = 'domcoremodify' - query_param = 'dom-modify' - - @classmethod - def Name(cls): - return 'dromaeo.domcoremodify' - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # http://dromaeo.com?dom-modify not disabled. - return StoryExpectations() - - -@benchmark.Owner(emails=['jbroman@chromium.org', - 'yukishiino@chromium.org', - 'haraken@chromium.org']) -class DromaeoDomCoreQuery(_DromaeoBenchmark): - """Dromaeo DOMCore query JavaScript benchmark. - - Tests querying DOM elements in a document. - """ - tag = 'domcorequery' - query_param = 'dom-query' - - @classmethod - def Name(cls): - return 'dromaeo.domcorequery' - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # http://dromaeo.com?dom-query not disabled. - return StoryExpectations() - - -@benchmark.Owner(emails=['jbroman@chromium.org', - 'yukishiino@chromium.org', - 'haraken@chromium.org']) -class DromaeoDomCoreTraverse(_DromaeoBenchmark): - """Dromaeo DOMCore traverse JavaScript benchmark. - - Tests traversing a DOM structure. - """ - tag = 'domcoretraverse' - query_param = 'dom-traverse' - - @classmethod - def Name(cls): - return 'dromaeo.domcoretraverse' - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableBenchmark([story.expectations.ALL_WIN], 'crbug.com/763263') - return StoryExpectations() + def CreateStorySet(self, options): + archive_data_file = '../page_sets/data/dromaeo.json' + ps = story.StorySet( + archive_data_file=archive_data_file, + base_dir=os.path.dirname(os.path.abspath(__file__)), + cloud_storage_bucket=story.PUBLIC_BUCKET) + for query_param in ['dom-attr', 'dom-modify', 'dom-query', 'dom-traverse']: + url = 'http://dromaeo.com?%s' % query_param + ps.AddStory(page_module.Page( + url, ps, ps.base_dir, make_javascript_deterministic=False, name=url)) + return ps
diff --git a/tools/perf/benchmarks/dummy_benchmark.py b/tools/perf/benchmarks/dummy_benchmark.py index 3a5bac49..e47de0d3 100644 --- a/tools/perf/benchmarks/dummy_benchmark.py +++ b/tools/perf/benchmarks/dummy_benchmark.py
@@ -13,7 +13,6 @@ from core import perf_benchmark from telemetry import benchmark -from telemetry import story from telemetry.value import scalar from telemetry.page import legacy_page_test from telemetry.web_perf import timeline_based_measurement @@ -52,12 +51,6 @@ def Name(cls): return 'dummy_benchmark.stable_benchmark_1' - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations() - @benchmark.Owner(emails=['nednguyen@google.com']) class DummyBenchmarkTwo(_DummyBenchmark): @@ -70,12 +63,6 @@ def Name(cls): return 'dummy_benchmark.noisy_benchmark_1' - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations() - @benchmark.Owner(emails=['eakuefner@chromium.org', 'simonhatch@chromium.org']) class DummyBenchmarkThree(perf_benchmark.PerfBenchmark): @@ -91,9 +78,3 @@ @classmethod def Name(cls): return 'dummy_benchmark.histogram_benchmark_1' - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableBenchmark([story.expectations.ALL], 'crbug.com/756210') - return StoryExpectations()
diff --git a/tools/perf/benchmarks/indexeddb_perf.py b/tools/perf/benchmarks/indexeddb_perf.py deleted file mode 100644 index a7c77bfca..0000000 --- a/tools/perf/benchmarks/indexeddb_perf.py +++ /dev/null
@@ -1,134 +0,0 @@ -# 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. - -"""Runs Chromium's IndexedDB performance test. These test: - -Databases: - create/delete -Keys: - create/delete -Indexes: - create/delete -Data access: - Random read/write - Read cache -Cursors: - Read & random writes - Walking multiple - Seeking. -""" - -import json - -from core import perf_benchmark - -from telemetry import benchmark -from telemetry import story -from telemetry.page import legacy_page_test -from telemetry.value import scalar - -from metrics import memory -from metrics import power - -import page_sets - -from telemetry.timeline import chrome_trace_category_filter -from telemetry.web_perf import timeline_based_measurement - - -IDB_CATEGORY = 'IndexedDB' -TIMELINE_REQUIRED_CATEGORY = 'blink.console' - - -class _IndexedDbMeasurement(legacy_page_test.LegacyPageTest): - - def __init__(self): - super(_IndexedDbMeasurement, self).__init__() - self._memory_metric = None - self._power_metric = None - - def WillStartBrowser(self, platform): - """Initialize metrics once right before the browser has been launched.""" - self._power_metric = power.PowerMetric(platform) - - def DidStartBrowser(self, browser): - """Initialize metrics once right after the browser has been launched.""" - self._memory_metric = memory.MemoryMetric(browser) - - def DidNavigateToPage(self, page, tab): - self._memory_metric.Start(page, tab) - self._power_metric.Start(page, tab) - - def ValidateAndMeasurePage(self, page, tab, results): - tab.WaitForDocumentReadyStateToBeComplete() - tab.WaitForJavaScriptCondition('window.done', timeout=600) - - self._power_metric.Stop(page, tab) - self._memory_metric.Stop(page, tab) - - self._memory_metric.AddResults(tab, results) - self._power_metric.AddResults(tab, results) - - result_dict = json.loads(tab.EvaluateJavaScript( - 'JSON.stringify(automation.getResults());')) - total = 0.0 - for key in result_dict: - if key == 'OverallTestDuration': - continue - msec = float(result_dict[key]) - results.AddValue(scalar.ScalarValue( - results.current_page, key, 'ms', msec, important=False)) - - total += msec - results.AddValue(scalar.ScalarValue( - results.current_page, 'Total Perf', 'ms', total)) - - def CustomizeBrowserOptions(self, options): - memory.MemoryMetric.CustomizeBrowserOptions(options) - power.PowerMetric.CustomizeBrowserOptions(options) - - -@benchmark.Owner(emails=['cmumford@chromium.org']) -class IndexedDbOriginalSectioned(perf_benchmark.PerfBenchmark): - """Chromium's IndexedDB Performance tests.""" - test = _IndexedDbMeasurement - page_set = page_sets.IndexedDBEndurePageSet - - @classmethod - def Name(cls): - return 'storage.indexeddb_endure' - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations() - - -@benchmark.Owner(emails=['cmumford@chromium.org']) -class IndexedDbTracing(perf_benchmark.PerfBenchmark): - """IndexedDB Performance tests that use tracing.""" - page_set = page_sets.IndexedDBEndurePageSet - - def CreateCoreTimelineBasedMeasurementOptions(self): - cat_filter = chrome_trace_category_filter.ChromeTraceCategoryFilter() - cat_filter.AddIncludedCategory(IDB_CATEGORY) - cat_filter.AddIncludedCategory(TIMELINE_REQUIRED_CATEGORY) - - return timeline_based_measurement.Options( - overhead_level=cat_filter) - - @classmethod - def Name(cls): - return 'storage.indexeddb_endure_tracing' - - @classmethod - def ValueCanBeAddedPredicate(cls, value, is_first_result): - return 'idb' in value.name - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations()
diff --git a/tools/perf/benchmarks/jetstream.py b/tools/perf/benchmarks/jetstream.py index c7724e7..7ca80257 100644 --- a/tools/perf/benchmarks/jetstream.py +++ b/tools/perf/benchmarks/jetstream.py
@@ -75,7 +75,7 @@ results.AddSummaryValue(list_of_scalar_values.ListOfScalarValues( None, 'Score', 'score', all_scores)) -@benchmark.Owner(emails=['bmeurer@chromium.org', 'mvstanton@chromium.org']) +@benchmark.Owner(emails=['hablich@chromium.org']) class Jetstream(perf_benchmark.PerfBenchmark): test = _JetstreamMeasurement @@ -93,9 +93,3 @@ make_javascript_deterministic=False, name='http://browserbench.org/JetStream/')) return ps - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # http://browserbench.org/JetStream/ not disabled. - return StoryExpectations()
diff --git a/tools/perf/benchmarks/kraken.py b/tools/perf/benchmarks/kraken.py index 75edc4f..bfa6854c 100644 --- a/tools/perf/benchmarks/kraken.py +++ b/tools/perf/benchmarks/kraken.py
@@ -102,7 +102,7 @@ '(http://krakenbenchmark.mozilla.org/)')) -@benchmark.Owner(emails=['bmeurer@chromium.org', 'mvstanton@chromium.org']) +@benchmark.Owner(emails=['hablich@chromium.org']) class Kraken(perf_benchmark.PerfBenchmark): """Mozilla's Kraken JavaScript benchmark. @@ -124,11 +124,3 @@ ps, ps.base_dir, name='http://krakenbenchmark.mozilla.org/kraken-1.1/driver.html')) return ps - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableStory( - 'http://krakenbenchmark.mozilla.org/kraken-1.1/driver.html', - [story.expectations.ANDROID_SVELTE], 'crbug.com/624411') - return StoryExpectations()
diff --git a/tools/perf/benchmarks/loading.py b/tools/perf/benchmarks/loading.py index 0e8ff58..5c15375 100644 --- a/tools/perf/benchmarks/loading.py +++ b/tools/perf/benchmarks/loading.py
@@ -24,24 +24,14 @@ return tbm_options -@benchmark.Owner(emails=['kouhei@chormium.org', 'ksakamoto@chromium.org']) +@benchmark.Owner(emails=['kouhei@chromium.org', 'ksakamoto@chromium.org']) class LoadingDesktop(_LoadingBase): """ A benchmark measuring loading performance of desktop sites. """ SUPPORTED_PLATFORMS = [story.expectations.ALL_DESKTOP] def CreateStorySet(self, options): return page_sets.LoadingDesktopStorySet( - cache_temperatures=[cache_temperature.PCV1_COLD, - cache_temperature.PCV1_WARM,]) - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableStory( - 'uol.com.br', [story.expectations.ALL_LINUX], 'crbug.com/752611') - self.DisableStory( - 'Orange', [story.expectations.ALL_WIN], 'crbug.com/723783') - return StoryExpectations() + cache_temperatures=[cache_temperature.COLD, cache_temperature.WARM]) @classmethod def Name(cls): @@ -56,49 +46,11 @@ def CreateStorySet(self, options): return page_sets.LoadingMobileStorySet( cache_temperatures=[cache_temperature.ANY], + cache_temperatures_for_pwa=[cache_temperature.COLD, + cache_temperature.WARM, + cache_temperature.HOT], traffic_settings=[traffic_setting.NONE, traffic_setting.REGULAR_3G]) - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableBenchmark( - [story.expectations.ANDROID_NEXUS6_WEBVIEW], 'crbug.com/676612') - self.DisableStory('GFK', [story.expectations.ALL], - 'N5X Timeout issue: crbug.com/702175') - self.DisableStory('MLSMatrix', [story.expectations.ALL], - 'N5XTimeout issue: crbug.com/702175') - self.DisableStory('EBS', [story.expectations.ALL], - 'N5XTimeout issue: crbug.com/702175') - self.DisableStory('IBI', [story.expectations.ALL], - 'N5XTimeout issue: crbug.com/702175') - self.DisableStory('SBS', [story.expectations.ALL], - 'N5XTimeout issue: crbug.com/702175') - self.DisableStory('FuturaSciences', [story.expectations.ALL], - 'N5XTimeout issue: crbug.com/702175') - self.DisableStory('HashOcean', [story.expectations.ALL], - 'N5XTimeout issue: crbug.com/702175') - self.DisableStory('163', [story.expectations.ALL], - 'N5XTimeout issue: crbug.com/702175') - self.DisableStory('G1', [story.expectations.ALL], 'crbug.com/656861') - self.DisableStory('Dramaq', [story.expectations.ANDROID_NEXUS5X], - 'Test Failure: crbug.com/750747') - self.DisableStory('Hongkiat', [story.expectations.ANDROID_NEXUS5X], - 'Test Failure: crbug.com/750747') - self.DisableStory('Facebook', [story.expectations.ANDROID_NEXUS7], - 'Nexus7v2 Timeout: crbug.com/759861') - # TODO(rnephew): Uncomment Disablings. crbug.com/728882 - # self.DisableStory( - # 'AirHorner', [story.expectations.ALL], 'crbug.com/653775') - # self.DisableStory( - # 'BusRouter', [story.expectations.ALL], 'crbug.com/653775') - # self.DisableStory('WikiOffline', [story.expectations.ALL], - # 'crbug.com/653775') - # self.DisableStory( - # 'Detik', [story.expectations.ALL], 'crbug.com/653775') - # self.DisableStory( - # 'Blogspot', [story.expectations.ALL], 'crbug.com/653775') - return StoryExpectations() - @classmethod def Name(cls): return 'loading.mobile'
diff --git a/tools/perf/benchmarks/media.py b/tools/perf/benchmarks/media.py index 81bdaf2..36f79963 100644 --- a/tools/perf/benchmarks/media.py +++ b/tools/perf/benchmarks/media.py
@@ -8,93 +8,28 @@ from telemetry import benchmark from telemetry import story -from telemetry.page import legacy_page_test from telemetry.timeline import chrome_trace_category_filter from telemetry.timeline import chrome_trace_config -from telemetry.value import list_of_scalar_values -from telemetry.value import scalar from telemetry.web_perf import timeline_based_measurement -from measurements import media import page_sets # TODO(rnephew): Revisit the re-enabled benchmarks on Wed, Aug 8 2017. -# See tr.v.Numeric.getSummarizedScalarNumericsWithNames() -# https://github.com/catapult-project/catapult/blob/master/tracing/tracing/value/numeric.html#L323 + +# Regex to filter out a few names of statistics supported by +# Histogram.getStatisticScalar(), see: +# https://github.com/catapult-project/catapult/blob/d4179a05/tracing/tracing/value/histogram.html#L645 pylint: disable=line-too-long _IGNORED_STATS_RE = re.compile( r'(?<!dump)(?<!process)_(std|count|max|min|sum|pct_\d{4}(_\d+)?)$') -class _MSEMeasurement(legacy_page_test.LegacyPageTest): +class _MediaBenchmark(perf_benchmark.PerfBenchmark): + """Base class for TBMv2-based media benchmarks (MediaDesktop and + MediaMobile).""" - def __init__(self): - super(_MSEMeasurement, self).__init__() - - def ValidateAndMeasurePage(self, page, tab, results): - del page # unused - media_metric = tab.EvaluateJavaScript('window.__testMetrics') - trace = media_metric['id'] if 'id' in media_metric else None - metrics = media_metric['metrics'] if 'metrics' in media_metric else [] - for m in metrics: - trace_name = '%s.%s' % (m, trace) - if isinstance(metrics[m], list): - results.AddValue(list_of_scalar_values.ListOfScalarValues( - results.current_page, trace_name, units='ms', - values=[float(v) for v in metrics[m]], - important=True)) - - else: - results.AddValue(scalar.ScalarValue( - results.current_page, trace_name, units='ms', - value=float(metrics[m]), important=True)) - - -# android: See media.android.tough_video_cases below -@benchmark.Owner(emails=['crouleau@chromium.org'], - component='Internals>Media') -class MediaToughVideoCases(perf_benchmark.PerfBenchmark): - """Obtains media metrics for key user scenarios.""" - test = media.Media - page_set = page_sets.ToughVideoCasesPageSet - SUPPORTED_PLATFORMS = [story.expectations.ALL_DESKTOP] - - @classmethod - def Name(cls): - return 'media.tough_video_cases' - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass - return StoryExpectations() - - -# If any story is failing on svelte, please only disable on svelte. -@benchmark.Owner(emails=['crouleau@chromium.org', 'videostack-eng@google.com'], - component='Internals>Media') -class MediaAndroidToughVideoCases(perf_benchmark.PerfBenchmark): - """Obtains media metrics for key user scenarios on Android.""" - test = media.Media - tag = 'android' - page_set = page_sets.ToughVideoCasesPageSet - options = {'story_tag_filter_exclude': 'is_4k,is_50fps'} - SUPPORTED_PLATFORMS = [story.expectations.ANDROID_NOT_WEBVIEW] - - @classmethod - def Name(cls): - return 'media.android.tough_video_cases' - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass - return StoryExpectations() - - -class _MediaTBMv2Benchmark(perf_benchmark.PerfBenchmark): def CreateStorySet(self, options): - return page_sets.ToughVideoCasesPageSet(measure_memory=True) + return page_sets.MediaCasesStorySet(measure_memory=True) def CreateCoreTimelineBasedMeasurementOptions(self): category_filter = chrome_trace_category_filter.ChromeTraceCategoryFilter() @@ -124,39 +59,30 @@ 'cpuTimeMetric', 'memoryMetric']) return options + @classmethod + def ShouldAddValue(cls, name, from_first_story_run): + del from_first_story_run # unused + # TODO(crbug.com/610962): Remove this stopgap when the perf dashboard + # is able to cope with the data load generated by TBMv2 metrics. + return not _IGNORED_STATS_RE.search(name) -# android: See media.android.tough_video_cases below + @benchmark.Owner(emails=['johnchen@chromium.org', 'crouleau@chromium.org'], component='Internals>Media') -class MediaToughVideoCasesTBMv2(_MediaTBMv2Benchmark): - """Obtains media metrics using TBMv2. - Will eventually replace MediaToughVideoCases class.""" +class MediaDesktop(_MediaBenchmark): + """Obtains media performance for key user scenarios on desktop.""" SUPPORTED_PLATFORMS = [story.expectations.ALL_DESKTOP] @classmethod def Name(cls): - return 'media.tough_video_cases_tbmv2' - - @classmethod - def ValueCanBeAddedPredicate(cls, value, is_first_result): - # TODO(crbug.com/610962): Remove this stopgap when the perf dashboard - # is able to cope with the data load generated by TBMv2 metrics. - return not _IGNORED_STATS_RE.search(value.name) - - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass - return StoryExpectations() + return 'media.desktop' # If any story is failing on svelte, please only disable on svelte. @benchmark.Owner(emails=['johnchen@chromium.org', 'crouleau@chromium.org'], component='Internals>Media') -class MediaAndroidToughVideoCasesTBMv2(_MediaTBMv2Benchmark): - """Obtains media metrics for key user scenarios on Android using TBMv2. - Will eventually replace MediaAndroidToughVideoCases class.""" +class MediaMobile(_MediaBenchmark): + """Obtains media performance for key user scenarios on mobile devices.""" tag = 'android' options = {'story_tag_filter_exclude': 'is_4k,is_50fps'} @@ -164,76 +90,11 @@ @classmethod def Name(cls): - return 'media.android.tough_video_cases_tbmv2' - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass - return StoryExpectations() + return 'media.mobile' def SetExtraBrowserOptions(self, options): # By default, Chrome on Android does not allow autoplay # of media: it requires a user gesture event to start a video. # The following option works around that. - # Note that both of these flags should be used until every build from - # ToT to Stable switches over to one flag or another. This is to support - # reference builds. - # --disable-gesture-requirement-for-media-playback is the old one and can be - # removed after M60 goes to stable. options.AppendExtraBrowserArgs( - ['--ignore-autoplay-restrictions', - '--disable-gesture-requirement-for-media-playback']) - - @classmethod - def ValueCanBeAddedPredicate(cls, value, is_first_result): - # TODO(crbug.com/610962): Remove this stopgap when the perf dashboard - # is able to cope with the data load generated by TBMv2 metrics. - return not _IGNORED_STATS_RE.search(value.name) - - -@benchmark.Owner(emails=['crouleau@chromium.org', 'videostack-eng@google.com'], - component='Internals>Media') -class MediaNetworkSimulation(perf_benchmark.PerfBenchmark): - """Obtains media metrics under different network simulations.""" - test = media.Media - page_set = page_sets.MediaCnsCasesPageSet - - @classmethod - def Name(cls): - return 'media.media_cns_cases' - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableBenchmark([story.expectations.ALL], - 'Code path is old. crbug.com/676345') - return StoryExpectations() - - -@benchmark.Owner(emails=['crouleau@chromium.org', 'videostack-eng@google.com'], - component='Internals>Media>Source') -class MediaSourceExtensions(perf_benchmark.PerfBenchmark): - """Obtains media metrics for key media source extensions functions.""" - test = _MSEMeasurement - page_set = page_sets.MseCasesPageSet - - @classmethod - def Name(cls): - return 'media.mse_cases' - - def SetExtraBrowserOptions(self, options): - # Needed to allow XHR requests to return stream objects. - options.AppendExtraBrowserArgs( - ['--enable-experimental-web-platform-features', - '--ignore-autoplay-restrictions']) - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableStory( - 'startup_test.html?testType=A&doNotWaitForBodyOnLoad=true', - [story.expectations.ANDROID_WEBVIEW], - 'crbug.com/755639') - - return StoryExpectations() + ['--autoplay-policy=no-user-gesture-required'])
diff --git a/tools/perf/benchmarks/memory.py b/tools/perf/benchmarks/memory.py index 8b225f1c..5a1e2a84 100644 --- a/tools/perf/benchmarks/memory.py +++ b/tools/perf/benchmarks/memory.py
@@ -15,8 +15,9 @@ import page_sets -# See tr.v.Numeric.getSummarizedScalarNumericsWithNames() -# https://github.com/catapult-project/catapult/blob/master/tracing/tracing/value/numeric.html#L323 +# Regex to filter out a few names of statistics supported by +# Histogram.getStatisticScalar(), see: +# https://github.com/catapult-project/catapult/blob/d4179a05/tracing/tracing/value/histogram.html#L645 pylint: disable=line-too-long _IGNORED_STATS_RE = re.compile( r'(?<!dump)(?<!process)_(std|count|max|min|sum|pct_\d{4}(_\d+)?)$') @@ -54,14 +55,14 @@ options.clear_sytem_cache_for_browser_and_profile_on_start = True -def DefaultValueCanBeAddedPredicateForMemoryMeasurement(value): +def DefaultShouldAddValueForMemoryMeasurement(name): """Default predicate when measuring memory usage. Separated out so that code can be re-used in other benchmarks. """ # TODO(crbug.com/610962): Remove this stopgap when the perf dashboard # is able to cope with the data load generated by TBMv2 metrics. - return not _IGNORED_STATS_RE.search(value.name) + return not _IGNORED_STATS_RE.search(name) class _MemoryInfra(perf_benchmark.PerfBenchmark): @@ -101,14 +102,8 @@ return 'memory.desktop' @classmethod - def ValueCanBeAddedPredicate(cls, value, is_first_result): - return DefaultValueCanBeAddedPredicateForMemoryMeasurement(value) - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass - return StoryExpectations() + def ShouldAddValue(cls, name, _): + return DefaultShouldAddValueForMemoryMeasurement(name) @benchmark.Owner(emails=['perezju@chromium.org']) @@ -127,14 +122,8 @@ return 'memory.top_10_mobile' @classmethod - def ValueCanBeAddedPredicate(cls, value, is_first_result): - return DefaultValueCanBeAddedPredicateForMemoryMeasurement(value) - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass - return StoryExpectations() + def ShouldAddValue(cls, name, _): + return DefaultShouldAddValueForMemoryMeasurement(name) class _MemoryV8Benchmark(_MemoryInfra): @@ -159,15 +148,15 @@ return options @classmethod - def ValueCanBeAddedPredicate(cls, value, _): - if 'memory:chrome' in value.name: + def ShouldAddValue(cls, name, _): + if 'memory:chrome' in name: # TODO(petrcermak): Remove the first two cases once # https://codereview.chromium.org/2018503002/ lands in Catapult and rolls # into Chromium. - return ('renderer:subsystem:v8' in value.name or - 'renderer:vmstats:overall' in value.name or - bool(cls._V8_AND_OVERALL_MEMORY_RE.search(value.name))) - return 'v8' in value.name + return ('renderer:subsystem:v8' in name or + 'renderer:vmstats:overall' in name or + bool(cls._V8_AND_OVERALL_MEMORY_RE.search(name))) + return 'v8' in name @benchmark.Owner(emails=['ulan@chromium.org']) @@ -180,14 +169,6 @@ def Name(cls): return 'memory.long_running_idle_gmail_tbmv2' - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableBenchmark( - [story.expectations.ANDROID_SVELTE], - 'Requires a lot of memory: crbug.com/611167') - return StoryExpectations() - @benchmark.Owner(emails=['ulan@chromium.org']) class MemoryLongRunningIdleGmailBackground(_MemoryV8Benchmark): @@ -202,11 +183,3 @@ @classmethod def Name(cls): return 'memory.long_running_idle_gmail_background_tbmv2' - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableBenchmark( - [story.expectations.ANDROID_SVELTE], - 'Requires a lot of memory: crbug.com/616530') - return StoryExpectations()
diff --git a/tools/perf/benchmarks/octane.py b/tools/perf/benchmarks/octane.py index 3919c0f..e4de4b67 100644 --- a/tools/perf/benchmarks/octane.py +++ b/tools/perf/benchmarks/octane.py
@@ -117,7 +117,7 @@ 'benchmark collection.')) -@benchmark.Owner(emails=['bmeurer@chromium.org', 'mvstanton@chromium.org']) +@benchmark.Owner(emails=['hablich@chromium.org']) class Octane(perf_benchmark.PerfBenchmark): """Google's Octane JavaScript benchmark. @@ -139,11 +139,3 @@ ps, ps.base_dir, make_javascript_deterministic=False, name='http://chromium.github.io/octane/index.html?auto=1')) return ps - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableStory( - 'http://chromium.github.io/octane/index.html?auto=1', - [story.expectations.ANDROID_ONE], 'http://crbug.com/764875') - return StoryExpectations()
diff --git a/tools/perf/benchmarks/oortonline.py b/tools/perf/benchmarks/oortonline.py index 08cced9..5df5de6 100644 --- a/tools/perf/benchmarks/oortonline.py +++ b/tools/perf/benchmarks/oortonline.py
@@ -8,54 +8,11 @@ from core import perf_benchmark from telemetry import benchmark -from telemetry import story -from telemetry.page import legacy_page_test -from telemetry.value import scalar -from telemetry.value import improvement_direction from telemetry.timeline import chrome_trace_category_filter from telemetry.timeline import chrome_trace_config from telemetry.web_perf import timeline_based_measurement -class _OortOnlineMeasurement(legacy_page_test.LegacyPageTest): - - def __init__(self): - super(_OortOnlineMeasurement, self).__init__() - - def ValidateAndMeasurePage(self, page, tab, results): - del page # unused - tab.WaitForJavaScriptCondition('window.benchmarkFinished', timeout=1000) - scores = tab.EvaluateJavaScript('window.benchmarkScore') - for score in scores: - valid = score['valid'] - if valid: - results.AddValue(scalar.ScalarValue( - results.current_page, score['name'], 'score', score['score'], - important=True, improvement_direction=improvement_direction.UP)) - - -@benchmark.Owner(emails=['ulan@chromium.org']) -class OortOnline(perf_benchmark.PerfBenchmark): - """OortOnline benchmark that measures WebGL and V8 performance. - URL: http://oortonline.gl/#run - Info: http://v8project.blogspot.de/2015/10/jank-busters-part-one.html - """ - test = _OortOnlineMeasurement - SUPPORTED_PLATFORMS = [story.expectations.ALL_DESKTOP] - - @classmethod - def Name(cls): - return 'oortonline' - - def CreateStorySet(self, options): - return page_sets.OortOnlinePageSet() - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass - return StoryExpectations() - @benchmark.Owner(emails=['ulan@chromium.org']) class OortOnlineTBMv2(perf_benchmark.PerfBenchmark): """OortOnline benchmark that measures WebGL and V8 performance. @@ -71,12 +28,6 @@ page_set = page_sets.OortOnlineTBMPageSet - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # http://oortonline.gl/#run not disabled. - return StoryExpectations() - def CreateCoreTimelineBasedMeasurementOptions(self): categories = [ # Implicitly disable all categories. @@ -112,9 +63,9 @@ return 'oortonline_tbmv2' @classmethod - def ValueCanBeAddedPredicate(cls, value, _): - if 'memory:chrome' in value.name: - return bool(cls._V8_AND_OVERALL_MEMORY_RE.search(value.name)) - if 'animation ' in value.name: - return 'throughput' in value.name or 'frameTimeDiscrepancy' in value.name - return 'v8' in value.name + def ShouldAddValue(cls, name, _): + if 'memory:chrome' in name: + return bool(cls._V8_AND_OVERALL_MEMORY_RE.search(name)) + if 'animation ' in name: + return 'throughput' in name or 'frameTimeDiscrepancy' in name + return 'v8' in name
diff --git a/tools/perf/benchmarks/power.py b/tools/perf/benchmarks/power.py index 15ed918..d2c37b0b 100644 --- a/tools/perf/benchmarks/power.py +++ b/tools/perf/benchmarks/power.py
@@ -23,25 +23,9 @@ options.full_performance_mode = False @classmethod - def ShouldDisable(cls, possible_browser): - # http://crbug.com/597656 - if (possible_browser.browser_type == 'reference' and - possible_browser.platform.GetDeviceTypeName() == 'Nexus 5X'): - return True - - # crbug.com/671631 - return possible_browser.platform.GetDeviceTypeName() == 'Nexus 9' - - @classmethod def Name(cls): return 'power.typical_10_mobile' - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass - return StoryExpectations() - @benchmark.Owner(emails=['charliea@chromium.org', 'rnephew@chromium.org']) class IdlePlatformBenchmark(perf_benchmark.PerfBenchmark): @@ -66,19 +50,9 @@ ]) return options - @classmethod - def ShouldDisable(cls, possible_browser): - return not possible_browser.platform.HasBattOrConnected() - def CreateStorySet(self, options): return page_sets.IdleStorySet() @classmethod def Name(cls): return 'power.idle_platform' - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations()
diff --git a/tools/perf/benchmarks/rasterize_and_record_micro.py b/tools/perf/benchmarks/rasterize_and_record_micro.py index ec45067..5737d350a6 100644 --- a/tools/perf/benchmarks/rasterize_and_record_micro.py +++ b/tools/perf/benchmarks/rasterize_and_record_micro.py
@@ -7,7 +7,6 @@ from measurements import rasterize_and_record_micro import page_sets from telemetry import benchmark -from telemetry import story class _RasterizeAndRecordMicro(perf_benchmark.PerfBenchmark): @@ -57,20 +56,6 @@ def Name(cls): return 'rasterize_and_record_micro.top_25' - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - # Should a story need to be disabled, note that story names - # for the static top 25 page set used by this benchmark are of - # the format "file://static_top_25/page.html" where - # "page.html" is substituted with the actual story's static - # html filename as found under - # tools/perf/page_sets/static_top_25. - self.DisableStory( - 'file://static_top_25/wikipedia.html', [story.expectations.ALL], - 'crbug.com/764543') - return StoryExpectations() - @benchmark.Owner( emails=['vmpstr@chromium.org', 'wkorman@chromium.org'], @@ -84,9 +69,3 @@ @classmethod def Name(cls): return 'rasterize_and_record_micro.partial_invalidation' - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations()
diff --git a/tools/perf/benchmarks/service_worker.py b/tools/perf/benchmarks/service_worker.py deleted file mode 100644 index f9530e36..0000000 --- a/tools/perf/benchmarks/service_worker.py +++ /dev/null
@@ -1,207 +0,0 @@ -# Copyright 2014 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 collections -import page_sets -import re - -from core import perf_benchmark - -from telemetry import benchmark -from telemetry import story -from telemetry.core import util -from telemetry.page import legacy_page_test -from telemetry.timeline import async_slice as async_slice_module -from telemetry.timeline import slice as slice_module -from telemetry.value import scalar - -from measurements import timeline_controller -from metrics import speedindex - - -class _ServiceWorkerTimelineMetric(object): - - def AddResultsOfCounters(self, process, counter_regex_string, results): - counter_filter = re.compile(counter_regex_string) - for counter_name, counter in process.counters.iteritems(): - if not counter_filter.search(counter_name): - continue - - total = sum(counter.totals) - - # Results objects cannot contain the '.' character, so remove that here. - sanitized_counter_name = counter_name.replace('.', '_') - - results.AddValue(scalar.ScalarValue( - results.current_page, sanitized_counter_name, 'count', total)) - results.AddValue(scalar.ScalarValue( - results.current_page, sanitized_counter_name + '_avg', 'count', - total / float(len(counter.totals)))) - - def AddResultsOfEvents( - self, process, thread_regex_string, event_regex_string, results): - thread_filter = re.compile(thread_regex_string) - event_filter = re.compile(event_regex_string) - - for thread in process.threads.itervalues(): - thread_name = thread.name.replace('/', '_') - if not thread_filter.search(thread_name): - continue - - filtered_events = [] - for event in thread.IterAllEvents(): - event_name = event.name.replace('.', '_') - if event_filter.search(event_name): - filtered_events.append(event) - - async_events_by_name = collections.defaultdict(list) - sync_events_by_name = collections.defaultdict(list) - for event in filtered_events: - if isinstance(event, async_slice_module.AsyncSlice): - async_events_by_name[event.name].append(event) - elif isinstance(event, slice_module.Slice): - sync_events_by_name[event.name].append(event) - - for event_name, event_group in async_events_by_name.iteritems(): - times = [e.duration for e in event_group] - self._AddResultOfEvent(thread_name, event_name, times, results) - - for event_name, event_group in sync_events_by_name.iteritems(): - times = [e.self_time for e in event_group] - self._AddResultOfEvent(thread_name, event_name, times, results) - - def _AddResultOfEvent(self, thread_name, event_name, times, results): - total = sum(times) - biggest_jank = max(times) - - # Results objects cannot contain the '.' character, so remove that here. - sanitized_event_name = event_name.replace('.', '_') - - full_name = thread_name + '|' + sanitized_event_name - results.AddValue(scalar.ScalarValue( - results.current_page, full_name, 'ms', total)) - results.AddValue(scalar.ScalarValue( - results.current_page, full_name + '_max', 'ms', biggest_jank)) - results.AddValue(scalar.ScalarValue( - results.current_page, full_name + '_avg', 'ms', total / len(times))) - - -class _ServiceWorkerMeasurement(legacy_page_test.LegacyPageTest): - """Measure Speed Index and TRACE_EVENTs""" - - def __init__(self): - super(_ServiceWorkerMeasurement, self).__init__() - self._timeline_controller = timeline_controller.TimelineController() - self._speed_index = speedindex.SpeedIndexMetric() - self._page_open_times = collections.defaultdict(int) - - def DidRunPage(self, platform): - if platform.tracing_controller.is_tracing_running: - platform.tracing_controller.StopTracing() - - def WillNavigateToPage(self, page, tab): - self._timeline_controller.SetUp(page, tab) - self._timeline_controller.Start(tab) - self._speed_index.Start(page, tab) - - def ValidateAndMeasurePage(self, page, tab, results): - # timeline_controller requires creation of at least a single interaction - # record. service_worker should be refactored to follow the - # timeline_based_measurement or it should not re-use timeline_controller - # logic for start & stop tracing. - with tab.action_runner.CreateInteraction('_DummyInteraction'): - pass - tab.WaitForDocumentReadyStateToBeComplete(40) - self._timeline_controller.Stop(tab, results) - - # Retrieve TRACE_EVENTs - timeline_metric = _ServiceWorkerTimelineMetric() - browser_process = self._timeline_controller.model.browser_process - filter_text = '(RegisterServiceWorker|'\ - 'UnregisterServiceWorker|'\ - 'ProcessAllocate|'\ - 'FindRegistrationForDocument|'\ - 'DispatchFetchEvent)' - timeline_metric.AddResultsOfEvents( - browser_process, 'IOThread', filter_text, results) - - # Record Speed Index - def SpeedIndexIsFinished(): - return self._speed_index.IsFinished(tab) - util.WaitFor(SpeedIndexIsFinished, 60) - self._speed_index.Stop(page, tab) - # Distinguish the first and second load from the subsequent loads - url = str(page) - chart_prefix = 'page_load' - self._page_open_times[url] += 1 - if self._page_open_times[url] == 1: - chart_prefix += '_1st' - elif self._page_open_times[url] == 2: - chart_prefix += '_2nd' - else: - chart_prefix += '_later' - self._speed_index.AddResults(tab, results, chart_prefix) - - -class _ServiceWorkerMicroBenchmarkMeasurement(legacy_page_test.LegacyPageTest): - """Record results reported by the JS microbenchmark.""" - - def __init__(self): - super(_ServiceWorkerMicroBenchmarkMeasurement, self).__init__() - - def ValidateAndMeasurePage(self, page, tab, results): - del page # unused - tab.WaitForJavaScriptCondition('window.done', timeout=40) - json = tab.EvaluateJavaScript('window.results || {}') - for key, value in json.iteritems(): - results.AddValue(scalar.ScalarValue( - results.current_page, key, value['units'], value['value'])) - - -@benchmark.Owner(emails=['horo@chromium.org']) -class ServiceWorkerPerfTest(perf_benchmark.PerfBenchmark): - """Performance test of pages using ServiceWorker. - - The page set contains pages like Trained to Thrill and svgomg. - Execution time of these pages will be shown as Speed Index, and TRACE_EVENTs - are subsidiary information to understand performance regressions in more - detail. - """ - test = _ServiceWorkerMeasurement - page_set = page_sets.ServiceWorkerPageSet - - @classmethod - def Name(cls): - return 'service_worker.service_worker' - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableBenchmark([story.expectations.ALL], - 'crbug.com/736518, crbug.com/763153') - return StoryExpectations() - - -@benchmark.Owner(emails=['horo@chromium.org']) -class ServiceWorkerMicroBenchmarkPerfTest(perf_benchmark.PerfBenchmark): - """This test is a microbenchmark of service worker. - - The page set is a benchmark page that generates many concurrent requests - handled by a service worker that does respondWith(new Response()). The test - result is the response times. - """ - test = _ServiceWorkerMicroBenchmarkMeasurement - page_set = page_sets.ServiceWorkerMicroBenchmarkPageSet - - @classmethod - def Name(cls): - return 'service_worker.service_worker_micro_benchmark' - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableStory('http://localhost:8091/index.html', - [story.expectations.ANDROID_WEBVIEW], - 'crbug.com/653924') - return StoryExpectations()
diff --git a/tools/perf/benchmarks/smoothness.py b/tools/perf/benchmarks/smoothness.py index 0dc07a2..defb980 100644 --- a/tools/perf/benchmarks/smoothness.py +++ b/tools/perf/benchmarks/smoothness.py
@@ -14,27 +14,12 @@ class _Smoothness(perf_benchmark.PerfBenchmark): """Base class for smoothness-based benchmarks.""" - # Certain smoothness pages do not perform gesture scrolling, in turn yielding - # an empty first_gesture_scroll_update_latency result. Such empty results - # should be ignored, allowing aggregate metrics for that page set. - _PAGES_WITHOUT_SCROLL_GESTURE_BLACKLIST = [ - 'http://mobile-news.sandbox.google.com/news/pt0'] - test = smoothness.Smoothness @classmethod def Name(cls): return 'smoothness' - @classmethod - def ValueCanBeAddedPredicate(cls, value, is_first_result): - del is_first_result # unused - if (value.name == 'first_gesture_scroll_update_latency' and - value.page.url in cls._PAGES_WITHOUT_SCROLL_GESTURE_BLACKLIST and - value.values is None): - return False - return True - @benchmark.Owner(emails=['vmiura@chromium.org']) class SmoothnessTop25(_Smoothness): @@ -42,24 +27,20 @@ http://www.chromium.org/developers/design-documents/rendering-benchmarks """ - page_set = page_sets.Top25SmoothPageSet @classmethod def Name(cls): return 'smoothness.top_25_smooth' - def GetExpectations(self): - class StoryExpectations(story_module.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableStory('http://www.cnn.com', [story_module.expectations.ALL], - 'crbug.com/528474') - self.DisableStory('http://www.amazon.com', - [story_module.expectations.ALL], - 'crbug.com/667432') - self.DisableStory('https://mail.google.com/mail/', - [story_module.expectations.ALL_WIN], - 'crbug.com/750147') - return StoryExpectations() + @classmethod + def AddBenchmarkCommandLineArgs(cls, parser): + parser.add_option('--scroll-forever', action='store_true', + help='If set, continuously scroll up and down forever. ' + 'This is useful for analysing scrolling behaviour ' + 'with tools such as perf.') + + def CreateStorySet(self, options): + return page_sets.Top25SmoothPageSet(scroll_forever=options.scroll_forever) @benchmark.Owner(emails=['senorblanco@chromium.org']) @@ -74,13 +55,6 @@ def Name(cls): return 'smoothness.tough_filters_cases' - def GetExpectations(self): - class StoryExpectations(story_module.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableBenchmark([story_module.expectations.ANDROID_NEXUS6], - 'crbug.com/624032') - return StoryExpectations() - @benchmark.Owner(emails=['senorblanco@chromium.org']) class SmoothnessToughPathRenderingCases(_Smoothness): @@ -93,12 +67,6 @@ def Name(cls): return 'smoothness.tough_path_rendering_cases' - def GetExpectations(self): - class StoryExpectations(story_module.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing. - return StoryExpectations() - @benchmark.Owner(emails=['junov@chromium.org']) class SmoothnessToughCanvasCases(_Smoothness): @@ -115,24 +83,6 @@ def Name(cls): return 'smoothness.tough_canvas_cases' - def GetExpectations(self): - class StoryExpectations(story_module.expectations.StoryExpectations): - def SetExpectations(self): - # TODO(rnephew): Uncomment out after story is added back to set after - # rerecording. - # self.DisableStory( - # 'http://ie.microsoft.com/testdrive/Performance/Fireflies/Default.' - # 'html', [story_module.expectations.ALL], 'crbug.com/314131') - - # pylint: disable=line-too-long - self.DisableStory('http://geoapis.appspot.com/agdnZW9hcGlzchMLEgtFeGFtcGxlQ29kZRjh1wIM', - [story_module.expectations.ANDROID_NEXUS5], - 'crbug.com/364248') - self.DisableStory('tough_canvas_cases/canvas_toBlob.html', - [story_module.expectations.ANDROID_ONE], - 'crbug.com/755657') - return StoryExpectations() - @benchmark.Owner(emails=['kbr@chromium.org', 'zmo@chromium.org']) class SmoothnessToughWebGLCases(_Smoothness): @@ -142,30 +92,15 @@ def Name(cls): return 'smoothness.tough_webgl_cases' - def GetExpectations(self): - class StoryExpectations(story_module.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing. - return StoryExpectations() - @benchmark.Owner(emails=['kbr@chromium.org', 'zmo@chromium.org']) -class SmoothnessMaps(perf_benchmark.PerfBenchmark): +class SmoothnessMaps(_Smoothness): page_set = page_sets.MapsPageSet @classmethod def Name(cls): return 'smoothness.maps' - def GetExpectations(self): - class StoryExpectations(story_module.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableStory( - 'http://map-test/performance.html', - [story_module.expectations.ANDROID_WEBVIEW], - 'crbug.com/653993') - return StoryExpectations() - @benchmark.Owner(emails=['ssid@chromium.org']) class SmoothnessKeyDesktopMoveCases(_Smoothness): @@ -176,14 +111,6 @@ def Name(cls): return 'smoothness.key_desktop_move_cases' - def GetExpectations(self): - class StoryExpectations(story_module.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableStory('https://mail.google.com/mail/', - [story_module.expectations.ALL_WIN], - 'crbug.com/750131') - return StoryExpectations() - @benchmark.Owner(emails=['vmiura@chromium.org', 'tdresser@chromium.org']) class SmoothnessKeyMobileSites(_Smoothness): @@ -198,15 +125,6 @@ def Name(cls): return 'smoothness.key_mobile_sites_smooth' - def GetExpectations(self): - class StoryExpectations(story_module.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableStory( - 'http://digg.com', - [story_module.expectations.ALL_ANDROID], - 'crbug.com/756119') - return StoryExpectations() - @benchmark.Owner(emails=['alancutter@chromium.org']) class SmoothnessToughAnimationCases(_Smoothness): @@ -216,26 +134,6 @@ def Name(cls): return 'smoothness.tough_animation_cases' - def GetExpectations(self): - class StoryExpectations(story_module.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableStory('robohornetpro', [story_module.expectations.ALL], - 'crbug.com/350692') - self.DisableStory( - 'balls_css_keyframe_animations_composited_transform.html', - [story_module.expectations.ALL_MOBILE], - 'crbug.com/755556') - self.DisableStory( - 'mix_blend_mode_animation_difference.html', - [story_module.expectations.ALL_MAC], - 'crbug.com/755556') - self.DisableStory( - 'mix_blend_mode_animation_hue.html', - [story_module.expectations.ALL_MAC], - 'crbug.com/755556') - - return StoryExpectations() - @benchmark.Owner(emails=['ajuma@chromium.org']) class SmoothnessKeySilkCases(_Smoothness): @@ -249,24 +147,6 @@ def Name(cls): return 'smoothness.key_silk_cases' - def CreateStorySet(self, options): - stories = super(SmoothnessKeySilkCases, self).CreateStorySet(options) - # Page26 (befamous) is too noisy to be useful; crbug.com/461127 - to_remove = [story for story in stories - if isinstance(story, page_sets.key_silk_cases.Page26)] - for story in to_remove: - stories.RemoveStory(story) - return stories - - def GetExpectations(self): - class StoryExpectations(story_module.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableStory( - 'inbox_app.html?slide_drawer', [story_module.expectations.ALL], - 'Story contains multiple interaction records. Not supported in ' - 'smoothness benchmarks.') - return StoryExpectations() - @benchmark.Owner(emails=['vmiura@chromium.org']) class SmoothnessGpuRasterizationTop25(_Smoothness): @@ -274,7 +154,8 @@ """ tag = 'gpu_rasterization' page_set = page_sets.Top25SmoothPageSet - SUPPORTED_PLATFORMS = [story_module.expectations.ALL_MOBILE] + SUPPORTED_PLATFORMS = [story_module.expectations.ALL_MOBILE, + story_module.expectations.ALL_CHROMEOS] def SetExtraBrowserOptions(self, options): silk_flags.CustomizeBrowserOptionsForGpuRasterization(options) @@ -283,18 +164,6 @@ def Name(cls): return 'smoothness.gpu_rasterization.top_25_smooth' - def GetExpectations(self): - class StoryExpectations(story_module.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableStory('http://www.cnn.com', [story_module.expectations.ALL], - 'crbug.com/528474') - self.DisableStory('http://www.amazon.com', - [story_module.expectations.ALL], - 'crbug.com/667432') - self.DisableStory('Pinterest', [story_module.expectations.ALL], - 'crbug.com/667432') - return StoryExpectations() - # Although GPU rasterization is enabled on Mac, it is blacklisted for certain # path cases, so it is still valuable to run both the GPU and non-GPU versions @@ -314,12 +183,6 @@ def Name(cls): return 'smoothness.gpu_rasterization.tough_path_rendering_cases' - def GetExpectations(self): - class StoryExpectations(story_module.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing. - return StoryExpectations() - @benchmark.Owner(emails=['senorblanco@chromium.org']) class SmoothnessGpuRasterizationFiltersCases(_Smoothness): @@ -344,12 +207,6 @@ def Name(cls): return 'smoothness.gpu_rasterization.tough_filters_cases' - def GetExpectations(self): - class StoryExpectations(story_module.expectations.StoryExpectations): - def SetExpectations(self): - pass - return StoryExpectations() - @benchmark.Owner(emails=['tdresser@chromium.org', 'rbyers@chromium.org']) class SmoothnessSyncScrollKeyMobileSites(_Smoothness): @@ -367,15 +224,6 @@ def Name(cls): return 'smoothness.sync_scroll.key_mobile_sites_smooth' - def GetExpectations(self): - class StoryExpectations(story_module.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableStory( - 'http://digg.com', - [story_module.expectations.ALL], - 'crbug.com/756119') - return StoryExpectations() - @benchmark.Owner(emails=['vmiura@chromium.org']) class SmoothnessSimpleMobilePages(_Smoothness): @@ -388,14 +236,6 @@ def Name(cls): return 'smoothness.simple_mobile_sites' - def GetExpectations(self): - class StoryExpectations(story_module.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableStory('https://www.flickr.com/', - [story_module.expectations.ANDROID_WEBVIEW], - 'crbug.com/750833') - return StoryExpectations() - @benchmark.Owner(emails=['bokan@chromium.org']) class SmoothnessToughPinchZoomCases(_Smoothness): @@ -409,65 +249,6 @@ def Name(cls): return 'smoothness.tough_pinch_zoom_cases' - def GetExpectations(self): - class StoryExpectations(story_module.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableStory('https://www.google.com/#hl=en&q=barack+obama', - [story_module.expectations.ALL_ANDROID], - 'crbug.com/631015') - self.DisableStory('https://mail.google.com/mail/', - [story_module.expectations.ALL_ANDROID], - 'crbug.com/631015') - self.DisableStory('https://www.google.com/calendar/', - [story_module.expectations.ALL_ANDROID], - 'crbug.com/631015') - self.DisableStory('https://www.google.com/search?q=cats&tbm=isch', - [story_module.expectations.ALL_ANDROID], - 'crbug.com/631015') - self.DisableStory('http://www.youtube.com', - [story_module.expectations.ALL_ANDROID], - 'crbug.com/631015') - self.DisableStory('Blogger', - [story_module.expectations.ALL_ANDROID], - 'crbug.com/631015') - self.DisableStory('Facebook', - [story_module.expectations.ALL_ANDROID], - 'crbug.com/631015') - self.DisableStory('LinkedIn', - [story_module.expectations.ALL_ANDROID], - 'crbug.com/631015') - self.DisableStory('Twitter', - [story_module.expectations.ALL_ANDROID], - 'crbug.com/631015') - self.DisableStory('ESPN', - [story_module.expectations.ALL_ANDROID], - 'crbug.com/631015') - self.DisableStory('http://news.yahoo.com', - [story_module.expectations.ALL_ANDROID], - 'crbug.com/631015') - self.DisableStory('http://www.cnn.com', - [story_module.expectations.ALL_ANDROID], - 'crbug.com/631015') - self.DisableStory('Weather.com', - [story_module.expectations.ALL_ANDROID], - 'crbug.com/631015') - self.DisableStory('http://www.amazon.com', - [story_module.expectations.ALL_ANDROID], - 'crbug.com/631015') - self.DisableStory('http://www.ebay.com', - [story_module.expectations.ALL_ANDROID], - 'crbug.com/631015') - self.DisableStory('http://games.yahoo.com', - [story_module.expectations.ALL_ANDROID], - 'crbug.com/631015') - self.DisableStory('http://booking.com', - [story_module.expectations.ALL_ANDROID], - 'crbug.com/631015') - self.DisableStory('http://sports.yahoo.com/', - [story_module.expectations.ALL_ANDROID], - 'crbug.com/631015') - return StoryExpectations() - @benchmark.Owner(emails=['ericrk@chromium.org']) class SmoothnessDesktopToughPinchZoomCases(_Smoothness): @@ -481,12 +262,6 @@ def Name(cls): return 'smoothness.desktop_tough_pinch_zoom_cases' - def GetExpectations(self): - class StoryExpectations(story_module.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations() - @benchmark.Owner(emails=['ericrk@chromium.org']) class SmoothnessGpuRasterizationToughPinchZoomCases(_Smoothness): @@ -505,63 +280,6 @@ def Name(cls): return 'smoothness.gpu_rasterization.tough_pinch_zoom_cases' - def GetExpectations(self): - - class StoryExpectations(story_module.expectations.StoryExpectations): - - def SetExpectations(self): - self.DisableStory('https://www.google.com/#hl=en&q=barack+obama', - [story_module.expectations.ALL_ANDROID], - 'crbug.com/610021') - self.DisableStory('https://mail.google.com/mail/', - [story_module.expectations.ALL_ANDROID], - 'crbug.com/610021') - self.DisableStory('https://www.google.com/calendar/', - [story_module.expectations.ALL_ANDROID], - 'crbug.com/610021') - self.DisableStory('https://www.google.com/search?q=cats&tbm=isch', - [story_module.expectations.ALL_ANDROID], - 'crbug.com/610021') - self.DisableStory('http://www.youtube.com', - [story_module.expectations.ALL_ANDROID], - 'crbug.com/610021') - self.DisableStory('Blogger', [story_module.expectations.ALL_ANDROID], - 'crbug.com/610021') - self.DisableStory('Facebook', [story_module.expectations.ALL_ANDROID], - 'crbug.com/610021') - self.DisableStory('LinkedIn', [story_module.expectations.ALL_ANDROID], - 'crbug.com/610021') - self.DisableStory('Twitter', [story_module.expectations.ALL_ANDROID], - 'crbug.com/610021') - self.DisableStory('ESPN', [story_module.expectations.ALL_ANDROID], - 'crbug.com/610021') - self.DisableStory('http://news.yahoo.com', - [story_module.expectations.ALL_ANDROID], - 'crbug.com/610021') - self.DisableStory('http://www.cnn.com', - [story_module.expectations.ALL_ANDROID], - 'crbug.com/610021') - self.DisableStory('Weather.com', - [story_module.expectations.ALL_ANDROID], - 'crbug.com/610021') - self.DisableStory('http://www.amazon.com', - [story_module.expectations.ALL_ANDROID], - 'crbug.com/610021') - self.DisableStory('http://www.ebay.com', - [story_module.expectations.ALL_ANDROID], - 'crbug.com/610021') - self.DisableStory('http://games.yahoo.com', - [story_module.expectations.ALL_ANDROID], - 'crbug.com/610021') - self.DisableStory('http://booking.com', - [story_module.expectations.ALL_ANDROID], - 'crbug.com/610021') - self.DisableStory('http://sports.yahoo.com/', - [story_module.expectations.ALL_ANDROID], - 'crbug.com/610021') - - return StoryExpectations() - @benchmark.Owner(emails=['vmiura@chromium.org']) class SmoothnessGpuRasterizationPolymer(_Smoothness): @@ -577,37 +295,23 @@ def Name(cls): return 'smoothness.gpu_rasterization.polymer' - def GetExpectations(self): - class StoryExpectations(story_module.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableBenchmark( - [story_module.expectations.ALL], - 'Mobile Benchmark that needs modernization. Crbug.com/750876') - return StoryExpectations() - @benchmark.Owner(emails=['reveman@chromium.org']) class SmoothnessToughScrollingCases(_Smoothness): page_set = page_sets.ToughScrollingCasesPageSet @classmethod - def ValueCanBeAddedPredicate(cls, value, is_first_result): - del is_first_result # unused + def ShouldAddValue(cls, name, from_first_story_run): + del from_first_story_run # unused # Only keep 'mean_pixels_approximated' and 'mean_pixels_checkerboarded' # metrics. (crbug.com/529331) - return value.name in ('mean_pixels_approximated', - 'mean_pixels_checkerboarded') + return name in ('mean_pixels_approximated', + 'mean_pixels_checkerboarded') @classmethod def Name(cls): return 'smoothness.tough_scrolling_cases' - def GetExpectations(self): - class StoryExpectations(story_module.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing. - return StoryExpectations() - @benchmark.Owner(emails=['ericrk@chromium.org']) class SmoothnessGpuRasterizationToughScrollingCases(_Smoothness): @@ -622,12 +326,6 @@ def Name(cls): return 'smoothness.gpu_rasterization.tough_scrolling_cases' - def GetExpectations(self): - class StoryExpectations(story_module.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing. - return StoryExpectations() - class SmoothnessToughImageDecodeCases(_Smoothness): page_set = page_sets.ToughImageDecodeCasesPageSet @@ -636,12 +334,6 @@ def Name(cls): return 'smoothness.tough_image_decode_cases' - def GetExpectations(self): - class StoryExpectations(story_module.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing. - return StoryExpectations() - @benchmark.Owner(emails=['cblume@chromium.org']) class SmoothnessImageDecodingCases(_Smoothness): @@ -657,12 +349,6 @@ def Name(cls): return 'smoothness.image_decoding_cases' - def GetExpectations(self): - class StoryExpectations(story_module.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing. - return StoryExpectations() - @benchmark.Owner(emails=['cblume@chromium.org']) class SmoothnessGpuImageDecodingCases(_Smoothness): @@ -680,12 +366,6 @@ def Name(cls): return 'smoothness.gpu_rasterization_and_decoding.image_decoding_cases' - def GetExpectations(self): - class StoryExpectations(story_module.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing. - return StoryExpectations() - @benchmark.Owner(emails=['picksi@chromium.org']) class SmoothnessPathologicalMobileSites(_Smoothness): @@ -698,13 +378,6 @@ def Name(cls): return 'smoothness.pathological_mobile_sites' - def GetExpectations(self): - class StoryExpectations(story_module.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableBenchmark([story_module.expectations.ANDROID_NEXUS7], - 'crbug.com/685342') - return StoryExpectations() - @benchmark.Owner(emails=['vmiura@chromium.org']) class SmoothnessToughTextureUploadCases(_Smoothness): @@ -714,11 +387,6 @@ def Name(cls): return 'smoothness.tough_texture_upload_cases' - def GetExpectations(self): - class StoryExpectations(story_module.expectations.StoryExpectations): - pass # Nothing. - return StoryExpectations() - @benchmark.Owner(emails=['skyostil@chromium.org']) class SmoothnessToughAdCases(_Smoothness): @@ -730,17 +398,10 @@ return 'smoothness.tough_ad_cases' @classmethod - def ValueCanBeAddedPredicate(cls, value, is_first_result): - del is_first_result # unused + def ShouldAddValue(cls, name, from_first_story_run): + del from_first_story_run # unused # These pages don't scroll so it's not necessary to measure input latency. - return value.name != 'first_gesture_scroll_update_latency' - - def GetExpectations(self): - class StoryExpectations(story_module.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableBenchmark([story_module.expectations.ANDROID_SVELTE], - 'www.crbug.com/555089') - return StoryExpectations() + return name != 'first_gesture_scroll_update_latency' @benchmark.Owner(emails=['skyostil@chromium.org']) @@ -752,13 +413,6 @@ def Name(cls): return 'smoothness.tough_webgl_ad_cases' - def GetExpectations(self): - class StoryExpectations(story_module.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableBenchmark([story_module.expectations.ANDROID_SVELTE], - 'crbug.com/574485') - return StoryExpectations() - @benchmark.Owner(emails=['skyostil@chromium.org', 'brianderson@chromium.org']) class SmoothnessToughSchedulingCases(_Smoothness):
diff --git a/tools/perf/benchmarks/speedometer.py b/tools/perf/benchmarks/speedometer.py index 95a3950..c51058d 100644 --- a/tools/perf/benchmarks/speedometer.py +++ b/tools/perf/benchmarks/speedometer.py
@@ -72,6 +72,12 @@ page, 'Total', 'ms', tab.EvaluateJavaScript('benchmarkClient._timeValues'), important=True)) + results.AddValue(list_of_scalar_values.ListOfScalarValues( + page, 'RunsPerMinute', 'score', + tab.EvaluateJavaScript( + '[parseFloat(document.getElementById("result-number").innerText)];' + ), + important=True)) # Extract the timings for each suite for suite_name in self.enabled_suites: @@ -89,7 +95,7 @@ keychain_metric.KeychainMetric().AddResults(tab, results) -@benchmark.Owner(emails=['bmeurer@chromium.org', 'mvstanton@chromium.org']) +@benchmark.Owner(emails=['hablich@chromium.org']) class Speedometer(perf_benchmark.PerfBenchmark): test = SpeedometerMeasurement @@ -108,8 +114,17 @@ name='http://browserbench.org/Speedometer/')) return ps - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # http://browserbench.org/Speedometer/ not disabled. - return StoryExpectations() + +@benchmark.Owner(emails=['hablich@chromium.org']) +class V8SpeedometerFuture(Speedometer): + """Speedometer benchmark with the V8 flag --future. + + Shows the performance of upcoming V8 VM features. + """ + + @classmethod + def Name(cls): + return 'speedometer-future' + + def SetExtraBrowserOptions(self, options): + options.AppendExtraBrowserArgs('--enable-features=V8VmFuture')
diff --git a/tools/perf/benchmarks/speedometer2.py b/tools/perf/benchmarks/speedometer2.py index 9f056b660..e9301de9 100644 --- a/tools/perf/benchmarks/speedometer2.py +++ b/tools/perf/benchmarks/speedometer2.py
@@ -6,6 +6,7 @@ """ import os +import re from core import path_util from core import perf_benchmark @@ -19,11 +20,32 @@ _SPEEDOMETER_DIR = os.path.join(path_util.GetChromiumSrcDir(), 'third_party', 'WebKit', 'PerformanceTests', 'Speedometer') +_SPEEDOMETER_SUITE_NAME_BASE = '{0}-TodoMVC' +_SPEEDOMETER_SUITES = [ + 'VanillaJS', + 'Vanilla-ES2015', + 'Vanilla-ES2015-Babel-Webpack', + 'React', + 'React-Redux', + 'EmberJS', + 'EmberJS-Debug', + 'BackboneJS', + 'AngularJS', + 'Angular2-TypeScript', + 'VueJS', + 'jQuery', + 'Preact', + 'Inferno', + 'Elm', + 'Flight' +] class Speedometer2Measurement(legacy_page_test.LegacyPageTest): - def __init__(self): + def __init__(self, should_filter_suites, filtered_suite_names=None): super(Speedometer2Measurement, self).__init__() + self.should_filter_suites_ = should_filter_suites + self.filtered_suites_ = filtered_suite_names def ValidateAndMeasurePage(self, page, tab, results): tab.WaitForDocumentReadyStateToBeComplete() @@ -33,6 +55,13 @@ if tab.browser.platform.GetOSName() == 'android': iterationCount = 3 + if self.should_filter_suites_: + tab.ExecuteJavaScript(""" + Suites.forEach(function(suite) { + suite.disabled = {{ filtered_suites }}.indexOf(suite.name) < 0; + }); + """, filtered_suites=self.filtered_suites_) + enabled_suites = tab.EvaluateJavaScript(""" (function() { var suitesNames = []; @@ -49,10 +78,8 @@ var iterationCount = {{ count }}; var benchmarkClient = {}; var suiteValues = []; - var totalValues = []; benchmarkClient.didRunSuites = function(measuredValues) { suiteValues.push(measuredValues); - totalValues.push(measuredValues.total); }; benchmarkClient.didFinishLastIteration = function () { testDone = true; @@ -62,10 +89,16 @@ """, count=iterationCount) tab.WaitForJavaScriptCondition('testDone', timeout=600) - results.AddValue(list_of_scalar_values.ListOfScalarValues( - page, 'Total', 'ms', - tab.EvaluateJavaScript('totalValues'), - important=True)) + + if not self.should_filter_suites_: + results.AddValue(list_of_scalar_values.ListOfScalarValues( + page, 'Total', 'ms', + tab.EvaluateJavaScript('suiteValues.map(each => each.total)'), + important=True)) + results.AddValue(list_of_scalar_values.ListOfScalarValues( + page, 'RunsPerMinute', 'score', + tab.EvaluateJavaScript('suiteValues.map(each => each.score)'), + important=True)) # Extract the timings for each suite for suite_name in enabled_suites: @@ -82,17 +115,68 @@ key=suite_name), important=False)) -@benchmark.Owner(emails=['verwaest@chromium.org, mvstanton@chromium.org']) +@benchmark.Owner(emails=['hablich@chromium.org']) class Speedometer2(perf_benchmark.PerfBenchmark): - test = Speedometer2Measurement + """Speedometer2 Benchmark. + Runs all the speedometer 2 suites by default. Add --suite=<regex> to filter + out suites, and only run suites whose names are matched by the regular + expression provided. + """ @classmethod def Name(cls): return 'speedometer2' + @staticmethod + def GetFullSuiteName(name): + return _SPEEDOMETER_SUITE_NAME_BASE.format(name) + + @staticmethod + def GetSuites(suite_regex): + if not suite_regex: + return [] + exp = re.compile(suite_regex) + return [name for name in _SPEEDOMETER_SUITES + if exp.search(Speedometer2.GetFullSuiteName(name))] + + def CreatePageTest(self, options): + should_filter_suites = bool(options.suite) + filtered_suite_names = map(Speedometer2.GetFullSuiteName, + Speedometer2.GetSuites(options.suite)) + return Speedometer2Measurement(should_filter_suites, filtered_suite_names) + def CreateStorySet(self, options): ps = story.StorySet(base_dir=_SPEEDOMETER_DIR, serving_dirs=[_SPEEDOMETER_DIR]) ps.AddStory(page_module.Page( 'file://InteractiveRunner.html', ps, ps.base_dir, name='Speedometer2')) return ps + + @classmethod + def AddBenchmarkCommandLineArgs(cls, parser): + parser.add_option('--suite', type="string", + help="Only runs suites that match regex provided") + + @classmethod + def ProcessCommandLineArgs(cls, parser, args): + if args.suite: + try: + if not Speedometer2.GetSuites(args.suite): + raise parser.error('--suite: No matches.') + except re.error: + raise parser.error('--suite: Invalid regex.') + + +@benchmark.Owner(emails=['hablich@chromium.org']) +class V8Speedometer2Future(Speedometer2): + """Speedometer2 benchmark with the V8 flag --future. + + Shows the performance of upcoming V8 VM features. + """ + + @classmethod + def Name(cls): + return 'speedometer2-future' + + def SetExtraBrowserOptions(self, options): + options.AppendExtraBrowserArgs('--enable-features=V8VmFuture')
diff --git a/tools/perf/benchmarks/start_with_url.py b/tools/perf/benchmarks/start_with_url.py index c142c7fae..ea2e2f9 100644 --- a/tools/perf/benchmarks/start_with_url.py +++ b/tools/perf/benchmarks/start_with_url.py
@@ -47,16 +47,6 @@ def Name(cls): return 'start_with_url.cold.startup_pages' - # TODO(rnephew): Test if kapook.com fails on both or just one of the configs. - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableBenchmark( - [story.expectations.ANDROID_NEXUS7], 'crbug.com/667470') - self.DisableStory( - 'http://kapook.com', [story.expectations.ALL], 'crbug.com/667470') - return StoryExpectations() - @benchmark.Owner(emails=['pasko@chromium.org']) class StartWithUrlWarmTBM(_StartupPerfBenchmark): @@ -71,17 +61,40 @@ return 'start_with_url.warm.startup_pages' @classmethod - def ValueCanBeAddedPredicate(cls, value, is_first_result): - del value # unused + def ShouldAddValue(cls, name, from_first_story_run): + del name # unused # Ignores first results because the first invocation is actualy cold since # we are loading the profile for the first time. - return not is_first_result + return not from_first_story_run - # TODO(rnephew): Test if kapook.com fails on both or just one of the configs. - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableStory( - 'http://kapook.com', [story.expectations.ALL], 'crbug.com/667470') - return StoryExpectations() +@benchmark.Owner(emails=['pasko@chromium.org']) +class ExperimentalStartWithUrlCold(perf_benchmark.PerfBenchmark): + """Measures time to start Chrome cold with startup URLs (TBMv2 version).""" + # TODO(pasko): also add the .warm version of the TBMv2 benchmark after the + # cold one graduates from experimental. + + page_set = page_sets.ExperimentalStartupPagesPageSet + options = {'pageset_repeat': 11} + SUPPORTED_PLATFORMS = [story.expectations.ANDROID_NOT_WEBVIEW] + + @classmethod + def Name(cls): + # TODO(pasko): Actually make it 'coldish', that is, purge the OS page cache + # only for files of the Chrome application, its profile and disk caches. + return 'experimental.startup.android.coldish' + + def SetExtraBrowserOptions(self, options): + options.clear_sytem_cache_for_browser_and_profile_on_start = True + super(ExperimentalStartWithUrlCold, self).SetExtraBrowserOptions(options) + + def CreateCoreTimelineBasedMeasurementOptions(self): + startup_category_filter = ( + chrome_trace_category_filter.ChromeTraceCategoryFilter( + filter_string=('loading,net,netlog,network,offline_pages,' + 'startup,toplevel,Java,EarlyJava'))) + options = timeline_based_measurement.Options( + overhead_level=startup_category_filter) + options.config.enable_chrome_trace = True + options.SetTimelineBasedMetrics(['androidStartupMetric']) + return options
diff --git a/tools/perf/benchmarks/system_health.py b/tools/perf/benchmarks/system_health.py index 0db7b45..62739ec1 100644 --- a/tools/perf/benchmarks/system_health.py +++ b/tools/perf/benchmarks/system_health.py
@@ -16,8 +16,9 @@ import page_sets -# See tr.v.Numeric.getSummarizedScalarNumericsWithNames() -# https://github.com/catapult-project/catapult/blob/master/tracing/tracing/value/numeric.html#L323 +# Regex to filter out a few names of statistics supported by +# Histogram.getStatisticScalar(), see: +# https://github.com/catapult-project/catapult/blob/d4179a05/tracing/tracing/value/histogram.html#L645 pylint: disable=line-too-long _IGNORED_STATS_RE = re.compile(r'_(std|count|max|min|sum|pct_\d{4}(_\d+)?)$') @@ -35,9 +36,11 @@ """ def CreateCoreTimelineBasedMeasurementOptions(self): - options = timeline_based_measurement.Options( - chrome_trace_category_filter.ChromeTraceCategoryFilter( - filter_string='rail,toplevel')) + cat_filter = chrome_trace_category_filter.ChromeTraceCategoryFilter( + filter_string='rail,toplevel') + cat_filter.AddIncludedCategory('accessibility') + + options = timeline_based_measurement.Options(cat_filter) options.config.enable_battor_trace = True options.config.enable_chrome_trace = True options.config.enable_cpu_trace = True @@ -45,7 +48,9 @@ 'clockSyncLatencyMetric', 'cpuTimeMetric', 'powerMetric', - 'tracingMetric' + 'tracingMetric', + 'accessibilityMetric', + 'limitedCpuTimeMetric' ]) loading_metrics_category.AugmentOptionsForLoadingMetrics(options) # The EQT metric depends on the same categories as the loading metric. @@ -66,9 +71,6 @@ def Name(cls): return 'system_health.common_desktop' - def GetExpectations(self): - return page_sets.SystemHealthDesktopCommonExpectations() - @benchmark.Owner(emails=['charliea@chromium.org', 'nednguyen@chromium.org']) class MobileCommonSystemHealth(_CommonSystemHealthBenchmark): @@ -80,9 +82,6 @@ def Name(cls): return 'system_health.common_mobile' - def GetExpectations(self): - return page_sets.SystemHealthMobileCommonExpectations() - class _MemorySystemHealthBenchmark(perf_benchmark.PerfBenchmark): """Chrome Memory System Health Benchmark. @@ -110,10 +109,11 @@ take_memory_measurement=True) @classmethod - def ValueCanBeAddedPredicate(cls, value, is_first_result): + def ShouldAddValue(cls, name, from_first_story_run): + del from_first_story_run # unused # TODO(crbug.com/610962): Remove this stopgap when the perf dashboard # is able to cope with the data load generated by TBMv2 metrics. - return not _IGNORED_STATS_RE.search(value.name) + return not _IGNORED_STATS_RE.search(name) @benchmark.Owner(emails=['perezju@chromium.org']) @@ -134,9 +134,6 @@ # '--enable-heap-profiling=native', #]) - def GetExpectations(self): - return page_sets.SystemHealthDesktopMemoryExpectations() - @benchmark.Owner(emails=['perezju@chromium.org']) class MobileMemorySystemHealth(_MemorySystemHealthBenchmark): @@ -157,9 +154,6 @@ def Name(cls): return 'system_health.memory_mobile' - def GetExpectations(self): - return page_sets.SystemHealthMobileMemoryExpectations() - @benchmark.Owner(emails=['perezju@chromium.org', 'torne@chromium.org']) class WebviewStartupSystemHealthBenchmark(perf_benchmark.PerfBenchmark): @@ -176,9 +170,6 @@ def CreateStorySet(self, options): return page_sets.SystemHealthBlankStorySet() - def GetExpectations(self): - return page_sets.SystemHealthWebviewStartupExpectations() - def CreateCoreTimelineBasedMeasurementOptions(self): options = timeline_based_measurement.Options() options.SetTimelineBasedMetrics(['webviewStartupMetric'])
diff --git a/tools/perf/benchmarks/system_health_smoke_test.py b/tools/perf/benchmarks/system_health_smoke_test.py index ca2fc23..b76334d 100644 --- a/tools/perf/benchmarks/system_health_smoke_test.py +++ b/tools/perf/benchmarks/system_health_smoke_test.py
@@ -11,6 +11,7 @@ import unittest +from core import path_util from core import perf_benchmark from telemetry import benchmark as benchmark_module @@ -45,10 +46,11 @@ 'benchmarks.system_health_smoke_test.SystemHealthBenchmarkSmokeTest.system_health.memory_desktop.long_running:tools:gmail-foreground', # pylint: disable=line-too-long 'benchmarks.system_health_smoke_test.SystemHealthBenchmarkSmokeTest.system_health.memory_desktop.long_running:tools:gmail-background', # pylint: disable=line-too-long - # Disable media tests in CQ. crbug.com/649392 - 'benchmarks.system_health_smoke_test.SystemHealthBenchmarkSmokeTest.system_health.memory_desktop.load:media:soundcloud', # pylint: disable=line-too-long + # crbug.com/769263 'benchmarks.system_health_smoke_test.SystemHealthBenchmarkSmokeTest.system_health.memory_desktop.play:media:soundcloud', # pylint: disable=line-too-long - 'benchmarks.system_health_smoke_test.SystemHealthBenchmarkSmokeTest.system_health.memory_desktop.play:media:google_play_music', # pylint: disable=line-too-long + + # crbug.com/769809 + 'benchmarks.system_health_smoke_test.SystemHealthBenchmarkSmokeTest.system_health.memory_desktop.browse_accessibility:tools:gmail_compose', # pylint: disable=line-too-long # crbug.com/ 'benchmarks.system_health_smoke_test.SystemHealthBenchmarkSmokeTest.system_health.memory_desktop.browse:news:nytimes', # pylint: disable=line-too-long @@ -63,16 +65,17 @@ 'benchmarks.system_health_smoke_test.SystemHealthBenchmarkSmokeTest.system_health.memory_desktop.load:tools:drive', # pylint: disable=line-too-long 'benchmarks.system_health_smoke_test.SystemHealthBenchmarkSmokeTest.system_health.memory_desktop.load:tools:gmail', # pylint: disable=line-too-long - # crbug.com/699966 - 'benchmarks.system_health_smoke_test.SystemHealthBenchmarkSmokeTest.system_health.memory_desktop.multitab:misc:typical24', # pylint: disable=line-too-long # crbug.com/725386 'benchmarks.system_health_smoke_test.SystemHealthBenchmarkSmokeTest.system_health.memory_desktop.browse:social:twitter', # pylint: disable=line-too-long - # crbug.com/755969 - 'benchmarks.system_health_smoke_test.SystemHealthBenchmarkSmokeTest.system_health.memory_desktop.browse:search:google', # pylint: disable=line-too-long + # crbug.com/799734 + 'benchmarks.system_health_smoke_test.SystemHealthBenchmarkSmokeTest.system_health.memory_desktop.browse:media:tumblr', # pylint: disable=line-too-long }) +MAX_NUM_VALUES = 50000 + + def _GenerateSmokeTestCase(benchmark_class, story_to_smoke_test): # NOTE TO SHERIFFS: DO NOT DISABLE THIS TEST. @@ -96,17 +99,30 @@ return story_set options = GenerateBenchmarkOptions(benchmark_class) + + # Prevent benchmarks from accidentally trying to upload too much data to the + # chromeperf dashboard. The number of values uploaded is equal to (the + # average number of values produced by a single story) * (1 + (the number of + # stories)). The "1 + " accounts for values summarized across all stories. + # We can approximate "the average number of values produced by a single + # story" as the number of values produced by the given story. + # pageset_repeat doesn't matter because values are summarized across + # repetitions before uploading. + story_set = benchmark_class().CreateStorySet(options) + SinglePageBenchmark.MAX_NUM_VALUES = MAX_NUM_VALUES / len(story_set.stories) + possible_browser = browser_finder.FindBrowser(options) if possible_browser is None: self.skipTest('Cannot find the browser to run the test.') - if (SinglePageBenchmark.ShouldDisable(possible_browser) or - not decorators.IsEnabled(benchmark_class, possible_browser)[0]): - self.skipTest('Benchmark %s is disabled' % SinglePageBenchmark.Name()) if self.id() in _DISABLED_TESTS: self.skipTest('Test is explicitly disabled') - self.assertEqual(0, SinglePageBenchmark().Run(options), + single_page_benchmark = SinglePageBenchmark() + with open(path_util.GetExpectationsPath()) as fp: + single_page_benchmark.AugmentExpectationsWithParser(fp.read()) + + self.assertEqual(0, single_page_benchmark.Run(options), msg='Failed: %s' % benchmark_class) # We attach the test method to SystemHealthBenchmarkSmokeTest dynamically
diff --git a/tools/perf/benchmarks/tab_switching.py b/tools/perf/benchmarks/tab_switching.py index 0765737..4aa43b5f 100644 --- a/tools/perf/benchmarks/tab_switching.py +++ b/tools/perf/benchmarks/tab_switching.py
@@ -6,10 +6,11 @@ from core import perf_benchmark -from measurements import tab_switching from page_sets.system_health import multi_tab_stories from telemetry import benchmark from telemetry import story +from telemetry.timeline import chrome_trace_category_filter +from telemetry.web_perf import timeline_based_measurement @benchmark.Owner(emails=['vovoy@chromium.org'], @@ -22,7 +23,6 @@ tabs, waits for them to load, and then switches to each tab and records the metric. The pages were chosen from Alexa top ranking sites. """ - test = tab_switching.TabSwitching SUPPORTED_PLATFORMS = [story.expectations.ALL_DESKTOP] @classmethod @@ -39,13 +39,13 @@ story_set, False, options.tabset_repeat)) return story_set + def CreateCoreTimelineBasedMeasurementOptions(self): + category_filter = chrome_trace_category_filter.ChromeTraceCategoryFilter() + category_filter.AddIncludedCategory('latency') + options = timeline_based_measurement.Options(category_filter) + options.SetTimelineBasedMetrics(['tabsMetric']) + return options + @classmethod def Name(cls): return 'tab_switching.typical_25' - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableStory('multitab:misc:typical24', - [story.expectations.ALL_MAC], 'crbug.com/747026') - return StoryExpectations()
diff --git a/tools/perf/benchmarks/thread_times.py b/tools/perf/benchmarks/thread_times.py index c1a1dda..2b8b70704 100644 --- a/tools/perf/benchmarks/thread_times.py +++ b/tools/perf/benchmarks/thread_times.py
@@ -23,9 +23,10 @@ return 'thread_times' @classmethod - def ValueCanBeAddedPredicate(cls, value, _): + def ShouldAddValue(cls, name, from_first_story_run): + del from_first_story_run # unused # Default to only reporting per-frame metrics. - return 'per_second' not in value.name + return 'per_second' not in name def SetExtraBrowserOptions(self, options): silk_flags.CustomizeBrowserOptionsForThreadTimes(options) @@ -45,23 +46,6 @@ def Name(cls): return 'thread_times.key_silk_cases' - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableStory('https://polymer-topeka.appspot.com/', - [story.expectations.ALL], 'crbug.com/507865') - self.DisableStory('http://plus.google.com/app/basic/stream', - [story.expectations.ALL], 'crbug.com/338838') - self.DisableStory('inbox_app.html?slide_drawer', - [story.expectations.ALL], 'crbug.com/446332') - self.DisableStory('http://s.codepen.io/befamous/fullpage/pFsqb?scroll', - [story.expectations.ALL], 'crbug.com/764825') - self.DisableStory('inbox_app.html?swipe_to_dismiss', - [story.expectations.ALL], 'crbug.com/764825') - self.DisableStory('masonry.html', - [story.expectations.ALL], 'crbug.com/764825') - return StoryExpectations() - class ThreadTimesKeyHitTestCases(_ThreadTimes): """Measure timeline metrics while performing smoothness action on key hit @@ -75,15 +59,6 @@ def Name(cls): return 'thread_times.key_hit_test_cases' - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableBenchmark( - [story.expectations.ALL], - 'Disabled on all platforms due to use of deprecated web platform ' - 'features. Crbug.com/750876.') - return StoryExpectations() - @benchmark.Owner(emails=['vmiura@chromium.org']) class ThreadTimesKeyMobileSitesSmooth(_ThreadTimes): @@ -98,21 +73,6 @@ def Name(cls): return 'thread_times.key_mobile_sites_smooth' - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass - # TODO(rnephew): Uncomment when these stories is rerecorded. - # self.DisableStory( - # 'http://forecast.io', [story.expectations.ALL], - # 'crbug.com/249736') - # self.DisableStory( - # 'Twitter', [story.expectations.ALL], - # 'Forbidden (Rate Limit Exceeded)') - # self.DisableStory('ESPN', [story.expectations.ALL], - # 'crbug.com/249722') - return StoryExpectations() - @benchmark.Owner(emails=['vmiura@chromium.org']) class ThreadTimesSimpleMobileSites(_ThreadTimes): @@ -125,13 +85,6 @@ def Name(cls): return 'thread_times.simple_mobile_sites' - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableStory('https://www.flickr.com/', [story.expectations.ALL], - 'crbug.com/752228') - return StoryExpectations() - @benchmark.Owner(emails=['vmiura@chromium.org']) class ThreadTimesCompositorCases(_ThreadTimes): @@ -149,12 +102,6 @@ def Name(cls): return 'thread_times.tough_compositor_cases' - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations() - @benchmark.Owner(emails=['skyostil@chromium.org']) class ThreadTimesKeyIdlePowerCases(_ThreadTimes): @@ -168,15 +115,10 @@ return 'thread_times.key_idle_power_cases' @classmethod - def ValueCanBeAddedPredicate(cls, value, _): + def ShouldAddValue(cls, name, from_first_story_run): + del from_first_story_run # unused # Only report per-second metrics. - return 'per_frame' not in value.name and 'mean_frame' not in value.name - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass - return StoryExpectations() + return 'per_frame' not in name and 'mean_frame' not in name class ThreadTimesKeyNoOpCases(_ThreadTimes): @@ -190,15 +132,10 @@ return 'thread_times.key_noop_cases' @classmethod - def ValueCanBeAddedPredicate(cls, value, _): + def ShouldAddValue(cls, name, from_first_story_run): + del from_first_story_run # unused # Only report per-second metrics. - return 'per_frame' not in value.name and 'mean_frame' not in value.name - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass - return StoryExpectations() + return 'per_frame' not in name and 'mean_frame' not in name @benchmark.Owner(emails=['tdresser@chromium.org']) @@ -210,9 +147,3 @@ @classmethod def Name(cls): return 'thread_times.tough_scrolling_cases' - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations()
diff --git a/tools/perf/benchmarks/tracing.py b/tools/perf/benchmarks/tracing.py index e7c0b77..092388cc 100644 --- a/tools/perf/benchmarks/tracing.py +++ b/tools/perf/benchmarks/tracing.py
@@ -5,8 +5,6 @@ from core import perf_benchmark from telemetry import benchmark -from telemetry import decorators -from telemetry import story from telemetry.timeline import chrome_trace_category_filter from telemetry.timeline import chrome_trace_config from telemetry.web_perf import timeline_based_measurement @@ -15,7 +13,6 @@ @benchmark.Owner(emails=['ssid@chromium.org']) -@decorators.Disabled('all') # crbug.com/765140 class TracingWithBackgroundMemoryInfra(perf_benchmark.PerfBenchmark): """Measures the overhead of background memory-infra dumps""" page_set = page_sets.Top10PageSet @@ -35,9 +32,3 @@ @classmethod def Name(cls): return 'tracing.tracing_with_background_memory_infra' - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # No tests disabled. - return StoryExpectations()
diff --git a/tools/perf/benchmarks/v8.py b/tools/perf/benchmarks/v8.py index 1e8f43e2..f4e807d 100644 --- a/tools/perf/benchmarks/v8.py +++ b/tools/perf/benchmarks/v8.py
@@ -8,7 +8,6 @@ import page_sets from telemetry import benchmark -from telemetry import story from telemetry.timeline import chrome_trace_category_filter from telemetry.web_perf import timeline_based_measurement @@ -25,16 +24,8 @@ def Name(cls): return 'v8.detached_context_age_in_gc' - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations() - class _Top25RuntimeStats(perf_benchmark.PerfBenchmark): - options = {'pageset_repeat': 3} - def SetExtraBrowserOptions(self, options): options.AppendExtraBrowserArgs( '--enable-blink-features=BlinkRuntimeCallStats') @@ -72,12 +63,6 @@ tbm_options.SetTimelineBasedMetrics(['runtimeStatsMetric']) return tbm_options - @classmethod - def ShouldDisable(cls, possible_browser): - if possible_browser.browser_type == 'reference': - return True - return False - @benchmark.Owner(emails=['cbruni@chromium.org']) class V8Top25RuntimeStats(_Top25RuntimeStats): @@ -93,11 +78,3 @@ def CreateStorySet(self, options): return page_sets.V8Top25StorySet() - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableBenchmark( - [story.expectations.ALL_ANDROID, story.expectations.ALL_WIN], - 'crbug.com/664318') - return StoryExpectations()
diff --git a/tools/perf/benchmarks/v8_browsing.py b/tools/perf/benchmarks/v8_browsing.py index b3d13b7..3d3b378 100644 --- a/tools/perf/benchmarks/v8_browsing.py +++ b/tools/perf/benchmarks/v8_browsing.py
@@ -13,8 +13,9 @@ import page_sets -# See tr.v.Numeric.getSummarizedScalarNumericsWithNames() -# https://github.com/catapult-project/catapult/blob/master/tracing/tracing/value/numeric.html#L323 +# Regex to filter out a few names of statistics supported by +# Histogram.getStatisticScalar(), see: +# https://github.com/catapult-project/catapult/blob/d4179a05/tracing/tracing/value/histogram.html#L645 pylint: disable=line-too-long _IGNORED_MEMORY_STATS_RE = re.compile(r'_(std|count|min|sum|pct_\d{4}(_\d+)?)$') # Track only the high-level GC stats to reduce the data load on dashboard. @@ -30,84 +31,15 @@ r'total_)') -class _v8BrowsingBenchmarkBaseClass(perf_benchmark.PerfBenchmark): - """Base class for all v8 browsing benchmarks.""" +class _V8BrowsingBenchmark(perf_benchmark.PerfBenchmark): + """Base class for V8 browsing benchmarks that measure RuntimeStats, + eqt, gc and memory metrics. + See browsing_stories._BrowsingStory for workload description. + """ + def CreateStorySet(self, options): return page_sets.SystemHealthStorySet(platform=self.PLATFORM, case='browse') - def GetExpectations(self): - if self.PLATFORM is 'desktop': - return page_sets.V8BrowsingDesktopExpecations() - if self.PLATFORM is 'mobile': - return page_sets.V8BrowsingMobileExpecations() - raise NotImplementedError, ('Only have expectations for mobile and desktop ' - 'platforms for v8_browsing tests.') - - -class _V8BrowsingBenchmark(_v8BrowsingBenchmarkBaseClass): - """Base class for V8 browsing benchmarks. - This benchmark measures memory usage with periodic memory dumps and v8 times. - See browsing_stories._BrowsingStory for workload description. - """ - - def CreateCoreTimelineBasedMeasurementOptions(self): - categories = [ - # Disable all categories by default. - '-*', - # Memory categories. - 'disabled-by-default-memory-infra', - # EQT categories. - 'blink.user_timing', - 'loading', - 'navigation', - 'toplevel', - # V8 categories. - 'blink.console', - 'disabled-by-default-v8.compile', - 'disabled-by-default-v8.gc', - 'renderer.scheduler', - 'v8', - 'webkit.console', - # TODO(crbug.com/616441, primiano): Remove this temporary workaround, - # which enables memory-infra V8 code stats in V8 code size benchmarks - # only (to not slow down detailed memory dumps in other benchmarks). - 'disabled-by-default-memory-infra.v8.code_stats', - # Blink categories. - 'blink_gc', - ] - options = timeline_based_measurement.Options( - chrome_trace_category_filter.ChromeTraceCategoryFilter( - ','.join(categories))) - options.config.enable_android_graphics_memtrack = True - # Trigger periodic light memory dumps every 1000 ms. - memory_dump_config = chrome_trace_config.MemoryDumpConfig() - memory_dump_config.AddTrigger('light', 1000) - options.config.chrome_trace_config.SetMemoryDumpConfig(memory_dump_config) - options.SetTimelineBasedMetrics([ - 'expectedQueueingTimeMetric', 'v8AndMemoryMetrics', 'blinkGcMetric']) - return options - - @classmethod - def ValueCanBeAddedPredicate(cls, value, is_first_result): - # TODO(crbug.com/610962): Remove this stopgap when the perf dashboard - # is able to cope with the data load generated by TBMv2 metrics. - if 'memory:chrome' in value.name: - return ('renderer_processes' in value.name and - not _IGNORED_MEMORY_STATS_RE.search(value.name)) - if 'v8-gc' in value.name: - return (_V8_GC_HIGH_LEVEL_STATS_RE.search(value.name) and - not _IGNORED_V8_STATS_RE.search(value.name)) - # Allow all other metrics. - return True - - -class _V8RuntimeStatsBrowsingBenchmark(_v8BrowsingBenchmarkBaseClass): - """Base class for V8 browsing benchmarks that measure RuntimeStats. - RuntimeStats measure the time spent by v8 in different phases like - compile, JS execute, runtime etc., - See browsing_stories._BrowsingStory for workload description. - """ - def CreateCoreTimelineBasedMeasurementOptions(self): categories = [ # Disable all categories by default. @@ -129,6 +61,10 @@ 'v8', 'webkit.console', 'disabled-by-default-v8.runtime_stats', + # TODO(crbug.com/616441, primiano): Remove this temporary workaround, + # which enables memory-infra V8 code stats in V8 code size benchmarks + # only (to not slow down detailed memory dumps in other benchmarks). + 'disabled-by-default-memory-infra.v8.code_stats', # Blink categories. 'blink_gc', ] @@ -143,33 +79,32 @@ options.SetTimelineBasedMetrics([ 'expectedQueueingTimeMetric', 'runtimeStatsTotalMetric', 'gcMetric', - 'blinkGcMetric']) + 'blinkGcMetric', 'memoryMetric']) return options - -@benchmark.Owner(emails=['ulan@chromium.org']) -class V8DesktopBrowsingBenchmark(_V8BrowsingBenchmark): - PLATFORM = 'desktop' - SUPPORTED_PLATFORMS = [story.expectations.ALL_DESKTOP] - @classmethod - def Name(cls): - return 'v8.browsing_desktop' + def ShouldAddValue(cls, name, from_first_story_run): + del from_first_story_run # unused + # TODO(crbug.com/775942): This is needed because of a race condition in + # the memory dump manager. Remove this once the bug is fixed. + if 'memory:unknown_browser' in name: + return ('renderer_processes' in name and + not _IGNORED_MEMORY_STATS_RE.search(name)) + # TODO(crbug.com/610962): Remove this stopgap when the perf dashboard + # is able to cope with the data load generated by TBMv2 metrics. + if 'memory:chrome' in name: + return ('renderer_processes' in name and + not _IGNORED_MEMORY_STATS_RE.search(name)) + if 'v8-gc' in name: + return (_V8_GC_HIGH_LEVEL_STATS_RE.search(name) and + not _IGNORED_V8_STATS_RE.search(name)) + # Allow all other metrics. + return True -@benchmark.Owner(emails=['ulan@chromium.org']) -class V8MobileBrowsingBenchmark(_V8BrowsingBenchmark): - PLATFORM = 'mobile' - SUPPORTED_PLATFORMS = [story.expectations.ALL_MOBILE] - - @classmethod - def Name(cls): - return 'v8.browsing_mobile' - - -@benchmark.Owner(emails=['mythria@chromium.org']) -class V8RuntimeStatsDesktopBrowsingBenchmark( - _V8RuntimeStatsBrowsingBenchmark): +@benchmark.Owner(emails=['mythria@chromium.org','ulan@chromium.org']) +class V8DesktopBrowsingBenchmark( + _V8BrowsingBenchmark): PLATFORM = 'desktop' SUPPORTED_PLATFORMS = [story.expectations.ALL_DESKTOP] @@ -179,32 +114,52 @@ @classmethod def Name(cls): - return 'v8.runtimestats.browsing_desktop' + return 'v8.browsing_desktop' -@benchmark.Owner(emails=['mythria@chromium.org']) -class V8RuntimeStatsMobileBrowsingBenchmark( - _V8RuntimeStatsBrowsingBenchmark): +@benchmark.Owner(emails=['mythria@chromium.org','ulan@chromium.org']) +class V8MobileBrowsingBenchmark( + _V8BrowsingBenchmark): PLATFORM = 'mobile' SUPPORTED_PLATFORMS = [story.expectations.ALL_MOBILE] - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableStory( - 'browse:shopping:avito', - [story.expectations.ANDROID_ONE], - 'crbug.com/767970') - self.DisableStory( - 'browse:news:cnn', - [story.expectations.ANDROID_ONE], - 'crbug.com/767970') - self.DisableStory( - 'browse:tech:discourse_infinite_scroll', - [story.expectations.ANDROID_ONE], - 'crbug.com/767970') - return StoryExpectations() + def SetExtraBrowserOptions(self, options): + options.AppendExtraBrowserArgs( + '--enable-blink-features=BlinkRuntimeCallStats') @classmethod def Name(cls): - return 'v8.runtimestats.browsing_mobile' + return 'v8.browsing_mobile' + + +@benchmark.Owner(emails=['mythria@chromium.org','ulan@chromium.org']) +class V8FutureDesktopBrowsingBenchmark( + _V8BrowsingBenchmark): + PLATFORM = 'desktop' + SUPPORTED_PLATFORMS = [story.expectations.ALL_DESKTOP] + + def SetExtraBrowserOptions(self, options): + options.AppendExtraBrowserArgs( + '--enable-blink-features=BlinkRuntimeCallStats') + options.AppendExtraBrowserArgs('--enable-features=V8VmFuture') + + @classmethod + def Name(cls): + return 'v8.browsing_desktop-future' + + +@benchmark.Owner(emails=['mythria@chromium.org','ulan@chromium.org']) +class V8FutureMobileBrowsingBenchmark( + _V8BrowsingBenchmark): + PLATFORM = 'mobile' + SUPPORTED_PLATFORMS = [story.expectations.ALL_MOBILE] + + def SetExtraBrowserOptions(self, options): + options.AppendExtraBrowserArgs( + '--enable-blink-features=BlinkRuntimeCallStats') + options.AppendExtraBrowserArgs( + '--enable-features=V8VmFuture') + + @classmethod + def Name(cls): + return 'v8.browsing_mobile-future'
diff --git a/tools/perf/benchmarks/wasm.py b/tools/perf/benchmarks/wasm.py new file mode 100644 index 0000000..4d80f685 --- /dev/null +++ b/tools/perf/benchmarks/wasm.py
@@ -0,0 +1,56 @@ +# Copyright 2017 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. +from core import perf_benchmark + +import page_sets + +from telemetry import benchmark +from telemetry.timeline import chrome_trace_category_filter +from telemetry.web_perf import timeline_based_measurement + + +@benchmark.Owner(emails=['bradnelson@chromium.org']) +class Wasm(perf_benchmark.PerfBenchmark): + """Runtime Stats benchmark for real world wasm apps.""" + + options = {'pageset_repeat': 3} + + def SetExtraBrowserOptions(self, options): + options.AppendExtraBrowserArgs( + '--enable-blink-features=BlinkRuntimeCallStats') + + def CreateCoreTimelineBasedMeasurementOptions(self): + cat_filter = chrome_trace_category_filter.ChromeTraceCategoryFilter() + + # "blink.console" is used for marking ranges in + # cache_temperature.MarkTelemetryInternal. + cat_filter.AddIncludedCategory('blink.console') + + # "navigation" and "blink.user_timing" are needed to capture core + # navigation events. + cat_filter.AddIncludedCategory('navigation') + cat_filter.AddIncludedCategory('blink.user_timing') + + # "loading" is needed for first-meaningful-paint computation. + cat_filter.AddIncludedCategory('loading') + + # "toplevel" category is used to capture TaskQueueManager events + # necessary to compute time-to-interactive. + cat_filter.AddIncludedCategory('toplevel') + + # V8 needed categories + cat_filter.AddIncludedCategory('v8') + cat_filter.AddDisabledByDefault('disabled-by-default-v8.runtime_stats') + + tbm_options = timeline_based_measurement.Options( + overhead_level=cat_filter) + tbm_options.SetTimelineBasedMetrics(['runtimeStatsMetric']) + return tbm_options + + @classmethod + def Name(cls): + return 'wasm' + + def CreateStorySet(self, options): + return page_sets.WasmRealWorldPagesStorySet()
diff --git a/tools/perf/benchmarks/webrtc.py b/tools/perf/benchmarks/webrtc.py index 2fd494e..ba2336bd 100644 --- a/tools/perf/benchmarks/webrtc.py +++ b/tools/perf/benchmarks/webrtc.py
@@ -6,7 +6,6 @@ import page_sets from telemetry import benchmark -from telemetry import story from telemetry.timeline import chrome_trace_category_filter from telemetry.web_perf import timeline_based_measurement @@ -43,23 +42,3 @@ def SetExtraBrowserOptions(self, options): options.AppendExtraBrowserArgs('--use-fake-device-for-media-stream') options.AppendExtraBrowserArgs('--use-fake-ui-for-media-stream') - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - # TODO(qyearsley, mcasas): Add webrtc.audio when http://crbug.com/468732 - # is fixed, or revert https://codereview.chromium.org/1544573002/ when - # http://crbug.com/568333 is fixed. - self.DisableStory('audio_call_opus_10s', - [story.expectations.ALL], - 'crbug.com/468732') - self.DisableStory('audio_call_g772_10s', - [story.expectations.ALL], - 'crbug.com/468732') - self.DisableStory('audio_call_pcmu_10s', - [story.expectations.ALL], - 'crbug.com/468732') - self.DisableStory('audio_call_isac/1600_10s', - [story.expectations.ALL], - 'crbug.com/468732') - return StoryExpectations()
diff --git a/tools/perf/chrome_telemetry_build/BUILD.gn b/tools/perf/chrome_telemetry_build/BUILD.gn index 54a039c..3b4e270 100644 --- a/tools/perf/chrome_telemetry_build/BUILD.gn +++ b/tools/perf/chrome_telemetry_build/BUILD.gn
@@ -3,6 +3,9 @@ # found in the LICENSE file. import("//build/config/compiler/compiler.gni") +if (is_android) { + import("//build/config/android/config.gni") # For public_android_sdk +} group("telemetry_chrome_test") { testonly = true @@ -12,7 +15,7 @@ "//chrome/android:chrome_public_apk", ] - if (!defined(use_unpublished_apis) || !use_unpublished_apis) { + if (public_android_sdk) { data_deps += [ "//android_webview:system_webview_apk", "//android_webview/tools/system_webview_shell:system_webview_shell_apk", @@ -38,14 +41,78 @@ } if (is_linux) { - data_deps += [ "//breakpad:dump_syms($host_toolchain)" ] + data_deps += [ "//third_party/breakpad:dump_syms($host_toolchain)" ] } if (is_mac) { data_deps += [ - "//breakpad:dump_syms", "//chrome:chrome_framework", "//chrome:chrome_helper_app", + "//third_party/breakpad:dump_syms", + "//third_party/crashpad/crashpad/tools:crashpad_database_util", + ] + } + + if (is_win && (symbol_level == 1 || symbol_level == 2)) { + data_deps += [ + "//build/win:copy_cdb_to_output", + "//third_party/crashpad/crashpad/tools:crashpad_database_util", + ] + + # TODO(GYP): These should be provided automatically through data_deps. + data += [ "$root_out_dir/chrome.exe.pdb" ] + if (is_component_build) { + data += [ + "$root_out_dir/base.dll.pdb", + "$root_out_dir/blink_platform.dll.pdb", + "$root_out_dir/content.dll.pdb", + ] + } else { + data += [ "$root_out_dir/chrome_child.dll.pdb" ] + } + } +} + +group("telemetry_chrome_test_experimental") { + testonly = true + + if (is_android) { + data_deps = [ + "//chrome/android:chrome_public_apk", + ] + + if (public_android_sdk) { + data_deps += [ + "//android_webview:system_webview_apk", + "//android_webview/tools/system_webview_shell:system_webview_shell_apk", + ] + } + } else { + data_deps = [ + "//third_party/catapult/telemetry:bitmaptools", + ] + } + + data = [ + "//tools/perf/core/", # chrome_telemetry_build/ depends on core/ + "//tools/perf/chrome_telemetry_build/", + "//third_party/catapult/", + "//components/crash/content/tools/generate_breakpad_symbols.py", + ] + + if (is_win) { + data_deps += [ "//chrome:reorder_imports" ] + } + + if (is_linux) { + data_deps += [ "//third_party/breakpad:dump_syms($host_toolchain)" ] + } + + if (is_mac) { + data_deps += [ + "//chrome:chrome_framework", + "//chrome:chrome_helper_app", + "//third_party/breakpad:dump_syms", "//third_party/crashpad/crashpad/tools:crashpad_database_util", ] }
diff --git a/tools/perf/chrome_telemetry_build/binary_dependencies.json b/tools/perf/chrome_telemetry_build/binary_dependencies.json index 43ab52c5..18596852 100644 --- a/tools/perf/chrome_telemetry_build/binary_dependencies.json +++ b/tools/perf/chrome_telemetry_build/binary_dependencies.json
@@ -62,22 +62,6 @@ ] } } - }, - "memtrack_helper": { - "file_info": { - "android_armeabi-v7a": { - "local_paths": [ - "../../../out/Debug/memtrack_helper", - "../../../out/Release/memtrack_helper" - ] - }, - "arm64-v8a": { - "local_paths": [ - "../../../out/Debug/memtrack_helper", - "../../../out/Release/memtrack_helper" - ] - } - } } } }
diff --git a/tools/perf/chrome_telemetry_build/chromium_config.py b/tools/perf/chrome_telemetry_build/chromium_config.py index 77887a63..fa5de39 100644 --- a/tools/perf/chrome_telemetry_build/chromium_config.py +++ b/tools/perf/chrome_telemetry_build/chromium_config.py
@@ -17,7 +17,8 @@ class ChromiumConfig(project_config.ProjectConfig): def __init__(self, top_level_dir=None, benchmark_dirs=None, - client_configs=None, default_chrome_root=None): + client_configs=None, default_chrome_root=None, + expectations_file=None): if client_configs is None: client_configs = [CLIENT_CONFIG_PATH] if default_chrome_root is None: @@ -25,4 +26,5 @@ super(ChromiumConfig, self).__init__( top_level_dir=top_level_dir, benchmark_dirs=benchmark_dirs, - client_configs=client_configs, default_chrome_root=default_chrome_root) + client_configs=client_configs, default_chrome_root=default_chrome_root, + expectations_file=expectations_file)
diff --git a/tools/perf/chromium.perf.fyi.extras.json b/tools/perf/chromium.perf.fyi.extras.json deleted file mode 100644 index 790a07c..0000000 --- a/tools/perf/chromium.perf.fyi.extras.json +++ /dev/null
@@ -1,60 +0,0 @@ -{ - "comment": [ - "This file contains manually-specified tests that should be merged into", - "testing/buildbot/chromium.perf.fyi.json." - ], - "Mojo Linux Perf": { - "isolated_scripts": [ - { - "args": [ - "loading.desktop.network_service", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release", - "--xvfb" - ], - "isolate_name": "telemetry_perf_tests", - "name": "loading.desktop.network_service", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "expiration": 36000, - "hard_timeout": 10800, - "ignore_task_failure": false, - "io_timeout": 3600 - } - } - ] - }, - "Histogram Pipeline Linux Perf": { - "isolated_scripts": [ - { - "args": [ - "dummy_benchmark.histogram_benchmark_1", - "-v", - "--upload-results", - "--output-format=histograms", - "--output-format=json-test-results", - "--browser=release", - "--xvfb", - "--also-run-disabled-tests" - ], - "isolate_name": "telemetry_perf_tests", - "name": "dummy_benchmark.histogram_benchmark_1", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "expiration": 36000, - "hard_timeout": 10800, - "ignore_task_failure": false, - "io_timeout": 3600 - } - } - ] - } -}
diff --git a/tools/perf/conditionally_execute b/tools/perf/conditionally_execute index 302ab4d..129ac454 100755 --- a/tools/perf/conditionally_execute +++ b/tools/perf/conditionally_execute
@@ -25,13 +25,7 @@ # tokenize the string before doing string matching. gyp_defines = os.environ.get('GYP_DEFINES', '').split() if options.gyp_condition in gyp_defines: - print 'Found matching condition in GYP_DEFINES. Execute: %s' % ( - ' '.join(script_args)) subprocess.check_call(script_args) - else: - print ('Not found "%s" condition in GYP_DEFINES="%s". ' - 'Skip script execution.' % - (options.gyp_condition, gyp_defines)) return 0
diff --git a/tools/perf/contrib/blink_perf_cmdline/blink_perf_cmdline.py b/tools/perf/contrib/blink_perf_cmdline/blink_perf_cmdline.py index cac63522..d146e16 100644 --- a/tools/perf/contrib/blink_perf_cmdline/blink_perf_cmdline.py +++ b/tools/perf/contrib/blink_perf_cmdline/blink_perf_cmdline.py
@@ -4,7 +4,7 @@ import os from benchmarks import blink_perf -from telemetry import story + # pylint: disable=protected-access class BlinkPerfAll(blink_perf._BlinkPerfBenchmark): @@ -30,9 +30,3 @@ print print 'Running all tests in %s' % path return blink_perf.CreateStorySetFromPath(path, blink_perf.SKIPPED_FILE) - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations()
diff --git a/tools/perf/contrib/blink_perf_xml_http_request/blink_perf_xml_http_request.py b/tools/perf/contrib/blink_perf_xml_http_request/blink_perf_xml_http_request.py index 1d09193..4422e62 100644 --- a/tools/perf/contrib/blink_perf_xml_http_request/blink_perf_xml_http_request.py +++ b/tools/perf/contrib/blink_perf_xml_http_request/blink_perf_xml_http_request.py
@@ -2,16 +2,9 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. from benchmarks import blink_perf -from telemetry import story # pylint: disable=protected-access class BlinkPerfXMLHttpRequest(blink_perf._BlinkPerfBenchmark): tag = 'xml_http_request' subdir = 'XMLHttpRequest' - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations()
diff --git a/tools/perf/contrib/cluster_telemetry/OWNERS b/tools/perf/contrib/cluster_telemetry/OWNERS index ad390b4..008d4cf1 100644 --- a/tools/perf/contrib/cluster_telemetry/OWNERS +++ b/tools/perf/contrib/cluster_telemetry/OWNERS
@@ -2,3 +2,4 @@ per-file loading_ct.py=nednguyen@chromium.org per-file repaint*=wkorman@chromium.org +per-file leak_detection_ct.py=yuzus@chromium.org
diff --git a/tools/perf/contrib/cluster_telemetry/leak_detection_ct.py b/tools/perf/contrib/cluster_telemetry/leak_detection_ct.py new file mode 100644 index 0000000..bad1d9de --- /dev/null +++ b/tools/perf/contrib/cluster_telemetry/leak_detection_ct.py
@@ -0,0 +1,37 @@ +# Copyright 2017 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 py_utils +from contrib.leak_detection import leak_detection as ld + +from contrib.cluster_telemetry import ct_benchmarks_util +from contrib.cluster_telemetry import page_set + +# pylint: disable=protected-access +class LeakDetectionClusterTelemetry(ld._LeakDetectionBase): + + options = {'upload_results': True} + + @classmethod + def AddBenchmarkCommandLineArgs(cls, parser): + super(LeakDetectionClusterTelemetry, + cls).AddBenchmarkCommandLineArgs(parser) + ct_benchmarks_util.AddBenchmarkCommandLineArgs(parser) + + def CreateStorySet(self, options): + def RunNavigateSteps(self, action_runner): + action_runner.Navigate('about:blank') + action_runner.PrepareForLeakDetection() + action_runner.MeasureMemory(True) + action_runner.Navigate(self.url) + py_utils.WaitFor(action_runner.tab.HasReachedQuiescence, timeout=30) + action_runner.Navigate('about:blank') + action_runner.PrepareForLeakDetection() + action_runner.MeasureMemory(True) + return page_set.CTPageSet( + options.urls_list, options.user_agent, options.archive_data_file, + run_navigate_steps_callback=RunNavigateSteps) + + @classmethod + def Name(cls): + return 'leak_detection.cluster_telemetry'
diff --git a/tools/perf/contrib/cluster_telemetry/loading_ct.py b/tools/perf/contrib/cluster_telemetry/loading_ct.py index eccfa68..5f637e1d 100644 --- a/tools/perf/contrib/cluster_telemetry/loading_ct.py +++ b/tools/perf/contrib/cluster_telemetry/loading_ct.py
@@ -6,7 +6,6 @@ from contrib.cluster_telemetry import ct_benchmarks_util from contrib.cluster_telemetry import page_set -from telemetry import story from telemetry.page import traffic_setting @@ -41,9 +40,3 @@ @classmethod def Name(cls): return 'loading.cluster_telemetry' - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Not tests disabled. - return StoryExpectations()
diff --git a/tools/perf/contrib/cluster_telemetry/multipage_skpicture_printer.py b/tools/perf/contrib/cluster_telemetry/multipage_skpicture_printer.py index feb37bd8..b0076bd 100644 --- a/tools/perf/contrib/cluster_telemetry/multipage_skpicture_printer.py +++ b/tools/perf/contrib/cluster_telemetry/multipage_skpicture_printer.py
@@ -55,12 +55,6 @@ options.page_set_base_dir) return story_set_class() - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Not tests disabled. - return StoryExpectations() - class MultipageSkpicturePrinterCT(perf_benchmark.PerfBenchmark): """Captures mSKPs for Cluster Telemetry.""" @@ -88,9 +82,3 @@ return page_set.CTPageSet( options.urls_list, options.user_agent, options.archive_data_file, run_page_interaction_callback=repaint_helpers.WaitThenRepaint) - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Not tests disabled. - return StoryExpectations()
diff --git a/tools/perf/contrib/cluster_telemetry/page_set.py b/tools/perf/contrib/cluster_telemetry/page_set.py index c92247a3..5b89331 100644 --- a/tools/perf/contrib/cluster_telemetry/page_set.py +++ b/tools/perf/contrib/cluster_telemetry/page_set.py
@@ -12,7 +12,8 @@ class CTPage(page_module.Page): def __init__(self, url, page_set, shared_page_state_class, archive_data_file, - traffic_setting, run_page_interaction_callback): + traffic_setting, run_page_interaction_callback, + run_navigate_steps_callback): super(CTPage, self).__init__( url=url, page_set=page_set, @@ -20,10 +21,14 @@ traffic_setting=traffic_setting, name=url) self.archive_data_file = archive_data_file + self._run_navigate_steps_callback = run_navigate_steps_callback self._run_page_interaction_callback = run_page_interaction_callback def RunNavigateSteps(self, action_runner): - action_runner.Navigate(self.url) + if self._run_navigate_steps_callback: + self._run_navigate_steps_callback(self, action_runner) + else: + action_runner.Navigate(self.url) def RunPageInteractions(self, action_runner): if self._run_page_interaction_callback: @@ -35,7 +40,8 @@ def __init__(self, urls_list, user_agent, archive_data_file, traffic_setting=traffic_setting_module.NONE, - run_page_interaction_callback=None): + run_page_interaction_callback=None, + run_navigate_steps_callback=None): if user_agent == 'mobile': shared_page_state_class = shared_page_state.SharedMobilePageState elif user_agent == 'desktop': @@ -50,4 +56,5 @@ CTPage(url, self, shared_page_state_class=shared_page_state_class, archive_data_file=archive_data_file, traffic_setting=traffic_setting, - run_page_interaction_callback=run_page_interaction_callback)) + run_page_interaction_callback=run_page_interaction_callback, + run_navigate_steps_callback=run_navigate_steps_callback,))
diff --git a/tools/perf/contrib/cluster_telemetry/smoothness_ct.py b/tools/perf/contrib/cluster_telemetry/smoothness_ct.py new file mode 100644 index 0000000..6efd3c4c --- /dev/null +++ b/tools/perf/contrib/cluster_telemetry/smoothness_ct.py
@@ -0,0 +1,37 @@ +# Copyright 2017 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. + +from contrib.cluster_telemetry import ct_benchmarks_util +from contrib.cluster_telemetry import page_set + +from core import perf_benchmark +from measurements import smoothness + +def ScrollToEndOfPage(action_runner): + action_runner.Wait(1) + with action_runner.CreateGestureInteraction('ScrollAction'): + action_runner.ScrollPage() + + +class SmoothnessCT(perf_benchmark.PerfBenchmark): + """Measures smoothness performance for Cluster Telemetry.""" + + test = smoothness.Smoothness + + @classmethod + def Name(cls): + return 'smoothness_ct' + + @classmethod + def AddBenchmarkCommandLineArgs(cls, parser): + ct_benchmarks_util.AddBenchmarkCommandLineArgs(parser) + + @classmethod + def ProcessCommandLineArgs(cls, parser, args): + ct_benchmarks_util.ValidateCommandLineArgs(parser, args) + + def CreateStorySet(self, options): + return page_set.CTPageSet( + options.urls_list, options.user_agent, options.archive_data_file, + run_page_interaction_callback=ScrollToEndOfPage)
diff --git a/tools/perf/contrib/cros_benchmarks/OWNERS b/tools/perf/contrib/cros_benchmarks/OWNERS index d9523a3..b7679f9 100644 --- a/tools/perf/contrib/cros_benchmarks/OWNERS +++ b/tools/perf/contrib/cros_benchmarks/OWNERS
@@ -3,3 +3,4 @@ vovoy@chromium.org lozano@chromium.org laszio@chromium.org +cylee@chromium.org
diff --git a/tools/perf/contrib/cros_benchmarks/data/tab_switching.json b/tools/perf/contrib/cros_benchmarks/data/tab_switching.json index 473be49..e90bb94 100644 --- a/tools/perf/contrib/cros_benchmarks/data/tab_switching.json +++ b/tools/perf/contrib/cros_benchmarks/data/tab_switching.json
@@ -1,7 +1,7 @@ { "archives": { "cros_tab_switching_typical24": { - "DEFAULT": "tab_switching.wpr" + "DEFAULT": "tab_switching.wprgo" } }, "description": "Describes the Web Page Replay archives for a story set. Don't edit by hand! Use record_wpr for updating.",
diff --git a/tools/perf/contrib/cros_benchmarks/data/tab_switching.wpr.sha1 b/tools/perf/contrib/cros_benchmarks/data/tab_switching.wpr.sha1 deleted file mode 100644 index ef87891..0000000 --- a/tools/perf/contrib/cros_benchmarks/data/tab_switching.wpr.sha1 +++ /dev/null
@@ -1 +0,0 @@ -fdf3c3844b38e9ff07fd3031b7c7f893867460a7 \ No newline at end of file
diff --git a/tools/perf/contrib/cros_benchmarks/data/tab_switching.wprgo.sha1 b/tools/perf/contrib/cros_benchmarks/data/tab_switching.wprgo.sha1 new file mode 100644 index 0000000..9fd6cb1 --- /dev/null +++ b/tools/perf/contrib/cros_benchmarks/data/tab_switching.wprgo.sha1
@@ -0,0 +1 @@ +42341cef9c0292dd30179051f674cdc0800dd19b \ No newline at end of file
diff --git a/tools/perf/contrib/cros_benchmarks/page_cycler_v2.py b/tools/perf/contrib/cros_benchmarks/page_cycler_v2.py index bfaf8158..34ff057 100644 --- a/tools/perf/contrib/cros_benchmarks/page_cycler_v2.py +++ b/tools/perf/contrib/cros_benchmarks/page_cycler_v2.py
@@ -13,7 +13,6 @@ from benchmarks import loading_metrics_category from telemetry import benchmark -from telemetry import story from telemetry.page import cache_temperature from telemetry.web_perf import timeline_based_measurement @@ -25,20 +24,6 @@ loading_metrics_category.AugmentOptionsForLoadingMetrics(tbm_options) return tbm_options - @classmethod - def ShouldDisable(cls, possible_browser): - # crbug.com/619254 - if possible_browser.browser_type == 'reference': - return True - - # crbug.com/616781 - if (cls.IsSvelte(possible_browser) or - possible_browser.platform.GetDeviceTypeName() == 'Nexus 5X' or - possible_browser.platform.GetDeviceTypeName() == 'AOSP on BullHead'): - return True - - return False - @benchmark.Owner(emails=['kouhei@chromium.org', 'ksakamoto@chromium.org']) class PageCyclerV2Typical25(_PageCyclerV2): @@ -55,13 +40,7 @@ def CreateStorySet(self, options): return page_sets.Typical25PageSet(run_no_page_interactions=True, cache_temperatures=[ - cache_temperature.PCV1_COLD, cache_temperature.PCV1_WARM]) - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations() + cache_temperature.COLD, cache_temperature.WARM]) @benchmark.Owner(emails=['kouhei@chromium.org', 'ksakamoto@chromium.org']) @@ -78,13 +57,7 @@ def CreateStorySet(self, options): return page_sets.IntlArFaHePageSet(cache_temperatures=[ - cache_temperature.PCV1_COLD, cache_temperature.PCV1_WARM]) - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations() + cache_temperature.COLD, cache_temperature.WARM]) @benchmark.Owner(emails=['kouhei@chromium.org', 'ksakamoto@chromium.org']) @@ -101,13 +74,7 @@ def CreateStorySet(self, options): return page_sets.IntlEsFrPtBrPageSet(cache_temperatures=[ - cache_temperature.PCV1_COLD, cache_temperature.PCV1_WARM]) - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations() + cache_temperature.COLD, cache_temperature.WARM]) @benchmark.Owner(emails=['kouhei@chromium.org', 'ksakamoto@chromium.org']) @@ -124,13 +91,7 @@ def CreateStorySet(self, options): return page_sets.IntlHiRuPageSet(cache_temperatures=[ - cache_temperature.PCV1_COLD, cache_temperature.PCV1_WARM]) - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations() + cache_temperature.COLD, cache_temperature.WARM]) @benchmark.Owner(emails=['kouhei@chromium.org', 'ksakamoto@chromium.org']) @@ -146,13 +107,7 @@ def CreateStorySet(self, options): return page_sets.IntlJaZhPageSet(cache_temperatures=[ - cache_temperature.PCV1_COLD, cache_temperature.PCV1_WARM]) - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations() + cache_temperature.COLD, cache_temperature.WARM]) @benchmark.Owner(emails=['kouhei@chromium.org', 'ksakamoto@chromium.org']) @@ -169,10 +124,4 @@ def CreateStorySet(self, options): return page_sets.IntlKoThViPageSet(cache_temperatures=[ - cache_temperature.PCV1_COLD, cache_temperature.PCV1_WARM]) - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations() + cache_temperature.COLD, cache_temperature.WARM])
diff --git a/tools/perf/contrib/cros_benchmarks/tab_switching_bench.py b/tools/perf/contrib/cros_benchmarks/tab_switching_bench.py index ae4326b..de0a1a0 100644 --- a/tools/perf/contrib/cros_benchmarks/tab_switching_bench.py +++ b/tools/perf/contrib/cros_benchmarks/tab_switching_bench.py
@@ -25,6 +25,7 @@ Benchmark specific option: --tabset-repeat=N: Duplicate tab set for N times. + --pause-after-creation=N: Pauses N secs after tab creation. The following usage example opens 120 tabs. $ ./run_benchmark --browser=cros-chrome --remote=DUT_IP cros_tab_switching.typical_24 --tabset-repeat=5 @@ -37,6 +38,8 @@ def AddBenchmarkCommandLineArgs(cls, parser): parser.add_option('--tabset-repeat', type='int', default=1, help='repeat tab page set') + parser.add_option('--pause-after-creation', type='int', default=0, + help='pause between tab creation and tab switch') def CreateStorySet(self, options): if not options.cros_remote: @@ -46,16 +49,13 @@ archive_data_file='data/tab_switching.json', base_dir=os.path.dirname(os.path.abspath(__file__)), cloud_storage_bucket=story.PARTNER_BUCKET) + # May not have pause_after_creation attribute in presubmit check. + pause_after_creation = getattr(options, 'pause_after_creation', 0) story_set.AddStory(tab_switching_stories.CrosMultiTabTypical24Story( - story_set, options.cros_remote, options.tabset_repeat)) + story_set, options.cros_remote, options.tabset_repeat, + pause_after_creation)) return story_set @classmethod def Name(cls): return 'cros_tab_switching.typical_24' - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations()
diff --git a/tools/perf/contrib/cros_benchmarks/tab_switching_stories.py b/tools/perf/contrib/cros_benchmarks/tab_switching_stories.py index 89e81fb5..914e2ad 100644 --- a/tools/perf/contrib/cros_benchmarks/tab_switching_stories.py +++ b/tools/perf/contrib/cros_benchmarks/tab_switching_stories.py
@@ -2,9 +2,10 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import py_utils import logging +import time +import py_utils from telemetry.core import exceptions from telemetry.page import page as page_module from telemetry.page import shared_page_state @@ -16,12 +17,14 @@ class CrosMultiTabStory(page_module.Page): """Base class for multi-tab stories.""" - def __init__(self, story_set, cros_remote, tabset_repeat=1): + def __init__(self, story_set, cros_remote, tabset_repeat=1, + pause_after_creation=0): super(CrosMultiTabStory, self).__init__( shared_page_state_class=shared_page_state.SharedPageState, page_set=story_set, name=self.NAME, url=self.URL) self._cros_remote = cros_remote self._tabset_repeat = tabset_repeat + self._pause_after_creation = pause_after_creation def RunNavigateSteps(self, action_runner): """Opening tabs and waiting for them to load.""" @@ -57,6 +60,7 @@ def RunPageInteractions(self, action_runner): """Tab switching to each tabs.""" + time.sleep(self._pause_after_creation) url_list = self.URL_LIST * self._tabset_repeat browser = action_runner.tab.browser
diff --git a/tools/perf/contrib/cros_benchmarks/ui_smoothness_bench.py b/tools/perf/contrib/cros_benchmarks/ui_smoothness_bench.py new file mode 100644 index 0000000..17ced155 --- /dev/null +++ b/tools/perf/contrib/cros_benchmarks/ui_smoothness_bench.py
@@ -0,0 +1,20 @@ +# Copyright 2018 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. +from core import perf_benchmark + +from measurements import smoothness +import page_sets +from telemetry import benchmark +from telemetry import story as story_module + +@benchmark.Owner(emails=['chiniforooshan@chromium.org', 'sadrul@chromium.org']) +class CrosUiSmoothnessBenchmark(perf_benchmark.PerfBenchmark): + """Measures ChromeOS UI smoothness.""" + test = smoothness.Smoothness + page_set = page_sets.CrosUiCasesPageSet + SUPPORTED_PLATFORMS = [story_module.expectations.ALL_CHROMEOS] + + @classmethod + def Name(cls): + return 'cros_ui_smoothness'
diff --git a/tools/perf/contrib/dromaeo_extras/dromaeo_extras.py b/tools/perf/contrib/dromaeo_extras/dromaeo_extras.py index fe6d68b..a470075 100644 --- a/tools/perf/contrib/dromaeo_extras/dromaeo_extras.py +++ b/tools/perf/contrib/dromaeo_extras/dromaeo_extras.py
@@ -3,7 +3,6 @@ # found in the LICENSE file. from telemetry import benchmark -from telemetry import story from benchmarks import dromaeo @@ -29,12 +28,6 @@ def Name(cls): return 'dromaeo.jslibattrjquery' - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations() - @benchmark.Owner(emails=['yukishiino@chromium.org', 'bashi@chromium.org', @@ -52,12 +45,6 @@ def Name(cls): return 'dromaeo.jslibattrprototype' - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations() - @benchmark.Owner(emails=['yukishiino@chromium.org', 'bashi@chromium.org', @@ -75,12 +62,6 @@ def Name(cls): return 'dromaeo.jslibeventjquery' - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations() - @benchmark.Owner(emails=['yukishiino@chromium.org', 'bashi@chromium.org', @@ -98,12 +79,6 @@ def Name(cls): return 'dromaeo.jslibeventprototype' - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations() - # win-ref: http://crbug.com/598705 # android: http://crbug.com/503138 @@ -124,12 +99,6 @@ def Name(cls): return 'dromaeo.jslibmodifyjquery' - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations() - @benchmark.Owner(emails=['yukishiino@chromium.org', 'bashi@chromium.org', @@ -147,12 +116,6 @@ def Name(cls): return 'dromaeo.jslibmodifyprototype' - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations() - @benchmark.Owner(emails=['yukishiino@chromium.org', 'bashi@chromium.org', @@ -170,12 +133,6 @@ def Name(cls): return 'dromaeo.jslibstylejquery' - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations() - @benchmark.Owner(emails=['yukishiino@chromium.org', 'bashi@chromium.org', @@ -193,12 +150,6 @@ def Name(cls): return 'dromaeo.jslibstyleprototype' - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations() - @benchmark.Owner(emails=['yukishiino@chromium.org', 'bashi@chromium.org', @@ -217,12 +168,6 @@ def Name(cls): return 'dromaeo.jslibtraversejquery' - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations() - @benchmark.Owner(emails=['yukishiino@chromium.org', 'bashi@chromium.org', @@ -239,12 +184,6 @@ def Name(cls): return 'dromaeo.jslibtraverseprototype' - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations() - class DromaeoCSSQueryJquery(_BaseDromaeoBenchmark): """Dromaeo CSS Query jquery JavaScript benchmark. @@ -257,9 +196,3 @@ @classmethod def Name(cls): return 'dromaeo.cssqueryjquery' - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations()
diff --git a/tools/perf/contrib/heap_profiling/OWNERS b/tools/perf/contrib/heap_profiling/OWNERS new file mode 100644 index 0000000..cbad6ffc --- /dev/null +++ b/tools/perf/contrib/heap_profiling/OWNERS
@@ -0,0 +1,2 @@ +primiano@chromium.org +perezju@chromium.org
diff --git a/tools/perf/contrib/heap_profiling/__init__.py b/tools/perf/contrib/heap_profiling/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tools/perf/contrib/heap_profiling/__init__.py
diff --git a/tools/perf/contrib/heap_profiling/heap_profiling.py b/tools/perf/contrib/heap_profiling/heap_profiling.py new file mode 100644 index 0000000..c60f4c5 --- /dev/null +++ b/tools/perf/contrib/heap_profiling/heap_profiling.py
@@ -0,0 +1,129 @@ +# Copyright 2017 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 + +from benchmarks import loading_metrics_category + +from core import perf_benchmark + +from telemetry import story +from telemetry.timeline import chrome_trace_category_filter +from telemetry.timeline import chrome_trace_config +from telemetry.web_perf import timeline_based_measurement + +import page_sets +from page_sets.system_health import loading_stories + + +_PAGE_SETS_DATA = os.path.join(os.path.dirname(page_sets.__file__), 'data') + + +class _HeapProfilingStorySet(story.StorySet): + """Small story set containing loading stories and invoking memory dumps.""" + def __init__(self, platform): + super(_HeapProfilingStorySet, self).__init__( + archive_data_file= + os.path.join(_PAGE_SETS_DATA, 'system_health_%s.json' % platform), + cloud_storage_bucket=story.PARTNER_BUCKET) + self.AddStory( + loading_stories.LoadGoogleStory(self, take_memory_measurement=True)) + self.AddStory( + loading_stories.LoadTwitterStory(self, take_memory_measurement=True)) + self.AddStory( + loading_stories.LoadCnnStory(self, take_memory_measurement=True)) + + +class _HeapProfilingBenchmark(perf_benchmark.PerfBenchmark): + """Bechmark to measure heap profiling overhead.""" + PROFILING_MODE = NotImplemented + PLATFORM = NotImplemented + + def CreateCoreTimelineBasedMeasurementOptions(self): + cat_filter = chrome_trace_category_filter.ChromeTraceCategoryFilter( + filter_string='-*,toplevel,rail,disabled-by-default-memory-infra') + options = timeline_based_measurement.Options(cat_filter) + options.SetTimelineBasedMetrics([ + 'cpuTimeMetric', + 'loadingMetric', + 'memoryMetric', + 'tracingMetric', + ]) + loading_metrics_category.AugmentOptionsForLoadingMetrics(options) + # Disable periodic dumps by setting default config. + options.config.chrome_trace_config.SetMemoryDumpConfig( + chrome_trace_config.MemoryDumpConfig()) + return options + + def CreateStorySet(self, options): + return _HeapProfilingStorySet(self.PLATFORM) + + def SetExtraBrowserOptions(self, options): + super(_HeapProfilingBenchmark, self).SetExtraBrowserOptions(options) + args = [] + if self.PROFILING_MODE == 'pseudo': + args += ['--enable-heap-profiling'] + elif self.PROFILING_MODE == 'native': + args += ['--enable-heap-profiling=native'] + options.AppendExtraBrowserArgs(args) + + +class PseudoHeapProfilingDesktopBenchmark(_HeapProfilingBenchmark): + PROFILING_MODE = 'pseudo' + PLATFORM = 'desktop' + SUPPORTED_PLATFORMS = [story.expectations.ALL_DESKTOP] + + @classmethod + def Name(cls): + return 'heap_profiling.desktop.pseudo' + + +class NativeHeapProfilingDesktopBenchmark(_HeapProfilingBenchmark): + PROFILING_MODE = 'native' + PLATFORM = 'desktop' + SUPPORTED_PLATFORMS = [story.expectations.ALL_DESKTOP] + + @classmethod + def Name(cls): + return 'heap_profiling.desktop.native' + + +class DisabledHeapProfilingDesktopBenchmark(_HeapProfilingBenchmark): + PROFILING_MODE = 'disabled' + PLATFORM = 'desktop' + SUPPORTED_PLATFORMS = [story.expectations.ALL_DESKTOP] + + @classmethod + def Name(cls): + return 'heap_profiling.desktop.disabled' + + +class PseudoHeapProfilingMobileBenchmark(_HeapProfilingBenchmark): + PROFILING_MODE = 'pseudo' + PLATFORM = 'mobile' + SUPPORTED_PLATFORMS = [story.expectations.ALL_MOBILE] + + @classmethod + def Name(cls): + return 'heap_profiling.mobile.pseudo' + + +class NativeHeapProfilingMobileBenchmark(_HeapProfilingBenchmark): + PROFILING_MODE = 'native' + PLATFORM = 'mobile' + SUPPORTED_PLATFORMS = [story.expectations.ALL_MOBILE] + + @classmethod + def Name(cls): + return 'heap_profiling.mobile.native' + + +class DisabledHeapProfilingMobileBenchmark(_HeapProfilingBenchmark): + PROFILING_MODE = 'disabled' + PLATFORM = 'mobile' + SUPPORTED_PLATFORMS = [story.expectations.ALL_MOBILE] + + @classmethod + def Name(cls): + return 'heap_profiling.mobile.disabled'
diff --git a/tools/perf/contrib/leak_detection/OWNERS b/tools/perf/contrib/leak_detection/OWNERS new file mode 100644 index 0000000..be07ccb --- /dev/null +++ b/tools/perf/contrib/leak_detection/OWNERS
@@ -0,0 +1,2 @@ +yuzus@chromium.org +keishi@chromium.org
diff --git a/tools/perf/contrib/leak_detection/__init__.py b/tools/perf/contrib/leak_detection/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tools/perf/contrib/leak_detection/__init__.py
diff --git a/tools/perf/contrib/leak_detection/data/leak_detection.json b/tools/perf/contrib/leak_detection/data/leak_detection.json new file mode 100644 index 0000000..7743170 --- /dev/null +++ b/tools/perf/contrib/leak_detection/data/leak_detection.json
@@ -0,0 +1,69 @@ +{ + "archives": { + "http://infomoney.com.br": { + "DEFAULT": "leak_detection_003.wprgo" + }, + "http://www.aljazeera.net": { + "DEFAULT": "leak_detection_003.wprgo" + }, + "http://www.amazon.com": { + "DEFAULT": "leak_detection_003.wprgo" + }, + "http://www.cheapoair.com": { + "DEFAULT": "leak_detection_003.wprgo" + }, + "http://www.dailypost.ng": { + "DEFAULT": "leak_detection_003.wprgo" + }, + "http://www.listindiario.com": { + "DEFAULT": "leak_detection_003.wprgo" + }, + "http://www.onlinedown.net": { + "DEFAULT": "leak_detection_003.wprgo" + }, + "http://www.qq.com": { + "DEFAULT": "leak_detection_003.wprgo" + }, + "http://www.quora.com": { + "DEFAULT": "leak_detection_003.wprgo" + }, + "http://www.time.com": { + "DEFAULT": "leak_detection_003.wprgo" + }, + "http://www.twitter.com": { + "DEFAULT": "leak_detection_003.wprgo" + }, + "https://www.baidu.com": { + "DEFAULT": "leak_detection_003.wprgo" + }, + "https://www.citi.com": { + "DEFAULT": "leak_detection_002.wprgo" + }, + "https://www.facebook.com": { + "DEFAULT": "leak_detection_003.wprgo" + }, + "https://www.google.com": { + "DEFAULT": "leak_detection_003.wprgo" + }, + "https://www.macys.com": { + "DEFAULT": "leak_detection_003.wprgo" + }, + "https://www.prezi.com": { + "DEFAULT": "leak_detection_003.wprgo" + }, + "https://www.reddit.com": { + "DEFAULT": "leak_detection_003.wprgo" + }, + "https://www.wikipedia.org": { + "DEFAULT": "leak_detection_003.wprgo" + }, + "https://www.yahoo.com": { + "DEFAULT": "leak_detection_003.wprgo" + }, + "https://www.youtube.com": { + "DEFAULT": "leak_detection_003.wprgo" + } + }, + "description": "Describes the Web Page Replay archives for a story set. Don't edit by hand! Use record_wpr for updating.", + "platform_specific": true +} \ No newline at end of file
diff --git a/tools/perf/contrib/leak_detection/data/leak_detection_001.wprgo.sha1 b/tools/perf/contrib/leak_detection/data/leak_detection_001.wprgo.sha1 new file mode 100644 index 0000000..5a433c2 --- /dev/null +++ b/tools/perf/contrib/leak_detection/data/leak_detection_001.wprgo.sha1
@@ -0,0 +1 @@ +3b0c1d8e392a9fc51ae6b75e83ca2117324608c0 \ No newline at end of file
diff --git a/tools/perf/contrib/leak_detection/data/leak_detection_002.wprgo.sha1 b/tools/perf/contrib/leak_detection/data/leak_detection_002.wprgo.sha1 new file mode 100644 index 0000000..cb20845 --- /dev/null +++ b/tools/perf/contrib/leak_detection/data/leak_detection_002.wprgo.sha1
@@ -0,0 +1 @@ +acfb5e0e8b8ca318df9314df113a1340e8e43867 \ No newline at end of file
diff --git a/tools/perf/contrib/leak_detection/data/leak_detection_003.wprgo b/tools/perf/contrib/leak_detection/data/leak_detection_003.wprgo new file mode 100644 index 0000000..04cc187 --- /dev/null +++ b/tools/perf/contrib/leak_detection/data/leak_detection_003.wprgo Binary files differ
diff --git a/tools/perf/contrib/leak_detection/data/leak_detection_003.wprgo.sha1 b/tools/perf/contrib/leak_detection/data/leak_detection_003.wprgo.sha1 new file mode 100644 index 0000000..008961ca --- /dev/null +++ b/tools/perf/contrib/leak_detection/data/leak_detection_003.wprgo.sha1
@@ -0,0 +1 @@ +c1545020790af562064421c06521b3e56be437e0 \ No newline at end of file
diff --git a/tools/perf/contrib/leak_detection/leak_detection.py b/tools/perf/contrib/leak_detection/leak_detection.py new file mode 100644 index 0000000..01925b5a --- /dev/null +++ b/tools/perf/contrib/leak_detection/leak_detection.py
@@ -0,0 +1,37 @@ +# Copyright 2017 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. + +from core import perf_benchmark +from telemetry import benchmark +from telemetry.timeline import chrome_trace_category_filter +from telemetry.timeline import chrome_trace_config +from telemetry.web_perf import timeline_based_measurement + +from contrib.leak_detection import page_sets + +class _LeakDetectionBase(perf_benchmark.PerfBenchmark): + """ A base class for leak detection benchmarks. """ + + def CreateCoreTimelineBasedMeasurementOptions(self): + tbm_options = timeline_based_measurement.Options( + chrome_trace_category_filter.ChromeTraceCategoryFilter( + '-*,disabled-by-default-memory-infra')) + # Setting an empty memory dump config disables periodic dumps. + tbm_options.config.chrome_trace_config.SetMemoryDumpConfig( + chrome_trace_config.MemoryDumpConfig()) + # Set required tracing categories for leak detection + tbm_options.AddTimelineBasedMetric('leakDetectionMetric') + return tbm_options + + def CustomizeBrowserOptions(self, options): + options.AppendExtraBrowserArgs('--js-flags=--expose-gc') + + +@benchmark.Owner(emails=['yuzus@chromium.org']) +class MemoryLeakDetectionBenchmark(_LeakDetectionBase): + page_set = page_sets.LeakDetectionStorySet + + @classmethod + def Name(cls): + return 'memory.leak_detection'
diff --git a/tools/perf/contrib/leak_detection/page_sets.py b/tools/perf/contrib/leak_detection/page_sets.py new file mode 100644 index 0000000..1c5b0a0 --- /dev/null +++ b/tools/perf/contrib/leak_detection/page_sets.py
@@ -0,0 +1,81 @@ +# Copyright 2017 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 py_utils +from telemetry import story as story_module +from telemetry.page import page as page_module +from telemetry.page import shared_page_state + +class LeakDetectionSharedState(shared_page_state.SharedDesktopPageState): + def ShouldStopBrowserAfterStoryRun(self, story): + del story # unused + return False # Keep the same browser instance open across stories. + + +class LeakDetectionPage(page_module.Page): + def __init__(self, url, page_set, name=''): + super(LeakDetectionPage, self).__init__( + url=url, page_set=page_set, name=name, + shared_page_state_class=LeakDetectionSharedState) + + def RunNavigateSteps(self, action_runner): + tabs = action_runner.tab.browser.tabs + new_tab = tabs.New() + new_tab.action_runner.Navigate('about:blank') + new_tab.action_runner.PrepareForLeakDetection() + new_tab.action_runner.MeasureMemory() + new_tab.action_runner.Navigate(self.url) + self._WaitForPageLoadToComplete(new_tab.action_runner) + new_tab.action_runner.Navigate('about:blank') + new_tab.action_runner.PrepareForLeakDetection() + new_tab.action_runner.MeasureMemory() + new_tab.Close() + + def _WaitForPageLoadToComplete(self, action_runner): + py_utils.WaitFor(action_runner.tab.HasReachedQuiescence, timeout=30) + + +# Some websites have a script that loads resources continuously, in which cases +# HasReachedQuiescence would not be reached. This class waits for document ready +# state to be complete to avoid timeout for those pages. +class ResourceLoadingLeakDetectionPage(LeakDetectionPage): + def _WaitForPageLoadToComplete(self, action_runner): + action_runner.tab.WaitForDocumentReadyStateToBeComplete() + + +class LeakDetectionStorySet(story_module.StorySet): + def __init__(self): + super(LeakDetectionStorySet, self).__init__( + archive_data_file='data/leak_detection.json', + cloud_storage_bucket=story_module.PARTNER_BUCKET) + urls_list = [ + # Alexa top websites + 'https://www.google.com', + 'https://www.youtube.com', + 'https://www.facebook.com', + 'https://www.baidu.com', + 'https://www.wikipedia.org', + 'http://www.qq.com', + 'http://www.amazon.com', + 'http://www.twitter.com', + # websites which were found to be leaking in the past + 'https://www.prezi.com', + 'http://www.time.com', + 'http://www.cheapoair.com', + 'http://www.onlinedown.net', + 'http://www.dailypost.ng', + 'http://www.aljazeera.net', + ] + resource_loading_urls_list = [ + 'https://www.yahoo.com', + 'http://www.quora.com', + 'https://www.macys.com', + 'https://www.reddit.com', + 'http://infomoney.com.br', + 'http://www.listindiario.com', + ] + for url in urls_list: + self.AddStory(LeakDetectionPage(url, self, url)) + for url in resource_loading_urls_list: + self.AddStory(ResourceLoadingLeakDetectionPage(url, self, url))
diff --git a/tools/perf/contrib/memory_extras/memory_extras.py b/tools/perf/contrib/memory_extras/memory_extras.py index abc74b5..f46092f 100644 --- a/tools/perf/contrib/memory_extras/memory_extras.py +++ b/tools/perf/contrib/memory_extras/memory_extras.py
@@ -6,7 +6,6 @@ import page_sets from telemetry import benchmark -from telemetry import story # pylint: disable=protected-access @@ -29,16 +28,11 @@ return page_sets.DualBrowserStorySet() @classmethod - def ValueCanBeAddedPredicate(cls, value, is_first_result): + def ShouldAddValue(cls, name, from_first_story_run): + del from_first_story_run # unused # TODO(crbug.com/610962): Remove this stopgap when the perf dashboard # is able to cope with the data load generated by TBMv2 metrics. - return not memory._IGNORED_STATS_RE.search(value.name) - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations() + return not memory._IGNORED_STATS_RE.search(name) @benchmark.Owner(emails=['perezju@chromium.org']) @@ -59,16 +53,11 @@ return page_sets.DualBrowserStorySet(long_running=True) @classmethod - def ValueCanBeAddedPredicate(cls, value, is_first_result): + def ShouldAddValue(cls, name, from_first_story_run): + del from_first_story_run # unused # TODO(crbug.com/610962): Remove this stopgap when the perf dashboard # is able to cope with the data load generated by TBMv2 metrics. - return not memory._IGNORED_STATS_RE.search(value.name) - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations() + return not memory._IGNORED_STATS_RE.search(name) @benchmark.Owner(emails=['etienneb@chromium.org']) @@ -102,13 +91,8 @@ return 'memory.long_running_desktop_sites' @classmethod - def ValueCanBeAddedPredicate(cls, value, is_first_result): + def ShouldAddValue(cls, name, from_first_story_run): + del from_first_story_run # unused # TODO(crbug.com/610962): Remove this stopgap when the perf dashboard # is able to cope with the data load generated by TBMv2 metrics. - return not memory._IGNORED_STATS_RE.search(value.name) - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations() + return not memory._IGNORED_STATS_RE.search(name)
diff --git a/tools/perf/contrib/network_service/OWNERS b/tools/perf/contrib/network_service/OWNERS index 716b2b1..28361a0 100644 --- a/tools/perf/contrib/network_service/OWNERS +++ b/tools/perf/contrib/network_service/OWNERS
@@ -1 +1 @@ -file://content/network/OWNERS +file://services/network/OWNERS
diff --git a/tools/perf/contrib/oilpan/oilpan_benchmarks.py b/tools/perf/contrib/oilpan/oilpan_benchmarks.py index bed8b9a..4b7609b4 100644 --- a/tools/perf/contrib/oilpan/oilpan_benchmarks.py +++ b/tools/perf/contrib/oilpan/oilpan_benchmarks.py
@@ -29,12 +29,6 @@ path = os.path.join(blink_perf.BLINK_PERF_BASE_DIR, 'BlinkGC') return blink_perf.CreateStorySetFromPath(path, blink_perf.SKIPPED_FILE) - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # No tests disabled. - return StoryExpectations() - @benchmark.Owner(emails=['peria@chromium.org']) class OilpanGCTimesSmoothnessAnimation(perf_benchmark.PerfBenchmark): @@ -45,12 +39,6 @@ def Name(cls): return 'oilpan_gc_times.tough_animation_cases' - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # Nothing disabled. - return StoryExpectations() - class OilpanGCTimesKeySilkCases(perf_benchmark.PerfBenchmark): test = oilpan_gc_times.OilpanGCTimesForSmoothness @@ -61,17 +49,6 @@ def Name(cls): return 'oilpan_gc_times.key_silk_cases' - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableStory('https://polymer-topeka.appspot.com/', - [story.expectations.ALL], 'crbug.com/507865') - self.DisableStory('http://plus.google.com/app/basic/stream', - [story.expectations.ALL], 'crbug.com/338838') - self.DisableStory('inbox_app.html?slide_drawer', - [story.expectations.ALL], 'crbug.com/446332') - return StoryExpectations() - class OilpanGCTimesSyncScrollKeyMobileSites(perf_benchmark.PerfBenchmark): tag = 'sync_scroll' @@ -85,12 +62,3 @@ @classmethod def Name(cls): return 'oilpan_gc_times.sync_scroll.key_mobile_sites_smooth' - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableStory( - 'http://digg.com', - [story.expectations.ALL], - 'crbug.com/756119') - return StoryExpectations()
diff --git a/tools/perf/contrib/oilpan/oilpan_gc_times.py b/tools/perf/contrib/oilpan/oilpan_gc_times.py index 228aae9..1f345f8d 100644 --- a/tools/perf/contrib/oilpan/oilpan_gc_times.py +++ b/tools/perf/contrib/oilpan/oilpan_gc_times.py
@@ -146,7 +146,7 @@ def ValidateAndMeasurePage(self, page, tab, results): del page # unused - timeline_data = tab.browser.platform.tracing_controller.StopTracing() + timeline_data = tab.browser.platform.tracing_controller.StopTracing()[0] timeline_model = TimelineModel(timeline_data) threads = timeline_model.GetAllThreads() for thread in threads:
diff --git a/tools/perf/contrib/oop_raster/OWNERS b/tools/perf/contrib/oop_raster/OWNERS new file mode 100644 index 0000000..2fd2c35 --- /dev/null +++ b/tools/perf/contrib/oop_raster/OWNERS
@@ -0,0 +1,3 @@ +enne@chromium.org +khushal@chromium.org +vmpstr@chromium.org
diff --git a/tools/perf/contrib/oop_raster/__init__.py b/tools/perf/contrib/oop_raster/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tools/perf/contrib/oop_raster/__init__.py
diff --git a/tools/perf/contrib/oop_raster/oop_raster.py b/tools/perf/contrib/oop_raster/oop_raster.py new file mode 100644 index 0000000..6ae3ed2 --- /dev/null +++ b/tools/perf/contrib/oop_raster/oop_raster.py
@@ -0,0 +1,45 @@ +# Copyright 2018 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. +from benchmarks import smoothness,thread_times +import page_sets +from telemetry import benchmark + +# pylint: disable=protected-access + +def CustomizeBrowserOptionsForOopRasterization(options): + """Enables flags needed for out of process rasterization.""" + options.AppendExtraBrowserArgs('--force-gpu-rasterization') + options.AppendExtraBrowserArgs('--enable-oop-rasterization') + + +@benchmark.Owner(emails=['enne@chromium.org']) +class SmoothnessOopRasterizationTop25(smoothness._Smoothness): + """Measures rendering statistics for the top 25 with oop rasterization. + """ + tag = 'oop_rasterization' + page_set = page_sets.Top25SmoothPageSet + + def SetExtraBrowserOptions(self, options): + CustomizeBrowserOptionsForOopRasterization(options) + + @classmethod + def Name(cls): + return 'smoothness.oop_rasterization.top_25_smooth' + + +@benchmark.Owner(emails=['enne@chromium.org']) +class ThreadTimesOopRasterKeyMobile(thread_times._ThreadTimes): + """Measure timeline metrics for key mobile pages while using out of process + raster.""" + tag = 'oop_rasterization' + page_set = page_sets.KeyMobileSitesSmoothPageSet + options = {'story_tag_filter': 'fastpath'} + + def SetExtraBrowserOptions(self, options): + super(ThreadTimesOopRasterKeyMobile, self).SetExtraBrowserOptions(options) + CustomizeBrowserOptionsForOopRasterization(options) + + @classmethod + def Name(cls): + return 'thread_times.oop_rasterization.key_mobile'
diff --git a/tools/perf/contrib/tracing/tracing.py b/tools/perf/contrib/tracing/tracing.py index a5adcb2e..75d2dbe 100644 --- a/tools/perf/contrib/tracing/tracing.py +++ b/tools/perf/contrib/tracing/tracing.py
@@ -4,7 +4,6 @@ from core import perf_benchmark -from telemetry import story from telemetry.web_perf import timeline_based_measurement import page_sets @@ -23,9 +22,3 @@ @classmethod def Name(cls): return 'tracing.tracing_with_debug_overhead' - - def GetExpectations(self): - class StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass # No tests disabled. - return StoryExpectations()
diff --git a/tools/perf/contrib/vr_benchmarks/BUILD.gn b/tools/perf/contrib/vr_benchmarks/BUILD.gn index 029bbe6..2170e86 100644 --- a/tools/perf/contrib/vr_benchmarks/BUILD.gn +++ b/tools/perf/contrib/vr_benchmarks/BUILD.gn
@@ -7,14 +7,17 @@ group("vr_perf_tests") { testonly = true data = [ + "./data/", "./__init__.py", "./shared_android_vr_page_state.py", "./vr_benchmarks.py", "./vr_browsing_mode_pages.py", "./vr_sample_page.py", "./webvr_sample_pages.py", + "./webvr_wpr_pages.py", "//chrome/android/shared_preference_files/test/", "//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk", + "//third_party/gvr-android-sdk/test-apks/vr_keyboard/vr_keyboard_current.apk", "//chrome/test/data/vr/webvr_info/samples/", # Necessary for running on bots
diff --git a/tools/perf/contrib/vr_benchmarks/OWNERS b/tools/perf/contrib/vr_benchmarks/OWNERS index a552bdf..2035467 100644 --- a/tools/perf/contrib/vr_benchmarks/OWNERS +++ b/tools/perf/contrib/vr_benchmarks/OWNERS
@@ -1,5 +1,5 @@ -nednguyen@chromium.org +bsheedy@chromium.org +tiborg@chromium.org # These users are familiar with the code, but not actually committers -bsheedy@chromium.org leilei@chromium.org
diff --git a/tools/perf/contrib/vr_benchmarks/data/.gitignore b/tools/perf/contrib/vr_benchmarks/data/.gitignore new file mode 100644 index 0000000..72ba1409 --- /dev/null +++ b/tools/perf/contrib/vr_benchmarks/data/.gitignore
@@ -0,0 +1,7 @@ +*.wpr +*.wprgo + +# Generated fetched binary's timestamp +# See details in py_utils.cloud_storage.GetIfChanged(file_path, bucket) method. +*.fetchts +
diff --git a/tools/perf/contrib/vr_benchmarks/data/webvr_wpr.json b/tools/perf/contrib/vr_benchmarks/data/webvr_wpr.json new file mode 100644 index 0000000..0bc07be --- /dev/null +++ b/tools/perf/contrib/vr_benchmarks/data/webvr_wpr.json
@@ -0,0 +1,21 @@ +{ + "archives": { + "dance_tonite": { + "DEFAULT": "webvr_wpr_000.wprgo" + }, + "mass_migrations": { + "DEFAULT": "webvr_wpr_000.wprgo" + }, + "sketchfab_pirates_dock": { + "DEFAULT": "webvr_wpr_000.wprgo" + }, + "under_neon_lights": { + "DEFAULT": "webvr_wpr_000.wprgo" + }, + "within_invasion_ep_1": { + "DEFAULT": "webvr_wpr_000.wprgo" + } + }, + "description": "Describes the Web Page Replay archives for a story set. Don't edit by hand! Use record_wpr for updating.", + "platform_specific": true +} \ No newline at end of file
diff --git a/tools/perf/contrib/vr_benchmarks/data/webvr_wpr_000.wprgo.sha1 b/tools/perf/contrib/vr_benchmarks/data/webvr_wpr_000.wprgo.sha1 new file mode 100644 index 0000000..f0e52657 --- /dev/null +++ b/tools/perf/contrib/vr_benchmarks/data/webvr_wpr_000.wprgo.sha1
@@ -0,0 +1 @@ +72ed936e30184a7338556e4817243ecd1ec924d0 \ No newline at end of file
diff --git a/tools/perf/contrib/vr_benchmarks/shared_android_vr_page_state.py b/tools/perf/contrib/vr_benchmarks/shared_android_vr_page_state.py index 5d42d95..c62a525b 100644 --- a/tools/perf/contrib/vr_benchmarks/shared_android_vr_page_state.py +++ b/tools/perf/contrib/vr_benchmarks/shared_android_vr_page_state.py
@@ -5,26 +5,29 @@ import os from core import path_util path_util.AddAndroidPylibToPath() -from page_sets import android_screen_restoration_shared_state as screen_state from pylib.utils import shared_preference_utils from telemetry.core import android_platform from telemetry.core import platform from telemetry.core import util from telemetry.internal.platform import android_device +from telemetry.page import shared_page_state -class SharedAndroidVrPageState( - screen_state.AndroidScreenRestorationSharedState): +CARDBOARD_PATH = os.path.join('chrome', 'android', 'shared_preference_files', + 'test', 'vr_cardboard_skipdon_setupcomplete.json') + + +class SharedAndroidVrPageState(shared_page_state.SharedPageState): """SharedPageState for VR Telemetry tests. - Performs the same functionality as SharedPageState, but with two main + Performs the same functionality as SharedPageState, but with three main differences: 1. It is currently restricted to Android 2. It performs VR-specific setup such as installing and configuring additional APKs that are necessary for testing - - Also ensures that the screen is on before the test starts by inheriting from - AndroidScreenRestorationSharedState. + 3. It cycles the screen off then on before each story, similar to how + AndroidScreenRestorationSharedState ensures that the screen is on. See + _CycleScreen() for an explanation on the reasoning behind this. """ def __init__(self, test, finder_options, story_set): # TODO(bsheedy): See about making this a cross-platform SharedVrPageState - @@ -43,8 +46,10 @@ def _PerformAndroidVrSetup(self): self._InstallVrCore() - self._ConfigureVrCore() + self._ConfigureVrCore(os.path.join(path_util.GetChromiumSrcDir(), + self._finder_options.shared_prefs_file)) self._InstallNfcApk() + self._InstallKeyboardApk() def _InstallVrCore(self): """Installs the VrCore APK.""" @@ -55,11 +60,9 @@ 'gvr-android-sdk', 'test-apks', 'vr_services', 'vr_services_current.apk')) - def _ConfigureVrCore(self): - """Configures VrCore using the settings file passed to the benchmark.""" - settings = shared_preference_utils.ExtractSettingsFromJson( - os.path.join(path_util.GetChromiumSrcDir(), - self._finder_options.shared_prefs_file)) + def _ConfigureVrCore(self, filepath): + """Configures VrCore using the provided settings file.""" + settings = shared_preference_utils.ExtractSettingsFromJson(filepath) for setting in settings: shared_pref = self._platform.GetSharedPrefs(setting['package'], setting['filename']) @@ -84,6 +87,45 @@ self._platform.InstallApplication( os.path.join(chromium_root, newest_apk_path)) + def _InstallKeyboardApk(self): + """Installs the VR Keyboard APK.""" + self._platform.InstallApplication( + os.path.join(path_util.GetChromiumSrcDir(), 'third_party', + 'gvr-android-sdk', 'test-apks', 'vr_keyboard', + 'vr_keyboard_current.apk')) + + def WillRunStory(self, page): + super(SharedAndroidVrPageState, self).WillRunStory(page) + if not self._finder_options.disable_screen_reset: + self._CycleScreen() + + def TearDownState(self): + super(SharedAndroidVrPageState, self).TearDownState() + # Re-apply Cardboard as the viewer to leave the device in a consistent + # state after a benchmark run + # TODO(bsheedy): Remove this after crbug.com/772969 is fixed + self._ConfigureVrCore(os.path.join(path_util.GetChromiumSrcDir(), + CARDBOARD_PATH)) + + def _CycleScreen(self): + """Cycles the screen off then on. + + This is because VR test devices are set to have normal screen brightness and + automatically turn off after several minutes instead of the usual approach + of having the screen always on at minimum brightness. This is due to the + motion-to-photon latency test being sensitive to screen brightness, and min + brightness does not work well for it. + + Simply using TurnScreenOn does not actually reset the timer for turning off + the screen, so instead cycle the screen to refresh it periodically. + """ + self.platform.android_action_runner.TurnScreenOff() + self.platform.android_action_runner.TurnScreenOn() + @property def platform(self): return self._platform + + @property + def recording_wpr(self): + return self._finder_options.recording_wpr
diff --git a/tools/perf/contrib/vr_benchmarks/vr_benchmarks.py b/tools/perf/contrib/vr_benchmarks/vr_benchmarks.py index 72ad463d4..3da8494 100644 --- a/tools/perf/contrib/vr_benchmarks/vr_benchmarks.py +++ b/tools/perf/contrib/vr_benchmarks/vr_benchmarks.py
@@ -5,10 +5,12 @@ from benchmarks import memory from core import perf_benchmark from telemetry import benchmark +from telemetry import story from telemetry.timeline import chrome_trace_category_filter from telemetry.timeline import chrome_trace_config from telemetry.web_perf import timeline_based_measurement from contrib.vr_benchmarks import webvr_sample_pages +from contrib.vr_benchmarks import webvr_wpr_pages from contrib.vr_benchmarks import vr_browsing_mode_pages @@ -23,17 +25,35 @@ 'preference files to edit and how to do so. ' 'See examples in //chrome/android/' 'shared_preference_files/test/') + parser.add_option( + '--disable-screen-reset', + action='store_true', + default=False, + help='Disables turning screen off and on after each story. ' + 'This is useful for local testing when turning off the ' + 'screen leads to locking the phone, which makes Telemetry ' + 'not produce valid results.') + parser.add_option( + '--recording-wpr', + action='store_true', + default=False, + help='Modifies benchmark behavior slightly while recording WPR files ' + 'for it. This largely boils down to adding waits/sleeps in order ' + 'to ensure that enough streaming data is recorded for the ' + 'benchmark to run without issues.') -@benchmark.Owner(emails=['bsheedy@chromium.org', 'leilei@chromium.org']) -class XrWebVrStatic(_BaseVRBenchmark): - """Measures WebVR performance with sample pages.""" +class _BaseWebVRBenchmark(_BaseVRBenchmark): + + SUPPORTED_PLATFORMS = [story.expectations.ALL_ANDROID] def CreateCoreTimelineBasedMeasurementOptions(self): memory_categories = ['blink.console', 'disabled-by-default-memory-infra'] gpu_categories = ['gpu'] + debug_categories = ['toplevel', 'viz'] category_filter = chrome_trace_category_filter.ChromeTraceCategoryFilter( - ','.join(['-*'] + memory_categories + gpu_categories)) + ','.join(['-*'] + memory_categories + gpu_categories + + debug_categories)) options = timeline_based_measurement.Options(category_filter) options.config.enable_android_graphics_memtrack = True options.config.enable_platform_display_trace = True @@ -43,9 +63,6 @@ chrome_trace_config.MemoryDumpConfig()) return options - def CreateStorySet(self, options): - return webvr_sample_pages.WebVrSamplePageSet() - def SetExtraBrowserOptions(self, options): memory.SetExtraBrowserOptionsForMemoryMeasurement(options) options.AppendExtraBrowserArgs([ @@ -53,25 +70,55 @@ ]) @classmethod + def ShouldAddValue(cls, name, from_first_story_run): + del from_first_story_run # unused + return memory.DefaultShouldAddValueForMemoryMeasurement(name) + + +@benchmark.Owner(emails=['bsheedy@chromium.org', 'leilei@chromium.org']) +class XrWebVrStatic(_BaseWebVRBenchmark): + """Measures WebVR performance with synthetic sample pages.""" + + def CreateStorySet(self, options): + return webvr_sample_pages.WebVrSamplePageSet() + + @classmethod def Name(cls): return 'xr.webvr.static' + +@benchmark.Owner(emails=['bsheedy@chromium.org', 'tiborg@chromium.org']) +class XrWebVrWprStatic(_BaseWebVRBenchmark): + """Measures WebVR performance with WPR copies of live websites.""" + + def CreateStorySet(self, options): + return webvr_wpr_pages.WebVrWprPageSet() + @classmethod - def ValueCanBeAddedPredicate(cls, value, is_first_result): - return memory.DefaultValueCanBeAddedPredicateForMemoryMeasurement(value) + def Name(cls): + return 'xr.webvr.wpr.static' @benchmark.Owner(emails=['tiborg@chromium.org']) class XrBrowsingStatic(_BaseVRBenchmark): """Benchmark for testing the VR performance in VR Browsing Mode.""" + SUPPORTED_PLATFORMS = [story.expectations.ALL_ANDROID] + def CreateTimelineBasedMeasurementOptions(self): - custom_categories = ['gpu'] + memory_categories = ['blink.console', 'disabled-by-default-memory-infra'] + gpu_categories = ['gpu'] + debug_categories = ['toplevel', 'viz'] category_filter = chrome_trace_category_filter.ChromeTraceCategoryFilter( - ','.join(custom_categories)) + ','.join(['-*'] + memory_categories + gpu_categories + + debug_categories)) options = timeline_based_measurement.Options(category_filter) + options.config.enable_android_graphics_memtrack = True options.config.enable_platform_display_trace = True - options.SetTimelineBasedMetrics(['frameCycleDurationMetric']) + options.SetTimelineBasedMetrics(['frameCycleDurationMetric', + 'memoryMetric']) + options.config.chrome_trace_config.SetMemoryDumpConfig( + chrome_trace_config.MemoryDumpConfig()) return options def CreateStorySet(self, options):
diff --git a/tools/perf/contrib/vr_benchmarks/vr_browsing_mode_pages.py b/tools/perf/contrib/vr_benchmarks/vr_browsing_mode_pages.py index 2c63a91..0c76f38 100644 --- a/tools/perf/contrib/vr_benchmarks/vr_browsing_mode_pages.py +++ b/tools/perf/contrib/vr_benchmarks/vr_browsing_mode_pages.py
@@ -34,8 +34,10 @@ # Browsing Mode. Wait times are flaky. action_runner.Wait(2) - with action_runner.CreateInteraction('Still'): - action_runner.Wait(5) + # MeasureMemory() waits for 10 seconds before measuring memory, which is + # long enough for us to collect our other data, so no additional sleeps + # necessary. + action_runner.MeasureMemory(True) class VrBrowsingModePageSet(story.StorySet):
diff --git a/tools/perf/contrib/vr_benchmarks/vr_sample_page.py b/tools/perf/contrib/vr_benchmarks/vr_sample_page.py index ef55b34..2f0c2e4a 100644 --- a/tools/perf/contrib/vr_benchmarks/vr_sample_page.py +++ b/tools/perf/contrib/vr_benchmarks/vr_sample_page.py
@@ -15,16 +15,18 @@ class VrSamplePage(page.Page): """Superclass for all VR sample pages.""" - def __init__(self, sample_page, page_set, get_parameters=None): + def __init__(self, sample_page, page_set, url_parameters=None, + extra_browser_args=None): url = '%s.html' % sample_page - if get_parameters is not None: - url += '?' + '&'.join(get_parameters) + if url_parameters is not None: + url += '?' + '&'.join(url_parameters) name = url.replace('.html', '') url = 'file://' + os.path.join(SAMPLE_DIR, url) super(VrSamplePage, self).__init__( url=url, page_set=page_set, name=name, + extra_browser_args=extra_browser_args, shared_page_state_class=vr_state.SharedAndroidVrPageState) self._shared_page_state = None
diff --git a/tools/perf/contrib/vr_benchmarks/webvr_sample_pages.py b/tools/perf/contrib/vr_benchmarks/webvr_sample_pages.py index e2ab450..a6950389 100644 --- a/tools/perf/contrib/vr_benchmarks/webvr_sample_pages.py +++ b/tools/perf/contrib/vr_benchmarks/webvr_sample_pages.py
@@ -8,15 +8,21 @@ class WebVrSamplePage(VrSamplePage): - def __init__(self, page_set, get_parameters): + def __init__(self, page_set, url_parameters, sample_page, + extra_browser_args=None,): super(WebVrSamplePage, self).__init__( - sample_page='test-slow-render', + sample_page=sample_page, page_set=page_set, - get_parameters=get_parameters) + url_parameters=url_parameters, + extra_browser_args=extra_browser_args) def RunPageInteractions(self, action_runner): action_runner.TapElement(selector='canvas[id="webgl-canvas"]') action_runner.MeasureMemory(True) + # We don't want to be in VR or on a page with a WebGL canvas at the end of + # the test, as this generates unnecessary heat while the trace data is being + # processed, so navigate to a blank page. + action_runner.Navigate("about:blank") class WebVrSamplePageSet(story.StorySet): @@ -25,33 +31,36 @@ def __init__(self): super(WebVrSamplePageSet, self).__init__() - # Standard sample app with no changes - self.AddStory( - WebVrSamplePage(self, [ - 'canvasClickPresents=1', - 'renderScale=1', - ])) - # Increased render scale - self.AddStory( - WebVrSamplePage(self, [ - 'canvasClickPresents=1', - 'renderScale=1.5', - ])) - # Default render scale, increased load - self.AddStory( - WebVrSamplePage(self, [ - 'canvasClickPresents=1', - 'renderScale=1', - 'heavyGpu=1', - 'cubeScale=0.2', - 'workTime=5', - ])) - # Further increased load - self.AddStory( - WebVrSamplePage(self, [ - 'canvasClickPresents=1', - 'renderScale=1', - 'heavyGpu=1', - 'cubeScale=0.3', - 'workTime=10', - ])) + # Test cases that use the synthetic cube field page + cube_test_cases = [ + # Standard sample app with no changes + ['canvasClickPresents=1', 'renderScale=1'], + # Increased render scale + ['canvasClickPresents=1', 'renderScale=1.5'], + # Default render scale, increased load + ['canvasClickPresents=1', 'renderScale=1', 'heavyGpu=1', 'cubeScale=0.2', + 'workTime=5'], + # Further increased load + ['canvasClickPresents=1', 'renderScale=1', 'heavyGpu=1', 'cubeScale=0.3', + 'workTime=10'], + # Absurd load for fill-rate testing + ['canvasClickPresents=1', 'renderScale=1.6', 'heavyGpu=1', + 'cubeScale=0.3', 'workTime=4'], + ] + + for url_parameters in cube_test_cases: + # Standard set of pages with defaults + self.AddStory(WebVrSamplePage(self, url_parameters, 'test-slow-render')) + # Set of pages with standardized render size and VSync alignment disabled + self.AddStory(WebVrSamplePage(self, url_parameters + ['standardSize=1'], + 'test-slow-render', + extra_browser_args=['--disable-features=WebVrVsyncAlign'])) + + # Test cases that use the 360 video page + video_test_cases = [ + # Test using the default, low resolution video + ['canvasClickPresents=1'], + ] + + for url_parameters in video_test_cases: + self.AddStory(WebVrSamplePage(self, url_parameters, 'XX-360-video'))
diff --git a/tools/perf/contrib/vr_benchmarks/webvr_wpr_pages.py b/tools/perf/contrib/vr_benchmarks/webvr_wpr_pages.py new file mode 100644 index 0000000..95911b0 --- /dev/null +++ b/tools/perf/contrib/vr_benchmarks/webvr_wpr_pages.py
@@ -0,0 +1,141 @@ +# Copyright 2018 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. + +from telemetry import story +from telemetry import page +from contrib.vr_benchmarks import (shared_android_vr_page_state as vr_state) + +class WebVrWprPage(page.Page): + """Class for running a story on a WebVR WPR page.""" + def __init__(self, page_set, url, name, interaction_function, + extra_browser_args=None): + """ + Args: + page_set: The StorySet the WebVrWprPage is being added to + url: The URL to navigate to for the story + name: The name of the story + interaction_function: A pointer to a function that takes an ActionRunner + and boolean indicating whether a WPR archive is being recorded. Meant + to handle webpage-specific VR entry + extra_browser_args: Extra browser args that are simply forwarded to + page.Page + """ + super(WebVrWprPage, self).__init__( + url=url, + page_set=page_set, + name=name, + extra_browser_args=extra_browser_args, + shared_page_state_class=vr_state.SharedAndroidVrPageState) + self._shared_page_state = None + self._interaction_function = interaction_function + + def RunPageInteractions(self, action_runner): + if self._interaction_function: + self._interaction_function(action_runner, self.recording_wpr) + + action_runner.MeasureMemory(True) + action_runner.Navigate("about:blank") + + def Run(self, shared_state): + self._shared_page_state = shared_state + super(WebVrWprPage, self).Run(shared_state) + + @property + def platform(self): + return self._shared_page_state.platform + + @property + def recording_wpr(self): + return self._shared_page_state.recording_wpr + + +class WebVrWprPageSet(story.StorySet): + """A page set using live WebVR sites recorded using WPR.""" + + def __init__(self): + super(WebVrWprPageSet, self).__init__( + archive_data_file='data/webvr_wpr.json', + cloud_storage_bucket=story.PARTNER_BUCKET) + + # View the Pirates: Dock model on Sketchfab + def SketchfabInteraction(action_runner, _): + action_runner.WaitForNetworkQuiescence() + action_runner.WaitForElement(selector='a[data-tooltip="View in VR"]') + action_runner.TapElement(selector='a[data-tooltip="View in VR"]') + self.AddStory(WebVrWprPage( + self, + 'https://sketchfab.com/models/uFqGJrS9ZjVr9Myk9kg4fubPNPz', + 'sketchfab_pirates_dock', + SketchfabInteraction)) + + # Watch part of the Invasion Episode 1 video on With.in + def WithinInvasionInteraction(action_runner, recording_wpr): + action_runner.WaitForNetworkQuiescence() + action_runner.TapElement(selector='div.play-button') + action_runner.TapElement(selector='div.right.stereo') + # Make sure we get enough streaming video during WPR recording to not run + # into issues when actually running the benchmark + if recording_wpr: + action_runner.Wait(30) + self.AddStory(WebVrWprPage( + self, + # Access the video directly to more easily set resolution and avoid + # iframe weirdness + 'https://player.with.in/embed/?id=272&resolution=2880&forced=false&' + 'autoplay=true&t=0&internal=true', + 'within_invasion_ep_1', + WithinInvasionInteraction)) + + # Look at "randomly" generated (constant seed) geometry in Mass Migrations + def MassMigrationsInteraction(action_runner, _): + action_runner.WaitForNetworkQuiescence() + # All DOM elements seem to be present on the page from the start, so + # instead wait until the button is actually visible + action_runner.WaitForJavaScriptCondition( + condition='document.querySelector(\'div[id="footer"]\').style.display' + '== "block"') + action_runner.TapElement(selector='a[id="vr"]') + self.AddStory(WebVrWprPage( + self, + # The /iaped is necessary to keep the geometry constant, as it acts as + # the seed for the generator - just visiting the site randomly generates + # geometry + 'https://massmigrations.com/iaped', + 'mass_migrations', + MassMigrationsInteraction)) + + # Watch a girl running through a giant forest (I think) in Under Neon Lights + # Note that this is semi-broken in that it doesn't move away from the + # opening when you enter VR, but we're still viewing a relatively complex + # WebGL scene, so it's still useful for perf testing + def UnderNeonLightsInteraction(action_runner, _): + action_runner.WaitForNetworkQuiescence() + # The VR button doesn't have any unique ID or anything, so instead select + # based on the unique text in a child div + action_runner.WaitForElement(text='Start in VR') + action_runner.TapElement(text='Start in VR') + self.AddStory(WebVrWprPage( + self, + # Access the content directly to avoid iframe weirdness + 'https://player.with.in/embed/?id=541&resolution=1920&forced=false&' + 'autoplay=true&t=0&internal=true', + 'under_neon_lights', + UnderNeonLightsInteraction)) + + # Watch dancing polyhedrons in Dance Tonite + def DanceToniteInteraction(action_runner, _): + action_runner.WaitForNetworkQuiescence() + action_runner.WaitForElement(selector='div.button-play') + action_runner.TapElement(selector='div.button-play') + action_runner.WaitForNetworkQuiescence() + # The VR entry button has no unique text, ID, etc. but does have a child + # SVG with a child path with a unique "d" attribute. It's super long, so + # only match against one part of it + action_runner.WaitForElement(selector='path[d~="M52.6"]') + action_runner.TapElement(selector='path[d~="M52.6"]') + self.AddStory(WebVrWprPage( + self, + 'https://tonite.dance', + 'dance_tonite', + DanceToniteInteraction))
diff --git a/tools/perf/core/benchmark_android_bot_map.json b/tools/perf/core/benchmark_android_bot_map.json new file mode 100644 index 0000000..88fc3ac --- /dev/null +++ b/tools/perf/core/benchmark_android_bot_map.json
@@ -0,0 +1,184 @@ +{ + "0": { + "benchmarks": [ + "system_health.memory_desktop", + "system_health.memory_mobile" + ] + }, + "1": { + "benchmarks": [ + "loading.desktop", + "smoothness.key_silk_cases", + "smoothness.simple_mobile_sites" + ] + }, + "2": { + "benchmarks": [ + "blink_perf.image_decoder", + "blink_perf.owp_storage", + "wasm" + ] + }, + "3": { + "benchmarks": [ + "speedometer-future", + "speedometer2-future", + "v8.browsing_desktop-future", + "v8.browsing_mobile-future" + ] + }, + "4": { + "benchmarks": [ + "system_health.common_desktop", + "v8.browsing_mobile" + ] + }, + "5": { + "benchmarks": [ + "dromaeo.domcoretraverse", + "memory.desktop", + "power.typical_10_mobile", + "smoothness.tough_animation_cases", + "thread_times.key_mobile_sites_smooth", + "webrtc" + ] + }, + "6": { + "benchmarks": [ + "blink_perf.shadow_dom", + "dromaeo.domcorequery", + "power.idle_platform", + "smoothness.gpu_rasterization_and_decoding.image_decoding_cases" + ] + }, + "7": { + "benchmarks": [ + "battor.trivial_pages", + "media.desktop", + "octane", + "smoothness.gpu_rasterization.tough_scrolling_cases", + "smoothness.tough_filters_cases", + "thread_times.key_hit_test_cases", + "thread_times.key_idle_power_cases", + "v8.runtimestats.browsing_mobile" + ] + }, + "8": { + "benchmarks": [ + "dummy_benchmark.histogram_benchmark_1", + "dummy_benchmark.noisy_benchmark_1", + "jetstream", + "smoothness.tough_texture_upload_cases", + "speedometer", + "speedometer2" + ] + }, + "9": { + "benchmarks": [ + "memory.top_10_mobile", + "smoothness.gpu_rasterization.tough_filters_cases", + "smoothness.image_decoding_cases", + "smoothness.pathological_mobile_sites", + "smoothness.tough_pinch_zoom_cases", + "v8.detached_context_age_in_gc" + ] + }, + "10": { + "benchmarks": [ + "blink_perf.bindings", + "blink_perf.canvas", + "rasterize_and_record_micro.partial_invalidation", + "smoothness.gpu_rasterization.polymer", + "start_with_url.cold.startup_pages", + "system_health.webview_startup" + ] + }, + "11": { + "benchmarks": [ + "blink_perf.layout", + "dromaeo", + "dromaeo.domcoreattr", + "oortonline_tbmv2", + "smoothness.maps", + "smoothness.tough_webgl_cases", + "thread_times.simple_mobile_sites" + ] + }, + "12": { + "benchmarks": [ + "battor.steady_state", + "blink_perf.svg", + "memory.long_running_idle_gmail_background_tbmv2", + "smoothness.gpu_rasterization.top_25_smooth", + "smoothness.gpu_rasterization.tough_path_rendering_cases", + "thread_times.key_noop_cases" + ] + }, + "13": { + "benchmarks": [ + "memory.long_running_idle_gmail_tbmv2", + "system_health.common_mobile" + ] + }, + "14": { + "benchmarks": [ + "loading.mobile", + "media.mobile", + "smoothness.tough_webgl_ad_cases", + "tab_switching.typical_25", + "v8.browsing_desktop" + ] + }, + "15": { + "benchmarks": [ + "blink_perf.events", + "dummy_benchmark.stable_benchmark_1", + "smoothness.top_25_smooth", + "smoothness.tough_ad_cases" + ] + }, + "16": { + "benchmarks": [ + "dromaeo.domcoremodify", + "smoothness.key_desktop_move_cases", + "smoothness.sync_scroll.key_mobile_sites_smooth", + "thread_times.tough_compositor_cases", + "thread_times.tough_scrolling_cases" + ] + }, + "17": { + "benchmarks": [ + "blink_perf.dom", + "rasterize_and_record_micro.top_25", + "smoothness.tough_canvas_cases", + "thread_times.key_silk_cases" + ] + }, + "18": { + "benchmarks": [ + "blink_perf.css", + "blink_perf.parser", + "scheduler.tough_scheduling_cases", + "smoothness.gpu_rasterization.tough_pinch_zoom_cases", + "smoothness.tough_image_decode_cases", + "start_with_url.warm.startup_pages" + ] + }, + "19": { + "benchmarks": [ + "blink_perf.paint", + "kraken", + "smoothness.key_mobile_sites_smooth", + "tracing.tracing_with_background_memory_infra" + ] + }, + "20": { + "benchmarks": [ + "smoothness.desktop_tough_pinch_zoom_cases", + "smoothness.tough_path_rendering_cases", + "smoothness.tough_scrolling_cases", + "v8.runtime_stats.top_25", + "v8.runtimestats.browsing_desktop" + ] + } +}
diff --git a/tools/perf/core/benchmark_bot_map.json b/tools/perf/core/benchmark_bot_map.json new file mode 100644 index 0000000..de7654e --- /dev/null +++ b/tools/perf/core/benchmark_bot_map.json
@@ -0,0 +1,12 @@ +{ + "0": { + "benchmarks": [ + "dummy_benchmark.stable_benchmark_1" + ] + }, + "1": { + "benchmarks": [ + "dummy_benchmark.histogram_benchmark_1" + ] + } +}
diff --git a/tools/perf/core/benchmark_desktop_bot_map.json b/tools/perf/core/benchmark_desktop_bot_map.json new file mode 100644 index 0000000..86e19ea --- /dev/null +++ b/tools/perf/core/benchmark_desktop_bot_map.json
@@ -0,0 +1,120 @@ +{ + "0": { + "benchmarks": [ + "blink_perf.dom", + "blink_perf.paint", + "dromaeo.domcoremodify", + "dummy_benchmark.stable_benchmark_1", + "media.mobile", + "memory.top_10_mobile", + "scheduler.tough_scheduling_cases", + "smoothness.key_desktop_move_cases", + "smoothness.key_mobile_sites_smooth", + "smoothness.tough_ad_cases", + "smoothness.tough_image_decode_cases", + "system_health.memory_desktop", + "thread_times.key_mobile_sites_smooth", + "thread_times.key_silk_cases", + "v8.runtime_stats.top_25" + ] + }, + "1": { + "benchmarks": [ + "blink_perf.bindings", + "blink_perf.canvas", + "blink_perf.image_decoder", + "blink_perf.owp_storage", + "dummy_benchmark.histogram_benchmark_1", + "dummy_benchmark.noisy_benchmark_1", + "loading.desktop", + "octane", + "oortonline_tbmv2", + "power.idle_platform", + "smoothness.key_silk_cases", + "smoothness.pathological_mobile_sites", + "smoothness.top_25_smooth", + "smoothness.tough_webgl_cases", + "system_health.common_mobile", + "system_health.memory_mobile", + "thread_times.key_hit_test_cases", + "thread_times.key_noop_cases", + "thread_times.tough_scrolling_cases", + "tracing.tracing_with_background_memory_infra", + "v8.browsing_mobile", + "webrtc" + ] + }, + "2": { + "benchmarks": [ + "battor.trivial_pages", + "blink_perf.layout", + "dromaeo", + "dromaeo.domcoreattr", + "memory.long_running_idle_gmail_background_tbmv2", + "rasterize_and_record_micro.top_25", + "smoothness.gpu_rasterization.polymer", + "smoothness.gpu_rasterization.top_25_smooth", + "smoothness.gpu_rasterization_and_decoding.image_decoding_cases", + "smoothness.image_decoding_cases", + "smoothness.simple_mobile_sites", + "smoothness.tough_filters_cases", + "smoothness.tough_path_rendering_cases", + "smoothness.tough_scrolling_cases", + "speedometer", + "speedometer2", + "tab_switching.typical_25", + "thread_times.tough_compositor_cases", + "v8.browsing_desktop-future", + "v8.browsing_mobile-future", + "wasm" + ] + }, + "3": { + "benchmarks": [ + "blink_perf.parser", + "blink_perf.svg", + "dromaeo.domcorequery", + "dromaeo.domcoretraverse", + "jetstream", + "memory.desktop", + "power.typical_10_mobile", + "smoothness.gpu_rasterization.tough_filters_cases", + "smoothness.gpu_rasterization.tough_pinch_zoom_cases", + "smoothness.tough_canvas_cases", + "smoothness.tough_pinch_zoom_cases", + "speedometer-future", + "speedometer2-future", + "start_with_url.cold.startup_pages", + "v8.browsing_desktop", + "v8.detached_context_age_in_gc", + "v8.runtimestats.browsing_desktop" + ] + }, + "4": { + "benchmarks": [ + "battor.steady_state", + "blink_perf.css", + "blink_perf.events", + "blink_perf.shadow_dom", + "kraken", + "loading.mobile", + "media.desktop", + "memory.long_running_idle_gmail_tbmv2", + "rasterize_and_record_micro.partial_invalidation", + "smoothness.desktop_tough_pinch_zoom_cases", + "smoothness.gpu_rasterization.tough_path_rendering_cases", + "smoothness.gpu_rasterization.tough_scrolling_cases", + "smoothness.maps", + "smoothness.sync_scroll.key_mobile_sites_smooth", + "smoothness.tough_animation_cases", + "smoothness.tough_texture_upload_cases", + "smoothness.tough_webgl_ad_cases", + "start_with_url.warm.startup_pages", + "system_health.common_desktop", + "system_health.webview_startup", + "thread_times.key_idle_power_cases", + "thread_times.simple_mobile_sites", + "v8.runtimestats.browsing_mobile" + ] + } +}
diff --git a/tools/perf/core/benchmark_sharding_map.json b/tools/perf/core/benchmark_sharding_map.json index add862eb..5305dbd 100644 --- a/tools/perf/core/benchmark_sharding_map.json +++ b/tools/perf/core/benchmark_sharding_map.json
@@ -1,4 +1,9 @@ { + "comment": [ + "This file contains the current master benchmark list that is run and", + "is updated manually. Please also add new benchmarks to", + "tools/perf/core/benchmark_*_bot_map.json" + ], "Android Nexus5 Perf": { "build13-b1--device1": { "benchmarks": [ @@ -10,30 +15,28 @@ "loading.desktop", "smoothness.key_silk_cases", "smoothness.simple_mobile_sites", - "system_health.memory_desktop", - "v8.browsing_desktop_classic" + "system_health.memory_desktop" ] }, "build13-b1--device3": { "benchmarks": [ - "page_cycler_v2.intl_ja_zh", - "v8.runtimestats.browsing_mobile_classic", + "blink_perf.image_decoder", "blink_perf.owp_storage", - "blink_perf.image_decoder" + "wasm" ] }, "build13-b1--device4": { "benchmarks": [ - "blink_perf.blink_gc", - "page_cycler_v2.typical_25", - "v8.infinite_scroll-turbo_tbmv2" + "speedometer-future", + "speedometer2-future", + "v8.browsing_desktop-future", + "v8.browsing_mobile-future" ] }, "build13-b1--device5": { "benchmarks": [ "system_health.common_desktop", - "v8.browsing_mobile", - "v8.browsing_mobile_turbo" + "v8.browsing_mobile" ] }, "build13-b1--device6": { @@ -50,33 +53,27 @@ "benchmarks": [ "blink_perf.shadow_dom", "dromaeo.domcorequery", - "page_cycler_v2.intl_ko_th_vi", "power.idle_platform", - "smoothness.gpu_rasterization_and_decoding.image_decoding_cases", - "start_with_ext.warm.blank_page", - "v8.browsing_mobile_classic" + "smoothness.gpu_rasterization_and_decoding.image_decoding_cases" ] }, "build14-b1--device1": { "benchmarks": [ "battor.trivial_pages", - "media.tough_video_cases_tbmv2", + "media.desktop", "octane", "smoothness.gpu_rasterization.tough_scrolling_cases", "smoothness.tough_filters_cases", "thread_times.key_hit_test_cases", "thread_times.key_idle_power_cases", - "tracing.tracing_with_debug_overhead", - "v8.infinite_scroll-classic_tbmv2", "v8.runtimestats.browsing_mobile" ] }, "build14-b1--device2": { "benchmarks": [ - "dummy_benchmark.noisy_benchmark_1", "dummy_benchmark.histogram_benchmark_1", + "dummy_benchmark.noisy_benchmark_1", "jetstream", - "page_cycler_v2.intl_hi_ru", "smoothness.tough_texture_upload_cases", "speedometer", "speedometer2" @@ -89,8 +86,6 @@ "smoothness.image_decoding_cases", "smoothness.pathological_mobile_sites", "smoothness.tough_pinch_zoom_cases", - "startup.large_profile.cold.blank_page", - "storage.indexeddb_endure_tracing", "v8.detached_context_age_in_gc" ] }, @@ -98,23 +93,18 @@ "benchmarks": [ "blink_perf.bindings", "blink_perf.canvas", - "memory.dual_browser_test", - "page_cycler_v2.intl_es_fr_pt-BR", "rasterize_and_record_micro.partial_invalidation", "smoothness.gpu_rasterization.polymer", "start_with_url.cold.startup_pages", - "startup.warm.blank_page", - "startup.warm.chrome_signin", - "system_health.webview_startup", - "v8.browsing_desktop_turbo" + "system_health.webview_startup" ] }, "build14-b1--device5": { "benchmarks": [ "blink_perf.layout", + "dromaeo", "dromaeo.domcoreattr", "oortonline_tbmv2", - "page_cycler_v2.intl_ar_fa_he", "smoothness.maps", "smoothness.tough_webgl_cases", "thread_times.simple_mobile_sites" @@ -124,35 +114,22 @@ "benchmarks": [ "battor.steady_state", "blink_perf.svg", - "blob_storage.blob_storage", - "media.android.tough_video_cases", "memory.long_running_idle_gmail_background_tbmv2", - "rasterize_and_record_micro.polymer", "smoothness.gpu_rasterization.top_25_smooth", "smoothness.gpu_rasterization.tough_path_rendering_cases", - "thread_times.key_noop_cases", - "thread_times.polymer", - "v8.mobile_infinite_scroll-turbo_tbmv2", - "v8.runtimestats.browsing_mobile_turbo" + "thread_times.key_noop_cases" ] }, "build14-b1--device7": { "benchmarks": [ - "image_decoding.image_decoding_measurement", - "media.mse_cases", "memory.long_running_idle_gmail_tbmv2", - "smoothness.scrolling_tough_ad_cases", - "speedometer-classic", - "system_health.common_mobile", - "v8.infinite_scroll_tbmv2" + "system_health.common_mobile" ] }, "build48-b1--device1": { "benchmarks": [ "loading.mobile", - "media.android.tough_video_cases_tbmv2", - "media.tough_video_cases", - "service_worker.service_worker", + "media.mobile", "smoothness.tough_webgl_ad_cases", "tab_switching.typical_25", "v8.browsing_desktop" @@ -162,18 +139,13 @@ "benchmarks": [ "blink_perf.events", "dummy_benchmark.stable_benchmark_1", - "power.trivial_pages", "smoothness.top_25_smooth", - "smoothness.tough_ad_cases", - "startup.large_profile.warm.blank_page" + "smoothness.tough_ad_cases" ] }, "build48-b1--device3": { "benchmarks": [ "dromaeo.domcoremodify", - "media.media_cns_cases", - "memory.top_10_mobile_stress", - "page_cycler_v2_site_isolation.basic_oopif", "smoothness.key_desktop_move_cases", "smoothness.sync_scroll.key_mobile_sites_smooth", "thread_times.tough_compositor_cases", @@ -183,13 +155,8 @@ "build48-b1--device4": { "benchmarks": [ "blink_perf.dom", - "page_cycler_v2.basic_oopif", "rasterize_and_record_micro.top_25", "smoothness.tough_canvas_cases", - "speedometer-turbo", - "start_with_ext.cold.blank_page", - "storage.indexeddb_endure", - "system_health.webview_startup_multiprocess", "thread_times.key_silk_cases" ] }, @@ -197,38 +164,27 @@ "benchmarks": [ "blink_perf.css", "blink_perf.parser", - "page_cycler_v2.top_10_mobile", - "rasterize_and_record_micro.key_silk_cases", "scheduler.tough_scheduling_cases", "smoothness.gpu_rasterization.tough_pinch_zoom_cases", "smoothness.tough_image_decode_cases", - "start_with_url.warm.startup_pages", - "v8.mobile_infinite_scroll-classic_tbmv2", - "v8.mobile_infinite_scroll_tbmv2", - "v8.runtimestats.browsing_desktop_turbo" + "start_with_url.warm.startup_pages" ] }, "build48-b1--device6": { "benchmarks": [ "blink_perf.paint", "kraken", - "power.steady_state", "smoothness.key_mobile_sites_smooth", - "startup.cold.blank_page", "tracing.tracing_with_background_memory_infra" ] }, "build48-b1--device7": { "benchmarks": [ - "oortonline", - "rasterize_and_record_micro.key_mobile_sites", - "service_worker.service_worker_micro_benchmark", "smoothness.desktop_tough_pinch_zoom_cases", "smoothness.tough_path_rendering_cases", "smoothness.tough_scrolling_cases", "v8.runtime_stats.top_25", - "v8.runtimestats.browsing_desktop", - "v8.runtimestats.browsing_desktop_classic" + "v8.runtimestats.browsing_desktop" ] } }, @@ -243,30 +199,28 @@ "benchmarks": [ "loading.desktop", "smoothness.key_silk_cases", - "smoothness.simple_mobile_sites", - "v8.browsing_desktop_classic" + "smoothness.simple_mobile_sites" ] }, "build73-b1--device3": { "benchmarks": [ - "page_cycler_v2.intl_ja_zh", - "v8.runtimestats.browsing_mobile_classic", + "blink_perf.image_decoder", "blink_perf.owp_storage", - "blink_perf.image_decoder" + "wasm" ] }, "build73-b1--device4": { "benchmarks": [ - "blink_perf.blink_gc", - "page_cycler_v2.typical_25", - "v8.infinite_scroll-turbo_tbmv2" + "speedometer-future", + "speedometer2-future", + "v8.browsing_desktop-future", + "v8.browsing_mobile-future" ] }, "build73-b1--device5": { "benchmarks": [ "system_health.common_desktop", - "v8.browsing_mobile", - "v8.browsing_mobile_turbo" + "v8.browsing_mobile" ] }, "build73-b1--device6": { @@ -283,33 +237,27 @@ "benchmarks": [ "blink_perf.shadow_dom", "dromaeo.domcorequery", - "page_cycler_v2.intl_ko_th_vi", "power.idle_platform", - "smoothness.gpu_rasterization_and_decoding.image_decoding_cases", - "start_with_ext.warm.blank_page", - "v8.browsing_mobile_classic" + "smoothness.gpu_rasterization_and_decoding.image_decoding_cases" ] }, "build74-b1--device1": { "benchmarks": [ "battor.trivial_pages", - "media.tough_video_cases_tbmv2", + "media.desktop", "octane", "smoothness.gpu_rasterization.tough_scrolling_cases", "smoothness.tough_filters_cases", "thread_times.key_hit_test_cases", "thread_times.key_idle_power_cases", - "tracing.tracing_with_debug_overhead", - "v8.infinite_scroll-classic_tbmv2", "v8.runtimestats.browsing_mobile" ] }, "build74-b1--device2": { "benchmarks": [ - "dummy_benchmark.noisy_benchmark_1", "dummy_benchmark.histogram_benchmark_1", + "dummy_benchmark.noisy_benchmark_1", "jetstream", - "page_cycler_v2.intl_hi_ru", "smoothness.tough_texture_upload_cases", "speedometer", "speedometer2" @@ -322,8 +270,6 @@ "smoothness.image_decoding_cases", "smoothness.pathological_mobile_sites", "smoothness.tough_pinch_zoom_cases", - "startup.large_profile.cold.blank_page", - "storage.indexeddb_endure_tracing", "v8.detached_context_age_in_gc" ] }, @@ -331,23 +277,18 @@ "benchmarks": [ "blink_perf.bindings", "blink_perf.canvas", - "memory.dual_browser_test", - "page_cycler_v2.intl_es_fr_pt-BR", "rasterize_and_record_micro.partial_invalidation", "smoothness.gpu_rasterization.polymer", "start_with_url.cold.startup_pages", - "startup.warm.blank_page", - "startup.warm.chrome_signin", - "system_health.webview_startup", - "v8.browsing_desktop_turbo" + "system_health.webview_startup" ] }, "build74-b1--device5": { "benchmarks": [ "blink_perf.layout", + "dromaeo", "dromaeo.domcoreattr", "oortonline_tbmv2", - "page_cycler_v2.intl_ar_fa_he", "smoothness.maps", "smoothness.tough_webgl_cases", "thread_times.simple_mobile_sites" @@ -357,35 +298,22 @@ "benchmarks": [ "battor.steady_state", "blink_perf.svg", - "blob_storage.blob_storage", - "media.android.tough_video_cases", "memory.long_running_idle_gmail_background_tbmv2", - "rasterize_and_record_micro.polymer", "smoothness.gpu_rasterization.top_25_smooth", "smoothness.gpu_rasterization.tough_path_rendering_cases", - "thread_times.key_noop_cases", - "thread_times.polymer", - "v8.mobile_infinite_scroll-turbo_tbmv2", - "v8.runtimestats.browsing_mobile_turbo" + "thread_times.key_noop_cases" ] }, "build74-b1--device7": { "benchmarks": [ - "image_decoding.image_decoding_measurement", - "media.mse_cases", "memory.long_running_idle_gmail_tbmv2", - "smoothness.scrolling_tough_ad_cases", - "speedometer-classic", - "system_health.common_mobile", - "v8.infinite_scroll_tbmv2" + "system_health.common_mobile" ] }, "build75-b1--device1": { "benchmarks": [ "loading.mobile", - "media.android.tough_video_cases_tbmv2", - "media.tough_video_cases", - "service_worker.service_worker", + "media.mobile", "smoothness.tough_webgl_ad_cases", "tab_switching.typical_25", "v8.browsing_desktop" @@ -395,18 +323,13 @@ "benchmarks": [ "blink_perf.events", "dummy_benchmark.stable_benchmark_1", - "power.trivial_pages", "smoothness.top_25_smooth", - "smoothness.tough_ad_cases", - "startup.large_profile.warm.blank_page" + "smoothness.tough_ad_cases" ] }, "build75-b1--device3": { "benchmarks": [ "dromaeo.domcoremodify", - "media.media_cns_cases", - "memory.top_10_mobile_stress", - "page_cycler_v2_site_isolation.basic_oopif", "smoothness.key_desktop_move_cases", "smoothness.sync_scroll.key_mobile_sites_smooth", "thread_times.tough_compositor_cases", @@ -416,13 +339,8 @@ "build75-b1--device4": { "benchmarks": [ "blink_perf.dom", - "page_cycler_v2.basic_oopif", "rasterize_and_record_micro.top_25", "smoothness.tough_canvas_cases", - "speedometer-turbo", - "start_with_ext.cold.blank_page", - "storage.indexeddb_endure", - "system_health.webview_startup_multiprocess", "thread_times.key_silk_cases" ] }, @@ -430,38 +348,27 @@ "benchmarks": [ "blink_perf.css", "blink_perf.parser", - "page_cycler_v2.top_10_mobile", - "rasterize_and_record_micro.key_silk_cases", "scheduler.tough_scheduling_cases", "smoothness.gpu_rasterization.tough_pinch_zoom_cases", "smoothness.tough_image_decode_cases", - "start_with_url.warm.startup_pages", - "v8.mobile_infinite_scroll-classic_tbmv2", - "v8.mobile_infinite_scroll_tbmv2", - "v8.runtimestats.browsing_desktop_turbo" + "start_with_url.warm.startup_pages" ] }, "build75-b1--device6": { "benchmarks": [ "blink_perf.paint", "kraken", - "power.steady_state", "smoothness.key_mobile_sites_smooth", - "startup.cold.blank_page", "tracing.tracing_with_background_memory_infra" ] }, "build75-b1--device7": { "benchmarks": [ - "oortonline", - "rasterize_and_record_micro.key_mobile_sites", - "service_worker.service_worker_micro_benchmark", "smoothness.desktop_tough_pinch_zoom_cases", "smoothness.tough_path_rendering_cases", "smoothness.tough_scrolling_cases", "v8.runtime_stats.top_25", - "v8.runtimestats.browsing_desktop", - "v8.runtimestats.browsing_desktop_classic" + "v8.runtimestats.browsing_desktop" ] } }, @@ -476,19 +383,24 @@ "build164-b1--device2": { "benchmarks": [ "loading.desktop", - "smoothness.simple_mobile_sites" + "smoothness.simple_mobile_sites", + "speedometer-future", + "speedometer2-future" ] }, "build164-b1--device3": { "benchmarks": [ - "system_health.common_desktop", + "blink_perf.image_decoder", "blink_perf.owp_storage", - "blink_perf.image_decoder" + "system_health.common_desktop", + "wasm" ] }, "build164-b1--device4": { "benchmarks": [ - "smoothness.tough_animation_cases" + "smoothness.tough_animation_cases", + "v8.browsing_desktop-future", + "v8.browsing_mobile-future" ] }, "build164-b1--device5": { @@ -501,7 +413,6 @@ "benchmarks": [ "memory.desktop", "power.typical_10_mobile", - "startup.large_profile.cold.blank_page", "thread_times.key_mobile_sites_smooth", "webrtc" ] @@ -512,16 +423,15 @@ "blink_perf.canvas", "blink_perf.paint", "power.idle_platform", - "smoothness.image_decoding_cases", - "start_with_ext.warm.blank_page" + "smoothness.image_decoding_cases" ] }, "build165-b1--device1": { "benchmarks": [ "blink_perf.shadow_dom", - "dummy_benchmark.noisy_benchmark_1", "dummy_benchmark.histogram_benchmark_1", - "media.tough_video_cases_tbmv2", + "dummy_benchmark.noisy_benchmark_1", + "media.desktop", "memory.long_running_idle_gmail_background_tbmv2", "smoothness.gpu_rasterization.tough_scrolling_cases", "smoothness.tough_image_decode_cases", @@ -533,10 +443,7 @@ "build165-b1--device2": { "benchmarks": [ "dromaeo.domcorequery", - "dromaeo.domcoretraverse", - "oortonline", - "power.trivial_pages", - "tracing.tracing_with_debug_overhead" + "dromaeo.domcoretraverse" ] }, "build165-b1--device3": { @@ -547,50 +454,40 @@ "smoothness.gpu_rasterization_and_decoding.image_decoding_cases", "smoothness.pathological_mobile_sites", "smoothness.tough_pinch_zoom_cases", - "startup.warm.blank_page", "thread_times.tough_scrolling_cases" ] }, "build165-b1--device4": { "benchmarks": [ "smoothness.gpu_rasterization.polymer", - "smoothness.scrolling_tough_ad_cases", "smoothness.tough_canvas_cases", "smoothness.tough_path_rendering_cases", "start_with_url.cold.startup_pages", - "startup.large_profile.warm.blank_page", - "startup.warm.chrome_signin", "system_health.webview_startup" ] }, "build165-b1--device5": { "benchmarks": [ + "dromaeo", "dromaeo.domcoreattr", "oortonline_tbmv2", "smoothness.gpu_rasterization.tough_filters_cases", "smoothness.maps", "smoothness.tough_webgl_ad_cases", - "startup.cold.blank_page", "thread_times.simple_mobile_sites" ] }, "build165-b1--device6": { "benchmarks": [ "dromaeo.domcoremodify", - "media.android.tough_video_cases", - "media.media_cns_cases", - "rasterize_and_record_micro.key_mobile_sites", - "rasterize_and_record_micro.polymer", "smoothness.gpu_rasterization.top_25_smooth", "thread_times.key_noop_cases", - "thread_times.polymer", "thread_times.tough_compositor_cases", "v8.detached_context_age_in_gc" ] }, "build165-b1--device7": { "benchmarks": [ - "media.mse_cases", "smoothness.key_desktop_move_cases", "smoothness.tough_ad_cases", "smoothness.tough_scrolling_cases", @@ -600,13 +497,10 @@ }, "build166-b1--device1": { "benchmarks": [ - "image_decoding.image_decoding_measurement", "kraken", "loading.mobile", - "media.android.tough_video_cases_tbmv2", - "power.steady_state", - "smoothness.tough_filters_cases", - "storage.indexeddb_endure_tracing" + "media.mobile", + "smoothness.tough_filters_cases" ] }, "build166-b1--device2": { @@ -620,8 +514,6 @@ }, "build166-b1--device3": { "benchmarks": [ - "page_cycler_v2.basic_oopif", - "service_worker.service_worker_micro_benchmark", "smoothness.desktop_tough_pinch_zoom_cases", "smoothness.sync_scroll.key_mobile_sites_smooth", "speedometer", @@ -633,41 +525,32 @@ "benchmarks": [ "blink_perf.events", "blink_perf.parser", - "page_cycler_v2_site_isolation.basic_oopif", "smoothness.tough_texture_upload_cases", - "start_with_ext.cold.blank_page", "thread_times.key_silk_cases" ] }, "build166-b1--device5": { "benchmarks": [ - "rasterize_and_record_micro.key_silk_cases", "rasterize_and_record_micro.partial_invalidation", "rasterize_and_record_micro.top_25", - "service_worker.service_worker", "smoothness.gpu_rasterization.tough_pinch_zoom_cases", "smoothness.top_25_smooth", "start_with_url.warm.startup_pages", - "tracing.tracing_with_background_memory_infra", - "v8.mobile_infinite_scroll_tbmv2" + "tracing.tracing_with_background_memory_infra" ] }, "build166-b1--device6": { "benchmarks": [ "blink_perf.css", "blink_perf.layout", - "media.tough_video_cases", - "smoothness.key_mobile_sites_smooth", - "storage.indexeddb_endure" + "smoothness.key_mobile_sites_smooth" ] }, "build166-b1--device7": { "benchmarks": [ "blink_perf.svg", - "blob_storage.blob_storage", "dummy_benchmark.stable_benchmark_1", "smoothness.gpu_rasterization.tough_path_rendering_cases", - "v8.infinite_scroll_tbmv2", "v8.runtime_stats.top_25", "v8.runtimestats.browsing_desktop" ] @@ -684,30 +567,28 @@ "benchmarks": [ "loading.desktop", "smoothness.key_silk_cases", - "smoothness.simple_mobile_sites", - "v8.browsing_desktop_classic" + "smoothness.simple_mobile_sites" ] }, "build15-b1--device3": { "benchmarks": [ - "page_cycler_v2.intl_ja_zh", - "v8.runtimestats.browsing_mobile_classic", + "blink_perf.image_decoder", "blink_perf.owp_storage", - "blink_perf.image_decoder" + "wasm" ] }, "build15-b1--device4": { "benchmarks": [ - "blink_perf.blink_gc", - "page_cycler_v2.typical_25", - "v8.infinite_scroll-turbo_tbmv2" + "speedometer-future", + "speedometer2-future", + "v8.browsing_desktop-future", + "v8.browsing_mobile-future" ] }, "build15-b1--device5": { "benchmarks": [ "system_health.common_desktop", - "v8.browsing_mobile", - "v8.browsing_mobile_turbo" + "v8.browsing_mobile" ] }, "build15-b1--device6": { @@ -724,33 +605,27 @@ "benchmarks": [ "blink_perf.shadow_dom", "dromaeo.domcorequery", - "page_cycler_v2.intl_ko_th_vi", "power.idle_platform", - "smoothness.gpu_rasterization_and_decoding.image_decoding_cases", - "start_with_ext.warm.blank_page", - "v8.browsing_mobile_classic" + "smoothness.gpu_rasterization_and_decoding.image_decoding_cases" ] }, "build16-b1--device1": { "benchmarks": [ "battor.trivial_pages", - "media.tough_video_cases_tbmv2", + "media.desktop", "octane", "smoothness.gpu_rasterization.tough_scrolling_cases", "smoothness.tough_filters_cases", "thread_times.key_hit_test_cases", "thread_times.key_idle_power_cases", - "tracing.tracing_with_debug_overhead", - "v8.infinite_scroll-classic_tbmv2", "v8.runtimestats.browsing_mobile" ] }, "build16-b1--device2": { "benchmarks": [ - "dummy_benchmark.noisy_benchmark_1", "dummy_benchmark.histogram_benchmark_1", + "dummy_benchmark.noisy_benchmark_1", "jetstream", - "page_cycler_v2.intl_hi_ru", "smoothness.tough_texture_upload_cases", "speedometer", "speedometer2" @@ -763,8 +638,6 @@ "smoothness.image_decoding_cases", "smoothness.pathological_mobile_sites", "smoothness.tough_pinch_zoom_cases", - "startup.large_profile.cold.blank_page", - "storage.indexeddb_endure_tracing", "v8.detached_context_age_in_gc" ] }, @@ -772,23 +645,18 @@ "benchmarks": [ "blink_perf.bindings", "blink_perf.canvas", - "memory.dual_browser_test", - "page_cycler_v2.intl_es_fr_pt-BR", "rasterize_and_record_micro.partial_invalidation", "smoothness.gpu_rasterization.polymer", "start_with_url.cold.startup_pages", - "startup.warm.blank_page", - "startup.warm.chrome_signin", - "system_health.webview_startup", - "v8.browsing_desktop_turbo" + "system_health.webview_startup" ] }, "build16-b1--device5": { "benchmarks": [ "blink_perf.layout", + "dromaeo", "dromaeo.domcoreattr", "oortonline_tbmv2", - "page_cycler_v2.intl_ar_fa_he", "smoothness.maps", "smoothness.tough_webgl_cases", "thread_times.simple_mobile_sites" @@ -798,35 +666,22 @@ "benchmarks": [ "battor.steady_state", "blink_perf.svg", - "blob_storage.blob_storage", - "media.android.tough_video_cases", "memory.long_running_idle_gmail_background_tbmv2", - "rasterize_and_record_micro.polymer", "smoothness.gpu_rasterization.top_25_smooth", "smoothness.gpu_rasterization.tough_path_rendering_cases", - "thread_times.key_noop_cases", - "thread_times.polymer", - "v8.mobile_infinite_scroll-turbo_tbmv2", - "v8.runtimestats.browsing_mobile_turbo" + "thread_times.key_noop_cases" ] }, "build16-b1--device7": { "benchmarks": [ - "image_decoding.image_decoding_measurement", - "media.mse_cases", "memory.long_running_idle_gmail_tbmv2", - "smoothness.scrolling_tough_ad_cases", - "speedometer-classic", - "system_health.common_mobile", - "v8.infinite_scroll_tbmv2" + "system_health.common_mobile" ] }, "build45-b1--device1": { "benchmarks": [ "loading.mobile", - "media.android.tough_video_cases_tbmv2", - "media.tough_video_cases", - "service_worker.service_worker", + "media.mobile", "smoothness.tough_webgl_ad_cases", "tab_switching.typical_25", "v8.browsing_desktop" @@ -836,18 +691,13 @@ "benchmarks": [ "blink_perf.events", "dummy_benchmark.stable_benchmark_1", - "power.trivial_pages", "smoothness.top_25_smooth", - "smoothness.tough_ad_cases", - "startup.large_profile.warm.blank_page" + "smoothness.tough_ad_cases" ] }, "build45-b1--device3": { "benchmarks": [ "dromaeo.domcoremodify", - "media.media_cns_cases", - "memory.top_10_mobile_stress", - "page_cycler_v2_site_isolation.basic_oopif", "smoothness.key_desktop_move_cases", "smoothness.sync_scroll.key_mobile_sites_smooth", "thread_times.tough_compositor_cases", @@ -857,13 +707,8 @@ "build45-b1--device4": { "benchmarks": [ "blink_perf.dom", - "page_cycler_v2.basic_oopif", "rasterize_and_record_micro.top_25", "smoothness.tough_canvas_cases", - "speedometer-turbo", - "start_with_ext.cold.blank_page", - "storage.indexeddb_endure", - "system_health.webview_startup_multiprocess", "thread_times.key_silk_cases" ] }, @@ -871,38 +716,27 @@ "benchmarks": [ "blink_perf.css", "blink_perf.parser", - "page_cycler_v2.top_10_mobile", - "rasterize_and_record_micro.key_silk_cases", "scheduler.tough_scheduling_cases", "smoothness.gpu_rasterization.tough_pinch_zoom_cases", "smoothness.tough_image_decode_cases", - "start_with_url.warm.startup_pages", - "v8.mobile_infinite_scroll-classic_tbmv2", - "v8.mobile_infinite_scroll_tbmv2", - "v8.runtimestats.browsing_desktop_turbo" + "start_with_url.warm.startup_pages" ] }, "build45-b1--device6": { "benchmarks": [ "blink_perf.paint", "kraken", - "power.steady_state", "smoothness.key_mobile_sites_smooth", - "startup.cold.blank_page", "tracing.tracing_with_background_memory_infra" ] }, "build45-b1--device7": { "benchmarks": [ - "oortonline", - "rasterize_and_record_micro.key_mobile_sites", - "service_worker.service_worker_micro_benchmark", "smoothness.desktop_tough_pinch_zoom_cases", "smoothness.tough_path_rendering_cases", "smoothness.tough_scrolling_cases", "v8.runtime_stats.top_25", - "v8.runtimestats.browsing_desktop", - "v8.runtimestats.browsing_desktop_classic" + "v8.runtimestats.browsing_desktop" ] } }, @@ -922,14 +756,17 @@ }, "build112-b1--device3": { "benchmarks": [ - "system_health.common_desktop", + "blink_perf.image_decoder", "blink_perf.owp_storage", - "blink_perf.image_decoder" + "system_health.common_desktop", + "wasm" ] }, "build112-b1--device4": { "benchmarks": [ - "smoothness.tough_animation_cases" + "smoothness.tough_animation_cases", + "v8.browsing_desktop-future", + "v8.browsing_mobile-future" ] }, "build112-b1--device5": { @@ -942,7 +779,6 @@ "benchmarks": [ "memory.desktop", "power.typical_10_mobile", - "startup.large_profile.cold.blank_page", "thread_times.key_mobile_sites_smooth", "webrtc" ] @@ -953,16 +789,15 @@ "blink_perf.canvas", "blink_perf.paint", "power.idle_platform", - "smoothness.image_decoding_cases", - "start_with_ext.warm.blank_page" + "smoothness.image_decoding_cases" ] }, "build113-b1--device1": { "benchmarks": [ "blink_perf.shadow_dom", - "dummy_benchmark.noisy_benchmark_1", "dummy_benchmark.histogram_benchmark_1", - "media.tough_video_cases_tbmv2", + "dummy_benchmark.noisy_benchmark_1", + "media.desktop", "memory.long_running_idle_gmail_background_tbmv2", "smoothness.gpu_rasterization.tough_scrolling_cases", "smoothness.tough_image_decode_cases", @@ -975,9 +810,8 @@ "benchmarks": [ "dromaeo.domcorequery", "dromaeo.domcoretraverse", - "oortonline", - "power.trivial_pages", - "tracing.tracing_with_debug_overhead" + "speedometer-future", + "speedometer2-future" ] }, "build113-b1--device3": { @@ -988,50 +822,40 @@ "smoothness.gpu_rasterization_and_decoding.image_decoding_cases", "smoothness.pathological_mobile_sites", "smoothness.tough_pinch_zoom_cases", - "startup.warm.blank_page", "thread_times.tough_scrolling_cases" ] }, "build113-b1--device4": { "benchmarks": [ "smoothness.gpu_rasterization.polymer", - "smoothness.scrolling_tough_ad_cases", "smoothness.tough_canvas_cases", "smoothness.tough_path_rendering_cases", "start_with_url.cold.startup_pages", - "startup.large_profile.warm.blank_page", - "startup.warm.chrome_signin", "system_health.webview_startup" ] }, "build113-b1--device5": { "benchmarks": [ + "dromaeo", "dromaeo.domcoreattr", "oortonline_tbmv2", "smoothness.gpu_rasterization.tough_filters_cases", "smoothness.maps", "smoothness.tough_webgl_ad_cases", - "startup.cold.blank_page", "thread_times.simple_mobile_sites" ] }, "build113-b1--device6": { "benchmarks": [ "dromaeo.domcoremodify", - "media.android.tough_video_cases", - "media.media_cns_cases", - "rasterize_and_record_micro.key_mobile_sites", - "rasterize_and_record_micro.polymer", "smoothness.gpu_rasterization.top_25_smooth", "thread_times.key_noop_cases", - "thread_times.polymer", "thread_times.tough_compositor_cases", "v8.detached_context_age_in_gc" ] }, "build113-b1--device7": { "benchmarks": [ - "media.mse_cases", "smoothness.key_desktop_move_cases", "smoothness.tough_ad_cases", "smoothness.tough_scrolling_cases", @@ -1041,13 +865,10 @@ }, "build114-b1--device1": { "benchmarks": [ - "image_decoding.image_decoding_measurement", "kraken", "loading.mobile", - "media.android.tough_video_cases_tbmv2", - "power.steady_state", - "smoothness.tough_filters_cases", - "storage.indexeddb_endure_tracing" + "media.mobile", + "smoothness.tough_filters_cases" ] }, "build114-b1--device2": { @@ -1061,8 +882,6 @@ }, "build114-b1--device3": { "benchmarks": [ - "page_cycler_v2.basic_oopif", - "service_worker.service_worker_micro_benchmark", "smoothness.desktop_tough_pinch_zoom_cases", "smoothness.sync_scroll.key_mobile_sites_smooth", "speedometer", @@ -1074,41 +893,32 @@ "benchmarks": [ "blink_perf.events", "blink_perf.parser", - "page_cycler_v2_site_isolation.basic_oopif", "smoothness.tough_texture_upload_cases", - "start_with_ext.cold.blank_page", "thread_times.key_silk_cases" ] }, "build114-b1--device5": { "benchmarks": [ - "rasterize_and_record_micro.key_silk_cases", "rasterize_and_record_micro.partial_invalidation", "rasterize_and_record_micro.top_25", - "service_worker.service_worker", "smoothness.gpu_rasterization.tough_pinch_zoom_cases", "smoothness.top_25_smooth", "start_with_url.warm.startup_pages", - "tracing.tracing_with_background_memory_infra", - "v8.mobile_infinite_scroll_tbmv2" + "tracing.tracing_with_background_memory_infra" ] }, "build114-b1--device6": { "benchmarks": [ "blink_perf.css", "blink_perf.layout", - "media.tough_video_cases", - "smoothness.key_mobile_sites_smooth", - "storage.indexeddb_endure" + "smoothness.key_mobile_sites_smooth" ] }, "build114-b1--device7": { "benchmarks": [ "blink_perf.svg", - "blob_storage.blob_storage", "dummy_benchmark.stable_benchmark_1", "smoothness.gpu_rasterization.tough_path_rendering_cases", - "v8.infinite_scroll_tbmv2", "v8.runtime_stats.top_25", "v8.runtimestats.browsing_desktop" ] @@ -1118,28 +928,24 @@ "build10-b1--device1": { "benchmarks": [ "battor.trivial_pages", - "media.tough_video_cases_tbmv2", + "media.desktop", "octane", "smoothness.gpu_rasterization.tough_scrolling_cases", "smoothness.tough_filters_cases", "thread_times.key_hit_test_cases", "thread_times.key_idle_power_cases", - "tracing.tracing_with_debug_overhead", - "v8.infinite_scroll-classic_tbmv2", "v8.runtimestats.browsing_mobile" ] }, "build10-b1--device2": { "benchmarks": [ - "dummy_benchmark.noisy_benchmark_1", "dummy_benchmark.histogram_benchmark_1", + "dummy_benchmark.noisy_benchmark_1", "jetstream", - "page_cycler_v2.intl_hi_ru", "smoothness.tough_scrolling_cases", "smoothness.tough_texture_upload_cases", "speedometer", - "speedometer2", - "storage.indexeddb_endure_tracing" + "speedometer2" ] }, "build10-b1--device3": { @@ -1149,31 +955,28 @@ "smoothness.image_decoding_cases", "smoothness.pathological_mobile_sites", "smoothness.tough_pinch_zoom_cases", - "startup.large_profile.cold.blank_page", - "v8.detached_context_age_in_gc" + "v8.detached_context_age_in_gc", + "wasm" ] }, "build10-b1--device4": { "benchmarks": [ "blink_perf.bindings", "blink_perf.canvas", - "memory.dual_browser_test", - "page_cycler_v2.intl_es_fr_pt-BR", "rasterize_and_record_micro.partial_invalidation", "smoothness.gpu_rasterization.polymer", "start_with_url.cold.startup_pages", - "startup.warm.blank_page", - "startup.warm.chrome_signin", "system_health.webview_startup", - "v8.browsing_desktop_turbo" + "v8.browsing_desktop-future", + "v8.browsing_mobile-future" ] }, "build10-b1--device5": { "benchmarks": [ "blink_perf.layout", + "dromaeo", "dromaeo.domcoreattr", "oortonline_tbmv2", - "page_cycler_v2.intl_ar_fa_he", "smoothness.maps", "smoothness.tough_webgl_cases", "thread_times.simple_mobile_sites" @@ -1183,35 +986,22 @@ "benchmarks": [ "battor.steady_state", "blink_perf.svg", - "blob_storage.blob_storage", - "media.android.tough_video_cases", "memory.long_running_idle_gmail_background_tbmv2", - "rasterize_and_record_micro.polymer", "smoothness.gpu_rasterization.top_25_smooth", "smoothness.gpu_rasterization.tough_path_rendering_cases", - "thread_times.key_noop_cases", - "thread_times.polymer", - "v8.mobile_infinite_scroll-turbo_tbmv2", - "v8.runtimestats.browsing_mobile_turbo" + "thread_times.key_noop_cases" ] }, "build10-b1--device7": { "benchmarks": [ - "image_decoding.image_decoding_measurement", - "media.mse_cases", "memory.long_running_idle_gmail_tbmv2", - "smoothness.scrolling_tough_ad_cases", - "speedometer-classic", - "system_health.common_mobile", - "v8.infinite_scroll_tbmv2" + "system_health.common_mobile" ] }, "build49-b1--device1": { "benchmarks": [ "loading.mobile", - "media.android.tough_video_cases_tbmv2", - "media.tough_video_cases", - "service_worker.service_worker", + "media.mobile", "smoothness.tough_webgl_ad_cases", "tab_switching.typical_25", "v8.browsing_desktop" @@ -1221,18 +1011,13 @@ "benchmarks": [ "blink_perf.events", "dummy_benchmark.stable_benchmark_1", - "power.trivial_pages", "smoothness.top_25_smooth", - "smoothness.tough_ad_cases", - "startup.large_profile.warm.blank_page" + "smoothness.tough_ad_cases" ] }, "build49-b1--device3": { "benchmarks": [ "dromaeo.domcoremodify", - "media.media_cns_cases", - "memory.top_10_mobile_stress", - "page_cycler_v2_site_isolation.basic_oopif", "smoothness.key_desktop_move_cases", "smoothness.sync_scroll.key_mobile_sites_smooth", "thread_times.tough_compositor_cases", @@ -1242,13 +1027,8 @@ "build49-b1--device4": { "benchmarks": [ "blink_perf.dom", - "page_cycler_v2.basic_oopif", "rasterize_and_record_micro.top_25", "smoothness.tough_canvas_cases", - "speedometer-turbo", - "start_with_ext.cold.blank_page", - "storage.indexeddb_endure", - "system_health.webview_startup_multiprocess", "thread_times.key_silk_cases" ] }, @@ -1256,37 +1036,26 @@ "benchmarks": [ "blink_perf.css", "blink_perf.parser", - "page_cycler_v2.top_10_mobile", - "rasterize_and_record_micro.key_silk_cases", "scheduler.tough_scheduling_cases", "smoothness.gpu_rasterization.tough_pinch_zoom_cases", "smoothness.tough_image_decode_cases", - "start_with_url.warm.startup_pages", - "v8.mobile_infinite_scroll-classic_tbmv2", - "v8.mobile_infinite_scroll_tbmv2", - "v8.runtimestats.browsing_desktop_turbo" + "start_with_url.warm.startup_pages" ] }, "build49-b1--device6": { "benchmarks": [ "blink_perf.paint", "kraken", - "power.steady_state", "smoothness.key_mobile_sites_smooth", - "startup.cold.blank_page", "tracing.tracing_with_background_memory_infra" ] }, "build49-b1--device7": { "benchmarks": [ - "oortonline", - "rasterize_and_record_micro.key_mobile_sites", - "service_worker.service_worker_micro_benchmark", "smoothness.desktop_tough_pinch_zoom_cases", "smoothness.tough_path_rendering_cases", "v8.runtime_stats.top_25", - "v8.runtimestats.browsing_desktop", - "v8.runtimestats.browsing_desktop_classic" + "v8.runtimestats.browsing_desktop" ] }, "build9-b1--device1": { @@ -1299,30 +1068,25 @@ "benchmarks": [ "loading.desktop", "smoothness.key_silk_cases", - "smoothness.simple_mobile_sites", - "v8.browsing_desktop_classic" + "smoothness.simple_mobile_sites" ] }, "build9-b1--device3": { "benchmarks": [ - "page_cycler_v2.intl_ja_zh", - "v8.runtimestats.browsing_mobile_classic", - "blink_perf.owp_storage", - "blink_perf.image_decoder" + "blink_perf.image_decoder", + "blink_perf.owp_storage" ] }, "build9-b1--device4": { "benchmarks": [ - "blink_perf.blink_gc", - "page_cycler_v2.typical_25", - "v8.infinite_scroll-turbo_tbmv2" + "speedometer-future", + "speedometer2-future" ] }, "build9-b1--device5": { "benchmarks": [ "system_health.common_desktop", - "v8.browsing_mobile", - "v8.browsing_mobile_turbo" + "v8.browsing_mobile" ] }, "build9-b1--device6": { @@ -1339,11 +1103,8 @@ "benchmarks": [ "blink_perf.shadow_dom", "dromaeo.domcorequery", - "page_cycler_v2.intl_ko_th_vi", "power.idle_platform", - "smoothness.gpu_rasterization_and_decoding.image_decoding_cases", - "start_with_ext.warm.blank_page", - "v8.browsing_mobile_classic" + "smoothness.gpu_rasterization_and_decoding.image_decoding_cases" ] } }, @@ -1358,30 +1119,28 @@ "build17-b1--device2": { "benchmarks": [ "loading.desktop", - "smoothness.simple_mobile_sites", - "v8.browsing_desktop_classic" + "smoothness.simple_mobile_sites" ] }, "build17-b1--device3": { "benchmarks": [ - "page_cycler_v2.intl_ja_zh", - "v8.runtimestats.browsing_mobile_classic", + "blink_perf.image_decoder", "blink_perf.owp_storage", - "blink_perf.image_decoder" + "wasm" ] }, "build17-b1--device4": { "benchmarks": [ - "blink_perf.blink_gc", - "page_cycler_v2.typical_25", - "v8.infinite_scroll-turbo_tbmv2" + "speedometer-future", + "speedometer2-future", + "v8.browsing_desktop-future", + "v8.browsing_mobile-future" ] }, "build17-b1--device5": { "benchmarks": [ "system_health.common_desktop", - "v8.browsing_mobile", - "v8.browsing_mobile_turbo" + "v8.browsing_mobile" ] }, "build17-b1--device6": { @@ -1396,23 +1155,19 @@ "build17-b1--device7": { "benchmarks": [ "kraken", - "page_cycler_v2.intl_ko_th_vi", - "power.idle_platform", - "start_with_ext.warm.blank_page", - "startup.warm.blank_page", - "v8.browsing_mobile_classic" + "power.idle_platform" ] }, "build18-b1--device1": { "benchmarks": [ "battor.trivial_pages", + "dromaeo", "dromaeo.domcoreattr", - "media.tough_video_cases_tbmv2", + "media.desktop", "memory.long_running_idle_gmail_tbmv2", "oortonline_tbmv2", "smoothness.gpu_rasterization.tough_scrolling_cases", "thread_times.key_idle_power_cases", - "v8.infinite_scroll-classic_tbmv2", "v8.runtimestats.browsing_mobile" ] }, @@ -1421,44 +1176,31 @@ "blink_perf.dom", "blink_perf.paint", "dromaeo.domcoretraverse", - "memory.long_running_idle_gmail_background_tbmv2", - "page_cycler_v2.intl_hi_ru" + "memory.long_running_idle_gmail_background_tbmv2" ] }, "build18-b1--device3": { "benchmarks": [ - "dummy_benchmark.noisy_benchmark_1", "dummy_benchmark.histogram_benchmark_1", + "dummy_benchmark.noisy_benchmark_1", "memory.top_10_mobile", "smoothness.gpu_rasterization.tough_path_rendering_cases", "smoothness.pathological_mobile_sites", - "smoothness.tough_pinch_zoom_cases", - "startup.large_profile.cold.blank_page", - "startup.large_profile.warm.blank_page", - "tracing.tracing_with_debug_overhead" + "smoothness.tough_pinch_zoom_cases" ] }, "build18-b1--device4": { "benchmarks": [ - "memory.dual_browser_test", - "page_cycler_v2.intl_es_fr_pt-BR", "rasterize_and_record_micro.partial_invalidation", "smoothness.gpu_rasterization.polymer", - "smoothness.scrolling_tough_ad_cases", "smoothness.tough_texture_upload_cases", "start_with_url.cold.startup_pages", - "startup.warm.chrome_signin", - "storage.indexeddb_endure", - "system_health.webview_startup", - "v8.browsing_desktop_turbo" + "system_health.webview_startup" ] }, "build18-b1--device5": { "benchmarks": [ - "media.media_cns_cases", - "page_cycler_v2.intl_ar_fa_he", "rasterize_and_record_micro.top_25", - "service_worker.service_worker_micro_benchmark", "smoothness.maps", "smoothness.tough_path_rendering_cases", "thread_times.simple_mobile_sites" @@ -1469,24 +1211,16 @@ "battor.steady_state", "blink_perf.layout", "blink_perf.shadow_dom", - "media.android.tough_video_cases", "octane", - "rasterize_and_record_micro.polymer", "smoothness.gpu_rasterization.top_25_smooth", "smoothness.tough_webgl_cases", - "thread_times.key_noop_cases", - "thread_times.polymer", - "v8.mobile_infinite_scroll-turbo_tbmv2", - "v8.runtimestats.browsing_mobile_turbo" + "thread_times.key_noop_cases" ] }, "build18-b1--device7": { "benchmarks": [ - "blob_storage.blob_storage", "jetstream", - "service_worker.service_worker", "smoothness.image_decoding_cases", - "speedometer-classic", "system_health.common_mobile", "tab_switching.typical_25", "v8.browsing_desktop" @@ -1497,18 +1231,15 @@ "blink_perf.css", "dummy_benchmark.stable_benchmark_1", "loading.mobile", - "media.android.tough_video_cases_tbmv2", - "power.trivial_pages", + "media.mobile", "speedometer", "speedometer2", - "thread_times.tough_compositor_cases", - "v8.infinite_scroll_tbmv2" + "thread_times.tough_compositor_cases" ] }, "build47-b1--device2": { "benchmarks": [ "blink_perf.canvas", - "media.tough_video_cases", "smoothness.tough_image_decode_cases", "smoothness.tough_webgl_ad_cases", "thread_times.tough_scrolling_cases" @@ -1516,27 +1247,19 @@ }, "build47-b1--device3": { "benchmarks": [ - "media.mse_cases", - "memory.top_10_mobile_stress", "smoothness.key_desktop_move_cases", "smoothness.sync_scroll.key_mobile_sites_smooth", "smoothness.top_25_smooth", "smoothness.tough_canvas_cases", - "smoothness.tough_filters_cases", - "storage.indexeddb_endure_tracing" + "smoothness.tough_filters_cases" ] }, "build47-b1--device4": { "benchmarks": [ "blink_perf.bindings", "dromaeo.domcorequery", - "page_cycler_v2.top_10_mobile", - "page_cycler_v2_site_isolation.basic_oopif", "smoothness.gpu_rasterization.tough_filters_cases", "smoothness.gpu_rasterization_and_decoding.image_decoding_cases", - "speedometer-turbo", - "start_with_ext.cold.blank_page", - "system_health.webview_startup_multiprocess", "thread_times.key_silk_cases" ] }, @@ -1544,23 +1267,15 @@ "benchmarks": [ "blink_perf.parser", "dromaeo.domcoremodify", - "oortonline", - "page_cycler_v2.basic_oopif", - "rasterize_and_record_micro.key_silk_cases", "smoothness.gpu_rasterization.tough_pinch_zoom_cases", "start_with_url.warm.startup_pages", - "startup.cold.blank_page", - "v8.detached_context_age_in_gc", - "v8.mobile_infinite_scroll-classic_tbmv2", - "v8.mobile_infinite_scroll_tbmv2", - "v8.runtimestats.browsing_desktop_turbo" + "v8.detached_context_age_in_gc" ] }, "build47-b1--device6": { "benchmarks": [ "blink_perf.events", "blink_perf.svg", - "rasterize_and_record_micro.key_mobile_sites", "scheduler.tough_scheduling_cases", "smoothness.desktop_tough_pinch_zoom_cases", "smoothness.key_mobile_sites_smooth" @@ -1568,15 +1283,12 @@ }, "build47-b1--device7": { "benchmarks": [ - "image_decoding.image_decoding_measurement", - "power.steady_state", "smoothness.tough_ad_cases", "smoothness.tough_scrolling_cases", "thread_times.key_hit_test_cases", "tracing.tracing_with_background_memory_infra", "v8.runtime_stats.top_25", - "v8.runtimestats.browsing_desktop", - "v8.runtimestats.browsing_desktop_classic" + "v8.runtimestats.browsing_desktop" ] } }, @@ -1591,29 +1303,27 @@ "build245-m4--device2": { "benchmarks": [ "loading.desktop", - "smoothness.simple_mobile_sites", - "v8.browsing_desktop_classic" + "smoothness.simple_mobile_sites" ] }, "build245-m4--device3": { "benchmarks": [ - "page_cycler_v2.intl_ja_zh", - "v8.runtimestats.browsing_mobile_classic", - "blink_perf.owp_storage" + "blink_perf.owp_storage", + "speedometer-future", + "speedometer2-future", + "wasm" ] }, "build245-m4--device4": { "benchmarks": [ - "blink_perf.blink_gc", - "page_cycler_v2.typical_25", - "v8.infinite_scroll-turbo_tbmv2" + "v8.browsing_desktop-future", + "v8.browsing_mobile-future" ] }, "build245-m4--device5": { "benchmarks": [ "system_health.common_desktop", - "v8.browsing_mobile", - "v8.browsing_mobile_turbo" + "v8.browsing_mobile" ] }, "build245-m4--device6": { @@ -1630,33 +1340,27 @@ "benchmarks": [ "blink_perf.shadow_dom", "dromaeo.domcorequery", - "page_cycler_v2.intl_ko_th_vi", "power.idle_platform", - "smoothness.gpu_rasterization_and_decoding.image_decoding_cases", - "start_with_ext.warm.blank_page", - "v8.browsing_mobile_classic" + "smoothness.gpu_rasterization_and_decoding.image_decoding_cases" ] }, "build248-m4--device1": { "benchmarks": [ "battor.trivial_pages", - "media.tough_video_cases_tbmv2", + "media.desktop", "octane", "smoothness.gpu_rasterization.tough_scrolling_cases", "smoothness.tough_filters_cases", "thread_times.key_hit_test_cases", "thread_times.key_idle_power_cases", - "tracing.tracing_with_debug_overhead", - "v8.infinite_scroll-classic_tbmv2", "v8.runtimestats.browsing_mobile" ] }, "build248-m4--device2": { "benchmarks": [ - "dummy_benchmark.noisy_benchmark_1", "dummy_benchmark.histogram_benchmark_1", + "dummy_benchmark.noisy_benchmark_1", "jetstream", - "page_cycler_v2.intl_hi_ru", "smoothness.tough_texture_upload_cases", "speedometer", "speedometer2" @@ -1669,8 +1373,6 @@ "smoothness.image_decoding_cases", "smoothness.pathological_mobile_sites", "smoothness.tough_pinch_zoom_cases", - "startup.large_profile.cold.blank_page", - "storage.indexeddb_endure_tracing", "v8.detached_context_age_in_gc" ] }, @@ -1678,23 +1380,18 @@ "benchmarks": [ "blink_perf.bindings", "blink_perf.canvas", - "memory.dual_browser_test", - "page_cycler_v2.intl_es_fr_pt-BR", "rasterize_and_record_micro.partial_invalidation", "smoothness.gpu_rasterization.polymer", "start_with_url.cold.startup_pages", - "startup.warm.blank_page", - "startup.warm.chrome_signin", - "system_health.webview_startup", - "v8.browsing_desktop_turbo" + "system_health.webview_startup" ] }, "build248-m4--device5": { "benchmarks": [ "blink_perf.layout", + "dromaeo", "dromaeo.domcoreattr", "oortonline_tbmv2", - "page_cycler_v2.intl_ar_fa_he", "smoothness.maps", "smoothness.tough_webgl_cases", "thread_times.simple_mobile_sites" @@ -1704,35 +1401,22 @@ "benchmarks": [ "battor.steady_state", "blink_perf.svg", - "blob_storage.blob_storage", - "media.android.tough_video_cases", "memory.long_running_idle_gmail_background_tbmv2", - "rasterize_and_record_micro.polymer", "smoothness.gpu_rasterization.top_25_smooth", "smoothness.gpu_rasterization.tough_path_rendering_cases", - "thread_times.key_noop_cases", - "thread_times.polymer", - "v8.mobile_infinite_scroll-turbo_tbmv2", - "v8.runtimestats.browsing_mobile_turbo" + "thread_times.key_noop_cases" ] }, "build248-m4--device7": { "benchmarks": [ - "image_decoding.image_decoding_measurement", - "media.mse_cases", "memory.long_running_idle_gmail_tbmv2", - "smoothness.scrolling_tough_ad_cases", - "speedometer-classic", - "system_health.common_mobile", - "v8.infinite_scroll_tbmv2" + "system_health.common_mobile" ] }, "build249-m4--device1": { "benchmarks": [ "loading.mobile", - "media.android.tough_video_cases_tbmv2", - "media.tough_video_cases", - "service_worker.service_worker", + "media.mobile", "smoothness.tough_webgl_ad_cases", "tab_switching.typical_25", "v8.browsing_desktop" @@ -1742,18 +1426,13 @@ "benchmarks": [ "blink_perf.events", "dummy_benchmark.stable_benchmark_1", - "power.trivial_pages", "smoothness.top_25_smooth", - "smoothness.tough_ad_cases", - "startup.large_profile.warm.blank_page" + "smoothness.tough_ad_cases" ] }, "build249-m4--device3": { "benchmarks": [ "dromaeo.domcoremodify", - "media.media_cns_cases", - "memory.top_10_mobile_stress", - "page_cycler_v2_site_isolation.basic_oopif", "smoothness.key_desktop_move_cases", "smoothness.sync_scroll.key_mobile_sites_smooth", "thread_times.tough_compositor_cases", @@ -1763,13 +1442,8 @@ "build249-m4--device4": { "benchmarks": [ "blink_perf.dom", - "page_cycler_v2.basic_oopif", "rasterize_and_record_micro.top_25", "smoothness.tough_canvas_cases", - "speedometer-turbo", - "start_with_ext.cold.blank_page", - "storage.indexeddb_endure", - "system_health.webview_startup_multiprocess", "thread_times.key_silk_cases" ] }, @@ -1777,114 +1451,81 @@ "benchmarks": [ "blink_perf.css", "blink_perf.parser", - "page_cycler_v2.top_10_mobile", - "rasterize_and_record_micro.key_silk_cases", "scheduler.tough_scheduling_cases", "smoothness.gpu_rasterization.tough_pinch_zoom_cases", "smoothness.tough_image_decode_cases", - "start_with_url.warm.startup_pages", - "v8.mobile_infinite_scroll-classic_tbmv2", - "v8.mobile_infinite_scroll_tbmv2", - "v8.runtimestats.browsing_desktop_turbo" + "start_with_url.warm.startup_pages" ] }, "build249-m4--device6": { "benchmarks": [ "blink_perf.paint", "kraken", - "power.steady_state", "smoothness.key_mobile_sites_smooth", - "startup.cold.blank_page", "tracing.tracing_with_background_memory_infra" ] }, "build249-m4--device7": { "benchmarks": [ - "oortonline", - "rasterize_and_record_micro.key_mobile_sites", - "service_worker.service_worker_micro_benchmark", "smoothness.desktop_tough_pinch_zoom_cases", "smoothness.tough_path_rendering_cases", "smoothness.tough_scrolling_cases", "v8.runtime_stats.top_25", - "v8.runtimestats.browsing_desktop", - "v8.runtimestats.browsing_desktop_classic" + "v8.runtimestats.browsing_desktop" ] } }, "Linux Perf": { - "build148-m1": { + "build27-a9": { "benchmarks": [ "blink_perf.dom", "blink_perf.paint", "dromaeo.domcoremodify", "dummy_benchmark.stable_benchmark_1", - "media.android.tough_video_cases_tbmv2", + "media.mobile", "memory.top_10_mobile", - "oortonline", - "power.trivial_pages", "smoothness.key_desktop_move_cases", "smoothness.key_mobile_sites_smooth", "smoothness.tough_ad_cases", "smoothness.tough_image_decode_cases", - "startup.cold.blank_page", - "startup.large_profile.warm.blank_page", "system_health.memory_desktop", "thread_times.key_mobile_sites_smooth", - "thread_times.key_silk_cases", - "tracing.tracing_with_debug_overhead" + "thread_times.key_silk_cases" ] }, - "build149-m1": { + "build28-a9": { "benchmarks": [ "blink_perf.bindings", - "blink_perf.blink_gc", "blink_perf.canvas", - "blink_perf.owp_storage", "blink_perf.image_decoder", - "dummy_benchmark.noisy_benchmark_1", + "blink_perf.owp_storage", "dummy_benchmark.histogram_benchmark_1", + "dummy_benchmark.noisy_benchmark_1", "loading.desktop", "octane", "oortonline_tbmv2", - "page_cycler_v2.intl_ar_fa_he", "power.idle_platform", - "rasterize_and_record_micro.key_silk_cases", "smoothness.key_silk_cases", "smoothness.pathological_mobile_sites", "smoothness.top_25_smooth", "smoothness.tough_webgl_cases", - "startup.warm.blank_page", - "storage.indexeddb_endure", - "storage.indexeddb_endure_tracing", "system_health.common_mobile", "system_health.memory_mobile", "thread_times.key_hit_test_cases", "thread_times.key_noop_cases", - "thread_times.polymer", "thread_times.tough_scrolling_cases", "tracing.tracing_with_background_memory_infra", "v8.browsing_mobile", - "v8.browsing_mobile_classic", - "v8.mobile_infinite_scroll-turbo_tbmv2", - "v8.mobile_infinite_scroll_tbmv2", - "v8.runtimestats.browsing_mobile_classic", - "v8.runtimestats.browsing_mobile_turbo", "webrtc" ] }, - "build150-m1": { + "build29-a9": { "benchmarks": [ "battor.trivial_pages", "blink_perf.layout", + "dromaeo", "dromaeo.domcoreattr", - "image_decoding.image_decoding_measurement", - "memory.dual_browser_test", "memory.long_running_idle_gmail_background_tbmv2", - "page_cycler_v2.basic_oopif", - "page_cycler_v2.intl_hi_ru", - "page_cycler_v2.intl_ja_zh", - "page_cycler_v2.top_10_mobile", "rasterize_and_record_micro.top_25", "smoothness.gpu_rasterization.polymer", "smoothness.gpu_rasterization.top_25_smooth", @@ -1895,56 +1536,38 @@ "smoothness.tough_path_rendering_cases", "smoothness.tough_scrolling_cases", "speedometer", + "speedometer-future", "speedometer2", - "speedometer-turbo", + "speedometer2-future", "tab_switching.typical_25", "thread_times.tough_compositor_cases", - "v8.browsing_desktop_classic", - "v8.browsing_desktop_turbo", - "v8.infinite_scroll-turbo_tbmv2", - "v8.runtimestats.browsing_desktop_classic", - "v8.runtimestats.browsing_desktop_turbo" + "v8.browsing_desktop-future", + "v8.browsing_mobile-future", + "wasm" ] }, - "build151-m1": { + "build30-a9": { "benchmarks": [ "blink_perf.parser", "blink_perf.svg", - "blob_storage.blob_storage", "dromaeo.domcorequery", "dromaeo.domcoretraverse", "jetstream", - "media.android.tough_video_cases", - "media.media_cns_cases", - "media.tough_video_cases", "memory.desktop", - "page_cycler_v2.intl_es_fr_pt-BR", - "page_cycler_v2.intl_ko_th_vi", - "page_cycler_v2.typical_25", - "power.steady_state", "power.typical_10_mobile", - "rasterize_and_record_micro.polymer", "scheduler.tough_scheduling_cases", - "service_worker.service_worker", - "service_worker.service_worker_micro_benchmark", "smoothness.gpu_rasterization.tough_filters_cases", "smoothness.gpu_rasterization.tough_pinch_zoom_cases", - "smoothness.scrolling_tough_ad_cases", "smoothness.tough_canvas_cases", "smoothness.tough_pinch_zoom_cases", - "speedometer-classic", - "start_with_ext.cold.blank_page", "start_with_url.cold.startup_pages", - "startup.warm.chrome_signin", - "system_health.webview_startup_multiprocess", "v8.browsing_desktop", "v8.detached_context_age_in_gc", - "v8.mobile_infinite_scroll-classic_tbmv2", "v8.runtime_stats.top_25", "v8.runtimestats.browsing_desktop" ] }, - "build152-m1": { + "build31-a9": { "benchmarks": [ "battor.steady_state", "blink_perf.css", @@ -1952,12 +1575,8 @@ "blink_perf.shadow_dom", "kraken", "loading.mobile", - "media.mse_cases", - "media.tough_video_cases_tbmv2", + "media.desktop", "memory.long_running_idle_gmail_tbmv2", - "memory.top_10_mobile_stress", - "page_cycler_v2_site_isolation.basic_oopif", - "rasterize_and_record_micro.key_mobile_sites", "rasterize_and_record_micro.partial_invalidation", "smoothness.desktop_tough_pinch_zoom_cases", "smoothness.gpu_rasterization.tough_path_rendering_cases", @@ -1967,16 +1586,11 @@ "smoothness.tough_animation_cases", "smoothness.tough_texture_upload_cases", "smoothness.tough_webgl_ad_cases", - "start_with_ext.warm.blank_page", "start_with_url.warm.startup_pages", - "startup.large_profile.cold.blank_page", "system_health.common_desktop", "system_health.webview_startup", "thread_times.key_idle_power_cases", "thread_times.simple_mobile_sites", - "v8.browsing_mobile_turbo", - "v8.infinite_scroll-classic_tbmv2", - "v8.infinite_scroll_tbmv2", "v8.runtimestats.browsing_mobile" ] } @@ -1988,60 +1602,41 @@ "blink_perf.paint", "dromaeo.domcoremodify", "dummy_benchmark.stable_benchmark_1", - "media.android.tough_video_cases_tbmv2", - "media.tough_video_cases", + "media.mobile", "memory.top_10_mobile", - "oortonline", - "power.trivial_pages", "scheduler.tough_scheduling_cases", "smoothness.key_desktop_move_cases", "smoothness.key_mobile_sites_smooth", "smoothness.tough_ad_cases", "smoothness.tough_image_decode_cases", - "startup.cold.blank_page", - "startup.large_profile.warm.blank_page", "system_health.memory_desktop", "thread_times.key_mobile_sites_smooth", "thread_times.key_silk_cases", - "tracing.tracing_with_debug_overhead", "v8.runtime_stats.top_25" ] }, "build103-b1": { "benchmarks": [ "blink_perf.bindings", - "blink_perf.blink_gc", "blink_perf.canvas", - "blink_perf.owp_storage", "blink_perf.image_decoder", - "dummy_benchmark.noisy_benchmark_1", + "blink_perf.owp_storage", "dummy_benchmark.histogram_benchmark_1", + "dummy_benchmark.noisy_benchmark_1", "loading.desktop", "octane", "oortonline_tbmv2", - "page_cycler_v2.basic_oopif", - "page_cycler_v2.intl_ar_fa_he", "power.idle_platform", - "rasterize_and_record_micro.key_silk_cases", "smoothness.key_silk_cases", "smoothness.pathological_mobile_sites", "smoothness.top_25_smooth", "smoothness.tough_webgl_cases", - "startup.warm.blank_page", - "storage.indexeddb_endure", - "storage.indexeddb_endure_tracing", "system_health.common_mobile", "system_health.memory_mobile", "thread_times.key_hit_test_cases", "thread_times.key_noop_cases", - "thread_times.polymer", "tracing.tracing_with_background_memory_infra", "v8.browsing_mobile", - "v8.browsing_mobile_classic", - "v8.mobile_infinite_scroll-turbo_tbmv2", - "v8.mobile_infinite_scroll_tbmv2", - "v8.runtimestats.browsing_mobile_classic", - "v8.runtimestats.browsing_mobile_turbo", "webrtc" ] }, @@ -2049,13 +1644,9 @@ "benchmarks": [ "battor.trivial_pages", "blink_perf.layout", + "dromaeo", "dromaeo.domcoreattr", - "image_decoding.image_decoding_measurement", - "memory.dual_browser_test", "memory.long_running_idle_gmail_background_tbmv2", - "page_cycler_v2.intl_hi_ru", - "page_cycler_v2.intl_ja_zh", - "page_cycler_v2.top_10_mobile", "rasterize_and_record_micro.top_25", "smoothness.gpu_rasterization.polymer", "smoothness.gpu_rasterization.top_25_smooth", @@ -2067,49 +1658,32 @@ "smoothness.tough_scrolling_cases", "speedometer", "speedometer2", - "speedometer-turbo", "tab_switching.typical_25", "thread_times.tough_compositor_cases", - "v8.browsing_desktop_classic", - "v8.browsing_desktop_turbo", - "v8.infinite_scroll-turbo_tbmv2", - "v8.runtimestats.browsing_desktop_classic", - "v8.runtimestats.browsing_desktop_turbo" + "v8.browsing_desktop-future", + "v8.browsing_mobile-future", + "wasm" ] }, "build105-b1": { "benchmarks": [ "blink_perf.parser", "blink_perf.svg", - "blob_storage.blob_storage", "dromaeo.domcorequery", "dromaeo.domcoretraverse", "jetstream", - "media.android.tough_video_cases", - "media.media_cns_cases", "memory.desktop", - "page_cycler_v2.intl_es_fr_pt-BR", - "page_cycler_v2.intl_ko_th_vi", - "page_cycler_v2.typical_25", - "power.steady_state", "power.typical_10_mobile", - "rasterize_and_record_micro.polymer", - "service_worker.service_worker", - "service_worker.service_worker_micro_benchmark", "smoothness.gpu_rasterization.tough_filters_cases", "smoothness.gpu_rasterization.tough_pinch_zoom_cases", - "smoothness.scrolling_tough_ad_cases", "smoothness.tough_canvas_cases", "smoothness.tough_pinch_zoom_cases", - "speedometer-classic", - "start_with_ext.cold.blank_page", + "speedometer-future", + "speedometer2-future", "start_with_url.cold.startup_pages", - "startup.warm.chrome_signin", - "system_health.webview_startup_multiprocess", "thread_times.tough_scrolling_cases", "v8.browsing_desktop", "v8.detached_context_age_in_gc", - "v8.mobile_infinite_scroll-classic_tbmv2", "v8.runtimestats.browsing_desktop" ] }, @@ -2121,12 +1695,8 @@ "blink_perf.shadow_dom", "kraken", "loading.mobile", - "media.mse_cases", - "media.tough_video_cases_tbmv2", + "media.desktop", "memory.long_running_idle_gmail_tbmv2", - "memory.top_10_mobile_stress", - "page_cycler_v2_site_isolation.basic_oopif", - "rasterize_and_record_micro.key_mobile_sites", "rasterize_and_record_micro.partial_invalidation", "smoothness.desktop_tough_pinch_zoom_cases", "smoothness.gpu_rasterization.tough_path_rendering_cases", @@ -2136,16 +1706,11 @@ "smoothness.tough_animation_cases", "smoothness.tough_texture_upload_cases", "smoothness.tough_webgl_ad_cases", - "start_with_ext.warm.blank_page", "start_with_url.warm.startup_pages", - "startup.large_profile.cold.blank_page", "system_health.common_desktop", "system_health.webview_startup", "thread_times.key_idle_power_cases", "thread_times.simple_mobile_sites", - "v8.browsing_mobile_turbo", - "v8.infinite_scroll-classic_tbmv2", - "v8.infinite_scroll_tbmv2", "v8.runtimestats.browsing_mobile" ] } @@ -2157,75 +1722,52 @@ "blink_perf.paint", "dromaeo.domcoremodify", "dummy_benchmark.stable_benchmark_1", - "media.android.tough_video_cases_tbmv2", - "media.tough_video_cases", + "media.mobile", "memory.top_10_mobile", - "oortonline", - "power.trivial_pages", "scheduler.tough_scheduling_cases", "smoothness.key_desktop_move_cases", "smoothness.key_mobile_sites_smooth", "smoothness.tough_ad_cases", "smoothness.tough_image_decode_cases", - "startup.cold.blank_page", - "startup.large_profile.warm.blank_page", "system_health.memory_desktop", "thread_times.key_mobile_sites_smooth", "thread_times.key_silk_cases", - "tracing.tracing_with_debug_overhead", "v8.runtime_stats.top_25" ] }, "build159-m1": { "benchmarks": [ "blink_perf.bindings", - "blink_perf.blink_gc", "blink_perf.canvas", - "blink_perf.owp_storage", "blink_perf.image_decoder", - "dummy_benchmark.noisy_benchmark_1", + "blink_perf.owp_storage", "dummy_benchmark.histogram_benchmark_1", + "dummy_benchmark.noisy_benchmark_1", "loading.desktop", "octane", "oortonline_tbmv2", - "page_cycler_v2.basic_oopif", - "page_cycler_v2.intl_ar_fa_he", "power.idle_platform", - "rasterize_and_record_micro.key_silk_cases", "smoothness.key_silk_cases", "smoothness.pathological_mobile_sites", "smoothness.top_25_smooth", "smoothness.tough_webgl_cases", - "startup.warm.blank_page", - "storage.indexeddb_endure", - "storage.indexeddb_endure_tracing", "system_health.common_mobile", "system_health.memory_mobile", "thread_times.key_hit_test_cases", "thread_times.key_noop_cases", - "thread_times.polymer", "thread_times.tough_scrolling_cases", "tracing.tracing_with_background_memory_infra", "v8.browsing_mobile", - "v8.browsing_mobile_classic", - "v8.mobile_infinite_scroll-turbo_tbmv2", - "v8.mobile_infinite_scroll_tbmv2", - "v8.runtimestats.browsing_desktop", - "v8.runtimestats.browsing_mobile_classic", - "v8.runtimestats.browsing_mobile_turbo" + "v8.runtimestats.browsing_desktop" ] }, "build160-m1": { "benchmarks": [ "battor.trivial_pages", "blink_perf.layout", + "dromaeo", "dromaeo.domcoreattr", - "image_decoding.image_decoding_measurement", - "memory.dual_browser_test", "memory.long_running_idle_gmail_background_tbmv2", - "page_cycler_v2.intl_hi_ru", - "page_cycler_v2.intl_ja_zh", - "page_cycler_v2.top_10_mobile", "rasterize_and_record_micro.top_25", "smoothness.gpu_rasterization.polymer", "smoothness.gpu_rasterization.top_25_smooth", @@ -2237,14 +1779,11 @@ "smoothness.tough_scrolling_cases", "speedometer", "speedometer2", - "speedometer-turbo", "tab_switching.typical_25", "thread_times.tough_compositor_cases", - "v8.browsing_desktop_classic", - "v8.browsing_desktop_turbo", - "v8.infinite_scroll-turbo_tbmv2", - "v8.runtimestats.browsing_desktop_classic", - "v8.runtimestats.browsing_desktop_turbo", + "v8.browsing_desktop-future", + "v8.browsing_mobile-future", + "wasm", "webrtc" ] }, @@ -2252,34 +1791,20 @@ "benchmarks": [ "blink_perf.parser", "blink_perf.svg", - "blob_storage.blob_storage", "dromaeo.domcorequery", "dromaeo.domcoretraverse", "jetstream", - "media.android.tough_video_cases", - "media.media_cns_cases", "memory.desktop", - "page_cycler_v2.intl_es_fr_pt-BR", - "page_cycler_v2.intl_ko_th_vi", - "page_cycler_v2.typical_25", - "power.steady_state", "power.typical_10_mobile", - "rasterize_and_record_micro.polymer", - "service_worker.service_worker", - "service_worker.service_worker_micro_benchmark", "smoothness.gpu_rasterization.tough_filters_cases", "smoothness.gpu_rasterization.tough_pinch_zoom_cases", - "smoothness.scrolling_tough_ad_cases", "smoothness.tough_canvas_cases", "smoothness.tough_pinch_zoom_cases", - "speedometer-classic", - "start_with_ext.cold.blank_page", + "speedometer-future", + "speedometer2-future", "start_with_url.cold.startup_pages", - "startup.warm.chrome_signin", - "system_health.webview_startup_multiprocess", "v8.browsing_desktop", - "v8.detached_context_age_in_gc", - "v8.mobile_infinite_scroll-classic_tbmv2" + "v8.detached_context_age_in_gc" ] }, "build162-m1": { @@ -2290,12 +1815,8 @@ "blink_perf.shadow_dom", "kraken", "loading.mobile", - "media.mse_cases", - "media.tough_video_cases_tbmv2", + "media.desktop", "memory.long_running_idle_gmail_tbmv2", - "memory.top_10_mobile_stress", - "page_cycler_v2_site_isolation.basic_oopif", - "rasterize_and_record_micro.key_mobile_sites", "rasterize_and_record_micro.partial_invalidation", "smoothness.desktop_tough_pinch_zoom_cases", "smoothness.gpu_rasterization.tough_path_rendering_cases", @@ -2305,16 +1826,11 @@ "smoothness.tough_animation_cases", "smoothness.tough_texture_upload_cases", "smoothness.tough_webgl_ad_cases", - "start_with_ext.warm.blank_page", "start_with_url.warm.startup_pages", - "startup.large_profile.cold.blank_page", "system_health.common_desktop", "system_health.webview_startup", "thread_times.key_idle_power_cases", "thread_times.simple_mobile_sites", - "v8.browsing_mobile_turbo", - "v8.infinite_scroll-classic_tbmv2", - "v8.infinite_scroll_tbmv2", "v8.runtimestats.browsing_mobile" ] } @@ -2326,74 +1842,51 @@ "blink_perf.paint", "dromaeo.domcoremodify", "dummy_benchmark.stable_benchmark_1", - "media.android.tough_video_cases_tbmv2", - "media.tough_video_cases", + "media.mobile", "memory.top_10_mobile", - "oortonline", - "power.trivial_pages", "scheduler.tough_scheduling_cases", "smoothness.key_desktop_move_cases", "smoothness.key_mobile_sites_smooth", "smoothness.tough_ad_cases", "smoothness.tough_image_decode_cases", - "startup.cold.blank_page", - "startup.large_profile.warm.blank_page", "system_health.memory_desktop", "thread_times.key_mobile_sites_smooth", - "thread_times.key_silk_cases", - "tracing.tracing_with_debug_overhead" + "thread_times.key_silk_cases" ] }, "build124-b1": { "benchmarks": [ "blink_perf.bindings", - "blink_perf.blink_gc", "blink_perf.canvas", - "blink_perf.owp_storage", "blink_perf.image_decoder", - "dummy_benchmark.noisy_benchmark_1", + "blink_perf.owp_storage", "dummy_benchmark.histogram_benchmark_1", + "dummy_benchmark.noisy_benchmark_1", "loading.desktop", "octane", "oortonline_tbmv2", - "page_cycler_v2.basic_oopif", - "page_cycler_v2.intl_ar_fa_he", "power.idle_platform", - "rasterize_and_record_micro.key_silk_cases", "smoothness.key_silk_cases", "smoothness.pathological_mobile_sites", "smoothness.top_25_smooth", "smoothness.tough_webgl_cases", - "startup.warm.blank_page", - "storage.indexeddb_endure", - "storage.indexeddb_endure_tracing", "system_health.common_mobile", "system_health.memory_mobile", "thread_times.key_hit_test_cases", "thread_times.key_noop_cases", - "thread_times.polymer", "thread_times.tough_scrolling_cases", "tracing.tracing_with_background_memory_infra", "v8.browsing_mobile", - "v8.browsing_mobile_classic", - "v8.mobile_infinite_scroll-turbo_tbmv2", - "v8.mobile_infinite_scroll_tbmv2", - "v8.runtimestats.browsing_desktop", - "v8.runtimestats.browsing_mobile_classic", - "v8.runtimestats.browsing_mobile_turbo" + "v8.runtimestats.browsing_desktop" ] }, "build125-b1": { "benchmarks": [ "battor.trivial_pages", "blink_perf.layout", + "dromaeo", "dromaeo.domcoreattr", - "image_decoding.image_decoding_measurement", - "memory.dual_browser_test", "memory.long_running_idle_gmail_background_tbmv2", - "page_cycler_v2.intl_hi_ru", - "page_cycler_v2.intl_ja_zh", - "page_cycler_v2.top_10_mobile", "rasterize_and_record_micro.top_25", "smoothness.gpu_rasterization.polymer", "smoothness.gpu_rasterization.top_25_smooth", @@ -2405,49 +1898,32 @@ "smoothness.tough_scrolling_cases", "speedometer", "speedometer2", - "speedometer-turbo", "tab_switching.typical_25", "thread_times.tough_compositor_cases", - "v8.browsing_desktop_classic", - "v8.browsing_desktop_turbo", - "v8.infinite_scroll-turbo_tbmv2", + "v8.browsing_desktop-future", + "v8.browsing_mobile-future", "v8.runtime_stats.top_25", - "v8.runtimestats.browsing_desktop_classic", - "v8.runtimestats.browsing_desktop_turbo" + "wasm" ] }, "build126-b1": { "benchmarks": [ "blink_perf.parser", "blink_perf.svg", - "blob_storage.blob_storage", "dromaeo.domcorequery", "dromaeo.domcoretraverse", "jetstream", - "media.android.tough_video_cases", - "media.media_cns_cases", "memory.desktop", - "page_cycler_v2.intl_es_fr_pt-BR", - "page_cycler_v2.intl_ko_th_vi", - "page_cycler_v2.typical_25", - "power.steady_state", "power.typical_10_mobile", - "rasterize_and_record_micro.polymer", - "service_worker.service_worker", - "service_worker.service_worker_micro_benchmark", "smoothness.gpu_rasterization.tough_filters_cases", "smoothness.gpu_rasterization.tough_pinch_zoom_cases", - "smoothness.scrolling_tough_ad_cases", "smoothness.tough_canvas_cases", "smoothness.tough_pinch_zoom_cases", - "speedometer-classic", - "start_with_ext.cold.blank_page", + "speedometer-future", + "speedometer2-future", "start_with_url.cold.startup_pages", - "startup.warm.chrome_signin", - "system_health.webview_startup_multiprocess", "v8.browsing_desktop", "v8.detached_context_age_in_gc", - "v8.mobile_infinite_scroll-classic_tbmv2", "webrtc" ] }, @@ -2459,12 +1935,8 @@ "blink_perf.shadow_dom", "kraken", "loading.mobile", - "media.mse_cases", - "media.tough_video_cases_tbmv2", + "media.desktop", "memory.long_running_idle_gmail_tbmv2", - "memory.top_10_mobile_stress", - "page_cycler_v2_site_isolation.basic_oopif", - "rasterize_and_record_micro.key_mobile_sites", "rasterize_and_record_micro.partial_invalidation", "smoothness.desktop_tough_pinch_zoom_cases", "smoothness.gpu_rasterization.tough_path_rendering_cases", @@ -2474,185 +1946,11 @@ "smoothness.tough_animation_cases", "smoothness.tough_texture_upload_cases", "smoothness.tough_webgl_ad_cases", - "start_with_ext.warm.blank_page", "start_with_url.warm.startup_pages", - "startup.large_profile.cold.blank_page", "system_health.common_desktop", "system_health.webview_startup", "thread_times.key_idle_power_cases", "thread_times.simple_mobile_sites", - "v8.browsing_mobile_turbo", - "v8.infinite_scroll-classic_tbmv2", - "v8.infinite_scroll_tbmv2", - "v8.runtimestats.browsing_mobile" - ] - } - }, - "Mac Mini 8GB 10.12 Perf": { - "build24-b1": { - "benchmarks": [ - "blink_perf.dom", - "blink_perf.paint", - "dromaeo.domcoremodify", - "dummy_benchmark.stable_benchmark_1", - "media.android.tough_video_cases_tbmv2", - "media.tough_video_cases", - "memory.top_10_mobile", - "oortonline", - "power.trivial_pages", - "scheduler.tough_scheduling_cases", - "smoothness.key_desktop_move_cases", - "smoothness.key_mobile_sites_smooth", - "smoothness.tough_ad_cases", - "smoothness.tough_image_decode_cases", - "startup.cold.blank_page", - "startup.large_profile.warm.blank_page", - "system_health.memory_desktop", - "thread_times.key_mobile_sites_smooth", - "thread_times.key_silk_cases", - "tracing.tracing_with_debug_overhead", - "v8.runtime_stats.top_25" - ] - }, - "build25-b1": { - "benchmarks": [ - "blink_perf.bindings", - "blink_perf.blink_gc", - "blink_perf.canvas", - "blink_perf.owp_storage", - "blink_perf.image_decoder", - "dummy_benchmark.noisy_benchmark_1", - "dummy_benchmark.histogram_benchmark_1", - "loading.desktop", - "octane", - "oortonline_tbmv2", - "page_cycler_v2.basic_oopif", - "page_cycler_v2.intl_ar_fa_he", - "power.idle_platform", - "rasterize_and_record_micro.key_silk_cases", - "smoothness.key_silk_cases", - "smoothness.pathological_mobile_sites", - "smoothness.top_25_smooth", - "smoothness.tough_webgl_cases", - "startup.warm.blank_page", - "storage.indexeddb_endure", - "storage.indexeddb_endure_tracing", - "system_health.common_mobile", - "system_health.memory_mobile", - "thread_times.key_hit_test_cases", - "thread_times.key_noop_cases", - "thread_times.polymer", - "thread_times.tough_scrolling_cases", - "tracing.tracing_with_background_memory_infra", - "v8.browsing_mobile", - "v8.browsing_mobile_classic", - "v8.mobile_infinite_scroll-turbo_tbmv2", - "v8.mobile_infinite_scroll_tbmv2", - "v8.runtimestats.browsing_desktop", - "v8.runtimestats.browsing_mobile_classic", - "v8.runtimestats.browsing_mobile_turbo" - ] - }, - "build26-b1": { - "benchmarks": [ - "battor.trivial_pages", - "blink_perf.layout", - "dromaeo.domcoreattr", - "image_decoding.image_decoding_measurement", - "memory.dual_browser_test", - "memory.long_running_idle_gmail_background_tbmv2", - "page_cycler_v2.intl_hi_ru", - "page_cycler_v2.intl_ja_zh", - "page_cycler_v2.top_10_mobile", - "rasterize_and_record_micro.top_25", - "smoothness.gpu_rasterization.polymer", - "smoothness.gpu_rasterization.top_25_smooth", - "smoothness.gpu_rasterization_and_decoding.image_decoding_cases", - "smoothness.image_decoding_cases", - "smoothness.simple_mobile_sites", - "smoothness.tough_filters_cases", - "smoothness.tough_path_rendering_cases", - "smoothness.tough_scrolling_cases", - "speedometer", - "speedometer2", - "speedometer-turbo", - "tab_switching.typical_25", - "thread_times.tough_compositor_cases", - "v8.browsing_desktop_classic", - "v8.browsing_desktop_turbo", - "v8.infinite_scroll-turbo_tbmv2", - "v8.runtimestats.browsing_desktop_classic", - "v8.runtimestats.browsing_desktop_turbo" - ] - }, - "build27-b1": { - "benchmarks": [ - "blink_perf.parser", - "blink_perf.svg", - "blob_storage.blob_storage", - "dromaeo.domcorequery", - "dromaeo.domcoretraverse", - "jetstream", - "media.android.tough_video_cases", - "media.media_cns_cases", - "memory.desktop", - "page_cycler_v2.intl_es_fr_pt-BR", - "page_cycler_v2.intl_ko_th_vi", - "page_cycler_v2.typical_25", - "power.steady_state", - "power.typical_10_mobile", - "rasterize_and_record_micro.polymer", - "service_worker.service_worker", - "service_worker.service_worker_micro_benchmark", - "smoothness.gpu_rasterization.tough_filters_cases", - "smoothness.gpu_rasterization.tough_pinch_zoom_cases", - "smoothness.scrolling_tough_ad_cases", - "smoothness.tough_canvas_cases", - "smoothness.tough_pinch_zoom_cases", - "speedometer-classic", - "start_with_ext.cold.blank_page", - "start_with_url.cold.startup_pages", - "startup.warm.chrome_signin", - "system_health.webview_startup_multiprocess", - "v8.browsing_desktop", - "v8.detached_context_age_in_gc", - "v8.mobile_infinite_scroll-classic_tbmv2", - "webrtc" - ] - }, - "build28-b1": { - "benchmarks": [ - "battor.steady_state", - "blink_perf.css", - "blink_perf.events", - "blink_perf.shadow_dom", - "kraken", - "loading.mobile", - "media.mse_cases", - "media.tough_video_cases_tbmv2", - "memory.long_running_idle_gmail_tbmv2", - "memory.top_10_mobile_stress", - "page_cycler_v2_site_isolation.basic_oopif", - "rasterize_and_record_micro.key_mobile_sites", - "rasterize_and_record_micro.partial_invalidation", - "smoothness.desktop_tough_pinch_zoom_cases", - "smoothness.gpu_rasterization.tough_path_rendering_cases", - "smoothness.gpu_rasterization.tough_scrolling_cases", - "smoothness.maps", - "smoothness.sync_scroll.key_mobile_sites_smooth", - "smoothness.tough_animation_cases", - "smoothness.tough_texture_upload_cases", - "smoothness.tough_webgl_ad_cases", - "start_with_ext.warm.blank_page", - "start_with_url.warm.startup_pages", - "startup.large_profile.cold.blank_page", - "system_health.common_desktop", - "system_health.webview_startup", - "thread_times.key_idle_power_cases", - "thread_times.simple_mobile_sites", - "v8.browsing_mobile_turbo", - "v8.infinite_scroll-classic_tbmv2", - "v8.infinite_scroll_tbmv2", "v8.runtimestats.browsing_mobile" ] } @@ -2664,61 +1962,42 @@ "blink_perf.paint", "dromaeo.domcoremodify", "dummy_benchmark.stable_benchmark_1", - "media.android.tough_video_cases_tbmv2", - "media.tough_video_cases", + "media.mobile", "memory.top_10_mobile", - "oortonline", - "power.trivial_pages", "scheduler.tough_scheduling_cases", "smoothness.key_desktop_move_cases", "smoothness.key_mobile_sites_smooth", "smoothness.tough_ad_cases", "smoothness.tough_image_decode_cases", - "startup.cold.blank_page", - "startup.large_profile.warm.blank_page", "system_health.memory_desktop", "thread_times.key_mobile_sites_smooth", "thread_times.key_silk_cases", - "tracing.tracing_with_debug_overhead", "v8.runtime_stats.top_25" ] }, "build129-b1": { "benchmarks": [ "blink_perf.bindings", - "blink_perf.blink_gc", "blink_perf.canvas", - "blink_perf.owp_storage", "blink_perf.image_decoder", - "dummy_benchmark.noisy_benchmark_1", + "blink_perf.owp_storage", "dummy_benchmark.histogram_benchmark_1", + "dummy_benchmark.noisy_benchmark_1", "loading.desktop", "octane", "oortonline_tbmv2", - "page_cycler_v2.basic_oopif", - "page_cycler_v2.intl_ar_fa_he", "power.idle_platform", - "rasterize_and_record_micro.key_silk_cases", "smoothness.key_silk_cases", "smoothness.pathological_mobile_sites", "smoothness.top_25_smooth", "smoothness.tough_webgl_cases", - "startup.warm.blank_page", - "storage.indexeddb_endure", - "storage.indexeddb_endure_tracing", "system_health.common_mobile", "system_health.memory_mobile", "thread_times.key_hit_test_cases", "thread_times.key_noop_cases", - "thread_times.polymer", "thread_times.tough_scrolling_cases", "tracing.tracing_with_background_memory_infra", "v8.browsing_mobile", - "v8.browsing_mobile_classic", - "v8.mobile_infinite_scroll-turbo_tbmv2", - "v8.mobile_infinite_scroll_tbmv2", - "v8.runtimestats.browsing_mobile_classic", - "v8.runtimestats.browsing_mobile_turbo", "webrtc" ] }, @@ -2726,13 +2005,9 @@ "benchmarks": [ "battor.trivial_pages", "blink_perf.layout", + "dromaeo", "dromaeo.domcoreattr", - "image_decoding.image_decoding_measurement", - "memory.dual_browser_test", "memory.long_running_idle_gmail_background_tbmv2", - "page_cycler_v2.intl_hi_ru", - "page_cycler_v2.intl_ja_zh", - "page_cycler_v2.top_10_mobile", "rasterize_and_record_micro.top_25", "smoothness.gpu_rasterization.polymer", "smoothness.gpu_rasterization.top_25_smooth", @@ -2744,48 +2019,31 @@ "smoothness.tough_scrolling_cases", "speedometer", "speedometer2", - "speedometer-turbo", "tab_switching.typical_25", "thread_times.tough_compositor_cases", - "v8.browsing_desktop_classic", - "v8.browsing_desktop_turbo", - "v8.infinite_scroll-turbo_tbmv2", - "v8.runtimestats.browsing_desktop_classic", - "v8.runtimestats.browsing_desktop_turbo" + "v8.browsing_desktop-future", + "v8.browsing_mobile-future", + "wasm" ] }, "build131-b1": { "benchmarks": [ "blink_perf.parser", "blink_perf.svg", - "blob_storage.blob_storage", "dromaeo.domcorequery", "dromaeo.domcoretraverse", "jetstream", - "media.android.tough_video_cases", - "media.media_cns_cases", "memory.desktop", - "page_cycler_v2.intl_es_fr_pt-BR", - "page_cycler_v2.intl_ko_th_vi", - "page_cycler_v2.typical_25", - "power.steady_state", "power.typical_10_mobile", - "rasterize_and_record_micro.polymer", - "service_worker.service_worker", - "service_worker.service_worker_micro_benchmark", "smoothness.gpu_rasterization.tough_filters_cases", "smoothness.gpu_rasterization.tough_pinch_zoom_cases", - "smoothness.scrolling_tough_ad_cases", "smoothness.tough_canvas_cases", "smoothness.tough_pinch_zoom_cases", - "speedometer-classic", - "start_with_ext.cold.blank_page", + "speedometer-future", + "speedometer2-future", "start_with_url.cold.startup_pages", - "startup.warm.chrome_signin", - "system_health.webview_startup_multiprocess", "v8.browsing_desktop", "v8.detached_context_age_in_gc", - "v8.mobile_infinite_scroll-classic_tbmv2", "v8.runtimestats.browsing_desktop" ] }, @@ -2797,12 +2055,8 @@ "blink_perf.shadow_dom", "kraken", "loading.mobile", - "media.mse_cases", - "media.tough_video_cases_tbmv2", + "media.desktop", "memory.long_running_idle_gmail_tbmv2", - "memory.top_10_mobile_stress", - "page_cycler_v2_site_isolation.basic_oopif", - "rasterize_and_record_micro.key_mobile_sites", "rasterize_and_record_micro.partial_invalidation", "smoothness.desktop_tough_pinch_zoom_cases", "smoothness.gpu_rasterization.tough_path_rendering_cases", @@ -2812,16 +2066,11 @@ "smoothness.tough_animation_cases", "smoothness.tough_texture_upload_cases", "smoothness.tough_webgl_ad_cases", - "start_with_ext.warm.blank_page", "start_with_url.warm.startup_pages", - "startup.large_profile.cold.blank_page", "system_health.common_desktop", "system_health.webview_startup", "thread_times.key_idle_power_cases", "thread_times.simple_mobile_sites", - "v8.browsing_mobile_turbo", - "v8.infinite_scroll-classic_tbmv2", - "v8.infinite_scroll_tbmv2", "v8.runtimestats.browsing_mobile" ] } @@ -2835,12 +2084,8 @@ "blink_perf.shadow_dom", "kraken", "loading.mobile", - "media.mse_cases", - "media.tough_video_cases_tbmv2", + "media.desktop", "memory.long_running_idle_gmail_tbmv2", - "memory.top_10_mobile_stress", - "page_cycler_v2_site_isolation.basic_oopif", - "rasterize_and_record_micro.key_mobile_sites", "rasterize_and_record_micro.partial_invalidation", "smoothness.desktop_tough_pinch_zoom_cases", "smoothness.gpu_rasterization.tough_path_rendering_cases", @@ -2850,16 +2095,11 @@ "smoothness.tough_animation_cases", "smoothness.tough_texture_upload_cases", "smoothness.tough_webgl_ad_cases", - "start_with_ext.warm.blank_page", "start_with_url.warm.startup_pages", - "startup.large_profile.cold.blank_page", "system_health.common_desktop", "system_health.webview_startup", "thread_times.key_idle_power_cases", "thread_times.simple_mobile_sites", - "v8.browsing_mobile_turbo", - "v8.infinite_scroll-classic_tbmv2", - "v8.infinite_scroll_tbmv2", "v8.runtimestats.browsing_mobile" ] }, @@ -2869,62 +2109,46 @@ "blink_perf.paint", "dromaeo.domcoremodify", "dummy_benchmark.stable_benchmark_1", - "media.android.tough_video_cases_tbmv2", - "media.tough_video_cases", + "media.mobile", "memory.top_10_mobile", - "oortonline", - "power.trivial_pages", "scheduler.tough_scheduling_cases", "smoothness.key_desktop_move_cases", "smoothness.key_mobile_sites_smooth", "smoothness.tough_ad_cases", "smoothness.tough_image_decode_cases", - "startup.cold.blank_page", - "startup.large_profile.warm.blank_page", "system_health.memory_desktop", "thread_times.key_mobile_sites_smooth", "thread_times.key_silk_cases", - "tracing.tracing_with_debug_overhead", "v8.runtime_stats.top_25" ] }, "build5-b1": { "benchmarks": [ "blink_perf.bindings", - "blink_perf.blink_gc", "blink_perf.canvas", - "blink_perf.owp_storage", "blink_perf.image_decoder", - "dummy_benchmark.noisy_benchmark_1", + "blink_perf.owp_storage", "dummy_benchmark.histogram_benchmark_1", + "dummy_benchmark.noisy_benchmark_1", "loading.desktop", "octane", "oortonline_tbmv2", - "page_cycler_v2.basic_oopif", - "page_cycler_v2.intl_ar_fa_he", "power.idle_platform", - "rasterize_and_record_micro.key_silk_cases", "smoothness.key_silk_cases", "smoothness.pathological_mobile_sites", "smoothness.top_25_smooth", "smoothness.tough_webgl_cases", - "startup.warm.blank_page", - "storage.indexeddb_endure", - "storage.indexeddb_endure_tracing", "system_health.common_mobile", "system_health.memory_mobile", "thread_times.key_hit_test_cases", "thread_times.key_noop_cases", - "thread_times.polymer", "thread_times.tough_scrolling_cases", "tracing.tracing_with_background_memory_infra", + "v8.browsing_desktop-future", + "v8.browsing_mobile-future", "v8.browsing_mobile", - "v8.browsing_mobile_classic", - "v8.mobile_infinite_scroll-turbo_tbmv2", - "v8.mobile_infinite_scroll_tbmv2", "v8.runtimestats.browsing_desktop", - "v8.runtimestats.browsing_mobile_classic", - "v8.runtimestats.browsing_mobile_turbo", + "wasm", "webrtc" ] }, @@ -2932,13 +2156,9 @@ "benchmarks": [ "battor.trivial_pages", "blink_perf.layout", + "dromaeo", "dromaeo.domcoreattr", - "image_decoding.image_decoding_measurement", - "memory.dual_browser_test", "memory.long_running_idle_gmail_background_tbmv2", - "page_cycler_v2.intl_hi_ru", - "page_cycler_v2.intl_ja_zh", - "page_cycler_v2.top_10_mobile", "rasterize_and_record_micro.top_25", "smoothness.gpu_rasterization.polymer", "smoothness.gpu_rasterization.top_25_smooth", @@ -2950,285 +2170,36 @@ "smoothness.tough_scrolling_cases", "speedometer", "speedometer2", - "speedometer-turbo", "tab_switching.typical_25", - "thread_times.tough_compositor_cases", - "v8.browsing_desktop_classic", - "v8.browsing_desktop_turbo", - "v8.infinite_scroll-turbo_tbmv2", - "v8.runtimestats.browsing_desktop_classic", - "v8.runtimestats.browsing_desktop_turbo" + "thread_times.tough_compositor_cases" ] }, "build7-b1": { "benchmarks": [ "blink_perf.parser", "blink_perf.svg", - "blob_storage.blob_storage", "dromaeo.domcorequery", "dromaeo.domcoretraverse", "jetstream", - "media.android.tough_video_cases", - "media.media_cns_cases", "memory.desktop", - "page_cycler_v2.intl_es_fr_pt-BR", - "page_cycler_v2.intl_ko_th_vi", - "page_cycler_v2.typical_25", - "power.steady_state", "power.typical_10_mobile", - "rasterize_and_record_micro.polymer", - "service_worker.service_worker", - "service_worker.service_worker_micro_benchmark", "smoothness.gpu_rasterization.tough_filters_cases", "smoothness.gpu_rasterization.tough_pinch_zoom_cases", - "smoothness.scrolling_tough_ad_cases", "smoothness.tough_canvas_cases", "smoothness.tough_pinch_zoom_cases", - "speedometer-classic", - "start_with_ext.cold.blank_page", + "speedometer-future", + "speedometer2-future", "start_with_url.cold.startup_pages", - "startup.warm.chrome_signin", - "system_health.webview_startup_multiprocess", "v8.browsing_desktop", - "v8.detached_context_age_in_gc", - "v8.mobile_infinite_scroll-classic_tbmv2" + "v8.detached_context_age_in_gc" ] } }, - "Win 10 4 Core Low-End Perf Tests": { - "build136-b1": { - "benchmarks": [ - "rasterize_and_record_micro.key_silk_cases", - "smoothness.simple_mobile_sites", - "system_health.memory_desktop", - "v8.mobile_infinite_scroll-classic_tbmv2" - ] - }, - "build137-b1": { - "benchmarks": [ - "loading.desktop", - "smoothness.gpu_rasterization.polymer", - "v8.runtimestats.browsing_mobile_classic" - ] - }, - "build138-b1": { - "benchmarks": [ - "memory.dual_browser_test", - "page_cycler_v2.intl_ja_zh", - "smoothness.maps", - "v8.browsing_mobile_turbo", - "v8.mobile_infinite_scroll_tbmv2" - ] - }, - "build139-b1": { - "benchmarks": [ - "blink_perf.owp_storage", - "blink_perf.image_decoder", - "page_cycler_v2.typical_25", - "speedometer-turbo", - "system_health.common_mobile", - "system_health.webview_startup_multiprocess" - ] - }, - "build140-b1": { - "benchmarks": [ - "rasterize_and_record_micro.polymer", - "smoothness.gpu_rasterization.tough_scrolling_cases", - "start_with_url.cold.startup_pages", - "system_health.common_desktop", - "system_health.webview_startup", - "thread_times.polymer", - "v8.runtimestats.browsing_mobile" - ] - }, - "build141-b1": { - "benchmarks": [ - "power.idle_platform", - "smoothness.tough_animation_cases", - "smoothness.tough_pinch_zoom_cases", - "v8.browsing_desktop_turbo" - ] - }, - "build142-b1": { - "benchmarks": [ - "blink_perf.blink_gc", - "dromaeo.domcoremodify", - "media.android.tough_video_cases", - "page_cycler_v2.intl_ko_th_vi", - "smoothness.key_mobile_sites_smooth", - "smoothness.key_silk_cases" - ] - }, - "build143-b1": { - "benchmarks": [ - "battor.trivial_pages", - "media.media_cns_cases", - "service_worker.service_worker", - "start_with_url.warm.startup_pages", - "thread_times.key_hit_test_cases", - "thread_times.key_noop_cases" - ] - }, - "build144-b1": { - "benchmarks": [ - "dromaeo.domcorequery", - "image_decoding.image_decoding_measurement", - "memory.long_running_idle_gmail_tbmv2", - "page_cycler_v2.intl_hi_ru" - ] - }, - "build145-b1": { - "benchmarks": [ - "memory.long_running_idle_gmail_background_tbmv2", - "smoothness.gpu_rasterization.top_25_smooth", - "smoothness.pathological_mobile_sites", - "smoothness.tough_image_decode_cases", - "speedometer-classic", - "startup.large_profile.cold.blank_page", - "tab_switching.typical_25", - "v8.runtimestats.browsing_desktop_classic" - ] - }, - "build146-b1": { - "benchmarks": [ - "jetstream", - "page_cycler_v2.intl_es_fr_pt-BR", - "smoothness.gpu_rasterization.tough_path_rendering_cases", - "smoothness.gpu_rasterization.tough_pinch_zoom_cases", - "tracing.tracing_with_background_memory_infra", - "v8.runtimestats.browsing_desktop" - ] - }, - "build147-b1": { - "benchmarks": [ - "blink_perf.parser", - "media.android.tough_video_cases_tbmv2", - "page_cycler_v2.intl_ar_fa_he", - "smoothness.tough_path_rendering_cases", - "startup.large_profile.warm.blank_page", - "system_health.memory_mobile", - "v8.runtime_stats.top_25" - ] - }, - "build148-b1": { - "benchmarks": [ - "battor.steady_state", - "blink_perf.paint", - "dummy_benchmark.noisy_benchmark_1", - "dummy_benchmark.histogram_benchmark_1", - "oortonline_tbmv2", - "rasterize_and_record_micro.top_25", - "smoothness.tough_webgl_cases", - "v8.mobile_infinite_scroll-turbo_tbmv2", - "v8.runtimestats.browsing_desktop_turbo" - ] - }, - "build149-b1": { - "benchmarks": [ - "blink_perf.layout", - "smoothness.scrolling_tough_ad_cases", - "smoothness.tough_texture_upload_cases", - "start_with_ext.warm.blank_page", - "startup.warm.blank_page", - "webrtc" - ] - }, - "build150-b1": { - "benchmarks": [ - "blob_storage.blob_storage", - "dromaeo.domcoretraverse", - "smoothness.gpu_rasterization.tough_filters_cases", - "storage.indexeddb_endure", - "thread_times.simple_mobile_sites", - "tracing.tracing_with_debug_overhead", - "v8.browsing_desktop" - ] - }, - "build151-b1": { - "benchmarks": [ - "kraken", - "octane", - "oortonline", - "power.trivial_pages", - "thread_times.key_idle_power_cases", - "thread_times.tough_compositor_cases", - "v8.infinite_scroll_tbmv2" - ] - }, - "build152-b1": { - "benchmarks": [ - "blink_perf.events", - "blink_perf.svg", - "media.tough_video_cases", - "smoothness.tough_webgl_ad_cases", - "start_with_ext.cold.blank_page", - "thread_times.tough_scrolling_cases", - "v8.browsing_mobile_classic" - ] - }, - "build153-b1": { - "benchmarks": [ - "blink_perf.dom", - "service_worker.service_worker_micro_benchmark", - "smoothness.top_25_smooth", - "smoothness.tough_canvas_cases", - "storage.indexeddb_endure_tracing", - "v8.detached_context_age_in_gc" - ] - }, - "build154-b1": { - "benchmarks": [ - "blink_perf.bindings", - "blink_perf.canvas", - "media.mse_cases", - "page_cycler_v2.top_10_mobile", - "page_cycler_v2_site_isolation.basic_oopif", - "smoothness.gpu_rasterization_and_decoding.image_decoding_cases", - "v8.infinite_scroll-turbo_tbmv2" - ] - }, - "build155-b1": { - "benchmarks": [ - "blink_perf.shadow_dom", - "memory.top_10_mobile", - "page_cycler_v2.basic_oopif", - "rasterize_and_record_micro.partial_invalidation", - "smoothness.desktop_tough_pinch_zoom_cases", - "smoothness.key_desktop_move_cases", - "startup.cold.blank_page", - "thread_times.key_silk_cases", - "v8.browsing_mobile" - ] - }, - "build47-b4": { + "One Buildbot Step Test Builder": { + "swarm823-c4": { "benchmarks": [ "blink_perf.css", - "dromaeo.domcoreattr", - "media.tough_video_cases_tbmv2", - "memory.top_10_mobile_stress", - "rasterize_and_record_micro.key_mobile_sites", - "scheduler.tough_scheduling_cases", - "smoothness.image_decoding_cases", - "smoothness.sync_scroll.key_mobile_sites_smooth", - "thread_times.key_mobile_sites_smooth", - "v8.browsing_desktop_classic", - "v8.infinite_scroll-classic_tbmv2" - ] - }, - "build48-b4": { - "benchmarks": [ - "dummy_benchmark.stable_benchmark_1", - "loading.mobile", - "memory.desktop", - "power.steady_state", - "power.typical_10_mobile", - "smoothness.tough_ad_cases", - "smoothness.tough_filters_cases", - "smoothness.tough_scrolling_cases", - "speedometer", - "speedometer2", - "startup.warm.chrome_signin", - "v8.runtimestats.browsing_mobile_turbo" + "smoothness.maps" ] } }, @@ -3239,75 +2210,52 @@ "blink_perf.paint", "dromaeo.domcoremodify", "dummy_benchmark.stable_benchmark_1", - "media.android.tough_video_cases_tbmv2", - "media.tough_video_cases", + "media.mobile", "memory.top_10_mobile", - "oortonline", - "power.trivial_pages", "scheduler.tough_scheduling_cases", "smoothness.key_desktop_move_cases", "smoothness.key_mobile_sites_smooth", "smoothness.tough_ad_cases", "smoothness.tough_image_decode_cases", - "startup.cold.blank_page", - "startup.large_profile.warm.blank_page", "system_health.memory_desktop", "thread_times.key_mobile_sites_smooth", "thread_times.key_silk_cases", - "tracing.tracing_with_debug_overhead", "v8.runtime_stats.top_25" ] }, "build118-b1": { "benchmarks": [ "blink_perf.bindings", - "blink_perf.blink_gc", "blink_perf.canvas", - "blink_perf.owp_storage", "blink_perf.image_decoder", - "dummy_benchmark.noisy_benchmark_1", + "blink_perf.owp_storage", "dummy_benchmark.histogram_benchmark_1", + "dummy_benchmark.noisy_benchmark_1", "loading.desktop", "octane", "oortonline_tbmv2", - "page_cycler_v2.basic_oopif", - "page_cycler_v2.intl_ar_fa_he", "power.idle_platform", - "rasterize_and_record_micro.key_silk_cases", "smoothness.key_silk_cases", "smoothness.pathological_mobile_sites", "smoothness.top_25_smooth", "smoothness.tough_webgl_cases", - "startup.warm.blank_page", - "storage.indexeddb_endure", - "storage.indexeddb_endure_tracing", "system_health.common_mobile", "system_health.memory_mobile", "thread_times.key_hit_test_cases", "thread_times.key_noop_cases", - "thread_times.polymer", "thread_times.tough_scrolling_cases", "tracing.tracing_with_background_memory_infra", "v8.browsing_mobile", - "v8.browsing_mobile_classic", - "v8.mobile_infinite_scroll-turbo_tbmv2", - "v8.mobile_infinite_scroll_tbmv2", - "v8.runtimestats.browsing_desktop", - "v8.runtimestats.browsing_mobile_classic", - "v8.runtimestats.browsing_mobile_turbo" + "v8.runtimestats.browsing_desktop" ] }, "build119-b1": { "benchmarks": [ "battor.trivial_pages", "blink_perf.layout", + "dromaeo", "dromaeo.domcoreattr", - "image_decoding.image_decoding_measurement", - "memory.dual_browser_test", "memory.long_running_idle_gmail_background_tbmv2", - "page_cycler_v2.intl_hi_ru", - "page_cycler_v2.intl_ja_zh", - "page_cycler_v2.top_10_mobile", "rasterize_and_record_micro.top_25", "smoothness.gpu_rasterization.polymer", "smoothness.gpu_rasterization.top_25_smooth", @@ -3319,48 +2267,31 @@ "smoothness.tough_scrolling_cases", "speedometer", "speedometer2", - "speedometer-turbo", "tab_switching.typical_25", "thread_times.tough_compositor_cases", - "v8.browsing_desktop_classic", - "v8.browsing_desktop_turbo", - "v8.infinite_scroll-turbo_tbmv2", - "v8.runtimestats.browsing_desktop_classic", - "v8.runtimestats.browsing_desktop_turbo" + "v8.browsing_desktop-future", + "v8.browsing_mobile-future", + "wasm" ] }, "build120-b1": { "benchmarks": [ "blink_perf.parser", "blink_perf.svg", - "blob_storage.blob_storage", "dromaeo.domcorequery", "dromaeo.domcoretraverse", "jetstream", - "media.android.tough_video_cases", - "media.media_cns_cases", "memory.desktop", - "page_cycler_v2.intl_es_fr_pt-BR", - "page_cycler_v2.intl_ko_th_vi", - "page_cycler_v2.typical_25", - "power.steady_state", "power.typical_10_mobile", - "rasterize_and_record_micro.polymer", - "service_worker.service_worker", - "service_worker.service_worker_micro_benchmark", "smoothness.gpu_rasterization.tough_filters_cases", "smoothness.gpu_rasterization.tough_pinch_zoom_cases", - "smoothness.scrolling_tough_ad_cases", "smoothness.tough_canvas_cases", "smoothness.tough_pinch_zoom_cases", - "speedometer-classic", - "start_with_ext.cold.blank_page", + "speedometer-future", + "speedometer2-future", "start_with_url.cold.startup_pages", - "startup.warm.chrome_signin", - "system_health.webview_startup_multiprocess", "v8.browsing_desktop", "v8.detached_context_age_in_gc", - "v8.mobile_infinite_scroll-classic_tbmv2", "webrtc" ] }, @@ -3372,12 +2303,8 @@ "blink_perf.shadow_dom", "kraken", "loading.mobile", - "media.mse_cases", - "media.tough_video_cases_tbmv2", + "media.desktop", "memory.long_running_idle_gmail_tbmv2", - "memory.top_10_mobile_stress", - "page_cycler_v2_site_isolation.basic_oopif", - "rasterize_and_record_micro.key_mobile_sites", "rasterize_and_record_micro.partial_invalidation", "smoothness.desktop_tough_pinch_zoom_cases", "smoothness.gpu_rasterization.tough_path_rendering_cases", @@ -3387,257 +2314,15 @@ "smoothness.tough_animation_cases", "smoothness.tough_texture_upload_cases", "smoothness.tough_webgl_ad_cases", - "start_with_ext.warm.blank_page", "start_with_url.warm.startup_pages", - "startup.large_profile.cold.blank_page", "system_health.common_desktop", "system_health.webview_startup", "thread_times.key_idle_power_cases", "thread_times.simple_mobile_sites", - "v8.browsing_mobile_turbo", - "v8.infinite_scroll-classic_tbmv2", - "v8.infinite_scroll_tbmv2", "v8.runtimestats.browsing_mobile" ] } }, - "Win 10 Low-End Perf Tests": { - "build171-b4": { - "benchmarks": [ - "rasterize_and_record_micro.key_silk_cases", - "smoothness.simple_mobile_sites", - "system_health.memory_desktop", - "v8.mobile_infinite_scroll-classic_tbmv2" - ] - }, - "build186-b4": { - "benchmarks": [ - "loading.desktop", - "smoothness.gpu_rasterization.polymer", - "v8.runtimestats.browsing_mobile_classic" - ] - }, - "build202-b4": { - "benchmarks": [ - "memory.dual_browser_test", - "page_cycler_v2.intl_ja_zh", - "smoothness.maps", - "v8.browsing_mobile_turbo", - "v8.mobile_infinite_scroll_tbmv2" - ] - }, - "build203-b4": { - "benchmarks": [ - "blink_perf.owp_storage", - "blink_perf.image_decoder", - "page_cycler_v2.typical_25", - "speedometer-turbo", - "system_health.common_mobile", - "system_health.webview_startup_multiprocess" - ] - }, - "build204-b4": { - "benchmarks": [ - "rasterize_and_record_micro.polymer", - "smoothness.gpu_rasterization.tough_scrolling_cases", - "start_with_url.cold.startup_pages", - "system_health.common_desktop", - "system_health.webview_startup", - "thread_times.polymer", - "v8.runtimestats.browsing_mobile" - ] - }, - "build205-b4": { - "benchmarks": [ - "power.idle_platform", - "smoothness.tough_animation_cases", - "smoothness.tough_pinch_zoom_cases", - "v8.browsing_desktop_turbo" - ] - }, - "build206-b4": { - "benchmarks": [ - "blink_perf.blink_gc", - "dromaeo.domcoremodify", - "media.android.tough_video_cases", - "page_cycler_v2.intl_ko_th_vi", - "smoothness.key_mobile_sites_smooth", - "smoothness.key_silk_cases" - ] - }, - "build207-b4": { - "benchmarks": [ - "battor.trivial_pages", - "media.media_cns_cases", - "service_worker.service_worker", - "start_with_url.warm.startup_pages", - "thread_times.key_hit_test_cases", - "thread_times.key_noop_cases" - ] - }, - "build208-b4": { - "benchmarks": [ - "dromaeo.domcorequery", - "image_decoding.image_decoding_measurement", - "memory.long_running_idle_gmail_tbmv2", - "page_cycler_v2.intl_hi_ru" - ] - }, - "build209-b4": { - "benchmarks": [ - "memory.long_running_idle_gmail_background_tbmv2", - "smoothness.gpu_rasterization.top_25_smooth", - "smoothness.pathological_mobile_sites", - "smoothness.tough_image_decode_cases", - "speedometer-classic", - "startup.large_profile.cold.blank_page", - "tab_switching.typical_25", - "v8.runtimestats.browsing_desktop_classic" - ] - }, - "build210-b4": { - "benchmarks": [ - "jetstream", - "page_cycler_v2.intl_es_fr_pt-BR", - "smoothness.gpu_rasterization.tough_path_rendering_cases", - "smoothness.gpu_rasterization.tough_pinch_zoom_cases", - "tracing.tracing_with_background_memory_infra", - "v8.runtimestats.browsing_desktop" - ] - }, - "build211-b4": { - "benchmarks": [ - "blink_perf.parser", - "media.android.tough_video_cases_tbmv2", - "page_cycler_v2.intl_ar_fa_he", - "smoothness.tough_path_rendering_cases", - "startup.large_profile.warm.blank_page", - "system_health.memory_mobile", - "v8.runtime_stats.top_25" - ] - }, - "build212-b4": { - "benchmarks": [ - "battor.steady_state", - "blink_perf.paint", - "dummy_benchmark.noisy_benchmark_1", - "dummy_benchmark.histogram_benchmark_1", - "oortonline_tbmv2", - "rasterize_and_record_micro.top_25", - "smoothness.tough_webgl_cases", - "v8.mobile_infinite_scroll-turbo_tbmv2", - "v8.runtimestats.browsing_desktop_turbo" - ] - }, - "build213-b4": { - "benchmarks": [ - "blink_perf.layout", - "smoothness.scrolling_tough_ad_cases", - "smoothness.tough_texture_upload_cases", - "start_with_ext.warm.blank_page", - "startup.warm.blank_page", - "webrtc" - ] - }, - "build214-b4": { - "benchmarks": [ - "blob_storage.blob_storage", - "dromaeo.domcoretraverse", - "smoothness.gpu_rasterization.tough_filters_cases", - "storage.indexeddb_endure", - "thread_times.simple_mobile_sites", - "tracing.tracing_with_debug_overhead", - "v8.browsing_desktop" - ] - }, - "build215-b4": { - "benchmarks": [ - "kraken", - "octane", - "oortonline", - "power.trivial_pages", - "thread_times.key_idle_power_cases", - "thread_times.tough_compositor_cases", - "v8.infinite_scroll_tbmv2" - ] - }, - "build216-b4": { - "benchmarks": [ - "blink_perf.events", - "blink_perf.svg", - "media.tough_video_cases", - "smoothness.tough_webgl_ad_cases", - "start_with_ext.cold.blank_page", - "thread_times.tough_scrolling_cases", - "v8.browsing_mobile_classic" - ] - }, - "build217-b4": { - "benchmarks": [ - "blink_perf.dom", - "service_worker.service_worker_micro_benchmark", - "smoothness.top_25_smooth", - "smoothness.tough_canvas_cases", - "storage.indexeddb_endure_tracing", - "v8.detached_context_age_in_gc" - ] - }, - "build218-b4": { - "benchmarks": [ - "blink_perf.bindings", - "blink_perf.canvas", - "media.mse_cases", - "page_cycler_v2.top_10_mobile", - "page_cycler_v2_site_isolation.basic_oopif", - "smoothness.gpu_rasterization_and_decoding.image_decoding_cases", - "v8.infinite_scroll-turbo_tbmv2" - ] - }, - "build219-b4": { - "benchmarks": [ - "blink_perf.shadow_dom", - "memory.top_10_mobile", - "page_cycler_v2.basic_oopif", - "rasterize_and_record_micro.partial_invalidation", - "smoothness.desktop_tough_pinch_zoom_cases", - "smoothness.key_desktop_move_cases", - "startup.cold.blank_page", - "thread_times.key_silk_cases", - "v8.browsing_mobile" - ] - }, - "build220-b4": { - "benchmarks": [ - "blink_perf.css", - "dromaeo.domcoreattr", - "media.tough_video_cases_tbmv2", - "memory.top_10_mobile_stress", - "rasterize_and_record_micro.key_mobile_sites", - "scheduler.tough_scheduling_cases", - "smoothness.image_decoding_cases", - "smoothness.sync_scroll.key_mobile_sites_smooth", - "thread_times.key_mobile_sites_smooth", - "v8.browsing_desktop_classic", - "v8.infinite_scroll-classic_tbmv2" - ] - }, - "build221-b4": { - "benchmarks": [ - "dummy_benchmark.stable_benchmark_1", - "loading.mobile", - "memory.desktop", - "power.steady_state", - "power.typical_10_mobile", - "smoothness.tough_ad_cases", - "smoothness.tough_filters_cases", - "smoothness.tough_scrolling_cases", - "speedometer", - "speedometer2", - "startup.warm.chrome_signin", - "v8.runtimestats.browsing_mobile_turbo" - ] - } - }, "Win 10 Perf": { "build132-m1": { "benchmarks": [ @@ -3645,62 +2330,43 @@ "blink_perf.paint", "dromaeo.domcoremodify", "dummy_benchmark.stable_benchmark_1", - "media.android.tough_video_cases_tbmv2", - "media.tough_video_cases", + "media.mobile", "memory.top_10_mobile", - "oortonline", - "power.trivial_pages", "scheduler.tough_scheduling_cases", "smoothness.key_desktop_move_cases", "smoothness.key_mobile_sites_smooth", "smoothness.tough_ad_cases", "smoothness.tough_image_decode_cases", - "startup.cold.blank_page", - "startup.large_profile.warm.blank_page", "system_health.memory_desktop", "thread_times.key_mobile_sites_smooth", "thread_times.key_silk_cases", - "tracing.tracing_with_debug_overhead", "v8.runtime_stats.top_25" ] }, "build133-m1": { "benchmarks": [ "blink_perf.bindings", - "blink_perf.blink_gc", "blink_perf.canvas", - "blink_perf.owp_storage", "blink_perf.image_decoder", - "dummy_benchmark.noisy_benchmark_1", + "blink_perf.owp_storage", "dummy_benchmark.histogram_benchmark_1", + "dummy_benchmark.noisy_benchmark_1", "loading.desktop", "octane", "oortonline_tbmv2", - "page_cycler_v2.basic_oopif", - "page_cycler_v2.intl_ar_fa_he", "power.idle_platform", - "rasterize_and_record_micro.key_silk_cases", "smoothness.key_silk_cases", "smoothness.pathological_mobile_sites", "smoothness.top_25_smooth", "smoothness.tough_webgl_cases", - "startup.warm.blank_page", - "storage.indexeddb_endure", - "storage.indexeddb_endure_tracing", "system_health.common_mobile", "system_health.memory_mobile", "thread_times.key_hit_test_cases", "thread_times.key_noop_cases", - "thread_times.polymer", "thread_times.tough_scrolling_cases", "tracing.tracing_with_background_memory_infra", "v8.browsing_mobile", - "v8.browsing_mobile_classic", - "v8.mobile_infinite_scroll-turbo_tbmv2", - "v8.mobile_infinite_scroll_tbmv2", "v8.runtimestats.browsing_desktop", - "v8.runtimestats.browsing_mobile_classic", - "v8.runtimestats.browsing_mobile_turbo", "webrtc" ] }, @@ -3708,13 +2374,9 @@ "benchmarks": [ "battor.trivial_pages", "blink_perf.layout", + "dromaeo", "dromaeo.domcoreattr", - "image_decoding.image_decoding_measurement", - "memory.dual_browser_test", "memory.long_running_idle_gmail_background_tbmv2", - "page_cycler_v2.intl_hi_ru", - "page_cycler_v2.intl_ja_zh", - "page_cycler_v2.top_10_mobile", "rasterize_and_record_micro.top_25", "smoothness.gpu_rasterization.polymer", "smoothness.gpu_rasterization.top_25_smooth", @@ -3726,49 +2388,32 @@ "smoothness.tough_scrolling_cases", "speedometer", "speedometer2", - "speedometer-turbo", "tab_switching.typical_25", "thread_times.tough_compositor_cases", - "v8.browsing_desktop_classic", - "v8.browsing_desktop_turbo", - "v8.infinite_scroll-turbo_tbmv2", - "v8.runtimestats.browsing_desktop_classic", - "v8.runtimestats.browsing_desktop_turbo" + "v8.browsing_desktop-future", + "v8.browsing_mobile-future", + "wasm" ] }, "build135-m1": { "benchmarks": [ "blink_perf.parser", "blink_perf.svg", - "blob_storage.blob_storage", "dromaeo.domcorequery", "dromaeo.domcoretraverse", "jetstream", - "media.android.tough_video_cases", - "media.media_cns_cases", "memory.desktop", - "page_cycler_v2.intl_es_fr_pt-BR", - "page_cycler_v2.intl_ko_th_vi", - "page_cycler_v2.typical_25", - "power.steady_state", "power.typical_10_mobile", - "rasterize_and_record_micro.polymer", - "service_worker.service_worker", - "service_worker.service_worker_micro_benchmark", "smoothness.gpu_rasterization.tough_filters_cases", "smoothness.gpu_rasterization.tough_pinch_zoom_cases", - "smoothness.scrolling_tough_ad_cases", "smoothness.tough_animation_cases", "smoothness.tough_canvas_cases", "smoothness.tough_pinch_zoom_cases", - "speedometer-classic", - "start_with_ext.cold.blank_page", + "speedometer-future", + "speedometer2-future", "start_with_url.cold.startup_pages", - "startup.warm.chrome_signin", - "system_health.webview_startup_multiprocess", "v8.browsing_desktop", - "v8.detached_context_age_in_gc", - "v8.mobile_infinite_scroll-classic_tbmv2" + "v8.detached_context_age_in_gc" ] }, "build136-m1": { @@ -3779,12 +2424,8 @@ "blink_perf.shadow_dom", "kraken", "loading.mobile", - "media.mse_cases", - "media.tough_video_cases_tbmv2", + "media.desktop", "memory.long_running_idle_gmail_tbmv2", - "memory.top_10_mobile_stress", - "page_cycler_v2_site_isolation.basic_oopif", - "rasterize_and_record_micro.key_mobile_sites", "rasterize_and_record_micro.partial_invalidation", "smoothness.desktop_tough_pinch_zoom_cases", "smoothness.gpu_rasterization.tough_path_rendering_cases", @@ -3793,16 +2434,11 @@ "smoothness.sync_scroll.key_mobile_sites_smooth", "smoothness.tough_texture_upload_cases", "smoothness.tough_webgl_ad_cases", - "start_with_ext.warm.blank_page", "start_with_url.warm.startup_pages", - "startup.large_profile.cold.blank_page", "system_health.common_desktop", "system_health.webview_startup", "thread_times.key_idle_power_cases", "thread_times.simple_mobile_sites", - "v8.browsing_mobile_turbo", - "v8.infinite_scroll-classic_tbmv2", - "v8.infinite_scroll_tbmv2", "v8.runtimestats.browsing_mobile" ] } @@ -3814,74 +2450,51 @@ "blink_perf.paint", "dromaeo.domcoremodify", "dummy_benchmark.stable_benchmark_1", - "media.android.tough_video_cases_tbmv2", - "media.tough_video_cases", + "media.mobile", "memory.top_10_mobile", - "oortonline", - "power.trivial_pages", "scheduler.tough_scheduling_cases", "smoothness.key_desktop_move_cases", "smoothness.key_mobile_sites_smooth", "smoothness.tough_ad_cases", "smoothness.tough_image_decode_cases", - "startup.cold.blank_page", - "startup.large_profile.warm.blank_page", "system_health.memory_desktop", "thread_times.key_mobile_sites_smooth", "thread_times.key_silk_cases", - "tracing.tracing_with_debug_overhead", "v8.runtime_stats.top_25" ] }, "build102-m1": { "benchmarks": [ "blink_perf.bindings", - "blink_perf.blink_gc", "blink_perf.canvas", - "blink_perf.owp_storage", "blink_perf.image_decoder", - "dummy_benchmark.noisy_benchmark_1", + "blink_perf.owp_storage", "dummy_benchmark.histogram_benchmark_1", + "dummy_benchmark.noisy_benchmark_1", "loading.desktop", "octane", "oortonline_tbmv2", - "page_cycler_v2.basic_oopif", - "page_cycler_v2.intl_ar_fa_he", "power.idle_platform", - "rasterize_and_record_micro.key_silk_cases", "smoothness.key_silk_cases", "smoothness.pathological_mobile_sites", "smoothness.top_25_smooth", "smoothness.tough_webgl_cases", - "startup.warm.blank_page", - "storage.indexeddb_endure", - "storage.indexeddb_endure_tracing", "system_health.common_mobile", "system_health.memory_mobile", "thread_times.key_hit_test_cases", "thread_times.key_noop_cases", - "thread_times.polymer", "tracing.tracing_with_background_memory_infra", "v8.browsing_mobile", - "v8.browsing_mobile_classic", - "v8.mobile_infinite_scroll-turbo_tbmv2", - "v8.mobile_infinite_scroll_tbmv2", - "v8.runtimestats.browsing_desktop", - "v8.runtimestats.browsing_mobile_classic", - "v8.runtimestats.browsing_mobile_turbo" + "v8.runtimestats.browsing_desktop" ] }, "build103-m1": { "benchmarks": [ "battor.trivial_pages", "blink_perf.layout", + "dromaeo", "dromaeo.domcoreattr", - "image_decoding.image_decoding_measurement", - "memory.dual_browser_test", "memory.long_running_idle_gmail_background_tbmv2", - "page_cycler_v2.intl_hi_ru", - "page_cycler_v2.intl_ja_zh", - "page_cycler_v2.top_10_mobile", "rasterize_and_record_micro.top_25", "smoothness.gpu_rasterization.polymer", "smoothness.gpu_rasterization.top_25_smooth", @@ -3893,49 +2506,32 @@ "smoothness.tough_scrolling_cases", "speedometer", "speedometer2", - "speedometer-turbo", "tab_switching.typical_25", "thread_times.tough_compositor_cases", - "v8.browsing_desktop_classic", - "v8.browsing_desktop_turbo", - "v8.infinite_scroll-turbo_tbmv2", - "v8.runtimestats.browsing_desktop_classic", - "v8.runtimestats.browsing_desktop_turbo" + "v8.browsing_desktop-future", + "v8.browsing_mobile-future", + "wasm" ] }, "build104-m1": { "benchmarks": [ "blink_perf.parser", "blink_perf.svg", - "blob_storage.blob_storage", "dromaeo.domcorequery", "dromaeo.domcoretraverse", "jetstream", - "media.android.tough_video_cases", - "media.media_cns_cases", "memory.desktop", - "page_cycler_v2.intl_es_fr_pt-BR", - "page_cycler_v2.intl_ko_th_vi", - "page_cycler_v2.typical_25", - "power.steady_state", "power.typical_10_mobile", - "rasterize_and_record_micro.polymer", - "service_worker.service_worker", - "service_worker.service_worker_micro_benchmark", "smoothness.gpu_rasterization.tough_filters_cases", "smoothness.gpu_rasterization.tough_pinch_zoom_cases", - "smoothness.scrolling_tough_ad_cases", "smoothness.tough_canvas_cases", "smoothness.tough_pinch_zoom_cases", - "speedometer-classic", - "start_with_ext.cold.blank_page", + "speedometer-future", + "speedometer2-future", "start_with_url.cold.startup_pages", - "startup.warm.chrome_signin", - "system_health.webview_startup_multiprocess", "thread_times.tough_scrolling_cases", "v8.browsing_desktop", "v8.detached_context_age_in_gc", - "v8.mobile_infinite_scroll-classic_tbmv2", "webrtc" ] }, @@ -3947,12 +2543,8 @@ "blink_perf.shadow_dom", "kraken", "loading.mobile", - "media.mse_cases", - "media.tough_video_cases_tbmv2", + "media.desktop", "memory.long_running_idle_gmail_tbmv2", - "memory.top_10_mobile_stress", - "page_cycler_v2_site_isolation.basic_oopif", - "rasterize_and_record_micro.key_mobile_sites", "rasterize_and_record_micro.partial_invalidation", "smoothness.desktop_tough_pinch_zoom_cases", "smoothness.gpu_rasterization.tough_path_rendering_cases", @@ -3962,16 +2554,11 @@ "smoothness.tough_animation_cases", "smoothness.tough_texture_upload_cases", "smoothness.tough_webgl_ad_cases", - "start_with_ext.warm.blank_page", "start_with_url.warm.startup_pages", - "startup.large_profile.cold.blank_page", "system_health.common_desktop", "system_health.webview_startup", "thread_times.key_idle_power_cases", "thread_times.simple_mobile_sites", - "v8.browsing_mobile_turbo", - "v8.infinite_scroll-classic_tbmv2", - "v8.infinite_scroll_tbmv2", "v8.runtimestats.browsing_mobile" ] } @@ -3983,75 +2570,52 @@ "blink_perf.paint", "dromaeo.domcoremodify", "dummy_benchmark.stable_benchmark_1", - "media.android.tough_video_cases_tbmv2", - "media.tough_video_cases", + "media.mobile", "memory.top_10_mobile", - "oortonline", - "power.trivial_pages", "scheduler.tough_scheduling_cases", "smoothness.key_desktop_move_cases", "smoothness.key_mobile_sites_smooth", "smoothness.tough_ad_cases", "smoothness.tough_image_decode_cases", - "startup.cold.blank_page", - "startup.large_profile.warm.blank_page", "system_health.memory_desktop", "thread_times.key_mobile_sites_smooth", "thread_times.key_silk_cases", - "tracing.tracing_with_debug_overhead", "v8.runtime_stats.top_25" ] }, "build165-m1": { "benchmarks": [ "blink_perf.bindings", - "blink_perf.blink_gc", "blink_perf.canvas", - "blink_perf.owp_storage", "blink_perf.image_decoder", - "dummy_benchmark.noisy_benchmark_1", + "blink_perf.owp_storage", "dummy_benchmark.histogram_benchmark_1", + "dummy_benchmark.noisy_benchmark_1", "loading.desktop", "octane", "oortonline_tbmv2", - "page_cycler_v2.basic_oopif", - "page_cycler_v2.intl_ar_fa_he", "power.idle_platform", - "rasterize_and_record_micro.key_silk_cases", "smoothness.key_silk_cases", "smoothness.pathological_mobile_sites", "smoothness.top_25_smooth", "smoothness.tough_webgl_cases", - "startup.warm.blank_page", - "storage.indexeddb_endure", - "storage.indexeddb_endure_tracing", "system_health.common_mobile", "system_health.memory_mobile", "thread_times.key_hit_test_cases", "thread_times.key_noop_cases", - "thread_times.polymer", "thread_times.tough_scrolling_cases", "tracing.tracing_with_background_memory_infra", "v8.browsing_mobile", - "v8.browsing_mobile_classic", - "v8.mobile_infinite_scroll-turbo_tbmv2", - "v8.mobile_infinite_scroll_tbmv2", - "v8.runtimestats.browsing_desktop", - "v8.runtimestats.browsing_mobile_classic", - "v8.runtimestats.browsing_mobile_turbo" + "v8.runtimestats.browsing_desktop" ] }, "build166-m1": { "benchmarks": [ "battor.trivial_pages", "blink_perf.layout", + "dromaeo", "dromaeo.domcoreattr", - "image_decoding.image_decoding_measurement", - "memory.dual_browser_test", "memory.long_running_idle_gmail_background_tbmv2", - "page_cycler_v2.intl_hi_ru", - "page_cycler_v2.intl_ja_zh", - "page_cycler_v2.top_10_mobile", "rasterize_and_record_micro.top_25", "smoothness.gpu_rasterization.polymer", "smoothness.gpu_rasterization.top_25_smooth", @@ -4063,48 +2627,31 @@ "smoothness.tough_scrolling_cases", "speedometer", "speedometer2", - "speedometer-turbo", "tab_switching.typical_25", "thread_times.tough_compositor_cases", - "v8.browsing_desktop_classic", - "v8.browsing_desktop_turbo", - "v8.infinite_scroll-turbo_tbmv2", - "v8.runtimestats.browsing_desktop_classic", - "v8.runtimestats.browsing_desktop_turbo" + "v8.browsing_desktop-future", + "v8.browsing_mobile-future", + "wasm" ] }, "build167-m1": { "benchmarks": [ "blink_perf.parser", "blink_perf.svg", - "blob_storage.blob_storage", "dromaeo.domcorequery", "dromaeo.domcoretraverse", "jetstream", - "media.android.tough_video_cases", - "media.media_cns_cases", "memory.desktop", - "page_cycler_v2.intl_es_fr_pt-BR", - "page_cycler_v2.intl_ko_th_vi", - "page_cycler_v2.typical_25", - "power.steady_state", "power.typical_10_mobile", - "rasterize_and_record_micro.polymer", - "service_worker.service_worker", - "service_worker.service_worker_micro_benchmark", "smoothness.gpu_rasterization.tough_filters_cases", "smoothness.gpu_rasterization.tough_pinch_zoom_cases", - "smoothness.scrolling_tough_ad_cases", "smoothness.tough_canvas_cases", "smoothness.tough_pinch_zoom_cases", - "speedometer-classic", - "start_with_ext.cold.blank_page", + "speedometer-future", + "speedometer2-future", "start_with_url.cold.startup_pages", - "startup.warm.chrome_signin", - "system_health.webview_startup_multiprocess", "v8.browsing_desktop", "v8.detached_context_age_in_gc", - "v8.mobile_infinite_scroll-classic_tbmv2", "webrtc" ] }, @@ -4116,12 +2663,8 @@ "blink_perf.shadow_dom", "kraken", "loading.mobile", - "media.mse_cases", - "media.tough_video_cases_tbmv2", + "media.desktop", "memory.long_running_idle_gmail_tbmv2", - "memory.top_10_mobile_stress", - "page_cycler_v2_site_isolation.basic_oopif", - "rasterize_and_record_micro.key_mobile_sites", "rasterize_and_record_micro.partial_invalidation", "smoothness.desktop_tough_pinch_zoom_cases", "smoothness.gpu_rasterization.tough_path_rendering_cases", @@ -4131,16 +2674,11 @@ "smoothness.tough_animation_cases", "smoothness.tough_texture_upload_cases", "smoothness.tough_webgl_ad_cases", - "start_with_ext.warm.blank_page", "start_with_url.warm.startup_pages", - "startup.large_profile.cold.blank_page", "system_health.common_desktop", "system_health.webview_startup", "thread_times.key_idle_power_cases", "thread_times.simple_mobile_sites", - "v8.browsing_mobile_turbo", - "v8.infinite_scroll-classic_tbmv2", - "v8.infinite_scroll_tbmv2", "v8.runtimestats.browsing_mobile" ] } @@ -4152,75 +2690,52 @@ "blink_perf.paint", "dromaeo.domcoremodify", "dummy_benchmark.stable_benchmark_1", - "media.android.tough_video_cases_tbmv2", - "media.tough_video_cases", + "media.mobile", "memory.top_10_mobile", - "oortonline", - "power.trivial_pages", "scheduler.tough_scheduling_cases", "smoothness.key_desktop_move_cases", "smoothness.key_mobile_sites_smooth", "smoothness.tough_ad_cases", "smoothness.tough_image_decode_cases", - "startup.cold.blank_page", - "startup.large_profile.warm.blank_page", "system_health.memory_desktop", "thread_times.key_mobile_sites_smooth", "thread_times.key_silk_cases", - "tracing.tracing_with_debug_overhead", "v8.runtime_stats.top_25" ] }, "build93-m1": { "benchmarks": [ "blink_perf.bindings", - "blink_perf.blink_gc", "blink_perf.canvas", - "blink_perf.owp_storage", "blink_perf.image_decoder", - "dummy_benchmark.noisy_benchmark_1", + "blink_perf.owp_storage", "dummy_benchmark.histogram_benchmark_1", + "dummy_benchmark.noisy_benchmark_1", "loading.desktop", "octane", "oortonline_tbmv2", - "page_cycler_v2.basic_oopif", - "page_cycler_v2.intl_ar_fa_he", "power.idle_platform", - "rasterize_and_record_micro.key_silk_cases", "smoothness.key_silk_cases", "smoothness.pathological_mobile_sites", "smoothness.top_25_smooth", "smoothness.tough_webgl_cases", - "startup.warm.blank_page", - "storage.indexeddb_endure", - "storage.indexeddb_endure_tracing", "system_health.common_mobile", "system_health.memory_mobile", "thread_times.key_hit_test_cases", "thread_times.key_noop_cases", - "thread_times.polymer", "thread_times.tough_scrolling_cases", "tracing.tracing_with_background_memory_infra", "v8.browsing_mobile", - "v8.browsing_mobile_classic", - "v8.mobile_infinite_scroll-turbo_tbmv2", - "v8.mobile_infinite_scroll_tbmv2", - "v8.runtimestats.browsing_desktop", - "v8.runtimestats.browsing_mobile_classic", - "v8.runtimestats.browsing_mobile_turbo" + "v8.runtimestats.browsing_desktop" ] }, "build94-m1": { "benchmarks": [ "battor.trivial_pages", "blink_perf.layout", + "dromaeo", "dromaeo.domcoreattr", - "image_decoding.image_decoding_measurement", - "memory.dual_browser_test", "memory.long_running_idle_gmail_background_tbmv2", - "page_cycler_v2.intl_hi_ru", - "page_cycler_v2.intl_ja_zh", - "page_cycler_v2.top_10_mobile", "rasterize_and_record_micro.top_25", "smoothness.gpu_rasterization.polymer", "smoothness.gpu_rasterization.top_25_smooth", @@ -4232,49 +2747,31 @@ "smoothness.tough_scrolling_cases", "speedometer", "speedometer2", - "speedometer-turbo", "tab_switching.typical_25", "thread_times.tough_compositor_cases", - "v8.browsing_desktop_classic", - "v8.browsing_desktop_turbo", - "v8.infinite_scroll-turbo_tbmv2", - "v8.runtimestats.browsing_desktop_classic", - "v8.runtimestats.browsing_desktop_turbo" + "v8.browsing_desktop-future", + "v8.browsing_mobile-future", + "wasm" ] }, "build95-m1": { "benchmarks": [ "blink_perf.parser", "blink_perf.svg", - "blob_storage.blob_storage", "dromaeo.domcorequery", "dromaeo.domcoretraverse", "jetstream", - "media.android.tough_video_cases", - "media.media_cns_cases", "memory.desktop", - "page_cycler_v2.intl_es_fr_pt-BR", - "page_cycler_v2.intl_ko_th_vi", - "page_cycler_v2.typical_25", - "power.steady_state", "power.typical_10_mobile", - "rasterize_and_record_micro.polymer", - "service_worker.service_worker", - "service_worker.service_worker_micro_benchmark", "smoothness.gpu_rasterization.tough_filters_cases", "smoothness.gpu_rasterization.tough_pinch_zoom_cases", - "smoothness.scrolling_tough_ad_cases", "smoothness.tough_canvas_cases", "smoothness.tough_pinch_zoom_cases", - "speedometer-classic", - "start_with_ext.cold.blank_page", + "speedometer-future", + "speedometer2-future", "start_with_url.cold.startup_pages", - "startup.warm.chrome_signin", - "system_health.webview_startup_multiprocess", "v8.browsing_desktop", "v8.detached_context_age_in_gc", - "v8.infinite_scroll_tbmv2", - "v8.mobile_infinite_scroll-classic_tbmv2", "webrtc" ] }, @@ -4286,12 +2783,8 @@ "blink_perf.shadow_dom", "kraken", "loading.mobile", - "media.mse_cases", - "media.tough_video_cases_tbmv2", + "media.desktop", "memory.long_running_idle_gmail_tbmv2", - "memory.top_10_mobile_stress", - "page_cycler_v2_site_isolation.basic_oopif", - "rasterize_and_record_micro.key_mobile_sites", "rasterize_and_record_micro.partial_invalidation", "smoothness.desktop_tough_pinch_zoom_cases", "smoothness.gpu_rasterization.tough_path_rendering_cases", @@ -4301,15 +2794,11 @@ "smoothness.tough_animation_cases", "smoothness.tough_texture_upload_cases", "smoothness.tough_webgl_ad_cases", - "start_with_ext.warm.blank_page", "start_with_url.warm.startup_pages", - "startup.large_profile.cold.blank_page", "system_health.common_desktop", "system_health.webview_startup", "thread_times.key_idle_power_cases", "thread_times.simple_mobile_sites", - "v8.browsing_mobile_turbo", - "v8.infinite_scroll-classic_tbmv2", "v8.runtimestats.browsing_mobile" ] } @@ -4321,60 +2810,42 @@ "blink_perf.paint", "dromaeo.domcoremodify", "dummy_benchmark.stable_benchmark_1", - "media.android.tough_video_cases_tbmv2", - "media.tough_video_cases", + "media.mobile", "memory.top_10_mobile", - "oortonline", - "power.trivial_pages", "scheduler.tough_scheduling_cases", "smoothness.key_desktop_move_cases", "smoothness.key_mobile_sites_smooth", "smoothness.tough_ad_cases", "smoothness.tough_image_decode_cases", - "startup.cold.blank_page", - "startup.large_profile.warm.blank_page", "system_health.memory_desktop", "thread_times.key_mobile_sites_smooth", "thread_times.key_silk_cases", - "tracing.tracing_with_debug_overhead", "v8.runtime_stats.top_25" ] }, "build186-m1": { "benchmarks": [ "blink_perf.bindings", - "blink_perf.blink_gc", "blink_perf.canvas", - "blink_perf.owp_storage", "blink_perf.image_decoder", - "dummy_benchmark.noisy_benchmark_1", + "blink_perf.owp_storage", "dummy_benchmark.histogram_benchmark_1", + "dummy_benchmark.noisy_benchmark_1", "loading.desktop", "octane", "oortonline_tbmv2", - "page_cycler_v2.intl_ar_fa_he", "power.idle_platform", - "rasterize_and_record_micro.key_silk_cases", "smoothness.key_silk_cases", "smoothness.pathological_mobile_sites", "smoothness.top_25_smooth", "smoothness.tough_webgl_cases", - "startup.warm.blank_page", - "storage.indexeddb_endure", - "storage.indexeddb_endure_tracing", "system_health.common_mobile", "system_health.memory_mobile", "thread_times.key_hit_test_cases", "thread_times.key_noop_cases", - "thread_times.polymer", "tracing.tracing_with_background_memory_infra", "v8.browsing_mobile", - "v8.browsing_mobile_classic", - "v8.mobile_infinite_scroll-turbo_tbmv2", - "v8.mobile_infinite_scroll_tbmv2", "v8.runtimestats.browsing_desktop", - "v8.runtimestats.browsing_mobile_classic", - "v8.runtimestats.browsing_mobile_turbo", "webrtc" ] }, @@ -4382,13 +2853,9 @@ "benchmarks": [ "battor.trivial_pages", "blink_perf.layout", + "dromaeo", "dromaeo.domcoreattr", - "image_decoding.image_decoding_measurement", - "memory.dual_browser_test", "memory.long_running_idle_gmail_background_tbmv2", - "page_cycler_v2.intl_hi_ru", - "page_cycler_v2.intl_ja_zh", - "page_cycler_v2.top_10_mobile", "rasterize_and_record_micro.top_25", "smoothness.gpu_rasterization.polymer", "smoothness.gpu_rasterization.top_25_smooth", @@ -4400,50 +2867,32 @@ "smoothness.tough_scrolling_cases", "speedometer", "speedometer2", - "speedometer-turbo", "tab_switching.typical_25", "thread_times.tough_compositor_cases", - "v8.browsing_desktop_classic", - "v8.browsing_desktop_turbo", - "v8.infinite_scroll-turbo_tbmv2", - "v8.runtimestats.browsing_desktop_classic", - "v8.runtimestats.browsing_desktop_turbo" + "v8.browsing_desktop-future", + "v8.browsing_mobile-future", + "wasm" ] }, "build188-m1": { "benchmarks": [ "blink_perf.parser", "blink_perf.svg", - "blob_storage.blob_storage", "dromaeo.domcorequery", "dromaeo.domcoretraverse", "jetstream", - "media.android.tough_video_cases", - "media.media_cns_cases", "memory.desktop", - "page_cycler_v2.basic_oopif", - "page_cycler_v2.intl_es_fr_pt-BR", - "page_cycler_v2.intl_ko_th_vi", - "page_cycler_v2.typical_25", - "power.steady_state", "power.typical_10_mobile", - "rasterize_and_record_micro.polymer", - "service_worker.service_worker", - "service_worker.service_worker_micro_benchmark", "smoothness.gpu_rasterization.tough_filters_cases", "smoothness.gpu_rasterization.tough_pinch_zoom_cases", - "smoothness.scrolling_tough_ad_cases", "smoothness.tough_canvas_cases", "smoothness.tough_pinch_zoom_cases", - "speedometer-classic", - "start_with_ext.cold.blank_page", + "speedometer-future", + "speedometer2-future", "start_with_url.cold.startup_pages", - "startup.warm.chrome_signin", - "system_health.webview_startup_multiprocess", "thread_times.tough_scrolling_cases", "v8.browsing_desktop", - "v8.detached_context_age_in_gc", - "v8.mobile_infinite_scroll-classic_tbmv2" + "v8.detached_context_age_in_gc" ] }, "build189-m1": { @@ -4454,12 +2903,8 @@ "blink_perf.shadow_dom", "kraken", "loading.mobile", - "media.mse_cases", - "media.tough_video_cases_tbmv2", + "media.desktop", "memory.long_running_idle_gmail_tbmv2", - "memory.top_10_mobile_stress", - "page_cycler_v2_site_isolation.basic_oopif", - "rasterize_and_record_micro.key_mobile_sites", "rasterize_and_record_micro.partial_invalidation", "smoothness.desktop_tough_pinch_zoom_cases", "smoothness.gpu_rasterization.tough_path_rendering_cases", @@ -4469,16 +2914,11 @@ "smoothness.tough_animation_cases", "smoothness.tough_texture_upload_cases", "smoothness.tough_webgl_ad_cases", - "start_with_ext.warm.blank_page", "start_with_url.warm.startup_pages", - "startup.large_profile.cold.blank_page", "system_health.common_desktop", "system_health.webview_startup", "thread_times.key_idle_power_cases", "thread_times.simple_mobile_sites", - "v8.browsing_mobile_turbo", - "v8.infinite_scroll-classic_tbmv2", - "v8.infinite_scroll_tbmv2", "v8.runtimestats.browsing_mobile" ] } @@ -4490,58 +2930,41 @@ "blink_perf.paint", "dromaeo.domcoremodify", "dummy_benchmark.stable_benchmark_1", - "media.android.tough_video_cases_tbmv2", - "media.tough_video_cases", + "media.mobile", "memory.top_10_mobile", - "oortonline", - "power.trivial_pages", "scheduler.tough_scheduling_cases", "smoothness.key_desktop_move_cases", "smoothness.key_mobile_sites_smooth", "smoothness.tough_ad_cases", "smoothness.tough_image_decode_cases", - "startup.cold.blank_page", - "startup.large_profile.warm.blank_page", "system_health.memory_desktop", "thread_times.key_mobile_sites_smooth", "thread_times.key_silk_cases", - "tracing.tracing_with_debug_overhead", "v8.runtime_stats.top_25" ] }, "build139-m1": { "benchmarks": [ "blink_perf.bindings", - "blink_perf.blink_gc", "blink_perf.canvas", - "blink_perf.owp_storage", "blink_perf.image_decoder", - "dummy_benchmark.noisy_benchmark_1", + "blink_perf.owp_storage", "dummy_benchmark.histogram_benchmark_1", + "dummy_benchmark.noisy_benchmark_1", "loading.desktop", "octane", "oortonline_tbmv2", - "page_cycler_v2.basic_oopif", - "page_cycler_v2.intl_ar_fa_he", "power.idle_platform", - "rasterize_and_record_micro.key_silk_cases", "smoothness.key_silk_cases", "smoothness.pathological_mobile_sites", "smoothness.top_25_smooth", "smoothness.tough_webgl_cases", - "startup.warm.blank_page", "system_health.common_mobile", "system_health.memory_mobile", "thread_times.key_hit_test_cases", "thread_times.key_noop_cases", - "thread_times.polymer", "tracing.tracing_with_background_memory_infra", "v8.browsing_mobile", - "v8.browsing_mobile_classic", - "v8.mobile_infinite_scroll-turbo_tbmv2", - "v8.mobile_infinite_scroll_tbmv2", - "v8.runtimestats.browsing_mobile_classic", - "v8.runtimestats.browsing_mobile_turbo", "webrtc" ] }, @@ -4549,13 +2972,9 @@ "benchmarks": [ "battor.trivial_pages", "blink_perf.layout", + "dromaeo", "dromaeo.domcoreattr", - "image_decoding.image_decoding_measurement", - "memory.dual_browser_test", "memory.long_running_idle_gmail_background_tbmv2", - "page_cycler_v2.intl_hi_ru", - "page_cycler_v2.intl_ja_zh", - "page_cycler_v2.top_10_mobile", "rasterize_and_record_micro.top_25", "smoothness.gpu_rasterization.polymer", "smoothness.gpu_rasterization.top_25_smooth", @@ -4567,51 +2986,32 @@ "smoothness.tough_scrolling_cases", "speedometer", "speedometer2", - "speedometer-turbo", "tab_switching.typical_25", "thread_times.tough_compositor_cases", - "v8.browsing_desktop_classic", - "v8.browsing_desktop_turbo", - "v8.infinite_scroll-turbo_tbmv2", - "v8.runtimestats.browsing_desktop_classic", - "v8.runtimestats.browsing_desktop_turbo" + "v8.browsing_desktop-future", + "v8.browsing_mobile-future", + "wasm" ] }, "build141-m1": { "benchmarks": [ "blink_perf.parser", "blink_perf.svg", - "blob_storage.blob_storage", "dromaeo.domcorequery", "dromaeo.domcoretraverse", "jetstream", - "media.android.tough_video_cases", - "media.media_cns_cases", "memory.desktop", - "page_cycler_v2.intl_es_fr_pt-BR", - "page_cycler_v2.intl_ko_th_vi", - "page_cycler_v2.typical_25", - "power.steady_state", "power.typical_10_mobile", - "rasterize_and_record_micro.polymer", - "service_worker.service_worker", - "service_worker.service_worker_micro_benchmark", "smoothness.gpu_rasterization.tough_filters_cases", "smoothness.gpu_rasterization.tough_pinch_zoom_cases", - "smoothness.scrolling_tough_ad_cases", "smoothness.tough_canvas_cases", "smoothness.tough_pinch_zoom_cases", - "speedometer-classic", - "start_with_ext.cold.blank_page", + "speedometer-future", + "speedometer2-future", "start_with_url.cold.startup_pages", - "startup.warm.chrome_signin", - "storage.indexeddb_endure", - "storage.indexeddb_endure_tracing", - "system_health.webview_startup_multiprocess", "thread_times.tough_scrolling_cases", "v8.browsing_desktop", "v8.detached_context_age_in_gc", - "v8.mobile_infinite_scroll-classic_tbmv2", "v8.runtimestats.browsing_desktop" ] }, @@ -4623,12 +3023,8 @@ "blink_perf.shadow_dom", "kraken", "loading.mobile", - "media.mse_cases", - "media.tough_video_cases_tbmv2", + "media.desktop", "memory.long_running_idle_gmail_tbmv2", - "memory.top_10_mobile_stress", - "page_cycler_v2_site_isolation.basic_oopif", - "rasterize_and_record_micro.key_mobile_sites", "rasterize_and_record_micro.partial_invalidation", "smoothness.desktop_tough_pinch_zoom_cases", "smoothness.gpu_rasterization.tough_path_rendering_cases", @@ -4638,16 +3034,11 @@ "smoothness.tough_animation_cases", "smoothness.tough_texture_upload_cases", "smoothness.tough_webgl_ad_cases", - "start_with_ext.warm.blank_page", "start_with_url.warm.startup_pages", - "startup.large_profile.cold.blank_page", "system_health.common_desktop", "system_health.webview_startup", "thread_times.key_idle_power_cases", "thread_times.simple_mobile_sites", - "v8.browsing_mobile_turbo", - "v8.infinite_scroll-classic_tbmv2", - "v8.infinite_scroll_tbmv2", "v8.runtimestats.browsing_mobile" ] } @@ -4659,75 +3050,52 @@ "blink_perf.paint", "dromaeo.domcoremodify", "dummy_benchmark.stable_benchmark_1", - "media.android.tough_video_cases_tbmv2", - "media.tough_video_cases", + "media.mobile", "memory.top_10_mobile", - "oortonline", - "power.trivial_pages", "scheduler.tough_scheduling_cases", "smoothness.key_desktop_move_cases", "smoothness.key_mobile_sites_smooth", "smoothness.tough_ad_cases", "smoothness.tough_image_decode_cases", - "startup.cold.blank_page", - "startup.large_profile.warm.blank_page", "system_health.memory_desktop", "thread_times.key_mobile_sites_smooth", "thread_times.key_silk_cases", - "tracing.tracing_with_debug_overhead", "v8.runtime_stats.top_25" ] }, "build144-m1": { "benchmarks": [ "blink_perf.bindings", - "blink_perf.blink_gc", "blink_perf.canvas", - "blink_perf.owp_storage", "blink_perf.image_decoder", - "dummy_benchmark.noisy_benchmark_1", + "blink_perf.owp_storage", "dummy_benchmark.histogram_benchmark_1", + "dummy_benchmark.noisy_benchmark_1", "loading.desktop", "octane", "oortonline_tbmv2", - "page_cycler_v2.basic_oopif", - "page_cycler_v2.intl_ar_fa_he", "power.idle_platform", - "rasterize_and_record_micro.key_silk_cases", "smoothness.key_silk_cases", "smoothness.pathological_mobile_sites", "smoothness.top_25_smooth", "smoothness.tough_webgl_cases", - "startup.warm.blank_page", - "storage.indexeddb_endure", - "storage.indexeddb_endure_tracing", "system_health.common_mobile", "system_health.memory_mobile", "thread_times.key_hit_test_cases", "thread_times.key_noop_cases", - "thread_times.polymer", "thread_times.tough_scrolling_cases", "tracing.tracing_with_background_memory_infra", "v8.browsing_mobile", - "v8.browsing_mobile_classic", - "v8.mobile_infinite_scroll-turbo_tbmv2", - "v8.mobile_infinite_scroll_tbmv2", - "v8.runtimestats.browsing_desktop", - "v8.runtimestats.browsing_mobile_classic", - "v8.runtimestats.browsing_mobile_turbo" + "v8.runtimestats.browsing_desktop" ] }, "build145-m1": { "benchmarks": [ "battor.trivial_pages", "blink_perf.layout", + "dromaeo", "dromaeo.domcoreattr", - "image_decoding.image_decoding_measurement", - "memory.dual_browser_test", "memory.long_running_idle_gmail_background_tbmv2", - "page_cycler_v2.intl_hi_ru", - "page_cycler_v2.intl_ja_zh", - "page_cycler_v2.top_10_mobile", "rasterize_and_record_micro.top_25", "smoothness.gpu_rasterization.polymer", "smoothness.gpu_rasterization.top_25_smooth", @@ -4739,49 +3107,31 @@ "smoothness.tough_scrolling_cases", "speedometer", "speedometer2", - "speedometer-turbo", "tab_switching.typical_25", "thread_times.tough_compositor_cases", - "v8.browsing_desktop_classic", - "v8.browsing_desktop_turbo", - "v8.infinite_scroll-turbo_tbmv2", - "v8.runtimestats.browsing_desktop_classic", - "v8.runtimestats.browsing_desktop_turbo" + "v8.browsing_desktop-future", + "v8.browsing_mobile-future", + "wasm" ] }, "build146-m1": { "benchmarks": [ "blink_perf.parser", "blink_perf.svg", - "blob_storage.blob_storage", "dromaeo.domcorequery", "dromaeo.domcoretraverse", "jetstream", - "media.android.tough_video_cases", - "media.media_cns_cases", "memory.desktop", - "page_cycler_v2.intl_es_fr_pt-BR", - "page_cycler_v2.intl_ko_th_vi", - "page_cycler_v2.typical_25", - "power.steady_state", "power.typical_10_mobile", - "rasterize_and_record_micro.polymer", - "service_worker.service_worker", - "service_worker.service_worker_micro_benchmark", "smoothness.gpu_rasterization.tough_filters_cases", "smoothness.gpu_rasterization.tough_pinch_zoom_cases", - "smoothness.scrolling_tough_ad_cases", "smoothness.tough_canvas_cases", "smoothness.tough_pinch_zoom_cases", - "speedometer-classic", - "start_with_ext.cold.blank_page", + "speedometer-future", + "speedometer2-future", "start_with_url.cold.startup_pages", - "startup.warm.chrome_signin", - "system_health.webview_startup_multiprocess", "v8.browsing_desktop", "v8.detached_context_age_in_gc", - "v8.infinite_scroll_tbmv2", - "v8.mobile_infinite_scroll-classic_tbmv2", "webrtc" ] }, @@ -4793,12 +3143,8 @@ "blink_perf.shadow_dom", "kraken", "loading.mobile", - "media.mse_cases", - "media.tough_video_cases_tbmv2", + "media.desktop", "memory.long_running_idle_gmail_tbmv2", - "memory.top_10_mobile_stress", - "page_cycler_v2_site_isolation.basic_oopif", - "rasterize_and_record_micro.key_mobile_sites", "rasterize_and_record_micro.partial_invalidation", "smoothness.desktop_tough_pinch_zoom_cases", "smoothness.gpu_rasterization.tough_path_rendering_cases", @@ -4808,15 +3154,11 @@ "smoothness.tough_animation_cases", "smoothness.tough_texture_upload_cases", "smoothness.tough_webgl_ad_cases", - "start_with_ext.warm.blank_page", "start_with_url.warm.startup_pages", - "startup.large_profile.cold.blank_page", "system_health.common_desktop", "system_health.webview_startup", "thread_times.key_idle_power_cases", "thread_times.simple_mobile_sites", - "v8.browsing_mobile_turbo", - "v8.infinite_scroll-classic_tbmv2", "v8.runtimestats.browsing_mobile" ] } @@ -4829,14 +3171,14 @@ "blink_perf.css", "blink_perf.dom", "blink_perf.events", + "blink_perf.image_decoder", "blink_perf.layout", "blink_perf.owp_storage", - "blink_perf.image_decoder", "blink_perf.paint", "blink_perf.parser", "blink_perf.shadow_dom", "blink_perf.svg", - "blob_storage.blob_storage", + "dromaeo", "dromaeo.domcoreattr", "dromaeo.domcoremodify", "dromaeo.domcorequery", @@ -4844,38 +3186,23 @@ "dummy_benchmark.histogram_benchmark_1", "dummy_benchmark.noisy_benchmark_1", "dummy_benchmark.stable_benchmark_1", - "image_decoding.image_decoding_measurement", "jetstream", "kraken", "loading.desktop", "loading.mobile", - "media.android.tough_video_cases", - "media.android.tough_video_cases_tbmv2", - "media.media_cns_cases", - "media.mse_cases", - "media.tough_video_cases", - "media.tough_video_cases_tbmv2", + "media.desktop", + "media.mobile", "memory.desktop", "memory.long_running_idle_gmail_background_tbmv2", "memory.long_running_idle_gmail_tbmv2", "memory.top_10_mobile", "octane", - "oortonline", "oortonline_tbmv2", - "page_cycler_v2.basic_oopif", - "page_cycler_v2_site_isolation.basic_oopif", "power.idle_platform", - "power.steady_state", - "power.trivial_pages", "power.typical_10_mobile", - "rasterize_and_record_micro.key_mobile_sites", - "rasterize_and_record_micro.key_silk_cases", "rasterize_and_record_micro.partial_invalidation", - "rasterize_and_record_micro.polymer", "rasterize_and_record_micro.top_25", "scheduler.tough_scheduling_cases", - "service_worker.service_worker", - "service_worker.service_worker_micro_benchmark", "smoothness.desktop_tough_pinch_zoom_cases", "smoothness.gpu_rasterization.polymer", "smoothness.gpu_rasterization.top_25_smooth", @@ -4890,7 +3217,6 @@ "smoothness.key_silk_cases", "smoothness.maps", "smoothness.pathological_mobile_sites", - "smoothness.scrolling_tough_ad_cases", "smoothness.simple_mobile_sites", "smoothness.sync_scroll.key_mobile_sites_smooth", "smoothness.top_25_smooth", @@ -4906,18 +3232,11 @@ "smoothness.tough_webgl_ad_cases", "smoothness.tough_webgl_cases", "speedometer", + "speedometer-future", "speedometer2", - "start_with_ext.cold.blank_page", - "start_with_ext.warm.blank_page", + "speedometer2-future", "start_with_url.cold.startup_pages", "start_with_url.warm.startup_pages", - "startup.cold.blank_page", - "startup.large_profile.cold.blank_page", - "startup.large_profile.warm.blank_page", - "startup.warm.blank_page", - "startup.warm.chrome_signin", - "storage.indexeddb_endure", - "storage.indexeddb_endure_tracing", "system_health.common_desktop", "system_health.common_mobile", "system_health.memory_desktop", @@ -4929,20 +3248,19 @@ "thread_times.key_mobile_sites_smooth", "thread_times.key_noop_cases", "thread_times.key_silk_cases", - "thread_times.polymer", "thread_times.simple_mobile_sites", "thread_times.tough_compositor_cases", "thread_times.tough_scrolling_cases", "tracing.tracing_with_background_memory_infra", - "tracing.tracing_with_debug_overhead", "v8.browsing_desktop", + "v8.browsing_desktop-future", "v8.browsing_mobile", + "v8.browsing_mobile-future", "v8.detached_context_age_in_gc", - "v8.infinite_scroll_tbmv2", - "v8.mobile_infinite_scroll_tbmv2", "v8.runtime_stats.top_25", "v8.runtimestats.browsing_desktop", "v8.runtimestats.browsing_mobile", + "wasm", "webrtc" ] }
diff --git a/tools/perf/core/desktop_benchmark_avg_times.json b/tools/perf/core/desktop_benchmark_avg_times.json index 206436c..b62c4e9f 100644 --- a/tools/perf/core/desktop_benchmark_avg_times.json +++ b/tools/perf/core/desktop_benchmark_avg_times.json
@@ -40,7 +40,6 @@ "kraken": 30.564739039895958, "loading.desktop": 4906.865, "media.media_cns_cases": 175.98004016036506, - "media.mse_cases": 40.25715385278066, "media.tough_video_cases": 497.14298761720244, "media.tough_video_cases_extra": 275.80860590281554, "memory.long_running_idle_gmail_background_tbmv2": 188.2264252694185,
diff --git a/tools/perf/core/generate_system_health_csv_unittest.py b/tools/perf/core/generate_system_health_csv_unittest.py new file mode 100644 index 0000000..998215c --- /dev/null +++ b/tools/perf/core/generate_system_health_csv_unittest.py
@@ -0,0 +1,48 @@ +# Copyright 2017 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 unittest +import sys + +from core import system_health_csv_generator +from core import path_util +sys.path.insert(1, path_util.GetTelemetryDir()) # To resolve telemetry imports + + +class GenerateSystemHealthCSVTest(unittest.TestCase): + def testPopulateExpectations(self): + expected_result = { + 'browse:media:tumblr': 'Mac 10.11', + 'browse:news:cnn': 'Mac Platforms', + 'browse:news:hackernews': 'Win Platforms, Mac Platforms', + 'browse:search:google': 'Win Platforms', + 'browse:tools:earth': 'All Platforms', + 'browse:tools:maps': 'All Platforms', + 'play:media:google_play_music': 'All Platforms', + 'play:media:pandora': 'All Platforms', + 'play:media:soundcloud': 'Win Platforms'} + all_expects = [{ + 'browse:news:cnn': [( + ['Mac Platforms'], 'crbug.com/728576')], + 'browse:tools:earth': [( + ['All Platforms'], 'crbug.com/760966')], + 'browse:news:hackernews': [( + ['Win Platforms', 'Mac Platforms'], + 'crbug.com/712694')], + 'play:media:soundcloud': [( + ['Win Platforms'], 'crbug.com/649392')], + 'play:media:google_play_music': [( + ['All Platforms'], 'crbug.com/649392')], + 'browse:tools:maps': [( + ['All Platforms'], 'crbug.com/712694')], + 'browse:search:google': [( + ['Win Platforms'], 'win:crbug.com/673775, mac:crbug.com/756027')], + 'browse:media:tumblr': [( + ['Mac 10.11'], 'crbug.com/760966')], + 'play:media:pandora': [( + ['All Platforms'], 'crbug.com/649392')], + }] + self.assertEquals( + expected_result, + system_health_csv_generator.PopulateExpectations(all_expects))
diff --git a/tools/perf/core/path_util.py b/tools/perf/core/path_util.py index acb100c..3f499af 100644 --- a/tools/perf/core/path_util.py +++ b/tools/perf/core/path_util.py
@@ -70,3 +70,6 @@ android_pylib_path = GetAndroidPylibDir() if android_pylib_path not in sys.path: sys.path.insert(1, android_pylib_path) + +def GetExpectationsPath(): + return os.path.join(GetPerfDir(), 'expectations.config')
diff --git a/tools/perf/core/perf_data_generator.py b/tools/perf/core/perf_data_generator.py index 3abf199..e055d9a 100755 --- a/tools/perf/core/perf_data_generator.py +++ b/tools/perf/core/perf_data_generator.py
@@ -5,17 +5,17 @@ # pylint: disable=too-many-lines -"""Script to generate chromium.perf.json and chromium.perf.fyi.json in +"""Script to generate chromium.perf.json in the src/testing/buildbot directory and benchmark.csv in the src/tools/perf directory. Maintaining these files by hand is too unwieldy. +Note: chromium.perf.fyi.json is updated manuall for now until crbug.com/757933 +is complete. """ -import argparse import collections import csv import json import os import re -import sys import sets @@ -24,7 +24,6 @@ from telemetry import benchmark as benchmark_module from telemetry import decorators -from telemetry.story import expectations from py_utils import discover @@ -32,6 +31,7 @@ _UNSCHEDULED_TELEMETRY_BENCHMARKS = set([ + 'experimental.startup.android.coldish' ]) @@ -59,6 +59,14 @@ def add_tester(waterfall, name, perf_id, platform, target_bits=64, num_host_shards=1, num_device_shards=1, swarming=None, replace_system_webview=False): + """ Adds tester named |name| to |waterfall|. + + Tests can be added via 'perf_tests', which expects a 2 element tuple of + (isolate_name, shard), or via 'perf_tests_with_args', which allows you + to specify command line arguments for the tests. 'perf_tests_with_args' + expects a tuple of 4 elements: (name, shard, test_args, isolate_name). + 'test_args' is a list of strings pass via the test's command line. + """ del perf_id # this will be needed waterfall['testers'][name] = { 'platform': platform, @@ -75,64 +83,29 @@ return waterfall -def get_fyi_waterfall_config(): - waterfall = {'builders':{}, 'testers': {}} - waterfall = add_tester( - waterfall, 'Win 10 Low-End Perf Tests', - 'win-10-low-end', 'win', - swarming=[ - { - 'gpu': '1002:9874', - 'os': 'Windows-10-10586', - 'pool': 'Chrome-perf-fyi', - 'device_ids': [ - 'build171-b4', 'build186-b4', 'build202-b4', 'build203-b4', - 'build204-b4', 'build205-b4', 'build206-b4', 'build207-b4', - 'build208-b4', 'build209-b4', 'build210-b4', 'build211-b4', - 'build212-b4', 'build213-b4', 'build214-b4', 'build215-b4', - 'build216-b4', 'build217-b4', 'build218-b4', 'build219-b4', - 'build220-b4', 'build221-b4'] - } - ]) - waterfall = add_tester( - waterfall, 'Win 10 4 Core Low-End Perf Tests', - 'win-10-4-core-low-end', 'win', - swarming=[ - { - 'gpu': '8086:22b1', - 'os': 'Windows-10-10586', - 'pool': 'Chrome-perf-fyi', - 'device_ids': [ - 'build136-b1', 'build137-b1', 'build138-b1', 'build139-b1', - 'build140-b1', 'build141-b1', 'build142-b1', 'build143-b1', - 'build144-b1', 'build145-b1', 'build146-b1', 'build147-b1', - 'build148-b1', 'build149-b1', 'build150-b1', 'build151-b1', - 'build152-b1', 'build153-b1', 'build154-b1', 'build155-b1', - 'build47-b4', 'build48-b4'], - 'perf_tests': [ - ('cc_perftests', 'build136-b1'), - ('gpu_perftests', 'build136-b1'), - ('load_library_perf_tests', 'build136-b1'), - ('angle_perftests', 'build137-b1'), - ('performance_browser_tests', 'build137-b1'), - ('tracing_perftests', 'build137-b1')] - } - ]) - - return waterfall +# Additional compile targets to add to builders. +# On desktop builders, chromedriver is added as an additional compile target. +# The perf waterfall builds this target for each commit, and the resulting +# ChromeDriver is archived together with Chrome for use in bisecting. +# This can be used by Chrome test team, as well as by google3 teams for +# bisecting Chrome builds with their web tests. For questions or to report +# issues, please contact johnchen@chromium.org and stgao@chromium.org. +BUILDER_ADDITIONAL_COMPILE_TARGETS = { + 'Android Compile': ['microdump_stackwalk', 'angle_perftests'], + 'Android arm64 Compile': ['microdump_stackwalk', 'angle_perftests'], + 'Linux Builder': ['chromedriver'], + 'Mac Builder': ['chromedriver'], + 'Win Builder': ['chromedriver'], + 'Win x64 Builder': ['chromedriver'], +} def get_waterfall_config(): waterfall = {'builders':{}, 'testers': {}} - waterfall = add_builder( - waterfall, 'Android Compile', additional_compile_targets=[ - 'microdump_stackwalk' - ]) - waterfall = add_builder( - waterfall, 'Android arm64 Compile', additional_compile_targets=[ - 'microdump_stackwalk' - ]) + for builder, targets in BUILDER_ADDITIONAL_COMPILE_TARGETS.items(): + waterfall = add_builder( + waterfall, builder, additional_compile_targets=targets) # These configurations are taken from chromium_perf.py in # build/scripts/slave/recipe_modules/chromium_tests and must be kept in sync @@ -158,7 +131,12 @@ ('tracing_perftests', 'build73-b1--device2'), ('gpu_perftests', 'build73-b1--device2'), # ('cc_perftests', 'build73-b1--device2'), # crbug.com/721757 - ] + ('media_perftests', 'build74-b1--device7'), + ], + 'perf_tests_with_args': [ + ('angle_perftests', 'build73-b1--device4', ['--shard-timeout=180'], + 'angle_perftests'), + ] } ]) waterfall = add_tester( @@ -255,7 +233,7 @@ ], 'perf_tests': [ ('tracing_perftests', 'build17-b1--device2'), - ('gpu_perftests', 'build18-b1--device2'), + # ('gpu_perftests', 'build18-b1--device2'), https://crbug.com/775219 # ('cc_perftests', 'build47-b1--device2'), https://crbug.com/736150 ] } @@ -333,7 +311,8 @@ 'build134-m1', 'build135-m1', 'build136-m1' ], 'perf_tests': [ - ('media_perftests', 'build134-m1')] + ('media_perftests', 'build134-m1'), + ('views_perftests', 'build135-m1')] } ]) waterfall = add_tester( @@ -402,7 +381,8 @@ 'build103-m1', 'build104-m1', 'build105-m1' ], 'perf_tests': [ - ('angle_perftests', 'build103-m1'), + # crbug.com/785291 + # ('angle_perftests', 'build103-m1'), ('load_library_perf_tests', 'build103-m1'), ('performance_browser_tests', 'build103-m1'), ('media_perftests', 'build104-m1')] @@ -431,7 +411,7 @@ 'chromium-rel-win7-gpu-nvidia', 'win', swarming=[ { - 'gpu': '10de:104a', + 'gpu': '10de:1cb3', 'os': 'Windows-2008ServerR2-SP1', 'pool': 'Chrome-perf', 'device_ids': [ @@ -443,27 +423,19 @@ ('load_library_perf_tests', 'build94-m1'), # crbug.com/735679 # ('performance_browser_tests', 'build94-m1'), - ('media_perftests', 'build95-m1')] + ('media_perftests', 'build95-m1') + ], + 'perf_tests_with_args': [ + ('passthrough_command_buffer_perftests', 'build94-m1', + ['--use-cmd-decoder=passthrough', '--use-angle=gl-null'], + 'command_buffer_perftests'), + ('validating_command_buffer_perftests', 'build94-m1', + ['--use-cmd-decoder=validating', '--use-stub'], + 'command_buffer_perftests')] } ]) waterfall = add_tester( - waterfall, 'Mac 10.11 Perf', 'chromium-rel-mac11', - 'mac', - swarming=[ - { - 'gpu': '8086:0166', - 'os': 'Mac-10.11', - 'pool': 'Chrome-perf', - 'device_ids': [ - 'build102-b1', 'build103-b1', - 'build104-b1', 'build105-b1', 'build106-b1' - ], - 'perf_tests': [ - ('media_perftests', 'build105-b1')] - } - ]) - waterfall = add_tester( waterfall, 'Mac 10.12 Perf', 'chromium-rel-mac12', 'mac', swarming=[ @@ -476,23 +448,7 @@ 'build161-m1', 'build162-m1'], 'perf_tests': [ ('net_perftests', 'build159-m1'), - ] - } - ]) - waterfall = add_tester( - waterfall, 'Mac Retina Perf', - 'chromium-rel-mac-retina', 'mac', - swarming=[ - { - 'gpu': '8086:0d26', - 'os': 'Mac-10.11', - 'pool': 'Chrome-perf', - 'device_ids': [ - 'build4-b1', 'build5-b1', 'build6-b1', 'build7-b1', - 'build30-b4' # replacing build8-b1. crbug.com/724998 - ], - 'perf_tests': [ - ('performance_browser_tests', 'build30-b4') + ('views_perftests', 'build160-m1'), ] } ]) @@ -530,39 +486,27 @@ ] } ]) - waterfall = add_tester( - waterfall, 'Mac Mini 8GB 10.12 Perf', - 'chromium-rel-mac12-mini-8gb', 'mac', - swarming=[ - { - 'gpu': '8086:0a26', - 'os': 'Mac-10.12', - 'pool': 'Chrome-perf', - 'device_ids': [ - 'build24-b1', 'build25-b1', - 'build26-b1', 'build27-b1', 'build28-b1' - ] - } - ]) waterfall = add_tester( waterfall, 'Linux Perf', 'linux-release', 'linux', swarming=[ { - 'gpu': '102b:0534', + 'gpu': '10de:1cb3', 'os': 'Ubuntu-14.04', 'pool': 'Chrome-perf', 'device_ids': [ - 'build148-m1', 'build149-m1', - 'build150-m1', 'build151-m1', 'build152-m1' + 'build27-a9', 'build28-a9', 'build29-a9', + 'build30-a9', 'build31-a9', ], 'perf_tests': [ # crbug.com/698831 # ('cc_perftests', 'build150-m1'), - ('load_library_perf_tests', 'build150-m1'), - ('net_perftests', 'build150-m1'), - ('tracing_perftests', 'build150-m1'), - ('media_perftests', 'build151-m1')] + ('load_library_perf_tests', 'build29-a9'), + ('net_perftests', 'build29-a9'), + ('tracing_perftests', 'build29-a9'), + ('media_perftests', 'build30-a9'), + ('views_perftests', 'build31-a9') + ] } ]) @@ -589,36 +533,19 @@ 'expiration': 10 * 60 * 60, # 10 hour timeout 'hard_timeout': swarming_timeout if swarming_timeout else 10800, # 3 hours 'ignore_task_failure': ignore_task_failure, - 'io_timeout': io_timeout if io_timeout else 600, # 10 minutes + 'io_timeout': io_timeout if io_timeout else 1200, # 20 minutes 'dimension_sets': swarming_dimensions, - 'upload_test_results': False, + 'upload_test_results': True, } - if step_name in BENCHMARKS_TO_UPLOAD_TO_FLAKINESS_DASHBOARD: - result['swarming']['upload_test_results'] = True return result -# Manually curated for now. System health is in here because it's an important -# benchmark. Others are semi randomly chosen; they've failed on the waterfall -# recently, so should be useful to upload. -BENCHMARKS_TO_UPLOAD_TO_FLAKINESS_DASHBOARD = [ - 'service_worker.service_worker', - 'smoothness.tough_texture_upload_cases', - 'smoothness.tough_webgl_ad_cases', - 'system_health.common_desktop', - 'system_health.common_mobile', - 'system_health.memory_desktop', - 'system_health.memory_mobile', - 'v8.browsing_mobile', - 'v8.browsing_desktop', - 'v8.runtimestats.browsing_mobile', - 'v8.runtimestats.browsing_desktop', +BENCHMARKS_TO_OUTPUT_HISTOGRAMS = [ + 'dummy_benchmark.noisy_benchmark_1', + 'dummy_benchmark.stable_benchmark_1', ] -BENCHMARKS_TO_OUTPUT_HISTOGRAMS = [] - - def generate_telemetry_test(swarming_dimensions, benchmark_name, browser): # The step name must end in 'test' or 'tests' in order for the # results to automatically show up on the flakiness dashboard. @@ -687,15 +614,30 @@ return complete_dimension +def generate_cplusplus_isolate_script_entry( + dimension, name, shard, test_args, isolate_name): + return generate_isolate_script_entry( + [get_swarming_dimension(dimension, shard)], test_args, isolate_name, + name, ignore_task_failure=False) + + def generate_cplusplus_isolate_script_test(dimension): return [ - generate_isolate_script_entry( - [get_swarming_dimension(dimension, shard)], [], name, - name, ignore_task_failure=False) + generate_cplusplus_isolate_script_entry( + dimension, name, shard, [], name) for name, shard in dimension['perf_tests'] ] +def generate_cplusplus_isolate_script_test_with_args(dimension): + return [ + generate_cplusplus_isolate_script_entry( + dimension, name, shard, test_args, isolate_name) + for name, shard, test_args, isolate_name + in dimension['perf_tests_with_args'] + ] + + def ShouldBenchmarksBeScheduled( benchmark, name, os_name, browser_name): # StoryExpectations uses finder_options.browser_type, platform.GetOSName, @@ -785,7 +727,7 @@ 'add the benchmark to ' '_UNSCHEDULED_TELEMETRY_BENCHMARKS list, ' 'then file a bug with Speed>Benchmarks>Waterfall ' - 'component and assign to eyaich@ or martiniss@ to ' + 'component and assign to eyaich@ or ashleymarie@ to ' 'schedule the benchmark on the perf waterfall.' % ( benchmark.Name())) swarming_dimensions.append(get_swarming_dimension( @@ -814,7 +756,7 @@ BENCHMARK_SWARMING_TIMEOUTS = { 'loading.desktop': 14400, # 4 hours (crbug.com/753798) 'loading.mobile': 16200, # 4.5 hours - 'system_health.memory_mobile': 10800, # 3 hours + 'system_health.memory_mobile': 14400, # 4 hours (crbug.com/775242) 'system_health.memory_desktop': 10800, # 3 hours } @@ -832,9 +774,9 @@ # List of benchmarks that are to never be run with reference builds. BENCHMARK_REF_BUILD_BLACKLIST = [ - 'power.idle_platform', # No browser used in benchmark. 'loading.desktop', # Long running benchmark. 'loading.mobile', # Long running benchmark. + 'power.idle_platform', # No browser used in benchmark. 'v8.runtime_stats.top_25', # Long running benchmark. ] @@ -898,6 +840,9 @@ if config['swarming_dimensions'][0].get('perf_tests', False): isolated_scripts += generate_cplusplus_isolate_script_test( config['swarming_dimensions'][0]) + if config['swarming_dimensions'][0].get('perf_tests_with_args', False): + isolated_scripts += generate_cplusplus_isolate_script_test_with_args( + config['swarming_dimensions'][0]) isolated_scripts, devices_to_test_skipped = remove_blacklisted_device_tests( isolated_scripts, BLACKLISTED_DEVICES) @@ -927,56 +872,11 @@ return os.path.join(buildbot_dir, filename) -def get_extras_json_config_file_for_waterfall(waterfall): - filename = '%s.extras.json' % waterfall['name'] - buildbot_dir = os.path.join(path_util.GetChromiumSrcDir(), 'tools', 'perf') - return os.path.join(buildbot_dir, filename) - - -def append_extra_tests(waterfall, tests): - """Appends extra tests to |tests|. - - Those extra tests are loaded from tools/perf/<waterfall name>.extras.json. - """ - extra_config_file = get_extras_json_config_file_for_waterfall(waterfall) - if os.path.isfile(extra_config_file): - with open(extra_config_file) as extra_fp: - extra_tests = json.load(extra_fp) - for key, value in extra_tests.iteritems(): - if key == 'comment': - continue - assert key not in tests - tests[key] = value - - -def tests_are_up_to_date(waterfalls): - up_to_date = True - all_tests = {} - for w in waterfalls: - tests = generate_all_tests(w) - # Note: |all_tests| don't cover those manually-specified tests added by - # append_extra_tests(). - all_tests.update(tests) - append_extra_tests(w, tests) - tests_data = json.dumps(tests, indent=2, separators=(',', ': '), - sort_keys=True) - config_file = get_json_config_file_for_waterfall(w) - with open(config_file, 'r') as fp: - config_data = fp.read().strip() - up_to_date &= tests_data == config_data - verify_all_tests_in_benchmark_csv(all_tests, - get_all_waterfall_benchmarks_metadata()) - return up_to_date - - def update_all_tests(waterfalls): all_tests = {} for w in waterfalls: tests = generate_all_tests(w) - # Note: |all_tests| don't cover those manually-specified tests added by - # append_extra_tests(). all_tests.update(tests) - append_extra_tests(w, tests) config_file = get_json_config_file_for_waterfall(w) with open(config_file, 'w') as fp: json.dump(tests, fp, indent=2, separators=(',', ': '), sort_keys=True) @@ -991,16 +891,28 @@ BenchmarkMetadata = collections.namedtuple( 'BenchmarkMetadata', 'emails component not_scheduled') NON_TELEMETRY_BENCHMARKS = { - 'angle_perftests': BenchmarkMetadata('jmadill@chromium.org', None, False), + 'angle_perftests': BenchmarkMetadata( + 'jmadill@chromium.org, chrome-gpu-perf-owners@chromium.org', + 'Internals>GPU>ANGLE', False), + 'validating_command_buffer_perftests': BenchmarkMetadata( + 'piman@chromium.org, chrome-gpu-perf-owners@chromium.org', + 'Internals>GPU', False), + 'passthrough_command_buffer_perftests': BenchmarkMetadata( + 'piman@chromium.org, chrome-gpu-perf-owners@chromium.org', + 'Internals>GPU>ANGLE', False), 'net_perftests': BenchmarkMetadata('xunjieli@chromium.org', None, False), 'cc_perftests': BenchmarkMetadata('enne@chromium.org', None, False), - 'gpu_perftests': BenchmarkMetadata('reveman@chromium.org', None, False), + 'gpu_perftests': BenchmarkMetadata( + 'reveman@chromium.org, chrome-gpu-perf-owners@chromium.org', + 'Internals>GPU', False), 'tracing_perftests': BenchmarkMetadata( 'kkraynov@chromium.org, primiano@chromium.org', None, False), 'load_library_perf_tests': BenchmarkMetadata(None, None, False), 'media_perftests': BenchmarkMetadata('crouleau@chromium.org', None, False), 'performance_browser_tests': BenchmarkMetadata( - 'miu@chromium.org', None, False) + 'miu@chromium.org', None, False), + 'views_perftests': BenchmarkMetadata( + 'tapted@chromium.org', 'Internals>Views', False) } @@ -1025,17 +937,11 @@ benchmark_list = current_benchmarks() for benchmark in benchmark_list: - exp = benchmark().GetExpectations() - disabled = 'all' in decorators.GetDisabledAttributes(benchmark) or any( - any(isinstance(condition, expectations.ALL.__class__) - for condition in conditions) - for (conditions, _) in exp.disabled_platforms) - emails = decorators.GetEmails(benchmark) if emails: emails = ', '.join(emails) metadata[benchmark.Name()] = BenchmarkMetadata( - emails, decorators.GetComponent(benchmark), disabled) + emails, decorators.GetComponent(benchmark), False) return metadata @@ -1049,9 +955,8 @@ elif 'scripts' in tests[t]: scripts = tests[t]['scripts'] else: - assert('Android Compile' == t - or 'Android arm64 Compile' == t - or t.startswith('AAAAA')), 'Unknown test data %s' % t + assert(t in BUILDER_ADDITIONAL_COMPILE_TARGETS + or t.startswith('AAAAA')), 'Unknown test data %s' % t for s in scripts: name = s['name'] name = re.sub('\\.reference$', '', name) @@ -1135,33 +1040,9 @@ writer.writerows(csv_data) -def main(args): - parser = argparse.ArgumentParser( - description=('Generate perf test\' json config and benchmark.csv. ' - 'This needs to be done anytime you add/remove any existing' - 'benchmarks in tools/perf/benchmarks.')) - parser.add_argument( - '--validate-only', action='store_true', default=False, - help=('Validate whether the perf json generated will be the same as the ' - 'existing configs. This does not change the contain of existing ' - 'configs')) - options = parser.parse_args(args) - +def main(): waterfall = get_waterfall_config() waterfall['name'] = 'chromium.perf' - fyi_waterfall = get_fyi_waterfall_config() - fyi_waterfall['name'] = 'chromium.perf.fyi' - if options.validate_only: - if tests_are_up_to_date([fyi_waterfall, waterfall]): - print 'All the perf JSON config files are up-to-date. \\o/' - return 0 - else: - print ('The perf JSON config files are not up-to-date. Please run %s ' - 'without --validate-only flag to update the perf JSON ' - 'configs and benchmark.csv.') % sys.argv[0] - return 1 - else: - update_all_tests([fyi_waterfall, waterfall]) - update_benchmark_csv() - return 0 + update_all_tests([waterfall]) + update_benchmark_csv()
diff --git a/tools/perf/core/perf_data_generator_unittest.py b/tools/perf/core/perf_data_generator_unittest.py index e01f88c..18b1b2e 100644 --- a/tools/perf/core/perf_data_generator_unittest.py +++ b/tools/perf/core/perf_data_generator_unittest.py
@@ -7,7 +7,6 @@ from core.perf_data_generator import BenchmarkMetadata from telemetry import benchmark -from telemetry import story import mock @@ -91,8 +90,8 @@ 'hard_timeout': 10800, 'can_use_on_swarming_builders': True, 'expiration': 36000, - 'io_timeout': 600, - 'upload_test_results': False, + 'io_timeout': 1200, + 'upload_test_results': True, }, 'name': 'speedometer', 'isolate_name': 'telemetry_perf_tests', @@ -115,8 +114,8 @@ 'hard_timeout': 10800, 'can_use_on_swarming_builders': True, 'expiration': 36000, - 'io_timeout': 600, - 'upload_test_results': False, + 'io_timeout': 1200, + 'upload_test_results': True, }, 'name': 'speedometer.reference', 'isolate_name': 'telemetry_perf_tests', @@ -150,28 +149,6 @@ '--webview-embedder-apk=../../out/Release/apks/SystemWebViewShell.apk']) self.assertEquals(test['isolate_name'], 'telemetry_perf_webview_tests') - def testGenerateTelemetryTestsWithUploadToFlakinessDashboard(self): - swarming_dimensions = [{'os': 'SkyNet', 'id': 'T-850', 'pool': 'T-RIP'}] - test = perf_data_generator.generate_telemetry_test( - swarming_dimensions, 'system_health.common_desktop', 'release') - expected_generated_test = { - 'override_compile_targets': ['telemetry_perf_tests'], - 'args': ['system_health.common_desktop', '-v', '--upload-results', - '--browser=release', '--output-format=chartjson'], - 'swarming': { - 'ignore_task_failure': False, - 'dimension_sets': [{'os': 'SkyNet', 'id': 'T-850', 'pool': 'T-RIP'}], - 'hard_timeout': 10800, - 'can_use_on_swarming_builders': True, - 'expiration': 36000, - 'io_timeout': 600, - 'upload_test_results': True, - }, - 'name': 'system_health.common_desktop', - 'isolate_name': 'telemetry_perf_tests', - } - self.assertEquals(test, expected_generated_test) - def testGenerateTelemetryTestsBlacklistedReferenceBuildTest(self): class BlacklistedBenchmark(benchmark.Benchmark): @classmethod @@ -257,33 +234,6 @@ 'build2-b1': ['other_test', 'test'], })) - def testExtraTestsAreLoadedFromFile(self): - tests = { - 'Linux Perf': {} - } - - mock_extras_json = ''' - { - "comment": [ "This is comment and therefore should be skipped." ], - "Mojo Linux Perf": {} - } - ''' - - mock_waterfall_name = 'hello' - - def mockIsFile(path): - return path.endswith('%s.extras.json' % mock_waterfall_name) - - with mock.patch('os.path.isfile', side_effect=mockIsFile): - with mock.patch('__builtin__.open', - mock.mock_open(read_data=mock_extras_json)): - perf_data_generator.append_extra_tests({'name': mock_waterfall_name}, - tests) - - self.assertTrue('Linux Perf' in tests) - self.assertTrue('Mojo Linux Perf' in tests) - self.assertFalse('comment' in tests) - def testShouldBenchmarksBeScheduledBadOS(self): class RegularBenchmark(benchmark.Benchmark): @classmethod @@ -305,24 +255,6 @@ perf_data_generator.ShouldBenchmarksBeScheduled( RegularBenchmark, 'bot_name', os, None)) - def testShouldBenchmarksBeScheduledDisabledButScheduled(self): - class RegularBenchmark(benchmark.Benchmark): - @classmethod - def Name(cls): - return 'regular' - - def GetExpectations(self): - class Expectations(story.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableBenchmark([story.expectations.ALL], 'reason') - return Expectations() - - valid_os_list = ['mac', 'android', 'windows', 'linux'] - for os in valid_os_list: - self.assertTrue( - perf_data_generator.ShouldBenchmarksBeScheduled( - RegularBenchmark, 'bot_name', os, None)) - def testShouldBenchmarkBeScheduledSupportedPlatform(self): class RegularBenchmark(benchmark.Benchmark): SUPPORTED_PLATFORMS = [] @@ -334,3 +266,53 @@ self.assertFalse( perf_data_generator.ShouldBenchmarksBeScheduled( RegularBenchmark, 'bot_name', 'mac', None)) + + def testListsAlphabetical(self): + keys = [ + 'BENCHMARK_REF_BUILD_BLACKLIST', + 'SVELTE_DEVICE_LIST' + ] + for key in keys: + lst = getattr(perf_data_generator, key) + self.assertEqual(sorted(lst), lst, 'please sort %s' % key) + + def testGenerateCplusplusIsolateScriptTest(self): + dimension={ + 'gpu': '10de:104a', + 'os': 'Windows-2008ServerR2-SP1', + 'pool': 'Chrome-perf', + 'device_ids': [ + 'build92-m1', 'build93-m1', + 'build94-m1', 'build95-m1', 'build96-m1' + ], + 'perf_tests': [ + ('angle_perftests', 'build94-m1'), + ], + } + test = perf_data_generator.generate_cplusplus_isolate_script_test(dimension) + test = test[0] + self.assertEqual(test['name'], 'angle_perftests') + self.assertEqual(test['isolate_name'], 'angle_perftests') + + def testGenerateCplusplusIsolateScriptTestWithArgs(self): + dimension={ + 'gpu': '10de:104a', + 'os': 'Windows-2008ServerR2-SP1', + 'pool': 'Chrome-perf', + 'device_ids': [ + 'build92-m1', 'build93-m1', + 'build94-m1', 'build95-m1', 'build96-m1' + ], + 'perf_tests_with_args': [ + ('passthrough_command_buffer_perftests', 'build94-m1', + ['--use-cmd-decoder=passthrough', '--use-angle=gl-null'], + 'command_buffer_perftests') + ] + } + test = perf_data_generator.generate_cplusplus_isolate_script_test_with_args( + dimension) + test = test[0] + self.assertEqual(test['name'], 'passthrough_command_buffer_perftests') + self.assertEqual(test['isolate_name'], 'command_buffer_perftests') + self.assertTrue('--use-cmd-decoder=passthrough' in test['args']) + self.assertTrue('--use-angle=gl-null' in test['args'])
diff --git a/tools/perf/core/results_dashboard.py b/tools/perf/core/results_dashboard.py new file mode 100755 index 0000000..596525e --- /dev/null +++ b/tools/perf/core/results_dashboard.py
@@ -0,0 +1,530 @@ +#!/usr/bin/env python +# Copyright (c) 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. + +"""Functions for adding results to perf dashboard.""" + +# This file was copy-pasted over from: +# //build/scripts/slave/results_dashboard.py + +import calendar +import datetime +import httplib +import httplib2 +import json +import os +import subprocess +import sys +import traceback +import urllib +import urllib2 + +# The paths in the results dashboard URLs for sending and viewing results. +SEND_RESULTS_PATH = '/add_point' +SEND_HISTOGRAMS_PATH = '/add_histograms' +RESULTS_LINK_PATH = '/report?masters=%s&bots=%s&tests=%s&rev=%s' + +# CACHE_DIR/CACHE_FILENAME will be created in options.build_dir to cache +# results which need to be retried. +CACHE_DIR = 'results_dashboard' +CACHE_FILENAME = 'results_to_retry' + + +def SendResults(data, url, build_dir, json_url_file=None, + send_as_histograms=False, oauth_token=None): + """Sends results to the Chrome Performance Dashboard. + + This function tries to send the given data to the dashboard, in addition to + any data from the cache file. The cache file contains any data that wasn't + successfully sent in a previous run. + + Args: + data: The data to try to send. Must be JSON-serializable. + url: Performance Dashboard URL (including schema). + build_dir: Directory name, where the cache directory shall be. + json_url_file: Optional file to which to write the dashboard viewing URL. + send_as_histograms: True if result is to be sent to /add_histograms. + oauth_token: string; used for flushing oauth uploads from cache. + """ + results_json = json.dumps({ + 'is_histogramset': send_as_histograms, + 'data': data + }) + + # Write the new request line to the cache file, which contains all lines + # that we shall try to send now. + cache_file_name = _GetCacheFileName(build_dir) + _AddLineToCacheFile(results_json, cache_file_name) + + # Send all the results from this run and the previous cache to the dashboard. + fatal_error, errors = _SendResultsFromCache(cache_file_name, url, oauth_token) + + if json_url_file: + # Dump dashboard url to file. + dashboard_url = _DashboardUrl(url, data) + with open(json_url_file, 'w') as f: + json.dump(dashboard_url if dashboard_url else '', f) + + + # Print any errors; if there was a fatal error, it should be an exception. + for error in errors: + print error + if fatal_error: + print 'Error uploading to dashboard.' + print '@@@STEP_EXCEPTION@@@' + return False + return True + + +def _GetCacheFileName(build_dir): + """Gets the cache filename, creating the file if it does not exist.""" + cache_dir = os.path.join(os.path.abspath(build_dir), CACHE_DIR) + if not os.path.exists(cache_dir): + os.makedirs(cache_dir) + cache_filename = os.path.join(cache_dir, CACHE_FILENAME) + if not os.path.exists(cache_filename): + # Create the file. + open(cache_filename, 'wb').close() + return cache_filename + + +def _AddLineToCacheFile(line, cache_file_name): + """Appends a line to the given file.""" + with open(cache_file_name, 'ab') as cache: + cache.write('\n' + line) + + +def _SendResultsFromCache(cache_file_name, url, oauth_token): + """Tries to send each line from the cache file in a separate request. + + This also writes data which failed to send back to the cache file. + + Args: + cache_file_name: A file name. + url: The instance URL to which to post results. + oauth_token: An oauth token to use for histogram uploads. Might be None. + + Returns: + A pair (fatal_error, errors), where fatal_error is a boolean indicating + whether there there was a major error and the step should fail, and errors + is a list of error strings. + """ + with open(cache_file_name, 'rb') as cache: + cache_lines = cache.readlines() + total_results = len(cache_lines) + + fatal_error = False + errors = [] + + lines_to_retry = [] + for index, line in enumerate(cache_lines): + line = line.strip() + if not line: + continue + print 'Sending result %d of %d to dashboard.' % (index + 1, total_results) + # We need to check whether we're trying to upload histograms. If the JSON + # is invalid, we should not try to send this data or re-try it later. + # Instead, we'll print an error. + try: + is_histogramset, data = _GetData(line) + except ValueError: + errors.append('Could not parse JSON: %s' % line) + continue + + if is_histogramset: + # TODO(eakuefner): Remove this discard logic once all bots use histograms. + if oauth_token is None: + print 'No oauth token provided, cannot upload HistogramSet. Discarding.' + fatal_error = True + break + error = _SendHistogramJson(url, json.dumps(data), oauth_token) + else: + error = _SendResultsJson(url, json.dumps(data)) + + # If the dashboard returned an error, we will re-try next time. + if error: + if 'HTTPError: 400' in error: + # If the remote app rejects the JSON, it's probably malformed, + # so we don't want to retry it. + print 'Discarding JSON, error:\n%s' % error + fatal_error = True + break + + if index != len(cache_lines) - 1: + # The very last item in the cache_lines list is the new results line. + # If this line is not the new results line, then this results line + # has already been tried before; now it's considered fatal. + fatal_error = True + + # The lines to retry are all lines starting from the current one. + lines_to_retry = [l.strip() for l in cache_lines[index:] if l.strip()] + errors.append(error) + break + + # Write any failing requests to the cache file. + cache = open(cache_file_name, 'wb') + cache.write('\n'.join(set(lines_to_retry))) + cache.close() + + return fatal_error, errors + + +def _GetData(line): + line_dict = json.loads(line) + return bool(line_dict.get('is_histogramset')), line_dict['data'] + + +def MakeHistogramSetWithDiagnostics(histograms_file, chromium_checkout_path, + test_name, bot, buildername, buildnumber, + revisions_dict, is_reference_build, + perf_dashboard_machine_group): + add_diagnostics_args = [] + add_diagnostics_args.extend([ + '--benchmarks', test_name, + '--bots', bot, + '--builds', buildnumber, + '--masters', perf_dashboard_machine_group, + '--is_reference_build', 'true' if is_reference_build else '', + ]) + + url = _MakeStdioUrl(test_name, buildername, buildnumber) + if url: + add_diagnostics_args.extend(['--log_urls', url]) + + for k, v in revisions_dict.iteritems(): + add_diagnostics_args.extend((k, v)) + + add_diagnostics_args.append(histograms_file) + + # Subprocess only accepts string args + add_diagnostics_args = [str(v) for v in add_diagnostics_args] + + add_reserved_diagnostics_path = os.path.join( + chromium_checkout_path, 'src', 'third_party', 'catapult', 'tracing', + 'bin', 'add_reserved_diagnostics') + cmd = [sys.executable, add_reserved_diagnostics_path] + add_diagnostics_args + + subprocess.call(cmd) + + # TODO: Handle reference builds + with open(histograms_file) as f: + hs = json.load(f) + + return hs + + +def MakeListOfPoints(charts, bot, test_name, buildername, + buildnumber, supplemental_columns, + perf_dashboard_machine_group, + revisions_dict=None): + """Constructs a list of point dictionaries to send. + + The format output by this function is the original format for sending data + to the perf dashboard. + + Args: + charts: A dictionary of chart names to chart data, as generated by the + log processor classes (see process_log_utils.GraphingLogProcessor). + bot: A string which comes from perf_id, e.g. linux-release. + test_name: A test suite name, e.g. sunspider. + buildername: Builder name (for stdio links). + buildnumber: Build number (for stdio links). + supplemental_columns: A dictionary of extra data to send with a point. + perf_dashboard_machine_group: Builder's perf machine group. + + Returns: + A list of dictionaries in the format accepted by the perf dashboard. + Each dictionary has the keys "master", "bot", "test", "value", "revision". + The full details of this format are described at http://goo.gl/TcJliv. + """ + results = [] + + for chart_name, chart_data in sorted(charts.items()): + point_id, revision_columns = _RevisionNumberColumns( + revisions_dict if revisions_dict is not None else chart_data, prefix='r_') + + for trace_name, trace_values in sorted(chart_data['traces'].items()): + is_important = trace_name in chart_data.get('important', []) + test_path = _TestPath(test_name, chart_name, trace_name) + result = { + 'master': perf_dashboard_machine_group, + 'bot': bot, + 'test': test_path, + 'revision': point_id, + 'supplemental_columns': {} + } + + # Add the supplemental_columns values that were passed in after the + # calculated revision column values so that these can be overwritten. + result['supplemental_columns'].update(revision_columns) + result['supplemental_columns'].update( + _GetStdioUriColumn(test_name, buildername, buildnumber)) + result['supplemental_columns'].update(supplemental_columns) + + result['value'] = trace_values[0] + result['error'] = trace_values[1] + + # Add other properties to this result dictionary if available. + if chart_data.get('units'): + result['units'] = chart_data['units'] + if is_important: + result['important'] = True + + results.append(result) + + return results + + +def MakeDashboardJsonV1(chart_json, revision_dict, test_name, bot, buildername, + buildnumber, supplemental_dict, is_ref, + perf_dashboard_machine_group): + """Generates Dashboard JSON in the new Telemetry format. + + See http://goo.gl/mDZHPl for more info on the format. + + Args: + chart_json: A dict containing the telmetry output. + revision_dict: Dictionary of revisions to include, include "rev", + which determines the point ID. + test_name: A test suite name, e.g. sunspider. + bot: A string which comes from perf_id, e.g. linux-release. + buildername: Builder name (for stdio links). + buildnumber: Build number (for stdio links). + supplemental_dict: A dictionary of extra data to send with a point; + this includes revisions and annotation data. + is_ref: True if this is a reference build, False otherwise. + perf_dashboard_machine_group: Builder's perf machine group. + + Returns: + A dictionary in the format accepted by the perf dashboard. + """ + if not chart_json: + print 'Error: No json output from telemetry.' + print '@@@STEP_FAILURE@@@' + + point_id, versions = _RevisionNumberColumns(revision_dict, prefix='') + + supplemental = {} + for key in supplemental_dict: + if key.startswith('r_'): + versions[key.replace('r_', '', 1)] = supplemental_dict[key] + if key.startswith('a_'): + supplemental[key.replace('a_', '', 1)] = supplemental_dict[key] + + supplemental.update( + _GetStdioUriColumn(test_name, buildername, buildnumber)) + + # TODO(sullivan): The android recipe sends "test_name.reference" + # while the desktop one just sends "test_name" for ref builds. Need + # to figure out why. + # https://github.com/catapult-project/catapult/issues/2046 + test_name = test_name.replace('.reference', '') + + fields = { + 'master': perf_dashboard_machine_group, + 'bot': bot, + 'test_suite_name': test_name, + 'point_id': point_id, + 'supplemental': supplemental, + 'versions': versions, + 'chart_data': chart_json, + 'is_ref': is_ref, + } + return fields + + +def _MakeStdioUrl(test_name, buildername, buildnumber): + """Returns a string url pointing to buildbot stdio log.""" + # TODO(780914): Link to logdog instead of buildbot. + if not buildername or not buildnumber: + return '' + + return '%sbuilders/%s/builds/%s/steps/%s/logs/stdio' % ( + _GetBuildBotUrl(), + urllib.quote(buildername), + urllib.quote(str(buildnumber)), + urllib.quote(test_name)) + + +def _GetStdioUriColumn(test_name, buildername, buildnumber): + """Gets a supplemental column containing buildbot stdio link.""" + url = _MakeStdioUrl(test_name, buildername, buildnumber) + if not url: + return {} + return _CreateLinkColumn('stdio_uri', 'Buildbot stdio', url) + + +def _CreateLinkColumn(name, label, url): + """Returns a column containing markdown link to show on dashboard.""" + return {'a_' + name: '[%s](%s)' % (label, url)} + + +def _GetBuildBotUrl(): + """Gets the buildbot URL which contains hostname and master name.""" + return os.environ.get('BUILDBOT_BUILDBOTURL', + 'http://build.chromium.org/p/chromium/') + + +def _GetTimestamp(): + """Get the Unix timestamp for the current time.""" + return int(calendar.timegm(datetime.datetime.utcnow().utctimetuple())) + + +def _RevisionNumberColumns(data, prefix): + """Get the point id and revision-related columns from the given data. + + Args: + data: A dict of information from one line of the log file. + master: The name of the buildbot master. + prefix: Prefix for revision type keys. 'r_' for non-telemetry json, '' for + telemetry json. + + Returns: + A tuple with the point id (which must be an int), and a dict of + revision-related columns. + """ + revision_supplemental_columns = {} + + # The dashboard requires points' x-values to be integers, and points are + # ordered by these x-values. If data['rev'] can't be parsed as an int, assume + # that it's a git commit hash and use timestamp as the x-value. + try: + revision = int(data['rev']) + if revision and revision > 300000 and revision < 1000000: + # Revision is the commit pos. + # TODO(sullivan,qyearsley): use got_revision_cp when available. + revision_supplemental_columns[prefix + 'commit_pos'] = revision + except ValueError: + # The dashboard requires ordered integer revision numbers. If the revision + # is not an integer, assume it's a git hash and send a timestamp. + revision = _GetTimestamp() + revision_supplemental_columns[prefix + 'chromium'] = data['rev'] + + # An explicit data['point_id'] overrides the default behavior. + if 'point_id' in data: + revision = int(data['point_id']) + + # For other revision data, add it if it's present and not undefined: + for key in ['webrtc_rev', 'v8_rev']: + if key in data and data[key] != 'undefined': + revision_supplemental_columns[prefix + key] = data[key] + + # If possible, also send the git hash. + if 'git_revision' in data and data['git_revision'] != 'undefined': + revision_supplemental_columns[prefix + 'chromium'] = data['git_revision'] + + return revision, revision_supplemental_columns + + +def _TestPath(test_name, chart_name, trace_name): + """Get the slash-separated test path to send. + + Args: + test: Test name. Typically, this will be a top-level 'test suite' name. + chart_name: Name of a chart where multiple trace lines are grouped. If the + chart name is the same as the trace name, that signifies that this is + the main trace for the chart. + trace_name: The "trace name" is the name of an individual line on chart. + + Returns: + A slash-separated list of names that corresponds to the hierarchy of test + data in the Chrome Performance Dashboard; doesn't include master or bot + name. + """ + # For tests run on reference builds by builds/scripts/slave/telemetry.py, + # "_ref" is appended to the trace name. On the dashboard, as long as the + # result is on the right chart, it can just be called "ref". + if trace_name == chart_name + '_ref': + trace_name = 'ref' + chart_name = chart_name.replace('_by_url', '') + + # No slashes are allowed in the trace name. + trace_name = trace_name.replace('/', '_') + + # The results for "test/chart" and "test/chart/*" will all be shown on the + # same chart by the dashboard. The result with path "test/path" is considered + # the main trace for the chart. + test_path = '%s/%s/%s' % (test_name, chart_name, trace_name) + if chart_name == trace_name: + test_path = '%s/%s' % (test_name, chart_name) + return test_path + + +def _SendResultsJson(url, results_json): + """Make a HTTP POST with the given JSON to the Performance Dashboard. + + Args: + url: URL of Performance Dashboard instance, e.g. + "https://chromeperf.appspot.com". + results_json: JSON string that contains the data to be sent. + + Returns: + None if successful, or an error string if there were errors. + """ + # When data is provided to urllib2.Request, a POST is sent instead of GET. + # The data must be in the application/x-www-form-urlencoded format. + data = urllib.urlencode({'data': results_json}) + req = urllib2.Request(url + SEND_RESULTS_PATH, data) + try: + urllib2.urlopen(req) + except (urllib2.HTTPError, urllib2.URLError, httplib.HTTPException): + return traceback.format_exc() + return None + +def _Httplib2Request(url, data, oauth_token): + data = urllib.urlencode({'data': data}) + headers = { + 'Authorization': 'Bearer %s' % oauth_token, + 'User-Agent': 'perf-uploader/1.0' + } + + http = httplib2.Http() + return http.request( + url + SEND_HISTOGRAMS_PATH, method='POST', body=data, headers=headers) + +def _SendHistogramJson(url, histogramset_json, oauth_token): + """POST a HistogramSet JSON to the Performance Dashboard. + + Args: + url: URL of Performance Dashboard instance, e.g. + "https://chromeperf.appspot.com". + histogramset_json: JSON string that contains a serialized HistogramSet. + oauth_token: An oauth token to be used for this upload. + + Returns: + None if successful, or an error string if there were errors. + """ + try: + _, content = _Httplib2Request(url, histogramset_json, oauth_token) + result = json.loads(content) or {} + error = result.get('error') + if error is not None: + return 'HTTP error: %s\n' % error + except (httplib2.HttpLib2Error, ValueError): + return traceback.format_exc() + return None + +def _DashboardUrl(url, data): + """Returns link to the dashboard if possible. + + Args: + url: The Performance Dashboard URL, e.g. "https://chromeperf.appspot.com" + data: The data that's being sent to the dashboard. + + Returns: + An annotation to print, or None. + """ + if not data: + return None + if isinstance(data, list): + master, bot, test, revision = ( + data[0]['master'], data[0]['bot'], data[0]['test'], data[0]['revision']) + else: + master, bot, test, revision = ( + data['master'], data['bot'], data['chart_data']['benchmark_name'], + data['point_id']) + results_link = url + RESULTS_LINK_PATH % ( + urllib.quote(master), urllib.quote(bot), urllib.quote(test.split('/')[0]), + revision) + return results_link
diff --git a/tools/perf/core/results_merger.py b/tools/perf/core/results_merger.py new file mode 100644 index 0000000..d7cbee0 --- /dev/null +++ b/tools/perf/core/results_merger.py
@@ -0,0 +1,286 @@ +# Copyright 2016 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. + +# This file was copy-pasted over from: +# //build/scripts/slave/recipe_modules/swarming/resources/results_merger.py + +# This file is responsbile for merging JSON test results in both the simplified +# JSON format and the Chromium JSON test results format version 3. + +import copy +import json +import sys + +# These fields must appear in the test result output +REQUIRED = { + 'interrupted', + 'num_failures_by_type', + 'seconds_since_epoch', + 'tests', + } + +# These fields are optional, but must have the same value on all shards +OPTIONAL_MATCHING = ( + 'builder_name', + 'build_number', + 'chromium_revision', + 'has_pretty_patch', + 'has_wdiff', + 'path_delimiter', + 'pixel_tests_enabled', + 'random_order_seed', + ) + +OPTIONAL_IGNORED = ( + 'layout_tests_dir', + ) + +# These fields are optional and will be summed together +OPTIONAL_COUNTS = ( + 'fixable', + 'num_flaky', + 'num_passes', + 'num_regressions', + 'skipped', + 'skips', + ) + + +class MergeException(Exception): + pass + + +def merge_test_results(shard_results_list): + """ Merge list of results. + + Args: + shard_results_list: list of results to merge. All the results must have the + same format. Supported format are simplified JSON format & Chromium JSON + test results format version 3 (see + https://www.chromium.org/developers/the-json-test-results-format) + + Returns: + a dictionary that represent the merged results. Its format follow the same + format of all results in |shard_results_list|. + """ + shard_results_list = [x for x in shard_results_list if x] + if not shard_results_list: + return {} + + if 'seconds_since_epoch' in shard_results_list[0]: + return _merge_json_test_result_format(shard_results_list) + else: + return _merge_simplified_json_format(shard_results_list) + + +def _merge_simplified_json_format(shard_results_list): + # This code is specialized to the "simplified" JSON format that used to be + # the standard for recipes. + + # These are the only keys we pay attention to in the output JSON. + merged_results = { + 'successes': [], + 'failures': [], + 'valid': True, + } + + for result_json in shard_results_list: + successes = result_json.get('successes', []) + failures = result_json.get('failures', []) + valid = result_json.get('valid', True) + + if (not isinstance(successes, list) or not isinstance(failures, list) or + not isinstance(valid, bool)): + raise MergeException( + 'Unexpected value type in %s' % result_json) # pragma: no cover + + merged_results['successes'].extend(successes) + merged_results['failures'].extend(failures) + merged_results['valid'] = merged_results['valid'] and valid + return merged_results + + +def _merge_json_test_result_format(shard_results_list): + # This code is specialized to the Chromium JSON test results format version 3: + # https://www.chromium.org/developers/the-json-test-results-format + + # These are required fields for the JSON test result format version 3. + merged_results = { + 'tests': {}, + 'interrupted': False, + 'version': 3, + 'seconds_since_epoch': float('inf'), + 'num_failures_by_type': { + } + } + + # To make sure that we don't mutate existing shard_results_list. + shard_results_list = copy.deepcopy(shard_results_list) + for result_json in shard_results_list: + # TODO(tansell): check whether this deepcopy is actually neccessary. + result_json = copy.deepcopy(result_json) + + # Check the version first + version = result_json.pop('version', -1) + if version != 3: + raise MergeException( # pragma: no cover (covered by + # results_merger_unittest). + 'Unsupported version %s. Only version 3 is supported' % version) + + # Check the results for each shard have the required keys + missing = REQUIRED - set(result_json) + if missing: + raise MergeException( # pragma: no cover (covered by + # results_merger_unittest). + 'Invalid json test results (missing %s)' % missing) + + # Curry merge_values for this result_json. + # pylint: disable=cell-var-from-loop + merge = lambda key, merge_func: merge_value( + result_json, merged_results, key, merge_func) + + # Traverse the result_json's test trie & merged_results's test tries in + # DFS order & add the n to merged['tests']. + merge('tests', merge_tries) + + # If any were interrupted, we are interrupted. + merge('interrupted', lambda x,y: x|y) + + # Use the earliest seconds_since_epoch value + merge('seconds_since_epoch', min) + + # Sum the number of failure types + merge('num_failures_by_type', sum_dicts) + + # Optional values must match + for optional_key in OPTIONAL_MATCHING: + if optional_key not in result_json: + continue + + if optional_key not in merged_results: + # Set this value to None, then blindly copy over it. + merged_results[optional_key] = None + merge(optional_key, lambda src, dst: src) + else: + merge(optional_key, ensure_match) + + # Optional values ignored + for optional_key in OPTIONAL_IGNORED: + if optional_key in result_json: + merged_results[optional_key] = result_json.pop( + # pragma: no cover (covered by + # results_merger_unittest). + optional_key) + + # Sum optional value counts + for count_key in OPTIONAL_COUNTS: + if count_key in result_json: # pragma: no cover + # TODO(mcgreevy): add coverage. + merged_results.setdefault(count_key, 0) + merge(count_key, lambda a, b: a+b) + + if result_json: + raise MergeException( # pragma: no cover (covered by + # results_merger_unittest). + 'Unmergable values %s' % result_json.keys()) + + return merged_results + + +def merge_tries(source, dest): + """ Merges test tries. + + This is intended for use as a merge_func parameter to merge_value. + + Args: + source: A result json test trie. + dest: A json test trie merge destination. + """ + # merge_tries merges source into dest by performing a lock-step depth-first + # traversal of dest and source. + # pending_nodes contains a list of all sub-tries which have been reached but + # need further merging. + # Each element consists of a trie prefix, and a sub-trie from each of dest + # and source which is reached via that prefix. + pending_nodes = [('', dest, source)] + while pending_nodes: + prefix, dest_node, curr_node = pending_nodes.pop() + for k, v in curr_node.iteritems(): + if k in dest_node: + if not isinstance(v, dict): + raise MergeException( + "%s:%s: %r not mergable, curr_node: %r\ndest_node: %r" % ( + prefix, k, v, curr_node, dest_node)) + pending_nodes.append(("%s:%s" % (prefix, k), dest_node[k], v)) + else: + dest_node[k] = v + return dest + + +def ensure_match(source, dest): + """ Returns source if it matches dest. + + This is intended for use as a merge_func parameter to merge_value. + + Raises: + MergeException if source != dest + """ + if source != dest: + raise MergeException( # pragma: no cover (covered by + # results_merger_unittest). + "Values don't match: %s, %s" % (source, dest)) + return source + + +def sum_dicts(source, dest): + """ Adds values from source to corresponding values in dest. + + This is intended for use as a merge_func parameter to merge_value. + """ + for k, v in source.iteritems(): + dest.setdefault(k, 0) + dest[k] += v + + return dest + + +def merge_value(source, dest, key, merge_func): + """ Merges a value from source to dest. + + The value is deleted from source. + + Args: + source: A dictionary from which to pull a value, identified by key. + dest: The dictionary into to which the value is to be merged. + key: The key which identifies the value to be merged. + merge_func(src, dst): A function which merges its src into dst, + and returns the result. May modify dst. May raise a MergeException. + + Raises: + MergeException if the values can not be merged. + """ + try: + dest[key] = merge_func(source[key], dest[key]) + except MergeException as e: + e.message = "MergeFailure for %s\n%s" % (key, e.message) + e.args = tuple([e.message] + list(e.args[1:])) + raise + del source[key] + + +def main(files): + if len(files) < 2: + sys.stderr.write("Not enough JSON files to merge.\n") + return 1 + sys.stderr.write('Starting with %s\n' % files[0]) + result = json.load(open(files[0])) + for f in files[1:]: + sys.stderr.write('Merging %s\n' % f) + result = merge_test_results([result, json.load(open(f))]) + print json.dumps(result) + return 0 + + +if __name__ == "__main__": + sys.exit(main(sys.argv[1:]))
diff --git a/tools/perf/core/sharding_map_generator.py b/tools/perf/core/sharding_map_generator.py index 841b6c310..7dcfcb7 100644 --- a/tools/perf/core/sharding_map_generator.py +++ b/tools/perf/core/sharding_map_generator.py
@@ -104,7 +104,9 @@ with open(get_sharding_map_path()) as f: sharding_map = json.load(f) - sharding_map[u'all_benchmarks'] = [b.Name() for b in benchmarks] + + all_benchmarks = [b.Name() for b in benchmarks] + sharding_map[u'all_benchmarks'] = all_benchmarks for name, config in waterfall_configs.items(): for builder, tester in config['testers'].items(): @@ -133,6 +135,12 @@ continue for value in builder_values.values(): + # Remove any deleted benchmarks + benchmarks = [] + for b in value['benchmarks']: + if b in all_benchmarks: + benchmarks.append(b) + value['benchmarks'] = benchmarks value['benchmarks'].sort() if not dry_run:
diff --git a/tools/perf/core/stacktrace_unittest.py b/tools/perf/core/stacktrace_unittest.py index 7c2df429..912f453 100644 --- a/tools/perf/core/stacktrace_unittest.py +++ b/tools/perf/core/stacktrace_unittest.py
@@ -37,7 +37,7 @@ def testCrashMinimalSymbols(self): with self.assertRaises(exceptions.DevtoolsTargetCrashException) as c: self._tab.Navigate('chrome://crash', timeout=5) - self.assertIn('PrepareRenderViewForNavigation', + self.assertIn('HandleRendererDebugURL', '\n'.join(c.exception.stack_trace)) # The breakpad file specific test only apply to platforms which use the
diff --git a/tools/perf/core/story_expectation_validator.py b/tools/perf/core/story_expectation_validator.py index 4c30b2c..8e03425d 100755 --- a/tools/perf/core/story_expectation_validator.py +++ b/tools/perf/core/story_expectation_validator.py
@@ -3,6 +3,10 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """Script to check validity of StoryExpectations.""" + +import optparse +import argparse +import json import os from core import benchmark_finders @@ -10,6 +14,7 @@ path_util.AddTelemetryToPath() path_util.AddAndroidPylibToPath() + from telemetry.internal.browser import browser_options @@ -22,25 +27,70 @@ ] -def validate_story_names(benchmarks): +def validate_story_names(benchmarks, raw_expectations_data): for benchmark in benchmarks: if benchmark.Name() in CLUSTER_TELEMETRY_BENCHMARKS: continue b = benchmark() + b.AugmentExpectationsWithParser(raw_expectations_data) options = browser_options.BrowserFinderOptions() - # tabset_repeat is needed for tab_switcher benchmarks. - options.tabset_repeat = 1 - # test_path required for blink_perf benchmark in contrib/. - options.test_path = '' - # shared_prefs_file required for benchmarks in contrib/vr_benchmarks/ - options.shared_prefs_file = '' + + # Add default values for any extra commandline options + # provided by the benchmark. + parser = optparse.OptionParser() + before, _ = parser.parse_args([]) + benchmark.AddBenchmarkCommandLineArgs(parser) + after, _ = parser.parse_args([]) + for extra_option in dir(after): + if extra_option not in dir(before): + setattr(options, extra_option, getattr(after, extra_option)) + story_set = b.CreateStorySet(options) failed_stories = b.GetBrokenExpectations(story_set) assert not failed_stories, 'Incorrect story names: %s' % str(failed_stories) +def GetDisabledStories(benchmarks, raw_expectations_data): + # Creates a dictionary of the format: + # { + # 'benchmark_name1' : { + # 'story_1': [ + # {'conditions': conditions, 'reason': reason}, + # ... + # ], + # ... + # }, + # ... + # } + disables = {} + for benchmark in benchmarks: + name = benchmark.Name() + disables[name] = {} + b = benchmark() + b.AugmentExpectationsWithParser(raw_expectations_data) + expectations = b.expectations.AsDict()['stories'] + for story in expectations: + for conditions, reason in expectations[story]: + if not disables[name].get(story): + disables[name][story] = [] + conditions_str = [str(a) for a in conditions] + disables[name][story].append((conditions_str, reason)) + return disables + + def main(args): - del args # unused + parser = argparse.ArgumentParser( + description=('Tests if disabled stories exist.')) + parser.add_argument( + '--list', action='store_true', default=False, + help=('Prints list of disabled stories.')) + options = parser.parse_args(args) benchmarks = benchmark_finders.GetAllBenchmarks() - validate_story_names(benchmarks) + with open(path_util.GetExpectationsPath()) as fp: + raw_expectations_data = fp.read() + if options.list: + stories = GetDisabledStories(benchmarks, raw_expectations_data) + print json.dumps(stories, sort_keys=True, indent=4, separators=(',', ': ')) + else: + validate_story_names(benchmarks, raw_expectations_data) return 0
diff --git a/tools/perf/core/story_expectation_validator_unittest.py b/tools/perf/core/story_expectation_validator_unittest.py new file mode 100644 index 0000000..702a3b9 --- /dev/null +++ b/tools/perf/core/story_expectation_validator_unittest.py
@@ -0,0 +1,71 @@ +# Copyright 2017 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 unittest + +from core import story_expectation_validator + +from telemetry import benchmark +from telemetry import story + +class FakePage(object): + def __init__(self, name): + self._name = name + + @property + def name(self): + return self._name + + +class FakeStorySetOne(story.StorySet): + def __init__(self): # pylint: disable=super-init-not-called + self._stories = [ + FakePage('One'), + FakePage('Two') + ] + + @property + def stories(self): + return self._stories + + +class FakeBenchmark(benchmark.Benchmark): + @classmethod + def Name(cls): + return 'b1' + + def CreateStorySet(self, options): + return FakeStorySetOne() + + +class StoryExpectationValidatorTest(unittest.TestCase): + def testValidateStoryInValidName(self): + raw_expectations = '# tags: Mac\ncrbug.com/123 [ Mac ] b1/s1 [ Skip ]' + benchmarks = [FakeBenchmark] + with self.assertRaises(AssertionError): + story_expectation_validator.validate_story_names( + benchmarks, raw_expectations) + + def testValidateStoryValidName(self): + raw_expectations = '# tags: Mac\ncrbug.com/123 [ Mac ] b1/One [ Skip ]' + benchmarks = [FakeBenchmark] + # If a name is invalid, an exception is thrown. If no exception is thrown + # all story names are valid. That is why there is no assert here. + story_expectation_validator.validate_story_names( + benchmarks, raw_expectations) + + def testGetDisabledStoriesWithExpectationsData(self): + raw_expectations = '# tags: Mac\ncrbug.com/123 [ Mac ] b1/One [ Skip ]' + benchmarks = [FakeBenchmark] + results = story_expectation_validator.GetDisabledStories( + benchmarks, raw_expectations) + expected = {'b1': {'One': [(['Mac'], 'crbug.com/123')]}} + self.assertEqual(expected, results) + + def testGetDisabledStoriesWithoutMatchingExpectationsData(self): + raw_expectations = '# tags: Mac\ncrbug.com/123 [ Mac ] b2/One [ Skip ]' + benchmarks = [FakeBenchmark] + results = story_expectation_validator.GetDisabledStories( + benchmarks, raw_expectations) + expected = { 'b1': {}} + self.assertEqual(expected, results)
diff --git a/tools/perf/core/system_health_csv_generator.py b/tools/perf/core/system_health_csv_generator.py new file mode 100644 index 0000000..90aa3f51 --- /dev/null +++ b/tools/perf/core/system_health_csv_generator.py
@@ -0,0 +1,84 @@ +# Copyright 2016 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 csv +import sys + +from core import path_util + +sys.path.insert(1, path_util.GetPerfDir()) # To resolve perf imports +path_util.AddPyUtilsToPath() +path_util.AddTelemetryToPath() +import page_sets +from py_utils import expectations_parser +from telemetry.story import expectations as expectations + +def IterAllSystemHealthStories(): + for s in page_sets.SystemHealthStorySet(platform='desktop'): + yield s + for s in page_sets.SystemHealthStorySet(platform='mobile'): + if len(s.SUPPORTED_PLATFORMS) < 2: + yield s + + +def PopulateExpectations(all_expectations): + """Accepts Expectations and parses out the storyname and disabled platforms. + + Args: + all_expectations = { + story_name: [[conditions], reason]} + conditions: list of disabled platforms for story_name + reason: Bug referencing why the test is disabled on the platform + + Returns: + A dictionary containing the disabled platforms for each story. + disables = { + story_name: "Disabled Platforms"} + """ + disables = {} + for exp in all_expectations: + exp_keys = exp.keys() + exp_keys.sort() + + for story in exp_keys: + for conditions, _ in exp[story]: + conditions_str = ", ".join(map(str, conditions)) + if story in disables: + if conditions_str not in disables[story]: + disables[story] += ", " + conditions_str + else: + disables[story] = conditions_str + return disables + +def GenerateSystemHealthCSV(file_path): + system_health_stories = list(IterAllSystemHealthStories()) + + e = expectations.StoryExpectations() + with open(path_util.GetExpectationsPath()) as fp: + parser = expectations_parser.TestExpectationParser(fp.read()) + + benchmarks = ['system_health.common_desktop', 'system_health.common_mobile', + 'system_health.memory_desktop', 'system_health.memory_mobile'] + for benchmark in benchmarks: + e.GetBenchmarkExpectationsFromParser(parser.expectations, benchmark) + + disabed_platforms = PopulateExpectations([e.AsDict()['stories']]) + + system_health_stories.sort(key=lambda s: s.name) + with open(file_path, 'w') as f: + csv_writer = csv.writer(f) + csv_writer.writerow([ + 'Story name', 'Platform', 'Description', 'Disabled Platforms']) + for s in system_health_stories: + p = s.SUPPORTED_PLATFORMS + if len(p) == 2: + p = 'all' + else: + p = list(p)[0] + if s.name in disabed_platforms: + csv_writer.writerow( + [s.name, p, s.GetStoryDescription(), disabed_platforms[s.name]]) + else: + csv_writer.writerow([s.name, p, s.GetStoryDescription(), " "]) + return 0
diff --git a/tools/perf/core/trybot_command.py b/tools/perf/core/trybot_command.py index 79e738b0..3cfeec0 100644 --- a/tools/perf/core/trybot_command.py +++ b/tools/perf/core/trybot_command.py
@@ -2,632 +2,24 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import argparse -import base64 -import collections -import gzip -import io -import json -import logging -import os -import platform -import subprocess -import tempfile -import urllib -import urllib2 - - -from core import benchmark_finders -from core import path_util - -from telemetry import benchmark -from telemetry import decorators from telemetry.util import command_line -from telemetry.util import matching -ALL_CONFIG_BOTS = [ - 'all', - 'all-win', - 'all-mac', - 'all-linux', - 'all-android' -] - -# Default try bot to use incase builbot is unreachable. -DEFAULT_TRYBOTS = [ - 'linux_perf_bisect', - 'mac_10_11_perf_bisect', - 'winx64_10_perf_bisect', - 'android_s5_perf_bisect', -] - -CHROMIUM_SRC_PATH = path_util.GetChromiumSrcDir() -# Mapping of repo to its root path and git remote URL. -# Values for 'src' key in the map are related to path to the repo in the -# DEPS file, These values are to used create the DEPS patch along with patch -# that is being tried. -REPO_INFO_MAP = { - 'src': { - 'src': 'src', - 'url': 'https://chromium.googlesource.com/chromium/src.git', - }, - 'v8': { - 'src': 'src/v8', - 'url': 'https://chromium.googlesource.com/v8/v8.git', - }, - 'skia': { - 'src': 'src/third_party/skia', - 'url': 'https://chromium.googlesource.com/skia.git', - }, - 'angle': { - 'src': 'src/third_party/angle', - 'url': 'https://chromium.googlesource.com/angle/angle.git', - }, - 'catapult': { - 'src': 'src/third_party/catapult', - 'url': ('https://chromium.googlesource.com/external/github.com/' - 'catapult-project/catapult.git') - } -} - -_MILO_MASTER_ENDPOINT = ('https://luci-milo.appspot.com/prpc/milo.Buildbot/' - 'GetCompressedMasterJSON') - -_MILO_RESPONSE_PREFIX = ')]}\'\n' - - -def _IsPerfBisectBot(builder): - return ( - builder.endswith('_perf_bisect') and - # Bisect FYI bots are not meant for testing actual perf regressions. - # Hardware configuration on these bots is different from actual bisect bot - # and these bots runs E2E integration tests for auto-bisect - # using dummy benchmarks. - not builder.endswith('fyi_perf_bisect') - # Individual bisect bots may be blacklisted here. - ) - - -assert all(_IsPerfBisectBot(builder) for builder in DEFAULT_TRYBOTS), ( - 'A default trybot is being exluded by the perf bisect bot filter.') - - -class TrybotError(Exception): - - def __str__(self): - return '(ERROR) Perf Try Job: %s' % self.args[0] - - -def _ProcessMiloData(data): - if not data.startswith(_MILO_RESPONSE_PREFIX): - return None - data = data[len(_MILO_RESPONSE_PREFIX):] - - try: - response_data = json.loads(data) - except Exception: - return None - - try: - decoded_data = base64.b64decode(response_data.get('data')) - except Exception: - return None - - try: - with io.BytesIO(decoded_data) as compressed_file: - with gzip.GzipFile(fileobj=compressed_file) as decompressed_file: - data_json = decompressed_file.read() - except Exception: - return None - - return json.loads(data_json) - - -def _GetTrybotList(builders): - builders = ['%s' % bot.replace('_perf_bisect', '').replace('_', '-') - for bot in builders] - builders.extend(ALL_CONFIG_BOTS) - return sorted(builders) - - -def _GetBotPlatformFromTrybotName(trybot_name): - os_names = ['linux', 'android', 'mac', 'win'] - try: - return next(b for b in os_names if b in trybot_name) - except StopIteration: - raise TrybotError('Trybot "%s" unsupported for tryjobs.' % trybot_name) - - -def _GetPlatformVariantFromBuilderName(builder): - bot_platform = _GetBotPlatformFromTrybotName(builder) - # Special case for platform variants that need special configs. - if bot_platform == 'win' and 'x64' in builder: - return 'win-x64' - elif bot_platform == 'android' and 'webview' in builder: - return 'android-webview' - else: - return bot_platform - - -def _GetBuilderNames(trybot_name, builders): - """Return platform and its available bot name as dictionary.""" - if trybot_name in ALL_CONFIG_BOTS: - platform_prefix = trybot_name[4:] - platform_and_bots = collections.defaultdict(list) - for builder in builders: - bot_platform = _GetPlatformVariantFromBuilderName(builder) - if bot_platform.startswith(platform_prefix): - platform_and_bots[bot_platform].append(builder) - return platform_and_bots - else: - builder = '%s_perf_bisect' % trybot_name.replace('-', '_') - bot_platform = _GetPlatformVariantFromBuilderName(builder) - return {bot_platform: [builder]} - - -_GIT_CMD = 'git' - - -if platform.system() == 'Windows': - # On windows, the git command is installed as 'git.bat' - _GIT_CMD = 'git.bat' - - -def RunGit(cmd, msg_on_error='', ignore_return_code=False): - """Runs the git command with the given arguments. - - Args: - cmd: git command arguments. - msg_on_error: Message to be displayed on git command error. - ignore_return_code: Ignores the return code for git command. - - Returns: - The output of the git command as string. - - Raises: - TrybotError: This exception is raised when git command fails. - """ - proc = subprocess.Popen( - [_GIT_CMD] + cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - output, err = proc.communicate() - returncode = proc.poll() - if returncode: - if ignore_return_code: - return None - raise TrybotError('%s. \n%s \n%s' % (msg_on_error, err, output)) - - return output.strip() +_DEPRECATED_MESSAGE = ('\nERROR: This command has been removed.' + '\n\nPlease visit https://chromium.googlesource.com/chromium/' + 'src/+/master/docs/speed/perf_trybots.md for up-to-date information on ' + 'running perf try jobs.\n\n') class Trybot(command_line.ArgParseCommand): """Run telemetry perf benchmark on trybot.""" usage = 'botname benchmark_name [<benchmark run options>]' - _builders = None def __init__(self): - self._builder_names = None - - @classmethod - def _GetBuilderList(cls): - if not cls._builders: - try: - headers = { - 'Accept': 'application/json', - 'Content-Type': 'application/json', - } - values = {'name': 'tryserver.chromium.perf'} - data = urllib.urlencode(values) - req = urllib2.Request(_MILO_MASTER_ENDPOINT, None, headers) - f = urllib2.urlopen(req, json.dumps(values), timeout=10) - # In case of any kind of exception, allow tryjobs to use default trybots. - # Possible exception are ssl.SSLError, urllib2.URLError, - # socket.timeout, socket.error. - except Exception: # pylint: disable=broad-except - # Incase of any exception return default trybots. - print ('WARNING: Unable to reach builbot to retrieve trybot ' - 'information, tryjob will use default trybots.') - cls._builders = DEFAULT_TRYBOTS - else: - data = _ProcessMiloData(f.read()) - builders = data.get('builders', {}).keys() - # Exclude unsupported bots like win xp and some dummy bots. - cls._builders = [bot for bot in builders if _IsPerfBisectBot(bot)] - - return cls._builders - - def _InitializeBuilderNames(self, trybot): - self._builder_names = _GetBuilderNames(trybot, self._GetBuilderList()) - - @classmethod - def CreateParser(cls): - parser = argparse.ArgumentParser( - ('Run telemetry benchmarks on trybot. You can add all the benchmark ' - 'options available except the --browser option'), - formatter_class=argparse.RawTextHelpFormatter) - return parser - - @classmethod - def ProcessCommandLineArgs(cls, parser, options, extra_args, environment): - del environment # unused - for arg in extra_args: - if arg == '--browser' or arg.startswith('--browser='): - parser.error('--browser=... is not allowed when running trybot.') - all_benchmarks = benchmark_finders.GetAllPerfBenchmarks() - all_benchmarks.extend(benchmark_finders.GetAllContribBenchmarks()) - all_benchmark_names = [b.Name() for b in all_benchmarks] - all_benchmarks_by_names = {b.Name(): b for b in all_benchmarks} - benchmark_class = all_benchmarks_by_names.get(options.benchmark_name, None) - if not benchmark_class: - possible_benchmark_names = matching.GetMostLikelyMatchedObject( - all_benchmark_names, options.benchmark_name) - parser.error( - 'No benchmark named "%s". Do you mean any of those benchmarks ' - 'below?\n%s' % ( - options.benchmark_name, '\n'.join(possible_benchmark_names))) - is_benchmark_disabled, reason = cls.IsBenchmarkDisabledOnTrybotPlatform( - benchmark_class, options.trybot) - also_run_disabled_option = '--also-run-disabled-tests' - if is_benchmark_disabled and also_run_disabled_option not in extra_args: - parser.error('%s To run the benchmark on trybot anyway, add ' - '%s option.' % (reason, also_run_disabled_option)) - - @classmethod - def IsBenchmarkDisabledOnTrybotPlatform(cls, benchmark_class, trybot_name): - """Return whether benchmark will be disabled on trybot platform. - - Note that we cannot tell with certainty whether the benchmark will be - disabled on the trybot platform since the disable logic in ShouldDisable() - can be very dynamic and can only be verified on the trybot server platform. - - We are biased on the side of enabling the benchmark, and attempt to - early discover whether the benchmark will be disabled as our best. - - It should never be the case that the benchmark will be enabled on the test - platform but this method returns True. - - Returns: - A tuple (is_benchmark_disabled, reason) whereas |is_benchmark_disabled| is - a boolean that tells whether we are sure that the benchmark will be - disabled, and |reason| is a string that shows the reason why we think the - benchmark is disabled for sure. - """ - benchmark_name = benchmark_class.Name() - benchmark_disabled_strings = decorators.GetDisabledAttributes( - benchmark_class) - if 'all' in benchmark_disabled_strings: - return True, 'Benchmark %s is disabled on all platform.' % benchmark_name - if trybot_name == 'all': - return False, '' - trybot_platform = _GetBotPlatformFromTrybotName(trybot_name) - if trybot_platform in benchmark_disabled_strings: - return True, ( - "Benchmark %s is disabled on %s, and trybot's platform is %s." % - (benchmark_name, ', '.join(benchmark_disabled_strings), - trybot_platform)) - benchmark_enabled_strings = decorators.GetEnabledAttributes(benchmark_class) - if (benchmark_enabled_strings and - trybot_platform not in benchmark_enabled_strings and - 'all' not in benchmark_enabled_strings): - return True, ( - "Benchmark %s is only enabled on %s, and trybot's platform is %s." % - (benchmark_name, ', '.join(benchmark_enabled_strings), - trybot_platform)) - if benchmark_class.ShouldDisable != benchmark.Benchmark.ShouldDisable: - logging.warning( - 'Benchmark %s has ShouldDisable() method defined. If your trybot run ' - 'does not produce any results, it is possible that the benchmark ' - 'is disabled on the target trybot platform.', benchmark_name) - return False, '' - - @classmethod - def AddCommandLineArgs(cls, parser, environment): - del environment # unused - available_bots = _GetTrybotList(cls._GetBuilderList()) - parser.add_argument( - 'trybot', choices=available_bots, - help=('specify which bots to run telemetry benchmarks on. ' - ' Allowed values are:\n' + '\n'.join(available_bots)), - metavar='<trybot name>') - parser.add_argument( - 'benchmark_name', type=str, - help=('specify which benchmark to run. To see all available benchmarks,' - ' run `run_benchmark list`'), - metavar='<benchmark name>') - parser.add_argument( - '--repo_path', type=str, default=CHROMIUM_SRC_PATH, - help=("""specify the repo path where the patch is created.' -This argument should only be used if the changes are made outside chromium repo. -E.g., -1) Assume you are running run_benchmarks command from $HOME/cr/src/ directory:' - a) If your changes are in $HOME/cr/src/v8, then --repo_path=v8 or - --repo-path=$HOME/cr/src/v8 - b) If your changes are in $HOME/cr/src/third_party/catapult, then - --repo_path=third_party/catapult or - --repo_path = $HOME/cr/src/third_party/catapult' - c) If your changes are not relative to src/ e.g. you created changes in some - other directory say $HOME/mydir/v8/v8/, then the - --repo_path=$HOME/mydir/v8/v8 -2) Assume you are running run_benchmarks command not relative to src i.e., - you are running from $HOME/mydir/ directory:' - a) If your changes are in $HOME/cr/src/v8, then --repo-path=$HOME/cr/src/v8 - b) If your changes are in $HOME/cr/src/third_party/catapult, then - --repo_path=$HOME/cr/src/third_party/catapult' - c) If your changes are in $HOME/mydir/v8/v8/, then the - --repo_path=$HOME/mydir/v8/v8 or --repo_path=v8/v8"""), - metavar='<repo path>') - parser.add_argument( - '--deps_revision', type=str, default=None, - help=('specify DEPS revision to modify DEPS entry in Chromium to a ' - 'certain pushed revision.\n' - 'This revision overrides value in DEPS on TOT Chromium for the ' - 'repo specified in --repo_path.\nIt is applied for both with and ' - 'wihout patch.'), - metavar='<deps revision>') + pass def Run(self, options, extra_args=None): - """Sends a tryjob to a perf trybot. + print _DEPRECATED_MESSAGE - This creates a branch, telemetry-tryjob, switches to that branch, edits - the bisect config, commits it, uploads the CL to rietveld, and runs a - tryjob on the given bot. - """ - if extra_args is None: - extra_args = [] - self._InitializeBuilderNames(options.trybot) - - return self._AttemptTryjob(options, extra_args) - - def _GetPerfConfig(self, bot_platform, arguments): - """Generates the perf config for try job. - - Args: - bot_platform: Name of the platform to be generated. - arguments: Command line arguments. - - Returns: - A dictionary with perf config parameters. - """ - # To make sure that we don't mutate the original args - arguments = arguments[:] - - # Always set verbose logging for later debugging - if '-v' not in arguments and '--verbose' not in arguments: - arguments.append('--verbose') - - # Generate the command line for the perf trybots - target_arch = 'ia32' - if any(arg == '--chrome-root' or arg.startswith('--chrome-root=') for arg - in arguments): - raise ValueError( - 'Trybot does not suport --chrome-root option set directly ' - 'through command line since it may contain references to your local ' - 'directory') - - arguments.insert(0, 'src/tools/perf/run_benchmark') - if bot_platform == 'android': - arguments.insert(1, '--browser=android-chromium') - elif bot_platform == 'android-webview': - arguments.insert(1, '--browser=android-webview') - elif bot_platform == 'win-x64': - arguments.insert(1, '--browser=release_x64') - target_arch = 'x64' - else: - arguments.insert(1, '--browser=release') - - dummy_parser = argparse.ArgumentParser() - dummy_parser.add_argument('--output-format', action='append') - args, _ = dummy_parser.parse_known_args(arguments) - if not args.output_format or 'html' not in args.output_format: - arguments.append('--output-format=html') - - command = ' '.join(arguments) - - return { - 'command': command, - 'repeat_count': '1', - 'max_time_minutes': '120', - 'truncate_percent': '0', - 'target_arch': target_arch, - } - - def _GetRepoAndBranchName(self, repo_path): - """Gets the repository name and working branch name. - - Args: - repo_path: Path to the repository. - - Returns: - Repository name and branch name as tuple. - - Raises: - TrybotError: This exception is raised for the following cases: - 1. Try job is for non-git repository or in invalid branch. - 2. Un-committed changes in the current branch. - 3. No local commits in the current branch. - """ - # If command runs successfully, then the output will be repo root path. - # and current branch name. - output = RunGit(['rev-parse', '--abbrev-ref', '--show-toplevel', 'HEAD'], - ('%s is not a git repository, must be in a git repository ' - 'to send changes to trybots' % os.getcwd())) - - repo_info = output.split() - # Assuming the base directory name is same as repo project name set in - # codereviews.settings file. - repo_name = os.path.basename(repo_info[0]).strip() - branch_name = repo_info[1].strip() - - if branch_name == 'HEAD': - raise TrybotError('Not on a valid branch, looks like branch ' - 'is dettached. [branch:%s]' % branch_name) - - # Check if the tree is dirty: make sure the index is up to date and then - # run diff-index - RunGit(['update-index', '--refresh', '-q'], ignore_return_code=True) - output = RunGit(['diff-index', 'HEAD']) - if output: - raise TrybotError( - 'Cannot send a try job with a dirty tree.\nPlease commit locally and ' - 'upload your changes to rietveld in %s repository.' % repo_path) - - return (repo_name, branch_name) - - def _GetBaseGitHashForRepo(self, branch_name, git_url): - """Gets the base revision for the repo on which local changes are made. - - Finds the upstream of the current branch that it is set to and gets - the HEAD revision from upstream. This also checks if the remote URL on - the upstream is supported by Perf Try job. - - Args: - branch_name: Current working branch name. - git_url: Remote URL of the repo. - - Returns: - Git hash of the HEAD revision from the upstream branch. - - Raises: - TrybotError: This exception is raised when a GIT command fails or if the - remote URL of the repo found is not supported. - """ - # Check if there is any upstream branch associated with current working - # branch, Once the upstream branch is found i.e., then validates the - # remote URL and then returns the HEAD revision from the remote branch. - while not self._IsRepoSupported(branch_name, git_url): - branch_name = RunGit( - ['rev-parse', '--abbrev-ref', '%s@{upstream}' % branch_name], - 'Failed to get upstream branch name.') - - return RunGit( - ['rev-parse', '%s@{upstream}' % branch_name], - 'Failed to get base revision hash on upstream.') - - def _IsRepoSupported(self, current_branch, repo_git_url): - cur_remote = RunGit( - ['config', 'branch.%s.remote'% current_branch], - 'Failed to get branch.%s.remote from git config' % current_branch) - cur_remote = cur_remote.strip() - if cur_remote == '.': - return False - cur_remote_url = RunGit( - ['config', 'remote.%s.url' % cur_remote], - 'Failed to get remote.%s.url from git config' % cur_remote) - if cur_remote_url.lower() == repo_git_url: - return True - raise TrybotError('URL %s on remote %s is not recognized on branch.'% ( - cur_remote_url, cur_remote)) - - def _GetChangeList(self): - """Gets the codereview URL for the current changes.""" - temp_file = None - json_output = None - try: - fd, temp_file = tempfile.mkstemp(suffix='.json', prefix='perf_try_cl') - os.close(fd) - RunGit(['cl', 'issue', '--json', temp_file], - 'Failed to run "git cl issue" command.') - with open(temp_file, 'r') as f: - json_output = json.load(f) - finally: - try: - if temp_file: - os.remove(temp_file) - except OSError: - pass - - # Make sure the local commits are uploaded to rietveld. - if not json_output.get('issue'): - raise TrybotError( - 'PLEASE NOTE: The workflow for Perf Try jobs is changed. ' - 'In order to run the perf try job, you must first upload your ' - 'changes to rietveld.') - return json_output.get('issue_url') - - def _AttemptTryjob(self, options, extra_args): - """Attempts to run a tryjob from a repo directory. - - Args: - options: Command line arguments to run benchmark. - extra_args: Extra arugments to run benchmark. - - Returns: - If successful returns 0, otherwise 1. - """ - original_workdir = os.getcwd() - repo_path = os.path.abspath(options.repo_path) - try: - # Check the existence of repo path. - if not os.path.exists(repo_path): - raise TrybotError('Repository path "%s" does not exist, please check ' - 'the value of <repo_path> argument.' % repo_path) - # Change to the repo directory. - os.chdir(repo_path) - repo_name, branch_name = self._GetRepoAndBranchName(repo_path) - - repo_info = REPO_INFO_MAP.get(repo_name, None) - if not repo_info: - raise TrybotError('Unsupported repository %s' % repo_name) - - deps_override = None - if repo_name != 'src': - if not options.deps_revision: - options.deps_revision = self._GetBaseGitHashForRepo( - branch_name, repo_info.get('url')) - deps_override = {repo_info.get('src'): options.deps_revision} - - rietveld_url = self._GetChangeList() - print ('\nRunning try job....\nview progress here %s.' - '\n\tRepo Name: %s\n\tPath: %s\n\tBranch: %s' % ( - rietveld_url, repo_name, repo_path, branch_name)) - - for bot_platform in self._builder_names: - if not self._builder_names[bot_platform]: - logging.warning('No builder is found for %s', bot_platform) - continue - try: - arguments = [options.benchmark_name] + extra_args - self._RunTryJob(bot_platform, arguments, deps_override) - # Even if git cl try throws TrybotError exception for any platform, - # keep sending try jobs to other platforms. - except TrybotError, err: - print err - except TrybotError, error: - print error - return 1 - finally: - # Restore to original working directory. - os.chdir(original_workdir) return 0 - - def _RunTryJob(self, bot_platform, arguments, deps_override): - """Executes perf try job with benchmark test properties. - - Args: - bot_platform: Name of the platform to be generated. - arguments: Command line arguments. - deps_override: DEPS revision if needs to be overridden. - - Raises: - TrybotError: When trybot fails to upload CL or run git try. - """ - config = self._GetPerfConfig(bot_platform, arguments) - - # Generate git try command for available bots. - git_try_command = ['cl', 'try', '-m', 'tryserver.chromium.perf'] - - # Add Perf Test config to git try --properties arg. - git_try_command.extend(['-p', 'perf_try_config=%s' % json.dumps(config)]) - - error_msg_on_fail = 'Could not try CL for %s' % bot_platform - # Add deps overrides to git try --properties arg. - if deps_override: - git_try_command.extend([ - '-p', 'deps_revision_overrides=%s' % json.dumps(deps_override)]) - error_msg_on_fail += ' with DEPS override (%s)' % deps_override - for bot in self._builder_names[bot_platform]: - git_try_command.extend(['-b', bot]) - - RunGit(git_try_command, error_msg_on_fail) - print 'Perf Try job sent to rietveld for %s platform.' % bot_platform
diff --git a/tools/perf/core/trybot_command_unittest.py b/tools/perf/core/trybot_command_unittest.py deleted file mode 100644 index 733a31c..0000000 --- a/tools/perf/core/trybot_command_unittest.py +++ /dev/null
@@ -1,962 +0,0 @@ -# Copyright 2015 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 argparse -import base64 -import io -import gzip -import json -import logging -import os -import StringIO -import sys -import tempfile -import unittest - -from core import trybot_command -import mock -from telemetry import benchmark -from telemetry import decorators - -class FakeProcess(object): - - def __init__(self, expected_responses): - self._communicate = expected_responses[1:] - self._poll = expected_responses[0] - - def communicate(self): - return self._communicate - - def poll(self): - return self._poll - - -class TrybotCommandTest(unittest.TestCase): - - # pylint: disable=protected-access - - def setUp(self): - self.log_output = StringIO.StringIO() - self.stream_handler = logging.StreamHandler(self.log_output) - logging.getLogger().addHandler(self.stream_handler) - self._subprocess_patcher = mock.patch('core.trybot_command.subprocess') - self._mock_subprocess = self._subprocess_patcher.start() - self._urllib2_patcher = mock.patch('core.trybot_command.urllib2') - self._urllib2_mock = self._urllib2_patcher.start() - self._tempfile_patcher = mock.patch('core.trybot_command.tempfile') - self._tempfile_mock = self._tempfile_patcher.start() - # Always set git command to 'git' to simplify testing across platforms. - self._original_git_cmd = trybot_command._GIT_CMD - trybot_command._GIT_CMD = 'git' - - def tearDown(self): - logging.getLogger().removeHandler(self.stream_handler) - self.log_output.close() - self._subprocess_patcher.stop() - self._urllib2_patcher.stop() - self._tempfile_patcher.stop() - # Reset the cached builders in trybot_command - trybot_command.Trybot._builders = None - trybot_command._GIT_CMD = self._original_git_cmd - - def _ExpectProcesses(self, expected_args_list): - counter = [-1] - def side_effect(args, **kwargs): - if not expected_args_list: - self.fail( - 'Not expect any Popen() call but got a Popen call with %s\n' % args) - del kwargs # unused - counter[0] += 1 - expected_args, expected_responses = expected_args_list[counter[0]] - self.assertEquals( - expected_args, args, - 'Popen() is called with unexpected args.\n Actual: %s.\n' - 'Expecting (index %i): %s' % (args, counter[0], expected_args)) - return FakeProcess(expected_responses) - self._mock_subprocess.Popen.side_effect = side_effect - - def _MockBuilderList(self): - excluded_bots = trybot_command.EXCLUDED_BOTS - builders = [bot for bot in self._builder_list if bot not in excluded_bots] - return builders - - def _MockTryserverJson(self, bots_dict): - data_to_compress = json.dumps({'builders': bots_dict}) - - with io.BytesIO() as dst: - with gzip.GzipFile(fileobj=dst, mode='wb') as src: - src.write(data_to_compress) - compressed_data = dst.getvalue() - - milo_data = {'data': base64.b64encode(compressed_data)} - milo_data = json.dumps(milo_data) - milo_data = trybot_command._MILO_RESPONSE_PREFIX + milo_data - - data = mock.Mock() - data.read.return_value = milo_data - self._urllib2_mock.urlopen.return_value = data - - def _MockTempFile(self, issue, issue_url): - fd, temp_file = tempfile.mkstemp(suffix='.json', prefix='cl') - with open(temp_file, 'w') as f: - json.dump({"issue": issue, "issue_url": issue_url}, f) - self._tempfile_mock.mkstemp.return_value = (fd, temp_file) - return temp_file - - def _AssertTryBotExceptions(self, message, func, *args): - with self.assertRaises(trybot_command.TrybotError) as e: - func(*args) - self.assertIn(message, e.exception.message) - - def _SetupTrybotCommand( - self, try_json_dict, trybot, benchmark_name='sunspider', - repo_path=trybot_command.CHROMIUM_SRC_PATH, deps_revision=None): - self._MockTryserverJson(try_json_dict) - command = trybot_command.Trybot() - command._InitializeBuilderNames(trybot) - opts = argparse.Namespace( - trybot=trybot, benchmark_name=benchmark_name, repo_path=repo_path, - deps_revision=deps_revision) - - return command, opts - - def _GetConfigForTrybot(self, name, platform, extra_benchmark_args=None, - repo_path=trybot_command.CHROMIUM_SRC_PATH, - deps_revision=None): - bot = '%s_perf_bisect' % name.replace('', '').replace('-', '_') - command, options = self._SetupTrybotCommand( - {bot: 'stuff'}, name, repo_path=repo_path, deps_revision=deps_revision) - extra_benchmark_args = extra_benchmark_args or [] - arguments = [options.benchmark_name] + extra_benchmark_args - cfg = command._GetPerfConfig(platform, arguments) - - return cfg, command - - def _ExpectedGitTryTestArgs(self, test_name, browser, target_arch='ia32'): - return ('perf_try_config={' - '"repeat_count": "1", "command": "src/tools/perf/run_benchmark ' - '--browser=%s %s --verbose --output-format=html", ' - '"max_time_minutes": "120", ' - '"target_arch": "%s", "truncate_percent": "0"}' % ( - browser, test_name, target_arch)) - - def testFindAllBrowserTypesList(self): - self._MockTryserverJson({ - 'android_nexus4_perf_bisect': 'stuff', - 'mac_10_9_perf_bisect': 'otherstuff', - 'win_perf_bisect_builder': 'not a trybot', - }) - expected_trybots_list = [ - 'all', - 'all-android', - 'all-linux', - 'all-mac', - 'all-win', - 'android-nexus4', - 'mac-10-9' - ] - parser = trybot_command.Trybot.CreateParser() - trybot_command.Trybot.AddCommandLineArgs(parser, None) - trybot_action = [a for a in parser._actions if a.dest == 'trybot'][0] - self.assertEquals( - expected_trybots_list, - sorted(trybot_action.choices)) - - def testFindAllBrowserTypesTrybot(self): - self._MockTryserverJson({ - 'android_nexus4_perf_bisect': 'stuff', - 'mac_10_9_perf_bisect': 'otherstuff', - 'win_perf_bisect_builder': 'not a trybot', - 'android_fyi_perf_bisect': 'not meant for actual perf testing' - }) - expected_trybots_list = [ - 'all', - 'all-android', - 'all-linux', - 'all-mac', - 'all-win', - 'android-nexus4', - 'mac-10-9' - ] - - parser = trybot_command.Trybot.CreateParser() - trybot_command.Trybot.AddCommandLineArgs(parser, None) - trybot_action = [a for a in parser._actions if a.dest == 'trybot'][0] - self.assertEquals(expected_trybots_list, sorted(trybot_action.choices)) - - def testFindAllBrowserTypesNonTrybotBrowser(self): - self._MockTryserverJson({}) - parser = trybot_command.Trybot.CreateParser() - trybot_command.Trybot.AddCommandLineArgs(parser, None) - trybot_action = [a for a in parser._actions if a.dest == 'trybot'][0] - self.assertEquals( - ['all', 'all-android', 'all-linux', 'all-mac', 'all-win'], - sorted(trybot_action.choices)) - - def testConstructor(self): - self._MockTryserverJson({ - 'android_nexus4_perf_bisect': 'stuff', - 'mac_10_9_perf_bisect': 'otherstuff', - 'win_perf_bisect_builder': 'not a trybot', - }) - command = trybot_command.Trybot() - command._InitializeBuilderNames('android-nexus4') - self.assertTrue('android' in command._builder_names) - self.assertEquals(['android_nexus4_perf_bisect'], - command._builder_names.get('android')) - - def testConstructorTrybotAll(self): - self._MockTryserverJson({ - 'android_nexus4_perf_bisect': 'stuff', - 'android_nexus5_perf_bisect': 'stuff2', - 'android_webview_nexus6_aosp_perf_bisect': 'stuff3', - 'mac_10_9_perf_bisect': 'otherstuff', - 'mac_perf_bisect': 'otherstuff1', - 'win_perf_bisect': 'otherstuff2', - 'linux_perf_bisect': 'otherstuff3', - 'win_x64_perf_bisect': 'otherstuff4', - 'win_perf_bisect_builder': 'not a trybot', - }) - command = trybot_command.Trybot() - command._InitializeBuilderNames('all') - self.assertEquals( - ['android', 'android-webview', 'linux', 'mac', 'win', 'win-x64'], - sorted(command._builder_names)) - self.assertEquals( - ['android_nexus4_perf_bisect', 'android_nexus5_perf_bisect'], - sorted(command._builder_names.get('android'))) - self.assertEquals( - ['android_webview_nexus6_aosp_perf_bisect'], - sorted(command._builder_names.get('android-webview'))) - self.assertEquals( - ['mac_10_9_perf_bisect', 'mac_perf_bisect'], - sorted(command._builder_names.get('mac'))) - self.assertEquals( - ['linux_perf_bisect'], sorted(command._builder_names.get('linux'))) - self.assertEquals( - ['win_perf_bisect'], sorted(command._builder_names.get('win'))) - self.assertEquals( - ['win_x64_perf_bisect'], sorted(command._builder_names.get('win-x64'))) - - def testConstructorTrybotAllWin(self): - self._MockTryserverJson({ - 'android_nexus4_perf_bisect': 'stuff', - 'android_nexus5_perf_bisect': 'stuff2', - 'win_8_perf_bisect': 'otherstuff', - 'win_perf_bisect': 'otherstuff2', - 'linux_perf_bisect': 'otherstuff3', - 'win_x64_perf_bisect': 'otherstuff4', - 'win_perf_bisect_builder': 'not a trybot', - 'win_x64_10_perf_bisect': 'otherstuff4', - 'winx64ati_perf_bisect': 'not a trybot', - 'winx64nvidia_perf_bisect': 'not a trybot', - }) - command = trybot_command.Trybot() - command._InitializeBuilderNames('all-win') - self.assertEquals( - ['win', 'win-x64'], - sorted(command._builder_names)) - self.assertEquals( - ['win_8_perf_bisect', 'win_perf_bisect'], - sorted(command._builder_names.get('win'))) - self.assertNotIn( - 'win_x64_perf_bisect', - sorted(command._builder_names.get('win'))) - self.assertEquals( - sorted(['win_x64_perf_bisect', 'win_x64_10_perf_bisect', - 'winx64ati_perf_bisect', 'winx64nvidia_perf_bisect']), - sorted(command._builder_names.get('win-x64'))) - - def testConstructorTrybotAllAndroid(self): - self._MockTryserverJson({ - 'android_nexus4_perf_bisect': 'stuff', - 'android_nexus5_perf_bisect': 'stuff2', - 'android_webview_nexus6_aosp_perf_bisect': 'stuff3', - 'win_8_perf_bisect': 'otherstuff', - 'win_perf_bisect': 'otherstuff2', - 'linux_perf_bisect': 'otherstuff3', - 'win_x64_perf_bisect': 'otherstuff4', - 'win_perf_bisect_builder': 'not a trybot', - }) - command = trybot_command.Trybot() - command._InitializeBuilderNames('all-android') - self.assertEquals( - ['android_nexus4_perf_bisect', 'android_nexus5_perf_bisect'], - sorted(command._builder_names.get('android'))) - self.assertEquals( - ['android_webview_nexus6_aosp_perf_bisect'], - sorted(command._builder_names.get('android-webview'))) - - def testConstructorTrybotAllMac(self): - self._MockTryserverJson({ - 'android_nexus4_perf_bisect': 'stuff', - 'win_8_perf_bisect': 'otherstuff', - 'mac_perf_bisect': 'otherstuff2', - 'win_perf_bisect_builder': 'not a trybot', - }) - command = trybot_command.Trybot() - command._InitializeBuilderNames('all-mac') - self.assertEquals( - ['mac'], - sorted(command._builder_names)) - self.assertEquals( - ['mac_perf_bisect'], - sorted(command._builder_names.get('mac'))) - - def testConstructorTrybotAllLinux(self): - self._MockTryserverJson({ - 'android_nexus4_perf_bisect': 'stuff', - 'linux_perf_bisect': 'stuff1', - 'win_8_perf_bisect': 'otherstuff', - 'mac_perf_bisect': 'otherstuff2', - 'win_perf_bisect_builder': 'not a trybot', - }) - command = trybot_command.Trybot() - command._InitializeBuilderNames('all-linux') - self.assertEquals( - ['linux'], - sorted(command._builder_names)) - self.assertEquals( - ['linux_perf_bisect'], - sorted(command._builder_names.get('linux'))) - - @mock.patch('core.trybot_command.os.path.abspath', - mock.MagicMock(return_value='/dummy/path')) - @mock.patch('core.trybot_command.os.path.exists', - mock.MagicMock(return_value=False)) - def testRepoPathExists(self): - command, options = self._SetupTrybotCommand( - {'linux_perf_bisect': 'stuff'}, 'linux', repo_path='/dummy/path') - command.Run(options) - self.assertEquals(( - '(ERROR) Perf Try Job: Repository path "/dummy/path" does not exist, ' - 'please check the value of <repo_path> argument.'), - sys.stdout.getvalue().strip()) - - def testNoGit(self): - command, options = self._SetupTrybotCommand({'linux_perf_bisect': 'stuff'}, - 'linux') - self._ExpectProcesses(( - (['git', 'rev-parse', '--abbrev-ref', '--show-toplevel', 'HEAD'], - (128, None, None)), - )) - self._AssertTryBotExceptions( - ('%s is not a git repository, must be in a git repository to send ' - 'changes to trybots.' % os.getcwd()), - command._GetRepoAndBranchName, - options.repo_path - ) - - def testDettachedBranch(self): - command, options = self._SetupTrybotCommand({'linux_perf_bisect': 'stuff'}, - 'linux') - self._ExpectProcesses(( - (['git', 'rev-parse', '--abbrev-ref', '--show-toplevel', 'HEAD'], - (0, '/root/path_to/repo/src\nHEAD\n', None)), - )) - self._AssertTryBotExceptions( - 'Not on a valid branch, looks like branch is dettached. [branch:HEAD]', - command._GetRepoAndBranchName, - options.repo_path - ) - - def testDirtyTree(self): - command, options = self._SetupTrybotCommand({'linux_perf_bisect': 'stuff'}, - 'linux') - self._ExpectProcesses(( - (['git', 'rev-parse', '--abbrev-ref', '--show-toplevel', 'HEAD'], - (0, '/root/path_to/repo/src\nbr\n', None)), - (['git', 'update-index', '--refresh', '-q'], (0, '', None,)), - (['git', 'diff-index', 'HEAD'], (0, 'dirty tree', None)), - )) - self._AssertTryBotExceptions( - 'Cannot send a try job with a dirty tree.', - command._GetRepoAndBranchName, - options.repo_path - ) - - def testGetRepoAndBranchName(self): - command, options = self._SetupTrybotCommand({'linux_perf_bisect': 'stuff'}, - 'linux') - self._ExpectProcesses(( - (['git', 'rev-parse', '--abbrev-ref', '--show-toplevel', 'HEAD'], - (0, '/root/path_to/repo/src\nbr\n', None)), - (['git', 'update-index', '--refresh', '-q'], (0, '', None,)), - (['git', 'diff-index', 'HEAD'], (0, '', None)), - )) - self.assertEquals( - command._GetRepoAndBranchName(options.repo_path), ('src', 'br')) - - def testErrorOnBrowserArgSpecified(self): - parser = trybot_command.Trybot.CreateParser() - options, extra_args = parser.parse_known_args( - ['sunspider', '--trybot=android-all', '--browser=mac']) - with self.assertRaises(SystemExit): - trybot_command.Trybot.ProcessCommandLineArgs( - parser, options, extra_args, None) - - def testConfigAndroid(self): - config, _ = self._GetConfigForTrybot('android-nexus4', 'android') - self.assertEquals( - {'command': ('src/tools/perf/run_benchmark ' - '--browser=android-chromium sunspider --verbose ' - '--output-format=html'), - 'max_time_minutes': '120', - 'repeat_count': '1', - 'target_arch': 'ia32', - 'truncate_percent': '0' - }, config) - - def testConfigAndroidWebview(self): - config, _ = self._GetConfigForTrybot( - 'android-webview-nexus6-aosp', 'android-webview') - self.assertEquals( - {'command': ('src/tools/perf/run_benchmark ' - '--browser=android-webview sunspider --verbose ' - '--output-format=html'), - 'max_time_minutes': '120', - 'repeat_count': '1', - 'target_arch': 'ia32', - 'truncate_percent': '0' - }, config) - - def testConfigMac(self): - config, _ = self._GetConfigForTrybot('mac-10-9', 'mac') - self.assertEquals( - {'command': ('src/tools/perf/run_benchmark ' - '--browser=release sunspider --verbose ' - '--output-format=html'), - 'max_time_minutes': '120', - 'repeat_count': '1', - 'target_arch': 'ia32', - 'truncate_percent': '0' - }, config) - - def testConfigWinX64(self): - config, _ = self._GetConfigForTrybot('win-x64', 'win-x64') - - self.assertEquals( - {'command': ('src/tools/perf/run_benchmark ' - '--browser=release_x64 sunspider --verbose ' - '--output-format=html'), - 'max_time_minutes': '120', - 'repeat_count': '1', - 'target_arch': 'x64', - 'truncate_percent': '0' - }, config) - - def testVerboseOptionIsNotAddedTwice(self): - config, _ = self._GetConfigForTrybot( - 'win-x64', 'win-x64', extra_benchmark_args=['-v']) - self.assertEquals( - {'command': ('src/tools/perf/run_benchmark ' - '--browser=release_x64 sunspider -v ' - '--output-format=html'), - 'max_time_minutes': '120', - 'repeat_count': '1', - 'target_arch': 'x64', - 'truncate_percent': '0' - }, config) - - def testConfigWinX64WithNoHyphen(self): - config, _ = self._GetConfigForTrybot('winx64nvidia', 'win-x64') - self.assertEquals( - {'command': ('src/tools/perf/run_benchmark ' - '--browser=release_x64 sunspider --verbose ' - '--output-format=html'), - 'max_time_minutes': '120', - 'repeat_count': '1', - 'target_arch': 'x64', - 'truncate_percent': '0' - }, config) - - def testUnsupportedTrybot(self): - self.assertRaises( - trybot_command.TrybotError, - trybot_command._GetBuilderNames, - 'arms-nvidia', - {'win_perf_bisect': 'stuff'} - ) - - def testConfig_EmptyOutputFormat_AddsHtml(self): - config, _ = self._GetConfigForTrybot('android-nexus4', 'android') - self.assertEquals( - {'command': ('src/tools/perf/run_benchmark ' - '--browser=android-chromium sunspider --verbose ' - '--output-format=html'), - 'max_time_minutes': '120', - 'repeat_count': '1', - 'target_arch': 'ia32', - 'truncate_percent': '0' - }, config) - - def testConfig_OtherOutputFormat_AddsHtml(self): - config, _ = self._GetConfigForTrybot('android-nexus4', 'android', - extra_benchmark_args=['--output-format=foo']) - self.assertEquals( - {'command': ('src/tools/perf/run_benchmark ' - '--browser=android-chromium sunspider --output-format=foo ' - '--verbose --output-format=html'), - 'max_time_minutes': '120', - 'repeat_count': '1', - 'target_arch': 'ia32', - 'truncate_percent': '0' - }, config) - - def testConfig_HtmlOutputFormat_Skipped(self): - config, _ = self._GetConfigForTrybot('android-nexus4', 'android', - extra_benchmark_args=['--output-format', 'html']) - self.assertEquals( - {'command': ('src/tools/perf/run_benchmark ' - '--browser=android-chromium sunspider ' - '--output-format html --verbose'), - 'max_time_minutes': '120', - 'repeat_count': '1', - 'target_arch': 'ia32', - 'truncate_percent': '0' - }, config) - - def testConfig_HtmlOutputFormat_UsesEquals_Skipped(self): - config, _ = self._GetConfigForTrybot('android-nexus4', 'android', - extra_benchmark_args=['--output-format=html']) - self.assertEquals( - {'command': ('src/tools/perf/run_benchmark ' - '--browser=android-chromium sunspider ' - '--output-format=html --verbose'), - 'max_time_minutes': '120', - 'repeat_count': '1', - 'target_arch': 'ia32', - 'truncate_percent': '0' - }, config) - - def testGetChangeListCommandError(self): - temp_file = self._MockTempFile(None, None) - command, _ = self._SetupTrybotCommand( - {'linux_perf_bisect': 'stuff'}, 'linux') - self._ExpectProcesses(( - (['git', 'cl', 'issue', '--json', temp_file], (128, None, None)), - )) - self._AssertTryBotExceptions( - 'Failed to run "git cl issue" command.', - command._GetChangeList) - - def testGetChangeListNoIssues(self): - temp_file = self._MockTempFile(None, None) - command, _ = self._SetupTrybotCommand( - {'linux_perf_bisect': 'stuff'}, 'linux') - self._ExpectProcesses(( - (['git', 'cl', 'issue', '--json', temp_file], - (0, 'Issue number: None (None)', None)), - )) - self._AssertTryBotExceptions( - ('PLEASE NOTE: The workflow for Perf Try jobs is changed. ' - 'In order to run the perf try job, you must first upload your ' - 'changes to rietveld.'), - command._GetChangeList) - - def testGetChangeListWithIssue(self): - temp_file = self._MockTempFile( - 12345, 'https://codereview.chromium.org/12345') - command, _ = self._SetupTrybotCommand( - {'linux_perf_bisect': 'stuff'}, 'linux') - self._ExpectProcesses(( - (['git', 'cl', 'issue', '--json', temp_file], - (0, 'stuff https://codereview.chromium.org/12345 stuff', None)), - )) - self.assertEquals('https://codereview.chromium.org/12345', - command._GetChangeList()) - - def testRunTryJobFailed(self): - test_args = self._ExpectedGitTryTestArgs('sunspider', 'release') - command, options = self._SetupTrybotCommand( - {'linux_perf_bisect': 'stuff'}, 'linux', repo_path='path_to_repo/src') - arguments = [options.benchmark_name] + [] - self._ExpectProcesses(( - (['git', 'cl', 'try', '-m', 'tryserver.chromium.perf', - '-p', test_args, - '-b', - 'linux_perf_bisect'], (128, None, None)),)) - self._AssertTryBotExceptions( - 'Could not try CL for linux', - command._RunTryJob, 'linux', arguments, None) - - def testRunTryJobWithDepsOverrideFailed(self): - test_args = self._ExpectedGitTryTestArgs('sunspider', 'release') - deps_override_arg = 'deps_revision_overrides={"src/v8": "feedbeed"}' - - command, options = self._SetupTrybotCommand( - {'linux_perf_bisect': 'stuff'}, 'linux', repo_path='path_to_repo/v8', - deps_revision='feedbeed') - arguments = [options.benchmark_name] + [] - self._ExpectProcesses(( - (['git', 'cl', 'try', '-m', 'tryserver.chromium.perf', - '-p', test_args, - '-p', deps_override_arg, - '-b', - 'linux_perf_bisect'], (128, None, None)),)) - self._AssertTryBotExceptions( - 'Could not try CL for linux with DEPS override', - command._RunTryJob, 'linux', arguments, {'src/v8': 'feedbeed'}) - - def testRunTryJobSuccess(self): - test_args = self._ExpectedGitTryTestArgs('sunspider', 'release') - command, options = self._SetupTrybotCommand( - {'linux_perf_bisect': 'stuff'}, 'linux', repo_path='path_to_repo/src') - arguments = [options.benchmark_name] + [] - self._ExpectProcesses(( - (['git', 'cl', 'try', '-m', 'tryserver.chromium.perf', - '-p', test_args, - '-b', - 'linux_perf_bisect'], (0, '', None)),)) - command._RunTryJob('linux', arguments, None) - self.assertEquals('Perf Try job sent to rietveld for linux platform.', - sys.stdout.getvalue().strip()) - - def testNoUpstream(self): - command, _ = self._SetupTrybotCommand({'linux_perf_bisect': 'stuff'}, - 'linux') - self._ExpectProcesses(( - (['git', 'config', 'branch.br.remote'], (0, '.', None)), - (['git', 'rev-parse', '--abbrev-ref', 'br@{upstream}'], - (128, 'None', None,)), - )) - self._AssertTryBotExceptions( - 'Failed to get upstream branch name.', - command._GetBaseGitHashForRepo, 'br', 'http://repo/git/url.git') - - def testGitConfigBranchRemote(self): - command, _ = self._SetupTrybotCommand({'linux_perf_bisect': 'stuff'}, - 'linux') - self._ExpectProcesses(( - (['git', 'config', 'branch.br.remote'], - (128, 'None', None)), - )) - self._AssertTryBotExceptions( - 'Failed to get branch.br.remote from git config', - command._GetBaseGitHashForRepo, 'br', 'http://repo/git/url.git') - - def testGitConfigBranchRemoteUrl(self): - command, _ = self._SetupTrybotCommand({'linux_perf_bisect': 'stuff'}, - 'linux') - self._ExpectProcesses(( - (['git', 'config', 'branch.br.remote'], (0, '.', None)), - (['git', 'rev-parse', '--abbrev-ref', 'br@{upstream}'], - (0, 'br1', None,)), - (['git', 'config', 'branch.br1.remote'], (0, 'origin', None)), - (['git', 'config', 'remote.origin.url'], (128, 'None', None)), - )) - self._AssertTryBotExceptions( - 'Failed to get remote.origin.url from git config', - command._GetBaseGitHashForRepo, 'br', 'http://repo/git/url.git') - - def testGetBaseGitHashForRemoteURLMatchFound(self): - command, _ = self._SetupTrybotCommand({'linux_perf_bisect': 'stuff'}, - 'linux') - self._ExpectProcesses(( - (['git', 'config', 'branch.br.remote'], - (0, '.', None)), - (['git', 'rev-parse', '--abbrev-ref', 'br@{upstream}'], - (0, 'br1', None,)), - (['git', 'config', 'branch.br1.remote'], (0, 'origin', None)), - (['git', 'config', 'remote.origin.url'], - (0, 'http://repo/git/url.git', None)), - (['git', 'rev-parse', 'br1@{upstream}'], (0, 'feedbeed', None)), - )) - self.assertEquals( - command._GetBaseGitHashForRepo('br', 'http://repo/git/url.git'), - 'feedbeed') - - def testGetBaseGitHashForRemoteUrlNoMatchFound(self): - command, _ = self._SetupTrybotCommand({'linux_perf_bisect': 'stuff'}, - 'linux') - self._ExpectProcesses(( - (['git', 'config', 'branch.br.remote'], - (0, '.', None)), - (['git', 'rev-parse', '--abbrev-ref', 'br@{upstream}'], - (0, 'br1', None,)), - (['git', 'config', 'branch.br1.remote'], - (0, 'origin', None)), - (['git', 'config', 'remote.origin.url'], - (0, 'http://non_maching_repo/git/url.git', None)), - (['git', 'rev-parse', 'br1@{upstream}'], - (0, 'feedbeed', None)), - )) - self._AssertTryBotExceptions( - ('URL http://non_maching_repo/git/url.git on remote origin is not ' - 'recognized on branch'), - command._GetBaseGitHashForRepo, 'br', 'http://repo/git/url.git') - - @mock.patch('core.trybot_command.os.chdir', mock.MagicMock()) - @mock.patch('core.trybot_command.os.path.exists', - mock.MagicMock(return_value=True)) - def testAttemptTryjobForCrRepo(self): - test_args = self._ExpectedGitTryTestArgs('sunspider', 'release') - command, options = self._SetupTrybotCommand({'linux_perf_bisect': 'stuff'}, - 'linux') - temp_file = self._MockTempFile( - 12345, 'https://codereview.chromium.org/12345') - - self._ExpectProcesses(( - (['git', 'rev-parse', '--abbrev-ref', '--show-toplevel', 'HEAD'], - (0, '/root/path_to/repo/src\nbr\n', None)), - (['git', 'update-index', '--refresh', '-q'], (0, '', None,)), - (['git', 'diff-index', 'HEAD'], (0, '', None)), - (['git', 'cl', 'issue', '--json', temp_file], - (0, 'stuff https://codereview.chromium.org/12345 stuff', None)), - (['git', 'cl', 'try', '-m', 'tryserver.chromium.perf', - '-p', test_args, '-b', 'linux_perf_bisect'], (0, '', None)) - )) - - with mock.patch('core.trybot_command.os.path.abspath', - return_value=trybot_command.CHROMIUM_SRC_PATH): - command._AttemptTryjob(options, []) - - output = ('Running try job....\n' - 'view progress here https://codereview.chromium.org/12345.\n' - '\tRepo Name: src\n' - '\tPath: %s\n' - '\tBranch: br\n' - 'Perf Try job sent to rietveld for linux platform.') % ( - options.repo_path) - self.assertEquals(output, sys.stdout.getvalue().strip()) - - @mock.patch('core.trybot_command.os.chdir', mock.MagicMock()) - @mock.patch('core.trybot_command.os.path.exists', - mock.MagicMock(return_value='True')) - def testAttemptTryjobAllForCrRepo(self): - default_config = self._ExpectedGitTryTestArgs('sunspider', 'release') - winx64_config = self._ExpectedGitTryTestArgs( - 'sunspider', 'release_x64', 'x64') - android_config = self._ExpectedGitTryTestArgs( - 'sunspider', 'android-chromium', 'ia32') - command, options = self._SetupTrybotCommand( - {'linux_perf_bisect': 'stuff', - 'win_perf_bisect': 'stuff', - 'winx64_perf_bisect': 'stuff', - 'android_perf_bisect': 'stuff', - 'mac_perf_bisect': 'stuff'}, 'all') - temp_file = self._MockTempFile( - 12345, 'https://codereview.chromium.org/12345') - - self._ExpectProcesses(( - (['git', 'rev-parse', '--abbrev-ref', '--show-toplevel', 'HEAD'], - (0, '/root/path_to/repo/src\nbr\n', None)), - (['git', 'update-index', '--refresh', '-q'], (0, '', None,)), - (['git', 'diff-index', 'HEAD'], (0, '', None)), - (['git', 'cl', 'issue', '--json', temp_file], - (0, 'stuff https://codereview.chromium.org/12345 stuff', None)), - (['git', 'cl', 'try', '-m', 'tryserver.chromium.perf', - '-p', default_config, '-b', 'win_perf_bisect'], (0, '', None)), - (['git', 'cl', 'try', '-m', 'tryserver.chromium.perf', - '-p', android_config, '-b', 'android_perf_bisect'], (0, '', None)), - (['git', 'cl', 'try', '-m', 'tryserver.chromium.perf', - '-p', winx64_config, '-b', 'winx64_perf_bisect'], (0, '', None)), - (['git', 'cl', 'try', '-m', 'tryserver.chromium.perf', - '-p', default_config, '-b', 'mac_perf_bisect'], (0, '', None)), - (['git', 'cl', 'try', '-m', 'tryserver.chromium.perf', - '-p', default_config, '-b', 'linux_perf_bisect'], (0, '', None)), - )) - - with mock.patch('core.trybot_command.os.path.abspath', - return_value=trybot_command.CHROMIUM_SRC_PATH): - command._AttemptTryjob(options, []) - - output = ('Running try job....\n' - 'view progress here https://codereview.chromium.org/12345.\n' - '\tRepo Name: src\n' - '\tPath: %s\n' - '\tBranch: br\n' - 'Perf Try job sent to rietveld for win platform.\n' - 'Perf Try job sent to rietveld for android platform.\n' - 'Perf Try job sent to rietveld for win-x64 platform.\n' - 'Perf Try job sent to rietveld for mac platform.\n' - 'Perf Try job sent to rietveld for linux platform.') % ( - options.repo_path) - self.assertEquals(output, sys.stdout.getvalue().strip()) - - @mock.patch('core.trybot_command.os.chdir', mock.MagicMock()) - @mock.patch('core.trybot_command.os.path.exists', - mock.MagicMock(return_value='True')) - def testAttemptTryjobForDepsRepo(self): - test_args = self._ExpectedGitTryTestArgs('sunspider', 'release') - deps_override_arg = 'deps_revision_overrides={"src/v8": "feedbeed"}' - command, options = self._SetupTrybotCommand( - {'linux_perf_bisect': 'stuff'}, 'linux', - repo_path='root/path_to/repo/v8') - temp_file = self._MockTempFile( - 12345, 'https://codereview.chromium.org/12345') - - self._ExpectProcesses(( - (['git', 'rev-parse', '--abbrev-ref', '--show-toplevel', 'HEAD'], - (0, 'root/path_to/repo/v8\nbr\n', None)), - (['git', 'update-index', '--refresh', '-q'], (0, '', None,)), - (['git', 'diff-index', 'HEAD'], (0, '', None)), - (['git', 'config', 'branch.br.remote'], (0, '.', None)), - (['git', 'rev-parse', '--abbrev-ref', 'br@{upstream}'], - (0, 'br1', None,)), - (['git', 'config', 'branch.br1.remote'], (0, 'origin', None)), - (['git', 'config', 'remote.origin.url'], - (0, 'https://chromium.googlesource.com/v8/v8.git', None)), - (['git', 'rev-parse', 'br1@{upstream}'], (0, 'feedbeed', None)), - (['git', 'cl', 'issue', '--json', temp_file], - (0, 'stuff https://codereview.chromium.org/12345 stuff', None)), - (['git', 'cl', 'try', '-m', 'tryserver.chromium.perf', - '-p', test_args, '-p', deps_override_arg, - '-b', 'linux_perf_bisect'], (0, '', None)) - )) - - with mock.patch('core.trybot_command.os.path.abspath', - return_value='root/path_to/repo/v8'): - command._AttemptTryjob(options, []) - - output = ('Running try job....\n' - 'view progress here https://codereview.chromium.org/12345.\n' - '\tRepo Name: v8\n' - '\tPath: root/path_to/repo/v8\n' - '\tBranch: br\n' - 'Perf Try job sent to rietveld for linux platform.') - self.assertEquals(output, sys.stdout.getvalue().strip()) - - @mock.patch('core.trybot_command.os.chdir', mock.MagicMock()) - @mock.patch('core.trybot_command.os.path.exists', - mock.MagicMock(return_value='True')) - def testAttemptTryjobAllForDepsRepo(self): - default_config = self._ExpectedGitTryTestArgs('sunspider', 'release') - deps_override_arg = 'deps_revision_overrides={"src/v8": "feedbeed"}' - winx64_config = self._ExpectedGitTryTestArgs( - 'sunspider', 'release_x64', 'x64') - android_config = self._ExpectedGitTryTestArgs( - 'sunspider', 'android-chromium', 'ia32') - command, options = self._SetupTrybotCommand( - {'linux_perf_bisect': 'stuff', - 'winx64_perf_bisect': 'stuff', - 'android_perf_bisect': 'stuff'}, - 'all', repo_path='root/path_to/repo/v8') - temp_file = self._MockTempFile( - 12345, 'https://codereview.chromium.org/12345') - - self._ExpectProcesses(( - (['git', 'rev-parse', '--abbrev-ref', '--show-toplevel', 'HEAD'], - (0, 'root/path_to/repo/v8\nbr\n', None)), - (['git', 'update-index', '--refresh', '-q'], (0, '', None,)), - (['git', 'diff-index', 'HEAD'], (0, '', None)), - (['git', 'config', 'branch.br.remote'], (0, '.', None)), - (['git', 'rev-parse', '--abbrev-ref', 'br@{upstream}'], - (0, 'br1', None,)), - (['git', 'config', 'branch.br1.remote'], (0, 'origin', None)), - (['git', 'config', 'remote.origin.url'], - (0, 'https://chromium.googlesource.com/v8/v8.git', None)), - (['git', 'rev-parse', 'br1@{upstream}'], - (0, 'feedbeed', None)), - (['git', 'cl', 'issue', '--json', temp_file], - (0, 'stuff https://codereview.chromium.org/12345 stuff', None)), - (['git', 'cl', 'try', '-m', 'tryserver.chromium.perf', - '-p', android_config, '-p', deps_override_arg, - '-b', 'android_perf_bisect'], (0, '', None)), - (['git', 'cl', 'try', '-m', 'tryserver.chromium.perf', - '-p', winx64_config, '-p', deps_override_arg, - '-b', 'winx64_perf_bisect'], (0, '', None)), - (['git', 'cl', 'try', '-m', 'tryserver.chromium.perf', - '-p', default_config, '-p', deps_override_arg, - '-b', 'linux_perf_bisect'], (0, '', None)), - )) - - with mock.patch('core.trybot_command.os.path.abspath', - return_value='root/path_to/repo/v8'): - command._AttemptTryjob(options, []) - - output = ('Running try job....\n' - 'view progress here https://codereview.chromium.org/12345.\n' - '\tRepo Name: v8\n' - '\tPath: root/path_to/repo/v8\n' - '\tBranch: br\n' - 'Perf Try job sent to rietveld for android platform.\n' - 'Perf Try job sent to rietveld for win-x64 platform.\n' - 'Perf Try job sent to rietveld for linux platform.') - self.assertEquals(output, sys.stdout.getvalue().strip()) - - @mock.patch('core.trybot_command.os.chdir', mock.MagicMock()) - @mock.patch('core.trybot_command.os.path.exists', - mock.MagicMock(return_value='True')) - def testAttemptTryjobWithDepsRevisionArg(self): - test_args = self._ExpectedGitTryTestArgs('sunspider', 'release') - deps_override_arg = 'deps_revision_overrides={"src/v8": "feedbeed"}' - command, options = self._SetupTrybotCommand( - {'linux_perf_bisect': 'stuff'}, 'linux', - repo_path='root/path_to/repo/v8', deps_revision='feedbeed') - temp_file = self._MockTempFile( - 12345, 'https://codereview.chromium.org/12345') - - self._ExpectProcesses(( - (['git', 'rev-parse', '--abbrev-ref', '--show-toplevel', 'HEAD'], - (0, 'root/path_to/repo/v8\nbr\n', None)), - (['git', 'update-index', '--refresh', '-q'], (0, '', None,)), - (['git', 'diff-index', 'HEAD'], (0, '', None)), - (['git', 'cl', 'issue', '--json', temp_file], - (0, 'stuff https://codereview.chromium.org/12345 stuff', None)), - (['git', 'cl', 'try', '-m', 'tryserver.chromium.perf', - '-p', test_args, '-p', deps_override_arg, - '-b', 'linux_perf_bisect'], (0, '', None)) - )) - with mock.patch('core.trybot_command.os.path.abspath', - return_value='root/path_to/repo/v8'): - command._AttemptTryjob(options, []) - - output = ('Running try job....\n' - 'view progress here https://codereview.chromium.org/12345.\n' - '\tRepo Name: v8\n' - '\tPath: root/path_to/repo/v8\n' - '\tBranch: br\n' - 'Perf Try job sent to rietveld for linux platform.') - self.assertEquals(output, sys.stdout.getvalue().strip()) - - -# TODO(rnephew): Modernize these tests to use StoryExpectations. -class IsBenchmarkDisabledOnTrybotPlatformTest(unittest.TestCase): - - def IsBenchmarkDisabled(self, benchmark_class, trybot_name): - return trybot_command.Trybot.IsBenchmarkDisabledOnTrybotPlatform( - benchmark_class, trybot_name)[0] - - def testBenchmarkIsDisabledAll(self): - @decorators.Disabled('all') - class FooBenchmark(benchmark.Benchmark): - pass - self.assertTrue(self.IsBenchmarkDisabled(FooBenchmark, 'all')) - self.assertTrue(self.IsBenchmarkDisabled(FooBenchmark, 'all-mac')) - self.assertTrue(self.IsBenchmarkDisabled(FooBenchmark, 'android-s5')) - self.assertTrue(self.IsBenchmarkDisabled(FooBenchmark, 'linux')) - self.assertTrue(self.IsBenchmarkDisabled(FooBenchmark, 'winx64ati')) - - def testBenchmarkIsEnabledAll(self): - @decorators.Enabled('all') - class FooBenchmark(benchmark.Benchmark): - pass - self.assertFalse(self.IsBenchmarkDisabled(FooBenchmark, 'all')) - self.assertFalse(self.IsBenchmarkDisabled(FooBenchmark, 'all-mac')) - self.assertFalse(self.IsBenchmarkDisabled(FooBenchmark, 'android-s5')) - self.assertFalse(self.IsBenchmarkDisabled(FooBenchmark, 'linux')) - self.assertFalse(self.IsBenchmarkDisabled(FooBenchmark, 'winx64ati')) - - def testBenchmarkIsDisabledOnMultiplePlatforms(self): - @decorators.Disabled('win', 'mac') - class FooBenchmark(benchmark.Benchmark): - pass - self.assertFalse(self.IsBenchmarkDisabled(FooBenchmark, 'all')) - self.assertFalse(self.IsBenchmarkDisabled(FooBenchmark, 'android-s5')) - self.assertFalse(self.IsBenchmarkDisabled(FooBenchmark, 'linux')) - - self.assertTrue(self.IsBenchmarkDisabled(FooBenchmark, 'all-mac')) - self.assertTrue(self.IsBenchmarkDisabled(FooBenchmark, 'winx64ati')) - - def testBenchmarkIsEnabledOnMultiplePlatforms(self): - @decorators.Enabled('win', 'mac') - class FooBenchmark(benchmark.Benchmark): - pass - self.assertFalse(self.IsBenchmarkDisabled(FooBenchmark, 'all')) - self.assertFalse(self.IsBenchmarkDisabled(FooBenchmark, 'all-mac')) - self.assertFalse(self.IsBenchmarkDisabled(FooBenchmark, 'winx64ati')) - - self.assertTrue(self.IsBenchmarkDisabled(FooBenchmark, 'android-s5')) - self.assertTrue(self.IsBenchmarkDisabled(FooBenchmark, 'linux')) - self.assertTrue(self.IsBenchmarkDisabled(FooBenchmark, 'all-linux'))
diff --git a/tools/perf/core/upload_results_to_perf_dashboard.py b/tools/perf/core/upload_results_to_perf_dashboard.py new file mode 100755 index 0000000..14ea676 --- /dev/null +++ b/tools/perf/core/upload_results_to_perf_dashboard.py
@@ -0,0 +1,269 @@ +#!/usr/bin/env python +# Copyright 2016 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. + +# This file was copy-pasted over from: +# //build/scripts/slave/upload_perf_dashboard_results.py +# with sections copied from: +# //build/scripts/slave/slave_utils.py + +import json +import optparse +import os +import re +import subprocess +import sys + +from core import results_dashboard + + +def _GetMainRevision(commit_pos, build_dir): + """Return revision to use as the numerical x-value in the perf dashboard. + This will be used as the value of "rev" in the data passed to + results_dashboard.SendResults. + In order or priority, this function could return: + 1. The value of "got_revision_cp" in build properties. + 3. An SVN number, git commit position, or git commit hash. + """ + if commit_pos is not None: + return int(re.search(r'{#(\d+)}', commit_pos).group(1)) + # TODO(sullivan,qyearsley): Don't fall back to _GetRevision if it returns + # a git commit, since this should be a numerical revision. Instead, abort + # and fail. + return _GetRevision(os.path.dirname(os.path.abspath(build_dir))) + + +def _GetDashboardJson(options): + main_revision = _GetMainRevision(options.got_revision_cp, options.build_dir) + revisions = _GetPerfDashboardRevisionsWithProperties( + options.got_webrtc_revision, options.got_v8_revision, options.version, + options.git_revision, main_revision) + reference_build = 'reference' in options.name + stripped_test_name = options.name.replace('.reference', '') + results = {} + with open(options.results_file) as f: + results = json.load(f) + dashboard_json = {} + if not 'charts' in results: + # These are legacy results. + dashboard_json = results_dashboard.MakeListOfPoints( + results, options.configuration.name, stripped_test_name, + options.buildername, options.buildnumber, {}, + _GetMachineGroup(options), revisions_dict=revisions) + else: + dashboard_json = results_dashboard.MakeDashboardJsonV1( + results, + revisions, stripped_test_name, options.configuration_name, + options.buildername, options.buildnumber, + {}, reference_build, + perf_dashboard_machine_group=_GetMachineGroup(options)) + return dashboard_json + +def _GetMachineGroup(options): + perf_dashboard_machine_group = options.perf_dashboard_machine_group + if options.is_luci_builder and not perf_dashboard_machine_group: + raise ValueError( + "Luci builder must set 'perf_dashboard_machine_group'. See " + 'bit.ly/perf-dashboard-machine-group for more details') + elif not options.is_luci_builder: + # TODO(crbug.com/801289): + # Remove this code path once all builders are converted to LUCI. + # perf_dashboard_machine_group = chromium_utils.GetActiveMaster() + # hardcoding the result of this line for now + perf_dashboard_machine_group = 'ChromiumPerfFyi' + return perf_dashboard_machine_group + + +def _GetDashboardHistogramData(options): + revisions = { + '--chromium_commit_positions': _GetMainRevision( + options.got_revision_cp, options.build_dir), + '--chromium_revisions': options.git_revision + } + + if options.got_webrtc_revision: + revisions['--webrtc_revisions'] = options.got_webrtc_revision + if options.got_v8_revision: + revisions['--v8_revisions'] = options.got_v8_revision + + is_reference_build = 'reference' in options.name + stripped_test_name = options.name.replace('.reference', '') + + return results_dashboard.MakeHistogramSetWithDiagnostics( + options.results_file, options.chromium_checkout_dir, stripped_test_name, + options.configuration_name, options.buildername, options.buildnumber, + revisions, is_reference_build, + perf_dashboard_machine_group=_GetMachineGroup(options)) + + +def _CreateParser(): + # Parse options + parser = optparse.OptionParser() + parser.add_option('--name') + parser.add_option('--results-file') + parser.add_option('--output-json-file') + parser.add_option('--got-revision-cp') + parser.add_option('--build-dir') + parser.add_option('--configuration-name') + parser.add_option('--results-url') + parser.add_option('--is-luci-builder', action='store_true', default=False) + parser.add_option('--perf-dashboard-machine-group') + parser.add_option('--buildername') + parser.add_option('--buildnumber') + parser.add_option('--got-webrtc-revision') + parser.add_option('--got-v8-revision') + parser.add_option('--version') + parser.add_option('--git-revision') + parser.add_option('--output-json-dashboard-url') + parser.add_option('--send-as-histograms', action='store_true') + parser.add_option('--oauth-token-file') + parser.add_option('--chromium-checkout-dir') + return parser + + +def main(args): + parser = _CreateParser() + options, extra_args = parser.parse_args(args) + + # Validate options. + if extra_args: + parser.error('Unexpected command line arguments') + if not options.configuration_name or not options.results_url: + parser.error('configuration_name and results_url are required.') + + if options.oauth_token_file: + with open(options.oauth_token_file) as f: + oauth_token = f.readline() + else: + oauth_token = None + + if not options.send_as_histograms: + dashboard_json = _GetDashboardJson(options) + else: + dashboard_json = _GetDashboardHistogramData(options) + + if dashboard_json: + if options.output_json_file: + with open(options.output_json_file, 'w') as output_file: + json.dump(dashboard_json, output_file) + if not results_dashboard.SendResults( + dashboard_json, + options.results_url, + options.build_dir, + options.output_json_dashboard_url, + send_as_histograms=options.send_as_histograms, + oauth_token=oauth_token): + return 1 + else: + print 'Error: No perf dashboard JSON was produced.' + print '@@@STEP_FAILURE@@@' + return 1 + return 0 + + +if __name__ == '__main__': + sys.exit(main((sys.argv[1:]))) + + +def _GetRevision(in_directory): + """Returns the SVN revision, git commit position, or git hash. + + Args: + in_directory: A directory in the repository to be checked. + + Returns: + An SVN revision as a string if the given directory is in a SVN repository, + or a git commit position number, or if that's not available, a git hash. + If all of that fails, an empty string is returned. + """ + if not os.path.exists(os.path.join(in_directory, '.svn')): + if _IsGitDirectory(in_directory): + svn_rev = _GetGitCommitPosition(in_directory) + if svn_rev: + return svn_rev + return _GetGitRevision(in_directory) + else: + return '' + + +def _IsGitDirectory(dir_path): + """Checks whether the given directory is in a git repository. + + Args: + dir_path: The directory path to be tested. + + Returns: + True if given directory is in a git repository, False otherwise. + """ + git_exe = 'git.bat' if sys.platform.startswith('win') else 'git' + with open(os.devnull, 'w') as devnull: + p = subprocess.Popen([git_exe, 'rev-parse', '--git-dir'], + cwd=dir_path, stdout=devnull, stderr=devnull) + return p.wait() == 0 + + +# Regex matching git comment lines containing svn revision info. +GIT_SVN_ID_RE = re.compile(r'^git-svn-id: .*@([0-9]+) .*$') +# Regex for the master branch commit position. +GIT_CR_POS_RE = re.compile(r'^Cr-Commit-Position: refs/heads/master@{#(\d+)}$') + + +def _GetGitCommitPositionFromLog(log): + """Returns either the commit position or svn rev from a git log.""" + # Parse from the bottom up, in case the commit message embeds the message + # from a different commit (e.g., for a revert). + for r in [GIT_CR_POS_RE, GIT_SVN_ID_RE]: + for line in reversed(log.splitlines()): + m = r.match(line.strip()) + if m: + return m.group(1) + return None + + +def _GetGitCommitPosition(dir_path): + """Extracts the commit position or svn revision number of the HEAD commit.""" + git_exe = 'git.bat' if sys.platform.startswith('win') else 'git' + p = subprocess.Popen( + [git_exe, 'log', '-n', '1', '--pretty=format:%B', 'HEAD'], + cwd=dir_path, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + (log, _) = p.communicate() + if p.returncode != 0: + return None + return _GetGitCommitPositionFromLog(log) + + +def _GetPerfDashboardRevisionsWithProperties( + got_webrtc_revision, got_v8_revision, version, git_revision, main_revision, + point_id=None): + """Fills in the same revisions fields that process_log_utils does.""" + + versions = {} + versions['rev'] = main_revision + versions['webrtc_rev'] = got_webrtc_revision + versions['v8_rev'] = got_v8_revision + versions['ver'] = version + versions['git_revision'] = git_revision + versions['point_id'] = point_id + # There are a lot of "bad" revisions to check for, so clean them all up here. + for key in versions.keys(): + if not versions[key] or versions[key] == 'undefined': + del versions[key] + return versions + + +def _GetGitRevision(in_directory): + """Returns the git hash tag for the given directory. + + Args: + in_directory: The directory where git is to be run. + + Returns: + The git SHA1 hash string. + """ + git_exe = 'git.bat' if sys.platform.startswith('win') else 'git' + p = subprocess.Popen( + [git_exe, 'rev-parse', 'HEAD'], + cwd=in_directory, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + (stdout, _) = p.communicate() + return stdout.strip()
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config new file mode 100644 index 0000000..21670851 --- /dev/null +++ b/tools/perf/expectations.config
@@ -0,0 +1,366 @@ +# Test Expectation file for telemetry tests. +# Instructions of how to use this file: +# https://chromium.googlesource.com/chromium/src/+/master/docs/speed/perf_bot_sheriffing.md#Disabling-Telemetry-Tests + +# tags: All Android_Svelte Android_Webview Android_but_not_webview Mac Win Linux +# tags: ChromeOS Android Desktop Mobile Nexus_5 Nexus_5X Nexus_6 Nexus_6P +# tags: Nexus_7 Cherry_Mobile_Android_One Mac_10.11 Mac_10.12 Nexus6_Webview +# tags: Nexus5X_Webview + +# Benchmark: battor.steady_state +crbug.com/505990 [ All ] battor.steady_state/http://abcnews.go.com/ [ Skip ] + +# Benchmark: blink_perf.bindings +crbug.com/764868 [ Cherry_Mobile_Android_One ] blink_perf.bindings/structured-clone-long-string-deserialize.html [ Skip ] +crbug.com/764868 [ Cherry_Mobile_Android_One ] blink_perf.bindings/structured-clone-json-serialize.html [ Skip ] +crbug.com/764868 [ Cherry_Mobile_Android_One ] blink_perf.bindings/structured-clone-long-string-serialize.html [ Skip ] +crbug.com/764868 [ Cherry_Mobile_Android_One ] blink_perf.bindings/structured-clone-json-deserialize.html [ Skip ] + +# Benchmark: blink_perf.canvas +crbug.com/593973 [ Android_Svelte ] blink_perf.canvas/* [ Skip ] +crbug.com/765799 [ Nexus_6 ] blink_perf.canvas/draw-static-canvas-2d-to-hw-accelerated-canvas-2d.html [ Skip ] +crbug.com/784540 [ Nexus_5 ] blink_perf.canvas/draw-static-canvas-2d-to-hw-accelerated-canvas-2d.html [ Skip ] +crbug.com/784540 [ Nexus_5X ] blink_perf.canvas/draw-static-canvas-2d-to-hw-accelerated-canvas-2d.html [ Skip ] +crbug.com/784540 [ Nexus_5 ] blink_perf.canvas/draw-dynamic-canvas-2d-to-hw-accelerated-canvas-2d.html [ Skip ] +crbug.com/784540 [ Nexus_5X ] blink_perf.canvas/draw-dynamic-canvas-2d-to-hw-accelerated-canvas-2d.html [ Skip ] +crbug.com/738453 [ Nexus_6 ] blink_perf.canvas/putImageData.html [ Skip ] + +# Benchmark: blink_perf.events +crbug.com/799184 [ Cherry_Mobile_Android_One ] blink_perf.events/EventsDispatchingInShadowTrees.html [ Skip ] + +# Benchmark: blink_perf.layout +crbug.com/551950 [ Android_Svelte ] blink_perf.layout/* [ Skip ] + +# Benchmark: blink_perf.paint +crbug.com/574483 [ Android_Svelte ] blink_perf.paint/* [ Skip ] +crbug.com/799540 [ Nexus_5 ] blink_perf.paint/* [ Skip ] +crbug.com/799540 [ Nexus_7 ] blink_perf.paint/* [ Skip ] + +# Benchmark: blink_perf.parser +crbug.com/796115 [ Cherry_Mobile_Android_One ] blink_perf.parser/html5-full-render.html [ Skip ] + +# Benchmark: blink_perf.shadow_dom +crbug.com/702319 [ Nexus_5X ] blink_perf.shadow_dom/* [ Skip ] + +# Benchmark: blink_perf.svg +crbug.com/736817 [ Nexus_5X ] blink_perf.svg/SvgCubics.html [ Skip ] +crbug.com/736817 [ Nexus_5X ] blink_perf.svg/Debian.html [ Skip ] +crbug.com/736817 [ Nexus_5X ] blink_perf.svg/HarveyRayner.html [ Skip ] +crbug.com/736817 [ Nexus_5X ] blink_perf.svg/CrawFishGanson.html [ Skip ] +crbug.com/736817 [ Nexus_5X ] blink_perf.svg/Worldcup.html [ Skip ] +crbug.com/736817 [ Nexus_5X ] blink_perf.svg/FlowerFromMyGarden.html [ Skip ] +crbug.com/736817 [ Nexus_5X ] blink_perf.svg/SvgNestedUse.html [ Skip ] + +# Benchmark: kraken +crbug.com/624411 [ Android_Svelte ] kraken/http://krakenbenchmark.mozilla.org/kraken-1.1/driver.html [ Skip ] + +# Benchmark: loading.desktop +crbug.com/723783 [ Win ] loading.desktop/Orange [ Skip ] +crbug.com/752611 [ Linux ] loading.desktop/uol.com.br [ Skip ] +crbug.com/805115 [ All ] loading.desktop/Ynet [ Skip ] +crbug.com/805115 [ All ] loading.desktop/Leboncoin [ Skip ] +crbug.com/805115 [ All ] loading.desktop/Rambler [ Skip ] +crbug.com/805115 [ All ] loading.desktop/2ch [ Skip ] +crbug.com/805115 [ All ] loading.desktop/goo.ne.jp [ Skip ] +crbug.com/805115 [ All ] loading.desktop/MLB [ Skip ] +crbug.com/805115 [ All ] loading.desktop/FDA [ Skip ] + +# Benchmark: loading.mobile +crbug.com/676612 [ Nexus6_Webview ] loading.mobile/* [ Skip ] +[ All ] loading.mobile/IBI [ Skip ] +[ All ] loading.mobile/HashOcean [ Skip ] +crbug.com/776092 [ Cherry_Mobile_Android_One ] loading.mobile/GoogleRedirectToGoogleJapan [ Skip ] +crbug.com/656861 [ All ] loading.mobile/G1 [ Skip ] +[ Nexus_5X ] loading.mobile/Hongkiat [ Skip ] +[ Nexus_5X ] loading.mobile/Dramaq [ Skip ] +[ Nexus_7 ] loading.mobile/Facebook [ Skip ] + +# Benchmark: memory.leak_detection +crbug.com/734427 [ All ] memory.leak_detection/https://www.google.com [ Skip ] +crbug.com/734427 [ All ] memory.leak_detection/https://www.facebook.com [ Skip ] +crbug.com/734427 [ All ] memory.leak_detection/https://www.baidu.com [ Skip ] +crbug.com/734427 [ All ] memory.leak_detection/https://www.wikipedia.org [ Skip ] +crbug.com/734427 [ All ] memory.leak_detection/http://www.twitter.com [ Skip ] +crbug.com/734427 [ All ] memory.leak_detection/https://www.yahoo.com [ Skip ] +crbug.com/734427 [ All ] memory.leak_detection/http://www.quora.com [ Skip ] + +# Benchmark: memory.long_running_idle_gmail_tbmv2 +crbug.com/611167 [ Android_Svelte ] memory.long_running_idle_gmail_tbmv2/* [ Skip ] + +# Benchmark: memory.long_running_idle_gmail_background_tbmv2 +crbug.com/611167 [ Android_Svelte ] memory.long_running_idle_gmail_background_tbmv2/* [ Skip ] + +# Benchmark: octane +[ Cherry_Mobile_Android_One ] octane/http://chromium.github.io/octane/index.html?auto=1 [ Skip ] + +# Benchmark: oilpan_gc_times.key_silk_cases +crbug.com/446332 [ All ] oilpan_gc_times.key_silk_cases/inbox_app.html?slide_drawer [ Skip ] +crbug.com/507865 [ All ] oilpan_gc_times.key_silk_cases/https://polymer-topeka.appspot.com/ [ Skip ] +crbug.com/338838 [ All ] oilpan_gc_times.key_silk_cases/http://plus.google.com/app/basic/stream [ Skip ] + +# Benchmark: oilpan_gc_times.sync_scroll.key_mobile_sites_smooth +crbug.com/756119 [ All ] oilpan_gc_times.sync_scroll.key_mobile_sites_smooth/http://digg.com [ Skip ] + +# Benchmark: power.idle_platform +crbug.com/773949 [ Nexus_5 ] power.idle_platform/* [ Skip ] +crbug.com/773949 [ Nexus_6 ] power.idle_platform/* [ Skip ] +crbug.com/773949 [ Nexus_7 ] power.idle_platform/* [ Skip ] +crbug.com/773949 [ Cherry_Mobile_Android_One ] power.idle_platform/* [ Skip ] + + +# Benchmark: smoothness.gpu_rasterization.polymer +[ All ] smoothness.gpu_rasterization.polymer/* [ Skip ] # Test needs to be modernized. + +# Benchmark: rasterize_and_record_micro.top_25 +crbug.com/768010 [ Cherry_Mobile_Android_One ] rasterize_and_record_micro.top_25/file://static_top_25/espn.html [ Skip ] +crbug.com/764543 [ All ] rasterize_and_record_micro.top_25/file://static_top_25/wikipedia.html [ Skip ] + +# Benchmark: smoothness.gpu_rasterization.top_25_smooth +crbug.com/667432 [ All ] smoothness.gpu_rasterization.top_25_smooth/Pinterest [ Skip ] +crbug.com/667432 [ All ] smoothness.gpu_rasterization.top_25_smooth/http://www.amazon.com [ Skip ] +crbug.com/528474 [ All ] smoothness.gpu_rasterization.top_25_smooth/http://www.cnn.com [ Skip ] +crbug.com/803869 [ Nexus_5X ] smoothness.gpu_rasterization.top_25_smooth/http://www.youtube.com [ Skip ] + +# Benchmark: smoothness.key_desktop_move_cases +crbug.com/750131 [ Win ] smoothness.key_desktop_move_cases/https://mail.google.com/mail/ [ Skip ] +crbug.com/770904 [ Mac ] smoothness.key_desktop_move_cases/https://mail.google.com/mail/ [ Skip ] + +# Benchmark: smoothness.key_mobile_sites_smooth +crbug.com/756119 [ All ] smoothness.key_mobile_sites_smooth/http://digg.com [ Skip ] +crbug.com/667432 [ All ] smoothness.key_mobile_sites_smooth/http://www.amazon.com/gp/aw/s/ref=is_box_?k=nicolas+cage [ Skip ] +crbug.com/169980 [ All ] smoothness.key_mobile_sites_smooth/Twitter [ Skip ] +crbug.com/249722 [ All ] smoothness.key_mobile_sites_smooth/ESPN [ Skip ] +crbug.com/249736 [ All ] smoothness.key_mobile_sites_smooth/http://forecast.io [ Skip ] + +# Benchmark: smoothness.key_silk_cases +[ All ] smoothness.key_silk_cases/inbox_app.html?slide_drawer [ Skip ] +crbug.com/780525 [ All ] smoothness.key_silk_cases/https://polymer-topeka.appspot.com/ [ Skip ] +crbug.com/461127 [ All ] smoothness.key_silk_cases/http://s.codepen.io/befamous/fullpage/pFsqb?scroll [ Skip ] + +# Benchmark: smoothness.maps +crbug.com/653993 [ Android_Webview ] smoothness.maps/maps_perf_test [ Skip ] + +# Benchmark: smoothness.pathological_mobile_sites +crbug.com/685342 [ Nexus_7 ] smoothness.pathological_mobile_sites/* [ Skip ] + +# Benchmark: smoothness.simple_mobile_sites +crbug.com/750833 [ Android_Webview ] smoothness.simple_mobile_sites/https://www.flickr.com/ [ Skip ] + +# Benchmark: smoothness.sync_scroll.key_mobile_sites_smooth +crbug.com/756119 [ All ] smoothness.sync_scroll.key_mobile_sites_smooth/http://digg.com [ Skip ] + +# Benchmark: smoothness.top_25_smooth +crbug.com/762165 [ Win ] smoothness.top_25_smooth/https://www.google.com/calendar/ [ Skip ] +crbug.com/762165 [ Win ] smoothness.top_25_smooth/http://www.youtube.com [ Skip ] +crbug.com/667432 [ All ] smoothness.top_25_smooth/http://www.amazon.com [ Skip ] +crbug.com/528474 [ All ] smoothness.top_25_smooth/http://www.cnn.com [ Skip ] +crbug.com/762165 [ Win ] smoothness.top_25_smooth/https://plus.google.com/110031535020051778989/posts [ Skip ] +crbug.com/762165 [ Win ] smoothness.top_25_smooth/https://www.google.com/search?q=cats&tbm=isch [ Skip ] +crbug.com/762165 [ Win ] smoothness.top_25_smooth/Docs_(1_open_document_tab) [ Skip ] + +# Benchmark: smoothness.tough_ad_cases +crbug.com/555089 [ Android_Svelte ] smoothness.tough_ad_cases/* [ Skip ] + +# Benchmark: smoothness.tough_animation_cases +crbug.com/350692 [ All ] smoothness.tough_animation_cases/robohornetpro [ Skip ] +crbug.com/755556 [ Mobile ] smoothness.tough_animation_cases/balls_css_keyframe_animations_composited_transform.html [ Skip ] +crbug.com/755556 [ Mac ] smoothness.tough_animation_cases/mix_blend_mode_animation_difference.html [ Skip ] +crbug.com/755556 [ Mac ] smoothness.tough_animation_cases/mix_blend_mode_animation_hue.html [ Skip ] + +# Benchmark: smoothness.tough_canvas_cases +crbug.com/785485 [ Android_Webview ] smoothness.tough_canvas_cases/http://www.kevs3d.co.uk/dev/canvask3d/k3d_test.html [ Skip ] +crbug.com/755657 [ Cherry_Mobile_Android_One ] smoothness.tough_canvas_cases/tough_canvas_cases/canvas_toBlob.html [ Skip ] +crbug.com/785286 [ Android_Webview ] smoothness.tough_canvas_cases/http://www.smashcat.org/av/canvas_test/ [ Skip ] +crbug.com/785286 [ Android_Webview ] smoothness.tough_canvas_cases/http://www.effectgames.com/demos/canvascycle/ [ Skip ] +crbug.com/364248 [ Nexus_5 ] smoothness.tough_canvas_cases/http://geoapis.appspot.com/agdnZW9hcGlzchMLEgtFeGFtcGxlQ29kZRjh1wIM [ Skip ] + +# Benchmark: smoothness.tough_scrolling_cases +crbug.com/785473 [ Android_Webview ] smoothness.tough_scrolling_cases/canvas_15000_pixels_per_second [ Skip ] +crbug.com/785473 [ Android_Webview ] smoothness.tough_scrolling_cases/canvas_20000_pixels_per_second [ Skip ] +crbug.com/785473 [ Android_Webview ] smoothness.tough_scrolling_cases/canvas_40000_pixels_per_second [ Skip ] +crbug.com/785473 [ Android_Webview ] smoothness.tough_scrolling_cases/canvas_50000_pixels_per_second [ Skip ] +crbug.com/785473 [ Android_Webview ] smoothness.tough_scrolling_cases/canvas_10000_pixels_per_second [ Skip ] +crbug.com/785473 [ Android_Webview ] smoothness.tough_scrolling_cases/canvas_05000_pixels_per_second [ Skip ] +crbug.com/785473 [ Android_Webview ] smoothness.tough_scrolling_cases/canvas_30000_pixels_per_second [ Skip ] +crbug.com/785473 [ Android_Webview ] smoothness.tough_scrolling_cases/canvas_75000_pixels_per_second [ Skip ] +crbug.com/785473 [ Android_Webview ] smoothness.tough_scrolling_cases/canvas_60000_pixels_per_second [ Skip ] +crbug.com/785473 [ Android_Webview ] smoothness.tough_scrolling_cases/canvas_90000_pixels_per_second [ Skip ] + +# Benchmark: smoothness.tough_texture_upload_cases +crbug.com/795060 [ Cherry_Mobile_Android_One ] smoothness.tough_texture_upload_cases/extra_large_texture_uploads.html [ Skip ] + +# Benchmark: smoothness.tough_webgl_ad_cases +crbug.com/574485 [ Android_Svelte ] smoothness.tough_webgl_ad_cases/* [ Skip ] + +# Benchmark: speedometer2-future +crbug.com/792495 [ Linux ] speedometer2-future/Speedometer2 [ Skip ] +crbug.com/784025 [ Win ] speedometer2-future/Speedometer2 [ Skip ] + +# Benchmark: system_health.common_desktop +crbug.com/728576 [ Mac ] system_health.common_desktop/browse:news:cnn [ Skip ] +crbug.com/64939 [ All ] system_health.common_desktop/play:media:pandora [ Skip ] +crbug.com/809146 [ All ] system_health.common_desktop/browse:media:tumblr [ Skip ] +crbug.com/676336 [ Win ] system_health.common_desktop/browse:news:hackernews [ Skip ] +crbug.com/676336 [ Mac ] system_health.common_desktop/browse:news:hackernews [ Skip ] +crbug.com/649392 [ Win ] system_health.common_desktop/play:media:soundcloud [ Skip ] +crbug.com/649392 [ All ] system_health.common_desktop/play:media:google_play_music [ Skip ] +crbug.com/773084 [ Mac ] system_health.common_desktop/browse:tools:maps [ Skip ] +crbug.com/769809 [ All ] system_health.common_desktop/browse_accessibility:tools:gmail_compose [ Skip ] +crbug.com/673775 [ Win ] system_health.common_desktop/browse:search:google [ Skip ] +crbug.com/773393 [ Win ] system_health.common_desktop/browse:media:tumblr [ Skip ] +crbug.com/799106 [ Win ] system_health.common_desktop/browse:media:flickr_infinite_scroll [ Skip ] + +# Benchmark: system_health.common_mobile +[ Android_Webview ] system_health.common_mobile/browse:chrome:omnibox [ Skip ] +crbug.com/736497 [ Nexus_6 ] system_health.common_mobile/browse:shopping:avito [ Skip ] +crbug.com/657433 [ Android ] system_health.common_mobile/load:tools:gmail [ Skip ] +crbug.com/714650 [ Android ] system_health.common_mobile/browse:news:globo [ Skip ] +crbug.com/728081 [ Android ] system_health.common_mobile/browse:news:toi [ Skip ] +[ Android_Webview ] system_health.common_mobile/long_running:tools:gmail-background [ Skip ] +crbug.com/787001 [ Android_Webview ] system_health.common_mobile/load:media:soundcloud [ Skip ] +crbug.com/708300 [ Android ] system_health.common_mobile/browse:shopping:flipkart [ Skip ] +[ Android_Webview ] system_health.common_mobile/browse:chrome:newtab [ Skip ] +crbug.com/738854 [ Nexus_5X ] system_health.common_mobile/load:tools:drive [ Skip ] +crbug.com/738854 [ Android_Webview ] system_health.common_mobile/load:tools:drive [ Skip ] +crbug.com/797261 [ Android_Webview ] system_health.common_mobile/load:games:spychase [ Skip ] +crbug.com/798536 [ Android ] system_health.common_mobile/background:news:nytimes [ Skip ] +crbug.com/798536 [ Android ] system_health.common_mobile/load:games:spychase [ Skip ] +crbug.com/736147 [ Cherry_Mobile_Android_One ] system_health.common_mobile/browse:social:tumblr_infinite_scroll [ Skip ] +crbug.com/803461 [ Nexus_5 ] system_health.common_mobile/browse:chrome:newtab [ Skip ] + +# Benchmark: system_health.memory_desktop +crbug.com/728576 [ Mac ] system_health.memory_desktop/browse:news:cnn [ Skip ] +crbug.com/64939 [ All ] system_health.memory_desktop/play:media:pandora [ Skip ] +crbug.com/676336 [ Win ] system_health.memory_desktop/browse:news:hackernews [ Skip ] +crbug.com/676336 [ Mac ] system_health.memory_desktop/browse:news:hackernews [ Skip ] +crbug.com/649392 [ Win ] system_health.memory_desktop/play:media:soundcloud [ Skip ] +crbug.com/649392 [ All ] system_health.memory_desktop/play:media:google_play_music [ Skip ] +crbug.com/742475 [ Mac ] system_health.memory_desktop/multitab:misc:typical24 [ Skip ] +crbug.com/773084 [ Mac ] system_health.memory_desktop/browse:tools:maps [ Skip ] +crbug.com/769809 [ All ] system_health.memory_desktop/browse_accessibility:tools:gmail_compose [ Skip ] +crbug.com/673775 [ Win ] system_health.memory_desktop/browse:search:google [ Skip ] +crbug.com/664661 [ Mac ] system_health.memory_desktop/load:games:miniclip [ Skip ] +crbug.com/728464 [ All ] system_health.memory_desktop/browse:social:twitter_infinite_scroll [ Skip ] +crbug.com/799106 [ Win ] system_health.memory_desktop/browse:media:flickr_infinite_scroll [ Skip ] + +# Benchmark: system_health.memory_mobile +crbug.com/787001 [ Android_Webview ] system_health.memory_mobile/load:media:soundcloud [ Skip ] +[ Android_Webview ] system_health.memory_mobile/browse:chrome:newtab [ Skip ] +crbug.com/714650 [ Android ] system_health.memory_mobile/browse:news:globo [ Skip ] +[ Android_Webview ] system_health.memory_mobile/browse:chrome:omnibox [ Skip ] +crbug.com/657433 [ Android ] system_health.memory_mobile/load:tools:gmail [ Skip ] +crbug.com/728081 [ Android ] system_health.memory_mobile/browse:news:toi [ Skip ] +crbug.com/777355 [ Android_Svelte ] system_health.memory_mobile/long_running:tools:gmail-background [ Skip ] +[ Android_Webview ] system_health.memory_mobile/long_running:tools:gmail-background [ Skip ] +crbug.com/708300 [ Android ] system_health.memory_mobile/browse:shopping:flipkart [ Skip ] +crbug.com/784400 [ Nexus_5 ] system_health.memory_mobile/background:tools:gmail [ Skip ] +crbug.com/780779 [ Nexus_5 ] system_health.memory_mobile/browse:social:facebook [ Skip ] +crbug.com/738854 [ Nexus_5X ] system_health.memory_mobile/load:tools:drive [ Skip ] +crbug.com/738854 [ Android_Webview ] system_health.memory_mobile/load:tools:drive [ Skip ] +crbug.com/797261 [ Android_Webview ] system_health.memory_mobile/load:games:spychase [ Skip ] +crbug.com/803462 [ Nexus_5 ] system_health.memory_mobile/browse:chrome:newtab [ Skip ] + +# Benchmark: tab_switching.typical_25 +crbug.com/747026 [ Mac ] tab_switching.typical_25/multitab:misc:typical24 [ Skip ] + +# Benchmark: thread_times.key_hit_test_cases +crbug.com/750876 [ All ] thread_times.key_hit_test_cases/* [ Skip ] + +# Benchmark: thread_times.key_silk_cases +crbug.com/446332 [ All ] thread_times.key_silk_cases/inbox_app.html?slide_drawer [ Skip ] +crbug.com/764825 [ All ] thread_times.key_silk_cases/inbox_app.html?swipe_to_dismiss [ Skip ] +crbug.com/507865 [ All ] thread_times.key_silk_cases/https://polymer-topeka.appspot.com/ [ Skip ] +crbug.com/764825 [ All ] thread_times.key_silk_cases/http://s.codepen.io/befamous/fullpage/pFsqb?scroll [ Skip ] +crbug.com/764825 [ All ] thread_times.key_silk_cases/masonry.html [ Skip ] +crbug.com/338838 [ All ] thread_times.key_silk_cases/http://plus.google.com/app/basic/stream [ Skip ] + +# Benchmark: thread_times.simple_mobile_sites +crbug.com/752228 [ All ] thread_times.simple_mobile_sites/https://www.flickr.com/ [ Skip ] + +# Benchmark: thread_times.tough_scrolling_cases +crbug.com/783362 [ Android_Webview ] thread_times.tough_scrolling_cases/canvas_15000_pixels_per_second [ Skip ] +crbug.com/783362 [ Android_Webview ] thread_times.tough_scrolling_cases/canvas_20000_pixels_per_second [ Skip ] +crbug.com/783362 [ Android_Webview ] thread_times.tough_scrolling_cases/canvas_40000_pixels_per_second [ Skip ] +crbug.com/783362 [ Android_Webview ] thread_times.tough_scrolling_cases/canvas_50000_pixels_per_second [ Skip ] +crbug.com/783362 [ Android_Webview ] thread_times.tough_scrolling_cases/canvas_10000_pixels_per_second [ Skip ] +crbug.com/783362 [ Android_Webview ] thread_times.tough_scrolling_cases/canvas_05000_pixels_per_second [ Skip ] +crbug.com/783362 [ Android_Webview ] thread_times.tough_scrolling_cases/canvas_30000_pixels_per_second [ Skip ] +crbug.com/783362 [ Android_Webview ] thread_times.tough_scrolling_cases/canvas_75000_pixels_per_second [ Skip ] +crbug.com/783362 [ Android_Webview ] thread_times.tough_scrolling_cases/canvas_60000_pixels_per_second [ Skip ] +crbug.com/783362 [ Android_Webview ] thread_times.tough_scrolling_cases/canvas_90000_pixels_per_second [ Skip ] + +# Benchmark: v8.browsing_desktop +crbug.com/773084 [ Mac ] v8.browsing_desktop/browse:tools:maps [ Skip ] +crbug.com/788796 [ Linux ] v8.browsing_desktop/browse:media:imgur [ Skip ] +crbug.com/806001 [ Linux ] v8.browsing_desktop/browse:media:tumblr [ Skip ] +#crbug.com/676336 [ Win ] v8.browsing_desktop/browse:news:hackernews [ Skip ] +crbug.com/676336 [ Mac ] v8.browsing_desktop/browse:news:hackernews [ Skip ] +[ Mac ] v8.browsing_desktop/browse:news:cnn [ Skip ] +crbug.com/798465 [ Mac ] v8.browsing_desktop/browse:news:flipboard [ Skip ] +crbug.com/798465 [ Win ] v8.browsing_desktop/browse:news:flipboard [ Skip ] + +# Benchmark: v8.browsing_desktop-future +crbug.com/773084 [ Mac ] v8.browsing_desktop-future/browse:tools:maps [ Skip ] +crbug.com/788796 [ Linux ] v8.browsing_desktop-future/browse:media:imgur [ Skip ] +crbug.com/806001 [ Linux ] v8.browsing_desktop-future/browse:media:tumblr [ Skip ] +crbug.com/676336 [ Win ] v8.browsing_desktop-future/browse:media:flickr_infinite_scroll [ Skip ] +crbug.com/676336 [ Win ] v8.browsing_desktop-future/browse:news:hackernews [ Skip ] +crbug.com/676336 [ Mac ] v8.browsing_desktop-future/browse:news:hackernews [ Skip ] +crbug.com/728576 [ Mac ] v8.browsing_desktop-future/browse:news:cnn [ Skip ] +crbug.com/798465 [ Mac ] v8.browsing_desktop-future/browse:news:flipboard [ Skip ] +crbug.com/798465 [ Win ] v8.browsing_desktop-future/browse:news:flipboard [ Skip ] +crbug.com/805934 [ Mac_10.12 ] v8.browsing_desktop-future/browse:tech:discourse_infinite_scroll [ Skip ] + +# Benchmark: v8.browsing_mobile +crbug.com/788797 [ Cherry_Mobile_Android_One ] v8.browsing_mobile/browse:social:facebook_infinite_scroll [ Skip ] +crbug.com/788797 [ Cherry_Mobile_Android_One ] v8.browsing_mobile/browse:social:pinterest_infinite_scroll [ Skip ] +crbug.com/768472 [ Cherry_Mobile_Android_One ] v8.browsing_mobile/browse:shopping:lazada [ Skip ] +crbug.com/714650 [ Android ] v8.browsing_mobile/browse:news:globo [ Skip ] +crbug.com/767970 [ Cherry_Mobile_Android_One ] v8.browsing_mobile/browse:tech:discourse_infinite_scroll [ Skip ] +crbug.com/767970 [ Cherry_Mobile_Android_One ] v8.browsing_mobile/browse:shopping:avito [ Skip ] +[ Android_Webview ] v8.browsing_mobile/browse:chrome:omnibox [ Skip ] +crbug.com/728081 [ Android ] v8.browsing_mobile/browse:news:toi [ Skip ] +crbug.com/767970 [ Cherry_Mobile_Android_One ] v8.browsing_mobile/browse:news:cnn [ Skip ] +crbug.com/767970 [ Mobile ] v8.browsing_mobile/browse:shopping:flipkart [ Skip ] +crbug.com/708300 [ Mobile ] v8.browsing_mobile/browse:shopping:flipkart [ Skip ] +[ Android_Webview ] v8.browsing_mobile/browse:chrome:newtab [ Skip ] +crbug.com/803465 [ Nexus_5 ] v8.browsing_mobile/browse:chrome:newtab [ Skip ] +crbug.com/803870 [ Cherry_Mobile_Android_One ] v8.browsing_mobile/browse:social:tumblr_infinite_scroll [ Skip ] +crbug.com/803870 [ Cherry_Mobile_Android_One ] v8.browsing_mobile/browse:media:youtube [ Skip ] +crbug.com/799080 [ Nexus_7 ] v8.browsing_mobile-future/browse:news:cnn [ Skip ] + +# Benchmark: v8.browsing_mobile-future +crbug.com/788797 [ Cherry_Mobile_Android_One ] v8.browsing_mobile-future/browse:social:facebook_infinite_scroll [ Skip ] +crbug.com/788797 [ Cherry_Mobile_Android_One ] v8.browsing_mobile-future/browse:social:pinterest_infinite_scroll [ Skip ] +crbug.com/768472 [ Cherry_Mobile_Android_One ] v8.browsing_mobile-future/browse:shopping:lazada [ Skip ] +crbug.com/714650 [ Android ] v8.browsing_mobile-future/browse:news:globo [ Skip ] +crbug.com/767970 [ Cherry_Mobile_Android_One ] v8.browsing_mobile-future/browse:tech:discourse_infinite_scroll [ Skip ] +crbug.com/767970 [ Cherry_Mobile_Android_One ] v8.browsing_mobile-future/browse:shopping:avito [ Skip ] +[ Android_Webview ] v8.browsing_mobile-future/browse:chrome:omnibox [ Skip ] +crbug.com/728081 [ Android ] v8.browsing_mobile-future/browse:news:toi [ Skip ] +crbug.com/767970 [ Cherry_Mobile_Android_One ] v8.browsing_mobile-future/browse:news:cnn [ Skip ] +crbug.com/803870 [ Cherry_Mobile_Android_One ] v8.browsing_mobile-future/browse:media:youtube [ Skip ] +crbug.com/767970 [ Mobile ] v8.browsing_mobile-future/browse:shopping:flipkart [ Skip ] +crbug.com/708300 [ Mobile ] v8.browsing_mobile-future/browse:shopping:flipkart [ Skip ] +[ Android_Webview ] v8.browsing_mobile-future/browse:chrome:newtab [ Skip ] +crbug.com/799080 [ Nexus_5 ] v8.browsing_mobile-future/browse:social:tumblr_infinite_scroll [ Skip ] +crbug.com/799080 [ Nexus_5X Android_Webview ] v8.browsing_mobile-future/browse:social:facebook [ Skip ] +crbug.com/799080 [ Nexus_7 ] v8.browsing_mobile-future/browse:news:cnn [ Skip ] +crbug.com/799080 [ Nexus_7 ] v8.browsing_mobile-future/browse:shopping:avito [ Skip ] +crbug.com/799080 [ Nexus_7 ] v8.browsing_mobile-future/browse:social:pinterest_infinite_scroll [ Skip ] +crbug.com/803465 [ Nexus_5 ] v8.browsing_mobile-future/browse:chrome:newtab [ Skip ] + +# Benchmark: v8.detached_context_age_in_gc +crbug.com/770982 [ Win ] v8.detached_context_age_in_gc/Docs_(1_open_document_tab) [ Skip ] + +# Benchmark: v8.runtime_stats.top_25 +crbug.com/664318 [ Android ] v8.runtime_stats.top_25/* [ Skip ] +crbug.com/664318 [ Win ] v8.runtime_stats.top_25/* [ Skip ] + +# Benchmark: wasm +[ Cherry_Mobile_Android_One ] wasm/WasmSpaceBuggy [ Skip ] + +##### Perf FYI benchmarks go after here ##### +# Benchmark: loading.desktop.network_service +crbug.com/723783 [ Win ] loading.desktop.network_service/Orange [ Skip ] +crbug.com/752611 [ Linux ] loading.desktop.network_service/uol.com.br [ Skip ]
diff --git a/tools/perf/fetch_benchmark_deps_unittest.py b/tools/perf/fetch_benchmark_deps_unittest.py index 605885c..9c2485e 100644 --- a/tools/perf/fetch_benchmark_deps_unittest.py +++ b/tools/perf/fetch_benchmark_deps_unittest.py
@@ -57,7 +57,7 @@ self._RunFetchBenchmarkDepsTest('smoothness.top_25_smooth') def testFetchServingDirs(self): - self._RunFetchBenchmarkDepsTest('media.tough_video_cases') + self._RunFetchBenchmarkDepsTest('media.desktop') def testFetchOctane(self): octane_wpr_path = os.path.join(
diff --git a/tools/perf/generate_perf_data b/tools/perf/generate_perf_data index fe0c73c..1a3fe4b 100755 --- a/tools/perf/generate_perf_data +++ b/tools/perf/generate_perf_data
@@ -9,4 +9,4 @@ if __name__ == '__main__': - sys.exit(perf_data_generator.main(sys.argv[1:])) + sys.exit(perf_data_generator.main())
diff --git a/tools/perf/generate_profile b/tools/perf/generate_profile deleted file mode 100755 index d477115..0000000 --- a/tools/perf/generate_profile +++ /dev/null
@@ -1,14 +0,0 @@ -#!/usr/bin/env python -# 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. -import os -import sys - -from chrome_telemetry_build import chromium_config -sys.path.insert(1, chromium_config.GetTelemetryDir()) - -from profile_creators import profile_generator - -if __name__ == '__main__': - sys.exit(profile_generator.Main())
diff --git a/tools/perf/generate_system_health_csv b/tools/perf/generate_system_health_csv index aa1c079..f462ba1 100755 --- a/tools/perf/generate_system_health_csv +++ b/tools/perf/generate_system_health_csv
@@ -3,43 +3,13 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import csv -import os import sys - +import os +from core import system_health_csv_generator from core import path_util -sys.path.insert(1, path_util.GetTelemetryDir()) # To resolve telemetry imports -import page_sets - - -def IterAllSystemHealthStories(): - for s in page_sets.SystemHealthStorySet(platform='desktop'): - yield s - for s in page_sets.SystemHealthStorySet(platform='mobile'): - if len(s.SUPPORTED_PLATFORMS) < 2: - yield s - -SYSTEM_HEALTH_CSV = os.path.join(os.path.dirname(__file__), +SYSTEM_HEALTH_CSV = os.path.join(path_util.GetPerfDir(), 'system_health_stories.csv') - - -def main(): - system_health_stories = list(IterAllSystemHealthStories()) - system_health_stories.sort(key=lambda s: s.name) - with open(SYSTEM_HEALTH_CSV, 'w') as f: - csv_writer = csv.writer(f) - csv_writer.writerow([ - 'Story name', 'Platform', 'Description']) - for s in system_health_stories: - p = s.SUPPORTED_PLATFORMS - if len(p) == 2: - p = 'all' - else: - p = list(p)[0] - csv_writer.writerow([s.name, p, s.GetStoryDescription()]) - return 0 - - if __name__ == '__main__': - sys.exit(main()) + sys.exit(system_health_csv_generator.GenerateSystemHealthCSV( + SYSTEM_HEALTH_CSV)) \ No newline at end of file
diff --git a/tools/perf/measurements/clock_domain_test.py b/tools/perf/measurements/clock_domain_test.py index bc03404f..46c1919 100644 --- a/tools/perf/measurements/clock_domain_test.py +++ b/tools/perf/measurements/clock_domain_test.py
@@ -25,7 +25,8 @@ options.enable_chrome_trace = True tracing_controller.StartTracing(options) - full_trace = tracing_controller.StopTracing() + full_trace = tracing_controller.StopTracing()[0] + chrome_sync = GetSyncEvents( full_trace.GetTraceFor(trace_data.CHROME_TRACE_PART)['traceEvents']) telemetry_sync = GetSyncEvents(
diff --git a/tools/perf/measurements/draw_properties.py b/tools/perf/measurements/draw_properties.py index 3021930..ba84406 100644 --- a/tools/perf/measurements/draw_properties.py +++ b/tools/perf/measurements/draw_properties.py
@@ -38,7 +38,7 @@ def ValidateAndMeasurePage(self, page, tab, results): del page # unused - timeline_data = tab.browser.platform.tracing_controller.StopTracing() + timeline_data = tab.browser.platform.tracing_controller.StopTracing()[0] timeline_model = model.TimelineModel(timeline_data) pt_avg = self.ComputeAverageOfDurations(
diff --git a/tools/perf/measurements/image_decoding.py b/tools/perf/measurements/image_decoding.py index 5906488..27bc37b 100644 --- a/tools/perf/measurements/image_decoding.py +++ b/tools/perf/measurements/image_decoding.py
@@ -48,7 +48,7 @@ tab.browser.platform.tracing_controller.StartTracing(config) def ValidateAndMeasurePage(self, page, tab, results): - timeline_data = tab.browser.platform.tracing_controller.StopTracing() + timeline_data = tab.browser.platform.tracing_controller.StopTracing()[0] timeline_model = model.TimelineModel(timeline_data) self._power_metric.Stop(page, tab) self._power_metric.AddResults(tab, results)
diff --git a/tools/perf/measurements/media.py b/tools/perf/measurements/media.py deleted file mode 100644 index bed1efa..0000000 --- a/tools/perf/measurements/media.py +++ /dev/null
@@ -1,80 +0,0 @@ -# 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. - -from telemetry.page import legacy_page_test - -from metrics import cpu -from metrics import media -from metrics import power -from metrics import system_memory - - -class Media(legacy_page_test.LegacyPageTest): - """The MediaMeasurement class gathers media-related metrics on a page set. - - Media metrics recorded are controlled by metrics/media.js. At the end of the - test each metric for every media element in the page are reported. - """ - - def __init__(self): - super(Media, self).__init__() - self._media_metric = None - # Used to add browser power and CPU metrics to results per test. - self._add_browser_metrics = False - self._cpu_metric = None - self._memory_metric = None - self._power_metric = None - - def WillStartBrowser(self, platform): - self._power_metric = power.PowerMetric(platform) - - def CustomizeBrowserOptions(self, options): - # Needed to run media actions in JS on touch-based devices as on Android. - # Note that both of these flags should be used until every build from - # ToT to Stable switches over to one flag or another. This is to support - # reference builds. - # --disable-gesture-requirement-for-media-playback is the old one and can be - # removed after M60 goes to stable. - options.AppendExtraBrowserArgs( - ['--ignore-autoplay-restrictions', - '--disable-gesture-requirement-for-media-playback']) - power.PowerMetric.CustomizeBrowserOptions(options) - - def DidNavigateToPage(self, page, tab): - """Override to do operations right after the page is navigated.""" - self._media_metric = media.MediaMetric(tab) - self._media_metric.Start(page, tab) - - # Reset to false for every page. - self._add_browser_metrics = ( - page.add_browser_metrics - if hasattr(page, 'add_browser_metrics') else False) - - if self._add_browser_metrics: - self._cpu_metric = cpu.CpuMetric(tab.browser) - self._cpu_metric.Start(page, tab) - self._memory_metric = system_memory.SystemMemoryMetric(tab.browser) - self._memory_metric.Start(page, tab) - self._power_metric.Start(page, tab) - - def ValidateAndMeasurePage(self, page, tab, results): - """Measure the page's performance.""" - self._media_metric.Stop(page, tab) - trace_name = self._media_metric.AddResults(tab, results) - - if self._add_browser_metrics: - self._cpu_metric.Stop(page, tab) - self._memory_metric.Stop(page, tab) - self._power_metric.Stop(page, tab) - self._cpu_metric.AddResults(tab, results, trace_name=trace_name) - exclude_metrics = ['WorkingSetSizePeak', 'SystemCommitCharge', 'VMPeak', - 'VM'] - self._memory_metric.AddResults(tab, results, - trace_name=trace_name, - exclude_metrics=exclude_metrics) - self._power_metric.AddResults(tab, results) - - def DidRunPage(self, platform): - del platform # unused - self._power_metric.Close()
diff --git a/tools/perf/measurements/smoothness.py b/tools/perf/measurements/smoothness.py index 6017cc51..d96c716 100644 --- a/tools/perf/measurements/smoothness.py +++ b/tools/perf/measurements/smoothness.py
@@ -3,37 +3,32 @@ # found in the LICENSE file. from telemetry.page import legacy_page_test -from telemetry.timeline import chrome_trace_category_filter -from telemetry.web_perf import timeline_based_measurement +from telemetry.timeline import model as model_module +from telemetry.value import trace from telemetry.web_perf.metrics import smoothness +from telemetry.web_perf import smooth_gesture_util +from telemetry.web_perf import timeline_interaction_record as tir_module +from telemetry.timeline import tracing_config -class _CustomResultsWrapper(timeline_based_measurement.ResultsWrapperInterface): - - def __init__(self): - super(_CustomResultsWrapper, self).__init__() - self._pages_to_tir_labels = {} - - def _AssertNewValueHasSameInteractionLabel(self, new_value): - tir_label = self._pages_to_tir_labels.get(new_value.page) - if tir_label: - assert tir_label == self._tir_label, ( - 'Smoothness measurement do not support multiple interaction record ' - 'labels per page yet. See crbug.com/453109 for more information.') - else: - self._pages_to_tir_labels[new_value.page] = self._tir_label - - def AddValue(self, value): - self._AssertNewValueHasSameInteractionLabel(value) - self._results.AddValue(value) +def _CollectRecordsFromRendererThreads(model, renderer_thread): + records = [] + for event in renderer_thread.async_slices: + if tir_module.IsTimelineInteractionRecord(event.name): + interaction = tir_module.TimelineInteractionRecord.FromAsyncEvent(event) + # Adjust the interaction record to match the synthetic gesture + # controller if needed. + interaction = ( + smooth_gesture_util.GetAdjustedInteractionIfContainGesture( + model, interaction)) + records.append(interaction) + return records class Smoothness(legacy_page_test.LegacyPageTest): def __init__(self): super(Smoothness, self).__init__() - self._results_wrapper = _CustomResultsWrapper() - self._tbm = None self._results = None @classmethod @@ -44,24 +39,49 @@ def WillNavigateToPage(self, page, tab): # FIXME: Remove webkit.console when blink.console lands in chromium and # the ref builds are updated. crbug.com/386847 + config = tracing_config.TracingConfig() + config.enable_chrome_trace = True + config.enable_platform_display_trace = True + + # Basic categories for smoothness. custom_categories = [ 'webkit.console', 'blink.console', 'benchmark', 'trace_event_overhead'] - category_filter = chrome_trace_category_filter.ChromeTraceCategoryFilter( - ','.join(custom_categories)) - if self.options and self.options.extra_chrome_categories: - category_filter.AddFilterString(self.options.extra_chrome_categories) + for cat in custom_categories: + config.chrome_trace_config.category_filter.AddFilterString(cat) - options = timeline_based_measurement.Options(category_filter) - options.config.enable_platform_display_trace = True - options.SetLegacyTimelineBasedMetrics([smoothness.SmoothnessMetric()]) - self._tbm = timeline_based_measurement.TimelineBasedMeasurement( - options, self._results_wrapper) - self._tbm.WillRunStory(tab.browser.platform) + # Extra categories from commandline flag. + if self.options and self.options.extra_chrome_categories: + config.chrome_trace_config.category_filter.AddFilterString( + self.options.extra_chrome_categories) + + tab.browser.platform.tracing_controller.StartTracing(config) def ValidateAndMeasurePage(self, _, tab, results): self._results = results - self._tbm.Measure(tab.browser.platform, results) + trace_result = tab.browser.platform.tracing_controller.StopTracing()[0] + trace_value = trace.TraceValue( + results.current_page, trace_result, + file_path=results.telemetry_info.trace_local_path, + remote_path=results.telemetry_info.trace_remote_path, + upload_bucket=results.telemetry_info.upload_bucket, + cloud_url=results.telemetry_info.trace_remote_url) + results.AddValue(trace_value) + + model = model_module.TimelineModel(trace_result) + renderer_thread = model.GetRendererThreadFromTabId(tab.id) + records = _CollectRecordsFromRendererThreads(model, renderer_thread) + metric = smoothness.SmoothnessMetric() + metric.AddResults(model, renderer_thread, records, results) def DidRunPage(self, platform): - if self._tbm: - self._tbm.DidRunStory(platform, self._results) + if platform.tracing_controller.is_tracing_running: + trace_result = platform.tracing_controller.StopTracing()[0] + if self._results: + trace_value = trace.TraceValue( + self._results.current_page, trace_result, + file_path=self._results.telemetry_info.trace_local_path, + remote_path=self._results.telemetry_info.trace_remote_path, + upload_bucket=self._results.telemetry_info.upload_bucket, + cloud_url=self._results.telemetry_info.trace_remote_url) + + self._results.AddValue(trace_value)
diff --git a/tools/perf/measurements/smoothness_unittest.py b/tools/perf/measurements/smoothness_unittest.py index d19636de..6475ec2 100644 --- a/tools/perf/measurements/smoothness_unittest.py +++ b/tools/perf/measurements/smoothness_unittest.py
@@ -1,19 +1,13 @@ # 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. -import unittest - from telemetry import decorators -from telemetry.page import page from telemetry.testing import options_for_unittests from telemetry.testing import page_test_test_case from telemetry.util import wpr_modes -from telemetry.value import scalar from measurements import smoothness -import mock - class FakeTracingController(object): @@ -51,23 +45,6 @@ pass -class CustomResultsWrapperUnitTest(unittest.TestCase): - - def testOnlyOneInteractionRecordPerPage(self): - test_page = page.Page('http://dummy', None, name='http://dummy') - - # pylint: disable=protected-access - results_wrapper = smoothness._CustomResultsWrapper() - results_wrapper.SetResults(mock.Mock()) - - results_wrapper.SetTirLabel('foo') - results_wrapper.AddValue(scalar.ScalarValue(test_page, 'num', 'ms', 44)) - - results_wrapper.SetTirLabel('bar') - with self.assertRaises(AssertionError): - results_wrapper.AddValue(scalar.ScalarValue(test_page, 'num', 'ms', 42)) - - class SmoothnessUnitTest(page_test_test_case.PageTestTestCase): """Smoke test for smoothness measurement @@ -80,8 +57,8 @@ self._options = options_for_unittests.GetCopy() self._options.browser_options.wpr_mode = wpr_modes.WPR_OFF - # crbug.com/483212 - @decorators.Disabled('chromeos') + # crbug.com/483212 and crbug.com/713260 + @decorators.Disabled('chromeos', 'linux') def testSmoothness(self): ps = self.CreateStorySetFromFileInUnittestDataDir('scrollable_page.html') measurement = smoothness.Smoothness()
diff --git a/tools/perf/measurements/tab_switching.py b/tools/perf/measurements/tab_switching.py deleted file mode 100644 index 5b8868e..0000000 --- a/tools/perf/measurements/tab_switching.py +++ /dev/null
@@ -1,53 +0,0 @@ -# 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. - -"""The tab switching measurement. - -This measurement opens pages in different tabs. After all the tabs have opened, -it cycles through each tab in sequence, and records a histogram of the time -between when a tab was first requested to be shown, and when it was painted. -Power usage is also measured. -""" - -from telemetry.page import legacy_page_test -from telemetry.value import histogram -from telemetry.value import histogram_util - -from metrics import keychain_metric - - -class TabSwitching(legacy_page_test.LegacyPageTest): - def __init__(self): - super(TabSwitching, self).__init__() - self._first_histogram = None - - def CustomizeBrowserOptions(self, options): - keychain_metric.KeychainMetric.CustomizeBrowserOptions(options) - - options.AppendExtraBrowserArgs(['--enable-stats-collection-bindings']) - - @classmethod - def _GetTabSwitchHistogram(cls, tab_to_switch): - histogram_name = 'MPArch.RWH_TabSwitchPaintDuration' - histogram_type = histogram_util.BROWSER_HISTOGRAM - return histogram_util.GetHistogram( - histogram_type, histogram_name, tab_to_switch) - - def DidNavigateToPage(self, page, tab): - """record the starting histogram""" - self._first_histogram = self._GetTabSwitchHistogram(tab) - - def ValidateAndMeasurePage(self, page, tab, results): - """record the ending histogram for the tab switching metric.""" - last_histogram = self._GetTabSwitchHistogram(tab) - total_diff_histogram = histogram_util.SubtractHistogram(last_histogram, - self._first_histogram) - - display_name = 'MPArch_RWH_TabSwitchPaintDuration' - results.AddSummaryValue( - histogram.HistogramValue(None, display_name, 'ms', - raw_value_json=total_diff_histogram, - important=False)) - - keychain_metric.KeychainMetric().AddResults(tab, results)
diff --git a/tools/perf/measurements/tab_switching_unittest.py b/tools/perf/measurements/tab_switching_unittest.py deleted file mode 100644 index d882553b4..0000000 --- a/tools/perf/measurements/tab_switching_unittest.py +++ /dev/null
@@ -1,117 +0,0 @@ -# Copyright 2015 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 contextlib -from measurements import tab_switching -import mock -from page_sets.system_health import multi_tab_stories -from telemetry import decorators -from telemetry import story as story_module -from telemetry.internal.results import page_test_results -from telemetry.testing import page_test_test_case -from telemetry.testing import options_for_unittests -from telemetry.value import histogram - - -class BrowserForTest(object): - def __init__(self): - self.tabs = [] - self.platform = mock.MagicMock() - self.platform.CanMonitorPower = mock.Mock(return_value=False) - - def AddTab(self, tab): - tab.browser = self - self.tabs.append(tab) - - -class StorySetForTest(object): - def __init__(self): - self.stories = [] - - def AddStory(self, story): - story.story_set = self - self.stories.append(story) - -INTEGRATION_TEST_TAB_COUNT = 3 - -class EmptyMultiTabStory(multi_tab_stories.MultiTabStory): - NAME = 'multitab:test:empty' - URL_LIST = ['about:blank'] * INTEGRATION_TEST_TAB_COUNT - URL = URL_LIST[0] - -class TabSwitchingUnittest(page_test_test_case.PageTestTestCase): - @staticmethod - def MakeStoryForTest(): - story = mock.MagicMock() - story.story_set = None - return story - - @staticmethod - def MakeTabForTest(): - tab = mock.MagicMock() - tab.browser = None - tab.HasReachedQuiescence = mock.Mock(return_value=True) - return tab - - def testIsDone(self): - """Tests ValidateAndMeasurePage, specifically _IsDone check.""" - measure = tab_switching.TabSwitching() - - # For sanity check: #tabs == #stories - story_set = StorySetForTest() - story_set.AddStory(self.MakeStoryForTest()) - story_set.AddStory(self.MakeStoryForTest()) - - # Set up a browser with two tabs open - browser = BrowserForTest() - tab_0 = self.MakeTabForTest() - browser.AddTab(tab_0) - tab_1 = self.MakeTabForTest() - browser.AddTab(tab_1) - - # Mock histogram result to test _IsDone really works. - expected_histogram = [ - # DidNavigateToPage() calls GetHistogram() once - '{"count": 0, "buckets": []}', - # ValidateAndMeasurePage() calls GetHistogram() once - '{"count": 2, "buckets": [{"low": 1, "high": 2, "count": 1},' - '{"low": 2, "high": 3, "count": 1}]}', - ] - mock_get_histogram = mock.MagicMock(side_effect=expected_histogram) - - with contextlib.nested( - mock.patch('telemetry.value.histogram_util.GetHistogram', - mock_get_histogram), - mock.patch('metrics.keychain_metric.KeychainMetric')): - measure.DidNavigateToPage(story_set.stories[0], browser.tabs[-1]) - measure.ValidateAndMeasurePage(story_set.stories[0], browser.tabs[-1], - page_test_results.PageTestResults()) - self.assertEqual(len(expected_histogram), - len(mock_get_histogram.mock_calls)) - # The last tab is passed to DidNavigateToPage() and - # ValidateAndMeasurePage() - expected_calls = [mock.call(mock.ANY, mock.ANY, t) for t in - [browser.tabs[-1]] * 2] - self.assertEqual(expected_calls, mock_get_histogram.mock_calls) - - @decorators.Enabled('has tabs') - @decorators.Disabled('mac') - @decorators.Disabled('android') - def testTabSwitching(self): - """IT of TabSwitching measurement and multi-tab story""" - ps = story_module.StorySet() - ps.AddStory(EmptyMultiTabStory(ps, False)) - measurement = tab_switching.TabSwitching() - options = options_for_unittests.GetCopy() - results = self.RunMeasurement(measurement, ps, options=options) - self.assertEquals(len(results.failures), 0) - - self.assertEquals(len(results.all_summary_values), 1) - summary = results.all_summary_values[0] - self.assertIsInstance(summary, histogram.HistogramValue) - self.assertEquals(summary.name, 'MPArch_RWH_TabSwitchPaintDuration') - histogram_count = sum([b.count for b in summary.buckets]) - self.assertEquals(histogram_count, INTEGRATION_TEST_TAB_COUNT) - histogram_mean = summary.GetRepresentativeNumber() - self.assertGreater(histogram_mean, 0)
diff --git a/tools/perf/measurements/task_execution_time.py b/tools/perf/measurements/task_execution_time.py index 44e0ea3..b8a9fc4a 100644 --- a/tools/perf/measurements/task_execution_time.py +++ b/tools/perf/measurements/task_execution_time.py
@@ -53,7 +53,7 @@ def ValidateAndMeasurePage(self, page, tab, results): del page # unused - trace_data = tab.browser.platform.tracing_controller.StopTracing() + trace_data = tab.browser.platform.tracing_controller.StopTracing()[0] timeline_model = TimelineModel(trace_data) self._renderer_process = timeline_model.GetRendererProcessFromTabId(tab.id)
diff --git a/tools/perf/measurements/thread_times.py b/tools/perf/measurements/thread_times.py index f8c63df..dac37934 100644 --- a/tools/perf/measurements/thread_times.py +++ b/tools/perf/measurements/thread_times.py
@@ -4,7 +4,6 @@ from telemetry.page import legacy_page_test from telemetry.timeline import chrome_trace_category_filter -from telemetry.web_perf.metrics import layout from measurements import timeline_controller from metrics import timeline @@ -47,9 +46,6 @@ metric.details_to_report = timeline.ReportSilkDetails metric.AddResults(self._timeline_controller.model, renderer_thread, self._timeline_controller.smooth_records, results) - layout_metric = layout.LayoutMetric() - layout_metric.AddResults(self._timeline_controller.model, renderer_thread, - self._timeline_controller.smooth_records, results) def DidRunPage(self, platform): if self._timeline_controller:
diff --git a/tools/perf/measurements/timeline_controller.py b/tools/perf/measurements/timeline_controller.py index 14c850a..6b25d2340 100644 --- a/tools/perf/measurements/timeline_controller.py +++ b/tools/perf/measurements/timeline_controller.py
@@ -52,7 +52,7 @@ if self._enable_auto_issuing_record: self._interaction.End() # Stop tracing. - timeline_data = tab.browser.platform.tracing_controller.StopTracing() + timeline_data = tab.browser.platform.tracing_controller.StopTracing()[0] # TODO(#763375): Rely on results.telemetry_info.trace_local_path/etc. kwargs = {}
diff --git a/tools/perf/measurements/v8_detached_context_age_in_gc.py b/tools/perf/measurements/v8_detached_context_age_in_gc.py index 0a1f4a9..1fc443d1 100644 --- a/tools/perf/measurements/v8_detached_context_age_in_gc.py +++ b/tools/perf/measurements/v8_detached_context_age_in_gc.py
@@ -7,7 +7,6 @@ from telemetry.page import legacy_page_test from telemetry.value import histogram_util from telemetry.value import scalar -from telemetry.value import skip _NAME = 'V8.DetachedContextAgeInGC' _UNITS = 'garbage_collections' @@ -49,8 +48,7 @@ tab.CollectGarbage() value = _GetMaxDetachedContextAge(tab, self._data_start) if value is None: - results.AddValue(skip.SkipValue( - results.current_page, 'No detached contexts')) + results.Skip('No detached contexts') else: results.AddValue(scalar.ScalarValue( results.current_page, _DISPLAY_NAME, _UNITS, value,
diff --git a/tools/perf/measurements/v8_gc_times.py b/tools/perf/measurements/v8_gc_times.py index 19ddd37..3658eb2 100644 --- a/tools/perf/measurements/v8_gc_times.py +++ b/tools/perf/measurements/v8_gc_times.py
@@ -34,8 +34,9 @@ def ValidateAndMeasurePage(self, page, tab, results): del page # unused - trace_data = tab.browser.platform.tracing_controller.StopTracing() + trace_data = tab.browser.platform.tracing_controller.StopTracing()[0] timeline_model = TimelineModel(trace_data) + renderer_process = timeline_model.GetRendererProcessFromTabId(tab.id) self._AddV8MetricsToResults(renderer_process, results)
diff --git a/tools/perf/metrics/media.js b/tools/perf/metrics/media.js deleted file mode 100644 index b99b5b39..0000000 --- a/tools/perf/metrics/media.js +++ /dev/null
@@ -1,210 +0,0 @@ -// 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. - -// This file contains common utilities to find video/audio elements on a page -// and collect metrics for each. - -(function() { - // MediaMetric class responsible for collecting metrics on a media element. - // It attaches required event listeners in order to collect different metrics. - function MediaMetricBase(element) { - checkElementIsNotBound(element); - this.metrics = {}; - this.id = ''; - this.element = element; - } - - MediaMetricBase.prototype.getMetrics = function() { - return this.metrics; - }; - - MediaMetricBase.prototype.getSummary = function() { - return { - 'id': this.id, - 'metrics': this.getMetrics() - }; - }; - - function HTMLMediaMetric(element) { - MediaMetricBase.prototype.constructor.call(this, element); - // Set the basic event handlers for HTML5 media element. - var metric = this; - function onVideoLoad(event) { - // If a 'Play' action is performed, then playback_timer != undefined. - if (metric.playbackTimer == undefined) - metric.playbackTimer = new Timer(); - } - // For the cases where autoplay=true, and without a 'play' action, we want - // to start playbackTimer at 'play' or 'loadedmetadata' events. - this.element.addEventListener('play', onVideoLoad); - this.element.addEventListener('loadedmetadata', onVideoLoad); - this.element.addEventListener('playing', function(e) { - metric.onPlaying(e); - }); - this.element.addEventListener('ended', function(e) { - metric.onEnded(e); - }); - this.setID(); - - // Listen to when a Telemetry actions gets called. - this.element.addEventListener('willPlay', function (e) { - metric.onWillPlay(e); - }, false); - this.element.addEventListener('willSeek', function (e) { - metric.onWillSeek(e); - }, false); - this.element.addEventListener('willLoop', function (e) { - metric.onWillLoop(e); - }, false); - } - - HTMLMediaMetric.prototype = new MediaMetricBase(); - HTMLMediaMetric.prototype.constructor = HTMLMediaMetric; - - HTMLMediaMetric.prototype.setID = function() { - if (this.element.id) - this.id = this.element.id; - else if (this.element.src) - this.id = this.element.src.substring(this.element.src.lastIndexOf("/")+1); - else - this.id = 'media_' + window.__globalCounter++; - }; - - HTMLMediaMetric.prototype.onWillPlay = function(e) { - this.playbackTimer = new Timer(); - }; - - HTMLMediaMetric.prototype.onWillSeek = function(e) { - var seekLabel = ''; - if (e.seekLabel) - seekLabel = '_' + e.seekLabel; - var metric = this; - var onSeeked = function(e) { - metric.appendMetric('seek' + seekLabel, metric.seekTimer.stop()) - e.target.removeEventListener('seeked', onSeeked); - }; - this.seekTimer = new Timer(); - this.element.addEventListener('seeked', onSeeked); - }; - - HTMLMediaMetric.prototype.onWillLoop = function(e) { - var loopTimer = new Timer(); - var metric = this; - var loopCount = e.loopCount; - var onEndLoop = function(e) { - var actualDuration = loopTimer.stop(); - var idealDuration = metric.element.duration * loopCount; - var avg_loop_time = (actualDuration - idealDuration) / loopCount; - metric.metrics['avg_loop_time'] = - Math.round(avg_loop_time * 1000) / 1000; - e.target.removeEventListener('endLoop', onEndLoop); - }; - this.element.addEventListener('endLoop', onEndLoop); - }; - - HTMLMediaMetric.prototype.appendMetric = function(metric, value) { - if (!this.metrics[metric]) - this.metrics[metric] = []; - this.metrics[metric].push(value); - } - - HTMLMediaMetric.prototype.onPlaying = function(event) { - // Playing event can fire more than once if seeking. - if (!this.metrics['time_to_play'] && this.playbackTimer) - this.metrics['time_to_play'] = this.playbackTimer.stop(); - }; - - HTMLMediaMetric.prototype.onEnded = function(event) { - var time_to_end = this.playbackTimer.stop() - this.metrics['time_to_play']; - // TODO(shadi): Measure buffering time more accurately using events such as - // stalled, waiting, progress, etc. This works only when continuous playback - // is used. - this.metrics['buffering_time'] = time_to_end - this.element.duration * 1000; - }; - - HTMLMediaMetric.prototype.getMetrics = function() { - var decodedFrames = this.element.webkitDecodedFrameCount; - var droppedFrames = this.element.webkitDroppedFrameCount; - // Audio media does not report decoded/dropped frame count - if (decodedFrames != undefined) - this.metrics['decoded_frame_count'] = decodedFrames; - if (droppedFrames != undefined) - this.metrics['dropped_frame_count'] = droppedFrames; - this.metrics['decoded_video_bytes'] = - this.element.webkitVideoDecodedByteCount || 0; - this.metrics['decoded_audio_bytes'] = - this.element.webkitAudioDecodedByteCount || 0; - return this.metrics; - }; - - function MediaMetric(element) { - if (element instanceof HTMLMediaElement) - return new HTMLMediaMetric(element); - throw new Error('Unrecognized media element type.'); - } - - function Timer() { - this.start_ = 0; - this.start(); - } - - Timer.prototype = { - start: function() { - this.start_ = getCurrentTime(); - }, - - stop: function() { - // Return delta time since start in millisecs. - return Math.round((getCurrentTime() - this.start_) * 1000) / 1000; - } - }; - - function checkElementIsNotBound(element) { - if (!element) - return; - if (getMediaMetric(element)) - throw new Error('Can not create MediaMetric for same element twice.'); - } - - function getMediaMetric(element) { - for (var i = 0; i < window.__mediaMetrics.length; i++) { - if (window.__mediaMetrics[i].element == element) - return window.__mediaMetrics[i]; - } - return null; - } - - function createMediaMetricsForDocument() { - // Searches for all video and audio elements on the page and creates a - // corresponding media metric instance for each. - var mediaElements = document.querySelectorAll('video, audio'); - for (var i = 0; i < mediaElements.length; i++) - window.__mediaMetrics.push(new MediaMetric(mediaElements[i])); - } - - function getCurrentTime() { - if (window.performance) - return (performance.now || - performance.mozNow || - performance.msNow || - performance.oNow || - performance.webkitNow).call(window.performance); - else - return Date.now(); - } - - function getAllMetrics() { - // Returns a summary (info + metrics) for all media metrics. - var metrics = []; - for (var i = 0; i < window.__mediaMetrics.length; i++) - metrics.push(window.__mediaMetrics[i].getSummary()); - return metrics; - } - - window.__globalCounter = 0; - window.__mediaMetrics = []; - window.__getMediaMetric = getMediaMetric; - window.__getAllMetrics = getAllMetrics; - window.__createMediaMetricsForDocument = createMediaMetricsForDocument; -})();
diff --git a/tools/perf/metrics/media.py b/tools/perf/metrics/media.py deleted file mode 100644 index 78411351..0000000 --- a/tools/perf/metrics/media.py +++ /dev/null
@@ -1,98 +0,0 @@ -# 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. - -import logging -import os - -from telemetry.value import list_of_scalar_values -from telemetry.value import scalar - -from metrics import Metric - - -class MediaMetric(Metric): - """MediaMetric class injects and calls JS responsible for recording metrics. - - Default media metrics are collected for every media element in the page, - such as decoded_frame_count, dropped_frame_count, decoded_video_bytes, and - decoded_audio_bytes. - """ - - def __init__(self, tab): - super(MediaMetric, self).__init__() - with open(os.path.join(os.path.dirname(__file__), 'media.js')) as f: - js = f.read() - tab.ExecuteJavaScript(js) - self._results = None - self._skip_basic_metrics = False - - def Start(self, page, tab): - """Create the media metrics for all media elements in the document.""" - if hasattr(page, 'skip_basic_metrics'): - self._skip_basic_metrics = page.skip_basic_metrics - tab.ExecuteJavaScript('window.__createMediaMetricsForDocument()') - - def Stop(self, page, tab): - self._results = tab.EvaluateJavaScript('window.__getAllMetrics()') - - # Optional |exclude_metrics| args are not in base class Metric. - # pylint: disable=arguments-differ - def AddResults(self, tab, results, exclude_metrics=None): - """Reports all recorded metrics as Telemetry perf results.""" - exclude_metrics = exclude_metrics or [] - trace_names = [] - for media_metric in self._results: - trace_names.append(self._AddResultsForMediaElement(media_metric, results, - exclude_metrics)) - - return '_'.join(trace_names) or tab.url - - def _AddResultsForMediaElement(self, media_metric, results, exclude_metrics): - """Reports metrics for one media element. - - Media metrics contain an ID identifying the media element and values: - media_metric = { - 'id': 'video_1', - 'metrics': { - 'time_to_play': 120, - 'decoded_bytes': 13233, - ... - } - } - """ - def AddOneResult(metric, unit): - if metric in exclude_metrics: - return - - metrics = media_metric['metrics'] - for m in metrics: - if m.startswith(metric): - special_label = m[len(metric):] - trace_name = '%s.%s%s' % (metric, trace, special_label) - if isinstance(metrics[m], list): - results.AddValue(list_of_scalar_values.ListOfScalarValues( - results.current_page, trace_name, unit, - values=[float(v) for v in metrics[m]], - important=True)) - else: - results.AddValue(scalar.ScalarValue( - results.current_page, trace_name, unit, value=float(metrics[m]), - important=True)) - - trace = media_metric['id'] - if not trace: - logging.error('Metrics ID is missing in results.') - return - - if not self._skip_basic_metrics: - AddOneResult('buffering_time', 'ms') - AddOneResult('decoded_audio_bytes', 'bytes') - AddOneResult('decoded_video_bytes', 'bytes') - AddOneResult('decoded_frame_count', 'frames') - AddOneResult('dropped_frame_count', 'frames') - AddOneResult('time_to_play', 'ms') - - AddOneResult('avg_loop_time', 'ms') - AddOneResult('seek', 'ms') - return trace
diff --git a/tools/perf/metrics/memory.py b/tools/perf/metrics/memory.py deleted file mode 100644 index 62bb370..0000000 --- a/tools/perf/metrics/memory.py +++ /dev/null
@@ -1,248 +0,0 @@ -# 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. - -import logging -import sys - -from telemetry.value import histogram -from telemetry.value import histogram_util -from telemetry.value import scalar - -from metrics import Metric - - -_HISTOGRAMS = [ - { - 'name': 'V8.MemoryExternalFragmentationTotal', 'units': 'percent', - 'display_name': 'V8_MemoryExternalFragmentationTotal', - 'type': histogram_util.RENDERER_HISTOGRAM, - 'description': 'Total external memory fragmentation after each GC in ' - 'percent.', - }, - { - 'name': 'V8.MemoryHeapSampleTotalCommitted', 'units': 'kb', - 'display_name': 'V8_MemoryHeapSampleTotalCommitted', - 'type': histogram_util.RENDERER_HISTOGRAM, - 'description': 'The total size of committed memory used by V8 after ' - 'each GC in KB.' - }, - { - 'name': 'V8.MemoryHeapSampleTotalUsed', 'units': 'kb', - 'display_name': 'V8_MemoryHeapSampleTotalUsed', - 'type': histogram_util.RENDERER_HISTOGRAM, - 'description': 'The total size of live memory used by V8 after each ' - 'GC in KB.', - }, - { - 'name': 'V8.MemoryHeapSampleMaximumCommitted', 'units': 'kb', - 'display_name': 'V8_MemoryHeapSampleMaximumCommitted', - 'type': histogram_util.RENDERER_HISTOGRAM - }, - { - 'name': 'Memory.RendererUsed', 'units': 'kb', - 'display_name': 'Memory_RendererUsed', - 'type': histogram_util.RENDERER_HISTOGRAM - }, - { - 'name': 'Memory.BrowserUsed', 'units': 'kb', - 'display_name': 'Memory_BrowserUsed', - 'type': histogram_util.BROWSER_HISTOGRAM - }, -] - - -class MemoryMetric(Metric): - """MemoryMetric gathers memory statistics from the browser object. - - This includes both per-page histogram stats, most about javascript - memory usage, and overall memory stats from the system for the whole - test run.""" - - def __init__(self, browser): - super(MemoryMetric, self).__init__() - self._browser = browser - start_memory_stats = self._browser.memory_stats - self._start_commit_charge = None - if 'SystemCommitCharge' in start_memory_stats: - self._start_commit_charge = start_memory_stats['SystemCommitCharge'] - self._memory_stats = None - self._histogram_start = dict() - self._histogram_delta = dict() - self._started = False - - @classmethod - def CustomizeBrowserOptions(cls, options): - options.AppendExtraBrowserArgs([ - '--enable-stats-collection-bindings', - # For a hard-coded set of Google pages (such as GMail), we produce - # custom memory histograms (V8.Something_gmail) instead of the generic - # histograms (V8.Something), if we detect that a renderer is only - # rendering this page and no other pages. For this test, we need to - # disable histogram customizing, so that we get the same generic - # histograms produced for all pages. - '--disable-histogram-customizer' - ]) - - def Start(self, page, tab): - """Start the per-page preparation for this metric. - - Here, this consists of recording the start value of all the histograms. - """ - if not self._browser.supports_memory_metrics: - logging.warning('Memory metrics not supported.') - return - - self._started = True - - for h in _HISTOGRAMS: - histogram_data = histogram_util.GetHistogram( - h['type'], h['name'], tab) - # Histogram data may not be available - if not histogram_data: - continue - self._histogram_start[h['name']] = histogram_data - - def Stop(self, page, tab): - """Prepare the results for this page. - - The results are the differences between the current histogram values - and the values when Start() was called. - """ - if not self._browser.supports_memory_metrics: - return - - assert self._started, 'Must call Start() first' - for h in _HISTOGRAMS: - # Histogram data may not be available - if h['name'] not in self._histogram_start: - continue - histogram_data = histogram_util.GetHistogram( - h['type'], h['name'], tab) - self._histogram_delta[h['name']] = histogram_util.SubtractHistogram( - histogram_data, self._histogram_start[h['name']]) - - # Optional argument trace_name is not in base class Metric. - # pylint: disable=arguments-differ - def AddResults(self, tab, results, trace_name=None): - """Add results for this page to the results object.""" - if not self._browser.supports_memory_metrics: - return - - assert self._histogram_delta, 'Must call Stop() first' - for h in _HISTOGRAMS: - # Histogram data may not be available - if h['name'] not in self._histogram_start: - continue - results.AddValue(histogram.HistogramValue( - results.current_page, h['display_name'], h['units'], - raw_value_json=self._histogram_delta[h['name']], important=False, - description=h.get('description'))) - self._memory_stats = self._browser.memory_stats - if not self._memory_stats['Browser']: - return - AddResultsForProcesses(results, self._memory_stats, - metric_trace_name=trace_name) - - if self._start_commit_charge: - end_commit_charge = self._memory_stats['SystemCommitCharge'] - commit_charge_difference = end_commit_charge - self._start_commit_charge - results.AddValue(scalar.ScalarValue( - results.current_page, - 'commit_charge.' + (trace_name or 'commit_charge'), - 'kb', commit_charge_difference, important=False, - description='System commit charge (committed memory pages).')) - results.AddValue(scalar.ScalarValue( - results.current_page, 'processes.' + (trace_name or 'processes'), - 'count', self._memory_stats['ProcessCount'], important=False, - description='Number of processes used by Chrome.')) - - -def AddResultsForProcesses(results, memory_stats, chart_trace_name='final', - metric_trace_name=None, - exclude_metrics=None): - """Adds memory stats for browser, renderer and gpu processes. - - Args: - results: A telemetry.results.PageTestResults object. - memory_stats: System memory stats collected. - chart_trace_name: Trace to identify memory metrics. Default is 'final'. - metric_trace_name: Trace to identify the metric results per test page. - exclude_metrics: List of memory metrics to exclude from results, - e.g. VM, WorkingSetSize, etc. - """ - metric = 'resident_set_size' - if sys.platform == 'win32': - metric = 'working_set' - - exclude_metrics = exclude_metrics or {} - - def AddResultsForProcessTypes(process_types_memory, process_type_trace): - """Add all results for a given set of process types. - - Args: - process_types_memory: A list of process types, e.g. Browser, 'Renderer'. - process_type_trace: The name of this set of process types in the output. - """ - def AddResult(value_name_memory, value_name_trace, description): - """Add a result for a given statistic. - - Args: - value_name_memory: Name of some statistic, e.g. VM, WorkingSetSize. - value_name_trace: Name of this statistic to be used in the output. - """ - if value_name_memory in exclude_metrics: - return - if len(process_types_memory) > 1 and value_name_memory.endswith('Peak'): - return - values = [] - for process_type_memory in process_types_memory: - stats = memory_stats[process_type_memory] - if value_name_memory in stats: - values.append(stats[value_name_memory]) - if values: - if metric_trace_name: - current_trace = '%s_%s' % (metric_trace_name, process_type_trace) - chart_name = value_name_trace - else: - current_trace = '%s_%s' % (value_name_trace, process_type_trace) - chart_name = current_trace - results.AddValue(scalar.ScalarValue( - results.current_page, '%s.%s' % (chart_name, current_trace), 'kb', - sum(values) / 1024, important=False, description=description)) - - AddResult('VM', 'vm_%s_size' % chart_trace_name, - 'Virtual Memory Size (address space allocated).') - AddResult('WorkingSetSize', 'vm_%s_%s_size' % (metric, chart_trace_name), - 'Working Set Size (Windows) or Resident Set Size (other ' - 'platforms).') - AddResult('PrivateDirty', 'vm_private_dirty_%s' % chart_trace_name, - 'Private Dirty is basically the amount of RAM inside the ' - 'process that can not be paged to disk (it is not backed by the ' - 'same data on disk), and is not shared with any other ' - 'processes. Another way to look at this is the RAM that will ' - 'become available to the system when that process goes away ' - '(and probably quickly subsumed into caches and other uses of ' - 'it).') - AddResult('ProportionalSetSize', - 'vm_proportional_set_size_%s' % chart_trace_name, - 'The Proportional Set Size (PSS) number is a metric the kernel ' - 'computes that takes into account memory sharing -- basically ' - 'each page of RAM in a process is scaled by a ratio of the ' - 'number of other processes also using that page. This way you ' - 'can (in theory) add up the PSS across all processes to see ' - 'the total RAM they are using, and compare PSS between ' - 'processes to get a rough idea of their relative weight.') - AddResult('SharedDirty', 'vm_shared_dirty_%s' % chart_trace_name, - 'Shared Dirty is the amount of RAM outside the process that can ' - 'not be paged to disk, and is shared with other processes.') - AddResult('VMPeak', 'vm_peak_size', - 'The peak Virtual Memory Size (address space allocated) usage ' - 'achieved by the * process.') - AddResult('WorkingSetSizePeak', '%s_peak_size' % metric, - 'Peak Working Set Size.') - - AddResultsForProcessTypes(['Browser'], 'browser') - AddResultsForProcessTypes(['Renderer'], 'renderer') - AddResultsForProcessTypes(['Gpu'], 'gpu') - AddResultsForProcessTypes(['Browser', 'Renderer', 'Gpu'], 'total')
diff --git a/tools/perf/metrics/power.py b/tools/perf/metrics/power.py index 09fe49f..d9b4155f 100644 --- a/tools/perf/metrics/power.py +++ b/tools/perf/metrics/power.py
@@ -11,7 +11,6 @@ from metrics import Metric -MONSOON_POWER_LABEL = 'monsoon_energy_consumption_mwh' FUELGAUGE_POWER_LABEL = 'fuel_gauge_energy_consumption_mwh' APP_POWER_LABEL = 'application_energy_consumption_mwh' TOTAL_POWER_LABEL = 'energy_consumption_mwh' @@ -122,7 +121,6 @@ total_energy_consumption_mwh = self._results.get(TOTAL_POWER_LABEL) fuel_gauge_energy_consumption_mwh = self._results.get( FUELGAUGE_POWER_LABEL) - monsoon_energy_consumption_mwh = self._results.get(MONSOON_POWER_LABEL) if (PowerMetric._quiescent_power_draw_mwh and application_energy_consumption_mwh is None and @@ -136,11 +134,6 @@ results.current_page, FUELGAUGE_POWER_LABEL, 'mWh', fuel_gauge_energy_consumption_mwh)) - if monsoon_energy_consumption_mwh is not None: - results.AddValue(scalar.ScalarValue( - results.current_page, MONSOON_POWER_LABEL, 'mWh', - monsoon_energy_consumption_mwh)) - if total_energy_consumption_mwh is not None: results.AddValue(scalar.ScalarValue( results.current_page, TOTAL_POWER_LABEL, 'mWh',
diff --git a/tools/perf/metrics/speedindex.py b/tools/perf/metrics/speedindex.py deleted file mode 100644 index 41a1f4ce..0000000 --- a/tools/perf/metrics/speedindex.py +++ /dev/null
@@ -1,191 +0,0 @@ -# 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. - -from telemetry.util import image_util -from telemetry.util import rgba_color -from telemetry.value import scalar - -from metrics import Metric - - -class SpeedIndexMetric(Metric): - """The speed index metric is one way of measuring page load speed. - - It is meant to approximate user perception of page load speed, and it - is based on the amount of time that it takes to paint to the visual - portion of the screen. It includes paint events that occur after the - onload event, and it doesn't include time loading things off-screen. - - This speed index metric is based on WebPageTest.org (WPT). - For more info see: http://goo.gl/e7AH5l - """ - - def __init__(self): - super(SpeedIndexMetric, self).__init__() - self._impl = None - - @classmethod - def CustomizeBrowserOptions(cls, options): - options.AppendExtraBrowserArgs('--disable-infobars') - - def Start(self, _, tab): - """Start recording events. - - This method should be called in the WillNavigateToPage method of - a PageTest, so that all the events can be captured. If it's called - in DidNavigateToPage, that will be too late. - """ - if not tab.video_capture_supported: - return - self._impl = VideoSpeedIndexImpl() - self._impl.Start(tab) - - def Stop(self, _, tab): - """Stop recording.""" - if not tab.video_capture_supported: - return - assert self._impl, 'Must call Start() before Stop()' - assert self.IsFinished(tab), 'Must wait for IsFinished() before Stop()' - self._impl.Stop(tab) - - # Optional argument chart_name is not in base class Metric. - # pylint: disable=arguments-differ - def AddResults(self, tab, results, chart_name=None): - """Calculate the speed index and add it to the results.""" - try: - if tab.video_capture_supported: - index = self._impl.CalculateSpeedIndex(tab) - none_value_reason = None - else: - index = None - none_value_reason = 'Video capture is not supported.' - finally: - self._impl = None # Release the tab so that it can be disconnected. - - results.AddValue(scalar.ScalarValue( - results.current_page, '%s_speed_index' % chart_name, 'ms', index, - description='Speed Index. This focuses on time when visible parts of ' - 'page are displayed and shows the time when the ' - 'first look is "almost" composed. If the contents of the ' - 'testing page are composed by only static resources, load ' - 'time can measure more accurately and speed index will be ' - 'smaller than the load time. On the other hand, If the ' - 'contents are composed by many XHR requests with small ' - 'main resource and javascript, speed index will be able to ' - 'get the features of performance more accurately than load ' - 'time because the load time will measure the time when ' - 'static resources are loaded. If you want to get more ' - 'detail, please refer to http://goo.gl/Rw3d5d. Currently ' - 'there are two implementations: for Android and for ' - 'Desktop. The Android version uses video capture; the ' - 'Desktop one uses paint events and has extra overhead to ' - 'catch paint events.', none_value_reason=none_value_reason)) - - def IsFinished(self, tab): - """Decide whether the recording should be stopped. - - A page may repeatedly request resources in an infinite loop; a timeout - should be placed in any measurement that uses this metric, e.g.: - def IsDone(): - return self._speedindex.IsFinished(tab) - util.WaitFor(IsDone, 60) - - Returns: - True if 2 seconds have passed since last resource received, false - otherwise. - """ - return tab.HasReachedQuiescence() - - -class SpeedIndexImpl(object): - - def Start(self, tab): - raise NotImplementedError() - - def Stop(self, tab): - raise NotImplementedError() - - def GetTimeCompletenessList(self, tab): - """Returns a list of time to visual completeness tuples. - - In the WPT PHP implementation, this is also called 'visual progress'. - """ - raise NotImplementedError() - - def CalculateSpeedIndex(self, tab): - """Calculate the speed index. - - The speed index number conceptually represents the number of milliseconds - that the page was "visually incomplete". If the page were 0% complete for - 1000 ms, then the score would be 1000; if it were 0% complete for 100 ms - then 90% complete (ie 10% incomplete) for 900 ms, then the score would be - 1.0*100 + 0.1*900 = 190. - - Returns: - A single number, milliseconds of visual incompleteness. - """ - time_completeness_list = self.GetTimeCompletenessList(tab) - prev_completeness = 0.0 - speed_index = 0.0 - prev_time = time_completeness_list[0][0] - for time, completeness in time_completeness_list: - # Add the incremental value for the interval just before this event. - elapsed_time = time - prev_time - incompleteness = (1.0 - prev_completeness) - speed_index += elapsed_time * incompleteness - - # Update variables for next iteration. - prev_completeness = completeness - prev_time = time - return int(speed_index) - - -class VideoSpeedIndexImpl(SpeedIndexImpl): - - def __init__(self, image_util_module=image_util): - # Allow image_util to be passed in so we can fake it out for testing. - super(VideoSpeedIndexImpl, self).__init__() - self._time_completeness_list = None - self._image_util_module = image_util_module - - def Start(self, tab): - assert tab.video_capture_supported - # Blank out the current page so it doesn't count towards the new page's - # completeness. - tab.Highlight(rgba_color.WHITE) - # TODO(tonyg): Bitrate is arbitrary here. Experiment with screen capture - # overhead vs. speed index accuracy and set the bitrate appropriately. - tab.StartVideoCapture(min_bitrate_mbps=4) - - def Stop(self, tab): - # Ignore white because Chrome may blank out the page during load and we want - # that to count as 0% complete. Relying on this fact, we also blank out the - # previous page to white. The tolerance of 8 experimentally does well with - # video capture at 4mbps. We should keep this as low as possible with - # supported video compression settings. - video_capture = tab.StopVideoCapture() - histograms = [ - (time, self._image_util_module.GetColorHistogram( - image, ignore_color=rgba_color.WHITE, tolerance=8)) - for time, image in video_capture.GetVideoFrameIter() - ] - - start_histogram = histograms[0][1] - final_histogram = histograms[-1][1] - total_distance = start_histogram.Distance(final_histogram) - - def FrameProgress(histogram): - if total_distance == 0: - if histogram.Distance(final_histogram) == 0: - return 1.0 - else: - return 0.0 - return 1 - histogram.Distance(final_histogram) / total_distance - - self._time_completeness_list = [(time, FrameProgress(hist)) - for time, hist in histograms] - - def GetTimeCompletenessList(self, tab): - assert self._time_completeness_list, 'Must call Stop() first.' - return self._time_completeness_list
diff --git a/tools/perf/metrics/speedindex_unittest.py b/tools/perf/metrics/speedindex_unittest.py deleted file mode 100644 index 2bcc5a0..0000000 --- a/tools/perf/metrics/speedindex_unittest.py +++ /dev/null
@@ -1,125 +0,0 @@ -# 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. - -# These tests access private methods in the speedindex module. -# pylint: disable=protected-access - -import unittest - -from telemetry.util import color_histogram -from telemetry.util import rgba_color - -from metrics import speedindex - - -class FakeImageUtil(object): - - # pylint: disable=unused-argument - def GetColorHistogram(self, image, ignore_color=None, tolerance=None): - return image.ColorHistogram() - - -class FakeVideo(object): - - def __init__(self, frames): - self._frames = frames - - def GetVideoFrameIter(self): - for frame in self._frames: - yield frame - - -class FakeBitmap(object): - - def __init__(self, r, g, b): - self._histogram = color_histogram.ColorHistogram(r, g, b, rgba_color.WHITE) - - # pylint: disable=unused-argument - def ColorHistogram(self, ignore_color=None, tolerance=None): - return self._histogram - - -class FakeTab(object): - - def __init__(self, video_capture_result=None): - self._javascript_result = None - self._video_capture_result = FakeVideo(video_capture_result) - - @property - def video_capture_supported(self): - return self._video_capture_result is not None - - def SetEvaluateJavaScriptResult(self, result): - self._javascript_result = result - - def EvaluateJavaScript(self, _): - return self._javascript_result - - def StartVideoCapture(self, min_bitrate_mbps=1): - assert self.video_capture_supported - assert min_bitrate_mbps > 0 - - def StopVideoCapture(self): - assert self.video_capture_supported - return self._video_capture_result - - def Highlight(self, _): - pass - - -class SpeedIndexImplTest(unittest.TestCase): - - def testVideoCompleteness(self): - frames = [ - (0.0, FakeBitmap([0, 0, 0, 10], [0, 0, 0, 10], [0, 0, 0, 10])), - (0.1, FakeBitmap([10, 0, 0, 0], [10, 0, 0, 0], [10, 0, 0, 0])), - (0.2, FakeBitmap([0, 0, 2, 8], [0, 0, 4, 6], [0, 0, 1, 9])), - (0.3, FakeBitmap([0, 3, 2, 5], [2, 1, 0, 7], [0, 3, 0, 7])), - (0.4, FakeBitmap([0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0])), - (0.5, FakeBitmap([0, 4, 6, 0], [0, 4, 6, 0], [0, 4, 6, 0])), - ] - max_distance = 42. - - tab = FakeTab(frames) - impl = speedindex.VideoSpeedIndexImpl(FakeImageUtil()) - impl.Start(tab) - impl.Stop(tab) - time_completeness = impl.GetTimeCompletenessList(tab) - self.assertEqual(len(time_completeness), 6) - self.assertEqual(time_completeness[0], (0.0, 0)) - self.assertTimeCompleteness( - time_completeness[1], 0.1, 1 - (16 + 16 + 16) / max_distance) - self.assertTimeCompleteness( - time_completeness[2], 0.2, 1 - (12 + 10 + 13) / max_distance) - self.assertTimeCompleteness( - time_completeness[3], 0.3, 1 - (6 + 10 + 8) / max_distance) - self.assertTimeCompleteness( - time_completeness[4], 0.4, 1 - (4 + 4 + 4) / max_distance) - self.assertEqual(time_completeness[5], (0.5, 1)) - - def testBlankPage(self): - frames = [ - (0.0, FakeBitmap([0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 0, 1])), - (0.1, FakeBitmap([0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 0, 1])), - (0.2, FakeBitmap([1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 0, 1])), - (0.3, FakeBitmap([0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 0, 1])), - ] - tab = FakeTab(frames) - impl = speedindex.VideoSpeedIndexImpl(FakeImageUtil()) - impl.Start(tab) - impl.Stop(tab) - time_completeness = impl.GetTimeCompletenessList(tab) - self.assertEqual(len(time_completeness), 4) - self.assertEqual(time_completeness[0], (0.0, 1.0)) - self.assertEqual(time_completeness[1], (0.1, 1.0)) - self.assertEqual(time_completeness[2], (0.2, 0.0)) - self.assertEqual(time_completeness[3], (0.3, 1.0)) - - def assertTimeCompleteness(self, time_completeness, time, completeness): - self.assertEqual(time_completeness[0], time) - self.assertAlmostEqual(time_completeness[1], completeness) - - -if __name__ == "__main__": - unittest.main()
diff --git a/tools/perf/metrics/system_memory.py b/tools/perf/metrics/system_memory.py deleted file mode 100644 index 4637705..0000000 --- a/tools/perf/metrics/system_memory.py +++ /dev/null
@@ -1,126 +0,0 @@ -# Copyright 2014 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. - -from telemetry.value import scalar - -from metrics import memory -from metrics import Metric - - -class SystemMemoryMetric(Metric): - """SystemMemoryMetric gathers system memory statistic. - - This metric collects system memory stats per test. It reports the difference - (delta) in system memory starts from the start of the test to the end of it. - """ - - def __init__(self, browser): - super(SystemMemoryMetric, self).__init__() - self._browser = browser - self._memory_stats_start = None - self._memory_stats_end = None - - def Start(self, page, tab): - """Start the per-page preparation for this metric. - - Records the system memory stats at this point. - """ - self._memory_stats_start = self._browser.memory_stats - - def Stop(self, page, tab): - """Prepare the results for this page. - - The results are the differences between the current system memory stats - and the values when Start() was called. - """ - assert self._memory_stats_start, 'Must call Start() first' - self._memory_stats_end = self._browser.memory_stats - - # |trace_name| and |exclude_metrics| args are not in base class Metric. - # pylint: disable=arguments-differ - def AddResults(self, tab, results, trace_name=None, exclude_metrics=None): - """Add results for this page to the results object. - - Reports the delta in memory stats between the start stats and the end stats - (as *_delta metrics). It reports end memory stats in case no matching start - memory stats exists. - - Args: - trace_name: Trace name to identify the summary results for current page. - exclude_metrics: List of memory metrics to exclude from results, - e.g. VM, VMPeak, etc. See AddResultsForProcesses(). - """ - assert self._memory_stats_end, 'Must call Stop() first' - memory_stats = _SubtractMemoryStats(self._memory_stats_end, - self._memory_stats_start) - if not memory_stats['Browser']: - return - exclude_metrics = exclude_metrics or {} - memory.AddResultsForProcesses( - results, memory_stats, - metric_trace_name=trace_name, chart_trace_name='delta', - exclude_metrics=exclude_metrics) - - if 'SystemCommitCharge' not in exclude_metrics: - results.AddValue(scalar.ScalarValue( - results.current_page, - 'commit_charge_delta.%s' % (trace_name or 'commit_charge'), 'kb', - memory_stats['SystemCommitCharge'], important=False)) - - if 'ProcessCount' not in exclude_metrics: - results.AddValue(scalar.ScalarValue( - results.current_page, - 'processes_delta.%s' % (trace_name or 'processes'), 'count', - memory_stats['ProcessCount'], important=False)) - - -def _SubtractMemoryStats(end_memory_stats, start_memory_stats): - """Computes the difference in memory usage stats. - - Each of the two stats arguments is a dict with the following format: - {'Browser': {metric: value, ...}, - 'Renderer': {metric: value, ...}, - 'Gpu': {metric: value, ...}, - 'ProcessCount': value, - etc - } - The metrics can be VM, WorkingSetSize, ProportionalSetSize, etc depending on - the platform/test. - - NOTE: The only metrics that are not subtracted from original are the *Peak* - memory values. - - Returns: - A dict of process type names (Browser, Renderer, etc.) to memory usage - metrics between the end collected stats and the start collected stats. - """ - memory_stats = {} - end_memory_stats = end_memory_stats or {} - start_memory_stats = start_memory_stats or {} - - for process_type in end_memory_stats: - memory_stats[process_type] = {} - end_process_memory = end_memory_stats[process_type] - if not end_process_memory: - continue - - # If a process has end stats without start stats then report the end stats. - # For example, a GPU process that started just after media playback. - if (process_type not in start_memory_stats or - not start_memory_stats[process_type]): - memory_stats[process_type] = end_process_memory - continue - - if not isinstance(end_process_memory, dict): - start_value = start_memory_stats[process_type] or 0 - memory_stats[process_type] = end_process_memory - start_value - else: - for metric in end_process_memory: - end_value = end_process_memory[metric] - start_value = start_memory_stats[process_type].get(metric, 0) - if 'Peak' in metric: - memory_stats[process_type][metric] = end_value - else: - memory_stats[process_type][metric] = end_value - start_value - return memory_stats
diff --git a/tools/perf/metrics/timeline.py b/tools/perf/metrics/timeline.py index f5032d8..4d39da54 100644 --- a/tools/perf/metrics/timeline.py +++ b/tools/perf/metrics/timeline.py
@@ -8,65 +8,6 @@ from telemetry.web_perf.metrics import timeline_based_metric -class LoadTimesTimelineMetric(timeline_based_metric.TimelineBasedMetric): - - def __init__(self): - super(LoadTimesTimelineMetric, self).__init__() - self.report_main_thread_only = True - - def AddResults(self, model, renderer_thread, interaction_records, results): - assert model - assert len(interaction_records) == 1, ( - "LoadTimesTimelineMetric cannot compute metrics for more than 1 time " - "range.") - interaction_record = interaction_records[0] - if self.report_main_thread_only: - thread_filter = "CrRendererMain" - else: - thread_filter = None - - events_by_name = collections.defaultdict(list) - renderer_process = renderer_thread.parent - - for thread in renderer_process.threads.itervalues(): - - if thread_filter and not thread.name in thread_filter: - continue - - thread_name = thread.name.replace("/", "_") - for e in thread.IterAllSlicesInRange(interaction_record.start, - interaction_record.end): - events_by_name[e.name].append(e) - - for event_name, event_group in events_by_name.iteritems(): - times = [event.self_time for event in event_group] - total = sum(times) - biggest_jank = max(times) - - # Results objects cannot contain the '.' character, so remove that - # here. - sanitized_event_name = event_name.replace(".", "_") - - full_name = thread_name + "|" + sanitized_event_name - results.AddValue(scalar.ScalarValue( - results.current_page, full_name, "ms", total)) - results.AddValue(scalar.ScalarValue( - results.current_page, full_name + "_max", "ms", biggest_jank)) - results.AddValue(scalar.ScalarValue( - results.current_page, full_name + "_avg", "ms", total / len(times))) - - for counter_name, counter in renderer_process.counters.iteritems(): - total = sum(counter.totals) - - # Results objects cannot contain the '.' character, so remove that here. - sanitized_counter_name = counter_name.replace(".", "_") - - results.AddValue(scalar.ScalarValue( - results.current_page, sanitized_counter_name, "count", total)) - results.AddValue(scalar.ScalarValue( - results.current_page, sanitized_counter_name + "_avg", "count", - total / float(len(counter.totals)))) - # We want to generate a consistent picture of our thread usage, despite # having several process configurations (in-proc-gpu/single-proc). # Since we can't isolate renderer threads in single-process mode, we
diff --git a/tools/perf/metrics/timeline_unittest.py b/tools/perf/metrics/timeline_unittest.py index b4547b4..7a12872 100644 --- a/tools/perf/metrics/timeline_unittest.py +++ b/tools/perf/metrics/timeline_unittest.py
@@ -15,81 +15,6 @@ return tir_module.TimelineInteractionRecord('test-record', start, end) -class LoadTimesTimelineMetric(unittest.TestCase): - - def GetResults(self, metric, model, renderer_thread, interaction_records): - results = test_page_test_results.TestPageTestResults(self) - metric.AddResults(model, renderer_thread, interaction_records, results) - return results - - def testSanitizing(self): - model = model_module.TimelineModel() - renderer_main = model.GetOrCreateProcess(1).GetOrCreateThread(2) - renderer_main.name = 'CrRendererMain' - - # [ X ] - # [ Y ] - renderer_main.BeginSlice('cat1', 'x.y', 10, 0) - renderer_main.EndSlice(20, 20) - model.FinalizeImport() - - metric = timeline.LoadTimesTimelineMetric() - results = self.GetResults( - metric, model=model, renderer_thread=renderer_main, - interaction_records=[_GetInteractionRecord(0, float('inf'))]) - results.AssertHasPageSpecificScalarValue( - 'CrRendererMain|x_y', 'ms', 10) - results.AssertHasPageSpecificScalarValue( - 'CrRendererMain|x_y_max', 'ms', 10) - results.AssertHasPageSpecificScalarValue( - 'CrRendererMain|x_y_avg', 'ms', 10) - - def testTimelineBetweenRange(self): - model = model_module.TimelineModel() - renderer_main = model.GetOrCreateProcess(1).GetOrCreateThread(2) - renderer_main.name = 'CrRendererMain' - - # [ X ] [ Z ] - # [ Y ] [ T ] - # [ interaction record ] - renderer_main.BeginSlice('cat1', 'x.y', 10, 0) - renderer_main.EndSlice(20, 20) - renderer_main.BeginSlice('cat1', 'z.t', 30, 0) - renderer_main.EndSlice(35, 35) - model.FinalizeImport() - - metric = timeline.LoadTimesTimelineMetric() - results = self.GetResults( - metric, model=model, renderer_thread=renderer_main, - interaction_records=[_GetInteractionRecord(10, 20)]) - results.AssertHasPageSpecificScalarValue( - 'CrRendererMain|x_y', 'ms', 10) - results.AssertHasPageSpecificScalarValue( - 'CrRendererMain|x_y_max', 'ms', 10) - results.AssertHasPageSpecificScalarValue( - 'CrRendererMain|x_y_avg', 'ms', 10) - - def testCounterSanitizing(self): - model = model_module.TimelineModel() - renderer_main = model.GetOrCreateProcess(1).GetOrCreateThread(2) - renderer_main.name = 'CrRendererMain' - - x_counter = renderer_main.parent.GetOrCreateCounter('cat', 'x.y') - x_counter.samples += [1, 2] - x_counter.series_names += ['a'] - x_counter.timestamps += [0, 1] - model.FinalizeImport() - - metric = timeline.LoadTimesTimelineMetric() - results = self.GetResults( - metric, model=model, renderer_thread=renderer_main, - interaction_records=[_GetInteractionRecord(0, float('inf'))]) - results.AssertHasPageSpecificScalarValue( - 'cat_x_y', 'count', 3) - results.AssertHasPageSpecificScalarValue( - 'cat_x_y_avg', 'count', 1.5) - - class ThreadTimesTimelineMetricUnittest(unittest.TestCase): def GetResults(self, metric, model, renderer_thread, interaction_record):
diff --git a/tools/perf/page_sets/.gitignore b/tools/perf/page_sets/.gitignore index 5dfac26..a8d6d198 100644 --- a/tools/perf/page_sets/.gitignore +++ b/tools/perf/page_sets/.gitignore
@@ -11,3 +11,7 @@ *.webm *.wpr *.wprgo + +# Generated fetched binary's timestamp +# See details in py_utils.cloud_storage.GetIfChanged(file_path, bucket) method. +*.fetchts
diff --git a/tools/perf/page_sets/android_screen_restoration_shared_state.py b/tools/perf/page_sets/android_screen_restoration_shared_state.py index 8b073c5..ae39bba 100644 --- a/tools/perf/page_sets/android_screen_restoration_shared_state.py +++ b/tools/perf/page_sets/android_screen_restoration_shared_state.py
@@ -1,7 +1,6 @@ # Copyright 2015 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 from telemetry.page import shared_page_state @@ -19,11 +18,5 @@ finally: self._EnsureScreenOn() - def CanRunOnBrowser(self, browser_info, _): - if not browser_info.browser_type.startswith('android'): - logging.warning('Browser is non-Android, skipping test') - return False - return True - def _EnsureScreenOn(self): self.platform.android_action_runner.TurnScreenOn()
diff --git a/tools/perf/page_sets/cros_ui_cases.py b/tools/perf/page_sets/cros_ui_cases.py new file mode 100644 index 0000000..a2fc948 --- /dev/null +++ b/tools/perf/page_sets/cros_ui_cases.py
@@ -0,0 +1,61 @@ +# Copyright 2018 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. +from telemetry.page import page as page_module +from telemetry.page import shared_page_state +from telemetry import story + +class _SharedPageState(shared_page_state.SharedDesktopPageState): + + def CanRunOnBrowser(self, browser_info, page): + if not hasattr(page, 'CanRunOnBrowser'): + return True + return page.CanRunOnBrowser(browser_info.browser) + + +class DesktopUIPage(page_module.Page): + + def __init__(self, url, page_set, name): + super(DesktopUIPage, self).__init__( + url=url, + page_set=page_set, + name=name, + shared_page_state_class=_SharedPageState, + extra_browser_args=['--always-request-presentation-time']) + + +class OverviewMode(DesktopUIPage): + + def CanRunOnBrowser(self, browser): + return browser.supports_overview_mode + + def RunPageInteractions(self, action_runner): + action_runner.Wait(1) + # TODO(chiniforooshan): CreateInteraction creates an async event in the + # renderer, which works fine; it is nicer if we create UI interaction + # records in the browser process. + with action_runner.CreateInteraction('ui_EnterOverviewAction'): + action_runner.EnterOverviewMode() + # TODO(chiniforooshan): The follwoing wait, and the one after + # ExitOverviewMode(), is a workaround for crbug.com/788454. Remove when + # the bug is fixed. + action_runner.Wait(1) + action_runner.Wait(0.5) + with action_runner.CreateInteraction('ui_ExitOverviewAction'): + action_runner.ExitOverviewMode() + action_runner.Wait(1) + + +class CrosUiCasesPageSet(story.StorySet): + """Pages that test desktop UI performance.""" + + def __init__(self): + super(CrosUiCasesPageSet, self).__init__( + archive_data_file='data/cros_ui_cases.json', + cloud_storage_bucket=story.PARTNER_BUCKET) + + self.AddStory(OverviewMode( + 'http://news.yahoo.com', self, 'overview:yahoo_news')) + self.AddStory(OverviewMode( + 'http://jsbin.com/giqafofe/1/quiet?JS_POSTER_CIRCLE', self, + 'overview:js_poster_circle'))
diff --git a/tools/perf/page_sets/data/cros_ui_cases.json b/tools/perf/page_sets/data/cros_ui_cases.json new file mode 100644 index 0000000..ed41de5 --- /dev/null +++ b/tools/perf/page_sets/data/cros_ui_cases.json
@@ -0,0 +1,12 @@ +{ + "archives": { + "overview:js_poster_circle": { + "DEFAULT": "cros_ui_cases_000.wprgo" + }, + "overview:yahoo_news": { + "DEFAULT": "cros_ui_cases_000.wprgo" + } + }, + "description": "Describes the Web Page Replay archives for a story set. Don't edit by hand! Use record_wpr for updating.", + "platform_specific": true +}
diff --git a/tools/perf/page_sets/data/cros_ui_cases_000.wprgo.sha1 b/tools/perf/page_sets/data/cros_ui_cases_000.wprgo.sha1 new file mode 100644 index 0000000..55ea51e3 --- /dev/null +++ b/tools/perf/page_sets/data/cros_ui_cases_000.wprgo.sha1
@@ -0,0 +1 @@ +ea990882aea7b63d9c22c4c079a5756164bd69ff \ No newline at end of file
diff --git a/tools/perf/page_sets/data/dromaeo.json b/tools/perf/page_sets/data/dromaeo.json new file mode 100644 index 0000000..7a6b2e9 --- /dev/null +++ b/tools/perf/page_sets/data/dromaeo.json
@@ -0,0 +1,18 @@ +{ + "archives": { + "http://dromaeo.com?dom-attr": { + "DEFAULT": "dromaeo_000.wprgo" + }, + "http://dromaeo.com?dom-modify": { + "DEFAULT": "dromaeo_000.wprgo" + }, + "http://dromaeo.com?dom-query": { + "DEFAULT": "dromaeo_000.wprgo" + }, + "http://dromaeo.com?dom-traverse": { + "DEFAULT": "dromaeo_000.wprgo" + } + }, + "description": "Describes the Web Page Replay archives for a story set. Don't edit by hand! Use record_wpr for updating.", + "platform_specific": true +} \ No newline at end of file
diff --git a/tools/perf/page_sets/data/dromaeo_000.wprgo.sha1 b/tools/perf/page_sets/data/dromaeo_000.wprgo.sha1 new file mode 100644 index 0000000..4525f7d --- /dev/null +++ b/tools/perf/page_sets/data/dromaeo_000.wprgo.sha1
@@ -0,0 +1 @@ +286e419e1102290adfbc3c2efa4a2334de2c3870 \ No newline at end of file
diff --git a/tools/perf/page_sets/data/key_desktop_move_cases.json b/tools/perf/page_sets/data/key_desktop_move_cases.json index 40eafb5..ad5c0328 100644 --- a/tools/perf/page_sets/data/key_desktop_move_cases.json +++ b/tools/perf/page_sets/data/key_desktop_move_cases.json
@@ -1,10 +1,10 @@ { "archives": { "Maps": { - "DEFAULT": "key_desktop_move_cases_000.wpr" + "DEFAULT": "key_desktop_move_cases_000.wprgo" }, "https://mail.google.com/mail/": { - "DEFAULT": "key_desktop_move_cases_002.wpr" + "DEFAULT": "key_desktop_move_cases_002.wprgo" } }, "description": "Describes the Web Page Replay archives for a story set. Don't edit by hand! Use record_wpr for updating.",
diff --git a/tools/perf/page_sets/data/key_desktop_move_cases_000.wpr.sha1 b/tools/perf/page_sets/data/key_desktop_move_cases_000.wpr.sha1 deleted file mode 100644 index 79b4cb92..0000000 --- a/tools/perf/page_sets/data/key_desktop_move_cases_000.wpr.sha1 +++ /dev/null
@@ -1 +0,0 @@ -7982d4d8661f8e7bf33e4c4a68e41dd3b8dc7661 \ No newline at end of file
diff --git a/tools/perf/page_sets/data/key_desktop_move_cases_000.wprgo.sha1 b/tools/perf/page_sets/data/key_desktop_move_cases_000.wprgo.sha1 new file mode 100644 index 0000000..6223e1f --- /dev/null +++ b/tools/perf/page_sets/data/key_desktop_move_cases_000.wprgo.sha1
@@ -0,0 +1 @@ +26fe310f8a67bbbd91848cfbd260442285c91468 \ No newline at end of file
diff --git a/tools/perf/page_sets/data/key_desktop_move_cases_002.wpr.sha1 b/tools/perf/page_sets/data/key_desktop_move_cases_002.wpr.sha1 deleted file mode 100644 index 21eb8d3..0000000 --- a/tools/perf/page_sets/data/key_desktop_move_cases_002.wpr.sha1 +++ /dev/null
@@ -1 +0,0 @@ -2f03166ecdd325bacaf5ce2ab411d5f533d1b67a \ No newline at end of file
diff --git a/tools/perf/page_sets/data/key_desktop_move_cases_002.wprgo.sha1 b/tools/perf/page_sets/data/key_desktop_move_cases_002.wprgo.sha1 new file mode 100644 index 0000000..3fa537cb --- /dev/null +++ b/tools/perf/page_sets/data/key_desktop_move_cases_002.wprgo.sha1
@@ -0,0 +1 @@ +ef581f08a71089465e81b6fe4bc72e6ddde33766 \ No newline at end of file
diff --git a/tools/perf/page_sets/data/key_mobile_sites_011.wprgo.sha1 b/tools/perf/page_sets/data/key_mobile_sites_011.wprgo.sha1 new file mode 100644 index 0000000..35514c7a --- /dev/null +++ b/tools/perf/page_sets/data/key_mobile_sites_011.wprgo.sha1
@@ -0,0 +1 @@ +55b355eecc12fdaf9521181508f3c8abeff477f1 \ No newline at end of file
diff --git a/tools/perf/page_sets/data/key_mobile_sites_012.wprgo.sha1 b/tools/perf/page_sets/data/key_mobile_sites_012.wprgo.sha1 new file mode 100644 index 0000000..95b067e --- /dev/null +++ b/tools/perf/page_sets/data/key_mobile_sites_012.wprgo.sha1
@@ -0,0 +1 @@ +45d33e89afc119359b49ded38bf8f977fcffff8e \ No newline at end of file
diff --git a/tools/perf/page_sets/data/key_mobile_sites_013.wprgo.sha1 b/tools/perf/page_sets/data/key_mobile_sites_013.wprgo.sha1 new file mode 100644 index 0000000..986221b --- /dev/null +++ b/tools/perf/page_sets/data/key_mobile_sites_013.wprgo.sha1
@@ -0,0 +1 @@ +4168e2e0672f038f39450c0babbf4b4be6cbb1d7 \ No newline at end of file
diff --git a/tools/perf/page_sets/data/key_mobile_sites_014.wprgo.sha1 b/tools/perf/page_sets/data/key_mobile_sites_014.wprgo.sha1 new file mode 100644 index 0000000..16aa3af --- /dev/null +++ b/tools/perf/page_sets/data/key_mobile_sites_014.wprgo.sha1
@@ -0,0 +1 @@ +6fbfdaa7f5ee08be5d381f8426b64338daa63e2c \ No newline at end of file
diff --git a/tools/perf/page_sets/data/key_mobile_sites_015.wprgo.sha1 b/tools/perf/page_sets/data/key_mobile_sites_015.wprgo.sha1 new file mode 100644 index 0000000..1a2a3f5 --- /dev/null +++ b/tools/perf/page_sets/data/key_mobile_sites_015.wprgo.sha1
@@ -0,0 +1 @@ +9e603dce548fc0fdbb916a1cff04a0b7e7360782 \ No newline at end of file
diff --git a/tools/perf/page_sets/data/key_mobile_sites_smooth.json b/tools/perf/page_sets/data/key_mobile_sites_smooth.json index 0c59b5c1..bc74a96 100644 --- a/tools/perf/page_sets/data/key_mobile_sites_smooth.json +++ b/tools/perf/page_sets/data/key_mobile_sites_smooth.json
@@ -1,9 +1,15 @@ { "archives": { - "Wikipedia (1 tab)": { + "ESPN": { + "DEFAULT": "key_mobile_sites_012.wprgo" + }, + "Twitter": { + "DEFAULT": "key_mobile_sites_011.wprgo" + }, + "Wikipedia_(1_tab)": { "DEFAULT": "key_mobile_sites_009.wprgo" }, - "Wikipedia (1 tab) - delayed scroll start": { + "Wikipedia_(1_tab)-delayed_scroll_start": { "DEFAULT": "key_mobile_sites_009.wprgo" }, "http://answers.yahoo.com/question/index?qid=20110117024343AAopj8f": { @@ -13,7 +19,7 @@ "DEFAULT": "key_mobile_sites_000.wprgo" }, "http://digg.com": { - "DEFAULT": "key_mobile_sites_002.wprgo" + "DEFAULT": "key_mobile_sites_014.wprgo" }, "http://en.blog.wordpress.com/2012/09/04/freshly-pressed-editors-picks-for-august-2012/": { "DEFAULT": "key_mobile_sites_000.wprgo" @@ -21,6 +27,9 @@ "http://en.wikipedia.org/wiki/Wikipedia": { "DEFAULT": "key_mobile_sites_000.wprgo" }, + "http://forecast.io": { + "DEFAULT": "key_mobile_sites_013.wprgo" + }, "http://ftw.usatoday.com/2014/05/spelling-bee-rules-shenanigans": { "DEFAULT": "key_mobile_sites_007.wprgo" }, @@ -91,7 +100,7 @@ "DEFAULT": "key_mobile_sites_000.wprgo" }, "http://www.amazon.com/gp/aw/s/ref=is_box_?k=nicolas+cage": { - "DEFAULT": "key_mobile_sites_000.wprgo" + "DEFAULT": "key_mobile_sites_015.wprgo" }, "http://www.androidpolice.com/2012/10/03/rumor-evidence-mounts-that-an-lg-optimus-g-nexus-is-coming-along-with-a-nexus-phone-certification-program/": { "DEFAULT": "key_mobile_sites_000.wprgo"
diff --git a/tools/perf/page_sets/data/loading_desktop.json b/tools/perf/page_sets/data/loading_desktop.json index ee6ba79..a28948c 100644 --- a/tools/perf/page_sets/data/loading_desktop.json +++ b/tools/perf/page_sets/data/loading_desktop.json
@@ -1,94 +1,94 @@ { "archives": { "24h": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "2ch": { "DEFAULT": "loading_desktop_001.wprgo" }, "AirBnB": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "Aljayyash": { - "DEFAULT": "loading_desktop_000.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "AllRecipes": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "ArsTechnica": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "Baidu": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "Bhaskar": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "Chosun": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "Colorado.edu": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "Danawa": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "Daum": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "Donga": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "Economist": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "Elmundo": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "FC2Blog": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "FDA": { "DEFAULT": "loading_desktop_001.wprgo" }, "FIFA": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "FarsNews": { - "DEFAULT": "loading_desktop_000.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "Flickr": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "FlipKart": { - "DEFAULT": "loading_desktop_005.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "Free.fr": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "HTML5Rocks": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "Haraj": { - "DEFAULT": "loading_desktop_000.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "HatenaBookmark": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "IGN": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "IMDB": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "IndiaTimes": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "Kakaku": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "Kenh14": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "Leboncoin": { "DEFAULT": "loading_desktop_001.wprgo" @@ -97,85 +97,85 @@ "DEFAULT": "loading_desktop_001.wprgo" }, "Mercadolivre": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "NatGeo": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "Naver": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "Orange": { - "DEFAULT": "loading_desktop_002.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "Pantip": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "PremierLeague": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "QQ": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "REI": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "Rambler": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "Ruten": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "Sina": { - "DEFAULT": "loading_desktop_003.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "Taobao": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "TheOnion": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "TheVerge": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "TicketMaster": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "Vietnamnet": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "Vnexpress": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "Walgreens": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "Yandex": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "Ynet": { "DEFAULT": "loading_desktop_000.wprgo" }, "amazon.co.jp": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "goo.ne.jp": { "DEFAULT": "loading_desktop_001.wprgo" }, "ja.wikipedia": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "money.cnn": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "ru.wikipedia": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "uol.com.br": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" }, "yahoo.co.jp": { - "DEFAULT": "loading_desktop_001.wprgo" + "DEFAULT": "loading_desktop_006.wprgo" } }, "description": "Describes the Web Page Replay archives for a story set. Don't edit by hand! Use record_wpr for updating.",
diff --git a/tools/perf/page_sets/data/loading_desktop_006.wprgo.sha1 b/tools/perf/page_sets/data/loading_desktop_006.wprgo.sha1 new file mode 100644 index 0000000..7510140 --- /dev/null +++ b/tools/perf/page_sets/data/loading_desktop_006.wprgo.sha1
@@ -0,0 +1 @@ +140fce8aac3884d83ab2e198077742ae05d318d0 \ No newline at end of file
diff --git a/tools/perf/page_sets/data/loading_mobile.json b/tools/perf/page_sets/data/loading_mobile.json index b364e63..f1e82ba2 100644 --- a/tools/perf/page_sets/data/loading_mobile.json +++ b/tools/perf/page_sets/data/loading_mobile.json
@@ -1,8 +1,23 @@ { "archives": { + "DevOpera": { + "DEFAULT": "loading_mobile_003.wprgo" + }, "Facebook": { "DEFAULT": "loading_mobile_002.wprgo" }, + "FlipBoard": { + "DEFAULT": "loading_mobile_003.wprgo" + }, + "FlipKart": { + "DEFAULT": "loading_mobile_003.wprgo" + }, + "Suumo": { + "DEFAULT": "loading_mobile_003.wprgo" + }, + "VoiceMemos": { + "DEFAULT": "loading_mobile_003.wprgo" + }, "http://enquiry.indianrail.gov.in/mntes/MntesServlet?action=MainMenu&subAction=excep&excpType=EC": { "DEFAULT": "loading_mobile_000.wprgo" }, @@ -96,27 +111,9 @@ "http://xw.qq.com/news/20160803025029/NEW2016080302502901": { "DEFAULT": "loading_mobile_000.wprgo" }, - "https://2048-opera-pwa.surge.sh/": { - "DEFAULT": "loading_mobile_000.wprgo" - }, - "https://andreasbovens.github.io/inbox-attack/": { - "DEFAULT": "loading_mobile_000.wprgo" - }, - "https://dev.opera.com/": { - "DEFAULT": "loading_mobile_000.wprgo" - }, "https://en.m.wikipedia.org/wiki/Solo_Foods": { "DEFAULT": "loading_mobile_000.wprgo" }, - "https://flipboard.com/topic/yoga": { - "DEFAULT": "loading_mobile_000.wprgo" - }, - "https://guitar-tuner.appspot.com": { - "DEFAULT": "loading_mobile_000.wprgo" - }, - "https://jakearchibald.github.io/trained-to-thrill/": { - "DEFAULT": "loading_mobile_000.wprgo" - }, "https://m.baidu.com/s?word=%E9%B2%9C%E8%8A%B1%E9%80%9F%E9%80%92&oq=%E9%B2%9C%E8%8A%B1": { "DEFAULT": "loading_mobile_000.wprgo" }, @@ -126,18 +123,6 @@ "https://mobile.twitter.com/scottjehl/status/760618697727803394": { "DEFAULT": "loading_mobile_000.wprgo" }, - "https://smp.suumo.jp/mansion/tokyo/sc_104/cond/?moreCond=1": { - "DEFAULT": "loading_mobile_000.wprgo" - }, - "https://townwork.net": { - "DEFAULT": "loading_mobile_000.wprgo" - }, - "https://voice-memos.appspot.com": { - "DEFAULT": "loading_mobile_000.wprgo" - }, - "https://www.flipkart.com/big-wing-casuals/p/itmemeageyfn6m9z?lid=LSTSHOEMEAGURG2PHPW18FTBN&pid=SHOEMEAGURG2PHPW": { - "DEFAULT": "loading_mobile_000.wprgo" - }, "https://www.google.co.id/#q=pengiriman+bunga": { "DEFAULT": "loading_mobile_000.wprgo" }, @@ -150,13 +135,10 @@ "https://www.google.com/search?q=flower#q=flower+delivery": { "DEFAULT": "loading_mobile_000.wprgo" }, - "https://www.pokedex.org/": { - "DEFAULT": "loading_mobile_000.wprgo" - }, "https://www.youtube.com/watch?v=MU3YuvNRhVY": { "DEFAULT": "loading_mobile_000.wprgo" } }, "description": "Describes the Web Page Replay archives for a story set. Don't edit by hand! Use record_wpr for updating.", "platform_specific": true -} \ No newline at end of file +}
diff --git a/tools/perf/page_sets/data/loading_mobile_003.wprgo.sha1 b/tools/perf/page_sets/data/loading_mobile_003.wprgo.sha1 new file mode 100644 index 0000000..978ec5f --- /dev/null +++ b/tools/perf/page_sets/data/loading_mobile_003.wprgo.sha1
@@ -0,0 +1 @@ +e075a38890b06bc2bf5566a139b6872f453be3b2 \ No newline at end of file
diff --git a/tools/perf/page_sets/data/maps.json b/tools/perf/page_sets/data/maps.json deleted file mode 100644 index d7c05aaf..0000000 --- a/tools/perf/page_sets/data/maps.json +++ /dev/null
@@ -1,9 +0,0 @@ -{ - "archives": { - "http://map-test/performance.html": { - "DEFAULT": "maps_005.wprgo" - } - }, - "description": "Describes the Web Page Replay archives for a story set. Don't edit by hand! Use record_wpr for updating.", - "platform_specific": true -}
diff --git a/tools/perf/page_sets/data/maps_005.wprgo.sha1 b/tools/perf/page_sets/data/maps_005.wprgo.sha1 deleted file mode 100644 index ba3efe2..0000000 --- a/tools/perf/page_sets/data/maps_005.wprgo.sha1 +++ /dev/null
@@ -1 +0,0 @@ -b328c5622f92ff82b0e7ad8b30dc46d74e0a4c05 \ No newline at end of file
diff --git a/tools/perf/page_sets/data/service_worker.json b/tools/perf/page_sets/data/service_worker.json deleted file mode 100644 index 6164178..0000000 --- a/tools/perf/page_sets/data/service_worker.json +++ /dev/null
@@ -1,24 +0,0 @@ -{ - "archives": { - "first_load": { - "DEFAULT": "service_worker_040.wprgo" - }, - "https://jakearchibald.github.io/trained-to-thrill/": { - "DEFAULT": "service_worker_038.wprgo" - }, - "second_load": { - "DEFAULT": "service_worker_040.wprgo" - }, - "svgomg_first_load": { - "DEFAULT": "service_worker_040.wprgo" - }, - "svgomg_second_load": { - "DEFAULT": "service_worker_040.wprgo" - }, - "third_load": { - "DEFAULT": "service_worker_040.wprgo" - } - }, - "description": "Describes the Web Page Replay archives for a story set. Don't edit by hand! Use record_wpr for updating.", - "platform_specific": true -} \ No newline at end of file
diff --git a/tools/perf/page_sets/data/service_worker_038.wprgo.sha1 b/tools/perf/page_sets/data/service_worker_038.wprgo.sha1 deleted file mode 100644 index 5635337..0000000 --- a/tools/perf/page_sets/data/service_worker_038.wprgo.sha1 +++ /dev/null
@@ -1 +0,0 @@ -0e2cd9e417235cd3b4316e627d0bec469a04b871 \ No newline at end of file
diff --git a/tools/perf/page_sets/data/service_worker_040.wprgo.sha1 b/tools/perf/page_sets/data/service_worker_040.wprgo.sha1 deleted file mode 100644 index ca8ccac..0000000 --- a/tools/perf/page_sets/data/service_worker_040.wprgo.sha1 +++ /dev/null
@@ -1 +0,0 @@ -3dca2bbf7cad7690ce13bf9058d91643331834f3 \ No newline at end of file
diff --git a/tools/perf/page_sets/data/service_worker_micro_benchmark_004.wprgo.sha1 b/tools/perf/page_sets/data/service_worker_micro_benchmark_004.wprgo.sha1 deleted file mode 100644 index cbfaf2d..0000000 --- a/tools/perf/page_sets/data/service_worker_micro_benchmark_004.wprgo.sha1 +++ /dev/null
@@ -1 +0,0 @@ -ef25a3d6171d5e51cc8dfad1547bf88ca48219ee \ No newline at end of file
diff --git a/tools/perf/page_sets/data/system_health_desktop.json b/tools/perf/page_sets/data/system_health_desktop.json index 20502e54..993e66d 100644 --- a/tools/perf/page_sets/data/system_health_desktop.json +++ b/tools/perf/page_sets/data/system_health_desktop.json
@@ -60,6 +60,12 @@ "browse:social:twitter_infinite_scroll": { "DEFAULT": "system_health_desktop_054.wprgo" }, + "browse_accessibility:tech:codesearch": { + "DEFAULT": "system_health_desktop_059.wprgo" + }, + "browse_accessibility:tools:gmail_compose": { + "DEFAULT": "system_health_desktop_059.wprgo" + }, "load:games:alphabetty": { "DEFAULT": "system_health_desktop_005.wprgo" }, @@ -186,6 +192,12 @@ "load:tools:weather": { "DEFAULT": "system_health_desktop_004.wprgo" }, + "load_accessibility:media:wikipedia": { + "DEFAULT": "system_health_desktop_059.wprgo" + }, + "load_accessibility:shopping:amazon": { + "DEFAULT": "system_health_desktop_059.wprgo" + }, "long_running:tools:gmail-background": { "DEFAULT": "system_health_desktop_028.wprgo" },
diff --git a/tools/perf/page_sets/data/system_health_desktop_059.wprgo.sha1 b/tools/perf/page_sets/data/system_health_desktop_059.wprgo.sha1 new file mode 100644 index 0000000..91f7431a --- /dev/null +++ b/tools/perf/page_sets/data/system_health_desktop_059.wprgo.sha1
@@ -0,0 +1 @@ +e9da0dbcc23e0328990f7d6aa5ec747a2e0446e4 \ No newline at end of file
diff --git a/tools/perf/page_sets/data/top_25.json b/tools/perf/page_sets/data/top_25.json index 95bcc86..8fd52267 100644 --- a/tools/perf/page_sets/data/top_25.json +++ b/tools/perf/page_sets/data/top_25.json
@@ -1,7 +1,7 @@ { "archives": { - "Docs (1 open document tab)": { - "DEFAULT": "top_25_012.wprgo" + "Docs_(1_open_document_tab)": { + "DEFAULT": "top_25_014.wprgo" }, "ESPN": { "DEFAULT": "top_25_009.wprgo" @@ -21,7 +21,7 @@ "Weather.com": { "DEFAULT": "top_25_009.wprgo" }, - "Wikipedia (1 tab)": { + "Wikipedia_(1_tab)": { "DEFAULT": "top_25_009.wprgo" }, "http://answers.yahoo.com": { @@ -94,7 +94,7 @@ "DEFAULT": "top_25_000.wprgo" }, "https://www.google.com/#hl=en&q=barack+obama": { - "DEFAULT": "top_25_012.wprgo" + "DEFAULT": "top_25_015.wprgo" }, "https://www.google.com/calendar/": { "DEFAULT": "top_25_000.wprgo"
diff --git a/tools/perf/page_sets/data/top_25_012.wprgo.sha1 b/tools/perf/page_sets/data/top_25_012.wprgo.sha1 index 731f5df..217f848 100644 --- a/tools/perf/page_sets/data/top_25_012.wprgo.sha1 +++ b/tools/perf/page_sets/data/top_25_012.wprgo.sha1
@@ -1 +1 @@ -a61489a11fed60b3d9f1f37f90ab176bec345f21 \ No newline at end of file +bd503b282964e34176b6c617d84d38aee20aa07c \ No newline at end of file
diff --git a/tools/perf/page_sets/data/top_25_013.wprgo.sha1 b/tools/perf/page_sets/data/top_25_013.wprgo.sha1 new file mode 100644 index 0000000..720866f --- /dev/null +++ b/tools/perf/page_sets/data/top_25_013.wprgo.sha1
@@ -0,0 +1 @@ +e9eb7bd5faa98447624cfe06d618352f21b5987a \ No newline at end of file
diff --git a/tools/perf/page_sets/data/top_25_014.wprgo.sha1 b/tools/perf/page_sets/data/top_25_014.wprgo.sha1 new file mode 100644 index 0000000..13b0767 --- /dev/null +++ b/tools/perf/page_sets/data/top_25_014.wprgo.sha1
@@ -0,0 +1 @@ +f157f09b20ec18dfa75b570a74428e632d6e7cab \ No newline at end of file
diff --git a/tools/perf/page_sets/data/top_25_015.wprgo.sha1 b/tools/perf/page_sets/data/top_25_015.wprgo.sha1 new file mode 100644 index 0000000..98e489e --- /dev/null +++ b/tools/perf/page_sets/data/top_25_015.wprgo.sha1
@@ -0,0 +1 @@ +2f03409183725a1a53382560cb2e09f2570b3af3 \ No newline at end of file
diff --git a/tools/perf/page_sets/data/top_25_smooth.json b/tools/perf/page_sets/data/top_25_smooth.json index 941cecb..cbef06c9 100644 --- a/tools/perf/page_sets/data/top_25_smooth.json +++ b/tools/perf/page_sets/data/top_25_smooth.json
@@ -1,12 +1,12 @@ { "archives": { - "Docs (1 open document tab)": { + "Docs_(1_open_document_tab)": { "DEFAULT": "top_25_009.wprgo" }, "Facebook": { "DEFAULT": "top_25_003.wprgo" }, - "Wikipedia (1 tab)": { + "Wikipedia_(1_tab)": { "DEFAULT": "top_25_004.wprgo" }, "http://answers.yahoo.com": { @@ -86,8 +86,14 @@ }, "https://www.google.com/search?q=cats&tbm=isch": { "DEFAULT": "top_25_007.wprgo" + }, + "overview:js_poster_circle": { + "DEFAULT": "top_25_012.wprgo" + }, + "overview:yahoo_news": { + "DEFAULT": "top_25_013.wprgo" } }, "description": "Describes the Web Page Replay archives for a story set. Don't edit by hand! Use record_wpr for updating.", "platform_specific": true -} \ No newline at end of file +}
diff --git a/tools/perf/page_sets/data/tough_path_rendering_cases.json b/tools/perf/page_sets/data/tough_path_rendering_cases.json index e3faf58..f52a84d 100644 --- a/tools/perf/page_sets/data/tough_path_rendering_cases.json +++ b/tools/perf/page_sets/data/tough_path_rendering_cases.json
@@ -1,12 +1,12 @@ { "archives": { - "GUIMark Vector Chart Test": { + "GUIMark_Vector_Chart_Test": { "DEFAULT": "tough_path_rendering_cases_002.wprgo" }, - "MotionMark Canvas Fill Shapes": { + "MotionMark_Canvas_Fill_Shapes": { "DEFAULT": "tough_path_rendering_cases_002.wprgo" }, - "MotionMark Canvas Stroke Shapes": { + "MotionMark_Canvas_Stroke_Shapes": { "DEFAULT": "tough_path_rendering_cases_002.wprgo" }, "http://ie.microsoft.com/testdrive/Performance/Chalkboard/": { @@ -21,4 +21,4 @@ }, "description": "Describes the Web Page Replay archives for a story set. Don't edit by hand! Use record_wpr for updating.", "platform_specific": true -} \ No newline at end of file +}
diff --git a/tools/perf/page_sets/data/v8_top_25.json b/tools/perf/page_sets/data/v8_top_25.json index 64a5b172..20a7013 100644 --- a/tools/perf/page_sets/data/v8_top_25.json +++ b/tools/perf/page_sets/data/v8_top_25.json
@@ -1,5 +1,32 @@ { "archives": { + "AdsAMPAds": { + "DEFAULT": "v8_top_25_001.wprgo" + }, + "AdsAdSenseAsyncAds": { + "DEFAULT": "v8_top_25_001.wprgo" + }, + "AdsAsyncAdSenseImage": { + "DEFAULT": "v8_top_25_001.wprgo" + }, + "AdsDoubleClickAsyncAds": { + "DEFAULT": "v8_top_25_001.wprgo" + }, + "AdsMultipleAdSlots": { + "DEFAULT": "v8_top_25_001.wprgo" + }, + "AdsOnScreenDetection": { + "DEFAULT": "v8_top_25_001.wprgo" + }, + "AdsSyncAdSenseImage": { + "DEFAULT": "v8_top_25_001.wprgo" + }, + "AdsSyncLoadAsyncRenderAdSenseImage": { + "DEFAULT": "v8_top_25_001.wprgo" + }, + "AdsViewOptimizedRendering": { + "DEFAULT": "v8_top_25_001.wprgo" + }, "http://edition.cnn.com": { "DEFAULT": "v8_top_25_000.wprgo" },
diff --git a/tools/perf/page_sets/data/v8_top_25_001.wprgo.sha1 b/tools/perf/page_sets/data/v8_top_25_001.wprgo.sha1 new file mode 100644 index 0000000..0bcd4fe --- /dev/null +++ b/tools/perf/page_sets/data/v8_top_25_001.wprgo.sha1
@@ -0,0 +1 @@ +63d8f92a48c2a6381294e37d12eb0142249443ad \ No newline at end of file
diff --git a/tools/perf/page_sets/data/wasm_realworld_pages.json b/tools/perf/page_sets/data/wasm_realworld_pages.json new file mode 100644 index 0000000..cc8d5da4 --- /dev/null +++ b/tools/perf/page_sets/data/wasm_realworld_pages.json
@@ -0,0 +1,21 @@ +{ + "archives": { + "WasmSpaceBuggy": { + "DEFAULT": "wasm_realworld_pages_003.wprgo" + }, + "WasmStylizedRenderer": { + "DEFAULT": "wasm_realworld_pages_003.wprgo" + }, + "WasmSunTemple": { + "DEFAULT": "wasm_realworld_pages_003.wprgo" + }, + "WasmTanks": { + "DEFAULT": "wasm_realworld_pages_003.wprgo" + }, + "WasmZenGarden": { + "DEFAULT": "wasm_realworld_pages_003.wprgo" + } + }, + "description": "Describes the Web Page Replay archives for a story set. Don't edit by hand! Use record_wpr for updating.", + "platform_specific": true +} \ No newline at end of file
diff --git a/tools/perf/page_sets/data/wasm_realworld_pages_000.wprgo.sha1 b/tools/perf/page_sets/data/wasm_realworld_pages_000.wprgo.sha1 new file mode 100644 index 0000000..afce1a8 --- /dev/null +++ b/tools/perf/page_sets/data/wasm_realworld_pages_000.wprgo.sha1
@@ -0,0 +1 @@ +cf24016ce104e26f876a37deaf74cdba753ae977 \ No newline at end of file
diff --git a/tools/perf/page_sets/data/wasm_realworld_pages_001.wprgo.sha1 b/tools/perf/page_sets/data/wasm_realworld_pages_001.wprgo.sha1 new file mode 100644 index 0000000..f9a98a4 --- /dev/null +++ b/tools/perf/page_sets/data/wasm_realworld_pages_001.wprgo.sha1
@@ -0,0 +1 @@ +62abc4cfd6c01576551f197d58ef6a174fb3e633 \ No newline at end of file
diff --git a/tools/perf/page_sets/data/wasm_realworld_pages_002.wprgo.sha1 b/tools/perf/page_sets/data/wasm_realworld_pages_002.wprgo.sha1 new file mode 100644 index 0000000..8871c57 --- /dev/null +++ b/tools/perf/page_sets/data/wasm_realworld_pages_002.wprgo.sha1
@@ -0,0 +1 @@ +79ef3c0a1a123c3761e179c663e37bd393eff5fb \ No newline at end of file
diff --git a/tools/perf/page_sets/data/wasm_realworld_pages_003.wprgo.sha1 b/tools/perf/page_sets/data/wasm_realworld_pages_003.wprgo.sha1 new file mode 100644 index 0000000..e0f524a --- /dev/null +++ b/tools/perf/page_sets/data/wasm_realworld_pages_003.wprgo.sha1
@@ -0,0 +1 @@ +232959afb464037f766a9ed0ea9918d358dde75b \ No newline at end of file
diff --git a/tools/perf/page_sets/dual_browser_story.py b/tools/perf/page_sets/dual_browser_story.py index 218b111f..a6fbd1ac 100644 --- a/tools/perf/page_sets/dual_browser_story.py +++ b/tools/perf/page_sets/dual_browser_story.py
@@ -80,8 +80,8 @@ extra_browser_types = set(story.browser_type for story in story_set) extra_browser_types.remove('default') # Must include 'default' browser. for browser_type in extra_browser_types: - options = _OptionsForBrowser(browser_type, finder_options) - if not self._PrepareBrowser(browser_type, options): + finder_options_copy = _OptionsForBrowser(browser_type, finder_options) + if not self._PrepareBrowser(browser_type, finder_options_copy): logging.warning( 'Cannot run %s (%s) because %s browser is not available', test.__name__, str(test), browser_type) @@ -97,10 +97,9 @@ wpr_mode = wpr_modes.WPR_RECORD else: wpr_mode = wpr_modes.WPR_REPLAY + self._extra_wpr_args = browser_options.extra_wpr_args - self.platform.network_controller.Open( - wpr_mode, browser_options.extra_wpr_args, - use_wpr_go=story_set.wpr_archive_info.is_using_wpr_go_archives) + self.platform.network_controller.Open(wpr_mode) @property def current_tab(self): @@ -110,7 +109,7 @@ def platform(self): return self._platform - def _PrepareBrowser(self, browser_type, options): + def _PrepareBrowser(self, browser_type, finder_options): """Add a browser to the dict of possible browsers. TODO(perezju): When available, use the GetBrowserForPlatform API instead. @@ -119,19 +118,16 @@ Returns: The possible browser if found, or None otherwise. """ - possible_browser = browser_finder.FindBrowser(options) + possible_browser = browser_finder.FindBrowser(finder_options) if possible_browser is None: return None if self._platform is None: self._platform = possible_browser.platform - # TODO(nedn): Remove the if condition once - # https://codereview.chromium.org/2265593003/ is rolled to Chromium tree. - if hasattr(self._platform.network_controller, 'InitializeIfNeeded'): - self._platform.network_controller.InitializeIfNeeded() else: assert self._platform is possible_browser.platform - self._possible_browsers[browser_type] = (possible_browser, options) + self._possible_browsers[browser_type] = ( + possible_browser, finder_options.browser_options) return possible_browser def _CreateAllBrowsersIfNeeeded(self): @@ -144,20 +140,26 @@ if self._browsers_created: return for browser_type in self._browsers: - possible_browser, options = self._possible_browsers[browser_type] - self._browsers[browser_type] = possible_browser.Create(options) + possible_browser, browser_options = self._possible_browsers[browser_type] + possible_browser.SetUpEnvironment(browser_options) + self._browsers[browser_type] = possible_browser.Create() self._browsers_created = True def _CloseAllBrowsers(self): """Close all of the browsers that were launched for this benchmark.""" - if not self._browsers_created: - return - for browser_type, browser in self._browsers.iteritems(): + for browser_type, browser in list(self._browsers.iteritems()): + if browser is not None: + try: + browser.Close() + except Exception: + logging.exception('Error while closing %s browser', browser_type) + self._browsers[browser_type] = None + possible_browser, _ = self._possible_browsers[browser_type] try: - browser.Close() + possible_browser.CleanUpEnvironment() except Exception: - logging.exception('Error while closing %s browser', browser_type) - self._browsers[browser_type] = None + logging.exception( + 'Error while cleaning up environment for %s', browser_type) self._browsers_created = False def CanRunStory(self, _): @@ -168,7 +170,8 @@ self.platform.network_controller.StartReplay( self._story_set.WprFilePathForStory(story), - story.make_javascript_deterministic) + story.make_javascript_deterministic, + self._extra_wpr_args) # Note: browsers need to be created after replay has been started. self._CreateAllBrowsersIfNeeeded()
diff --git a/tools/perf/page_sets/extension_profile_shared_state.py b/tools/perf/page_sets/extension_profile_shared_state.py deleted file mode 100644 index a0b4bab2..0000000 --- a/tools/perf/page_sets/extension_profile_shared_state.py +++ /dev/null
@@ -1,34 +0,0 @@ -# Copyright 2015 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 shutil - -from profile_creators import extension_profile_extender -from profile_creators import profile_generator -from telemetry.page import shared_page_state - - -class ExtensionProfileSharedState(shared_page_state.SharedPageState): - """Shared state tied with extension profile. - - Generates extension profile on initialization. - """ - - def __init__(self, test, finder_options, story_set): - super(ExtensionProfileSharedState, self).__init__( - test, finder_options, story_set) - generator = profile_generator.ProfileGenerator( - extension_profile_extender.ExtensionProfileExtender, - 'extension_profile') - self._out_dir, self._owns_out_dir = generator.Run(finder_options) - if self._out_dir: - finder_options.browser_options.profile_dir = self._out_dir - else: - finder_options.browser_options.dont_override_profile = True - - def TearDownState(self): - """Clean up generated profile directory.""" - super(ExtensionProfileSharedState, self).TearDownState() - if self._owns_out_dir: - shutil.rmtree(self._out_dir)
diff --git a/tools/perf/page_sets/google_pages.py b/tools/perf/page_sets/google_pages.py index 9e11ee4..03d51626 100644 --- a/tools/perf/page_sets/google_pages.py +++ b/tools/perf/page_sets/google_pages.py
@@ -16,12 +16,10 @@ class GooglePages(page_module.Page): def __init__(self, url, page_set, shared_page_state_class, - name='', credentials=None): + name=''): super(GooglePages, self).__init__( url=url, page_set=page_set, name=name, - credentials_path='data/credentials.json', shared_page_state_class=shared_page_state_class) - self.credentials = credentials self.script_to_evaluate_on_commit = _DeterministicPerformanceCounters() @@ -35,8 +33,7 @@ name='https://mail.google.com/mail/') def RunNavigateSteps(self, action_runner): - google_login.LoginGoogleAccount(action_runner, 'google', - self.credentials_path) + google_login.LoginGoogleAccount(action_runner, 'google') super(GmailPage, self).RunNavigateSteps(action_runner) action_runner.WaitForJavaScriptCondition( 'window.gmonkey !== undefined &&'
diff --git a/tools/perf/page_sets/idle_after_loading_stories.py b/tools/perf/page_sets/idle_after_loading_stories.py index 7f1a8a7..d42dd99 100644 --- a/tools/perf/page_sets/idle_after_loading_stories.py +++ b/tools/perf/page_sets/idle_after_loading_stories.py
@@ -51,9 +51,3 @@ # https://crbug.com/638365. for url in SITES: self.AddStory(_BasePage(self, url, wait_in_seconds, url)) - - -class IdleAfterLoadingStoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableStory( - 'http://abcnews.go.com/', [story.expectations.ALL], 'crbug.com/505990')
diff --git a/tools/perf/page_sets/indexeddb_endure_page.py b/tools/perf/page_sets/indexeddb_endure_page.py deleted file mode 100644 index 80feb6e..0000000 --- a/tools/perf/page_sets/indexeddb_endure_page.py +++ /dev/null
@@ -1,47 +0,0 @@ -# Copyright 2015 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. - -from telemetry.page import page as page_module -from telemetry import story - -class IndexedDBEndurePage(page_module.Page): - - def __init__(self, subtest, page_set): - super(IndexedDBEndurePage, self).__init__( - url='file://indexeddb_perf/perf_test.html', - page_set=page_set, - name='indexeddb-endure-' + subtest) - self._subtest = subtest - - def RunPageInteractions(self, action_runner): - action_runner.ExecuteJavaScript( - 'window.testFilter = {{ subtest }};', subtest=self._subtest) - with action_runner.CreateInteraction('Action_Test'): - action_runner.ExecuteJavaScript('window.test();') - action_runner.WaitForJavaScriptCondition( - 'window.done', timeout=600) - -class IndexedDBEndurePageSet(story.StorySet): - """The IndexedDB Endurance page set. - - This page set exercises various common operations in IndexedDB. - """ - - def __init__(self): - super(IndexedDBEndurePageSet, self).__init__() - tests = [ - 'testCreateAndDeleteDatabases', - 'testCreateAndDeleteDatabase', - 'testCreateKeysInStores', - 'testRandomReadsAndWritesWithoutIndex', - 'testRandomReadsAndWritesWithIndex', - 'testReadCacheWithoutIndex', - 'testReadCacheWithIndex', - 'testCreateAndDeleteIndex', - 'testWalkingMultipleCursors', - 'testCursorSeeksWithoutIndex', - 'testCursorSeeksWithIndex' - ] - for test in tests: - self.AddStory(IndexedDBEndurePage(test, self))
diff --git a/tools/perf/page_sets/indexeddb_perf/endure/app-worker.js b/tools/perf/page_sets/indexeddb_perf/endure/app-worker.js deleted file mode 100644 index d98ee3e..0000000 --- a/tools/perf/page_sets/indexeddb_perf/endure/app-worker.js +++ /dev/null
@@ -1,224 +0,0 @@ -// Copyright 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. - -// This file simulates a typical background process of an offline-capable -// authoring application. When in an "online" state it receives chunks of -// data updates from a simulated server and stores them in a temporary IDB -// data store. On a different timer, the chunks are drained from the -// temporary store and combined into larger records in a permanent store. -// When in an "offline" state, nothing else happens. - -function unexpectedErrorCallback(e) { - self.postMessage({type: 'ERROR', error: { - name: e.target.error.name, - message: e.target.error.message - }}); -} - -function unexpectedAbortCallback(e) { - self.postMessage({type: 'ABORT', error: { - name: e.target.error.name, - message: e.target.error.message - }}); -} - -function log(message) { - self.postMessage({type: 'LOG', message: message}); -} - -function error(message) { - self.postMessage({type: 'ERROR', message: message}); -} - -var DBNAME = 'endurance-db'; -var DBVERSION = 1; - -var MAX_DOC_ID = 25; -var MAX_CHUNK_ID = 10; -var MAX_CHUNK_SIZE = 5 * 1024; -var SYNC_TIMEOUT = 100; -var COMBINE_TIMEOUT = 234; // relatively prime with SYNC_TIMEOUT - -function randomString(len) -{ - var s = ''; - while (len--) - s += Math.floor((Math.random() * 36)).toString(36); - return s; -} - -var getNextChunk = ( - function () { - var nextDocID = 0; - var nextChunkID = 0; - - return function () { - var doc_id = nextDocID; - var chunk_id = nextChunkID; - - nextDocID += 1; - if (nextDocID >= MAX_DOC_ID) { - nextDocID = 0; - nextChunkID += 1; - if (nextChunkID >= MAX_CHUNK_ID) - nextChunkID = 0; - } - - return { - docid: doc_id, - chunkid: chunk_id, - timestamp: new Date(), - data: randomString(MAX_CHUNK_SIZE) - }; - }; - }() -); - - -self.onmessage = function (event) { - switch (event.data.type) { - case 'offline': - goOffline(); - break; - case 'online': - goOnline(); - break; - default: - throw new Error("Unexpected message: " + event.data.type); - } -}; - - -var offline = true; -var syncTimeoutId = 0; -var combineTimeoutId = 0; - -function goOffline() { - if (offline) - return; - log('offline'); - offline = true; - clearTimeout(syncTimeoutId); - syncTimeoutId = 0; - clearTimeout(combineTimeoutId); - combineTimeoutId = 0; -} - -function goOnline() { - if (!offline) - return; - offline = false; - log('online'); - syncTimeoutId = setTimeout(sync, SYNC_TIMEOUT); - combineTimeoutId = setTimeout(combine, COMBINE_TIMEOUT); - // NOTE: Not using setInterval as we need to be sure they complete. -} - -var sync_count = 0; -function sync() { - if (offline) - return; - - var sync_id = ++sync_count; - log('sync ' + sync_id + ' started'); - - var chunk = getNextChunk(); - log('sync ' + sync_id + - ' adding chunk: ' + chunk.chunkid + - ' to doc: ' + chunk.docid); - - var request = indexedDB.open(DBNAME); - request.onerror = unexpectedErrorCallback; - request.onsuccess = function () { - var db = request.result; - if (db.version !== DBVERSION) { - error('DB version incorrect'); - return; - } - - var transaction = db.transaction('sync-chunks', 'readwrite'); - var store = transaction.objectStore('sync-chunks'); - request = store.put(chunk); - transaction.onabort = unexpectedAbortCallback; - transaction.oncomplete = function () { - log('sync ' + sync_id + ' finished'); - db.close(); - syncTimeoutId = setTimeout(sync, SYNC_TIMEOUT); - }; - }; -} - -var combine_count = 0; -function combine() { - if (offline) - return; - - var combine_id = ++combine_count; - log('combine ' + combine_id + ' started'); - - var combine_chunk_count = 0; - - var request = indexedDB.open(DBNAME); - request.onerror = unexpectedErrorCallback; - request.onsuccess = function () { - var db = request.result; - if (db.version !== DBVERSION) { - error('DB version incorrect'); - return; - } - - var transaction = db.transaction(['sync-chunks', 'docs'], 'readwrite'); - var syncStore = transaction.objectStore('sync-chunks'); - var docStore = transaction.objectStore('docs'); - - var cursorRequest = syncStore.openCursor(); - cursorRequest.onerror = unexpectedErrorCallback; - cursorRequest.onsuccess = function () { - var cursor = cursorRequest.result; - if (cursor) { - combine_chunk_count += 1; - log('combine ' + combine_id + - ' processing chunk # ' + combine_chunk_count); - - var key = cursor.key; - var chunk = cursor.value; - var docRequest = docStore.get(chunk.docid); - docRequest.onerror = unexpectedErrorCallback; - docRequest.onsuccess = function () { - var doc = docRequest.result; - if (!doc) { - doc = { - docid: chunk.docid, - chunks: [] - }; - log('combine # ' + combine_id + - ' created doc: ' + doc.docid); - } - - log('combine # ' + combine_id + - ' updating doc: ' + doc.docid + - ' chunk: ' + chunk.chunkid); - - doc.chunks[chunk.chunkid] = chunk; - doc.timestamp = new Date(); - request = docStore.put(doc); - request.onerror = unexpectedErrorCallback; - cursor.delete(key); - cursor.continue(); - }; - } else { - // let transaction complete - log('combine ' + combine_id + - ' done, processed ' + combine_chunk_count + ' chunks'); - } - }; - transaction.onabort = unexpectedAbortCallback; - transaction.oncomplete = function () { - log('combine ' + combine_id + - ' finished, processed ' + combine_chunk_count + ' chunks'); - db.close(); - combineTimeoutId = setTimeout(combine, COMBINE_TIMEOUT); - }; - }; -}
diff --git a/tools/perf/page_sets/indexeddb_perf/endure/app.html b/tools/perf/page_sets/indexeddb_perf/endure/app.html deleted file mode 100644 index 19a5b13d..0000000 --- a/tools/perf/page_sets/indexeddb_perf/endure/app.html +++ /dev/null
@@ -1,21 +0,0 @@ -<!DOCTYPE html> -<title>IndexedDB Offline</title> -<p>This test models the typical design of an offline-aware authoring - application: -<ul> -<li>When "offline", a series of (fake) user events are logged into a - store -<li>When "online", the events are played back to a (fake) server, - draining the store -<li>When "online" a Worker synchronizes data from a (fake) remote - source into a store in chunks, then consolidates it into another - store -</ul> - -<div id="status"></div> - -<button disabled="true" id="offline">Go Offline</button> -<button disabled="true" id="online">Go Online</button> -<div id="state"></div> - -<script src="app.js?cachebust"></script>
diff --git a/tools/perf/page_sets/indexeddb_perf/endure/app.js b/tools/perf/page_sets/indexeddb_perf/endure/app.js deleted file mode 100644 index 6e0d5bc..0000000 --- a/tools/perf/page_sets/indexeddb_perf/endure/app.js +++ /dev/null
@@ -1,274 +0,0 @@ -// Copyright 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. - -// This file simulates a typical foreground process of an offline-capable -// authoring application. When in an "offline" state, simulated user actions -// are recorded for later playback in an IDB data store. When in an "online" -// state, the recorded actions are drained from the store (as if being sent -// to the server). - -var $ = function(s) { - return document.querySelector(s); -}; - -function status(message) { - var elem = $('#status'); - while (elem.firstChild) - elem.removeChild(elem.firstChild); - elem.appendChild(document.createTextNode(message)); -} - -function log(message) { - status(message); -} - -function error(message) { - status(message); - console.error(message); -} - -function unexpectedErrorCallback(e) { - error("Unexpected error callback: (" + e.target.error.name + ") " + - e.target.error.message); -} - -function unexpectedAbortCallback(e) { - error("Unexpected abort callback: (" + e.target.error.name + ") " + - e.target.error.message); -} - -function unexpectedBlockedCallback(e) { - error("Unexpected blocked callback!"); -} - -var DBNAME = 'endurance-db'; -var DBVERSION = 1; -var MAX_DOC_ID = 25; - -var db; - -function initdb() { - var request = indexedDB.deleteDatabase(DBNAME); - request.onerror = unexpectedErrorCallback; - request.onblocked = unexpectedBlockedCallback; - request.onsuccess = function () { - request = indexedDB.open(DBNAME, DBVERSION); - request.onerror = unexpectedErrorCallback; - request.onblocked = unexpectedBlockedCallback; - request.onupgradeneeded = function () { - db = request.result; - request.transaction.onabort = unexpectedAbortCallback; - - var syncStore = db.createObjectStore( - 'sync-chunks', {keyPath: 'sequence', autoIncrement: true}); - syncStore.createIndex('doc-index', 'docid'); - - var docStore = db.createObjectStore( - 'docs', {keyPath: 'docid'}); - docStore.createIndex( - 'owner-index', 'owner', {multiEntry: true}); - - var userEventStore = db.createObjectStore( - 'user-events', {keyPath: 'sequence', autoIncrement: true}); - userEventStore.createIndex('doc-index', 'docid'); - }; - request.onsuccess = function () { - log('initialized'); - $('#offline').disabled = true; - $('#online').disabled = false; - }; - }; -} - -var offline = true; -var worker = new Worker('app-worker.js?cachebust'); -worker.onmessage = function (event) { - var data = event.data; - switch (data.type) { - case 'ABORT': - unexpectedAbortCallback({target: {error: data.error}}); - break; - case 'ERROR': - unexpectedErrorCallback({target: {error: data.error}}); - break; - case 'BLOCKED': - unexpectedBlockedCallback({target: {error: data.error}}); - break; - case 'LOG': - log('WORKER: ' + data.message); - break; - case 'ERROR': - error('WORKER: ' + data.message); - break; - } -}; -worker.onerror = function (event) { - error("Error in: " + event.filename + "(" + event.lineno + "): " + - event.message); -}; - -$('#offline').addEventListener('click', goOffline); -$('#online').addEventListener('click', goOnline); - -var EVENT_INTERVAL = 100; -var eventIntervalId = 0; - -function goOffline() { - if (offline) - return; - offline = true; - $('#offline').disabled = offline; - $('#online').disabled = !offline; - $('#state').innerHTML = 'offline'; - log('offline'); - - worker.postMessage({type: 'offline'}); - - eventIntervalId = setInterval(recordEvent, EVENT_INTERVAL); -} - -function goOnline() { - if (!offline) - return; - offline = false; - $('#offline').disabled = offline; - $('#online').disabled = !offline; - $('#state').innerHTML = 'online'; - log('online'); - - worker.postMessage({type: 'online'}); - - setTimeout(playbackEvents, 100); - clearInterval(eventIntervalId); - eventIntervalId = 0; -}; - -function recordEvent() { - if (!db) { - error("Database not initialized"); - return; - } - - var transaction = db.transaction(['user-events'], 'readwrite'); - var store = transaction.objectStore('user-events'); - var record = { - // 'sequence' key will be generated - docid: Math.floor(Math.random() * MAX_DOC_ID), - timestamp: new Date(), - data: randomString(256) - }; - - log('putting user event'); - var request = store.put(record); - request.onerror = unexpectedErrorCallback; - transaction.onabort = unexpectedAbortCallback; - transaction.oncomplete = function () { - log('put user event'); - }; -} - -function sendEvent(record, callback) { - setTimeout( - function () { - if (offline) - callback(false); - else { - var serialization = JSON.stringify(record); - callback(true); - } - }, - Math.random() * 200); // Simulate network jitter -} - -var PLAYBACK_NONE = 0; -var PLAYBACK_SUCCESS = 1; -var PLAYBACK_FAILURE = 2; - -function playbackEvent(callback) { - log('playbackEvent'); - var result = false; - var transaction = db.transaction(['user-events'], 'readonly'); - transaction.onabort = unexpectedAbortCallback; - var store = transaction.objectStore('user-events'); - var cursorRequest = store.openCursor(); - cursorRequest.onerror = unexpectedErrorCallback; - cursorRequest.onsuccess = function () { - var cursor = cursorRequest.result; - if (cursor) { - var record = cursor.value; - var key = cursor.key; - // NOTE: sendEvent is asynchronous so transaction should finish - sendEvent( - record, - function (success) { - if (success) { - // Use another transaction to delete event - var transaction = db.transaction(['user-events'], 'readwrite'); - transaction.onabort = unexpectedAbortCallback; - var store = transaction.objectStore('user-events'); - var deleteRequest = store.delete(key); - deleteRequest.onerror = unexpectedErrorCallback; - transaction.oncomplete = function () { - // successfully sent and deleted event - callback(PLAYBACK_SUCCESS); - }; - } else { - // No progress made - callback(PLAYBACK_FAILURE); - } - }); - } else { - callback(PLAYBACK_NONE); - } - }; -} - -var playback = false; - -function playbackEvents() { - log('playbackEvents'); - if (!db) { - error("Database not initialized"); - return; - } - - if (playback) - return; - - playback = true; - log("Playing back events"); - - function nextEvent() { - playbackEvent( - function (result) { - switch (result) { - case PLAYBACK_NONE: - playback = false; - log("Done playing back events"); - return; - case PLAYBACK_SUCCESS: - setTimeout(nextEvent, 0); - return; - case PLAYBACK_FAILURE: - playback = false; - log("Failure during playback (dropped offline?)"); - return; - } - }); - } - - nextEvent(); -} - -function randomString(len) { - var s = ''; - while (len--) - s += Math.floor((Math.random() * 36)).toString(36); - return s; -} - -window.onload = function () { - log("initializing..."); - initdb(); -};
diff --git a/tools/perf/page_sets/indexeddb_perf/perf_shared.js b/tools/perf/page_sets/indexeddb_perf/perf_shared.js deleted file mode 100644 index 7536e92..0000000 --- a/tools/perf/page_sets/indexeddb_perf/perf_shared.js +++ /dev/null
@@ -1,435 +0,0 @@ -// Copyright 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. - -var automation = { - results: {} -}; - -automation.setDone = function() { - this.setStatus("Test complete."); - document.cookie = '__done=1; path=/'; -}; - -automation.addResult = function(name, result) { - result = "" + result; - this.results[name] = result; - var elt = document.getElementById('results'); - var div = document.createElement('div'); - div.textContent = name + ": " + result; - elt.appendChild(div); -}; - -automation.getResults = function() { - return this.results; -}; - -automation.setStatus = function(s) { - document.getElementById('status').textContent = s; -}; - -function assert(t) { - if (!t) { - var e = new Error("Assertion failed!"); - console.log(e.stack); - throw e; - } -} - -function onError(e) { - var s = "Caught error."; - if (e.target && e.target.error) - s += "\n" + e.target.error.name + "\n" + e.target.error.message; - console.log(s); - automation.setStatus(s); - e.stopPropagation(); - throw new Error(e); -} - -var baseVersion = 2; // The version with our object stores. -var curVersion; - -// Valid options fields: -// indexName: the name of an index to create on each object store -// indexKeyPath: the key path for that index -// indexIsUnique: the "unique" option for IDBIndexParameters -// indexIsMultiEntry: the "multiEntry" option for IDBIndexParameters -// -function createDatabase( - name, objectStoreNames, handler, errorHandler, optionSets) { - var openRequest = indexedDB.open(name, baseVersion); - openRequest.onblocked = errorHandler; - openRequest.onerror = errorHandler; - function createObjectStores(db) { - for (var store in objectStoreNames) { - var name = objectStoreNames[store]; - assert(!db.objectStoreNames.contains(name)); - var os = db.createObjectStore(name); - if (optionSets) { - for (o in optionSets) { - var options = optionSets[o]; - assert(options.indexName); - assert('indexKeyPath' in options); - os.createIndex(options.indexName, options.indexKeyPath, - { unique: options.indexIsUnique, - multiEntry: options.indexIsMultiEntry }); - } - } - } - } - openRequest.onupgradeneeded = function(ev) { - // This is the spec-compliant path, which doesn't yet run in Chrome, but - // works in Firefox. - assert(openRequest == ev.target); - var db = openRequest.result; - db.onerror = errorHandler; - createObjectStores(db); - // onsuccess will get called after this exits. - }; - openRequest.onsuccess = function(ev) { - assert(openRequest == ev.target); - var db = openRequest.result; - curVersion = db.version; - db.onerror = function(ev) { - console.log("db error", arguments, openRequest.error.message); - errorHandler(ev); - }; - if (curVersion != baseVersion) { - // This is the legacy path, which runs only in Chrome. - var setVersionRequest = db.setVersion(baseVersion); - setVersionRequest.onerror = errorHandler; - setVersionRequest.onsuccess = function(e) { - assert(setVersionRequest == e.target); - createObjectStores(db); - var versionTransaction = setVersionRequest.result; - versionTransaction.oncomplete = function() { handler(db); }; - versionTransaction.onerror = onError; - }; - } else { - handler(db); - } - }; -} - -// You must close all database connections before calling this. -function alterObjectStores( - name, objectStoreNames, func, handler, errorHandler) { - var version = curVersion + 1; - var openRequest = indexedDB.open(name, version); - openRequest.onblocked = errorHandler; - openRequest.onupgradeneeded = function(ev) { - doAlteration(ev.target.transaction); - // onsuccess will get called after this exits. - }; - openRequest.onsuccess = function(ev) { - assert(openRequest == ev.target); - var db = openRequest.result; - db.onerror = function(ev) { - console.log("error altering db", arguments, - openRequest.error.message); - errorHandler(); - }; - if (db.version != version) { - // This is the legacy path, which runs only in Chrome before M23. - var setVersionRequest = db.setVersion(version); - setVersionRequest.onerror = errorHandler; - setVersionRequest.onsuccess = - function(e) { - curVersion = db.version; - assert(setVersionRequest == e.target); - var versionTransaction = setVersionRequest.result; - versionTransaction.oncomplete = function() { handler(db); }; - versionTransaction.onerror = onError; - doAlteration(versionTransaction); - }; - } else { - handler(db); - } - }; - function doAlteration(target) { - for (var store in objectStoreNames) { - func(target.objectStore(objectStoreNames[store])); - } - } -} - -function getTransaction(db, objectStoreNames, mode, opt_handler) { - var transaction = db.transaction(objectStoreNames, mode); - transaction.onerror = onError; - transaction.onabort = onError; - if (opt_handler) { - transaction.oncomplete = opt_handler; - } - return transaction; -} - -function deleteDatabase(name, opt_handler) { - var deleteRequest = indexedDB.deleteDatabase(name); - deleteRequest.onerror = onError; - deleteRequest.onblocked = onError; - if (opt_handler) { - deleteRequest.onsuccess = opt_handler; - } -} - -function getCompletionFunc(db, testName, startTime, onTestComplete) { - function onDeleted() { - automation.setStatus("Deleted database."); - onTestComplete(); - } - return function() { - var duration = window.performance.now() - startTime; - // Ignore the cleanup time for this test. - automation.addResult(testName, duration); - automation.setStatus("Deleting database."); - db.close(); - deleteDatabase(testName, onDeleted); - }; -} - -function getDisplayName(args) { - function functionName(f) { - // Function.prototype.name is nonstandard, and not implemented in IE10- - return f.name || f.toString().match(/^function\s*([^(\s]*)/)[1]; - } - // The last arg is the completion callback the test runner tacks on. - // TODO(ericu): Make test errors delete the database automatically. - return functionName(getDisplayName.caller) + (args.length > 1 ? "_" : "") + - Array.prototype.slice.call(args, 0, args.length - 1).join("_"); -} - -// Pad a string [or object convertible to a string] to a fixed width; use this -// to have numeric strings sort properly. -function padToWidth(s, width) { - s = String(s); - assert(s.length <= width); - if (s.length < width) { - s = stringOfLength(width - s.length, '0') + s; - } - return s; -} - -function stringOfLength(n, c) { - if (c == null) - c = 'X'; - assert(n > 0); - assert(n == Math.floor(n)); - return new Array(n + 1).join(c); -} - -function getSimpleKey(i) { - return "key " + padToWidth(i, 10); -} - -function getSimpleValue(i) { - return "value " + padToWidth(i, 10); -} - -function getIndexableValue(i) { - return { id: getSimpleValue(i) }; -} - -function getForwardIndexKey(i) { - return i; -} - -function getBackwardIndexKey(i) { - return -i; -} - -// This is useful for indexing by keypath; the two names should be ordered in -// opposite directions for all i in uint32 range. -function getObjectValue(i) { - return { - firstName: getForwardIndexKey(i), - lastName: getBackwardIndexKey(i) - }; -} - -function getNFieldName(k) { - return "field" + k; -} - -function getNFieldObjectValue(i, n) { - assert(Math.floor(n) == n); - assert(n > 0); - var o = {}; - for (; n > 0; --n) { - // The value varies per field, each object will tend to be unique, - // and thanks to the modulus, indexing on different fields will give you - // different ordering for large-enough data sets. - o[getNFieldName(n - 1)] = Math.pow(i + 0.5, n + 0.5) % 65536; - } - return o; -} - -function putLinearValues( - transaction, objectStoreNames, numKeys, getKey, getValue) { - if (!getKey) - getKey = getSimpleKey; - if (!getValue) - getValue = getSimpleValue; - for (var i in objectStoreNames) { - var os = transaction.objectStore(objectStoreNames[i]); - for (var j = 0; j < numKeys; ++j) { - var request = os.put(getValue(j), getKey(j)); - request.onerror = onError; - } - } -} - -function verifyResultNonNull(result) { - assert(result != null); -} - -function getRandomValues( - transaction, objectStoreNames, numReads, numKeys, indexName, getKey) { - if (!getKey) - getKey = getSimpleKey; - for (var i in objectStoreNames) { - var os = transaction.objectStore(objectStoreNames[i]); - var source = os; - if (indexName) - source = source.index(indexName); - for (var j = 0; j < numReads; ++j) { - var rand = Math.floor(random() * numKeys); - var request = source.get(getKey(rand)); - request.onerror = onError; - request.onsuccess = verifyResultNonNull; - } - } -} - -function putRandomValues( - transaction, objectStoreNames, numPuts, numKeys, getKey, getValue) { - if (!getKey) - getKey = getSimpleKey; - if (!getValue) - getValue = getSimpleValue; - for (var i in objectStoreNames) { - var os = transaction.objectStore(objectStoreNames[i]); - for (var j = 0; j < numPuts; ++j) { - var rand = Math.floor(random() * numKeys); - var request = os.put(getValue(rand), getKey(rand)); - request.onerror = onError; - } - } -} - -function getSpecificValues(transaction, objectStoreNames, indexName, keys) { - for (var i in objectStoreNames) { - var os = transaction.objectStore(objectStoreNames[i]); - var source = os; - if (indexName) - source = source.index(indexName); - for (var j = 0; j < keys.length; ++j) { - var request = source.get(keys[j]); - request.onerror = onError; - request.onsuccess = verifyResultNonNull; - } - } -} - -// getKey should be deterministic, as we assume that a cursor that starts at -// getKey(X) and runs through getKey(X + K) has exactly K values available. -// This is annoying to guarantee generally when using an index, so we avoid both -// ends of the key space just in case and use simple indices. -// TODO(ericu): Figure out if this can be simplified and we can remove uses of -// getObjectValue in favor of getNFieldObjectValue. -function getValuesFromCursor( - transaction, inputObjectStoreName, numReads, numKeys, indexName, getKey, - readKeysOnly, outputObjectStoreName) { - assert(2 * numReads < numKeys); - if (!getKey) - getKey = getSimpleKey; - var rand = Math.floor(random() * (numKeys - 2 * numReads)) + numReads; - var values = []; - var queryObject = transaction.objectStore(inputObjectStoreName); - assert(queryObject); - if (indexName) - queryObject = queryObject.index(indexName); - var keyRange = IDBKeyRange.bound( - getKey(rand), getKey(rand + numReads), false, true); - var request; - if (readKeysOnly) { - request = queryObject.openKeyCursor(keyRange); - } else { - request = queryObject.openCursor(keyRange); - } - var oos; - if (outputObjectStoreName) - oos = transaction.objectStore(outputObjectStoreName); - var numReadsLeft = numReads; - request.onsuccess = function(event) { - var cursor = event.target.result; - if (cursor) { - assert(numReadsLeft); - --numReadsLeft; - if (oos) - // Put in random order for maximum difficulty. We add in numKeys just - // in case we're writing back to the same store; this way we won't - // affect the number of keys available to the cursor, since we're always - // outside its range. - oos.put(cursor.value, numKeys + random()); - values.push({key: cursor.key, value: cursor.value}); - cursor.continue(); - } else { - assert(!numReadsLeft); - } - }; - request.onerror = onError; -} - -function runTransactionBatch(db, count, batchFunc, objectStoreNames, mode, - onComplete) { - var numTransactionsRunning = 0; - - runOneBatch(db); - - function runOneBatch(db) { - if (count <= 0) { - return; - } - --count; - ++numTransactionsRunning; - var transaction = getTransaction(db, objectStoreNames, mode, - function() { - assert(!--numTransactionsRunning); - if (count <= 0) { - onComplete(); - } else { - runOneBatch(db); - } - }); - - batchFunc(transaction); - } -} - -// Use random() instead of Math.random() so runs are repeatable. -var random = (function(seed) { - - // Implementation of: http://www.burtleburtle.net/bob/rand/smallprng.html - function uint32(x) { return x >>> 0; } - function rot(x, k) { return (x << k) | (x >> (32 - k)); } - - function SmallPRNG(seed) { - seed = uint32(seed); - this.a = 0xf1ea5eed; - this.b = this.c = this.d = seed; - for (var i = 0; i < 20; ++i) - this.ranval(); - } - - SmallPRNG.prototype.ranval = function() { - var e = uint32(this.a - rot(this.b, 27)); - this.a = this.b ^ rot(this.c, 17); - this.b = uint32(this.c + this.d); - this.c = uint32(this.d + e); - this.d = uint32(e + this.a); - return this.d; - }; - - var prng = new SmallPRNG(seed); - return function() { return prng.ranval() / 0x100000000; }; -}(0));
diff --git a/tools/perf/page_sets/indexeddb_perf/perf_test.html b/tools/perf/page_sets/indexeddb_perf/perf_test.html deleted file mode 100644 index c368ced..0000000 --- a/tools/perf/page_sets/indexeddb_perf/perf_test.html +++ /dev/null
@@ -1,14 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <title>IndexedDB perf test first try</title> - <meta charset="UTF-8"> - <script type="text/javascript" src="perf_shared.js"></script> - <script type="text/javascript" src="perf_test.js"></script> - </head> - <body> - <div id="status">Starting...</div> - <div id="results"></div> - </body> -</html> -
diff --git a/tools/perf/page_sets/indexeddb_perf/perf_test.js b/tools/perf/page_sets/indexeddb_perf/perf_test.js deleted file mode 100644 index 2569a5c..0000000 --- a/tools/perf/page_sets/indexeddb_perf/perf_test.js +++ /dev/null
@@ -1,723 +0,0 @@ -// Copyright 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. - -var overallTestStartTime = window.performance.now(); -var kUseIndex = true; -var kDontUseIndex = false; -var kReadKeysOnly = true; -var kReadDataToo = false; -var kWriteToo = true; -var kDontWrite = false; -var kWriteSameStore = true; -var kWriteDifferentStore = false; -var kPlaceholderArg = false; -var kDontRead = false; -var kAlternateWithReads = true; - -var tests = [ -// Create 30 databases, populate them with 20 object stores with 10 items -// each, and then open them 60 times. Each item is 100 bytes long. - [testCreateAndDeleteDatabases, 30, 60, 10, 20, 100], -// Create a single small item in a single object store, then delete everything. - [testCreateAndDeleteDatabase, 1, 1, 1], -// Create many small items in a single object store, then delete everything. - [testCreateAndDeleteDatabase, 1000, 1, 1], -// Create a single small item in many object stores, then delete everything. - [testCreateAndDeleteDatabase, 1, 1000, 1], -// Create many large items in a single object store, then delete everything. - [testCreateAndDeleteDatabase, 1000, 1, 10000], -// Create a single small item in a single object store. - [testCreateKeysInStores, 1, 1, 1], -// Create many small items in a single object store. - [testCreateKeysInStores, 1000, 1, 1], -// Create a single small item in many object stores. - [testCreateKeysInStores, 1, 1000, 1], -// Create many large items in a single object store. - [testCreateKeysInStores, 1000, 1, 10000], - -// Read one item per transaction. - [testRandomReadsAndWritesWithoutIndex, 1000, 1, 0, 1000], -// Read a few random items in each of many transactions. - [testRandomReadsAndWritesWithoutIndex, 1000, 5, 0, 100], -// Read many random items in each of a few transactions. - [testRandomReadsAndWritesWithoutIndex, 1000, 500, 0, 5], -// Read many random items in each of a few transactions, in a large store. - [testRandomReadsAndWritesWithoutIndex, 10000, 500, 0, 5], -// Read and write a few random items in each of many transactions. - [testRandomReadsAndWritesWithoutIndex, 1000, 5, 5, 50], - -// Read one item per transaction. - [testRandomReadsAndWritesWithIndex, 1000, 1, 0, 1000], -// Read a few random items from an index, in each of many transactions. - [testRandomReadsAndWritesWithIndex, 1000, 5, 0, 100], -// Read many random items from an index, in each of a few transactions. - [testRandomReadsAndWritesWithIndex, 1000, 500, 0, 5], -// Read many random items from an index, in each of a few transactions, in a -// large store. - [testRandomReadsAndWritesWithIndex, 10000, 500, 0, 5], -// Read and write a few random items, reading from an index, in each of many -// transactions. - [testRandomReadsAndWritesWithIndex, 1000, 5, 5, 50], - -// Read a long, contiguous sequence of an object store via a cursor. - [testCursorReadsAndRandomWrites, kReadDataToo, kDontUseIndex, kDontWrite, - kPlaceholderArg], -// Read a sequence of an object store via a cursor, writing -// transformed values into another. - [testCursorReadsAndRandomWrites, kReadDataToo, kDontUseIndex, kWriteToo, - kWriteDifferentStore], -// Read a sequence of an object store via a cursor, writing -// transformed values into another. - [testCursorReadsAndRandomWrites, kReadDataToo, kDontUseIndex, kWriteToo, - kWriteSameStore], -// Read a sequence of an index into an object store via a cursor. - [testCursorReadsAndRandomWrites, kReadDataToo, kUseIndex, kDontWrite, - kPlaceholderArg], -// Read a sequence of an index into an object store via a key cursor. - [testCursorReadsAndRandomWrites, kReadKeysOnly, kUseIndex, kDontWrite, - kPlaceholderArg], - -// Make a small bunch of batches of reads of the same keys from an object store. - [testReadCacheWithoutIndex, 10], -// Make a bunch of batches of reads of the same keys from an object store. - [testReadCacheWithoutIndex, 50], -// Make a small bunch of batches of reads of the same keys from an object store. - [testReadCacheWithIndex, 10], -// Make a bunch of batches of reads of the same keys from an index. - [testReadCacheWithIndex, 50], - -// Create and delete an index on a store that already contains data [produces -// a timing result for each of creation and deletion]. - [testCreateAndDeleteIndex, 5000], -// Walk through multiple cursors into the same object store, round-robin, until -// you've reached the end of each of them. - [testWalkingMultipleCursors, 5], -// Walk through many cursors into the same object store, round-robin, until -// you've reached the end of each of them. - [testWalkingMultipleCursors, 50], -// Open an object store cursor, then continue(key) to the last value. - [testCursorSeeksWithoutIndex, 2000, 10, 4], -// Open an index key cursor, then continue(key) to the last value. - [testCursorSeeksWithIndex, 2000, 10, 4], -]; - - -function testRandomReadsAndWritesWithIndex( - numKeys, numReadsPerTransaction, numWritesPerTransaction, - numTransactions, onTestComplete) { - testRandomReadsAndWrites(numKeys, numReadsPerTransaction, - numWritesPerTransaction, - numTransactions, true, onTestComplete); -} - -function testRandomReadsAndWritesWithoutIndex( - numKeys, numReadsPerTransaction, numWritesPerTransaction, - numTransactions, onTestComplete) { - testRandomReadsAndWrites(numKeys, numReadsPerTransaction, - numWritesPerTransaction, - numTransactions, false, onTestComplete); -} - - -function testReadCacheWithIndex(numTransactions, onTestComplete) { - testReadCache(numTransactions, true, onTestComplete); -} - -function testReadCacheWithoutIndex(numTransactions, onTestComplete) { - testReadCache(numTransactions, false, onTestComplete) -} - -function testCursorSeeksWithIndex(numKeys, numSeeksPerTransaction, - numTransactions, onTestComplete) { - testCursorSeeks(numKeys, numSeeksPerTransaction, numTransactions, - true, onTestComplete); -} - -function testCursorSeeksWithoutIndex(numKeys, numSeeksPerTransaction, - numTransactions, onTestComplete) { - testCursorSeeks(numKeys, numSeeksPerTransaction, numTransactions, - false, onTestComplete); -} - - - -var currentTest = 0; -var testFilter; -var done = false; - -function test() { - done = false; - runNextTest(); -} - - -function runNextTest() { - var running_test, f; - while (currentTest < tests.length) { - running_test = tests[currentTest]; - f = running_test.shift(); - if (!testFilter || f.name == testFilter) - break; - ++currentTest; - } - - if (currentTest < tests.length) { - running_test.push(runNextTest); - f.apply(null, running_test); - ++currentTest; - } else { - onAllTestsComplete(); - } -} - -function onAllTestsComplete() { - var overallDuration = window.performance.now() - overallTestStartTime; - automation.addResult("OverallTestDuration", overallDuration); - automation.setDone(); - done = true; -} - -function testCreateAndDeleteDatabases( - numDatabases, numOpens, numKeys, numStores, - payloadLength, onTestComplete) { - var testName = getDisplayName(arguments); - assert(numOpens >= 1); - assert(numKeys >= 0); - assert(numStores >= 1); - var objectStoreNames = []; - for (var i=0; i < numStores; ++i) { - objectStoreNames.push("store " + i); - } - var value = stringOfLength(payloadLength); - function getValue() { - return value; - } - - automation.setStatus("Creating databases."); - var startTime = window.performance.now(); - - var numCreated = 0; - for (var i = 0; i < numDatabases; i++) { - createDatabase(testName + i, objectStoreNames, onCreated, onError); - } - - function onCreated(db) { - automation.setStatus("Constructing transactions."); - var transaction = - getTransaction(db, objectStoreNames, "readwrite", - function() { openLoop(db, numOpens); }); - putLinearValues(transaction, objectStoreNames, numKeys, null, getValue); - } - - function openLoop(db, timesLeft) { - db.close(); - if (timesLeft == 0) { - deleteDatabase(db.name, onDeleted); - return; - } - createDatabase(db.name, objectStoreNames, - function(db) { openLoop(db, timesLeft - 1); }, onError) - } - - var numDeleted = 0; - function onDeleted() { - var duration = window.performance.now() - startTime; - automation.addResult(testName, duration); - automation.setStatus("Deleted database."); - if (++numDeleted == numDatabases) { - onTestComplete(); - } - } -} - -function testCreateKeysInStores( - numKeys, numStores, payloadLength, onTestComplete) { - var testName = getDisplayName(arguments); - assert(numKeys >= 0); - assert(numStores >= 1); - var objectStoreNames = []; - for (var i=0; i < numStores; ++i) { - objectStoreNames.push("store " + i); - } - var value = stringOfLength(payloadLength); - function getValue() { - return value; - } - - automation.setStatus("Creating database."); - createDatabase(testName, objectStoreNames, onCreated, onError); - - function onCreated(db) { - automation.setStatus("Constructing transaction."); - var completionFunc = - getCompletionFunc(db, testName, window.performance.now(), - onTestComplete); - var transaction = - getTransaction(db, objectStoreNames, "readwrite", completionFunc); - putLinearValues(transaction, objectStoreNames, numKeys, null, getValue); - } -} - -// This is the only test that includes database creation and deletion in its -// results; the others just test specific operations. To see only the -// creation/deletion without the specific operations used to build up the data -// in the object stores here, subtract off the results of -// testCreateKeysInStores. -function testCreateAndDeleteDatabase( - numKeys, numStores, payloadLength, onTestComplete) { - var testName = getDisplayName(arguments); - assert(numKeys >= 0); - assert(numStores >= 1); - var objectStoreNames = []; - for (var i=0; i < numStores; ++i) { - objectStoreNames.push("store " + i); - } - var value = stringOfLength(payloadLength); - function getValue() { - return value; - } - - automation.setStatus("Creating database."); - var startTime = window.performance.now(); - - createDatabase(testName, objectStoreNames, onCreated, onError); - - function onCreated(db) { - automation.setStatus("Constructing transaction."); - var transaction = - getTransaction(db, objectStoreNames, "readwrite", - function() { onValuesWritten(db); }); - putLinearValues(transaction, objectStoreNames, numKeys, null, getValue); - } - - function onValuesWritten(db) { - automation.setStatus("Deleting database."); - db.close(); - deleteDatabase(testName, onDeleted); - } - - function onDeleted() { - var duration = window.performance.now() - startTime; - automation.addResult(testName, duration); - automation.setStatus("Deleted database."); - onTestComplete(); - } -} - -function testCreateKeysInStores( - numKeys, numStores, payloadLength, onTestComplete) { - var testName = getDisplayName(arguments); - assert(numKeys >= 0); - assert(numStores >= 1); - var objectStoreNames = []; - for (var i=0; i < numStores; ++i) { - objectStoreNames.push("store " + i); - } - var value = stringOfLength(payloadLength); - function getValue() { - return value; - } - - automation.setStatus("Creating database."); - createDatabase(testName, objectStoreNames, onCreated, onError); - - function onCreated(db) { - automation.setStatus("Constructing transaction."); - var completionFunc = - getCompletionFunc(db, testName, window.performance.now(), - onTestComplete); - var transaction = - getTransaction(db, objectStoreNames, "readwrite", completionFunc); - putLinearValues(transaction, objectStoreNames, numKeys, null, getValue); - } -} - -function testRandomReadsAndWrites( - numKeys, numReadsPerTransaction, numWritesPerTransaction, numTransactions, - useIndexForReads, onTestComplete) { - var indexName; - if (useIndexForReads) - indexName = "index"; - var testName = getDisplayName(arguments); - var objectStoreNames = ["store"]; - var getKey = getSimpleKey; - var getValue = useIndexForReads ? getIndexableValue : getSimpleValue; - - automation.setStatus("Creating database."); - var options; - if (useIndexForReads) { - options = [{ - indexName: indexName, - indexKeyPath: "id", - indexIsUnique: false, - indexIsMultiEntry: false, - }]; - } - createDatabase(testName, objectStoreNames, onCreated, onError, options); - - function onCreated(db) { - automation.setStatus("Setting up test database."); - var transaction = getTransaction(db, objectStoreNames, "readwrite", - function() { onSetupComplete(db); }); - putLinearValues(transaction, objectStoreNames, numKeys, null, - function() { return "test value"; }); - } - - function onSetupComplete(db) { - automation.setStatus("Setup complete."); - var completionFunc = - getCompletionFunc(db, testName, window.performance.now(), - onTestComplete); - var mode = "readonly"; - if (numWritesPerTransaction) - mode = "readwrite"; - runTransactionBatch(db, numTransactions, batchFunc, objectStoreNames, mode, - completionFunc); - } - - function batchFunc(transaction) { - getRandomValues(transaction, objectStoreNames, numReadsPerTransaction, - numKeys, indexName, getKey); - putRandomValues(transaction, objectStoreNames, numWritesPerTransaction, - numKeys, getKey, getValue); - } -} - -function testReadCache(numTransactions, useIndexForReads, onTestComplete) { - var numKeys = 10000; - var numReadsPerTransaction = 50; - var numTransactionsLeft = numTransactions; - var indexName; - if (useIndexForReads) - indexName = "index"; - var testName = getDisplayName(arguments); - var objectStoreNames = ["store"]; - var getKey = getSimpleKey; - var getValue = useIndexForReads ? getIndexableValue : getSimpleValue; - var keys = []; - - for (var i=0; i < numReadsPerTransaction; ++i) { - keys.push(getKey(Math.floor(random() * numKeys))); - } - - automation.setStatus("Creating database."); - var options; - if (useIndexForReads) { - options = [{ - indexName: indexName, - indexKeyPath: "id", - indexIsUnique: false, - indexIsMultiEntry: false, - }]; - } - createDatabase(testName, objectStoreNames, onCreated, onError, options); - - function onCreated(db) { - automation.setStatus("Setting up test database."); - var transaction = getTransaction(db, objectStoreNames, "readwrite", - function() { onSetupComplete(db); }); - putLinearValues(transaction, objectStoreNames, numKeys, getKey, - getValue); - } - - var completionFunc; - function onSetupComplete(db) { - automation.setStatus("Setup complete."); - completionFunc = - getCompletionFunc(db, testName, window.performance.now(), - onTestComplete); - runTransactionBatch(db, numTransactions, batchFunc, objectStoreNames, - "readonly", completionFunc); - } - - function batchFunc(transaction) { - getSpecificValues(transaction, objectStoreNames, indexName, keys); - } -} - -function testCreateAndDeleteIndex(numKeys, onTestComplete) { - var testName = getDisplayName(arguments); - var objectStoreNames = ["store"]; - - automation.setStatus("Creating database."); - createDatabase(testName, objectStoreNames, onCreated, onError); - - var startTime; - function onCreated(db) { - automation.setStatus("Initializing data."); - var transaction = getTransaction(db, objectStoreNames, "readwrite", - function() { onPopulated(db); }); - putLinearValues(transaction, objectStoreNames, numKeys, null, getValue); - } - - function getValue(i) { - return { firstName: i + " first name", lastName: i + " last name" }; - } - - function onPopulated(db) { - db.close(); - automation.setStatus("Building index."); - startTime = window.performance.now(); - var f = function(objectStore) { - objectStore.createIndex("index", "firstName", {unique: true}); - }; - alterObjectStores(testName, objectStoreNames, f, onIndexCreated, onError); - } - - var indexCreationCompleteTime; - function onIndexCreated(db) { - db.close(); - indexCreationCompleteTime = window.performance.now(); - automation.addResult("testCreateIndex", - indexCreationCompleteTime - startTime); - var f = function(objectStore) { - objectStore.deleteIndex("index"); - }; - automation.setStatus("Deleting index."); - alterObjectStores(testName, objectStoreNames, f, onIndexDeleted, onError); - } - - function onIndexDeleted(db) { - var duration = window.performance.now() - indexCreationCompleteTime; - // Ignore the cleanup time for this test. - automation.addResult("testDeleteIndex", duration); - automation.setStatus("Deleting database."); - db.close(); - deleteDatabase(testName, onDeleted); - } - - function onDeleted() { - automation.setStatus("Deleted database."); - onTestComplete(); - } -} - -function testCursorReadsAndRandomWrites( - readKeysOnly, useIndexForReads, writeAlso, sameStoreForWrites, - onTestComplete) { - // There's no key cursor unless you're reading from an index. - assert(useIndexForReads || !readKeysOnly); - // If we're writing to another store, having an index would constrain our - // writes, as we create both object stores with the same configurations. - // We could do that if needed, but it's simpler not to. - assert(!useIndexForReads || !writeAlso); - var numKeys = 10000; - var numReadsPerTransaction = 1000; - var testName = getDisplayName(arguments); - var objectStoreNames = ["input store"]; - var outputStoreName; - if (writeAlso) { - if (sameStoreForWrites) { - outputStoreName = objectStoreNames[0]; - } else { - outputStoreName = "output store"; - objectStoreNames.push(outputStoreName); - } - } - var getKeyForRead = getSimpleKey; - var indexName; - if (useIndexForReads) { - indexName = "index"; - getKeyForRead = function(i) { - // This depends on the implementations of getValuesFromCursor and - // getObjectValue. We reverse the order of the iteration here so that - // setting up bounds from k to k+n with n>0 works. Without this reversal, - // the upper bound is below the lower bound. - return getBackwardIndexKey(numKeys - i); - }; - } - - automation.setStatus("Creating database."); - var options; - if (useIndexForReads) { - options = [{ - indexName: indexName, - indexKeyPath: "lastName", // depends on getBackwardIndexKey() - indexIsUnique: true, - indexIsMultiEntry: false, - }]; - } - createDatabase(testName, objectStoreNames, onCreated, onError, options); - - function onCreated(db) { - automation.setStatus("Setting up test database."); - var transaction = getTransaction(db, objectStoreNames, "readwrite", - function() { onSetupComplete(db); }); - putLinearValues(transaction, objectStoreNames, numKeys, getSimpleKey, - getObjectValue); - } - function onSetupComplete(db) { - automation.setStatus("Setup complete."); - var completionFunc = - getCompletionFunc(db, testName, window.performance.now(), - onTestComplete); - var mode = "readonly"; - if (writeAlso) - mode = "readwrite"; - var transaction = - getTransaction(db, objectStoreNames, mode, completionFunc); - - getValuesFromCursor( - transaction, objectStoreNames[0], numReadsPerTransaction, numKeys, - indexName, getKeyForRead, readKeysOnly, outputStoreName); - } -} - -function testWalkingMultipleCursors(numCursors, onTestComplete) { - var numKeys = 1000; - var numHitsPerKey = 10; - var testName = getDisplayName(arguments); - var objectStoreNames = ["input store"]; - var indexName = "index name"; - var getKey = getSimpleKey; - var getValue = getIndexableValue; - - automation.setStatus("Creating database."); - var options = [{ - indexName: indexName, - indexKeyPath: "id", - indexIsUnique: false, - indexIsMultiEntry: false, - }]; - createDatabase(testName, objectStoreNames, onCreated, onError, options); - - function onCreated(db) { - automation.setStatus("Setting up test database."); - var transaction = getTransaction(db, objectStoreNames, "readwrite", - function() { onSetupComplete(db); }); - // This loop adds the same value numHitsPerKey times for each key. - for (var i = 0; i < numHitsPerKey; ++i) { - putLinearValues(transaction, objectStoreNames, numKeys, getKeyFunc(i), - getValue); - } - } - // While the value is the same each time through the putLinearValues loop, we - // want the key to keep increaasing for each copy. - function getKeyFunc(k) { - return function(i) { - return getKey(k * numKeys + i); - }; - } - var completionFunc; - function onSetupComplete(db) { - automation.setStatus("Setup complete."); - completionFunc = - getCompletionFunc(db, testName, window.performance.now(), - onTestComplete); - var transaction = - getTransaction(db, objectStoreNames, "readonly", verifyComplete); - - walkSeveralCursors(transaction, numKeys); - } - var responseCounts = []; - var cursorsRunning = numCursors; - function walkSeveralCursors(transaction, numKeys) { - var source = transaction.objectStore(objectStoreNames[0]).index(indexName); - var requests = []; - var continueCursorIndex = 0; - for (var i = 0; i < numCursors; ++i) { - var rand = Math.floor(random() * numKeys); - // Since we have numHitsPerKey copies of each value in the database, - // IDBKeyRange.only will return numHitsPerKey results, each referring to a - // different key with the matching value. - var request = source.openCursor(IDBKeyRange.only(getSimpleValue(rand))); - responseCounts.push(0); - request.onerror = onError; - request.onsuccess = function(event) { - assert(cursorsRunning); - var request = event.target; - if (!("requestIndex" in request)) { - assert(requests.length < numCursors); - request.requestIndex = requests.length; - requests.push(request); - } - var cursor = event.target.result; - if (cursor) { - assert(responseCounts[request.requestIndex] < numHitsPerKey); - ++responseCounts[request.requestIndex]; - } else { - assert(responseCounts[request.requestIndex] == numHitsPerKey); - --cursorsRunning; - } - if (cursorsRunning) { - if (requests.length == numCursors) { - requests[continueCursorIndex++].result.continue(); - continueCursorIndex %= numCursors; - } - } - }; - } - } - function verifyComplete() { - assert(!cursorsRunning); - completionFunc(); - } -} - -function testCursorSeeks( - numKeys, numSeeksPerTransaction, numTransactions, useIndexForReads, - onTestComplete) { - var testName = getDisplayName(arguments); - var objectStoreNames = ["store"]; - var getKey = useIndexForReads ? getForwardIndexKey : getSimpleKey; - var indexName; - if (useIndexForReads) { - indexName = "index"; - } - - automation.setStatus("Creating database."); - var options; - if (useIndexForReads) { - options = [{ - indexName: indexName, - indexKeyPath: "firstName", - indexIsUnique: true, - indexIsMultiEntry: false, - }]; - } - createDatabase(testName, objectStoreNames, onCreated, onError, options); - - function onCreated(db) { - automation.setStatus("Setting up test database."); - var transaction = getTransaction(db, objectStoreNames, "readwrite", - function() { onSetupComplete(db); }); - putLinearValues(transaction, objectStoreNames, numKeys, getSimpleKey, - getObjectValue); - } - - function onSetupComplete(db) { - automation.setStatus("Setup complete."); - var completionFunc = - getCompletionFunc(db, testName, window.performance.now(), - onTestComplete); - var mode = "readonly"; - runTransactionBatch(db, numTransactions, batchFunc, objectStoreNames, mode, - completionFunc); - } - - function batchFunc(transaction) { - for (var i in objectStoreNames) { - var source = transaction.objectStore(objectStoreNames[i]); - if (useIndexForReads) - source = source.index(indexName); - for (var j = 0; j < numSeeksPerTransaction; ++j) { - randomSeek(source); - } - } - } - - function randomSeek(source) { - var request = useIndexForReads ? source.openKeyCursor() - : source.openCursor(); - var first = true; - request.onerror = onError; - request.onsuccess = function() { - var cursor = request.result; - if (cursor && first) { - first = false; - cursor.continue(getKey(numKeys - 1)); - } - }; - } -}
diff --git a/tools/perf/page_sets/intl_ar_fa_he.py b/tools/perf/page_sets/intl_ar_fa_he.py index 6b7988c..c329157 100644 --- a/tools/perf/page_sets/intl_ar_fa_he.py +++ b/tools/perf/page_sets/intl_ar_fa_he.py
@@ -43,8 +43,3 @@ for url in urls_list: for temp in cache_temperatures: self.AddStory(IntlArFaHePage(url, self, cache_temperature=temp)) - - -class IntlArFaHeStoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass
diff --git a/tools/perf/page_sets/intl_es_fr_pt-BR.py b/tools/perf/page_sets/intl_es_fr_pt-BR.py index a8f65ee0..753e296 100644 --- a/tools/perf/page_sets/intl_es_fr_pt-BR.py +++ b/tools/perf/page_sets/intl_es_fr_pt-BR.py
@@ -51,8 +51,3 @@ for url in urls_list: for temp in cache_temperatures: self.AddStory(IntlEsFrPtBrPage(url, self, cache_temperature=temp)) - - -class IntlEsFrPtBrStoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass
diff --git a/tools/perf/page_sets/intl_hi_ru.py b/tools/perf/page_sets/intl_hi_ru.py index 8f98a19c..fd40173 100644 --- a/tools/perf/page_sets/intl_hi_ru.py +++ b/tools/perf/page_sets/intl_hi_ru.py
@@ -52,7 +52,3 @@ for url in urls_list: for temp in cache_temperatures: self.AddStory(IntlHiRuPage(url, self, cache_temperature=temp)) - -class IntlHiRuStoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass
diff --git a/tools/perf/page_sets/intl_ja_zh.py b/tools/perf/page_sets/intl_ja_zh.py index fb1fdaeb..b5439795 100644 --- a/tools/perf/page_sets/intl_ja_zh.py +++ b/tools/perf/page_sets/intl_ja_zh.py
@@ -63,8 +63,3 @@ for url in urls_list: for temp in cache_temperatures: self.AddStory(IntlJaZhPage(url, self, cache_temperature=temp)) - - -class IntlJaZhStoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass
diff --git a/tools/perf/page_sets/intl_ko_th_vi.py b/tools/perf/page_sets/intl_ko_th_vi.py index c5b33f65..928b7245c 100644 --- a/tools/perf/page_sets/intl_ko_th_vi.py +++ b/tools/perf/page_sets/intl_ko_th_vi.py
@@ -57,8 +57,3 @@ for url in urls_list: for temp in cache_temperatures: self.AddStory(IntlKoThViPage(url, self, cache_temperature=temp)) - - -class IntlKoThViStoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - pass
diff --git a/tools/perf/page_sets/key_desktop_move_cases.py b/tools/perf/page_sets/key_desktop_move_cases.py index ee1b1639..e2e6ad4 100644 --- a/tools/perf/page_sets/key_desktop_move_cases.py +++ b/tools/perf/page_sets/key_desktop_move_cases.py
@@ -10,14 +10,12 @@ class KeyDesktopMoveCasesPage(page_module.Page): - def __init__(self, url, page_set, name='', credentials=None): + def __init__(self, url, page_set, name=''): if name == '': name = url super(KeyDesktopMoveCasesPage, self).__init__( url=url, page_set=page_set, name=name, - credentials_path='data/credentials.json', shared_page_state_class=shared_page_state.SharedDesktopPageState) - self.credentials = credentials class GmailMouseScrollPage(KeyDesktopMoveCasesPage): @@ -37,8 +35,7 @@ }''' def RunNavigateSteps(self, action_runner): - google_login.LoginGoogleAccount(action_runner, 'googletest', - self.credentials_path) + google_login.LoginGoogleAccount(action_runner, 'googletest') super(GmailMouseScrollPage, self).RunNavigateSteps(action_runner) action_runner.WaitForJavaScriptCondition( 'window.gmonkey !== undefined &&'
diff --git a/tools/perf/page_sets/key_mobile_sites_pages.py b/tools/perf/page_sets/key_mobile_sites_pages.py index 7b59144..9b52f75 100644 --- a/tools/perf/page_sets/key_mobile_sites_pages.py +++ b/tools/perf/page_sets/key_mobile_sites_pages.py
@@ -7,24 +7,30 @@ class KeyMobileSitesPage(page_module.Page): - def __init__(self, url, page_set, name='', tags=None): + def __init__(self, url, page_set, name='', tags=None, + extra_browser_args=None): if name == '': name = url super(KeyMobileSitesPage, self).__init__( - url=url, page_set=page_set, name=name, + url=url, + page_set=page_set, + name=name, shared_page_state_class=shared_page_state.SharedMobilePageState, - credentials_path='data/credentials.json', tags=tags) + tags=tags, + extra_browser_args=extra_browser_args) class CapitolVolkswagenPage(KeyMobileSitesPage): - """ Why: Typical mobile business site """ - def __init__(self, page_set): + def __init__(self, page_set, name='', extra_browser_args=None): super(CapitolVolkswagenPage, self).__init__( - url=('http://iphone.capitolvolkswagen.com/index.htm' - '#new-inventory_p_2Fsb-new_p_2Ehtm_p_3Freset_p_3DInventoryListing'), - page_set=page_set) + url=( + 'http://iphone.capitolvolkswagen.com/index.htm' + '#new-inventory_p_2Fsb-new_p_2Ehtm_p_3Freset_p_3DInventoryListing'), + page_set=page_set, + name=name, + extra_browser_args=extra_browser_args) def RunNavigateSteps(self, action_runner): super(CapitolVolkswagenPage, self).RunNavigateSteps(action_runner) @@ -33,16 +39,17 @@ 'document.body.scrollHeight > 2560') - class TheVergeArticlePage(KeyMobileSitesPage): - """ Why: Top tech blog """ - def __init__(self, page_set): + def __init__(self, page_set, name='', extra_browser_args=None): super(TheVergeArticlePage, self).__init__( - # pylint: disable=line-too-long - url='http://www.theverge.com/2012/10/28/3568746/amazon-7-inch-fire-hd-ipad-mini-ad-ballsy', - page_set=page_set) + # pylint: disable=line-too-long + url= + 'http://www.theverge.com/2012/10/28/3568746/amazon-7-inch-fire-hd-ipad-mini-ad-ballsy', + page_set=page_set, + name=name, + extra_browser_args=extra_browser_args) def RunNavigateSteps(self, action_runner): super(TheVergeArticlePage, self).RunNavigateSteps(action_runner) @@ -55,29 +62,31 @@ class CnnArticlePage(KeyMobileSitesPage): - """ Why: Top news site """ - def __init__(self, page_set): + def __init__(self, page_set, name='', extra_browser_args=None): super(CnnArticlePage, self).__init__( - # pylint: disable=line-too-long - url='http://www.cnn.com/2012/10/03/politics/michelle-obama-debate/index.html', - page_set=page_set) + # pylint: disable=line-too-long + url= + 'http://www.cnn.com/2012/10/03/politics/michelle-obama-debate/index.html', + page_set=page_set, + name=name, + extra_browser_args=extra_browser_args) def RunNavigateSteps(self, action_runner): super(CnnArticlePage, self).RunNavigateSteps(action_runner) action_runner.Wait(8) - class FacebookPage(KeyMobileSitesPage): - """ Why: #1 (Alexa global) """ - def __init__(self, page_set): + def __init__(self, page_set, name='', extra_browser_args=None): super(FacebookPage, self).__init__( - url='https://facebook.com/barackobama', - page_set=page_set) + url='https://facebook.com/barackobama', + page_set=page_set, + name=name, + extra_browser_args=extra_browser_args) def RunNavigateSteps(self, action_runner): super(FacebookPage, self).RunNavigateSteps(action_runner) @@ -87,13 +96,14 @@ class YoutubeMobilePage(KeyMobileSitesPage): - """ Why: #3 (Alexa global) """ - def __init__(self, page_set): + def __init__(self, page_set, name='', extra_browser_args=None): super(YoutubeMobilePage, self).__init__( - url='http://m.youtube.com/watch?v=9hBpF_Zj4OA', - page_set=page_set) + url='http://m.youtube.com/watch?v=9hBpF_Zj4OA', + page_set=page_set, + name=name, + extra_browser_args=extra_browser_args) def RunNavigateSteps(self, action_runner): super(YoutubeMobilePage, self).RunNavigateSteps(action_runner) @@ -102,14 +112,14 @@ class LinkedInPage(KeyMobileSitesPage): - """ Why: #12 (Alexa global),Public profile """ - def __init__(self, page_set): + def __init__(self, page_set, name='LinkedIn', extra_browser_args=None): super(LinkedInPage, self).__init__( - url='https://www.linkedin.com/in/linustorvalds', - page_set=page_set, - name='LinkedIn') + url='https://www.linkedin.com/in/linustorvalds', + page_set=page_set, + name=name, + extra_browser_args=extra_browser_args) def RunNavigateSteps(self, action_runner): super(LinkedInPage, self).RunNavigateSteps(action_runner) @@ -117,16 +127,16 @@ 'document.getElementById("profile-view-scroller") !== null') - class YahooAnswersPage(KeyMobileSitesPage): - """ Why: #1 Alexa reference """ - def __init__(self, page_set): + def __init__(self, page_set, name='', extra_browser_args=None): super(YahooAnswersPage, self).__init__( - # pylint: disable=line-too-long - url='http://answers.yahoo.com/question/index?qid=20110117024343AAopj8f', - page_set=page_set) + # pylint: disable=line-too-long + url='http://answers.yahoo.com/question/index?qid=20110117024343AAopj8f', + page_set=page_set, + name=name, + extra_browser_args=extra_browser_args) def RunNavigateSteps(self, action_runner): super(YahooAnswersPage, self).RunNavigateSteps(action_runner) @@ -134,51 +144,15 @@ action_runner.ClickElement(text='Other Answers (1 - 20 of 149)') -class GroupClonedPage(KeyMobileSitesPage): - - """ Why: crbug.com/172906 """ - - def __init__(self, page_set): - super(GroupClonedPage, self).__init__( - url='http://groupcloned.com', - page_set=page_set) - - - def RunNavigateSteps(self, action_runner): - super(GroupClonedPage, self).RunNavigateSteps(action_runner) - action_runner.Wait(5) - action_runner.WaitForJavaScriptCondition(''' - document.getElementById("element-19") !== null && - document.getElementById("element-19").contentDocument - .getElementById("element-22") !== null && - document.getElementById("element-19").contentDocument - .getElementsByClassName( - "container list-item gc-list-item stretched").length !== 0''') - - -class GroupClonedListImagesPage(KeyMobileSitesPage): - - """ Why: crbug.com/172906 """ - - def __init__(self, page_set): - super(GroupClonedListImagesPage, self).__init__( - url='http://groupcloned.com/test/list-images-variable/index.html', - page_set=page_set) - - def RunNavigateSteps(self, action_runner): - super(GroupClonedListImagesPage, self).RunNavigateSteps(action_runner) - action_runner.WaitForJavaScriptCondition( - 'document.getElementById("element-5") !== null') - - class GoogleNewsMobilePage(KeyMobileSitesPage): - """ Why: Google News: accelerated scrolling version """ - def __init__(self, page_set): + def __init__(self, page_set, name='', extra_browser_args=None): super(GoogleNewsMobilePage, self).__init__( - url='http://mobile-news.sandbox.google.com/news/pt1', - page_set=page_set) + url='http://mobile-news.sandbox.google.com/news/pt1', + page_set=page_set, + name=name, + extra_browser_args=extra_browser_args) def RunNavigateSteps(self, action_runner): super(GoogleNewsMobilePage, self).RunNavigateSteps(action_runner) @@ -187,31 +161,14 @@ 'NEWS_telemetryReady == true') -class GoogleNewsMobile2Page(KeyMobileSitesPage): - - """ - Why: Google News: this iOS version is slower than accelerated scrolling - """ - - def __init__(self, page_set): - super(GoogleNewsMobile2Page, self).__init__( - url='http://mobile-news.sandbox.google.com/news/pt0', - page_set=page_set) - - def RunNavigateSteps(self, action_runner): - super(GoogleNewsMobile2Page, self).RunNavigateSteps(action_runner) - action_runner.WaitForJavaScriptCondition( - 'document.getElementById(":h") != null') - action_runner.Wait(1) - - class AmazonNicolasCagePage(KeyMobileSitesPage): - """ Why: #1 world commerce website by visits; #3 commerce in the US by time spent """ - def __init__(self, page_set): + def __init__(self, page_set, name='', extra_browser_args=None): super(AmazonNicolasCagePage, self).__init__( - url='http://www.amazon.com/gp/aw/s/ref=is_box_?k=nicolas+cage', - page_set=page_set) + url='http://www.amazon.com/gp/aw/s/ref=is_box_?k=nicolas+cage', + page_set=page_set, + name=name, + extra_browser_args=extra_browser_args)
diff --git a/tools/perf/page_sets/key_mobile_sites_smooth.py b/tools/perf/page_sets/key_mobile_sites_smooth.py index c836d86..f3997ac 100644 --- a/tools/perf/page_sets/key_mobile_sites_smooth.py +++ b/tools/perf/page_sets/key_mobile_sites_smooth.py
@@ -14,36 +14,47 @@ def _CreatePageClassWithSmoothInteractions(page_cls): + class DerivedSmoothPage(page_cls): # pylint: disable=no-init def RunPageInteractions(self, action_runner): _IssueMarkerAndScroll(action_runner) + return DerivedSmoothPage class KeyMobileSitesSmoothPage(page_module.Page): - def __init__(self, url, page_set, name='', tags=None, - action_on_load_complete=False): + def __init__(self, + url, + page_set, + name='', + tags=None, + action_on_load_complete=False, + extra_browser_args=None): if name == '': name = url super(KeyMobileSitesSmoothPage, self).__init__( - url=url, page_set=page_set, name=name, - credentials_path='data/credentials.json', tags=tags, - shared_page_state_class=shared_page_state.SharedMobilePageState) + url=url, + page_set=page_set, + name=name, + tags=tags, + shared_page_state_class=shared_page_state.SharedMobilePageState, + extra_browser_args=extra_browser_args) self.action_on_load_complete = action_on_load_complete def RunPageInteractions(self, action_runner): if self.action_on_load_complete: - action_runner.WaitForJavaScriptCondition( - 'document.readyState == "complete"', timeout=30) + action_runner.WaitForJavaScriptCondition( + 'document.readyState == "complete"', timeout=30) _IssueMarkerAndScroll(action_runner) class LinkedInSmoothPage(key_mobile_sites_pages.LinkedInPage): - def __init__(self, page_set): - super(LinkedInSmoothPage, self).__init__(page_set=page_set) + def __init__(self, page_set, name='', extra_browser_args=None): + super(LinkedInSmoothPage, self).__init__( + page_set=page_set, name=name, extra_browser_args=extra_browser_args) # Linkedin has expensive shader compilation so it can benefit from shader # cache from reload. @@ -55,10 +66,13 @@ class WowwikiSmoothPage(KeyMobileSitesSmoothPage): """Why: Mobile wiki.""" - def __init__(self, page_set): + + def __init__(self, page_set, name='', extra_browser_args=None): super(WowwikiSmoothPage, self).__init__( - url='http://www.wowwiki.com/World_of_Warcraft:_Mists_of_Pandaria', - page_set=page_set) + url='http://www.wowwiki.com/World_of_Warcraft:_Mists_of_Pandaria', + page_set=page_set, + name=name, + extra_browser_args=extra_browser_args) # Wowwiki has expensive shader compilation so it can benefit from shader # cache from reload. @@ -68,46 +82,7 @@ super(WowwikiSmoothPage, self).RunNavigateSteps(action_runner) -class GroupClonedSmoothPage(key_mobile_sites_pages.GroupClonedPage): - - def RunPageInteractions(self, action_runner): - with action_runner.CreateGestureInteraction('ScrollAction'): - action_runner.ScrollPage( - distance_expr=''' - Math.max(0, 1250 + document.getElementById("element-19") - .contentDocument - .getElementById("element-22") - .getBoundingClientRect().top);''', - use_touch=True) - - -class GroupClonedListImagesPage( - key_mobile_sites_pages.GroupClonedListImagesPage): - - def RunPageInteractions(self, action_runner): - with action_runner.CreateGestureInteraction('ScrollAction'): - action_runner.ScrollPage( - distance_expr=''' - Math.max(0, 1250 + - document.getElementById("element-5") - .getBoundingClientRect().top);''', - use_touch=True) - -class GoogleNewsMobile2SmoothPage( - key_mobile_sites_pages.GoogleNewsMobile2Page): - - def RunPageInteractions(self, action_runner): - with action_runner.CreateGestureInteraction('ScrollAction'): - action_runner.ScrollElement( - element_function='document.getElementById(":5")', - distance_expr=''' - Math.max(0, 2500 + - document.getElementById(':h').getBoundingClientRect().top)''', - use_touch=True) - - -class AmazonNicolasCageSmoothPage( - key_mobile_sites_pages.AmazonNicolasCagePage): +class AmazonNicolasCageSmoothPage(key_mobile_sites_pages.AmazonNicolasCagePage): def RunPageInteractions(self, action_runner): with action_runner.CreateGestureInteraction('ScrollAction'): @@ -115,8 +90,8 @@ selector='#search', distance_expr='document.body.scrollHeight - window.innerHeight') -class CNNArticleSmoothPage( - key_mobile_sites_pages.CnnArticlePage): + +class CNNArticleSmoothPage(key_mobile_sites_pages.CnnArticlePage): def RunPageInteractions(self, action_runner): with action_runner.CreateGestureInteraction('ScrollAction'): @@ -124,166 +99,159 @@ # will not be in the root scroller. action_runner.ScrollPage(top_start_ratio=0.01) -class KeyMobileSitesSmoothPageSet(story.StorySet): +class KeyMobileSitesSmoothPageSet(story.StorySet): """ Key mobile sites with smooth interactions. """ def __init__(self): super(KeyMobileSitesSmoothPageSet, self).__init__( - archive_data_file='data/key_mobile_sites_smooth.json', - cloud_storage_bucket=story.PARTNER_BUCKET) - + archive_data_file='data/key_mobile_sites_smooth.json', + cloud_storage_bucket=story.PARTNER_BUCKET) # Add pages with predefined classes that contain custom navigation logic. predefined_page_classes = [ - key_mobile_sites_pages.CapitolVolkswagenPage, - key_mobile_sites_pages.TheVergeArticlePage, - key_mobile_sites_pages.FacebookPage, - key_mobile_sites_pages.YoutubeMobilePage, - key_mobile_sites_pages.YahooAnswersPage, - key_mobile_sites_pages.GoogleNewsMobilePage, + key_mobile_sites_pages.CapitolVolkswagenPage, + key_mobile_sites_pages.TheVergeArticlePage, + key_mobile_sites_pages.FacebookPage, + key_mobile_sites_pages.YoutubeMobilePage, + key_mobile_sites_pages.YahooAnswersPage, + key_mobile_sites_pages.GoogleNewsMobilePage, ] for page_class in predefined_page_classes: - self.AddStory( - _CreatePageClassWithSmoothInteractions(page_class)(self)) + self.AddStory(_CreatePageClassWithSmoothInteractions(page_class)(self)) self.AddStory( - _CreatePageClassWithSmoothInteractions(LinkedInSmoothPage)(self)) + _CreatePageClassWithSmoothInteractions(LinkedInSmoothPage)(self)) self.AddStory(WowwikiSmoothPage(self)) # Add pages with custom page interaction logic. - - # Page behaves non-deterministically, replaced with test version for now. - # self.AddStory(GroupClonedSmoothPage(self)) - # mean_input_event_latency cannot be tracked correctly for - # GroupClonedListImagesPage. - # See crbug.com/409086. - # self.AddStory(GroupClonedListImagesSmoothPage(self)) - self.AddStory(GoogleNewsMobile2SmoothPage(self)) - # Amazon's Nicolas Cage search is currently failing. Reenable it once it's - # not anymore. - # crbug.com/667432 - # self.AddStory(AmazonNicolasCageSmoothPage(self)) + self.AddStory(AmazonNicolasCageSmoothPage(self)) self.AddStory(CNNArticleSmoothPage(self)) # Add pages with custom tags. # Why: Top news site. - self.AddStory(KeyMobileSitesSmoothPage( - url='http://nytimes.com/', page_set=self, tags=['fastpath'])) + self.AddStory( + KeyMobileSitesSmoothPage( + url='http://nytimes.com/', page_set=self, tags=['fastpath'])) # Why: Image-heavy site. - self.AddStory(KeyMobileSitesSmoothPage( - url='http://cuteoverload.com', page_set=self, tags=['fastpath'])) + self.AddStory( + KeyMobileSitesSmoothPage( + url='http://cuteoverload.com', page_set=self, tags=['fastpath'])) # Why: #11 (Alexa global), google property; some blogger layouts # have infinite scroll but more interesting. - self.AddStory(KeyMobileSitesSmoothPage( - url='http://googlewebmastercentral.blogspot.com/', - page_set=self, name='Blogger')) + self.AddStory( + KeyMobileSitesSmoothPage( + url='http://googlewebmastercentral.blogspot.com/', + page_set=self, + name='Blogger')) # Why: #18 (Alexa global), Picked an interesting post """ - self.AddStory(KeyMobileSitesSmoothPage( - url='http://en.blog.wordpress.com/2012/09/04/freshly-pressed-editors-picks-for-august-2012/', - page_set=self, - name='Wordpress')) + self.AddStory( + KeyMobileSitesSmoothPage( + url= + 'http://en.blog.wordpress.com/2012/09/04/freshly-pressed-editors-picks-for-august-2012/', + page_set=self, + name='Wordpress')) # Why: #6 (Alexa) most visited worldwide, picked an interesting page - self.AddStory(KeyMobileSitesSmoothPage( - url='http://en.wikipedia.org/wiki/Wikipedia', - page_set=self, - name='Wikipedia (1 tab)')) + self.AddStory( + KeyMobileSitesSmoothPage( + url='http://en.wikipedia.org/wiki/Wikipedia', + page_set=self, + name='Wikipedia_(1_tab)')) # Why: Wikipedia page with a delayed scroll start - self.AddStory(KeyMobileSitesSmoothPage( - url='http://en.wikipedia.org/wiki/Wikipedia', - page_set=self, - name='Wikipedia (1 tab) - delayed scroll start', - action_on_load_complete=True)) + self.AddStory( + KeyMobileSitesSmoothPage( + url='http://en.wikipedia.org/wiki/Wikipedia', + page_set=self, + name='Wikipedia_(1_tab)-delayed_scroll_start', + action_on_load_complete=True)) # Why: #8 (Alexa global), picked an interesting page - # Forbidden (Rate Limit Exceeded) - # self.AddStory(KeyMobileSitesSmoothPage( - # url='http://twitter.com/katyperry', page_set=self, name='Twitter')) + self.AddStory( + KeyMobileSitesSmoothPage( + url='http://twitter.com/katyperry', page_set=self, name='Twitter')) # Why: #37 (Alexa global) """ - self.AddStory(KeyMobileSitesSmoothPage( - url='http://pinterest.com', - page_set=self, - name='Pinterest')) + self.AddStory( + KeyMobileSitesSmoothPage( + url='http://pinterest.com', page_set=self, name='Pinterest')) # Why: #1 sports. - # Fails often; crbug.com/249722' - # self.AddStory(KeyMobileSitesSmoothPage( - # url='http://espn.go.com', page_set=self, name='ESPN')) + self.AddStory( + KeyMobileSitesSmoothPage( + url='http://espn.go.com', page_set=self, name='ESPN')) + # Why: crbug.com/231413 - # Doesn't scroll; crbug.com/249736 - # self.AddStory(KeyMobileSitesSmoothPage( - # url='http://forecast.io', page_set=self)) + self.AddStory( + KeyMobileSitesSmoothPage(url='http://forecast.io', page_set=self)) + # Why: crbug.com/169827 - self.AddStory(KeyMobileSitesSmoothPage( - url='http://slashdot.org/', page_set=self, tags=['fastpath'])) + self.AddStory( + KeyMobileSitesSmoothPage( + url='http://slashdot.org/', page_set=self, tags=['fastpath'])) # Why: #5 Alexa news """ - self.AddStory(KeyMobileSitesSmoothPage( - url='http://www.reddit.com/r/programming/comments/1g96ve', - page_set=self, tags=['fastpath'])) + self.AddStory( + KeyMobileSitesSmoothPage( + url='http://www.reddit.com/r/programming/comments/1g96ve', + page_set=self, + tags=['fastpath'])) # Why: Problematic use of fixed position elements """ - self.AddStory(KeyMobileSitesSmoothPage( - url='http://www.boingboing.net', page_set=self, tags=['fastpath'])) + self.AddStory( + KeyMobileSitesSmoothPage( + url='http://www.boingboing.net', page_set=self, tags=['fastpath'])) # Add simple pages with no custom navigation logic or tags. urls_list = [ - # Why: Social; top Google property; Public profile; infinite scrolls. - 'https://plus.google.com/app/basic/110031535020051778989/posts?source=apppromo', - # Why: crbug.com/242544 - ('http://www.androidpolice.com/2012/10/03/rumor-evidence-mounts-that-an-' - 'lg-optimus-g-nexus-is-coming-along-with-a-nexus-phone-certification-' - 'program/'), - # Why: crbug.com/149958 - 'http://gsp.ro', - # Why: Top tech blog - 'http://theverge.com', - # Why: Top tech site - 'http://digg.com', - # Why: Top Google property; a Google tab is often open - 'https://www.google.co.uk/search?hl=en&q=barack+obama&cad=h', - # Why: #1 news worldwide (Alexa global) - 'http://news.yahoo.com', - # Why: #2 news worldwide - 'http://www.cnn.com', - # Why: #1 commerce website by time spent by users in US - 'http://shop.mobileweb.ebay.com/searchresults?kw=viking+helmet', - # Why: #1 Alexa recreation - 'http://www.booking.com/searchresults.html?src=searchresults&latitude=65.0500&longitude=25.4667', - # Why: Top tech blog - 'http://techcrunch.com', - # Why: #6 Alexa sports - 'http://mlb.com/', - # Why: #14 Alexa California - 'http://www.sfgate.com/', - # Why: Non-latin character set - 'http://worldjournal.com/', - # Why: #15 Alexa news - 'http://online.wsj.com/home-page', - # Why: Image-heavy mobile site - 'http://www.deviantart.com/', - # Why: Top search engine - ('http://www.baidu.com/s?wd=barack+obama&rsv_bp=0&rsv_spt=3&rsv_sug3=9&' - 'rsv_sug=0&rsv_sug4=3824&rsv_sug1=3&inputT=4920'), - # Why: Top search engine - 'http://www.bing.com/search?q=sloths', - # Why: Good example of poor initial scrolling - 'http://ftw.usatoday.com/2014/05/spelling-bee-rules-shenanigans' + # Why: Social; top Google property; Public profile; infinite scrolls. + 'https://plus.google.com/app/basic/110031535020051778989/posts?source=apppromo', + # Why: crbug.com/242544 + ('http://www.androidpolice.com/2012/10/03/rumor-evidence-mounts-that-an-' + 'lg-optimus-g-nexus-is-coming-along-with-a-nexus-phone-certification-' + 'program/'), + # Why: crbug.com/149958 + 'http://gsp.ro', + # Why: Top tech blog + 'http://theverge.com', + # Why: Top tech site + 'http://digg.com', + # Why: Top Google property; a Google tab is often open + 'https://www.google.co.uk/search?hl=en&q=barack+obama&cad=h', + # Why: #1 news worldwide (Alexa global) + 'http://news.yahoo.com', + # Why: #2 news worldwide + 'http://www.cnn.com', + # Why: #1 commerce website by time spent by users in US + 'http://shop.mobileweb.ebay.com/searchresults?kw=viking+helmet', + # Why: #1 Alexa recreation + 'http://www.booking.com/searchresults.html?src=searchresults&latitude=65.0500&longitude=25.4667', + # Why: Top tech blog + 'http://techcrunch.com', + # Why: #6 Alexa sports + 'http://mlb.com/', + # Why: #14 Alexa California + 'http://www.sfgate.com/', + # Why: Non-latin character set + 'http://worldjournal.com/', + # Why: #15 Alexa news + 'http://online.wsj.com/home-page', + # Why: Image-heavy mobile site + 'http://www.deviantart.com/', + # Why: Top search engine + ('http://www.baidu.com/s?wd=barack+obama&rsv_bp=0&rsv_spt=3&rsv_sug3=9&' + 'rsv_sug=0&rsv_sug4=3824&rsv_sug1=3&inputT=4920'), + # Why: Top search engine + 'http://www.bing.com/search?q=sloths', + # Why: Good example of poor initial scrolling + 'http://ftw.usatoday.com/2014/05/spelling-bee-rules-shenanigans' ] for url in urls_list: self.AddStory(KeyMobileSitesSmoothPage(url, self)) - - -class KeyMobileSitesSmoothStoryExpectations( - story.expectations.StoryExpectations): - def SetExpectations(self): - pass # No tests disabled.
diff --git a/tools/perf/page_sets/key_silk_cases.py b/tools/perf/page_sets/key_silk_cases.py index 92ad8880..70eed60 100644 --- a/tools/perf/page_sets/key_silk_cases.py +++ b/tools/perf/page_sets/key_silk_cases.py
@@ -19,7 +19,7 @@ if not name.startswith('http'): name = url.split('/')[-1] super(KeySilkCasesPage, self).__init__( - url=url, page_set=page_set, credentials_path = 'data/credentials.json', + url=url, page_set=page_set, shared_page_state_class=shared_page_state.SharedMobilePageState, name=name) self._run_no_page_interactions = run_no_page_interactions @@ -467,8 +467,6 @@ url='http://plus.google.com/app/basic/stream', page_set=page_set, run_no_page_interactions=run_no_page_interactions) - self.credentials = 'google' - def RunNavigateSteps(self, action_runner): super(Page22, self).RunNavigateSteps(action_runner) action_runner.WaitForJavaScriptCondition(
diff --git a/tools/perf/page_sets/loading_desktop.py b/tools/perf/page_sets/loading_desktop.py index dc4e8ff..648fb7c1 100644 --- a/tools/perf/page_sets/loading_desktop.py +++ b/tools/perf/page_sets/loading_desktop.py
@@ -22,7 +22,7 @@ if cache_temperatures is None: cache_temperatures = [ - cache_temperature_module.PCV1_COLD, cache_temperature_module.PCV1_WARM + cache_temperature_module.COLD, cache_temperature_module.WARM ] # Passed as (story, name) tuple. self.AddStories( @@ -106,5 +106,5 @@ for url, name in urls: for temp in cache_temperatures: self.AddStory(page_cycler_story.PageCyclerStory(url, self, - shared_page_state_class=shared_page_state.SharedMobilePageState, + shared_page_state_class=shared_page_state.SharedDesktopPageState, cache_temperature=temp, tags=tags, name=name))
diff --git a/tools/perf/page_sets/loading_mobile.py b/tools/perf/page_sets/loading_mobile.py index 1849edeb..7a7cab7 100644 --- a/tools/perf/page_sets/loading_mobile.py +++ b/tools/perf/page_sets/loading_mobile.py
@@ -16,7 +16,8 @@ Design doc: https://docs.google.com/document/d/1QKlZIoURAxZk-brrXsKYZl9O8ieqXht3ogeF9yLNFCI/edit """ - def __init__(self, cache_temperatures=None, traffic_settings=None): + def __init__(self, cache_temperatures=None, cache_temperatures_for_pwa=None, + traffic_settings=None): super(LoadingMobileStorySet, self).__init__( archive_data_file='data/loading_mobile.json', cloud_storage_bucket=story.PARTNER_BUCKET) @@ -24,6 +25,9 @@ if cache_temperatures is None: cache_temperatures = [cache_temperature_module.ANY] + if cache_temperatures_for_pwa is None: + cache_temperatures_for_pwa = [cache_temperature_module.ANY] + if traffic_settings is None: traffic_settings = [traffic_setting_module.NONE] @@ -87,45 +91,33 @@ 'FlipKart'), ('https://smp.suumo.jp/mansion/tokyo/sc_104/cond/?moreCond=1', 'Suumo'), - ('https://guitar-tuner.appspot.com', 'GuitarTuner'), - ('https://andreasbovens.github.io/inbox-attack/', - 'InboxAttack'), ('https://voice-memos.appspot.com', 'VoiceMemos'), ('https://dev.opera.com/', 'DevOpera'), - ('https://www.pokedex.org/', 'Pokedex'), - ('https://2048-opera-pwa.surge.sh/', '2048'), - ('https://jakearchibald.github.io/trained-to-thrill/', - 'TrainedToThrill'), - ('https://townwork.net', 'TownWork'), ('https://flipboard.com/topic/yoga', 'FlipBoard'), # TODO(rnephew): Record these. crbug.com/728882 # ('https://wiki-offline.jakearchibald.com/', # 'WikiOffline'), # ('https://busrouter.sg', 'BusRouter'), # ('https://airhorner.com', 'AirHorner'), - ], cache_temperatures, traffic_settings) + ], cache_temperatures_for_pwa, traffic_settings) self.AddStories(['tough_ttfmp'], [ ('http://www.localmoxie.com', 'LocalMoxie'), ('http://www.dawn.com', 'Dawn'), ('http://www.thairath.co.th', 'Thairath'), ('http://www.hashocean.com', 'HashOcean'), - ('http://www.163.com', '163'), ], cache_temperatures, traffic_settings) self.AddStories(['easy_ttfmp'], [ ('http://www.slideshare.net', 'SlideShare'), ('http://www.bradesco.com.br', 'Bradesco'), ('http://www.gsshop.com', 'GSShop'), - ('http://www.sbs.co.kr', 'SBS'), - ('http://www.futura-sciences.com', 'FuturaSciences'), ], cache_temperatures, traffic_settings) self.AddStories(['tough_tti'], [ ('http://www.thestar.com.my', 'TheStar'), ('http://www.58pic.com', '58Pic'), ('http://www.hongkiat.com', 'Hongkiat'), - ('http://www.ebs.in', 'EBS'), ('http://www.ibicn.com', 'IBI'), ], cache_temperatures, traffic_settings) @@ -133,8 +125,6 @@ ('http://www.dramaq.com.tw', 'Dramaq'), ('http://www.locanto.in', 'Locanto'), ('http://www.francetvinfo.fr', 'FranceTVInfo'), - ('http://www.gfk.com', 'GFK'), - ('http://www.mlsmatrix.com', 'MLSMatrix'), ], cache_temperatures, traffic_settings) def AddStories(self, tags, urls, cache_temperatures, traffic_settings):
diff --git a/tools/perf/page_sets/login_helpers/login_utils.py b/tools/perf/page_sets/login_helpers/login_utils.py index 710c415..fa7c76aa 100644 --- a/tools/perf/page_sets/login_helpers/login_utils.py +++ b/tools/perf/page_sets/login_helpers/login_utils.py
@@ -5,9 +5,13 @@ import json import os +from py_utils import cloud_storage + DEFAULT_CREDENTIAL_PATH = os.path.join( - os.path.dirname(__file__), os.path.pardir, 'data', 'credentials.json') + os.path.dirname(__file__), '..', 'data', 'credentials.json') + +DEFAULT_CREDENTIAL_BUCKET = cloud_storage.PUBLIC_BUCKET def GetAccountNameAndPassword(credential, @@ -22,6 +26,11 @@ A tuple (username, password) in which both are username and password strings. """ + if (credentials_path == DEFAULT_CREDENTIAL_PATH and not + os.path.exists(DEFAULT_CREDENTIAL_PATH)): + cloud_storage.GetIfChanged( + DEFAULT_CREDENTIAL_PATH, DEFAULT_CREDENTIAL_BUCKET) + with open(credentials_path, 'r') as f: credentials = json.load(f) c = credentials.get(credential)
diff --git a/tools/perf/page_sets/maps.py b/tools/perf/page_sets/maps.py index 8287904e1..1005857e 100644 --- a/tools/perf/page_sets/maps.py +++ b/tools/perf/page_sets/maps.py
@@ -2,65 +2,49 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import os + from telemetry.page import page as page_module from telemetry import story from page_sets import webgl_supported_shared_state +_MAPS_PERF_TEST_DIR = os.path.join(os.path.dirname(__file__), 'maps_perf_test') + class MapsPage(page_module.Page): """Google Maps benchmarks and pixel tests. - The Maps team gave us a build of their test. The only modification - to the test was to config.js, where the width and height query args - were set to 800 by 600. The WPR was recorded with: + The Maps team gave us a build of their test. The static files are stored in + //src/tools/perf/page_sets/maps_perf_test/. - tools/perf/record_wpr smoothness_maps --browser=system + Note: the file maps_perf_test/load_dataset is a large binary file (~3Mb), + hence we upload it to cloud storage & only check in the SHA1 hash. - This produced maps_???.wpr, maps_???.wpr.sha1 and maps.json. - - It's worth noting that telemetry no longer allows replaying a URL that - refers to localhost. If the recording was created for the locahost URL, one - can update the host name by running: - - web-page-replay/httparchive.py remap-host maps_004.wpr \ - localhost:8000 map-test - - (web-page-replay/ can be found in third_party/catapult/telemetry/third_party/) - - After updating the host name in the WPR archive, or recording a - newly-numbered WPR archive, please remember to update - content/test/gpu/gpu_tests/maps_integration_test.py (and potentially - its pixel expectations) as well. - - To upload the maps_???.wpr to cloud storage, one would run: - - depot_tools/upload_to_google_storage.py --bucket=chromium-telemetry \ - maps_???.wpr - """ + The command to upload it to cloud_storage is: + <path to depot_tools>/upload_to_google_storage.py \ + maps_perf_test/load_dataset --bucket=chromium-telemetry +""" def __init__(self, page_set): - url = 'http://map-test/performance.html' super(MapsPage, self).__init__( - url=url, + url='file://performance.html', + base_dir=_MAPS_PERF_TEST_DIR, page_set=page_set, shared_page_state_class=( webgl_supported_shared_state.WebGLSupportedSharedState), - name=url) + name='maps_perf_test') @property def skipped_gpus(self): # Skip this intensive test on low-end devices. crbug.com/464731 return ['arm'] - def RunNavigateSteps(self, action_runner): - super(MapsPage, self).RunNavigateSteps(action_runner) - action_runner.Wait(3) - def RunPageInteractions(self, action_runner): + action_runner.WaitForJavaScriptCondition('window.startTest !== undefined') + action_runner.EvaluateJavaScript('startTest()') with action_runner.CreateInteraction('MapAnimation'): - action_runner.WaitForJavaScriptCondition( - 'window.testMetrics != undefined', timeout=120) + action_runner.WaitForJavaScriptCondition('window.testDone', timeout=120) class MapsPageSet(story.StorySet): @@ -68,8 +52,6 @@ """ Google Maps examples """ def __init__(self): - super(MapsPageSet, self).__init__( - archive_data_file='data/maps.json', - cloud_storage_bucket=story.PUBLIC_BUCKET) + super(MapsPageSet,self).__init__(cloud_storage_bucket=story.PUBLIC_BUCKET) self.AddStory(MapsPage(self))
diff --git a/tools/perf/page_sets/maps_perf_test/config.js b/tools/perf/page_sets/maps_perf_test/config.js new file mode 100644 index 0000000..bfd3b4c7 --- /dev/null +++ b/tools/perf/page_sets/maps_perf_test/config.js
@@ -0,0 +1,4 @@ +// This file was generated by the _js_query_arg_file Skylark rule defined in +// maps/vectortown/performance/script/build_defs.bzl. + +var testConfig = "overridePixelRatio=1&title=chrome_smoothness_performancetest_config&nobudget=false&nodraw=false&noprefetch=true&viewport=basic&wait=true";
diff --git a/tools/perf/page_sets/maps_perf_test/load_dataset.sha1 b/tools/perf/page_sets/maps_perf_test/load_dataset.sha1 new file mode 100644 index 0000000..39495d8 --- /dev/null +++ b/tools/perf/page_sets/maps_perf_test/load_dataset.sha1
@@ -0,0 +1 @@ +e6bf26977c2fd80c18789d1f279d474096a7b0d1 \ No newline at end of file
diff --git a/tools/perf/page_sets/maps_perf_test/performance.html b/tools/perf/page_sets/maps_perf_test/performance.html new file mode 100644 index 0000000..bc4b498 --- /dev/null +++ b/tools/perf/page_sets/maps_perf_test/performance.html
@@ -0,0 +1,41 @@ +<!DOCTYPE html> +<html> + <head> + <title>Performance Test</title> + <script src="config.js"></script> + <script> + var saveTraceRegEx = /[?&]wtf=?([^&]*)/; + var saveTrace = + saveTraceRegEx.exec(testConfig) || saveTraceRegEx.exec(window.location.search); + + var needsTraceStart = false; + if (saveTrace && !window.wtf) { + needsTraceStart = true; + var wtfUrl = "https://tracing-framework.appspot.com/CURRENT/wtf_trace_web_js_compiled.js"; + if (saveTrace[1]) wtfUrl = saveTrace[1]; + document.write('<' + 'script type="text/javascript" src="' + wtfUrl + '"><' + '/script>'); + } + </script> + <style> + body #wtf-failed {display: none} + body.wtf-failed {background: red} + body.wtf-failed #wtf-failed {display: block; color: white} + </style> + </head> + <body> + <script src="tracked.js"></script> + <h1 id="wtf-failed">Failed to load tracing framework.</h1> + <script> + if (needsTraceStart && !window.wtf) { + document.body.className += "wtf-failed"; + } else { + var tracker = new Tracker(); + // Upload WTF traces to the metric tracker. + if (saveTrace) { + tracker.enableTracing(needsTraceStart, 'http-rel:/savetrace'); + } + tracker.run(); + } + </script> + </body> +</html>
diff --git a/tools/perf/page_sets/maps_perf_test/tracked.js b/tools/perf/page_sets/maps_perf_test/tracked.js new file mode 100644 index 0000000..e6c1cb6 --- /dev/null +++ b/tools/perf/page_sets/maps_perf_test/tracked.js
@@ -0,0 +1,1246 @@ +(function(){'use strict';for(var r,aa="function"==typeof Object.defineProperties?Object.defineProperty:function(a,b,c){a!=Array.prototype&&a!=Object.prototype&&(a[b]=c.value)},ba="undefined"!=typeof window&&window===this?this:"undefined"!=typeof global&&null!=global?global:this,da=["Math","sign"],fa=0;fa<da.length-1;fa++){var ia=da[fa];ia in ba||(ba[ia]={});ba=ba[ia]}var ka=da[da.length-1],la=ba[ka],na=la?la:function(a){a=Number(a);return 0===a||isNaN(a)?a:0<a?1:-1}; +na!=la&&null!=na&&aa(ba,ka,{configurable:!0,writable:!0,value:na});var oa=oa||{},x=this;function B(a){return void 0!==a}function pa(a){return"string"==typeof a}function qa(a){return"number"==typeof a}function ra(a){a=a.split(".");for(var b=x,c=0;c<a.length;c++)if(b=b[a[c]],null==b)return null;return b}function sa(){}function ta(a){a.pb=void 0;a.sc=function(){return a.pb?a.pb:a.pb=new a}} +function ua(a){var b=typeof a;if("object"==b)if(a){if(a instanceof Array)return"array";if(a instanceof Object)return b;var c=Object.prototype.toString.call(a);if("[object Window]"==c)return"object";if("[object Array]"==c||"number"==typeof a.length&&"undefined"!=typeof a.splice&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("splice"))return"array";if("[object Function]"==c||"undefined"!=typeof a.call&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("call"))return"function"}else return"null"; +else if("function"==b&&"undefined"==typeof a.call)return"object";return b}function va(a){return"array"==ua(a)}function xa(a){var b=ua(a);return"array"==b||"object"==b&&"number"==typeof a.length}function ya(a){return"function"==ua(a)}function za(a){var b=typeof a;return"object"==b&&null!=a||"function"==b}var Aa="closure_uid_"+(1E9*Math.random()>>>0),Ba=0;function Ca(a,b,c){return a.call.apply(a.bind,arguments)} +function Da(a,b,c){if(!a)throw Error();if(2<arguments.length){var d=Array.prototype.slice.call(arguments,2);return function(){var c=Array.prototype.slice.call(arguments);Array.prototype.unshift.apply(c,d);return a.apply(b,c)}}return function(){return a.apply(b,arguments)}}function D(a,b,c){Function.prototype.bind&&-1!=Function.prototype.bind.toString().indexOf("native code")?D=Ca:D=Da;return D.apply(null,arguments)} +function Ea(a,b){var c=Array.prototype.slice.call(arguments,1);return function(){var b=c.slice();b.push.apply(b,arguments);return a.apply(this,b)}}var E=Date.now||function(){return+new Date}; +function Fa(a){if(x.execScript)x.execScript(a,"JavaScript");else if(x.eval){if(null==Ha){try{x.eval("var _evalTest_ = 1;")}catch(d){}if("undefined"!=typeof x._evalTest_){try{delete x._evalTest_}catch(d){}Ha=!0}else Ha=!1}if(Ha)x.eval(a);else{var b=x.document,c=b.createElement("SCRIPT");c.type="text/javascript";c.defer=!1;c.appendChild(b.createTextNode(a));b.head.appendChild(c);b.head.removeChild(c)}}else throw Error("goog.globalEval not available");}var Ha=null; +function Ia(a,b){a=a.split(".");var c=x;a[0]in c||!c.execScript||c.execScript("var "+a[0]);for(var d;a.length&&(d=a.shift());)!a.length&&B(b)?c[d]=b:c[d]&&c[d]!==Object.prototype[d]?c=c[d]:c=c[d]={}}function F(a,b){function c(){}c.prototype=b.prototype;a.R=b.prototype;a.prototype=new c;a.prototype.constructor=a;a.Xf=function(a,c,f){for(var d=Array(arguments.length-2),e=2;e<arguments.length;e++)d[e-2]=arguments[e];return b.prototype[c].apply(a,d)}};function Ja(a){if(Error.captureStackTrace)Error.captureStackTrace(this,Ja);else{var b=Error().stack;b&&(this.stack=b)}a&&(this.message=String(a))}F(Ja,Error);Ja.prototype.name="CustomError";var Ka=Array.prototype.indexOf?function(a,b){return Array.prototype.indexOf.call(a,b,void 0)}:function(a,b){if(pa(a))return pa(b)&&1==b.length?a.indexOf(b,0):-1;for(var c=0;c<a.length;c++)if(c in a&&a[c]===b)return c;return-1},La=Array.prototype.lastIndexOf?function(a,b){return Array.prototype.lastIndexOf.call(a,b,a.length-1)}:function(a,b){var c=a.length-1;0>c&&(c=Math.max(0,a.length+c));if(pa(a))return pa(b)&&1==b.length?a.lastIndexOf(b,c):-1;for(;0<=c;c--)if(c in a&&a[c]===b)return c;return-1}, +Ma=Array.prototype.forEach?function(a,b,c){Array.prototype.forEach.call(a,b,c)}:function(a,b,c){for(var d=a.length,e=pa(a)?a.split(""):a,f=0;f<d;f++)f in e&&b.call(c,e[f],f,a)},Na=Array.prototype.filter?function(a,b){return Array.prototype.filter.call(a,b,void 0)}:function(a,b){for(var c=a.length,d=[],e=0,f=pa(a)?a.split(""):a,g=0;g<c;g++)if(g in f){var h=f[g];b.call(void 0,h,g,a)&&(d[e++]=h)}return d},Oa=Array.prototype.reduce?function(a,b,c){return Array.prototype.reduce.call(a,b,c)}:function(a, +b,c){var d=c;Ma(a,function(c,f){d=b.call(void 0,d,c,f,a)});return d},Pa=Array.prototype.some?function(a,b){return Array.prototype.some.call(a,b,void 0)}:function(a,b){for(var c=a.length,d=pa(a)?a.split(""):a,e=0;e<c;e++)if(e in d&&b.call(void 0,d[e],e,a))return!0;return!1},Qa=Array.prototype.every?function(a,b){return Array.prototype.every.call(a,b,void 0)}:function(a,b){for(var c=a.length,d=pa(a)?a.split(""):a,e=0;e<c;e++)if(e in d&&!b.call(void 0,d[e],e,a))return!1;return!0}; +function Ra(a){a:{var b=Sa;for(var c=a.length,d=pa(a)?a.split(""):a,e=0;e<c;e++)if(e in d&&b.call(void 0,d[e],e,a)){b=e;break a}b=-1}return 0>b?null:pa(a)?a.charAt(b):a[b]}function Ta(a,b){b=Ka(a,b);var c;(c=0<=b)&&Array.prototype.splice.call(a,b,1);return c}function Ua(a){return Array.prototype.concat.apply([],arguments)}function Va(a){var b=a.length;if(0<b){for(var c=Array(b),d=0;d<b;d++)c[d]=a[d];return c}return[]} +function Wa(a,b,c){return 2>=arguments.length?Array.prototype.slice.call(a,b):Array.prototype.slice.call(a,b,c)}function Xa(a,b){if(!xa(a)||!xa(b)||a.length!=b.length)return!1;for(var c=a.length,d=Ya,e=0;e<c;e++)if(!d(a[e],b[e]))return!1;return!0}function Za(a,b){return a>b?1:a<b?-1:0}function Ya(a,b){return a===b};var $a=String.prototype.trim?function(a){return a.trim()}:function(a){return/^[\s\xa0]*([\s\S]*?)[\s\xa0]*$/.exec(a)[1]}; +function ab(a,b){var c=0;a=$a(String(a)).split(".");b=$a(String(b)).split(".");for(var d=Math.max(a.length,b.length),e=0;0==c&&e<d;e++){var f=a[e]||"",g=b[e]||"";do{f=/(\d*)(\D*)(.*)/.exec(f)||["","","",""];g=/(\d*)(\D*)(.*)/.exec(g)||["","","",""];if(0==f[0].length&&0==g[0].length)break;c=bb(0==f[1].length?0:parseInt(f[1],10),0==g[1].length?0:parseInt(g[1],10))||bb(0==f[2].length,0==g[2].length)||bb(f[2],g[2]);f=f[3];g=g[3]}while(0==c)}return c}function bb(a,b){return a<b?-1:a>b?1:0};var cb;a:{var db=x.navigator;if(db){var eb=db.userAgent;if(eb){cb=eb;break a}}cb=""}function fb(a){return-1!=cb.indexOf(a)};function gb(a,b,c){for(var d in a)b.call(c,a[d],d,a)}var hb="constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf".split(" ");function ib(a,b){for(var c,d,e=1;e<arguments.length;e++){d=arguments[e];for(c in d)a[c]=d[c];for(var f=0;f<hb.length;f++)c=hb[f],Object.prototype.hasOwnProperty.call(d,c)&&(a[c]=d[c])}};function jb(){return(fb("Chrome")||fb("CriOS"))&&!fb("Edge")};function kb(){return fb("iPhone")&&!fb("iPod")&&!fb("iPad")};function lb(a){lb[" "](a);return a}lb[" "]=sa;function mb(a,b){var c=nb;return Object.prototype.hasOwnProperty.call(c,a)?c[a]:c[a]=b(a)};var ob=fb("Opera"),pb=fb("Trident")||fb("MSIE"),qb=fb("Edge"),rb=fb("Gecko")&&!(-1!=cb.toLowerCase().indexOf("webkit")&&!fb("Edge"))&&!(fb("Trident")||fb("MSIE"))&&!fb("Edge"),sb=-1!=cb.toLowerCase().indexOf("webkit")&&!fb("Edge"),tb=fb("Windows");function ub(){var a=x.document;return a?a.documentMode:void 0}var vb; +a:{var wb="",xb=function(){var a=cb;if(rb)return/rv:([^\);]+)(\)|;)/.exec(a);if(qb)return/Edge\/([\d\.]+)/.exec(a);if(pb)return/\b(?:MSIE|rv)[: ]([^\);]+)(\)|;)/.exec(a);if(sb)return/WebKit\/(\S+)/.exec(a);if(ob)return/(?:Version)[ \/]?(\S+)/.exec(a)}();xb&&(wb=xb?xb[1]:"");if(pb){var yb=ub();if(null!=yb&&yb>parseFloat(wb)){vb=String(yb);break a}}vb=wb}var zb=vb,nb={};function Ab(a){return mb(a,function(){return 0<=ab(zb,a)})}var Bb;var Cb=x.document; +Bb=Cb&&pb?ub()||("CSS1Compat"==Cb.compatMode?parseInt(zb,10):5):void 0;function Db(a){var b=x.onerror,c=!1;sb&&!Ab("535.3")&&(c=!c);x.onerror=function(d,e,f,g,h){b&&b(d,e,f,g,h);a({message:d,fileName:e,line:f,lineNumber:f,Zf:g,error:h});return c}};var Eb=[],Fb=[],Gb=!1;function Hb(a){Eb[Eb.length]=a;if(Gb)for(var b=0;b<Fb.length;b++)a(D(Fb[b].a,Fb[b]))};function Ib(){this.u=this.u;this.o=this.o}Ib.prototype.u=!1;Ib.prototype.O=function(){return this.u};Ib.prototype.$=function(){this.u||(this.u=!0,this.X())};function Jb(a,b){Kb(a,Ea(Lb,b))}function Kb(a,b){a.u?B(void 0)?b.call(void 0):b():(a.o||(a.o=[]),a.o.push(B(void 0)?D(b,void 0):b))}Ib.prototype.X=function(){if(this.o)for(;this.o.length;)this.o.shift()()};function Lb(a){a&&"function"==typeof a.$&&a.$()};var Mb;(Mb=!pb)||(Mb=9<=Number(Bb));var Nb=Mb,Ob=pb&&!Ab("9"),Pb=function(){if(!x.addEventListener||!Object.defineProperty)return!1;var a=!1,b=Object.defineProperty({},"passive",{get:function(){a=!0}});x.addEventListener("test",sa,b);x.removeEventListener("test",sa,b);return a}();function Qb(a,b){this.type=a;this.a=this.target=b;this.Re=!0}Qb.prototype.b=function(){this.Re=!1};function Rb(a,b){Qb.call(this,a?a.type:"");this.relatedTarget=this.a=this.target=null;this.button=this.screenY=this.screenX=this.clientY=this.clientX=0;this.key="";this.metaKey=this.shiftKey=this.altKey=this.ctrlKey=!1;this.pointerId=0;this.pointerType="";this.c=null;if(a){var c=this.type=a.type,d=a.changedTouches?a.changedTouches[0]:null;this.target=a.target||a.srcElement;this.a=b;if(b=a.relatedTarget){if(rb){a:{try{lb(b.nodeName);var e=!0;break a}catch(f){}e=!1}e||(b=null)}}else"mouseover"==c?b= +a.fromElement:"mouseout"==c&&(b=a.toElement);this.relatedTarget=b;null===d?(this.clientX=void 0!==a.clientX?a.clientX:a.pageX,this.clientY=void 0!==a.clientY?a.clientY:a.pageY,this.screenX=a.screenX||0,this.screenY=a.screenY||0):(this.clientX=void 0!==d.clientX?d.clientX:d.pageX,this.clientY=void 0!==d.clientY?d.clientY:d.pageY,this.screenX=d.screenX||0,this.screenY=d.screenY||0);this.button=a.button;this.key=a.key||"";this.ctrlKey=a.ctrlKey;this.altKey=a.altKey;this.shiftKey=a.shiftKey;this.metaKey= +a.metaKey;this.pointerId=a.pointerId||0;this.pointerType=pa(a.pointerType)?a.pointerType:Sb[a.pointerType]||"";this.c=a;a.defaultPrevented&&this.b()}}F(Rb,Qb);var Sb={2:"touch",3:"pen",4:"mouse"};Rb.prototype.b=function(){Rb.R.b.call(this);var a=this.c;if(a.preventDefault)a.preventDefault();else if(a.returnValue=!1,Ob)try{if(a.ctrlKey||112<=a.keyCode&&123>=a.keyCode)a.keyCode=-1}catch(b){}};var Tb="closure_listenable_"+(1E6*Math.random()|0);function Ub(a){return!(!a||!a[Tb])}var Vb=0;function Wb(a,b,c,d,e){this.listener=a;this.a=null;this.src=b;this.type=c;this.capture=!!d;this.ad=e;this.key=++Vb;this.fc=this.Vc=!1}function Xb(a){a.fc=!0;a.listener=null;a.a=null;a.src=null;a.ad=null};function Yb(a){this.src=a;this.a={};this.b=0}Yb.prototype.add=function(a,b,c,d,e){var f=a.toString();a=this.a[f];a||(a=this.a[f]=[],this.b++);var g=Zb(a,b,d,e);-1<g?(b=a[g],c||(b.Vc=!1)):(b=new Wb(b,this.src,f,!!d,e),b.Vc=c,a.push(b));return b};function $b(a,b){var c=b.type;if(!(c in a.a))return!1;var d=Ta(a.a[c],b);d&&(Xb(b),0==a.a[c].length&&(delete a.a[c],a.b--));return d}Yb.prototype.tc=function(a,b,c,d){a=this.a[a.toString()];var e=-1;a&&(e=Zb(a,b,c,d));return-1<e?a[e]:null}; +function Zb(a,b,c,d){for(var e=0;e<a.length;++e){var f=a[e];if(!f.fc&&f.listener==b&&f.capture==!!c&&f.ad==d)return e}return-1};var ac="closure_lm_"+(1E6*Math.random()|0),bc={},cc=0;function dc(a,b,c,d,e){if(d&&d.once)return ec(a,b,c,d,e);if(va(b)){for(var f=0;f<b.length;f++)dc(a,b[f],c,d,e);return null}c=fc(c);return Ub(a)?a.cb(b,c,za(d)?!!d.capture:!!d,e):gc(a,b,c,!1,d,e)} +function gc(a,b,c,d,e,f){if(!b)throw Error("Invalid event type");var g=za(e)?!!e.capture:!!e,h=hc(a);h||(a[ac]=h=new Yb(a));c=h.add(b,c,d,g,f);if(c.a)return c;d=ic();c.a=d;d.src=a;d.listener=c;if(a.addEventListener)Pb||(e=g),void 0===e&&(e=!1),a.addEventListener(b.toString(),d,e);else if(a.attachEvent)a.attachEvent(jc(b.toString()),d);else if(a.addListener&&a.removeListener)a.addListener(d);else throw Error("addEventListener and attachEvent are unavailable.");cc++;return c} +function ic(){var a=kc,b=Nb?function(c){return a.call(b.src,b.listener,c)}:function(c){c=a.call(b.src,b.listener,c);if(!c)return c};return b}function ec(a,b,c,d,e){if(va(b)){for(var f=0;f<b.length;f++)ec(a,b[f],c,d,e);return null}c=fc(c);return Ub(a)?a.cc(b,c,za(d)?!!d.capture:!!d,e):gc(a,b,c,!0,d,e)}function lc(a,b,c,d,e){if(va(b))for(var f=0;f<b.length;f++)lc(a,b[f],c,d,e);else d=za(d)?!!d.capture:!!d,c=fc(c),Ub(a)?a.Sd(b,c,d,e):a&&(a=hc(a))&&(b=a.tc(b,c,d,e))&&mc(b)} +function mc(a){if(qa(a)||!a||a.fc)return!1;var b=a.src;if(Ub(b))return $b(b.Cb,a);var c=a.type,d=a.a;b.removeEventListener?b.removeEventListener(c,d,a.capture):b.detachEvent?b.detachEvent(jc(c),d):b.addListener&&b.removeListener&&b.removeListener(d);cc--;(c=hc(b))?($b(c,a),0==c.b&&(c.src=null,b[ac]=null)):Xb(a);return!0}function nc(a){if(a)if(Ub(a))a.Ld(void 0);else if(a=hc(a)){var b=0,c;for(c in a.a)for(var d=a.a[c].concat(),e=0;e<d.length;++e)mc(d[e])&&++b}} +function jc(a){return a in bc?bc[a]:bc[a]="on"+a}function oc(a,b,c,d){var e=!0;if(a=hc(a))if(b=a.a[b.toString()])for(b=b.concat(),a=0;a<b.length;a++){var f=b[a];f&&f.capture==c&&!f.fc&&(f=pc(f,d),e=e&&!1!==f)}return e}function pc(a,b){var c=a.listener,d=a.ad||a.src;a.Vc&&mc(a);return c.call(d,b)} +function kc(a,b){if(a.fc)return!0;if(!Nb){var c=b||ra("window.event");b=new Rb(c,this);var d=!0;if(!(0>c.keyCode||void 0!=c.returnValue)){a:{var e=!1;if(0==c.keyCode)try{c.keyCode=-1;break a}catch(g){e=!0}if(e||void 0==c.returnValue)c.returnValue=!0}c=[];for(e=b.a;e;e=e.parentNode)c.push(e);a=a.type;for(e=c.length-1;0<=e;e--){b.a=c[e];var f=oc(c[e],a,!0,b);d=d&&f}for(e=0;e<c.length;e++)b.a=c[e],f=oc(c[e],a,!1,b),d=d&&f}return d}return pc(a,new Rb(b,this))} +function hc(a){a=a[ac];return a instanceof Yb?a:null}var qc="__closure_events_fn_"+(1E9*Math.random()>>>0);function fc(a){if(ya(a))return a;a[qc]||(a[qc]=function(b){return a.handleEvent(b)});return a[qc]}Hb(function(a){kc=a(kc)});function rc(){Ib.call(this);this.Cb=new Yb(this);this.kf=this;this.Ed=null}F(rc,Ib);rc.prototype[Tb]=!0;r=rc.prototype;r.addEventListener=function(a,b,c,d){dc(this,a,b,c,d)};r.removeEventListener=function(a,b,c,d){lc(this,a,b,c,d)}; +r.dispatchEvent=function(a){var b,c=this.Ed;if(c)for(b=[];c;c=c.Ed)b.push(c);c=this.kf;var d=a.type||a;if(pa(a))a=new Qb(a,c);else if(a instanceof Qb)a.target=a.target||c;else{var e=a;a=new Qb(d,c);ib(a,e)}e=!0;if(b)for(var f=b.length-1;0<=f;f--){var g=a.a=b[f];e=sc(g,d,!0,a)&&e}g=a.a=c;e=sc(g,d,!0,a)&&e;e=sc(g,d,!1,a)&&e;if(b)for(f=0;f<b.length;f++)g=a.a=b[f],e=sc(g,d,!1,a)&&e;return e};r.X=function(){rc.R.X.call(this);this.Ld();this.Ed=null}; +r.cb=function(a,b,c,d){return this.Cb.add(String(a),b,!1,c,d)};r.cc=function(a,b,c,d){return this.Cb.add(String(a),b,!0,c,d)};r.Sd=function(a,b,c,d){var e=this.Cb;a=String(a).toString();if(a in e.a){var f=e.a[a];b=Zb(f,b,c,d);-1<b&&(Xb(f[b]),Array.prototype.splice.call(f,b,1),0==f.length&&(delete e.a[a],e.b--))}};r.Ld=function(a){if(this.Cb){var b=this.Cb;a=a&&a.toString();var c=0,d;for(d in b.a)if(!a||d==a){for(var e=b.a[d],f=0;f<e.length;f++)++c,Xb(e[f]);delete b.a[d];b.b--}}}; +function sc(a,b,c,d){b=a.Cb.a[String(b)];if(!b)return!0;b=b.concat();for(var e=!0,f=0;f<b.length;++f){var g=b[f];if(g&&!g.fc&&g.capture==c){var h=g.listener,k=g.ad||g.src;g.Vc&&$b(a.Cb,g);e=!1!==h.call(k,d)&&e}}return e&&0!=d.Re}r.tc=function(a,b,c,d){return this.Cb.tc(String(a),b,c,d)};function tc(a){switch(a){case 5:case 3:case 13:case 4:case 17:case 18:case 8:case 14:case 31:return 0;case 1:case 6:case 16:case 30:return 1;case 9:case 11:case 12:return 2;case 2:case 7:case 15:return 5;default:return-1}};var uc=fb("Firefox"),vc=kb()||fb("iPod"),wc=fb("iPad"),xc=fb("Android")&&!(jb()||fb("Firefox")||fb("Opera")||fb("Silk")),yc=jb(),zc=fb("Safari")&&!(jb()||fb("Coast")||fb("Opera")||fb("Edge")||fb("Silk")||fb("Android"))&&!(kb()||fb("iPad")||fb("iPod"));var Ac=null,Bc=null,Cc=null;function Dc(a,b){Ec();b=b?Cc:Ac;for(var c=[],d=0;d<a.length;d+=3){var e=a[d],f=d+1<a.length,g=f?a[d+1]:0,h=d+2<a.length,k=h?a[d+2]:0,l=e>>2;e=(e&3)<<4|g>>4;g=(g&15)<<2|k>>6;k&=63;h||(k=64,f||(g=64));c.push(b[l],b[e],b[g],b[k])}return c.join("")}function Fc(a){var b=[];Gc(a,function(a){b.push(a)});return b} +function Hc(a){var b=a.length,c=0;"="===a[b-2]?c=2:"="===a[b-1]&&(c=1);var d=new Uint8Array(Math.ceil(3*b/4)-c),e=0;Gc(a,function(a){d[e++]=a});return d.subarray(0,e)}function Gc(a,b){function c(b){for(;d<a.length;){var c=a.charAt(d++),e=Bc[c];if(null!=e)return e;if(!/^[\s\xa0]*$/.test(c))throw Error("Unknown base64 encoding at char: "+c);}return b}Ec();for(var d=0;;){var e=c(-1),f=c(0),g=c(64),h=c(64);if(64===h&&-1===e)break;b(e<<2|f>>4);64!=g&&(b(f<<4&240|g>>2),64!=h&&b(g<<6&192|h))}} +function Ec(){if(!Ac){Ac={};Bc={};Cc={};for(var a=0;65>a;a++)Ac[a]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(a),Bc[Ac[a]]=a,Cc[a]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.".charAt(a),62<=a&&(Bc["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.".charAt(a)]=a)}};var Ic=0,Jc=0;function Kc(a,b){var c=b&2147483648;c&&(a=~a+1>>>0,b=~b>>>0,0==a&&(b=b+1>>>0));a=4294967296*b+a;return c?-a:a}function Lc(a,b){return String.fromCharCode(a>>>0&255,a>>>8&255,a>>>16&255,a>>>24&255,b>>>0&255,b>>>8&255,b>>>16&255,b>>>24&255)}var Mc="0123456789abcdef".split(""); +function Nc(a,b){function c(a){for(var b=1E7,c=0;7>c;c++){b/=10;var d=a/b%10>>>0;if(0!=d||f)f=!0,g+=e[d]}}if(2097151>=b)return""+(4294967296*b+a);var d=(a>>>24|b<<8)>>>0&16777215;b=b>>16&65535;a=(a&16777215)+6777216*d+6710656*b;d+=8147497*b;b*=2;1E7<=a&&(d+=Math.floor(a/1E7),a%=1E7);1E7<=d&&(b+=Math.floor(d/1E7),d%=1E7);var e=Mc,f=!1,g="";(b||f)&&c(b);(d||f)&&c(d);(a||f)&&c(a);return g} +function Oc(a,b){var c=a.charCodeAt(4),d=a.charCodeAt(5),e=a.charCodeAt(6),f=a.charCodeAt(7);Ic=a.charCodeAt(0)+(a.charCodeAt(1)<<8)+(a.charCodeAt(2)<<16)+(a.charCodeAt(3)<<24)>>>0;Jc=c+(d<<8)+(e<<16)+(f<<24)>>>0;c=Ic;a=Jc;if(b){b=c;c=a;if(a=c&2147483648)b=~b+1>>>0,c=~c+(0==b?1:0)>>>0;b=Nc(b,c);b=a?"-"+b:b}else b=Nc(c,a);return b}function Pc(a,b){for(var c=Array(a.length),d=0;d<a.length;d++)c[d]=Oc(a[d],b);return c};function Qc(a,b,c){this.c=this.h=this.a=null;this.g=0;this.b=null;this.f=!0;Rc(this,a,b,c)}function Rc(a,b,c,d){b&&c&&(a.a=b,a.h=c);a.c=d||null;a.g=0;a.b=null;a.f=!a.a&&!a.c;a.next()}var Sc=[];function Tc(a,b,c){if(Sc.length){var d=Sc.pop();Rc(d,a,b,c);return d}return new Qc(a,b,c)}function Uc(a){a.clear();100>Sc.length&&Sc.push(a)}Qc.prototype.clear=function(){this.a&&Vc(this.a);this.c=this.h=this.a=null;this.g=0;this.b=null;this.f=!0};Qc.prototype.get=function(){return this.b};Qc.prototype.kb=function(){return this.f}; +Qc.prototype.next=function(){var a=this.b;this.a?this.a.kb()?(this.b=null,this.f=!0):this.b=this.h.call(this.a):this.c&&(this.g==this.c.length?(this.b=null,this.f=!0):this.b=this.c[this.g++]);return a};function Wc(a,b,c){this.b=null;this.f=this.g=this.a=this.c=this.h=0;this.i=!1;a&&Xc(this,a,b,c)}var Yc=[];function Zc(a,b,c){if(Yc.length){var d=Yc.pop();a&&Xc(d,a,b,c);return d}return new Wc(a,b,c)}function Vc(a){a.clear();100>Yc.length&&Yc.push(a)}r=Wc.prototype; +r.clear=function(){this.b=null;this.a=this.c=this.h=0;this.i=!1};function Xc(a,b,c,d){b=b.constructor===Uint8Array?b:b.constructor===ArrayBuffer?new Uint8Array(b):b.constructor===Array?new Uint8Array(b):b.constructor===String?Hc(b):new Uint8Array(0);a.b=b;a.h=B(c)?c:0;a.c=B(d)?a.h+d:a.b.length;a.a=a.h}r.reset=function(){this.a=this.h};r.kb=function(){return this.a==this.c};r.getError=function(){return this.i||0>this.a||this.a>this.c}; +function $c(a){for(var b,c=0,d,e=0;4>e;e++)if(b=a.b[a.a++],c|=(b&127)<<7*e,128>b){a.g=c>>>0;a.f=0;return}b=a.b[a.a++];c|=(b&127)<<28;d=0|(b&127)>>4;if(128>b)a.g=c>>>0,a.f=d>>>0;else{for(e=0;5>e;e++)if(b=a.b[a.a++],d|=(b&127)<<7*e+3,128>b){a.g=c>>>0;a.f=d>>>0;return}a.i=!0}}function ad(a){for(;a.b[a.a]&128;)a.a++;a.a++} +r.ca=function(){var a=this.b;var b=a[this.a+0];var c=b&127;if(128>b)return this.a+=1,c;b=a[this.a+1];c|=(b&127)<<7;if(128>b)return this.a+=2,c;b=a[this.a+2];c|=(b&127)<<14;if(128>b)return this.a+=3,c;b=a[this.a+3];c|=(b&127)<<21;if(128>b)return this.a+=4,c;b=a[this.a+4];c|=(b&15)<<28;if(128>b)return this.a+=5,c>>>0;this.a+=5;128<=a[this.a++]&&128<=a[this.a++]&&128<=a[this.a++]&&128<=a[this.a++]&&this.a++;return c};r.Ma=Wc.prototype.ca;r.da=function(){var a=this.ca();return a>>>1^-(a&1)}; +function bd(a){$c(a);return Kc(a.g,a.f)}r.Eb=function(){var a=this.b[this.a+0],b=this.b[this.a+1],c=this.b[this.a+2],d=this.b[this.a+3];this.a+=4;return(a<<0|b<<8|c<<16|d<<24)>>>0};r.zd=function(){var a=this.Eb(),b=2*(a>>31)+1,c=a>>>23&255;a&=8388607;return 255==c?a?NaN:Infinity*b:0==c?b*Math.pow(2,-149)*a:b*Math.pow(2,c-150)*(a+Math.pow(2,23))}; +function cd(a){var b=a.Eb(),c=a.Eb();a=2*(c>>31)+1;var d=c>>>20&2047;b=4294967296*(c&1048575)+b;return 2047==d?b?NaN:Infinity*a:0==d?a*Math.pow(2,-1074)*b:a*Math.pow(2,d-1075)*(b+4503599627370496)} +function dd(a,b){var c=a.b,d=a.a,e=d+b;b=[];for(var f="";d<e;){var g=c[d++];if(128>g)b.push(g);else if(192>g)continue;else if(224>g){var h=c[d++];b.push((g&31)<<6|h&63)}else if(240>g){h=c[d++];var k=c[d++];b.push((g&15)<<12|(h&63)<<6|k&63)}else if(248>g){h=c[d++];k=c[d++];var l=c[d++];g=(g&7)<<18|(h&63)<<12|(k&63)<<6|l&63;g-=65536;b.push((g>>10&1023)+55296,(g&1023)+56320)}8192<=b.length&&(f+=String.fromCharCode.apply(null,b),b.length=0)}c=f;if(8192>=b.length)b=String.fromCharCode.apply(null,b);else{e= +"";for(f=0;f<b.length;f+=8192)g=Wa(b,f,f+8192),e+=String.fromCharCode.apply(null,g);b=e}a.a=d;return c+b}r.Lf=function(){var a=this.ca();return dd(this,a)};r.De=function(){$c(this);return Lc(this.g,this.f)};r.Ce=function(){var a=this.b,b=this.a,c=a[b+0],d=a[b+1],e=a[b+2],f=a[b+3],g=a[b+4],h=a[b+5],k=a[b+6];a=a[b+7];this.a+=8;return String.fromCharCode(c,d,e,f,g,h,k,a)};function ed(a,b,c){this.c=Zc(a,b,c);this.b=this.c.a;this.f=this.a=-1;this.g=!1}var fd=[];function gd(a,b,c){if(fd.length){var d=fd.pop();a&&Xc(d.c,a,b,c);return d}return new ed(a,b,c)}function hd(a){a.c.clear();a.a=-1;a.f=-1;a.g=!1;100>fd.length&&fd.push(a)}function id(a){return a.c.a}function jd(a){return a.c.b}ed.prototype.getError=function(){return this.g||this.c.getError()};ed.prototype.reset=function(){this.c.reset();this.f=this.a=-1}; +function G(a){if(a.c.kb()||a.getError())return!1;a.b=a.c.a;var b=a.c.ca(),c=b&7;if(0!=c&&5!=c&&1!=c&&2!=c&&3!=c&&4!=c)return a.g=!0,!1;a.a=b>>>3;a.f=c;return!0}function kd(a){if(2!=a.f)H(a);else{var b=a.c.ca();a=a.c;a.a+=b}} +function H(a){switch(a.f){case 0:0!=a.f?H(a):ad(a.c);break;case 1:1!=a.f?H(a):(a=a.c,a.a+=8);break;case 2:kd(a);break;case 5:5!=a.f?H(a):(a=a.c,a.a+=4);break;case 3:var b=[a.a];do{if(!G(a)){a.g=!0;break}if(3==a.f)b.push(a.a);else if(4==a.f&&a.a!=b.pop()){a.g=!0;break}}while(0<b.length)}} +function ld(a,b){a.f=tc(b);switch(b){case 1:return cd(a.c);case 2:return md(a);case 3:return bd(a.c);case 4:return a=a.c,$c(a),4294967296*a.f+a.g;case 5:return J(a);case 6:return a=a.c,b=a.Eb(),4294967296*a.Eb()+b;case 7:return nd(a);case 8:return K(a);case 9:return L(a);case 10:case 11:case 12:return od(a);case 13:return M(a);case 14:return N(a);case 15:a=a.c;b=a.b[a.a+0];var c=a.b[a.a+1],d=a.b[a.a+2],e=a.b[a.a+3];a.a+=4;return b<<0|c<<8|d<<16|e<<24;case 16:return b=a.c,a=b.Eb(),b=b.Eb(),Kc(a,b); +case 17:return a.c.da();case 18:return b=a.c,$c(b),a=b.g,c=b.f,b=a&1,a=(a>>>1|c<<31)>>>0,c>>>=1,b&&(a=a+1>>>0,0==a&&(c=c+1>>>0)),a=4294967296*c+a,b?-a:a;case 30:return pd(a);case 31:return qd(a)}return 0}function O(a,b,c){var d=a.c.c,e=a.c.ca();e=a.c.a+e;a.c.c=e;c(b,a);a.c.a=e;a.c.c=d}function J(a){return a.c.Ma()}function M(a){return a.c.ca()}function nd(a){return a.c.Eb()}function md(a){return a.c.zd()}function K(a){return!!a.c.ca()}function N(a){return bd(a.c)} +function L(a){var b=a.c.ca();return dd(a.c,b)}function od(a){var b=a.c.ca();a=a.c;if(0>b||a.a+b>a.b.length)a.i=!0,b=new Uint8Array(0);else{var c=a.b.subarray(a.a,a.a+b);a.a+=b;b=c}return b}function qd(a){return a.c.De()}function pd(a){return a.c.Ce()};function rd(a,b,c,d,e,f,g){this.c=a;this.b=b;this.a=B(c)?c:null;this.i=B(d)?d:null;this.h=B(e)?e:null;this.f=B(f)?f:null;this.g=B(g)?g:null}function sd(){this.c=-1;this.value=this.a=this.b=this.start=this.buffer=null}var td=[],ud=0;function vd(a,b,c,d,e,f){if(ud){ud--;var g=td[ud];td[ud]=null}else g=new sd;var h=g;h.c=a;h.buffer=B(c)?c:null;h.start=B(d)?d:null;h.b=B(e)?e:null;h.a=B(f)?f:null;h.value=B(b)?b:null;return g} +function wd(a){if(a){null!=a.buffer&&null!=a.start&&null!=a.b&&null!=a.a&&null!=a.value&&(a.a.i&&a.a.i(a.value),a.value=null);a.c=-1;a.buffer=null;a.start=null;a.b=null;a.a=null;a.value=null;var b=ud;1E3>b&&(td[b]=a,ud++)}} +function xd(a){if(null==a)return null;for(var b=[],c=0;c<a.length;c++){var d=a[c],e=new sd;e.c=d.c;null!=d.value&&null!=d.a?(e.a=d.a,d.a.f?e.value=d.a.f(d.value):12==d.a.b?e.value=new Uint8Array(d.value):e.value=d.value):null!=d.buffer&&null!=d.start&&null!=d.b&&(e.buffer=new Uint8Array(d.buffer.buffer.slice(d.start,d.b)),e.start=0,e.b=d.b-d.start);b.push(e)}return b}function yd(a,b,c,d,e,f,g,h){c=new rd(b,c,d,e,f,g,h);for(d=0;d<a.length;d++)if(a[d].c==b){a[d]=c;return}a.push(c)};function zd(a,b,c){var d=Wc.prototype.Ma;return a&&null!=b&&null!=c&&d?(a=Zc(a,b,c-b),a.ca(),a.ca(),Tc(a,d,null)):Tc()}function Ad(a){return a?a.slice():null}function Bd(a,b){if(null===a)return null;for(var c=[],d=0;d<a.length;d++)c.push(b(a[d]));return c}function Cd(a,b){var c=a?a.length:0;if(c!=(b?b.length:0))return!1;for(var d=0;d<c;++d)if(a[d]!=b[d])return!1;return!0}function Dd(a,b,c){var d=a?a.length:0;if(d!=(b?b.length:0))return!1;for(var e=0;e<d;++e)if(!c(a[e],b[e]))return!1;return!0} +function Ed(a,b){var c=a?a.length:0;if(c!=(b?b.length:0))return!1;for(var d=0;d<c;d++){var e=a[d],f=b[d];if(e.a!==f.a)return!1;if(e.a.g){if(!e.a.g(e.value,f.value))return!1}else if(12==e.a.b){if(!Cd(e.value,f.value))return!1}else if(e.value!=f.value)return!1}return!0}function Fd(a,b,c,d){if(b&&null!=c&&null!=d){b=Zc(b,c,d-c);b.ca();b.ca();for(c=[];!b.kb();)c.push(a.call(b));Vc(b);return c}return null}function Gd(a,b,c){return a&&null!=b&&null!=c?(a=gd(a,b,c-b),G(a),b=od(a),hd(a),b):null} +function Hd(a,b,c,d,e){if(c&&null!=d&&null!=e){var f=[];for(c=gd(c,d,e-d);G(c);)d=a(),O(c,d,b),f.push(d);hd(c);return f}return null} +function Id(a,b){if(!a)return null;a:{for(var c=0;c<a.length;c++)if(a[c].c==b){a=a[c];break a}a=null}a&&a.a?a.value?a=a.value:null==a||null==a.a||null==a.buffer||null==a.start||null==a.b?a=null:(b=gd(a.buffer,a.start,a.b-a.start),G(b),a.a.a&&a.a.h?(a.value=a.a.a(),O(b,a.value,a.a.h)):a.value=ld(b,a.a.b),hd(b),a.buffer=null,a.start=null,a.b=null,a=a.value):a=null;return a} +function Jd(a,b){var c=a.a,d=jd(a),e=a.b;H(a);a=id(a);var f=null;if(b)for(var g=0;g<b.length;g++){var h=b[g];if(h.c==c){f=h;break}}return vd(c,null,d,e,a,f)};function Ld(a){var b=a;if(a instanceof Array)b=Array(a.length),Md(b,a);else if(a instanceof Object){var c=b={},d;for(d in a)a.hasOwnProperty(d)&&(c[d]=Ld(a[d]))}return b}function Md(a,b){for(var c=0;c<b.length;++c)b.hasOwnProperty(c)&&(a[c]=Ld(b[c]))}function Nd(a,b){a[b]||(a[b]=[]);return a[b]} +function Od(a,b){if(null==a||null==b)return null==a==(null==b);if(a.constructor!=Array&&a.constructor!=Object)throw Error("Invalid object type passed into jsproto.areObjectsEqual()");if(a===b)return!0;if(a.constructor!=b.constructor)return!1;for(var c in a)if(!(c in b&&Pd(a[c],b[c])))return!1;for(var d in b)if(!(d in a))return!1;return!0} +function Pd(a,b){if(a===b||!(!0!==a&&1!==a||!0!==b&&1!==b)||!(!1!==a&&0!==a||!1!==b&&0!==b))return!0;if(a instanceof Object&&b instanceof Object){if(!Od(a,b))return!1}else return!1;return!0}function Qd(a){return Rd(a.replace(/[+/]/g,function(a){return"+"==a?"-":"_"}))}function Sd(a){return Rd(a.replace(/[-_]/g,function(a){return"-"==a?"+":"/"}))}function Rd(a){return a.replace(/[.=]+$/,"")}function Td(a,b,c,d){this.type=a;this.label=b;this.tf=c;this.N=d} +function Ud(a){switch(a){case "d":case "f":case "i":case "j":case "u":case "v":case "x":case "y":case "g":case "h":case "n":case "o":case "e":return 0;case "s":case "z":case "B":return"";case "b":return!1;default:return null}}function Vd(a,b,c){return new Td(a,1,B(b)?b:Ud(a),c)}function Wd(a,b,c){return new Td(a,2,B(b)?b:Ud(a),c)}function Xd(a,b){return new Td(a,3,void 0,b)}var Yd=Vd("d",void 0);function Zd(a){return Vd("f",a)}var $d=Zd();function ae(a){return Vd("i",a)} +var P=ae(),be=Wd("i",void 0),ce=Xd("i"),Q=Vd("u",void 0),de=Wd("u",void 0),ee=Xd("u"),fe=Vd("v",void 0);function ge(a){return Vd("b",a)}var R=ge();function he(a){return Vd("e",a)}var T=he(),ie=Xd("e"),U=Vd("s",void 0),je=Wd("s",void 0),ke=Xd("s"),le=Vd("B",void 0);function V(a,b){return Vd("m",a,b)}function me(){var a=new ne([]),b=oe();return Wd("m",a,b)}function pe(a){return Xd("m",a)}var qe=Wd("x",void 0),re=Xd("x");function se(){}var te=new se,ue=/'/g;se.prototype.b=function(a,b){var c=[];ve(a,b,c);return c.join("&").replace(ue,"%27")};se.prototype.a=function(){throw Error("QueryStringSerializer.deserialize is not implemented");};function ve(a,b,c){for(var d=1;d<b.F.length;++d){var e=b.F[d],f=a[d+b.a];if(e&&null!=f)if(3==e.label)for(var g=0;g<f.length;++g)we(f[g],d,e,c);else we(f,d,e,c)}} +function we(a,b,c,d){if("m"==c.type){var e=d.length;ve(a,c.N,d);d.splice(e,0,[b,"m",d.length-e].join(""))}else"b"==c.type&&(a=a?"1":"0"),a=[b,c.type,encodeURIComponent(a)].join(""),d.push(a)};function W(a){this.data=a||[]}function xe(a,b){return null!=a.data[b]}function ye(a,b,c){a=a.data[b];return null!=a?a:c}function X(a,b,c){return ye(a,b,c||0)}function ze(a,b,c){return ye(a,b,c||"")}function Ae(a,b){var c=a.data[b];c||(c=a.data[b]=[]);return c}function Be(a,b){b in a.data&&delete a.data[b]}function Ce(a,b){return Nd(a.data,b)}function De(a,b){var c=[];Ce(a,b).push(c);return c}function Ee(a,b,c){return Ce(a,b)[c]}function Fe(a,b){return a.data[b]?a.data[b].length:0} +function Ge(a,b){return Od(a.data,b?(b&&b).data:null)}function He(a,b){b=b&&b;a=a.data;b=b?b.data:null;a!==b&&(a.length=0,b&&(a.length=b.length,Md(a,b)))};function Ie(){this.a=null}Ie.prototype.w=function(){return[]};function Je(a){if(a.a)for(var b=0;b<a.a.length;b++)wd(a.a[b]);a.a=null}var Ke=[];Ie.prototype.getExtension=function(a){var b=!1;4<=a&&2147483647>a&&(b=!0);return b?Id(this.a,a):null};function Le(a,b){for(;G(b);){a.a=a.a||[];var c=Jd(b,Ke);a.a.push(c)}};function Me(a){this.data=a||[]}var Ne;F(Me,W);function Oe(){Ne||(Ne={a:-1,F:[]});return Ne};function Pe(a){this.data=a||[]}var Qe;F(Pe,W);function Re(){Qe||(Qe={a:-1,F:[]},Qe.F=[,Wd("y",""),Wd("y",""),V(new Me([]),Oe())]);return Qe};function Se(){this.a=this.b=null}Se.prototype.w=function(){var a=[];if(null!==this.b){var b=this.b;a[0]=b}null!==this.a&&(b=this.a,a[1]=b);return a};function Te(a){a.b=null;a.a=null}Se.prototype.getExtension=function(){return null};function Ue(a,b){for(;G(b);)switch(b.a){case 1:var c=N(b);a.b=c;break;case 2:c=L(b);a.a=c;break;default:H(b)}};function Ve(){this.b=this.a=null}Ve.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;b=b.w();a[0]=b}null!==this.b&&(b=this.b,a[1]=b);return a};function We(a){var b=a.a;b&&Te(b);a.a=null;a.b=null}Ve.prototype.getExtension=function(){return null};function Xe(a,b){for(;G(b);)switch(b.a){case 1:var c=new Se;O(b,c,Ue);a.a=c;break;case 2:c=K(b);a.b=c;break;default:H(b)}};function Ye(){this.a=null}Ye.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;b=b.w();a[14]=b}return a};function Ze(a){var b=a.a;b&&We(b);a.a=null}Ye.prototype.getExtension=function(){return null};function $e(a,b){for(;G(b);)switch(b.a){case 15:var c=new Ve;O(b,c,Xe);a.a=c;break;default:H(b)}};function af(a){this.data=a||[]}var bf;F(af,W);function cf(a){this.data=a||[]}var df;F(cf,W);function ef(a){this.data=a||[]}var ff;F(ef,W);function gf(){if(!ff){var a=[];ff={a:-1,F:a};var b=new cf([]);if(!df){var c=df={a:-1,F:[]},d=new af([]);bf||(bf={a:-1,F:[]},bf.F=[,he(4369),U]);c.F=[,V(d,bf),R]}a[15]=V(b,df)}return ff};function hf(){this.a=this.b=this.f=this.c=null}hf.prototype.w=function(){var a=[];if(null!==this.c){var b=this.c;a[0]=b}null!==this.f&&(b=this.f,a[1]=b);null!==this.b&&(b=this.b,b=b.w(),a[14]=b);null!==this.a&&(b=this.a,b=b.w(),a[499]=b);return a}; +function jf(a){var b=new hf;kf(b);b.c=a.c;b.f=a.f;if(a.b){var c=new Ie;var d=a.b;Je(c);c.a=xd(d.a)}else c=null;b.b=c;if(a.a){c=new Ye;d=a.a;Ze(c);if(d.a){a=new Ve;d=d.a;We(a);if(d.a){var e=new Se;var f=d.a;Te(e);e.b=f.b;e.a=f.a}else e=null;a.a=e;a.b=d.b}else a=null;c.a=a}else c=null;b.a=c;return b}function kf(a){a.c=null;a.f=null;var b=a.b;b&&Je(b);a.b=null;(b=a.a)&&Ze(b);a.a=null}hf.prototype.getExtension=function(){return null}; +function lf(a,b){for(;G(b);)switch(b.a){case 1:var c=nd(b);a.c=c;break;case 2:c=nd(b);a.f=c;break;case 15:c=new Ie;O(b,c,Le);a.b=c;break;case 500:c=new Ye;O(b,c,$e);a.a=c;break;default:H(b)}} +function mf(a,b){if(a===b)b=!0;else if(null===a||null===b)b=!1;else{var c;if(c=a.c===b.c&&a.f===b.f){c=a.b;var d=b.b;c=c===d?!0:null===c||null===d?!1:Ed(c.a,d.a)?!0:!1}c&&(a=a.a,c=b.a,a===c?b=!0:null===a||null===c?b=!1:(b=a.a,a=c.a,(c=b===a)||(null===b||null===a?b=0:(c=b.a,d=a.a,b=(c===d?!0:null===c||null===d?!1:c.b!==d.b||c.a!==d.a?!1:!0)&&b.b===a.b),c=b),b=c?!0:!1),c=b);b=c?!0:!1}return b};function ne(a){this.data=a||[]}var nf;F(ne,W);function oe(){if(!nf){var a=[];nf={a:-1,F:a};a[1]=qe;a[2]=qe;a[500]=V(new ef([]),gf());a[15]=V(new Me([]),Oe())}return nf};function of(a){this.data=a||[]}var pf;F(of,W);function qf(){this.a=this.b=null}qf.prototype.w=function(){var a=[];if(null!==this.b){var b=this.b;b=b.w();a[0]=b}null!==this.a&&(b=this.a,b=b.w(),a[1]=b);return a};function rf(a){var b=a.b;b&&kf(b);a.b=null;(b=a.a)&&kf(b);a.a=null}qf.prototype.getExtension=function(){return null};function sf(a,b){for(;G(b);)switch(b.a){case 1:var c=new hf;O(b,c,lf);a.b=c;break;case 2:c=new hf;O(b,c,lf);a.a=c;break;default:H(b)}};function tf(a){this.data=a||[]}var uf;F(tf,W);function vf(){this.a=this.b=this.c=null}function wf(){this.b=this.a=null}vf.prototype.w=function(){var a=[];if(null!==this.c){var b=this.c;b=Oc(b,!0);a[0]=b}null!==this.b&&(b=this.b,a[1]=b);null!==this.a&&(b=this.a,a[2]=b);return a};function xf(a){var b=new vf;yf(b);b.c=a.c;b.b=a.b;b.a=a.a;return b}function yf(a){a.c=null;a.b=null;a.a=null}vf.prototype.getExtension=function(){return null}; +function zf(a,b){for(;G(b);)switch(b.a){case 1:var c=qd(b);a.c=c;break;case 2:c=nd(b);a.b=c;break;case 3:c=nd(b);a.a=c;break;default:H(b)}}function Af(a,b){return a===b?!0:null===a||null===b?!1:a.c!==b.c||a.b!==b.b||a.a!==b.a?!1:!0}wf.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;b=b.w();a[0]=b}null!==this.b&&(b=this.b,b=Oc(b,!0),a[1]=b);return a};function Bf(a){var b=new wf;Cf(b);b.a=a.a?xf(a.a):null;b.b=a.b;return b}function Cf(a){var b=a.a;b&&yf(b);a.a=null;a.b=null} +wf.prototype.getExtension=function(){return null};function Df(a,b){for(;G(b);)switch(b.a){case 1:var c=new vf;O(b,c,zf);a.a=c;break;case 2:c=qd(b);a.b=c;break;default:H(b)}}function Ef(a,b){return a===b?!0:null===a||null===b?!1:Af(a.a,b.a)&&a.b===b.b?!0:!1};function Ff(){this.f=this.c=this.a=this.b=null}Ff.prototype.w=function(){var a=[];if(null!==this.b){var b=this.b;b=b.w();a[0]=b}null!==this.a&&(b=this.a,b=b.w(),a[1]=b);null!==this.c&&(b=this.c,a[2]=b);null!==this.f&&(b=this.f,a[3]=b);return a};function Gf(a){var b=a.b;b&&yf(b);a.b=null;(b=a.a)&&Cf(b);a.a=null;a.c=null;a.f=null}Ff.prototype.getExtension=function(){return null}; +function Hf(a,b){for(;G(b);)switch(b.a){case 1:var c=new vf;O(b,c,zf);a.b=c;break;case 2:c=new wf;O(b,c,Df);a.a=c;break;case 3:c=J(b);a.c=c;break;case 4:c=N(b);a.f=c;break;default:H(b)}}Ff.prototype.ka=function(){return null==this.c?-1:this.c};function If(a){this.data=a||[]}var Jf;F(If,W);function Kf(a){this.data=a||[]}var Lf;F(Kf,W);function Mf(){Jf||(Jf={a:-1,F:[]},Jf.F=[,Wd("j",""),qe,qe]);return Jf}function Nf(){Lf||(Lf={a:-1,F:[]},Lf.F=[,V(new If([]),Mf()),Vd("j","")]);return Lf};function Of(a){this.data=a||[]}var Pf;F(Of,W);Of.prototype.ka=function(){return X(this,2,-1)};function Qf(){this.a=null}Qf.prototype.w=function(){var a=[];null!==this.a&&(a[0]=this.a);return a};Qf.prototype.getExtension=function(){return null};function Rf(a,b){for(;G(b);)switch(b.a){case 1:a.a=N(b);break;default:H(b)}};function Sf(a){this.data=a||[]}var Tf;F(Sf,W);function Uf(){Tf={a:-1,F:[,T]}};function Vf(){this.g=this.h=this.$a=this.ib=this.A=this.va=this.ra=this.D=this.b=this.l=this.Jb=this.f=this.Kb=this.o=this.P=this.C=this.Lb=this.Za=this.Wa=this.Bb=this.Z=this.G=this.H=this.I=this.J=this.Ba=this.Qa=this.Ia=this.c=this.s=this.sb=this.ya=this.jb=this.Ka=this.B=this.La=this.Ja=this.m=this.Sa=this.Ga=this.j=this.u=this.S=this.L=this.T=this.Oa=this.ga=this.ia=this.pa=this.ja=this.Da=this.O=this.Y=this.W=this.ha=this.M=this.U=this.fa=this.V=this.Pa=this.Ra=this.qb=this.a=this.i=this.Ca= +this.v=this.K=this.rb=null}function Wf(){this.b=this.c=this.a=null}function Xf(){this.c=this.f=this.a=this.b=this.g=null}function Yf(){this.b=this.g=this.a=this.f=this.m=this.l=this.j=this.c=this.i=this.h=null}function Zf(){this.a=null}function $f(){this.a=this.b=null}function ag(){this.b=this.a=this.c=null}function bg(){this.c=this.g=this.b=this.a=this.h=this.f=null}function cg(){this.b=this.f=this.c=this.a=null}function dg(){this.f=this.c=this.b=this.a=this.g=null} +function eg(){this.c=this.f=this.h=this.g=this.i=this.j=this.a=this.m=this.l=this.b=this.o=null}function fg(){this.a=this.b=null}function gg(){this.a=this.c=this.b=null}function hg(){this.b=this.c=this.a=null}function ig(){this.b=this.a=null}function jg(){this.a=this.b=this.g=this.f=this.c=null} +function kg(a,b){for(;G(b);)switch(b.a){case 1:var c=N(b);a.rb=c;break;case 2:c=L(b);a.K=c;break;case 3:c=new Wf;O(b,c,lg);a.v=c;break;case 4:c=L(b);a.Ca=c;break;case 5:c=new Yf;O(b,c,mg);a.i=c;break;case 6:c=new Yf;O(b,c,mg);a.a=a.a||[];a.a.push(c);break;case 7:c=K(b);a.qb=c;break;case 8:c=M(b);a.Ra=c;break;case 9:c=M(b);a.Pa=c;break;case 10:c=M(b);a.V=c;break;case 11:c=M(b);a.fa=c;break;case 12:c=M(b);a.U=c;break;case 13:c=M(b);a.M=c;break;case 14:c=M(b);a.ha=c;break;case 15:c=M(b);a.W=c;break; +case 16:c=M(b);a.Y=c;break;case 17:c=M(b);a.O=c;break;case 18:c=M(b);a.Da=c;break;case 19:c=M(b);a.ja=c;break;case 20:c=M(b);a.pa=c;break;case 21:c=L(b);a.ia=c;break;case 22:c=M(b);a.ga=c;break;case 23:c=N(b);a.Oa=c;break;case 24:c=M(b);a.T=c;break;case 25:c=M(b);a.L=c;break;case 26:c=L(b);a.S=c;break;case 27:c=new bg;O(b,c,ng);a.u=c;break;case 28:c=new ag;O(b,c,og);a.j=c;break;case 29:c=N(b);a.Ga=c;break;case 30:c=N(b);a.Sa=c;break;case 31:c=N(b);a.m=a.m||[];a.m.push(c);break;case 32:c=M(b);a.Ja= +c;break;case 33:c=L(b);a.La=c;break;case 34:c=M(b);a.B=c;break;case 35:c=M(b);a.Ka=c;break;case 36:c=M(b);a.jb=c;break;case 37:c=M(b);a.ya=c;break;case 38:c=K(b);a.sb=c;break;case 39:c=N(b);a.s=c;break;case 40:c=new Yf;O(b,c,mg);a.c=a.c||[];a.c.push(c);break;case 41:c=L(b);a.Ia=c;break;case 42:c=L(b);a.Qa=c;break;case 43:c=K(b);a.Ba=c;break;case 44:c=M(b);a.J=c;break;case 45:c=M(b);a.I=c;break;case 46:c=M(b);a.H=c;break;case 47:c=M(b);a.G=c;break;case 48:c=M(b);a.Z=c;break;case 49:c=M(b);a.Bb=c;break; +case 50:c=M(b);a.Wa=c;break;case 51:c=M(b);a.Za=c;break;case 52:c=M(b);a.Lb=c;break;case 53:c=M(b);a.C=c;break;case 54:c=M(b);a.P=c;break;case 55:c=new eg;O(b,c,pg);a.o=c;break;case 56:c=M(b);a.Kb=c;break;case 57:c=new hg;O(b,c,qg);a.f=a.f||[];a.f.push(c);break;case 58:c=M(b);a.Jb=c;break;case 59:c=new fg;O(b,c,rg);a.l=c;break;case 60:c=new gg;O(b,c,sg);a.b=a.b||[];a.b.push(c);break;case 62:c=M(b);a.D=c;break;case 63:c=M(b);a.ra=c;break;case 64:c=M(b);a.va=c;break;case 65:c=new ig;O(b,c,tg);a.A=c; +break;case 66:c=M(b);a.ib=c;break;case 67:c=M(b);a.$a=c;break;case 68:c=new jg;O(b,c,ug);a.h=c;break;case 69:c=new $f;O(b,c,vg);a.g=a.g||[];a.g.push(c);break;default:H(b)}} +Vf.prototype.w=function(){var a=[];if(null!==this.rb){var b=this.rb;a[0]=b}null!==this.K&&(b=this.K,a[1]=b);null!==this.v&&(b=this.v,b=b.w(),a[2]=b);null!==this.Ca&&(b=this.Ca,a[3]=b);null!==this.i&&(b=this.i,b=b.w(),a[4]=b);if(null!==this.a){b=this.a;b=b.slice();for(var c=0;c<b.length;c++)b[c]=b[c].w();a[5]=b}null!==this.qb&&(b=this.qb,a[6]=b);null!==this.Ra&&(b=this.Ra,a[7]=b);null!==this.Pa&&(b=this.Pa,a[8]=b);null!==this.V&&(b=this.V,a[9]=b);null!==this.fa&&(b=this.fa,a[10]=b);null!==this.U&& +(b=this.U,a[11]=b);null!==this.M&&(b=this.M,a[12]=b);null!==this.ha&&(b=this.ha,a[13]=b);null!==this.W&&(b=this.W,a[14]=b);null!==this.Y&&(b=this.Y,a[15]=b);null!==this.O&&(b=this.O,a[16]=b);null!==this.Da&&(b=this.Da,a[17]=b);null!==this.ja&&(b=this.ja,a[18]=b);null!==this.pa&&(b=this.pa,a[19]=b);null!==this.ia&&(b=this.ia,a[20]=b);null!==this.ga&&(b=this.ga,a[21]=b);null!==this.Oa&&(b=this.Oa,a[22]=b);null!==this.T&&(b=this.T,a[23]=b);null!==this.L&&(b=this.L,a[24]=b);null!==this.S&&(b=this.S,a[25]= +b);null!==this.u&&(b=this.u,b=b.w(),a[26]=b);null!==this.j&&(b=this.j,b=b.w(),a[27]=b);null!==this.Ga&&(b=this.Ga,a[28]=b);null!==this.Sa&&(b=this.Sa,a[29]=b);null!==this.m&&(b=this.m,b=b.slice(),a[30]=b);null!==this.Ja&&(b=this.Ja,a[31]=b);null!==this.La&&(b=this.La,a[32]=b);null!==this.B&&(b=this.B,a[33]=b);null!==this.Ka&&(b=this.Ka,a[34]=b);null!==this.jb&&(b=this.jb,a[35]=b);null!==this.ya&&(b=this.ya,a[36]=b);null!==this.sb&&(b=this.sb,a[37]=b);null!==this.s&&(b=this.s,a[38]=b);if(null!==this.c){b= +this.c;b=b.slice();for(c=0;c<b.length;c++)b[c]=b[c].w();a[39]=b}null!==this.Ia&&(b=this.Ia,a[40]=b);null!==this.Qa&&(b=this.Qa,a[41]=b);null!==this.Ba&&(b=this.Ba,a[42]=b);null!==this.J&&(b=this.J,a[43]=b);null!==this.I&&(b=this.I,a[44]=b);null!==this.H&&(b=this.H,a[45]=b);null!==this.G&&(b=this.G,a[46]=b);null!==this.Z&&(b=this.Z,a[47]=b);null!==this.Bb&&(b=this.Bb,a[48]=b);null!==this.Wa&&(b=this.Wa,a[49]=b);null!==this.Za&&(b=this.Za,a[50]=b);null!==this.Lb&&(b=this.Lb,a[51]=b);null!==this.C&& +(b=this.C,a[52]=b);null!==this.P&&(b=this.P,a[53]=b);null!==this.o&&(b=this.o,b=b.w(),a[54]=b);null!==this.Kb&&(b=this.Kb,a[55]=b);if(null!==this.f){b=this.f;b=b.slice();for(c=0;c<b.length;c++)b[c]=b[c].w();a[56]=b}null!==this.Jb&&(b=this.Jb,a[57]=b);null!==this.l&&(b=this.l,b=b.w(),a[58]=b);if(null!==this.b){b=this.b;b=b.slice();for(c=0;c<b.length;c++)b[c]=b[c].w();a[59]=b}null!==this.D&&(b=this.D,a[61]=b);null!==this.ra&&(b=this.ra,a[62]=b);null!==this.va&&(b=this.va,a[63]=b);null!==this.A&&(b= +this.A,b=b.w(),a[64]=b);null!==this.ib&&(b=this.ib,a[65]=b);null!==this.$a&&(b=this.$a,a[66]=b);null!==this.h&&(b=this.h,b=b.w(),a[67]=b);if(null!==this.g){b=this.g;b=b.slice();for(c=0;c<b.length;c++)b[c]=b[c].w();a[68]=b}return a}; +function wg(a,b){xg(a);a.rb=b.rb;a.K=b.K;a.v=b.v?yg(b.v):null;a.Ca=b.Ca;a.i=b.i?zg(b.i):null;a.a=Bd(b.a,Ag);a.qb=b.qb;a.Ra=b.Ra;a.Pa=b.Pa;a.V=b.V;a.fa=b.fa;a.U=b.U;a.M=b.M;a.ha=b.ha;a.W=b.W;a.Y=b.Y;a.O=b.O;a.Da=b.Da;a.ja=b.ja;a.pa=b.pa;a.ia=b.ia;a.ga=b.ga;a.Oa=b.Oa;a.T=b.T;a.L=b.L;a.S=b.S;a.u=b.u?Bg(b.u):null;a.j=b.j?Cg(b.j):null;a.Ga=b.Ga;a.Sa=b.Sa;a.m=Ad(b.m);a.Ja=b.Ja;a.La=b.La;a.B=b.B;a.Ka=b.Ka;a.jb=b.jb;a.ya=b.ya;a.sb=b.sb;a.s=b.s;a.c=Bd(b.c,Ag);a.Ia=b.Ia;a.Qa=b.Qa;a.Ba=b.Ba;a.J=b.J;a.I=b.I; +a.H=b.H;a.G=b.G;a.Z=b.Z;a.Bb=b.Bb;a.Wa=b.Wa;a.Za=b.Za;a.Lb=b.Lb;a.C=b.C;a.P=b.P;a.o=b.o?Dg(b.o):null;a.Kb=b.Kb;a.f=Bd(b.f,Eg);a.Jb=b.Jb;a.l=b.l?Fg(b.l):null;a.b=Bd(b.b,Gg);a.D=b.D;a.ra=b.ra;a.va=b.va;a.A=b.A?Hg(b.A):null;a.ib=b.ib;a.$a=b.$a;a.h=b.h?Ig(b.h):null;a.g=Bd(b.g,Jg)} +function xg(a){a.rb=null;a.K=null;Kg(a.v);a.v=null;a.Ca=null;Lg(a.i);a.i=null;if(a.a)for(var b=0;b<a.a.length;b++)Lg(a.a[b]);a.a=null;a.qb=null;a.Ra=null;a.Pa=null;a.V=null;a.fa=null;a.U=null;a.M=null;a.ha=null;a.W=null;a.Y=null;a.O=null;a.Da=null;a.ja=null;a.pa=null;a.ia=null;a.ga=null;a.Oa=null;a.T=null;a.L=null;a.S=null;Mg(a.u);a.u=null;Ng(a.j);a.j=null;a.Ga=null;a.Sa=null;a.m=null;a.Ja=null;a.La=null;a.B=null;a.Ka=null;a.jb=null;a.ya=null;a.sb=null;a.s=null;if(a.c)for(b=0;b<a.c.length;b++)Lg(a.c[b]); +a.c=null;a.Ia=null;a.Qa=null;a.Ba=null;a.J=null;a.I=null;a.H=null;a.G=null;a.Z=null;a.Bb=null;a.Wa=null;a.Za=null;a.Lb=null;a.C=null;a.P=null;Og(a.o);a.o=null;a.Kb=null;if(a.f)for(b=0;b<a.f.length;b++)Pg(a.f[b]);a.f=null;a.Jb=null;Qg(a.l);a.l=null;if(a.b)for(b=0;b<a.b.length;b++)Rg(a.b[b]);a.b=null;a.D=null;a.ra=null;a.va=null;Sg(a.A);a.A=null;a.ib=null;a.$a=null;Tg(a.h);a.h=null;if(a.g)for(b=0;b<a.g.length;b++)Ug(a.g[b]);a.g=null}Vf.prototype.getExtension=function(){return null}; +function Vg(a,b){kg(a,b)}Vf.prototype.getContext=function(){return null==this.s?0:this.s};Wf.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;a[0]=b}null!==this.c&&(b=this.c,a[1]=b);null!==this.b&&(b=this.b,a[2]=b);return a};function yg(a){var b=new Wf;b.a=null;b.c=null;b.b=null;b.a=a.a;b.c=a.c;b.b=a.b;return b}Wf.prototype.getExtension=function(){return null};function Kg(a){a&&(a.a=null,a.c=null,a.b=null)} +function lg(a,b){for(;G(b);)switch(b.a){case 1:var c=L(b);a.a=c;break;case 2:c=K(b);a.c=c;break;case 3:c=J(b);a.b=c;break;default:H(b)}}Wf.prototype.wa=function(){return null==this.a?"":this.a};Xf.prototype.w=function(){var a=[];if(null!==this.g){var b=this.g;a[0]=b}null!==this.b&&(b=this.b,a[1]=b);null!==this.a&&(b=this.a,a[2]=b);null!==this.f&&(b=this.f,a[3]=b);null!==this.c&&(b=this.c,a[4]=b);return a};function Wg(a){a.g=null;a.b=null;a.a=null;a.f=null;a.c=null}Xf.prototype.getExtension=function(){return null}; +function Xg(a,b){for(;G(b);)switch(b.a){case 1:var c=cd(b.c);a.g=c;break;case 2:c=M(b);a.b=c;break;case 3:c=M(b);a.a=c;break;case 4:c=M(b);a.f=c;break;case 5:c=M(b);a.c=c;break;default:H(b)}} +Yf.prototype.w=function(){var a=[];if(null!==this.h){var b=this.h;a[0]=b}null!==this.i&&(b=this.i,a[1]=b);null!==this.c&&(b=this.c,b=b.slice(),a[2]=b);null!==this.j&&(b=this.j,a[3]=b);null!==this.l&&(b=this.l,a[4]=b);null!==this.m&&(b=this.m,a[5]=b);null!==this.f&&(b=this.f,a[6]=b);if(null!==this.a){b=this.a;b=b.slice();for(var c=0;c<b.length;c++)b[c]=b[c].w();a[7]=b}null!==this.g&&(b=this.g,a[8]=b);null!==this.b&&(b=this.b,b=b.w(),a[9]=b);return a}; +function zg(a){var b=new Yf;Yg(b);b.h=a.h;b.i=a.i;b.c=Ad(a.c);b.j=a.j;b.l=a.l;b.m=a.m;b.f=a.f;b.a=Bd(a.a,Zg);b.g=a.g;if(a.b){var c=new Xf;a=a.b;Wg(c);c.g=a.g;c.b=a.b;c.a=a.a;c.f=a.f;c.c=a.c}else c=null;b.b=c;return b}function Yg(a){a.h=null;a.i=null;a.c=null;a.j=null;a.l=null;a.m=null;a.f=null;if(a.a)for(var b=0;b<a.a.length;b++){var c=a.a[b];c&&(c.a=null)}a.a=null;a.g=null;(b=a.b)&&Wg(b);a.b=null}Yf.prototype.getExtension=function(){return null};function Lg(a){a&&Yg(a)} +function Ag(a){return null===a?null:zg(a)}function mg(a,b){for(;G(b);)switch(b.a){case 1:var c=J(b);a.h=c;break;case 2:c=M(b);a.i=c;break;case 3:c=M(b);a.c=a.c||[];a.c.push(c);break;case 4:c=J(b);a.j=c;break;case 5:c=N(b);a.l=c;break;case 6:c=J(b);a.m=c;break;case 7:c=J(b);a.f=c;break;case 8:c=new Zf;O(b,c,$g);a.a=a.a||[];a.a.push(c);break;case 9:c=N(b);a.g=c;break;case 10:c=new Xf;O(b,c,Xg);a.b=c;break;default:H(b)}} +function ah(a,b){if(a===b)b=!0;else if(null===a||null===b)b=!1;else{var c;if(c=a.h===b.h&&a.i===b.i&&Cd(a.c,b.c)&&a.j===b.j&&a.l===b.l&&a.m===b.m&&a.f===b.f&&Dd(a.a,b.a,bh)&&a.g===b.g)a=a.b,b=b.b,c=a===b?!0:null===a||null===b?!1:a.g!==b.g||a.b!==b.b||a.a!==b.a||a.f!==b.f||a.c!==b.c?!1:!0;b=c?!0:!1}return b}Zf.prototype.w=function(){var a=[];null!==this.a&&(a[0]=this.a);return a};Zf.prototype.getExtension=function(){return null}; +function Zg(a){if(null===a)a=null;else{var b=new Zf;b.a=null;b.a=a.a;a=b}return a}function $g(a,b){for(;G(b);)switch(b.a){case 1:a.a=N(b);break;default:H(b)}}function bh(a,b){return a===b?!0:null===a||null===b?!1:a.a!==b.a?!1:!0}$f.prototype.w=function(){var a=[];if(null!==this.b){var b=this.b;a[0]=b}if(null!==this.a){b=this.a;b=b.slice();for(var c=0;c<b.length;c++)b[c]=b[c].w();a[1]=b}return a};function ch(a){a.b=null;if(a.a)for(var b=0;b<a.a.length;b++)Lg(a.a[b]);a.a=null} +$f.prototype.getExtension=function(){return null};function Ug(a){a&&ch(a)}function Jg(a){if(null===a)a=null;else{var b=new $f;ch(b);b.b=a.b;b.a=Bd(a.a,Ag);a=b}return a}function vg(a,b){for(;G(b);)switch(b.a){case 1:var c=L(b);a.b=c;break;case 2:c=new Yf;O(b,c,mg);a.a=a.a||[];a.a.push(c);break;default:H(b)}}function dh(a,b){return a===b?!0:null===a||null===b?!1:a.b===b.b&&Dd(a.a,b.a,ah)?!0:!1} +ag.prototype.w=function(){var a=[];if(null!==this.c){var b=this.c;a[0]=b}null!==this.a&&(b=this.a,a[1]=b);null!==this.b&&(b=this.b,a[2]=b);return a};function Cg(a){var b=new ag;b.c=null;b.a=null;b.b=null;b.c=a.c;b.a=a.a;b.b=a.b;return b}ag.prototype.getExtension=function(){return null};function Ng(a){a&&(a.c=null,a.a=null,a.b=null)}function og(a,b){for(;G(b);)switch(b.a){case 1:var c=K(b);a.c=c;break;case 2:c=K(b);a.a=c;break;case 3:c=K(b);a.b=c;break;default:H(b)}} +bg.prototype.w=function(){var a=[];if(null!==this.f){var b=this.f;a[0]=b}null!==this.h&&(b=this.h,a[1]=b);null!==this.a&&(b=this.a,a[2]=b);null!==this.b&&(b=this.b,a[3]=b);null!==this.g&&(b=this.g,a[4]=b);null!==this.c&&(b=this.c,a[5]=b);return a};function Bg(a){var b=new bg;eh(b);b.f=a.f;b.h=a.h;b.a=a.a;b.b=a.b;b.g=a.g;b.c=a.c;return b}function eh(a){a.f=null;a.h=null;a.a=null;a.b=null;a.g=null;a.c=null}bg.prototype.getExtension=function(){return null};function Mg(a){a&&eh(a)} +function ng(a,b){for(;G(b);)switch(b.a){case 1:var c=K(b);a.f=c;break;case 2:c=M(b);a.h=c;break;case 3:c=M(b);a.a=c;break;case 4:c=M(b);a.b=c;break;case 5:c=M(b);a.g=c;break;case 6:c=M(b);a.c=c;break;default:H(b)}}cg.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;a[0]=b}null!==this.c&&(b=this.c,a[1]=b);null!==this.f&&(b=this.f,a[2]=b);null!==this.b&&(b=this.b,a[3]=b);return a};function fh(a){a.a=null;a.c=null;a.f=null;a.b=null}cg.prototype.getExtension=function(){return null}; +function gh(a,b){for(;G(b);)switch(b.a){case 1:var c=M(b);a.a=c;break;case 2:c=M(b);a.c=c;break;case 3:c=M(b);a.f=c;break;case 4:c=L(b);a.b=c;break;default:H(b)}}dg.prototype.w=function(){var a=[];if(null!==this.g){var b=this.g;a[0]=b}null!==this.a&&(b=this.a,a[1]=b);null!==this.b&&(b=this.b,a[2]=b);null!==this.c&&(b=this.c,a[3]=b);null!==this.f&&(b=this.f,a[4]=b);return a};function hh(a){a.g=null;a.a=null;a.b=null;a.c=null;a.f=null}dg.prototype.getExtension=function(){return null}; +function ih(a){if(null===a)a=null;else{var b=new dg;hh(b);b.g=a.g;b.a=a.a;b.b=a.b;b.c=a.c;b.f=a.f;a=b}return a}function jh(a,b){for(;G(b);)switch(b.a){case 1:var c=K(b);a.g=c;break;case 2:c=K(b);a.a=c;break;case 3:c=K(b);a.b=c;break;case 4:c=M(b);a.c=c;break;case 5:c=M(b);a.f=c;break;default:H(b)}}function kh(a,b){return a===b?!0:null===a||null===b?!1:a.g!==b.g||a.a!==b.a||a.b!==b.b||a.c!==b.c||a.f!==b.f?!1:!0} +eg.prototype.w=function(){var a=[];if(null!==this.o){var b=this.o;a[0]=b}null!==this.b&&(b=this.b,b=b.w(),a[1]=b);null!==this.l&&(b=this.l,a[2]=b);null!==this.m&&(b=this.m,a[3]=b);if(null!==this.a){b=this.a;b=b.slice();for(var c=0;c<b.length;c++)b[c]=b[c].w();a[4]=b}null!==this.j&&(b=this.j,a[5]=b);null!==this.i&&(b=this.i,a[6]=b);null!==this.g&&(b=this.g,a[7]=b);null!==this.h&&(b=this.h,a[8]=b);null!==this.f&&(b=this.f,a[9]=b);null!==this.c&&(b=this.c,a[10]=b);return a}; +function Dg(a){var b=new eg;lh(b);b.o=a.o;if(a.b){var c=new cg;var d=a.b;fh(c);c.a=d.a;c.c=d.c;c.f=d.f;c.b=d.b}else c=null;b.b=c;b.l=a.l;b.m=a.m;b.a=Bd(a.a,ih);b.j=a.j;b.i=a.i;b.g=a.g;b.h=a.h;b.f=a.f;b.c=a.c;return b}function lh(a){a.o=null;var b=a.b;b&&fh(b);a.b=null;a.l=null;a.m=null;if(a.a)for(b=0;b<a.a.length;b++){var c=a.a[b];c&&hh(c)}a.a=null;a.j=null;a.i=null;a.g=null;a.h=null;a.f=null;a.c=null}eg.prototype.getExtension=function(){return null};function Og(a){a&&lh(a)} +function pg(a,b){for(;G(b);)switch(b.a){case 1:var c=J(b);a.o=c;break;case 2:c=new cg;O(b,c,gh);a.b=c;break;case 3:c=K(b);a.l=c;break;case 4:c=J(b);a.m=c;break;case 5:c=new dg;O(b,c,jh);a.a=a.a||[];a.a.push(c);break;case 6:c=J(b);a.j=c;break;case 7:c=J(b);a.i=c;break;case 8:c=J(b);a.g=c;break;case 9:c=J(b);a.h=c;break;case 10:c=J(b);a.f=c;break;case 11:c=J(b);a.c=c;break;default:H(b)}} +function mh(a,b){if(a===b)a=!0;else if(null===a||null===b)a=!1;else{var c;if(c=a.o===b.o){c=a.b;var d=b.b;c=c===d?!0:null===c||null===d?!1:c.a!==d.a||c.c!==d.c||c.f!==d.f||c.b!==d.b?!1:!0}a=c&&a.l===b.l&&a.m===b.m&&Dd(a.a,b.a,kh)&&a.j===b.j&&a.i===b.i&&a.g===b.g&&a.h===b.h&&a.f===b.f&&a.c===b.c?!0:!1}return a}fg.prototype.w=function(){var a=[];if(null!==this.b){var b=this.b;a[0]=b}null!==this.a&&(b=this.a,a[1]=b);return a};function Fg(a){var b=new fg;b.b=null;b.a=null;b.b=a.b;b.a=a.a;return b} +fg.prototype.getExtension=function(){return null};function Qg(a){a&&(a.b=null,a.a=null)}function rg(a,b){for(;G(b);)switch(b.a){case 1:var c=M(b);a.b=c;break;case 2:c=M(b);a.a=c;break;default:H(b)}}gg.prototype.w=function(){var a=[];if(null!==this.b){var b=this.b;a[0]=b}null!==this.c&&(b=this.c,a[1]=b);null!==this.a&&(b=this.a,a[2]=b);return a};gg.prototype.getExtension=function(){return null};function Rg(a){a&&(a.b=null,a.c=null,a.a=null)} +function Gg(a){if(null===a)a=null;else{var b=new gg;b.b=null;b.c=null;b.a=null;b.b=a.b;b.c=a.c;b.a=a.a;a=b}return a}function sg(a,b){for(;G(b);)switch(b.a){case 1:var c=N(b);a.b=c;break;case 2:c=L(b);a.c=c;break;case 3:c=J(b);a.a=c;break;default:H(b)}}function nh(a,b){return a===b?!0:null===a||null===b?!1:a.b!==b.b||a.c!==b.c||a.a!==b.a?!1:!0}hg.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;b=b.slice();a[0]=b}null!==this.c&&(b=this.c,a[1]=b);null!==this.b&&(b=this.b,a[2]=b);return a}; +hg.prototype.getExtension=function(){return null};function Pg(a){a&&(a.a=null,a.c=null,a.b=null)}function Eg(a){if(null===a)a=null;else{var b=new hg;b.a=null;b.c=null;b.b=null;b.a=Ad(a.a);b.c=a.c;b.b=a.b;a=b}return a}function qg(a,b){for(;G(b);)switch(b.a){case 1:var c=M(b);a.a=a.a||[];a.a.push(c);break;case 2:c=M(b);a.c=c;break;case 3:c=J(b);a.b=c;break;default:H(b)}}function oh(a,b){return a===b?!0:null===a||null===b?!1:Cd(a.a,b.a)&&a.c===b.c&&a.b===b.b?!0:!1} +ig.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;a[0]=b}null!==this.b&&(b=this.b,a[1]=b);return a};function Hg(a){var b=new ig;b.a=null;b.b=null;b.a=a.a;b.b=a.b;return b}ig.prototype.getExtension=function(){return null};function Sg(a){a&&(a.a=null,a.b=null)}function tg(a,b){for(;G(b);)switch(b.a){case 1:var c=J(b);a.a=c;break;case 2:c=J(b);a.b=c;break;default:H(b)}} +jg.prototype.w=function(){var a=[];if(null!==this.c){var b=this.c;a[0]=b}null!==this.f&&(b=this.f,a[1]=b);null!==this.g&&(b=this.g,a[2]=b);null!==this.b&&(b=this.b,a[3]=b);null!==this.a&&(b=this.a,a[4]=b);return a};function Ig(a){var b=new jg;ph(b);b.c=a.c;b.f=a.f;b.g=a.g;b.b=a.b;b.a=a.a;return b}function ph(a){a.c=null;a.f=null;a.g=null;a.b=null;a.a=null}jg.prototype.getExtension=function(){return null};function Tg(a){a&&ph(a)} +function ug(a,b){for(;G(b);)switch(b.a){case 1:var c=M(b);a.c=c;break;case 2:c=M(b);a.f=c;break;case 3:c=M(b);a.g=c;break;case 4:c=M(b);a.b=c;break;case 5:c=M(b);a.a=c;break;default:H(b)}};function qh(a){this.data=a||[]}var rh;F(qh,W);function sh(a){this.data=a||[]}var th;F(sh,W);function uh(a){this.data=a||[]}var vh;F(uh,W);function wh(a){this.data=a||[]}var xh;F(wh,W);var yh,zh;function Ah(a){this.data=a||[]}var Bh;F(Ah,W);function Ch(a){this.data=a||[]}var Dh;F(Ch,W);function Eh(a){this.data=a||[]}var Fh;F(Eh,W);var Gh;function Hh(a){this.data=a||[]}var Ih;F(Hh,W);function Jh(a){this.data=a||[]}var Kh;F(Jh,W);var Lh,Mh;function Nh(a){this.data=a||[]}var Oh;F(Nh,W); +function Ph(a){this.data=a||[]}var Qh;F(Ph,W); +function Rh(){var a=rh={a:-1,F:[]},b=new sh([]);th||(th={a:-1,F:[,U,R,P]});b=V(b,th);var c=V(new wh([]),Sh()),d=pe(Sh()),e=he(22),f=new Ch([]);Dh||(Dh={a:-1,F:[,R,Q,Q,Q,Q,Q]});f=V(f,Dh);var g=new Ah([]);Bh||(Bh={a:-1,F:[,R,R,R]});g=V(g,Bh);var h=he(1),k=he(1),l=pe(Sh()),m=new Hh([]);if(!Ih){var n=Ih={a:-1,F:[]},p=ae(-1),q=new Eh([]);Fh||(Fh={a:-1,F:[,Q,Q,Q,U]});q=V(q,Fh);Gh||(Gh={a:-1,F:[,R,R,R,Q,Q]});n.F=[,p,q,R,P,pe(Gh),ae(-1),P,P,P,P,P]}m=V(m,Ih);Mh||(Mh={a:-1,F:[]},Mh.F=[,ee,Q,ae(-1)]);n=pe(Mh); +p=new Jh([]);Kh||(Kh={a:-1,F:[,Q,Q]});p=V(p,Kh);Lh||(Lh={a:-1,F:[]},Lh.F=[,he(1),U,P]);q=pe(Lh);var t=new Nh([]);Oh||(Oh={a:-1,F:[,P,P]});t=V(t,Oh);var v=new Ph([]);Qh||(Qh={a:-1,F:[,Q,Q,Q,Q,Q]});v=V(v,Qh);zh||(zh={a:-1,F:[]},zh.F=[,U,pe(Sh())]);a.F=[,T,U,b,U,c,d,R,Q,Q,Q,Q,Q,Q,Q,Q,Q,Q,Q,Q,Q,U,Q,e,Q,Q,U,f,g,h,k,ie,Q,U,Q,Q,Q,Q,R,T,l,U,U,R,Q,Q,Q,Q,Q,Q,Q,Q,Q,Q,Q,m,Q,n,Q,p,q,,Q,Q,Q,t,Q,Q,v,pe(zh)]}qh.prototype.getContext=function(){return ye(this,38,0)};sh.prototype.wa=function(){return ze(this,0)}; +function Sh(){if(!xh){var a=xh={a:-1,F:[]},b=ae(-1);yh||(yh={a:-1,F:[,T]});var c=pe(yh),d=new uh([]);vh||(vh={a:-1,F:[,Yd,Q,Q,Q,Q]});a.F=[,b,Q,ee,P,T,P,P,c,T,V(d,vh)]}return xh};function Th(){this.b=this.a=null}Th.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;b=b.slice();a[0]=b}null!==this.b&&(b=this.b,a[1]=b);return a};Th.prototype.getExtension=function(){return null};function Uh(a,b){for(;G(b);)switch(b.a){case 1:var c=J(b);a.a=a.a||[];a.a.push(c);break;case 2:c=J(b);a.b=c;break;default:H(b)}};function Vh(){this.b=this.u=this.a=this.l=this.h=this.c=this.m=this.i=this.j=this.g=this.f=this.s=this.o=null} +Vh.prototype.w=function(){var a=[];if(null!==this.o){var b=this.o;a[0]=b}null!==this.s&&(b=this.s,a[1]=b);null!==this.f&&(b=this.f,a[4]=b);null!==this.g&&(b=this.g,a[5]=b);null!==this.j&&(b=this.j,a[6]=b);null!==this.i&&(b=this.i,a[7]=b);null!==this.m&&(b=this.m,a[8]=b);null!==this.c&&(b=this.c,a[9]=b);null!==this.h&&(b=this.h,a[10]=b);null!==this.l&&(b=this.l,b=Oc(b,!1),a[11]=b);null!==this.a&&(b=this.a,b=b.w(),a[12]=b);null!==this.u&&(b=this.u,a[13]=b);null!==this.b&&(b=this.b,b=b.w(),a[14]=b); +return a};function Wh(a){var b=new Vh;Xh(b);b.o=a.o;b.s=a.s;b.f=a.f;b.g=a.g;b.j=a.j;b.i=a.i;b.m=a.m;b.c=a.c;b.h=a.h;b.l=a.l;b.a=a.a?Bf(a.a):null;b.u=a.u;if(a.b){var c=new Th;a=a.b;c.a=null;c.b=null;c.a=Ad(a.a);c.b=a.b}else c=null;b.b=c;return b}function Xh(a){a.o=null;a.s=null;a.f=null;a.g=null;a.j=null;a.i=null;a.m=null;a.c=null;a.h=null;a.l=null;var b=a.a;b&&Cf(b);a.a=null;a.u=null;if(b=a.b)b.a=null,b.b=null;a.b=null}Vh.prototype.getExtension=function(){return null}; +function Yh(a,b){for(;G(b);)switch(b.a){case 1:var c=J(b);a.o=c;break;case 2:c=J(b);a.s=c;break;case 5:c=J(b);a.f=c;break;case 6:c=J(b);a.g=c;break;case 7:c=J(b);a.j=c;break;case 8:c=J(b);a.i=c;break;case 9:c=J(b);a.m=c;break;case 10:c=K(b);a.c=c;break;case 11:c=J(b);a.h=c;break;case 12:c=pd(b);a.l=c;break;case 13:c=new wf;O(b,c,Df);a.a=c;break;case 14:c=J(b);a.u=c;break;case 15:c=new Th;O(b,c,Uh);a.b=c;break;default:H(b)}} +function Zh(a,b){if(a===b)b=!0;else if(null===a||null===b)b=!1;else{var c;if(c=a.o===b.o&&a.s===b.s&&a.f===b.f&&a.g===b.g&&a.j===b.j&&a.i===b.i&&a.m===b.m&&a.c===b.c&&a.h===b.h&&a.l===b.l&&Ef(a.a,b.a)&&a.u===b.u)a=a.b,b=b.b,c=a===b?!0:null===a||null===b?!1:Cd(a.a,b.a)&&a.b===b.b?!0:!1;b=c?!0:!1}return b};function $h(a){this.data=a||[]}var ai;F($h,W);function bi(a){this.data=a||[]}var ci;F(bi,W);function di(){if(!ci){var a=ci={a:-1,F:[]},b=ae(-1),c=ae(-1),d=ae(-1),e=ae(-1),f=ae(-1),g=Vd("y",""),h=V(new Kf([]),Nf()),k=ae(-1),l=new $h([]);ai||(ai={a:-1,F:[,ce,P]});a.F=[,b,P,,,c,d,P,P,e,R,f,g,h,k,V(l,ai)]}return ci};function ei(){this.g=this.f=this.a=this.c=this.b=null}ei.prototype.w=function(){var a=[];if(null!==this.b){var b=this.b;b=b.w();a[0]=b}null!==this.c&&(b=this.c,b=b.w(),a[1]=b);null!==this.a&&(b=this.a,b=b.w(),a[2]=b);null!==this.f&&(b=this.f,a[3]=b);null!==this.g&&(b=this.g,a[4]=b);return a};function fi(a){var b=a.b;b&&yf(b);a.b=null;(b=a.c)&&Xh(b);a.c=null;(b=a.a)&&Cf(b);a.a=null;a.f=null;a.g=null}ei.prototype.getExtension=function(){return null}; +function gi(a,b){for(;G(b);)switch(b.a){case 1:var c=new vf;O(b,c,zf);a.b=c;break;case 2:c=new Vh;O(b,c,Yh);a.c=c;break;case 3:c=new wf;O(b,c,Df);a.a=c;break;case 4:c=L(b);a.f=c;break;case 5:c=L(b);a.g=c;break;default:H(b)}};function hi(){this.a=null}hi.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;b=b.w();a[0]=b}return a};function ii(a){var b=a.a;b&&fi(b);a.a=null}hi.prototype.getExtension=function(){return null};function ji(a,b){for(;G(b);)switch(b.a){case 1:var c=new ei;O(b,c,gi);a.a=c;break;default:H(b)}};function ki(a){this.data=a||[]}var li;F(ki,W);function mi(a){this.data=a||[]}var ni;F(mi,W);function oi(){this.a=this.g=this.h=this.c=this.f=this.j=this.l=this.m=this.b=this.i=this.o=null} +oi.prototype.w=function(){var a=[];if(null!==this.o){var b=this.o;a[0]=b}null!==this.i&&(b=this.i,a[2]=b);null!==this.b&&(b=this.b,b=b.slice(),a[3]=b);null!==this.m&&(b=this.m,a[4]=b);null!==this.l&&(b=this.l,a[5]=b);null!==this.j&&(b=this.j,a[6]=b);null!==this.f&&(b=this.f,b=b.w(),a[10]=b);null!==this.c&&(b=this.c,b=b.w(),a[231]=b);null!==this.h&&(b=this.h,b=b.slice(),a[259]=b);null!==this.g&&(b=this.g,b=b.slice(),a[329]=b);return a}; +function pi(a){a.o=null;a.i=null;a.b=null;a.m=null;a.l=null;a.j=null;var b=a.f;b&&Gf(b);a.f=null;(b=a.c)&&ii(b);a.c=null;a.h=null;a.g=null;if(a.a)for(b=0;b<a.a.length;b++)wd(a.a[b]);a.a=null}var qi=[]; +oi.prototype.getExtension=function(a){var b=!1;67<=a&&68>a&&(b=!0);259<=a&&260>a&&(b=!0);270<=a&&271>a&&(b=!0);271<=a&&272>a&&(b=!0);278<=a&&279>a&&(b=!0);234<=a&&235>a&&(b=!0);291<=a&&292>a&&(b=!0);292<=a&&293>a&&(b=!0);294<=a&&295>a&&(b=!0);296<=a&&297>a&&(b=!0);302<=a&&303>a&&(b=!0);304<=a&&305>a&&(b=!0);312<=a&&313>a&&(b=!0);313<=a&&314>a&&(b=!0);317<=a&&318>a&&(b=!0);319<=a&&320>a&&(b=!0);338<=a&&339>a&&(b=!0);355<=a&&356>a&&(b=!0);356<=a&&357>a&&(b=!0);363<=a&&364>a&&(b=!0);368<=a&&369>a&&(b= +!0);return b?Id(this.a,a):null};function ri(a){if(null===a)a=null;else{var b=new oi;pi(b);b.o=a.o;b.i=a.i;b.b=Ad(a.b);b.m=a.m;b.l=a.l;b.j=a.j;if(a.f){var c=new Ff;var d=a.f;Gf(c);c.b=d.b?xf(d.b):null;c.a=d.a?Bf(d.a):null;c.c=d.c;c.f=d.f}else c=null;b.f=c;if(a.c){c=new hi;var e=a.c;ii(c);e.a?(d=new ei,e=e.a,fi(d),d.b=e.b?xf(e.b):null,d.c=e.c?Wh(e.c):null,d.a=e.a?Bf(e.a):null,d.f=e.f,d.g=e.g):d=null;c.a=d}else c=null;b.c=c;b.h=Ad(a.h);b.g=Ad(a.g);b.a=xd(a.a);a=b}return a} +function si(a,b){for(;G(b);)switch(b.a){case 1:var c=J(b);a.o=c;break;case 3:c=J(b);a.i=c;break;case 4:c=J(b);a.b=a.b||[];a.b.push(c);break;case 5:c=L(b);a.m=c;break;case 6:c=N(b);a.l=c;break;case 7:c=J(b);a.j=c;break;case 11:c=new Ff;O(b,c,Hf);a.f=c;break;case 232:c=new hi;O(b,c,ji);a.c=c;break;case 260:c=L(b);a.h=a.h||[];a.h.push(c);break;case 330:c=J(b);a.g=a.g||[];a.g.push(c);break;default:a.a=a.a||[],c=Jd(b,qi),a.a.push(c)}} +function ti(a,b){if(a===b)a=!0;else if(null===a||null===b)a=!1;else{var c;if(c=a.o===b.o&&a.i===b.i&&Cd(a.b,b.b)&&a.m===b.m&&a.l===b.l&&a.j===b.j){c=a.f;var d=b.f;c=c===d?!0:null===c||null===d?!1:Af(c.b,d.b)&&Ef(c.a,d.a)&&c.c===d.c&&c.f===d.f?!0:!1}c&&(d=a.c,c=b.c,d===c?c=!0:null===d||null===c?c=!1:(d=d.a,c=c.a,c=d===c||(null===d||null===c?0:Af(d.b,c.b)&&Zh(d.c,c.c)&&Ef(d.a,c.a)&&d.f===c.f&&d.g===c.g)?!0:!1));a=c&&Cd(a.h,b.h)&&Cd(a.g,b.g)&&Ed(a.a,b.a)?!0:!1}return a};var ui;function vi(){var a=[];ui={a:-1,F:a};a[1]=P;a[3]=ae(-1);a[4]=ce;a[5]=U;a[7]=P;var b=new Of([]);Pf||(Pf={a:-1,F:[]},Pf.F=[,V(new If([]),Mf()),V(new Kf([]),Nf()),ae(-1),T]);a[11]=V(b,Pf);a[330]=ce;a[6]=T;a[260]=ke;b=new mi([]);if(!ni){var c=ni={a:-1,F:[]},d=new ki([]);li||(li={a:-1,F:[]},li.F=[,V(new If([]),Mf()),V(new bi([]),di()),V(new Kf([]),Nf()),U,U]);c.F=[,V(d,li)]}a[232]=V(b,ni)};function wi(){this.b=this.a=null}function xi(){this.b=this.a=null}function yi(){this.a=this.b=null}wi.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;a[2]=b}null!==this.b&&(b=this.b,a[3]=b);return a};function zi(a){var b=new wi;Ai(b);b.a=a.a;b.b=a.b;return b}function Ai(a){a.a=null;a.b=null}wi.prototype.getExtension=function(){return null};function Bi(a,b){for(;G(b);)switch(b.a){case 3:var c=cd(b.c);a.a=c;break;case 4:c=cd(b.c);a.b=c;break;default:H(b)}} +function Ci(a,b){return a===b?!0:null===a||null===b?!1:a.a!==b.a||a.b!==b.b?!1:!0}xi.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;a[0]=b}null!==this.b&&(b=this.b,a[1]=b);return a};function Di(a){var b=new xi;b.a=null;b.b=null;b.a=a.a;b.b=a.b;return b}xi.prototype.getExtension=function(){return null};function Ei(a,b){for(;G(b);)switch(b.a){case 1:var c=J(b);a.a=c;break;case 2:c=J(b);a.b=c;break;default:H(b)}} +function Fi(a,b){return a===b?!0:null===a||null===b?!1:a.a!==b.a||a.b!==b.b?!1:!0}yi.prototype.w=function(){var a=[];if(null!==this.b){var b=this.b;b=b.w();a[0]=b}null!==this.a&&(b=this.a,b=b.w(),a[1]=b);return a};function Gi(a){var b=a.b;b&&(b.a=null,b.b=null);a.b=null;if(b=a.a)b.a=null,b.b=null;a.a=null}yi.prototype.getExtension=function(){return null};function Hi(a){if(null===a)a=null;else{var b=new yi;Gi(b);b.b=a.b?Di(a.b):null;b.a=a.a?Di(a.a):null;a=b}return a} +function Ii(a,b){for(;G(b);)switch(b.a){case 1:var c=new xi;O(b,c,Ei);a.b=c;break;case 2:c=new xi;O(b,c,Ei);a.a=c;break;default:H(b)}}function Ji(a,b){return a===b?!0:null===a||null===b?!1:Fi(a.b,b.b)&&Fi(a.a,b.a)?!0:!1};function Ki(){this.c=this.a=this.g=this.f=this.b=null}Ki.prototype.w=function(){var a=[];if(null!==this.b){var b=this.b;a[0]=b}null!==this.f&&(b=this.f,a[1]=b);null!==this.g&&(b=this.g,a[2]=b);null!==this.a&&(b=this.a,a[3]=b);null!==this.c&&(b=this.c,a[4]=b);return a};function Li(a){var b=new Ki;Mi(b);b.b=a.b;b.f=a.f;b.g=a.g;b.a=a.a;b.c=a.c;return b}function Mi(a){a.b=null;a.f=null;a.g=null;a.a=null;a.c=null}Ki.prototype.getExtension=function(){return null}; +function Ni(a,b){for(;G(b);)switch(b.a){case 1:var c=J(b);a.b=c;break;case 2:c=J(b);a.f=c;break;case 3:c=J(b);a.g=c;break;case 4:c=N(b);a.a=c;break;case 5:c=L(b);a.c=c;break;default:H(b)}}function Oi(a,b){return a===b?!0:null===a||null===b?!1:a.b!==b.b||a.f!==b.f||a.g!==b.g||a.a!==b.a||a.c!==b.c?!1:!0};function Pi(){this.f=this.c=this.b=this.a=null}function Qi(){this.b=this.c=this.a=null}function Ri(){this.b=this.c=this.a=null}function Si(){this.a=this.b=null}Pi.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;b=b.w();a[0]=b}null!==this.b&&(b=this.b,b=b.w(),a[1]=b);null!==this.c&&(b=this.c,b=b.w(),a[2]=b);null!==this.f&&(b=this.f,a[3]=b);return a}; +function Ti(a){var b=new Pi;Ui(b);if(a.a){var c=a.a;var d=new Qi;d.a=null;d.c=null;d.b=null;d.a=c.a;d.c=c.c;d.b=c.b;c=d}else c=null;b.a=c;a.b?(c=a.b,d=new Ri,d.a=null,d.c=null,d.b=null,d.a=c.a,d.c=c.c,d.b=c.b,c=d):c=null;b.b=c;a.c?(c=a.c,d=new Si,d.b=null,d.a=null,d.b=c.b,d.a=c.a,c=d):c=null;b.c=c;b.f=a.f;return b}function Ui(a){var b=a.a;b&&(b.a=null,b.c=null,b.b=null);a.a=null;if(b=a.b)b.a=null,b.c=null,b.b=null;a.b=null;if(b=a.c)b.b=null,b.a=null;a.c=null;a.f=null}Pi.prototype.getExtension=function(){return null}; +function Vi(a,b){for(;G(b);)switch(b.a){case 1:var c=new Qi;O(b,c,Wi);a.a=c;break;case 2:c=new Ri;O(b,c,Xi);a.b=c;break;case 3:c=new Si;O(b,c,Yi);a.c=c;break;case 4:c=md(b);a.f=c;break;default:H(b)}} +function Zi(a,b){if(a===b)a=!0;else if(null===a||null===b)a=!1;else{var c=a.a,d=b.a;if(c=c===d?!0:null===c||null===d?!1:c.a!==d.a||c.c!==d.c||c.b!==d.b?!1:!0)c=a.b,d=b.b,c=c===d?!0:null===c||null===d?!1:c.a!==d.a||c.c!==d.c||c.b!==d.b?!1:!0;c&&(c=a.c,d=b.c,c=c===d?!0:null===c||null===d?!1:c.b!==d.b||c.a!==d.a?!1:!0);a=c&&a.f===b.f?!0:!1}return a}Qi.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;a[0]=b}null!==this.c&&(b=this.c,a[1]=b);null!==this.b&&(b=this.b,a[2]=b);return a}; +Qi.prototype.getExtension=function(){return null};function Wi(a,b){for(;G(b);)switch(b.a){case 1:var c=cd(b.c);a.a=c;break;case 2:c=cd(b.c);a.c=c;break;case 3:c=cd(b.c);a.b=c;break;default:H(b)}}Qi.prototype.ud=function(){return null==this.a?0:this.a};Ri.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;a[0]=b}null!==this.c&&(b=this.c,a[1]=b);null!==this.b&&(b=this.b,a[2]=b);return a};Ri.prototype.getExtension=function(){return null}; +function Xi(a,b){for(;G(b);)switch(b.a){case 1:var c=md(b);a.a=c;break;case 2:c=md(b);a.c=c;break;case 3:c=md(b);a.b=c;break;default:H(b)}}Si.prototype.w=function(){var a=[];if(null!==this.b){var b=this.b;a[0]=b}null!==this.a&&(b=this.a,a[1]=b);return a};Si.prototype.getExtension=function(){return null};function Yi(a,b){for(;G(b);)switch(b.a){case 1:var c=J(b);a.b=c;break;case 2:c=J(b);a.a=c;break;default:H(b)}};function $i(){this.v=this.u=this.s=this.a=this.m=this.j=this.g=this.i=this.h=this.f=this.b=this.c=this.o=this.l=null} +$i.prototype.w=function(){var a=[];if(null!==this.l){var b=this.l;a[0]=b}null!==this.o&&(b=this.o,a[1]=b);null!==this.c&&(b=this.c,b=b.w(),a[2]=b);null!==this.b&&(b=this.b,b=b.w(),a[3]=b);null!==this.f&&(b=this.f,a[4]=b);null!==this.h&&(b=this.h,a[5]=b);null!==this.i&&(b=this.i,a[6]=b);null!==this.g&&(b=this.g,a[8]=b);null!==this.j&&(b=this.j,a[9]=b);null!==this.m&&(b=this.m,a[10]=b);aj(this);null!==this.a&&(b=this.a,b=Dc(b),a[11]=b);return a}; +function bj(a){var b=new $i;cj(b);b.l=a.l;b.o=a.o;b.c=a.c?Ti(a.c):null;b.b=a.b?zi(a.b):null;b.f=a.f;b.h=a.h;b.i=a.i;b.g=a.g;b.j=a.j;b.m=a.m;b.a=a.a?new Uint8Array(a.a):null;b.s=a.s;b.u=a.u;b.v=a.v;return b}function cj(a){a.l=null;a.o=null;var b=a.c;b&&Ui(b);a.c=null;(b=a.b)&&Ai(b);a.b=null;a.f=null;a.h=null;a.i=null;a.g=null;a.j=null;a.m=null;a.a=null;a.s=null;a.u=null}$i.prototype.getExtension=function(){return null}; +function dj(a,b){for(a.v=jd(b);G(b);)switch(b.a){case 1:var c=L(b);a.l=c;break;case 2:c=L(b);a.o=c;break;case 3:c=new Pi;O(b,c,Vi);a.c=c;break;case 4:c=new wi;O(b,c,Bi);a.b=c;break;case 5:c=N(b);a.f=c;break;case 6:c=K(b);a.h=c;break;case 7:c=K(b);a.i=c;break;case 9:c=N(b);a.g=c;break;case 10:c=J(b);a.j=c;break;case 11:c=L(b);a.m=c;break;case 12:null===a.s&&(a.s=b.b);kd(b);a.u=id(b);break;default:H(b)}} +function ej(a,b){a===b?a=!0:null===a||null===b?a=!1:a.l===b.l&&a.o===b.o&&Zi(a.c,b.c)&&Ci(a.b,b.b)&&a.f===b.f&&a.h===b.h&&a.i===b.i&&a.g===b.g&&a.j===b.j&&a.m===b.m?(aj(a),a=Cd(a.a,b.a)?!0:!1):a=!1;return a}function aj(a){null!=a.s&&null==a.a&&(a.a=Gd(a.v,a.s,a.u))};function fj(){this.b=this.a=null}fj.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;b=b.slice();for(var c=0;c<b.length;c++)b[c]=b[c].w();a[0]=b}null!==this.b&&(b=this.b,a[1]=b);return a};function gj(a){if(a.a)for(var b=0;b<a.a.length;b++){var c=a.a[b];c&&Gi(c)}a.a=null;a.b=null}fj.prototype.getExtension=function(){return null};function hj(a,b){for(;G(b);)switch(b.a){case 1:var c=new yi;O(b,c,Ii);a.a=a.a||[];a.a.push(c);break;case 2:c=K(b);a.b=c;break;default:H(b)}};function ij(){this.u=this.f=this.g=this.v=this.c=this.K=this.L=this.W=this.U=this.s=this.J=this.V=this.l=this.j=this.P=this.S=this.m=this.h=this.M=this.O=this.B=this.C=this.D=this.i=this.H=this.G=this.I=this.b=this.a=this.T=this.A=this.o=null} +ij.prototype.w=function(){var a=[];if(null!==this.o){var b=this.o;a[0]=b}null!==this.A&&(b=this.A,a[1]=b);null!==this.T&&(b=this.T,a[2]=b);null!==this.a&&(b=this.a,a[3]=b);null!==this.b&&(b=this.b,a[6]=b);null!==this.I&&(b=this.I,a[8]=b);null!==this.G&&(b=this.G,a[16]=b);null!==this.H&&(b=this.H,a[17]=b);null!==this.i&&(b=this.i,a[19]=b);null!==this.D&&(b=this.D,a[22]=b);null!==this.C&&(b=this.C,a[23]=b);null!==this.B&&(b=this.B,a[24]=b);null!==this.O&&(b=this.O,a[25]=b);null!==this.M&&(b=this.M, +a[26]=b);null!==this.h&&(b=this.h,a[27]=b);null!==this.m&&(b=this.m,a[28]=b);null!==this.S&&(b=this.S,a[31]=b);null!==this.P&&(b=this.P,a[32]=b);null!==this.j&&(b=this.j,a[38]=b);null!==this.l&&(b=this.l,a[39]=b);null!==this.V&&(b=this.V,a[40]=b);null!==this.J&&(b=this.J,a[41]=b);null!==this.s&&(b=this.s,a[42]=b);null!==this.U&&(b=this.U,a[43]=b);null!==this.W&&(b=this.W,a[44]=b);null!==this.L&&(b=this.L,a[45]=b);null!==this.K&&(b=this.K,a[46]=b);null!==this.c&&(b=this.c,a[47]=b);null!==this.v&&(b= +this.v,a[48]=b);null!==this.g&&(b=this.g,a[49]=b);null!==this.f&&(b=this.f,a[50]=b);null!==this.u&&(b=this.u,a[51]=b);return a};function jj(a,b){kj(a);a.o=b.o;a.A=b.A;a.T=b.T;a.a=b.a;a.b=b.b;a.I=b.I;a.G=b.G;a.H=b.H;a.i=b.i;a.D=b.D;a.C=b.C;a.B=b.B;a.O=b.O;a.M=b.M;a.h=b.h;a.m=b.m;a.S=b.S;a.P=b.P;a.j=b.j;a.l=b.l;a.V=b.V;a.J=b.J;a.s=b.s;a.U=b.U;a.W=b.W;a.L=b.L;a.K=b.K;a.c=b.c;a.v=b.v;a.g=b.g;a.f=b.f;a.u=b.u} +function kj(a){a.o=null;a.A=null;a.T=null;a.a=null;a.b=null;a.I=null;a.G=null;a.H=null;a.i=null;a.D=null;a.C=null;a.B=null;a.O=null;a.M=null;a.h=null;a.m=null;a.S=null;a.P=null;a.j=null;a.l=null;a.V=null;a.J=null;a.s=null;a.U=null;a.W=null;a.L=null;a.K=null;a.c=null;a.v=null;a.g=null;a.f=null;a.u=null}ij.prototype.getExtension=function(){return null}; +function lj(a,b){for(;G(b);)switch(b.a){case 1:var c=K(b);a.o=c;break;case 2:c=J(b);a.A=c;break;case 3:c=J(b);a.T=c;break;case 4:c=K(b);a.a=c;break;case 7:c=J(b);a.b=c;break;case 9:c=L(b);a.I=c;break;case 17:c=K(b);a.G=c;break;case 18:c=K(b);a.H=c;break;case 20:c=J(b);a.i=c;break;case 23:c=K(b);a.D=c;break;case 24:c=J(b);a.C=c;break;case 25:c=K(b);a.B=c;break;case 26:c=J(b);a.O=c;break;case 27:c=J(b);a.M=c;break;case 28:c=cd(b.c);a.h=c;break;case 29:c=K(b);a.m=c;break;case 32:c=J(b);a.S=c;break;case 33:c= +J(b);a.P=c;break;case 39:c=J(b);a.j=c;break;case 40:c=J(b);a.l=c;break;case 41:c=J(b);a.V=c;break;case 42:c=K(b);a.J=c;break;case 43:c=J(b);a.s=c;break;case 44:c=K(b);a.U=c;break;case 45:c=K(b);a.W=c;break;case 46:c=J(b);a.L=c;break;case 47:c=J(b);a.K=c;break;case 48:c=K(b);a.c=c;break;case 49:c=K(b);a.v=c;break;case 50:c=K(b);a.g=c;break;case 51:c=K(b);a.f=c;break;case 52:c=L(b);a.u=c;break;default:H(b)}};function mj(){this.a=this.b=this.c=this.f=null}mj.prototype.w=function(){var a=[];if(null!==this.f){var b=this.f;a[0]=b}null!==this.c&&(b=this.c,a[1]=b);null!==this.b&&(b=this.b,a[2]=b);null!==this.a&&(b=this.a,a[3]=b);return a};function nj(a){a.f=null;a.c=null;a.b=null;a.a=null}mj.prototype.getExtension=function(){return null};function oj(a,b){for(;G(b);)switch(b.a){case 1:var c=L(b);a.f=c;break;case 2:c=md(b);a.c=c;break;case 3:c=L(b);a.b=c;break;case 4:c=L(b);a.a=c;break;default:H(b)}};function pj(){this.f=this.a=this.g=this.s=this.h=this.v=this.i=this.o=this.b=this.m=this.l=this.j=this.c=this.u=this.A=null}function sj(){this.g=this.f=this.c=this.a=this.b=null}function tj(){this.a=this.b=null}function uj(){this.b=this.c=this.a=null}function vj(){this.S=this.u=this.J=this.T=this.P=this.a=this.D=this.I=this.L=this.V=this.A=this.C=this.B=this.l=this.i=this.f=this.H=this.g=this.G=this.M=this.O=this.h=this.U=this.v=this.K=this.s=this.c=this.o=this.m=this.b=this.j=null} +function wj(){this.a=null}function xj(){this.l=this.h=this.b=this.j=this.i=this.a=this.f=this.c=this.g=null}function yj(){this.f=this.j=this.a=this.i=this.c=this.b=this.g=this.h=null}function zj(){this.c=this.b=this.f=this.a=null}function Aj(){this.h=this.c=this.a=this.g=this.f=this.b=this.o=this.i=this.j=this.l=this.m=null}function Bj(){this.a=null}function Cj(){this.a=this.b=null}function Dj(){this.a=this.b=null}function Ej(){this.l=this.f=this.i=this.g=this.a=this.h=this.j=this.c=this.b=null} +function Fj(){this.a=null}function Gj(){this.b=this.a=null}function Hj(){this.g=this.a=this.b=this.f=this.h=this.c=null} +pj.prototype.w=function(){var a=[];if(null!==this.A){var b=this.A;a[0]=b}null!==this.u&&(b=this.u,a[1]=b);null!==this.c&&(b=this.c,b=b.w(),a[2]=b);null!==this.j&&(b=this.j,a[3]=b);null!==this.l&&(b=this.l,a[4]=b);null!==this.m&&(b=this.m,a[5]=b);null!==this.b&&(b=this.b,b=b.w(),a[6]=b);null!==this.o&&(b=this.o,a[7]=b);null!==this.i&&(b=this.i,a[8]=b);null!==this.v&&(b=this.v,a[10]=b);null!==this.h&&(b=this.h,a[11]=b);null!==this.s&&(b=this.s,a[12]=b);null!==this.g&&(b=this.g,a[13]=b);null!==this.a&& +(b=this.a,b=b.w(),a[15]=b);null!==this.f&&(b=this.f,a[16]=b);return a};function Ij(a){var b=new pj;Jj(b);b.A=a.A;b.u=a.u;b.c=a.c?zi(a.c):null;b.j=a.j;b.l=a.l;b.m=a.m;if(a.b){var c=new mj;var d=a.b;nj(c);c.f=d.f;c.c=d.c;c.b=d.b;c.a=d.a}else c=null;b.b=c;b.o=a.o;b.i=a.i;b.v=a.v;b.h=a.h;b.s=a.s;b.g=a.g;if(a.a){d=a.a;c=new Fj;Kj(c);if(d.a){d=d.a;var e=new Gj;Lj(e);e.a=d.a?Ij(d.a):null;e.b=d.b;d=e}else d=null;c.a=d}else c=null;b.a=c;b.f=a.f;return b} +function Jj(a){a.A=null;a.u=null;var b=a.c;b&&Ai(b);a.c=null;a.j=null;a.l=null;a.m=null;(b=a.b)&&nj(b);a.b=null;a.o=null;a.i=null;a.v=null;a.h=null;a.s=null;a.g=null;(b=a.a)&&Kj(b);a.a=null;a.f=null}pj.prototype.getExtension=function(){return null};function Mj(a){return null===a?null:Ij(a)} +function Nj(a,b){for(;G(b);)switch(b.a){case 1:var c=L(b);a.A=c;break;case 2:c=L(b);a.u=c;break;case 3:c=new wi;O(b,c,Bi);a.c=c;break;case 4:c=L(b);a.j=c;break;case 5:c=N(b);a.l=c;break;case 6:c=N(b);a.m=c;break;case 7:c=new mj;O(b,c,oj);a.b=c;break;case 8:c=L(b);a.o=c;break;case 9:c=K(b);a.i=c;break;case 11:c=K(b);a.v=c;break;case 12:c=L(b);a.h=c;break;case 13:c=L(b);a.s=c;break;case 14:c=L(b);a.g=c;break;case 16:c=new Fj;O(b,c,Oj);a.a=c;break;case 17:c=J(b);a.f=c;break;default:H(b)}} +function Pj(a,b){if(a===b)a=!0;else if(null===a||null===b)a=!1;else{var c;if(c=a.A===b.A&&a.u===b.u&&Ci(a.c,b.c)&&a.j===b.j&&a.l===b.l&&a.m===b.m){c=a.b;var d=b.b;c=c===d?!0:null===c||null===d?!1:c.f!==d.f||c.c!==d.c||c.b!==d.b||c.a!==d.a?!1:!0}if(c=c&&a.o===b.o&&a.i===b.i&&a.v===b.v&&a.h===b.h&&a.s===b.s&&a.g===b.g)d=a.a,c=b.a,d===c?c=!0:null===d||null===c?c=!1:(d=d.a,c=c.a,c=d===c||(null===d||null===c?0:Pj(d.a,c.a)&&d.b===c.b)?!0:!1);a=c&&a.f===b.f?!0:!1}return a} +sj.prototype.w=function(){var a=[];if(null!==this.b){var b=this.b;a[0]=b}null!==this.a&&(b=this.a,b=b.w(),a[1]=b);null!==this.c&&(b=this.c,a[2]=b);null!==this.f&&(b=this.f,a[3]=b);null!==this.g&&(b=this.g,a[4]=b);return a};function Qj(a){a.b=null;var b=a.a;b&&Ai(b);a.a=null;a.c=null;a.f=null;a.g=null}sj.prototype.getExtension=function(){return null};function Rj(a){if(null===a)a=null;else{var b=new sj;Qj(b);b.b=a.b;b.a=a.a?zi(a.a):null;b.c=a.c;b.f=a.f;b.g=a.g;a=b}return a} +function Sj(a,b){for(;G(b);)switch(b.a){case 1:var c=J(b);a.b=c;break;case 2:c=new wi;O(b,c,Bi);a.a=c;break;case 3:c=L(b);a.c=c;break;case 4:c=md(b);a.f=c;break;case 5:c=K(b);a.g=c;break;default:H(b)}}function Tj(a,b){return a===b?!0:null===a||null===b?!1:a.b===b.b&&Ci(a.a,b.a)&&a.c===b.c&&a.f===b.f&&a.g===b.g?!0:!1}tj.prototype.w=function(){var a=[];if(null!==this.b){var b=this.b;a[0]=b}null!==this.a&&(b=this.a,a[1]=b);return a};function Uj(a,b){a.b=null;a.a=null;a.b=b.b;a.a=b.a} +tj.prototype.getExtension=function(){return null};function Vj(a,b){for(;G(b);)switch(b.a){case 1:var c=N(b);a.b=c;break;case 2:c=K(b);a.a=c;break;default:H(b)}}uj.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;a[0]=b}null!==this.c&&(b=this.c,a[1]=b);null!==this.b&&(b=this.b,b=Oc(b,!0),a[2]=b);return a};function Wj(a,b){a.a=null;a.c=null;a.b=null;a.a=b.a;a.c=b.c;a.b=b.b}uj.prototype.getExtension=function(){return null}; +function Xj(a,b){for(;G(b);)switch(b.a){case 1:var c=N(b);a.a=c;break;case 2:c=N(b);a.c=c;break;case 3:c=qd(b);a.b=c;break;default:H(b)}} +vj.prototype.w=function(){var a=[];if(null!==this.j){var b=this.j;b=b.w();a[0]=b}null!==this.b&&(b=this.b,b=b.w(),a[1]=b);null!==this.m&&(b=this.m,a[2]=b);null!==this.o&&(b=this.o,a[3]=b);null!==this.c&&(b=this.c,b=b.w(),a[5]=b);null!==this.s&&(b=this.s,a[6]=b);null!==this.K&&(b=this.K,a[7]=b);null!==this.v&&(b=this.v,a[8]=b);null!==this.U&&(b=this.U,a[9]=b);null!==this.h&&(b=this.h,b=b.w(),a[10]=b);null!==this.O&&(b=this.O,a[11]=b);null!==this.M&&(b=this.M,a[12]=b);null!==this.G&&(b=this.G,a[13]= +b);null!==this.g&&(b=this.g,b=b.slice(),a[14]=b);null!==this.H&&(b=this.H,a[15]=b);null!==this.f&&(b=this.f,b=b.w(),a[16]=b);null!==this.i&&(b=this.i,b=b.w(),a[18]=b);null!==this.l&&(b=this.l,b=b.w(),a[19]=b);null!==this.B&&(b=this.B,a[24]=b);null!==this.C&&(b=this.C,a[25]=b);null!==this.A&&(b=this.A,a[30]=b);null!==this.V&&(b=this.V,a[32]=b);null!==this.L&&(b=this.L,a[33]=b);null!==this.I&&(b=this.I,a[34]=b);null!==this.D&&(b=this.D,a[36]=b);if(null!==this.a){b=this.a;b=b.slice();for(var c=0;c<b.length;c++)b[c]= +b[c].w();a[37]=b}null!==this.P&&(b=this.P,a[38]=b);null!==this.T&&(b=this.T,a[39]=b);null!==this.J&&(b=this.J,a[40]=b);null!==this.u&&(b=this.u,a[41]=b);null!==this.S&&(b=this.S,a[42]=b);return a}; +function Yj(a,b){Zj(a);if(b.j){var c=b.j;var d=new Aj;ak(d);d.m=c.m;d.l=c.l;d.j=c.j;d.i=c.i;d.o=c.o;d.b=Ad(c.b);d.f=c.f;d.g=c.g;d.a=Bd(c.a,bk);if(c.c){var e=c.c;var f=new Cj;ck(f);f.b=e.b;f.a=e.a?dk(e.a):null;e=f}else e=null;d.c=e;d.h=c.h;c=d}else c=null;a.j=c;b.b?(c=b.b,d=new Ej,ek(d),d.b=c.b,d.c=c.c,d.j=c.j,d.h=c.h,c.a?(e=new xj,fk(e,c.a)):e=null,d.a=e,d.g=c.g,d.i=c.i,d.f=c.f,d.l=c.l,c=d):c=null;a.b=c;a.m=b.m;a.o=b.o;b.c?(c=new ij,jj(c,b.c)):c=null;a.c=c;a.s=b.s;a.K=b.K;a.v=b.v;a.U=b.U;b.h?(c=new tj, +Uj(c,b.h)):c=null;a.h=c;a.O=b.O;a.M=b.M;a.G=b.G;a.g=Ad(b.g);a.H=b.H;b.f?(c=b.f,d=new zj,gk(d),d.a=Ad(c.a),d.f=c.f,d.b=Ad(c.b),d.c=c.c,c=d):c=null;a.f=c;b.i?(c=new uj,Wj(c,b.i)):c=null;a.i=c;b.l?(c=b.l,d=new yj,hk(d),d.h=c.h,d.g=c.g,d.b=c.b,d.c=c.c,d.i=c.i,d.a=c.a,d.j=c.j,d.f=c.f,c=d):c=null;a.l=c;a.B=b.B;a.C=b.C;a.A=b.A;a.V=b.V;a.L=b.L;a.I=b.I;a.D=b.D;a.a=Bd(b.a,ik);a.P=b.P;a.T=b.T;a.J=b.J;a.u=b.u;a.S=b.S} +function Zj(a){var b=a.j;b&&ak(b);a.j=null;(b=a.b)&&ek(b);a.b=null;a.m=null;a.o=null;(b=a.c)&&kj(b);a.c=null;a.s=null;a.K=null;a.v=null;a.U=null;if(b=a.h)b.b=null,b.a=null;a.h=null;a.O=null;a.M=null;a.G=null;a.g=null;a.H=null;(b=a.f)&&gk(b);a.f=null;if(b=a.i)b.a=null,b.c=null,b.b=null;a.i=null;(b=a.l)&&hk(b);a.l=null;a.B=null;a.C=null;a.A=null;a.V=null;a.L=null;a.I=null;a.D=null;if(a.a)for(b=0;b<a.a.length;b++){var c=a.a[b];c&&(c.a=null)}a.a=null;a.P=null;a.T=null;a.J=null;a.u=null;a.S=null} +vj.prototype.getExtension=function(){return null}; +function jk(a,b){for(;G(b);)switch(b.a){case 1:var c=new Aj;O(b,c,kk);a.j=c;break;case 2:c=new Ej;O(b,c,lk);a.b=c;break;case 3:c=K(b);a.m=c;break;case 4:c=K(b);a.o=c;break;case 6:c=new ij;O(b,c,lj);a.c=c;break;case 7:c=K(b);a.s=c;break;case 8:c=K(b);a.K=c;break;case 9:c=N(b);a.v=c;break;case 10:c=K(b);a.U=c;break;case 11:c=new tj;O(b,c,Vj);a.h=c;break;case 12:c=K(b);a.O=c;break;case 13:c=K(b);a.M=c;break;case 14:c=K(b);a.G=c;break;case 15:c=J(b);a.g=a.g||[];a.g.push(c);break;case 16:c=K(b);a.H=c; +break;case 17:c=new zj;O(b,c,mk);a.f=c;break;case 19:c=new uj;O(b,c,Xj);a.i=c;break;case 20:c=new yj;O(b,c,nk);a.l=c;break;case 25:c=K(b);a.B=c;break;case 26:c=K(b);a.C=c;break;case 31:c=K(b);a.A=c;break;case 33:c=K(b);a.V=c;break;case 34:c=K(b);a.L=c;break;case 35:c=K(b);a.I=c;break;case 37:c=K(b);a.D=c;break;case 38:c=new wj;O(b,c,ok);a.a=a.a||[];a.a.push(c);break;case 39:c=K(b);a.P=c;break;case 40:c=K(b);a.T=c;break;case 41:c=K(b);a.J=c;break;case 42:c=K(b);a.u=c;break;case 43:c=J(b);a.S=c;break; +default:H(b)}}wj.prototype.w=function(){var a=[];null!==this.a&&(a[0]=this.a);return a};wj.prototype.getExtension=function(){return null};function ik(a){if(null===a)a=null;else{var b=new wj;b.a=null;b.a=a.a;a=b}return a}function ok(a,b){for(;G(b);)switch(b.a){case 1:a.a=J(b);break;default:H(b)}}function pk(a,b){return a===b?!0:null===a||null===b?!1:a.a!==b.a?!1:!0} +xj.prototype.w=function(){var a=[];if(null!==this.g){var b=this.g;a[1]=b}null!==this.c&&(b=this.c,a[2]=b);null!==this.f&&(b=this.f,a[3]=b);null!==this.a&&(b=this.a,a[4]=b);null!==this.i&&(b=this.i,a[5]=b);null!==this.j&&(b=this.j,a[6]=b);null!==this.b&&(b=this.b,a[8]=b);null!==this.h&&(b=this.h,a[9]=b);return a};function fk(a,b){qk(a);a.g=b.g;a.c=b.c;a.f=b.f;a.a=b.a;a.i=b.i;a.j=b.j;a.b=b.b;a.h=b.h;a.l=b.l}function qk(a){a.g=null;a.c=null;a.f=null;a.a=null;a.i=null;a.j=null;a.b=null;a.h=null} +xj.prototype.getExtension=function(){return null};function rk(a,b){for(a.l=jd(b);G(b);)switch(b.a){case 2:var c=K(b);a.g=c;break;case 3:c=K(b);a.c=c;break;case 4:c=K(b);a.f=c;break;case 5:c=K(b);a.a=c;break;case 6:c=N(b);a.i=c;break;case 7:c=N(b);a.j=c;break;case 9:c=K(b);a.b=c;break;case 10:c=N(b);a.h=c;break;default:H(b)}} +yj.prototype.w=function(){var a=[];if(null!==this.h){var b=this.h;a[0]=b}null!==this.g&&(b=this.g,a[1]=b);null!==this.b&&(b=this.b,a[2]=b);null!==this.c&&(b=this.c,a[3]=b);null!==this.i&&(b=this.i,a[4]=b);null!==this.a&&(b=this.a,a[5]=b);null!==this.j&&(b=this.j,a[6]=b);null!==this.f&&(b=this.f,a[7]=b);return a};function hk(a){a.h=null;a.g=null;a.b=null;a.c=null;a.i=null;a.a=null;a.j=null;a.f=null}yj.prototype.getExtension=function(){return null}; +function nk(a,b){for(;G(b);)switch(b.a){case 1:var c=N(b);a.h=c;break;case 2:c=N(b);a.g=c;break;case 3:c=K(b);a.b=c;break;case 4:c=K(b);a.c=c;break;case 5:c=N(b);a.i=c;break;case 6:c=K(b);a.a=c;break;case 7:c=K(b);a.j=c;break;case 8:c=K(b);a.f=c;break;default:H(b)}}zj.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;b=b.slice();a[0]=b}null!==this.f&&(b=this.f,a[1]=b);null!==this.b&&(b=this.b,b=b.slice(),a[2]=b);null!==this.c&&(b=this.c,a[3]=b);return a}; +function gk(a){a.a=null;a.f=null;a.b=null;a.c=null}zj.prototype.getExtension=function(){return null};function mk(a,b){for(;G(b);)switch(b.a){case 1:var c=N(b);a.a=a.a||[];a.a.push(c);break;case 2:c=K(b);a.f=c;break;case 3:c=N(b);a.b=a.b||[];a.b.push(c);break;case 4:c=N(b);a.c=c;break;default:H(b)}} +Aj.prototype.w=function(){var a=[];if(null!==this.m){var b=this.m;a[0]=b}null!==this.l&&(b=this.l,a[1]=b);null!==this.j&&(b=this.j,b=Oc(b,!0),a[2]=b);null!==this.i&&(b=this.i,a[4]=b);null!==this.o&&(b=this.o,a[5]=b);null!==this.b&&(b=this.b,b=b.slice(),a[6]=b);null!==this.f&&(b=this.f,a[7]=b);null!==this.g&&(b=this.g,a[8]=b);if(null!==this.a){b=this.a;b=b.slice();for(var c=0;c<b.length;c++)b[c]=b[c].w();a[9]=b}null!==this.c&&(b=this.c,b=b.w(),a[10]=b);null!==this.h&&(b=this.h,a[11]=b);return a}; +function ak(a){a.m=null;a.l=null;a.j=null;a.i=null;a.o=null;a.b=null;a.f=null;a.g=null;if(a.a)for(var b=0;b<a.a.length;b++){var c=a.a[b];c&&(c.a=null)}a.a=null;(b=a.c)&&ck(b);a.c=null;a.h=null}Aj.prototype.getExtension=function(){return null}; +function kk(a,b){for(;G(b);)switch(b.a){case 1:var c=N(b);a.m=c;break;case 2:c=N(b);a.l=c;break;case 3:c=qd(b);a.j=c;break;case 5:c=N(b);a.i=c;break;case 6:c=K(b);a.o=c;break;case 7:c=N(b);a.b=a.b||[];a.b.push(c);break;case 8:c=N(b);a.f=c;break;case 9:c=K(b);a.g=c;break;case 10:c=new Bj;O(b,c,sk);a.a=a.a||[];a.a.push(c);break;case 11:c=new Cj;O(b,c,tk);a.c=c;break;case 12:c=N(b);a.h=c;break;default:H(b)}} +function uk(a,b){if(a===b)a=!0;else if(null===a||null===b)a=!1;else{var c;if(c=a.m===b.m&&a.l===b.l&&a.j===b.j&&a.i===b.i&&a.o===b.o&&Cd(a.b,b.b)&&a.f===b.f&&a.g===b.g&&Dd(a.a,b.a,vk)){var d=a.c;c=b.c;if(d===c)c=!0;else if(null===d||null===c)c=!1;else{var e;if(e=d.b===c.b)d=d.a,c=c.a,e=d===c?!0:null===d||null===c?!1:d.b!==c.b||d.a!==c.a?!1:!0;c=e?!0:!1}}a=c&&a.h===b.h?!0:!1}return a}Bj.prototype.w=function(){var a=[];null!==this.a&&(a[0]=this.a);return a};Bj.prototype.getExtension=function(){return null}; +function bk(a){if(null===a)a=null;else{var b=new Bj;b.a=null;b.a=a.a;a=b}return a}function sk(a,b){for(;G(b);)switch(b.a){case 1:a.a=N(b);break;default:H(b)}}function vk(a,b){return a===b?!0:null===a||null===b?!1:a.a!==b.a?!1:!0}Cj.prototype.w=function(){var a=[];if(null!==this.b){var b=this.b;a[0]=b}null!==this.a&&(b=this.a,b=b.w(),a[2]=b);return a};function ck(a){a.b=null;var b=a.a;b&&(b.b=null,b.a=null);a.a=null}Cj.prototype.getExtension=function(){return null}; +function tk(a,b){for(;G(b);)switch(b.a){case 1:var c=N(b);a.b=c;break;case 3:c=new Dj;O(b,c,wk);a.a=c;break;default:H(b)}}Dj.prototype.w=function(){var a=[];if(null!==this.b){var b=this.b;a[0]=b}null!==this.a&&(b=this.a,a[1]=b);return a};function dk(a){var b=new Dj;b.b=null;b.a=null;b.b=a.b;b.a=a.a;return b}Dj.prototype.getExtension=function(){return null};function wk(a,b){for(;G(b);)switch(b.a){case 1:var c=J(b);a.b=c;break;case 2:c=J(b);a.a=c;break;default:H(b)}} +Ej.prototype.w=function(){var a=[];if(null!==this.b){var b=this.b;a[0]=b}null!==this.c&&(b=this.c,a[1]=b);null!==this.j&&(b=this.j,a[2]=b);null!==this.h&&(b=this.h,a[3]=b);null!==this.a&&(b=this.a,b=b.w(),a[4]=b);null!==this.g&&(b=this.g,a[5]=b);null!==this.i&&(b=this.i,a[6]=b);null!==this.f&&(b=this.f,a[7]=b);null!==this.l&&(b=this.l,a[19]=b);return a};function ek(a){a.b=null;a.c=null;a.j=null;a.h=null;var b=a.a;b&&qk(b);a.a=null;a.g=null;a.i=null;a.f=null;a.l=null}Ej.prototype.getExtension=function(){return null}; +function lk(a,b){for(;G(b);)switch(b.a){case 1:var c=K(b);a.b=c;break;case 2:c=K(b);a.c=c;break;case 3:c=K(b);a.j=c;break;case 4:c=K(b);a.h=c;break;case 5:c=new xj;O(b,c,rk);a.a=c;break;case 6:c=K(b);a.g=c;break;case 7:c=K(b);a.i=c;break;case 8:c=K(b);a.f=c;break;case 20:c=N(b);a.l=c;break;default:H(b)}} +function xk(a,b){if(a===b)a=!0;else if(null===a||null===b)a=!1;else{var c;if(c=a.b===b.b&&a.c===b.c&&a.j===b.j&&a.h===b.h){c=a.a;var d=b.a;c=c===d?!0:null===c||null===d?!1:c.g!==d.g||c.c!==d.c||c.f!==d.f||c.a!==d.a||c.i!==d.i||c.j!==d.j||c.b!==d.b||c.h!==d.h?!1:!0}a=c&&a.g===b.g&&a.i===b.i&&a.f===b.f&&a.l===b.l?!0:!1}return a}Fj.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;b=b.w();a[0]=b}return a};function Kj(a){var b=a.a;b&&Lj(b);a.a=null}Fj.prototype.getExtension=function(){return null}; +function Oj(a,b){for(;G(b);)switch(b.a){case 1:var c=new Gj;O(b,c,yk);a.a=c;break;default:H(b)}}Gj.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;b=b.w();a[0]=b}null!==this.b&&(b=this.b,a[1]=b);return a};function Lj(a){var b=a.a;b&&Jj(b);a.a=null;a.b=null}Gj.prototype.getExtension=function(){return null};function yk(a,b){for(;G(b);)switch(b.a){case 1:var c=new pj;O(b,c,Nj);a.a=c;break;case 2:c=K(b);a.b=c;break;default:H(b)}} +Hj.prototype.w=function(){var a=[];if(null!==this.c){var b=this.c;a[0]=b}null!==this.h&&(b=this.h,a[1]=b);null!==this.f&&(b=this.f,a[2]=b);null!==this.b&&(b=this.b,b=b.slice(),a[3]=b);null!==this.a&&(b=this.a,b=b.slice(),a[4]=b);null!==this.g&&(b=this.g,a[5]=b);return a};function zk(a){a.c=null;a.h=null;a.f=null;a.b=null;a.a=null;a.g=null}Hj.prototype.getExtension=function(){return null}; +function Ak(a,b){for(;G(b);)switch(b.a){case 1:var c=N(b);a.c=c;break;case 2:c=K(b);a.h=c;break;case 3:c=K(b);a.f=c;break;case 4:c=J(b);a.b=a.b||[];a.b.push(c);break;case 5:c=J(b);a.a=a.a||[];a.a.push(c);break;case 6:c=K(b);a.g=c;break;default:H(b)}};function Bk(){this.b=this.a=null}Bk.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;b=b.w();a[0]=b}null!==this.b&&(b=this.b,b=b.w(),a[1]=b);return a};function Ck(a){var b=a.a;b&&Cf(b);a.a=null;(b=a.b)&&Cf(b);a.b=null}Bk.prototype.getExtension=function(){return null};function Dk(a){if(null===a)a=null;else{var b=new Bk;Ck(b);b.a=a.a?Bf(a.a):null;b.b=a.b?Bf(a.b):null;a=b}return a} +function Ek(a,b){for(;G(b);)switch(b.a){case 1:var c=new wf;O(b,c,Df);a.a=c;break;case 2:c=new wf;O(b,c,Df);a.b=c;break;default:H(b)}}function Fk(a,b){return a===b?!0:null===a||null===b?!1:Ef(a.a,b.a)&&Ef(a.b,b.b)?!0:!1};function Gk(){this.a=this.c=this.b=null}Gk.prototype.w=function(){var a=[];if(null!==this.b){var b=this.b;a[0]=b}null!==this.c&&(b=this.c,a[1]=b);null!==this.a&&(b=this.a,a[2]=b);return a};Gk.prototype.getExtension=function(){return null};function Hk(a,b){for(;G(b);)switch(b.a){case 1:var c=K(b);a.b=c;break;case 2:c=L(b);a.c=c;break;case 3:c=L(b);a.a=c;break;default:H(b)}};function Ik(){this.C=this.s=this.m=this.i=this.f=this.G=this.b=this.I=this.h=this.l=this.J=this.g=this.j=this.v=this.a=this.B=this.A=this.o=this.c=this.u=this.H=this.D=null} +Ik.prototype.w=function(){var a=[];if(null!==this.D){var b=this.D;a[0]=b}null!==this.H&&(b=this.H,a[1]=b);null!==this.u&&(b=this.u,a[2]=b);null!==this.c&&(b=this.c,b=b.w(),a[3]=b);null!==this.o&&(b=this.o,a[4]=b);null!==this.A&&(b=this.A,a[5]=b);null!==this.B&&(b=this.B,a[6]=b);if(null!==this.a){b=this.a;b=b.slice();for(var c=0;c<b.length;c++)b[c]=b[c].w();a[7]=b}null!==this.v&&(b=this.v,a[8]=b);null!==this.j&&(b=this.j,a[9]=b);null!==this.g&&(b=this.g,b=b.w(),a[10]=b);null!==this.J&&(b=this.J,a[11]= +b);null!==this.l&&(b=this.l,a[12]=b);null!==this.h&&(b=this.h,b=b.w(),a[13]=b);null!==this.I&&(b=this.I,a[14]=b);if(null!==this.b){b=this.b;b=b.slice();for(c=0;c<b.length;c++)b[c]=b[c].w();a[15]=b}null!==this.G&&(b=this.G,a[16]=b);null!==this.f&&(b=this.f,b=b.slice(),a[17]=b);null!==this.i&&(b=this.i,b=b.w(),a[18]=b);null!==this.m&&(b=this.m,a[19]=b);null!==this.s&&(b=this.s,a[20]=b);null!==this.C&&(b=this.C,a[21]=b);return a}; +function Jk(a,b){Kk(a);a.D=b.D;a.H=b.H;a.u=b.u;a.c=b.c?Wh(b.c):null;a.o=b.o;a.A=b.A;a.B=b.B;a.a=Bd(b.a,ri);a.v=b.v;a.j=b.j;if(b.g){var c=new Vf;wg(c,b.g)}else c=null;a.g=c;a.J=b.J;a.l=b.l;if(b.h){c=new Gk;var d=b.h;c.b=null;c.c=null;c.a=null;c.b=d.b;c.c=d.c;c.a=d.a}else c=null;a.h=c;a.I=b.I;a.b=Bd(b.b,Dk);a.G=b.G;a.f=Ad(b.f);b.i?(c=new Qf,d=b.i,c.a=null,c.a=d.a):c=null;a.i=c;a.m=b.m;a.s=b.s;a.C=b.C} +function Kk(a){a.D=null;a.H=null;a.u=null;var b=a.c;b&&Xh(b);a.c=null;a.o=null;a.A=null;a.B=null;if(a.a)for(b=0;b<a.a.length;b++){var c=a.a[b];c&&pi(c)}a.a=null;a.v=null;a.j=null;(b=a.g)&&xg(b);a.g=null;a.J=null;a.l=null;if(b=a.h)b.b=null,b.c=null,b.a=null;a.h=null;a.I=null;if(a.b)for(b=0;b<a.b.length;b++)(c=a.b[b])&&Ck(c);a.b=null;a.G=null;a.f=null;if(b=a.i)b.a=null;a.i=null;a.m=null;a.s=null;a.C=null}Ik.prototype.getExtension=function(){return null}; +function Lk(a,b){for(;G(b);)switch(b.a){case 1:var c=L(b);a.D=c;break;case 2:c=L(b);a.H=c;break;case 3:c=K(b);a.u=c;break;case 4:c=new Vh;O(b,c,Yh);a.c=c;break;case 5:c=L(b);a.o=c;break;case 6:c=L(b);a.A=c;break;case 7:c=N(b);a.B=c;break;case 8:c=new oi;O(b,c,si);a.a=a.a||[];a.a.push(c);break;case 9:c=L(b);a.v=c;break;case 10:c=L(b);a.j=c;break;case 11:c=new Vf;O(b,c,Vg);a.g=c;break;case 12:c=N(b);a.J=c;break;case 13:c=N(b);a.l=c;break;case 14:c=new Gk;O(b,c,Hk);a.h=c;break;case 15:c=J(b);a.I=c;break; +case 16:c=new Bk;O(b,c,Ek);a.b=a.b||[];a.b.push(c);break;case 17:c=L(b);a.G=c;break;case 18:c=N(b);a.f=a.f||[];a.f.push(c);break;case 19:c=new Qf;O(b,c,Rf);a.i=c;break;case 20:c=K(b);a.m=c;break;case 21:c=K(b);a.s=c;break;case 22:c=K(b);a.C=c;break;default:H(b)}};function Mk(){this.h=this.i=this.f=this.b=this.g=this.s=this.o=this.m=this.l=this.c=this.a=this.j=null} +Mk.prototype.w=function(){var a=[];if(null!==this.j){var b=this.j;a[0]=b}null!==this.a&&(b=this.a,a[1]=b);null!==this.c&&(b=this.c,a[2]=b);null!==this.l&&(b=this.l,a[3]=b);null!==this.m&&(b=this.m,a[4]=b);null!==this.o&&(b=this.o,a[5]=b);null!==this.s&&(b=this.s,a[6]=b);null!==this.g&&(b=this.g,a[7]=b);null!==this.b&&(b=this.b,a[9]=b);null!==this.f&&(b=this.f,a[10]=b);null!==this.i&&(b=this.i,a[11]=b);null!==this.h&&(b=this.h,a[12]=b);return a}; +function Nk(a){a.j=null;a.a=null;a.c=null;a.l=null;a.m=null;a.o=null;a.s=null;a.g=null;a.b=null;a.f=null;a.i=null;a.h=null}Mk.prototype.getExtension=function(){return null}; +function Ok(a,b){for(;G(b);)switch(b.a){case 1:var c=L(b);a.j=c;break;case 2:c=L(b);a.a=c;break;case 3:c=L(b);a.c=c;break;case 4:c=L(b);a.l=c;break;case 5:c=L(b);a.m=c;break;case 6:c=L(b);a.o=c;break;case 7:c=L(b);a.s=c;break;case 8:c=L(b);a.g=c;break;case 10:c=L(b);a.b=c;break;case 11:c=L(b);a.f=c;break;case 12:c=L(b);a.i=c;break;case 13:c=L(b);a.h=c;break;default:H(b)}};function Pk(){this.a=null}Pk.prototype.w=function(){var a=[];null!==this.a&&(a[0]=this.a);return a};function Qk(a){a.a=null}Pk.prototype.getExtension=function(){return null};function Rk(a,b){for(;G(b);)switch(b.a){case 1:a.a=N(b);break;default:H(b)}};function Sk(){this.P=this.O=this.M=this.h=this.L=this.D=this.g=this.I=this.o=this.s=this.C=this.H=this.B=this.f=this.m=this.A=this.J=this.a=this.G=this.u=this.b=this.i=this.v=this.l=this.K=this.j=this.c=null}function Tk(){this.a=null} +Sk.prototype.w=function(){var a=[];if(null!==this.c){var b=this.c;b=b.slice();for(var c=0;c<b.length;c++)b[c]=b[c].w();a[0]=b}null!==this.j&&(b=this.j,b=b.w(),a[2]=b);null!==this.K&&(b=this.K,a[3]=b);null!==this.l&&(b=this.l,b=b.w(),a[5]=b);null!==this.v&&(b=this.v,a[6]=b);null!==this.i&&(b=this.i,b=b.w(),a[7]=b);if(null!==this.b){b=this.b;b=b.slice();for(c=0;c<b.length;c++)b[c]=b[c].w();a[8]=b}null!==this.u&&(b=this.u,a[11]=b);null!==this.G&&(b=this.G,a[12]=b);null!==this.a&&(b=this.a,b=b.w(),a[14]= +b);null!==this.J&&(b=this.J,a[15]=b);null!==this.A&&(b=this.A,a[16]=b);null!==this.m&&(b=this.m,b=b.w(),a[18]=b);null!==this.f&&(b=this.f,b=b.w(),a[19]=b);null!==this.B&&(b=this.B,a[20]=b);null!==this.H&&(b=this.H,a[21]=b);null!==this.C&&(b=this.C,a[22]=b);null!==this.s&&(b=this.s,a[24]=b);null!==this.o&&(b=this.o,b=b.w(),a[25]=b);null!==this.I&&(b=this.I,a[26]=b);null!==this.g&&(b=this.g,b=b.w(),a[27]=b);null!==this.D&&(b=this.D,a[28]=b);null!==this.L&&(b=this.L,a[29]=b);Uk(this);null!==this.h&& +(b=this.h,b=Dc(b),a[30]=b);return a}; +function Vk(a){var b=new Sk;Wk(b);b.c=Bd(a.c,Mj);b.j=a.j?Ti(a.j):null;b.K=a.K;if(a.l){var c=new vj;Yj(c,a.l)}else c=null;b.l=c;b.v=a.v;if(a.i){c=new Hj;var d=a.i;zk(c);c.c=d.c;c.h=d.h;c.f=d.f;c.b=Ad(d.b);c.a=Ad(d.a);c.g=d.g}else c=null;b.i=c;b.b=Bd(a.b,Rj);b.u=a.u;b.G=a.G;a.a?(c=new Ik,Jk(c,a.a)):c=null;b.a=c;b.J=a.J;b.A=a.A;a.m?(c=a.m,d=new Tk,d.a=null,d.a=c.a,c=d):c=null;b.m=c;a.f?(c=new fj,d=a.f,gj(c),c.a=Bd(d.a,Hi),c.b=d.b):c=null;b.f=c;b.B=a.B;b.H=a.H;b.C=a.C;b.s=a.s;a.o?(c=new Pk,d=a.o,Qk(c), +c.a=d.a):c=null;b.o=c;b.I=a.I;a.g?(c=new Mk,d=a.g,Nk(c),c.j=d.j,c.a=d.a,c.c=d.c,c.l=d.l,c.m=d.m,c.o=d.o,c.s=d.s,c.g=d.g,c.b=d.b,c.f=d.f,c.i=d.i,c.h=d.h):c=null;b.g=c;b.D=a.D;b.L=a.L;b.h=a.h?new Uint8Array(a.h):null;b.M=a.M;b.O=a.O;b.P=a.P;return b} +function Wk(a){if(a.c)for(var b=0;b<a.c.length;b++){var c=a.c[b];c&&Jj(c)}a.c=null;(b=a.j)&&Ui(b);a.j=null;a.K=null;(b=a.l)&&Zj(b);a.l=null;a.v=null;(b=a.i)&&zk(b);a.i=null;if(a.b)for(b=0;b<a.b.length;b++)(c=a.b[b])&&Qj(c);a.b=null;a.u=null;a.G=null;(b=a.a)&&Kk(b);a.a=null;a.J=null;a.A=null;if(b=a.m)b.a=null;a.m=null;(b=a.f)&&gj(b);a.f=null;a.B=null;a.H=null;a.C=null;a.s=null;(b=a.o)&&Qk(b);a.o=null;a.I=null;(b=a.g)&&Nk(b);a.g=null;a.D=null;a.L=null;a.h=null;a.M=null;a.O=null} +Sk.prototype.getExtension=function(){return null}; +function Xk(a,b){for(a.P=jd(b);G(b);)switch(b.a){case 1:var c=new pj;O(b,c,Nj);a.c=a.c||[];a.c.push(c);break;case 3:c=new Pi;O(b,c,Vi);a.j=c;break;case 4:c=J(b);a.K=c;break;case 6:c=new vj;O(b,c,jk);a.l=c;break;case 7:c=N(b);a.v=c;break;case 8:c=new Hj;O(b,c,Ak);a.i=c;break;case 9:c=new sj;O(b,c,Sj);a.b=a.b||[];a.b.push(c);break;case 12:c=K(b);a.u=c;break;case 13:c=L(b);a.G=c;break;case 15:c=new Ik;O(b,c,Lk);a.a=c;break;case 16:c=K(b);a.J=c;break;case 17:c=K(b);a.A=c;break;case 19:c=new Tk;O(b,c, +Yk);a.m=c;break;case 20:c=new fj;O(b,c,hj);a.f=c;break;case 21:c=L(b);a.B=c;break;case 22:c=K(b);a.H=c;break;case 23:c=J(b);a.C=c;break;case 25:c=K(b);a.s=c;break;case 26:c=new Pk;O(b,c,Rk);a.o=c;break;case 27:c=K(b);a.I=c;break;case 28:c=new Mk;O(b,c,Ok);a.g=c;break;case 29:c=N(b);a.D=c;break;case 30:c=N(b);a.L=c;break;case 31:null===a.M&&(a.M=b.b);kd(b);a.O=id(b);break;default:H(b)}} +function Zk(a,b){if(a===b)a=!0;else if(null===a||null===b)a=!1;else{var c;if(c=Dd(a.c,b.c,Pj)&&Zi(a.j,b.j)&&a.K===b.K){c=a.l;var d=b.l;if(c===d)c=!0;else if(null===c||null===d)c=!1;else{var e;if(e=uk(c.j,d.j)&&xk(c.b,d.b)&&c.m===d.m&&c.o===d.o){e=c.c;var f=d.c;e=e===f?!0:null===e||null===f?!1:e.o!==f.o||e.A!==f.A||e.T!==f.T||e.a!==f.a||e.b!==f.b||e.I!==f.I||e.G!==f.G||e.H!==f.H||e.i!==f.i||e.D!==f.D||e.C!==f.C||e.B!==f.B||e.O!==f.O||e.M!==f.M||e.h!==f.h||e.m!==f.m||e.S!==f.S||e.P!==f.P||e.j!==f.j|| +e.l!==f.l||e.V!==f.V||e.J!==f.J||e.s!==f.s||e.U!==f.U||e.W!==f.W||e.L!==f.L||e.K!==f.K||e.c!==f.c||e.v!==f.v||e.g!==f.g||e.f!==f.f||e.u!==f.u?!1:!0}if(e=e&&c.s===d.s&&c.K===d.K&&c.v===d.v&&c.U===d.U)e=c.h,f=d.h,e=e===f?!0:null===e||null===f?!1:e.b!==f.b||e.a!==f.a?!1:!0;if(e=e&&c.O===d.O&&c.M===d.M&&c.G===d.G&&Cd(c.g,d.g)&&c.H===d.H)e=c.f,f=d.f,e=e===f?!0:null===e||null===f?!1:Cd(e.a,f.a)&&e.f===f.f&&Cd(e.b,f.b)&&e.c===f.c?!0:!1;e&&(e=c.i,f=d.i,e=e===f?!0:null===e||null===f?!1:e.a!==f.a||e.c!==f.c|| +e.b!==f.b?!1:!0);e&&(e=c.l,f=d.l,e=e===f?!0:null===e||null===f?!1:e.h!==f.h||e.g!==f.g||e.b!==f.b||e.c!==f.c||e.i!==f.i||e.a!==f.a||e.j!==f.j||e.f!==f.f?!1:!0);c=e&&c.B===d.B&&c.C===d.C&&c.A===d.A&&c.V===d.V&&c.L===d.L&&c.I===d.I&&c.D===d.D&&Dd(c.a,d.a,pk)&&c.P===d.P&&c.T===d.T&&c.J===d.J&&c.u===d.u&&c.S===d.S?!0:!1}}if(c=c&&a.v===b.v)c=a.i,d=b.i,c=c===d?!0:null===c||null===d?!1:c.c===d.c&&c.h===d.h&&c.f===d.f&&Cd(c.b,d.b)&&Cd(c.a,d.a)&&c.g===d.g?!0:!1;if(c=c&&Dd(a.b,b.b,Tj)&&a.u===b.u&&a.G===b.G)if(c= +a.a,d=b.a,c===d)c=!0;else if(null===c||null===d)c=!1;else{if(e=c.D===d.D&&c.H===d.H&&c.u===d.u&&Zh(c.c,d.c)&&c.o===d.o&&c.A===d.A&&c.B===d.B&&Dd(c.a,d.a,ti)&&c.v===d.v&&c.j===d.j)if(e=c.g,f=d.g,e===f)e=!0;else if(null===e||null===f)e=!1;else{var g;if(g=e.rb===f.rb&&e.K===f.K){g=e.v;var h=f.v;g=g===h?!0:null===g||null===h?!1:g.a!==h.a||g.c!==h.c||g.b!==h.b?!1:!0}if(g=g&&e.Ca===f.Ca&&ah(e.i,f.i)&&Dd(e.a,f.a,ah)&&e.qb===f.qb&&e.Ra===f.Ra&&e.Pa===f.Pa&&e.V===f.V&&e.fa===f.fa&&e.U===f.U&&e.M===f.M&&e.ha=== +f.ha&&e.W===f.W&&e.Y===f.Y&&e.O===f.O&&e.Da===f.Da&&e.ja===f.ja&&e.pa===f.pa&&e.ia===f.ia&&e.ga===f.ga&&e.Oa===f.Oa&&e.T===f.T&&e.L===f.L&&e.S===f.S)g=e.u,h=f.u,g=g===h?!0:null===g||null===h?!1:g.f!==h.f||g.h!==h.h||g.a!==h.a||g.b!==h.b||g.g!==h.g||g.c!==h.c?!1:!0;g&&(g=e.j,h=f.j,g=g===h?!0:null===g||null===h?!1:g.c!==h.c||g.a!==h.a||g.b!==h.b?!1:!0);if(g=g&&e.Ga===f.Ga&&e.Sa===f.Sa&&Cd(e.m,f.m)&&e.Ja===f.Ja&&e.La===f.La&&e.B===f.B&&e.Ka===f.Ka&&e.jb===f.jb&&e.ya===f.ya&&e.sb===f.sb&&e.s===f.s&&Dd(e.c, +f.c,ah)&&e.Ia===f.Ia&&e.Qa===f.Qa&&e.Ba===f.Ba&&e.J===f.J&&e.I===f.I&&e.H===f.H&&e.G===f.G&&e.Z===f.Z&&e.Bb===f.Bb&&e.Wa===f.Wa&&e.Za===f.Za&&e.Lb===f.Lb&&e.C===f.C&&e.P===f.P&&mh(e.o,f.o)&&e.Kb===f.Kb&&Dd(e.f,f.f,oh)&&e.Jb===f.Jb)g=e.l,h=f.l,g=g===h?!0:null===g||null===h?!1:g.b!==h.b||g.a!==h.a?!1:!0;if(g=g&&Dd(e.b,f.b,nh)&&e.D===f.D&&e.ra===f.ra&&e.va===f.va)g=e.A,h=f.A,g=g===h?!0:null===g||null===h?!1:g.a!==h.a||g.b!==h.b?!1:!0;if(g=g&&e.ib===f.ib&&e.$a===f.$a)g=e.h,h=f.h,g=g===h?!0:null===g|| +null===h?!1:g.c!==h.c||g.f!==h.f||g.g!==h.g||g.b!==h.b||g.a!==h.a?!1:!0;e=g&&Dd(e.g,f.g,dh)?!0:!1}if(e=e&&c.J===d.J&&c.l===d.l)e=c.h,f=d.h,e=e===f?!0:null===e||null===f?!1:e.b!==f.b||e.c!==f.c||e.a!==f.a?!1:!0;if(e=e&&c.I===d.I&&Dd(c.b,d.b,Fk)&&c.G===d.G&&Cd(c.f,d.f))e=c.i,f=d.i,e=e===f?!0:null===e||null===f?!1:e.a!==f.a?!1:!0;c=e&&c.m===d.m&&c.s===d.s&&c.C===d.C?!0:!1}if(c=c&&a.J===b.J&&a.A===b.A)c=a.m,d=b.m,c=c===d?!0:null===c||null===d?!1:c.a!==d.a?!1:!0;c&&(c=a.f,d=b.f,c=c===d?!0:null===c||null=== +d?!1:Dd(c.a,d.a,Ji)&&c.b===d.b?!0:!1);if(c=c&&a.B===b.B&&a.H===b.H&&a.C===b.C&&a.s===b.s)c=a.o,d=b.o,c=c===d?!0:null===c||null===d?!1:c.a!==d.a?!1:!0;if(c=c&&a.I===b.I)c=a.g,d=b.g,c=c===d?!0:null===c||null===d?!1:c.j!==d.j||c.a!==d.a||c.c!==d.c||c.l!==d.l||c.m!==d.m||c.o!==d.o||c.s!==d.s||c.g!==d.g||c.b!==d.b||c.f!==d.f||c.i!==d.i||c.h!==d.h?!1:!0;c&&a.D===b.D&&a.L===b.L?(Uk(a),a=Cd(a.h,b.h)?!0:!1):a=!1}return a}Sk.prototype.xd=function(){return null!=this.a?!0:!1}; +Sk.prototype.vd=function(){null===this.a&&(this.a=new Ik);return this.a};function Uk(a){null!=a.M&&null==a.h&&(a.h=Gd(a.P,a.M,a.O))}Tk.prototype.w=function(){var a=[];null!==this.a&&(a[0]=this.a);return a};Tk.prototype.getExtension=function(){return null};function Yk(a,b){for(;G(b);)switch(b.a){case 1:a.a=N(b);break;default:H(b)}};function $k(a){this.data=a||[]}var al;F($k,W);var bl,cl,dl;function el(){bl={a:-1,F:[]};bl.F=[,me(),he(1),Q,U,Vd("u",4278190080),V(new Pe([]),Re()),R,V(new Me([]),Oe()),P,P,he(1)]}function fl(){var a=cl={a:-1,F:[]},b=new of([]);if(!pf){var c=[];pf={a:-1,F:c};c[1]=pe(oe());c[500]=V(new ef([]),gf());c[15]=V(new Me([]),Oe())}a.F=[,V(b,pf),Q,Zd(1),R]}function gl(){dl={a:-1,F:[]};dl.F=[,V(new ne([]),oe()),$d,Q,Zd(1),Q]};function hl(a){this.data=a||[]}var il;F(hl,W);function jl(a){this.data=a||[]}var kl;F(jl,W);function ll(a){this.data=a||[]}var ml;F(ll,W);var nl;function ol(){il||(il={a:-1,F:[,,,Yd,Yd]});return il}function pl(){ml||(ml={a:-1,F:[,P,P]});return ml}function ql(){nl={a:-1,F:[]};nl.F=[,V(new ll([]),pl()),V(new ll([]),pl())]};function rl(a){this.data=a||[]}var sl;F(rl,W);function tl(a){this.data=a||[]}var ul;F(tl,W);function vl(){if(!ul){var a=ul={a:-1,F:[]},b=new rl([]);sl||(sl={a:-1,F:[,P,P,P,T,U]});a.F=[,V(b,sl),V(new hl([]),ol()),U,U,,,R,P,R,U,T,he(1)]}return ul};function wl(a){this.data=a||[]}var xl;F(wl,W);function yl(a){this.data=a||[]}var zl;F(yl,W);function Al(a){this.data=a||[]}var Bl;F(Al,W);var Cl;function Dl(a){this.data=a||[]}var El;F(Dl,W);function Fl(a){this.data=a||[]}var Gl;F(Fl,W);function Hl(a){this.data=a||[]}var Il;F(Hl,W);function Jl(a){this.data=a||[]}var Kl;F(Jl,W);function Ll(){if(!El){var a=El={a:-1,F:[]},b=new Fl([]);Gl||(Gl={a:-1,F:[,Yd,Yd,Yd]});b=V(b,Gl);var c=new Hl([]);Il||(Il={a:-1,F:[,$d,$d,$d]});c=V(c,Il);var d=new Jl([]);Kl||(Kl={a:-1,F:[,P,P]});a.F=[,b,c,V(d,Kl),$d]}return El}Fl.prototype.ud=function(){return X(this,0)};function Ml(a){this.data=a||[]}var Nl;F(Ml,W);function Ol(){Nl||(Nl={a:-1,F:[]},Nl.F=[,U,U,V(new Dl([]),Ll()),V(new hl([]),ol()),T,R,R,,T,ae(2147483647),U,le]);return Nl};function Pl(a){this.data=a||[]}var Ql;F(Pl,W);function Rl(a){this.data=a||[]}var Sl;F(Rl,W);function Tl(a){this.data=a||[]}var Ul;F(Tl,W);function Vl(a){this.data=a||[]}var Wl;F(Vl,W);function Xl(a){this.data=a||[]}var Yl;F(Xl,W);function Zl(a){this.data=a||[]}var $l;F(Zl,W);function am(a){this.data=a||[]}var bm;F(am,W);var cm;function dm(a){this.data=a||[]}var em;F(dm,W);function fm(a){this.data=a||[]}var gm;F(fm,W); +function hm(){var a=bm={a:-1,F:[]},b=new dm([]);em||(em={a:-1,F:[,U,U,U,$d,$d]});b=V(b,em);if(!cm){var c=cm={a:-1,F:[]},d=V(new Pe([]),Re()),e=new Xl([]);Yl||(Yl={a:-1,F:[,,,Yd,Yd]});c.F=[,d,,U,,V(e,Yl)]}c=pe(cm);d=new Vl([]);if(!Wl){e=Wl={a:-1,F:[]};var f=new Tl([]);Ul||(Ul={a:-1,F:[]},Ul.F=[,T,Vd("v","0")]);f=V(f,Ul);var g=new Rl([]);if(!Sl){var h=Sl={a:-1,F:[]},k=ae(1),l=new Pl([]);Ql||(Ql={a:-1,F:[,P,P]});h.F=[,U,k,T,T,R,U,U,$d,V(l,Ql),P,T]}e.F=[,ie,f,,ie,,,U,T,V(g,Sl),,,ke,P,P,P,R,,R,R,ie,T]}d= +V(d,Wl);e=new tf([]);uf||(uf={a:-1,F:[]},uf.F=[,me(),me()]);e=V(e,uf);f=new jl([]);kl||(kl={a:-1,F:[]},kl.F=[,,,V(new hl([]),ol()),V(new hl([]),ol())]);f=V(f,kl);g=V(new Ml([]),Ol());h=new fm([]);gm||(gm={a:-1,F:[,R,U,ke]});h=V(h,gm);k=he(1);l=new Zl([]);$l||($l={a:-1,F:[,T,U]});a.F=[,U,b,c,d,U,e,,f,,R,R,U,g,,,,,U,h,k,V(l,$l)]};var im;function jm(a){this.data=a||[]}var km;F(jm,W);function lm(a){this.data=a||[]}var mm;F(lm,W);function nm(a){this.data=a||[]}var om;F(nm,W);function pm(a){this.data=a||[]}var qm;F(pm,W);function rm(a){this.data=a||[]}var sm;F(rm,W);function tm(a){this.data=a||[]}var um;F(tm,W);function vm(){um={a:-1,F:[]};um.F=[,R,P,P,R,,,P,,U,,,,,,,,R,R,,ae(-1),,,R,P,R,P,P,Vd("d",1),R,,,P,P,,,,,,P,P,P,R,ae(10),R,R,P,P,R,R,R,R,U]};function wm(a){this.data=a||[]}var xm;F(wm,W);function ym(a){this.data=a||[]}var zm;F(ym,W);var Am;function Bm(a){this.data=a||[]}var Cm;F(Bm,W);function Dm(a){this.data=a||[]}var Em;F(Dm,W);function Fm(a){this.data=a||[]}var Gm;F(Fm,W);var Hm;function Im(a){this.data=a||[]}var Jm;F(Im,W);function Km(a){this.data=a||[]}var Lm;F(Km,W);function Mm(a){this.data=a||[]}var Nm;F(Mm,W);function Om(a){this.data=a||[]}var Pm;F(Om,W);var Qm;function Rm(a){this.data=a||[]}var Sm;F(Rm,W);function Tm(a){this.data=a||[]}var Um;F(Tm,W); +function Vm(a){this.data=a||[]}var Wm;F(Vm,W);function Xm(a){this.data=a||[]}var Ym;F(Xm,W);function Zm(a){this.data=a||[]}var $m;F(Zm,W);function an(a){this.data=a||[]}var bn;F(an,W);function cn(){if(!zm){var a=zm={a:-1,F:[]},b=V(new hl([]),ol()),c=he(4),d=new wm([]);xm||(xm={a:-1,F:[,U,$d,U,U]});d=V(d,xm);var e=new Xm([]);if(!Ym){var f=Ym={a:-1,F:[]},g=new Zm([]);$m||($m={a:-1,F:[]},$m.F=[,V(new ym([]),cn()),R]);f.F=[,V(g,$m)]}a.F=[,U,U,b,U,c,T,d,U,R,,R,U,U,U,,V(e,Ym),P]}return zm} +function dn(){Cm={a:-1,F:[,T,R]}}function en(){Em={a:-1,F:[]};Em.F=[,T,he(1),Vd("j","")]}function fn(){Hm={a:-1,F:[,P]}}function gn(){Lm={a:-1,F:[]};Lm.F=[,he(6),he(1),ge(!0),R,T,R,R,R]}function hn(){Nm={a:-1,F:[]};Nm.F=[,ie,ge(!0),ie,T]}function jn(){var a=Pm={a:-1,F:[]},b=he(1E3),c=he(1),d=Vd("j",""),e=he(1);Qm||(Qm={a:-1,F:[,T]});var f=pe(Qm),g=new Rm([]);if(!Sm){var h=Sm={a:-1,F:[]},k=he(1),l=new Tm([]);Um||(Um={a:-1,F:[,P,P]});h.F=[,k,,V(l,Um)]}a.F=[,b,c,d,,e,R,ie,T,R,f,V(g,Sm),T]} +function kn(){var a=Wm={a:-1,F:[]},b=ge(!0),c=ge(!0),d=new Im([]);Jm||(Jm={a:-1,F:[,,R,R,R,R,T,T,,R,T]});a.F=[,R,R,b,c,V(d,Jm),ge(!0),R,R,,,,,,,,,,,,he(1)]};var ln;function mn(){ln={a:-1,F:[]};ln.F=[,V(new Kf([]),Nf()),V(new Kf([]),Nf())]};function nn(a){this.data=a||[]}var on;F(nn,W);function pn(){on={a:-1,F:[,R,U,U]}};function qn(a){this.data=a||[]}var rn;F(qn,W);function sn(a){this.data=a||[]}var tn;F(sn,W);function un(a){this.data=a||[]}var vn;F(un,W);function wn(a){this.data=a||[]}var xn;F(wn,W);function yn(a){this.data=a||[]}var zn;F(yn,W); +function An(){var a=xn={a:-1,F:[]},b=pe(cn()),c=V(new Dl([]),Ll()),d=new Fm([]);if(!Gm){var e=Gm={a:-1,F:[]},f=new Om([]);Pm||jn();f=V(f,Pm);var g=new Vm([]);Wm||kn();g=V(g,Wm);var h=ge(!0),k=ge(!0),l=new tm([]);um||vm();l=V(l,um);var m=he(2),n=new Bm([]);Cm||dn();n=V(n,Cm);var p=ge(!0),q=ge(!0),t=new Mm([]);Nm||hn();t=V(t,Nm);var v=new Dm([]);Em||en();v=V(v,Em);var u=new Km([]);Lm||gn();u=V(u,Lm);var w=ge(!0),y=ge(!0);Hm||fn();e.F=[,f,g,h,k,,l,R,R,m,R,n,p,q,R,ce,R,t,,v,u,,,,,R,R,,,,,w,,y,R,R,,R, +pe(Hm),R,R,R,R,ae(3)]}d=V(d,Gm);e=he(2);f=new an([]);bn||(bn={a:-1,F:[,T,R,R,ce,ce,R]});f=V(f,bn);Am||(Am={a:-1,F:[]},Am.F=[,P,V(new hl([]),ol()),U,$d,R]);g=pe(Am);h=new qn([]);rn||(k=rn={a:-1,F:[]},l=V(new bi([]),di()),ui||vi(),m=pe(ui),n=new qh([]),rh||Rh(),n=V(n,rh),p=new nn([]),on||pn(),p=V(p,on),ln||mn(),q=pe(ln),t=new Sf([]),Tf||Uf(),k.F=[,U,U,R,l,U,U,T,m,U,U,n,T,T,p,P,q,U,ie,V(t,Tf),R,R,R]);h=V(h,rn);k=new yn([]);zn||(zn={a:-1,F:[]},zn.F=[,he(1)]);k=V(k,zn);l=new rm([]);sm||(m=sm={a:-1,F:[]}, +nl||ql(),m.F=[,pe(nl),R]);l=V(l,sm);m=ge(!0);n=new un([]);vn||(vn={a:-1,F:[,T]});n=V(n,vn);p=new sn([]);tn||(tn={a:-1,F:[,U,U,U,U,U,U,U,U,,U,U,U,U]});a.F=[,b,,c,P,,d,e,f,g,,,R,U,,h,R,R,,k,l,U,R,P,,m,n,R,V(p,tn),T,T,le]}wn.prototype.xd=function(){return xe(this,14)};wn.prototype.vd=function(){return new qn(this.data[14])};function Bn(a){this.data=a||[]}var Cn;F(Bn,W);function Dn(a){this.data=a||[]}var En;F(Dn,W);function Fn(a){this.data=a||[]}var Gn;F(Fn,W);var Hn;function In(a){this.data=a||[]}var Jn;F(In,W);function Kn(a){this.data=a||[]}var Ln;F(Kn,W);var Mn; +function Nn(){if(!Cn){var a=Cn={a:-1,F:[]},b=V(new Bn([]),Nn()),c=V(new Ml([]),Ol()),d=new wl([]);if(!xl){var e=xl={a:-1,F:[]},f=new yl([]);zl||(zl={a:-1,F:[]},zl.F=[,,,,pe(vl())]);f=V(f,zl);var g=new Al([]);Bl||(Bl={a:-1,F:[,ke,P]});g=V(g,Bl);Cl||(Cl={a:-1,F:[]},Cl.F=[,U,V(new hl([]),ol()),T]);e.F=[,,f,g,pe(Cl)]}d=V(d,xl);e=V(new tl([]),vl());f=new wn([]);xn||An();f=V(f,xn);g=he(1);var h=new am([]);bm||hm();h=V(h,bm);var k=new jm([]);if(!km){var l=km={a:-1,F:[]},m=new lm([]);mm||(mm={a:-1,F:[]}, +mm.F=[,,,,,R,R,,R,ge(!0)]);m=V(m,mm);var n=new nm([]);om||(om={a:-1,F:[,R,R]});n=V(n,om);var p=new pm([]);qm||(qm={a:-1,F:[,,,,,,T,T,T]});l.F=[,,U,,,,,,,,,,,,R,,,,m,,,n,V(p,qm)]}k=V(k,km);im||(im={a:-1,F:[]},im.F=[,V(new Pe([]),Re()),U,V(new ne([]),oe())]);l=pe(im);Hn||(Hn={a:-1,F:[,T,U]});m=pe(Hn);n=new Dn([]);if(!En){p=En={a:-1,F:[]};var q=new Fn([]);Gn||(Gn={a:-1,F:[,ke,fe]});p.F=[,T,V(q,Gn)]}n=V(n,En);p=new In([]);Jn||(q=Jn={a:-1,F:[]},Mn||(Mn={a:-1,F:[,,U,ke,R,T]}),q.F=[,pe(Mn),U,U,Vd("j",""), +pe(ol()),P]);p=V(p,Jn);q=V(new hl([]),ol());var t=new Kn([]);Ln||(Ln={a:-1,F:[,U]});a.F=[,b,c,,,d,e,,f,,U,g,h,k,R,,l,U,m,ee,n,ie,p,q,V(t,Ln)]}return Cn}Bn.prototype.getContext=function(){return new Bn(this.data[0])};Dn.prototype.Ea=function(){return ye(this,0,0)};function On(a){this.data=a||[]}var Pn;F(On,W);function Qn(a){this.data=a||[]}var Rn;F(Qn,W);On.prototype.wa=function(){return ze(this,1)};Qn.prototype.na=function(){return ze(this,1)};function Sn(a){this.data=a||[]}var Tn;F(Sn,W);function Un(a){this.data=a||[]}var Vn;F(Un,W);function Wn(){Vn={a:-1,F:[,je,U]}}Un.prototype.na=function(){return ze(this,1)};function Xn(){return B(x.URL)&&B(x.URL.createObjectURL)?x.URL:B(x.webkitURL)&&B(x.webkitURL.createObjectURL)?x.webkitURL:B(x.createObjectURL)?x:null};function Yn(a,b,c){return Math.min(Math.max(a,b),c)}function Zn(a){a%=360;return 0>360*a?a+360:a}function $n(a,b,c){return a+c*(b-a)}function ao(a){return a*Math.PI/180}function bo(a){return Oa(arguments,function(a,c){return a+c},0)}function co(a){return bo.apply(null,arguments)/arguments.length};function eo(a,b){this.x=B(a)?a:0;this.y=B(b)?b:0}eo.prototype.ceil=function(){this.x=Math.ceil(this.x);this.y=Math.ceil(this.y);return this};eo.prototype.floor=function(){this.x=Math.floor(this.x);this.y=Math.floor(this.y);return this};eo.prototype.round=function(){this.x=Math.round(this.x);this.y=Math.round(this.y);return this};function fo(a,b){this.width=a;this.height=b}fo.prototype.ceil=function(){this.width=Math.ceil(this.width);this.height=Math.ceil(this.height);return this};fo.prototype.floor=function(){this.width=Math.floor(this.width);this.height=Math.floor(this.height);return this};fo.prototype.round=function(){this.width=Math.round(this.width);this.height=Math.round(this.height);return this};function go(a){return document.createElement(String(a))};function ho(a,b){x.setTimeout(function(){try{a()}catch(c){throw c;}},b)};function io(a){this.a=a||go("CANVAS");this.b=[];this.c=1}io.prototype.addEventListener=function(a,b){this.b.push({type:a,listener:b});this.a.addEventListener(a,b,!1)};io.prototype.removeEventListener=function(a,b){for(var c=0;c<this.b.length;c++)if(b===this.b[c].listener&&a===this.b[c].type){this.b.splice(c,1);break}this.a.removeEventListener(a,b,!1)}; +io.prototype.dispatchEvent=function(a){for(var b=!1,c=0;c<this.b.length;c++)if(a.type==this.b[c].type){var d=this.b[c].listener;b="function"===typeof d?b|d(a):b|d.handleEvent(a)}return b};function jo(a,b){Qb.call(this,"RenderComplete",a);this.startTime=b}F(jo,Qb);function ko(a,b){Qb.call(this,"RenderStart",a);this.startTime=b}F(ko,Qb);function lo(a,b,c){var d=c||x.document;if(d){var e=null;c=null;for(var f=0;f<mo.length;f+=2)if(B(d[mo[f]])){e=mo[f];c=mo[f+1];break}e&&c&&(f=function(){a(!d[e])},b?b.cb(d,c,f):dc(d,c,f))}}var mo="hidden visibilitychange webkitHidden webkitvisibilitychange mozHidden mozvisibilitychange msHidden msvisibilitychange".split(" ");function no(a){Ib.call(this);this.b=a;this.a={}}F(no,Ib);var oo=[];r=no.prototype;r.cb=function(a,b,c,d){return po(this,a,b,c,d)};function po(a,b,c,d,e,f){va(c)||(c&&(oo[0]=c.toString()),c=oo);for(var g=0;g<c.length;g++){var h=dc(b,c[g],d||a.handleEvent,e||!1,f||a.b||a);if(!h)break;a.a[h.key]=h}return a}r.cc=function(a,b,c,d){return qo(this,a,b,c,d)}; +function qo(a,b,c,d,e,f){if(va(c))for(var g=0;g<c.length;g++)qo(a,b,c[g],d,e,f);else{b=ec(b,c,d||a.handleEvent,e,f||a.b||a);if(!b)return a;a.a[b.key]=b}return a}r.Sd=function(a,b,c,d,e){if(va(b))for(var f=0;f<b.length;f++)this.Sd(a,b[f],c,d,e);else c=c||this.handleEvent,d=za(d)?!!d.capture:!!d,e=e||this.b||this,c=fc(c),d=!!d,b=Ub(a)?a.tc(b,c,d,e):a?(a=hc(a))?a.tc(b,c,d,e):null:null,b&&(mc(b),delete this.a[b.key])};function ro(a){gb(a.a,function(a,c){this.a.hasOwnProperty(c)&&mc(a)},a);a.a={}} +r.X=function(){no.R.X.call(this);ro(this)};r.handleEvent=function(){throw Error("EventHandler.handleEvent not implemented");};function so(a,b,c){rc.call(this);this.f=new no(this);Jb(this,this.f);this.b=a;this.g=!!c;this.a=null;this.c=!1;to(this,b)}F(so,rc);function to(a,b){lo(function(b){b&&uo(a)},a.f,b)}function uo(a){a.a&&!a.c&&(a.b.Ue(a),a.c=!0)}function vo(a){a.c=!1;if(!a.O()&&a.a){var b=E();a.dispatchEvent(new ko(a,b));a.a&&a.a.wc();a.dispatchEvent(new jo(a,b,E()));a.g&&uo(a)}};function wo(){this.a=this.f=!1;this.b=void 0;this.h=this.g=this.i=this.c=!1};function xo(a){return(a=a.exec(cb))?a[1]:""}var yo=function(){if(uc)return xo(/Firefox\/([0-9.]+)/);if(pb||qb||ob)return zb;if(yc)return kb()||fb("iPad")||fb("iPod")?xo(/CriOS\/([0-9.]+)/):xo(/Chrome\/([0-9.]+)/);if(zc&&!(kb()||fb("iPad")||fb("iPod")))return xo(/Version\/([0-9.]+)/);if(vc||wc){var a=/Version\/(\S+).*Mobile\/(\S+)/.exec(cb);if(a)return a[1]+"."+a[2]}else if(xc)return(a=xo(/Android\s+([0-9.]+)/))?a:xo(/Version\/([0-9.]+)/);return""}();var zo=["webgl","experimental-webgl","moz-webgl"],Ao=0; +function Bo(a,b,c){var d=b||new wo;if(d.c&&!Co())return Ao=7,null;b=b||new wo;var e={alpha:!0,stencil:!0,preserveDrawingBuffer:!1,failIfMajorPerformanceCaveat:!b.a&&!0};b.f&&(e.antialias=!1);rb&&!Ab(25)&&(e.preserveDrawingBuffer=!0);c=(c||Do)(a,e);if(!c)return Ao=1,null;c.getExtension("WEBGL_debug_renderer_info")?(b=c.getParameter(37446),Eo=Fo(b)):Eo=null;if(d.c&&!c.getExtension("ANGLE_instanced_arrays"))return Ao=7,null;if(c.drawingBufferWidth!=a.width||c.drawingBufferHeight!=a.height)return Ao= +2,null;if(4>c.getParameter(35660))return Ao=3,null;a=c.getParameter(3379);if(B(d.b)&&a<d.b)return Ao=6,null;if(23>c.getShaderPrecisionFormat(35632,36338).precision)return Ao=4,null;a=Eo;return pb&&!a?(Ao=8,null):!d.a&&a&&("Intel Q45"==a&&(pb||uc)||-1!=Go.indexOf(a))?(Ao=5,null):c}function Do(a,b){for(var c=null,d=zo.length,e=0;e<d;++e){try{c=a.getContext(zo[e],b)}catch(f){}if(c)return c}return null}var Eo=void 0;function Co(){return yc&&tb&&!(0<=ab(yo,"30"))||uc&&tb&&!(0<=ab(yo,"27"))?!1:!0} +function Fo(a){if(void 0===a)return null;a=a.toLowerCase();var b=a.match(/angle \((.*)\)/);b&&(a=b[1],a=a.replace(/\s*direct3d.*$/,""));a=a.replace(/\s*\([^\)]*wddm[^\)]*\)/,"");var c=a;0>c.indexOf("intel")?b=null:(b=["Intel"],0<=c.indexOf("mobile")&&b.push("Mobile"),(0<=c.indexOf("gma")||0<=c.indexOf("graphics media accelerator"))&&b.push("GMA"),0<=c.indexOf("haswell")?b.push("Haswell"):0<=c.indexOf("ivy")?b.push("HD 4000"):0<=c.indexOf("sandy")?b.push("HD 3000"):0<=c.indexOf("ironlake")?b.push("HD"): +(0<=c.indexOf("hd")&&b.push("HD"),(c=c.match(Ho))&&b.push(c[1].toUpperCase())),b=b.join(" "));if(b)return b;b=a;if(0>b.indexOf("nvidia")&&0>b.indexOf("quadro")&&0>b.indexOf("geforce")&&0>b.indexOf("nvs"))b=null;else{c=["nVidia"];0<=b.indexOf("geforce")&&c.push("geForce");0<=b.indexOf("quadro")&&c.push("Quadro");0<=b.indexOf("nvs")&&c.push("NVS");b.match(/\bion\b/)&&c.push("ION");b.match(/gtx\b/)?c.push("GTX"):b.match(/gts\b/)?c.push("GTS"):b.match(/gt\b/)?c.push("GT"):b.match(/gs\b/)?c.push("GS"): +b.match(/ge\b/)?c.push("GE"):b.match(/fx\b/)&&c.push("FX");var d=b.match(Ho);d&&c.push(d[1].toUpperCase().replace("GS",""));0<=b.indexOf("titan")?c.push("TITAN"):0<=b.indexOf("ti")&&c.push("Ti");b=c.join(" ")}if(b)return b;c=a;0>c.indexOf("amd")&&0>c.indexOf("ati")&&0>c.indexOf("radeon")&&0>c.indexOf("firegl")&&0>c.indexOf("firepro")?b=null:(b=["AMD"],0<=c.indexOf("mobil")&&b.push("Mobility"),d=c.indexOf("radeon"),0<=d&&b.push("Radeon"),0<=c.indexOf("firepro")?b.push("FirePro"):0<=c.indexOf("firegl")&& +b.push("FireGL"),0<=c.indexOf("hd")&&b.push("HD"),(c=(0<=d?c.substring(d):c).match(Ho))&&b.push(c[1].toUpperCase().replace("HD","")),b=b.join(" "));return b?b:a.substring(0,100)}var Ho=/([a-z0-9]*\d+[a-z0-9]*)/,Go="microsoft basic render driver;vmware svga 3d;Intel 965GM;Intel B43;Intel G41;Intel G45;Intel G965;Intel GMA 3600;Intel Mobile 4;Intel Mobile 45;Intel Mobile 965".split(";");function Io(a,b,c){this.a=a;this.g=b;this.f=c;this.h=this.a.createTexture();this.v=this.u=10497;this.s=9986;this.o=9729;this.c=0;this.b=3553;this.i=this.j=0;this.m=!1;this.l=34069}function Jo(a,b){a.c!=b&&(a.c=b)}Io.prototype.bind=function(){3553==this.b?this.f.xa(this.c,this):this.f.Vb(this.c,this)};function Ko(a,b){a.u!=b&&(a.bind(),a.a.texParameteri(a.b,10242,b),a.u=b)}function Lo(a,b){a.v!=b&&(a.bind(),a.a.texParameteri(a.b,10243,b),a.v=b)}function Mo(a,b){Ko(a,b);Lo(a,b)} +function No(a,b){a.s!=b&&(a.bind(),a.a.texParameteri(a.b,10241,b),a.s=b)}function Oo(a,b){a.o!=b&&(a.bind(),a.a.texParameteri(a.b,10240,b),a.o=b)}Io.prototype.deleteTexture=function(){for(var a=Po(this.g),b=0;b<=this.f.vb();++b)Jo(this,b),3553==this.b?this.f.c[this.c]==this&&this.f.xa(this.c,null):this.f.g[this.c]==this&&this.f.Vb(this.c,null);this.m=!0;this.a.deleteTexture(this.h);this.g.Rb(a)}; +function Qo(a,b,c,d,e){Ro(a,b.width,b.height,c,d,e);var f=So(a);a.bind();To(a,b.width,c,d);a.a.texImage2D(f,e,c,c,d,b);a.g.ub(3317)}function Uo(a,b,c,d,e,f,g){Ro(a,c,d,e,f,g);var h=So(a);a.bind();To(a,c,e,f);a.a.texImage2D(h,g,e,c,d,0,e,f,b);a.g.ub(3317)}function Vo(a,b,c,d,e,f,g,h,k){var l=So(a);a.bind();a.a.texSubImage2D(l,k,c,d,e,f,g,h,b)}function Ro(a,b,c,d,e,f){0!=f||b==a.j&&c==a.i&&d==a.A&&e==a.B||(a.j=b,a.i=c)}function So(a){return 34067==a.b?a.l:a.b} +var Wo={6408:4,6407:3,6410:2,6409:1,6406:1},Xo={5121:1,5126:4,32819:2,33635:2,32820:2};function To(a,b,c,d){b*=(5121==d||5126==d?Wo[c]:1)*Xo[d];0!=b%4&&(c=1,0==b%2&&(c=2),a.g.eb(3317,c))};function Yo(){this.h=this.f=this.i=this.b=void 0;this.c=[];this.g=[]}r=Yo.prototype;r.clear=function(){this.de();this.pe();this.qe();this.ve();for(var a=31;0<=a;--a)this.ye(a),this.ze(a)};r.apply=function(a){void 0!==a.b&&a.b!==this.b&&this.Ua(a.b);void 0!==a.i&&a.i!==this.i&&this.Jc(a.i);void 0!==a.f&&a.f!==this.f&&this.lc(a.f);void 0!==a.h&&a.h!==this.h&&this.Oc(a.h);for(var b=31;0<=b;--b)void 0!==a.c[b]&&a.c[b]!==this.c[b]&&this.xa(b,a.c[b]),void 0!==a.g[b]&&a.g[b]!==this.g[b]&&this.Vb(b,a.g[b])}; +r.vb=function(){return 32};r.Ua=function(a){this.b=a};r.de=function(){this.b=void 0};r.Jc=function(a){this.i=a};r.pe=function(){this.i=void 0};r.lc=function(a){this.f=a};r.qe=function(){this.f=void 0};r.Oc=function(a){this.h=a};r.ve=function(){this.h=void 0};r.xa=function(a,b){this.c[a]=b};r.ye=function(a){delete this.c[a]};r.Vb=function(a,b){this.g[a]=b};r.ze=function(a){delete this.g[a]};function Zo(a,b){Yo.call(this);this.a=a;this.l=Math.min(32,a.getParameter(35661));this.m=b;this.j=zc||sb&&!Ab("536.3");a=this.a;this.a=null;this.clear();this.a=a}F(Zo,Yo);r=Zo.prototype;r.Ua=function(a){if(this.j||this.b!==a)Zo.R.Ua.call(this,a),this.a&&this.a.bindBuffer(34962,a)};r.de=function(){this.Ua(null)};r.Jc=function(a){if(this.j||this.i!==a)Zo.R.Jc.call(this,a),this.a&&this.a.bindBuffer(34963,a)};r.pe=function(){this.Jc(null)}; +r.lc=function(a){if(this.j||this.f!==a)Zo.R.lc.call(this,a),this.a&&this.a.bindFramebuffer(36160,a)};r.qe=function(){this.lc(null)};r.Oc=function(a){if(this.j||this.h!==a)Zo.R.Oc.call(this,a),this.a&&this.a.bindRenderbuffer(36161,a)};r.ve=function(){this.Oc(null)};r.xa=function(a,b){a<this.l&&this.m.Rb(33984+a);if(this.j||this.c[a]!==b)Zo.R.xa.call(this,a,b),this.a&&(b?this.a.bindTexture(3553,b.h):this.a.bindTexture(3553,null))};r.ye=function(a){this.xa(a,null)}; +r.Vb=function(a,b){a<this.l&&this.m.Rb(33984+a);if(this.j||this.g[a]!==b)Zo.R.Vb.call(this,a,b),this.a&&(b?this.a.bindTexture(34067,b.h):this.a.bindTexture(34067,null))};r.ze=function(a){this.Vb(a,null)};r.vb=function(){return this.l-1};function $o(){this.h=new ArrayBuffer(ap);this.c=new Uint8Array(this.h);this.b=new Uint16Array(this.h);this.i=new Uint32Array(this.h);this.f=new Int32Array(this.h);this.a=new Float32Array(this.h);this.clear()} +$o.prototype.clear=function(){this.tb(3042);this.tb(2884);this.tb(2929);this.tb(3024);this.tb(32823);this.tb(32926);this.tb(32928);this.tb(3089);this.tb(2960);this.ee();this.fe();this.ge();this.me();this.we();this.he();this.ie();this.je();this.ke();this.ne();this.oe();this.xe();this.Ge();this.le();this.re();this.te();this.ue();for(var a=0;32>a;++a)this.Ae(a);this.ce();this.ub(3317);this.ub(3333);this.ub(37440);this.ub(37441);this.ub(37443);this.se(33170)}; +$o.prototype.apply=function(a){bp(a,3042)&&cp(a,3042)!=cp(this,3042)&&this.Ta(3042,cp(a,3042));bp(a,2884)&&cp(a,2884)!=cp(this,2884)&&this.Ta(2884,cp(a,2884));bp(a,2929)&&cp(a,2929)!=cp(this,2929)&&this.Ta(2929,cp(a,2929));bp(a,3024)&&cp(a,3024)!=cp(this,3024)&&this.Ta(3024,cp(a,3024));bp(a,32823)&&cp(a,32823)!=cp(this,32823)&&this.Ta(32823,cp(a,32823));bp(a,32926)&&cp(a,32926)!=cp(this,32926)&&this.Ta(32926,cp(a,32926));bp(a,32928)&&cp(a,32928)!=cp(this,32928)&&this.Ta(32928,cp(a,32928));bp(a,3089)&& +cp(a,3089)!=cp(this,3089)&&this.Ta(3089,cp(a,3089));bp(a,2960)&&cp(a,2960)!=cp(this,2960)&&this.Ta(2960,cp(a,2960));if(0<=a.a[3]){var b=a.a[3],c=a.a[4],d=a.a[5],e=a.a[6];this.a[3]==b&&this.a[4]==c&&this.a[5]==d&&this.a[6]==e||this.Bc(b,c,d,e)}65535==a.b[14]||dp(this,!1)==dp(a,!1)&&dp(this,!0)==dp(a,!0)||(b=dp(a,!1),c=dp(a,!0),c==b&&(c=void 0),this.jc(b,c));65535!=a.b[16]&&(b=a.b[16],c=a.b[17],d=a.b[18],e=a.b[19],this.b[16]!=b||this.b[17]!=c||this.b[18]!=d||this.b[19]!=e)&&(d==b&&e==c&&(e=d=void 0), +this.kc(b,c,d,e));65535!=a.b[20]&&ep(a)!=ep(this)&&this.Hc(ep(a));0<a.c[48]&&(b=a.a[11],c=2==a.c[48],this.a[11]==b&&this.c[48]==(c?2:1)||this.Pc(b,c));0<=a.a[13]&&(b=a.a[13],c=a.a[14],d=a.a[15],e=a.a[16],this.a[13]==b&&this.a[14]==c&&this.a[15]==d&&this.a[16]==e||this.Cc(b,c,d,e));0<=a.a[17]&&fp(a)!=fp(this)&&this.Dc(fp(a));1==a.c[76]&&gp(a)!=gp(this)&&this.Ec(gp(a));0<a.c[80]&&(b=2==a.c[80],c=2==a.c[81],d=2==a.c[82],e=2==a.c[83],hp(this,b,c,d,e)||this.Fc(b,c,d,e));0<a.c[84]&&ip(a)!=ip(this)&&this.Fb(ip(a)); +0<=a.a[jp]&&(b=a.a[jp],c=a.a[jp+1],this.a[jp]==b&&this.a[jp+1]==c||this.Ic(b,c));0<=a.f[kp+2]&&(b=a.f[kp],c=a.f[kp+1],d=a.f[kp+2],e=a.f[kp+3],this.f[kp]==b&&this.f[kp+1]==c&&this.f[kp+2]==d&&this.f[kp+3]==e||this.Qc(b,c,d,e));0<=a.f[lp+2]&&(b=a.f[lp],c=a.f[lp+1],d=a.f[lp+2],e=a.f[lp+3],this.f[lp]==b&&this.f[lp+1]==c&&this.f[lp+2]==d&&this.f[lp+3]==e||this.nc(b,c,d,e));65535!=a.b[mp]&&np(a)!=np(this)&&this.Gc(np(a));65535!=a.b[op]&&pp(a)!=pp(this)&&this.Kc(pp(a));0<a.a[qp]&&rp(a)!=rp(this)&&this.Mc(rp(a)); +0<a.c[sp]&&(b=a.a[tp],c=a.a[tp+1],0<this.c[sp]&&this.a[tp]==b&&this.a[tp+1]==c||this.Nc(b,c));for(b=0;32>b;++b)0<a.c[up+b]&&vp(a,b)!=vp(this,b)&&this.mc(b,vp(a,b));65535!=a.b[wp]&&Po(a)!=Po(this)&&this.Rb(Po(a));xp(a,3317)&&yp(a,3317)!=yp(this,3317)&&this.eb(3317,yp(a,3317));xp(a,3333)&&yp(a,3333)!=yp(this,3333)&&this.eb(3333,yp(a,3333));xp(a,37440)&&yp(a,37440)!=yp(this,37440)&&this.eb(37440,yp(a,37440));xp(a,37441)&&yp(a,37441)!=yp(this,37441)&&this.eb(37441,yp(a,37441));xp(a,37443)&&yp(a,37443)!= +yp(this,37443)&&this.eb(37443,yp(a,37443));65535!=a.b[zp]&&Ap(a)!=Ap(this)&&this.Lc(33170,Ap(a))};var Bp=[];Bp[3042]=0;Bp[2884]=1;Bp[2929]=2;Bp[3024]=3;Bp[32823]=4;Bp[32926]=5;Bp[32928]=6;Bp[3089]=7;Bp[2960]=8;r=$o.prototype;r.Ta=function(a,b){this.c[0+Bp[a]]=b?2:1};function cp(a,b){a=a.c[0+Bp[b]];if(0!=a)return 2==a}function bp(a,b){return 0<a.c[0+Bp[b]]}r.tb=function(a){this.c[0+Bp[a]]=0};r.Bc=function(a,b,c,d){this.a[3]=a;this.a[4]=b;this.a[5]=c;this.a[6]=d}; +r.ee=function(){this.a[3]=-1;this.a[4]=-1;this.a[5]=-1;this.a[6]=-1};r.jc=function(a,b){this.b[14]=a;this.b[15]=b||a};function dp(a,b){a=b?a.b[15]:a.b[14];if(65535!=a)return a}r.fe=function(){this.b[14]=65535;this.b[15]=65535};r.kc=function(a,b,c,d){this.b[16]=a;this.b[17]=b;this.b[18]=void 0===c?a:c;this.b[19]=void 0===d?b:d};r.ge=function(){this.b[16]=65535;this.b[17]=65535;this.b[18]=65535;this.b[19]=65535};r.Hc=function(a){this.b[20]=a};function ep(a){a=a.b[20];if(65535!=a)return a} +r.me=function(){this.b[20]=65535};r.Pc=function(a,b){this.a[11]=a;this.c[48]=b?2:1};r.we=function(){this.c[48]=0};r.Cc=function(a,b,c,d){this.a[13]=a;this.a[14]=b;this.a[15]=c;this.a[16]=d};r.he=function(){this.a[13]=-1;this.a[14]=-1;this.a[15]=-1;this.a[16]=-1};r.Dc=function(a){this.a[17]=a};function fp(a){a=a.a[17];if(!(0>a))return a}r.ie=function(){this.a[17]=-1};r.Ec=function(a){this.i[18]=a;this.c[76]=1};function gp(a){if(1==a.c[76])return a.i[18]}r.je=function(){this.c[76]=0}; +r.Fc=function(a,b,c,d){this.c[80]=a?2:1;this.c[81]=b?2:1;this.c[82]=c?2:1;this.c[83]=d?2:1};r.ke=function(){this.c[80]=0;this.c[81]=0;this.c[82]=0;this.c[83]=0};function hp(a,b,c,d,e){return a.c[80]==(b?2:1)&&a.c[81]==(c?2:1)&&a.c[82]==(d?2:1)&&a.c[83]==(e?2:1)}r.Fb=function(a){this.c[84]=a?2:1};function ip(a){a=a.c[84];if(0!=a)return 2==a}r.ne=function(){this.c[84]=0};var Cp=96,jp=22;$o.prototype.Ic=function(a,b){this.a[jp]=a;this.a[jp+1]=b}; +$o.prototype.oe=function(){this.a[jp]=-1;this.a[jp+1]=-1};var Dp=Cp+16,kp=Cp/4;$o.prototype.Qc=function(a,b,c,d){this.f[kp]=a;this.f[kp+1]=b;this.f[kp+2]=c;this.f[kp+3]=d};$o.prototype.xe=function(){this.f[kp+2]=-1;this.f[kp+3]=-1};var Ep=Dp+16,lp=Dp/4;$o.prototype.nc=function(a,b,c,d){this.f[lp]=a;this.f[lp+1]=b;this.f[lp+2]=c;this.f[lp+3]=d};function Fp(a){var b=a.f[lp+2];if(!(0>b))return[a.f[lp],a.f[lp+1],b,a.f[lp+3]]}$o.prototype.Ge=function(){this.f[lp+2]=-1;this.f[lp+3]=-1}; +var Gp=Ep+4,mp=Ep/2;$o.prototype.Gc=function(a){this.b[mp]=a};function np(a){a=a.b[mp];if(65535!=a)return a}$o.prototype.le=function(){this.b[mp]=65535};var Hp=Gp+4,op=Gp/2;$o.prototype.Kc=function(a){this.b[op]=a};function pp(a){a=a.b[op];if(65535!=a)return a}$o.prototype.re=function(){this.b[op]=65535};var Ip=Hp+4,qp=Hp/4;$o.prototype.Mc=function(a){this.a[qp]=a};function rp(a){a=a.a[qp];if(!(0>a))return a}$o.prototype.te=function(){this.a[qp]=-1};var up=Ip+12,tp=Ip/4,sp=Ip+8; +$o.prototype.Nc=function(a,b){this.a[tp]=a;this.a[tp+1]=b;this.c[sp]=1};$o.prototype.ue=function(){this.c[sp]=0};var Jp=up+32;$o.prototype.mc=function(a,b){this.c[up+a]=b?2:1};function vp(a,b){a=a.c[up+b];if(0!=a)return 2==a}$o.prototype.Ae=function(a){this.c[up+a]=0};var Kp=Jp+4,wp=Jp/2;$o.prototype.Rb=function(a){this.b[wp]=a};function Po(a){a=a.b[wp];if(65535!=a)return a}$o.prototype.ce=function(){this.b[wp]=65535};var Lp=[];Lp[3317]=0;Lp[3333]=1;Lp[37440]=2;Lp[37441]=3;Lp[37443]=4; +var Mp=Kp+12,Np=Kp/2;$o.prototype.eb=function(a,b){this.b[Np+Lp[a]]=b};function yp(a,b){a=a.b[Np+Lp[b]];if(65535!=a)return a}function xp(a,b){return 65535!=a.b[Np+Lp[b]]}$o.prototype.ub=function(a){this.b[Np+Lp[a]]=65535};var ap=Mp+4,zp=Mp/2;$o.prototype.Lc=function(a,b){this.b[zp]=b};function Ap(a){a=a.b[zp];if(65535!=a)return a}$o.prototype.se=function(){this.b[zp]=65535};function Op(a){this.g=a;a.scissor(0,0,0,0);a.viewport(0,0,0,0);a.enableVertexAttribArray(0);a=this.g;this.g=null;$o.call(this);this.g=a}F(Op,$o);r=Op.prototype;r.Ta=function(a,b){if(cp(this,a)!=b){Op.R.Ta.call(this,a,b);var c=this.g;c&&(b?c.enable(a):c.disable(a))}};r.tb=function(a){3024==a?this.Ta(a,!0):this.Ta(a,!1)};r.Bc=function(a,b,c,d){if(this.a[3]!=a||this.a[4]!=b||this.a[5]!=c||this.a[6]!=d){Op.R.Bc.call(this,a,b,c,d);var e=this.g;e&&e.blendColor(a,b,c,d)}};r.ee=function(){this.Bc(0,0,0,0)}; +r.jc=function(a,b){var c=void 0===b?a:b;if(dp(this,!1)!=a||dp(this,!0)!=c)Op.R.jc.call(this,a,b),(b=this.g)&&(c==a?b.blendEquation(a):b.blendEquationSeparate(a,c))};r.fe=function(){this.jc(32774)};r.kc=function(a,b,c,d){var e=void 0===c?a:c,f=void 0===d?b:d;if(this.b[16]!=a||this.b[17]!=b||this.b[18]!=e||this.b[19]!=f)Op.R.kc.call(this,a,b,c,d),(c=this.g)&&(e==a&&f==b?c.blendFunc(a,b):c.blendFuncSeparate(a,b,e,f))};r.ge=function(){this.kc(1,0)}; +r.Hc=function(a){if(ep(this)!=a){Op.R.Hc.call(this,a);var b=this.g;b&&b.depthFunc(a)}};r.me=function(){this.Hc(513)};r.Pc=function(a,b){if(this.a[11]!=a||this.c[48]!=(b?2:1)){Op.R.Pc.call(this,a,b);var c=this.g;c&&c.sampleCoverage(a,b)}};r.we=function(){this.Pc(1,!1)};r.Cc=function(a,b,c,d){if(this.a[13]!=a||this.a[14]!=b||this.a[15]!=c||this.a[16]!=d){Op.R.Cc.call(this,a,b,c,d);var e=this.g;e&&e.clearColor(a,b,c,d)}};r.he=function(){this.Cc(0,0,0,0)}; +r.Dc=function(a){if(fp(this)!=a){Op.R.Dc.call(this,a);var b=this.g;b&&b.clearDepth(a)}};r.ie=function(){this.Dc(1)};r.Ec=function(a){if(gp(this)!=a){Op.R.Ec.call(this,a);var b=this.g;b&&b.clearStencil(a)}};r.je=function(){this.Ec(0)};r.Fc=function(a,b,c,d){if(!hp(this,a,b,c,d)){Op.R.Fc.call(this,a,b,c,d);var e=this.g;e&&e.colorMask(a,b,c,d)}};r.ke=function(){this.Fc(!0,!0,!0,!0)};r.Fb=function(a){if(ip(this)!=a){Op.R.Fb.call(this,a);var b=this.g;b&&b.depthMask(a)}};r.ne=function(){this.Fb(!0)}; +r.Ic=function(a,b){if(this.a[jp]!=a||this.a[jp+1]!=b){Op.R.Ic.call(this,a,b);var c=this.g;c&&c.depthRange(a,b)}};r.oe=function(){this.Ic(0,1)};r.Qc=function(a,b,c,d){if(this.f[kp]!=a||this.f[kp+1]!=b||this.f[kp+2]!=c||this.f[kp+3]!=d){Op.R.Qc.call(this,a,b,c,d);var e=this.g;e&&e.scissor(a,b,c,d)}};r.xe=function(){this.Qc(0,0,0,0)};r.nc=function(a,b,c,d){if(this.f[lp]!=a||this.f[lp+1]!=b||this.f[lp+2]!=c||this.f[lp+3]!=d){Op.R.nc.call(this,a,b,c,d);var e=this.g;e&&e.viewport(a,b,c,d)}}; +r.Ge=function(){this.nc(0,0,0,0)};r.Gc=function(a){if(np(this)!=a){Op.R.Gc.call(this,a);var b=this.g;b&&b.cullFace(a)}};r.le=function(){this.Gc(1029)};r.Kc=function(a){if(pp(this)!=a){Op.R.Kc.call(this,a);var b=this.g;b&&b.frontFace(a)}};r.re=function(){this.Kc(2305)};r.Mc=function(a){if(rp(this)!=a){Op.R.Mc.call(this,a);var b=this.g;b&&b.lineWidth(a)}};r.te=function(){this.Mc(1)}; +r.Nc=function(a,b){if(!(0<this.c[sp])||this.a[tp]!=a||this.a[tp+1]!=b){Op.R.Nc.call(this,a,b);var c=this.g;c&&c.polygonOffset(a,b)}};r.ue=function(){this.Nc(0,0)};r.mc=function(a,b){if(vp(this,a)!=b){Op.R.mc.call(this,a,b);var c=this.g;c&&(b?c.enableVertexAttribArray(a):c.disableVertexAttribArray(a))}};r.Ae=function(a){this.mc(a,!1)};r.Rb=function(a){if(Po(this)!=a){$o.prototype.Rb.call(this,a);var b=this.g;b&&b.activeTexture(a)}};r.ce=function(){this.Rb(33984)}; +r.eb=function(a,b){if(yp(this,a)!=b){Op.R.eb.call(this,a,b);var c=this.g;c&&c.pixelStorei(a,b)}};r.ub=function(a){switch(a){case 3317:case 3333:this.eb(a,4);break;case 37440:case 37441:this.eb(a,0);break;default:this.eb(a,37444)}};r.Lc=function(a,b){if(Ap(this)!=b){Op.R.Lc.call(this,a,b);var c=this.g;c&&c.hint(a,b)}};r.se=function(a){this.Lc(a,4352)};function Pp(){this.Ka=!1;this.Da=this.M=null}Pp.prototype.O=function(){return this.Ka};Pp.prototype.$=function(){if(!this.Ka){this.Ka=!0;this.X();if(this.M){for(var a=0;a<this.M.length;++a)this.M[a].$();this.M=null}if(this.Da){for(a=0;a<this.Da.length;++a)this.Da[a]();this.Da=null}}};function Qp(a,b){a.M||(a.M=[]);a.M.push(b)}Pp.prototype.X=function(){};function Rp(){this.c=[0,0];this.a=[0,0];this.h=0;this.g=this.b=null;this.f={}}function Sp(a,b,c,d,e,f,g){this.handle=a;this.b=b;this.g=c;this.h=d;this.a=null;this.next=e;this.c=f;this.f=g}function Tp(a,b,c){a.c[0]=B(b)?b:a.c[0];a.c[1]=B(c)?c:a.c[1];Up(a)}Rp.prototype.add=function(a,b,c,d,e){c=c||0;d=d||0;if(c>this.c[0]||d>this.c[1])return-1;var f=this.h++;a=new Sp(f,a,b,e||null,this.b,c,d);this.f[f]=a;this.b&&(this.b.a=a);this.b=a;this.a[0]+=c;this.a[1]+=d;null==this.g&&(this.g=a);Up(this);return f}; +Rp.prototype.get=function(a){return(a=this.f[a])?a.b:void 0};function Up(a){for(var b=a.g;b&&(a.a[0]>a.c[0]||a.a[1]>a.c[1]);){var c=b;b=b.a;if(a.a[0]>a.c[0]&&0<c.c||a.a[1]>a.c[1]&&0<c.f||0==c.c&&0==c.f)c.g&&c.g.call(c.h,c.handle,c.b,!1),Vp(a,c.handle)}}function Wp(a,b){(b=a.f[b])&&b.a&&((b.a.next=b.next)?b.next.a=b.a:a.g=b.a,b.a=null,b.next=a.b,a.b.a=b,a.b=b)} +function Vp(a,b){var c=a.f[b];c&&(c.a?c.a.next=c.next:a.b=c.next,c.next?c.next.a=c.a:a.g=c.a,c.a=c.next=c.b=null,c.handle=-1,delete a.f[b],a.a[0]-=c.c,a.a[1]-=c.f)}Rp.prototype.clear=function(){for(;this.b;){var a=this.b;a.g.call(a.h,a.handle,a.b,!0);Vp(this,a.handle)}};function Xp(a,b,c){this.a=new Rp;this.j=a;this.i=this.m=0;this.o=1;this.h=this.u=this.g=this.s=0;this.b=[];this.f=[];this.c=[];this.v=D(this.l,this,this.f);D(this.l,this,this.b);D(this.l,this,this.c);Yp(this);var d=this;lo(function(a){d.o=a?1:.5;Yp(d)},c,b)}F(Xp,Pp);Xp.prototype.X=function(){this.clear();Zp(this);Xp.R.X.call(this)};Xp.prototype.clear=function(){this.a.clear()};function $p(a,b,c,d,e){return a.a.add(b,c,d,e)} +Xp.prototype.createTexture=function(a){var b=this.j,c=b.createTexture();b.bindTexture(3553,c);b.texParameteri(3553,10241,a);b.texParameteri(3553,10240,a);b.texParameteri(3553,10242,33071);b.texParameteri(3553,10243,33071);return this.a.add(c,this.v,0,1)};function Yp(a){var b=100*(.75*a.i+.25*a.m);b=Math.max(48E6,b*a.o);var c=Math.max(200,.002*a.i*a.o);a.s=.1*b;a.u=.1*c;Tp(a.a,b,c)} +Xp.prototype.l=function(a,b,c){var d=this.a.f[b];this.g+=d&&d.c;b=this.a.f[b];this.h+=b&&b.f;a.push(c);(this.g>=this.s||this.h>=this.u)&&Zp(this)};function Zp(a){for(var b=0;b<a.b.length;b++)a.j.deleteBuffer(a.b[b]);for(b=0;b<a.f.length;b++)a.j.deleteTexture(a.f[b]);for(b=0;b<a.c.length;b++)a.j.deleteRenderbuffer(a.c[b]);a.g=0;a.h=0;a.b.splice(0,a.b.length);a.f.splice(0,a.f.length);a.c.splice(0,a.c.length)};function aq(a){Ja.call(this,a)}F(aq,Ja);aq.prototype.name="LostContextError";function bq(a,b){this.c=a.createProgram();this.b=a;this.l=b;this.m=[];this.g=!0;this.f=[];this.j=[];this.a=[];this.h={};this.i={}}r=bq.prototype;r.Bd=function(){this.l.f!=this&&(this.l.f=this,this.b.useProgram(this.c))};r.attachShader=function(a){this.m.push(a);this.b.attachShader(this.c,a)};r.detachShader=function(a){Ta(this.m,a);this.b.detachShader(this.c,a)};r.bindAttribLocation=function(a,b){this.b.bindAttribLocation(this.c,a,b);this.i[b]=a}; +r.getAttribLocation=function(a){var b=this.i[a];void 0===b&&(b=this.b.getAttribLocation(this.c,a),this.i[a]=b);return b};r.deleteProgram=function(){this.b.deleteProgram(this.c)};r.getParameter=function(a){return this.b.getProgramParameter(this.c,a)};r.Cd=function(){this.b.linkProgram(this.c);this.g=!1}; +function cq(a){a.g=!0;a.i={};a.f=[];a.a=[];a.h={};for(var b=a.b.getProgramParameter(a.c,35718),c=0,d,e=0;e<b;++e){var f=a.b.getActiveUniform(a.c,e);if(0<=f.name.indexOf("[")){var g=f.name.substr(0,f.name.indexOf("[")),h=f.size;a.h[g]=c;for(var k=0;k<h;++k){d=c++;var l=g+"["+k+"]";a.h[l]=d;a.j[d]=h-k;a.f[d]=a.b.getUniformLocation(a.c,l);a.a[d]=dq(f.type)}}else d=c++,a.h[f.name]=d,a.j[d]=0,a.f[d]=a.b.getUniformLocation(a.c,f.name),a.a[d]=dq(f.type)}} +r.getActiveUniform=function(a){return this.b.getActiveUniform(this.c,a)};r.getUniformLocation=function(a){this.g||cq(this);return void 0!==this.h[a]?this.h[a]:-1};r.Ve=function(a,b){this.g||cq(this);var c=this.f,d=this.a,e=this.b;-1!=a&&b!=d[a]&&(d[a]=b,e.uniform1f(c[a],b))};r.Xe=function(a,b,c){this.g||cq(this);var d=this.f,e=this.b;if(-1!=a){var f=this.a[a];if(b!=f[0]||c!=f[1])f[0]=b,f[1]=c,e.uniform2f(d[a],b,c)}}; +r.$e=function(a,b,c,d,e){this.g||cq(this);var f=this.f,g=this.b;if(-1!=a){var h=this.a[a];if(b!=h[0]||c!=h[1]||d!=h[2]||e!=h[3])h[0]=b,h[1]=c,h[2]=d,h[3]=e,g.uniform4f(f[a],b,c,d,e)}};r.We=function(a,b){this.g||cq(this);var c=this.f,d=this.a,e=this.b;if(-1!=a){var f=b;"boolean"==typeof d[a]&&(f=!!b);f!=d[a]&&(d[a]=f,e.uniform1i(c[a],b))}}; +r.Ye=function(a,b){this.g||cq(this);if(-1!=a){var c=!1,d;for(d=0;!c&&d<b.length/2;++d)c=b[2*d]!=this.a[a+d][0]||b[2*d+1]!=this.a[a+d][1];if(c){for(d=0;d<b.length/2;++d)this.a[a+d][0]=b[2*d],this.a[a+d][1]=b[2*d+1];this.b.uniform2fv(this.f[a],b)}}}; +r.Ze=function(a,b){this.g||cq(this);if(-1!=a){var c=!1,d;for(d=0;!c&&d<b.length/3;++d)c=b[3*d]!=this.a[a+d][0]||b[3*d+1]!=this.a[a+d][1]||b[3*d+2]!=this.a[a+d][2];if(c){for(d=0;d<b.length/3;++d)this.a[a+d][0]=b[3*d],this.a[a+d][1]=b[3*d+1],this.a[a+d][2]=b[3*d+2];this.b.uniform3fv(this.f[a],b)}}}; +r.af=function(a,b){this.g||cq(this);if(-1!=a){var c=!1,d;for(d=0;!c&&d<b.length/4;++d)c=b[4*d]!=this.a[a+d][0]||b[4*d+1]!=this.a[a+d][1]||b[4*d+2]!=this.a[a+d][2]||b[4*d+3]!=this.a[a+d][3];if(c){for(d=0;d<b.length/4;++d)this.a[a+d][0]=b[4*d],this.a[a+d][1]=b[4*d+1],this.a[a+d][2]=b[4*d+2],this.a[a+d][3]=b[4*d+3];this.b.uniform4fv(this.f[a],b)}}}; +r.bf=function(a,b,c){this.g||cq(this);if(-1!=a){var d=!1;for(b=0;!d&&b<c.length/16;++b){d=16*b;var e=this.a[a+b];d=c[d]!=e[0]||c[d+1]!=e[1]||c[d+2]!=e[2]||c[d+3]!=e[3]||c[d+4]!=e[4]||c[d+5]!=e[5]||c[d+6]!=e[6]||c[d+7]!=e[7]||c[d+8]!=e[8]||c[d+9]!=e[9]||c[d+10]!=e[10]||c[d+11]!=e[11]||c[d+12]!=e[12]||c[d+13]!=e[13]||c[d+14]!=e[14]||c[d+15]!=e[15]}if(d){for(b=0;b<c.length/16;++b){e=this.a[a+b];d=16*b;for(var f=0;16>f;++f)e[f]=c[d+f]}this.b.uniformMatrix4fv(this.f[a],!1,c)}}}; +function dq(a){switch(a){case 35670:return!1;case 5124:case 5126:case 35678:case 35680:return 0;case 35664:return new Float32Array(2);case 35667:return new Int32Array(2);case 35671:return[!1,!1];case 35665:return new Float32Array(3);case 35668:return new Int32Array(3);case 35672:return[!1,!1,!1];case 35666:return new Float32Array(4);case 35669:return new Int32Array(4);case 35673:return[!1,!1,!1,!1];case 35674:return new Float32Array(4);case 35675:return new Float32Array(9);case 35676:return new Float32Array(16)}return null} +;function eq(a,b){rc.call(this);this.B=fq++;this.j=a;this.c=b;this.b=new Op(this.c);this.a=new Zo(this.c,this.b);this.v=new no(this);Jb(this,this.v);this.h=new Xp(this,void 0,this.v);Jb(this,this.h);this.f=null;this.m=this.s=this.g=void 0;this.i=this.getParameter(3379);this.getParameter(34076);this.l=void 0;po(this.v,a,"webglcontextlost",this.Ff,!1,this);po(this.v,a,"webglcontextrestored",this.Gf,!1,this);gq(this);this.A=0}F(eq,rc);var fq=0;r=eq.prototype;r.wa=function(){return this.B}; +function hq(a){a.A=1;return a.c}function iq(a){a.A&1&&(a.f=null);a.A=0}r.X=function(){this.f=null;this.c.useProgram(null);eq.R.X.call(this)};function gq(a){var b=(a.c.drawingBufferWidth||a.j.a.width)*(a.c.drawingBufferHeight||a.j.a.height),c=a.j.c;a=a.h;c=b/(c*c);if(b!=a.m||c!=a.i)a.m=b,a.i=c,Yp(a)}function jq(a,b){var c=Po(a.b)-33984;3553==b?(a=a.a.c[c],3553!=a.b&&(a.b=3553)):(a=a.a.g[c],34067!=a.b&&(a.b=34067),34067!=b&&(a.l=b));return a} +r.texImage2D=function(a,b,c,d,e,f,g,h,k){g?Uo(jq(this,a),k,d,e,g,h,b):Qo(jq(this,a),f,d,e,b)};r.texSubImage2D=function(a,b,c,d,e,f,g,h,k){h?Vo(jq(this,a),k,c,d,e,f,g,h,b):(a=jq(this,a),h=So(a),a.bind(),To(a,g.width,e,f),a.a.texSubImage2D(h,b,c,d,e,f,g),a.g.ub(3317))};r.compressedTexImage2D=function(a,b,c,d,e,f,g){a=jq(this,a);Ro(a,d,e,c,0,b);f=So(a);a.bind();a.a.compressedTexImage2D(f,b,c,d,e,0,g)};r.activeTexture=function(a){this.b.Rb(a)};r.blendColor=function(a,b,c,d){this.b.Bc(a,b,c,d)}; +r.blendEquation=function(a){this.b.jc(a)};r.blendEquationSeparate=function(a,b){this.b.jc(a,b)};r.blendFunc=function(a,b){this.b.kc(a,b)};r.blendFuncSeparate=function(a,b,c,d){this.b.kc(a,b,c,d)};r.clearColor=function(a,b,c,d){this.b.Cc(a,b,c,d)};r.clearDepth=function(a){this.b.Dc(a)};r.clearStencil=function(a){this.b.Ec(a)};r.colorMask=function(a,b,c,d){this.b.Fc(a,b,c,d)};r.cullFace=function(a){this.b.Gc(a)};r.depthFunc=function(a){this.b.Hc(a)};r.depthMask=function(a){this.b.Fb(a)}; +r.depthRange=function(a,b){this.b.Ic(a,b)};r.disable=function(a){this.b.Ta(a,!1)};r.disableVertexAttribArray=function(a){this.b.mc(a,!1)};r.enable=function(a){this.b.Ta(a,!0)};r.enableVertexAttribArray=function(a){this.b.mc(a,!0)};r.frontFace=function(a){this.b.Kc(a)};r.hint=function(a,b){this.b.Lc(a,b)};r.lineWidth=function(a){this.b.Mc(a)};r.pixelStorei=function(a,b){this.b.eb(a,b)};r.polygonOffset=function(a,b){this.b.Nc(a,b)};r.sampleCoverage=function(a,b){this.b.Pc(a,b)}; +r.scissor=function(a,b,c,d){this.b.Qc(a,b,c,d)};r.stencilFunc=function(a,b,c){this.c.stencilFunc(a,b,c)};r.stencilOp=function(a,b,c){this.c.stencilOp(a,b,c)};r.viewport=function(a,b,c,d){gq(this);this.b.nc(a,b,c,d)};r.bindBuffer=function(a,b){34962==a?this.a.Ua(b):this.a.Jc(b)};r.bindFramebuffer=function(a,b){this.a.lc(b)};r.bindRenderbuffer=function(a,b){this.a.Oc(b)};r.bindTexture=function(a,b){var c=Po(this.b)-33984;b&&(b.b!=a&&(b.b=a),Jo(b,c));3553==a?this.a.xa(c,b):this.a.Vb(c,b)}; +r.attachShader=function(a,b){a.attachShader&&a.attachShader(b)};r.bindAttribLocation=function(a,b,c){a.bindAttribLocation&&a.bindAttribLocation(b,c)};r.createProgram=function(){return new bq(this.c,this)};r.deleteProgram=function(a){a.deleteProgram&&a.deleteProgram()};r.detachShader=function(a,b){a.detachShader&&a.detachShader(b)};r.getActiveUniform=function(a,b){return a.getActiveUniform?a.getActiveUniform(b):null}; +r.getAttribLocation=function(a,b){return a.getAttribLocation?a.getAttribLocation(b):-1};r.getProgramParameter=function(a,b){return a.getParameter?a.getParameter(b):-1};r.getUniformLocation=function(a,b){return a.getUniformLocation?a.getUniformLocation(b):-1};r.linkProgram=function(a){a.Cd&&a.Cd()};r.uniform1f=function(a,b){var c=this.f;c&&c.Ve&&c.Ve(a,b)};r.uniform1i=function(a,b){var c=this.f;c&&c.We&&c.We(a,b)};r.uniform2f=function(a,b,c){var d=this.f;d&&d.Xe&&d.Xe(a,b,c)}; +r.uniform2fv=function(a,b){var c=this.f;c&&c.Ye&&c.Ye(a,b)};r.uniform3fv=function(a,b){var c=this.f;c&&c.Ze&&c.Ze(a,b)};r.uniform4f=function(a,b,c,d,e){var f=this.f;f&&f.$e&&f.$e(a,b,c,d,e)};r.uniform4fv=function(a,b){var c=this.f;c&&c.af&&c.af(a,b)};r.uniformMatrix4fv=function(a,b,c){var d=this.f;d&&d.bf&&d.bf(a,b,c)};r.useProgram=function(a){a.Bd&&a.Bd()};r.isContextLost=function(){return this.c.isContextLost()}; +r.getSupportedExtensions=function(){var a=this.c.getSupportedExtensions();if(!a&&this.isContextLost())throw new aq("getSupportedExtensions",this);return a};r.getExtension=function(a){return this.c.getExtension(a)};var kq=["WEBGL_compressed_texture_s3tc","WEBKIT_WEBGL_compressed_texture_s3tc","MOZ_WEBGL_compressed_texture_s3tc"];r=eq.prototype; +r.Zc=function(){if(B(this.g))return!!this.g;if(yc&&!Ab(30))for(var a=this.getSupportedExtensions(),b=kq,c=0;c<a.length;c++)for(var d=0;d<b.length;d++){if(a[c]==b[d]&&(this.g=this.getExtension(b[d])))return!0}else for(b=kq,d=0;d<b.length;d++)if(this.g=this.getExtension(b[d]))return!0;this.g=null;return!1}; +function lq(a){if(B(a.s))return!!a.s;var b=a.getExtension("OES_texture_float");if(b){a.getExtension("OES_texture_float_linear");a.getExtension("WEBGL_color_buffer_float");for(var c=0;8>c;++c)a.disableVertexAttribArray(c);a.disable(3089);a.disable(2960);a.disable(2929);a.disable(3042);a.disable(2884);c=a.createShader(35633);a.shaderSource(c,"attribute vec4 vertexClip;\nvoid main() {\n gl_Position = vec4(vertexClip.xy, 0.0, 1.0);\n}");a.compileShader(c);var d=a.createShader(35632);a.shaderSource(d, +"precision highp float;\nuniform sampler2D sampler;\nuniform float mode;\nvoid main() {\n if (mode == 0.0) {\n gl_FragColor = floor(gl_FragCoord.xyxy);\n } else {\n gl_FragColor = texture2D(sampler, vec2(0.5));\n }\n}\n");a.compileShader(d);var e=a.createProgram();e.attachShader(c);e.attachShader(d);e.Cd();e.Bd();var f=a.createBuffer();a.bindBuffer(34962,f);a.bufferData(34962,new Float32Array([-1,-1,1,1,1,-1,1,1,-1,1,1,1,1,1,1,1]),35044);a.enableVertexAttribArray(e.getAttribLocation("vertexClip")); +a.vertexAttribPointer(e.getAttribLocation("vertexClip"),4,5126,!1,0,0);a.activeTexture(33984);var g=a.createTexture();a.bindTexture(3553,g);a.texParameteri(3553,10241,9729);a.texParameteri(3553,10240,9729);a.texParameteri(3553,10242,33071);a.texParameteri(3553,10243,33071);Uo(jq(a,3553),null,2,2,6408,5126,0);a.bindTexture(3553,null);var h=a.createFramebuffer();a.bindFramebuffer(36160,h);a.framebufferTexture2D(36160,36064,3553,g,0);a.uniform1f(e.getUniformLocation("mode"),0);a.uniform1i(e.getUniformLocation("sampler"), +0);a.viewport(0,0,2,2);a.drawArrays(5,0,4);a.bindFramebuffer(36160,null);a.uniform1f(e.getUniformLocation("mode"),1);a.drawArrays(5,0,4);var k=new Uint8Array([0,0,0,0]);a.readPixels(0,0,1,1,6408,5121,k);a.disableVertexAttribArray(e.getAttribLocation("vertexClip"));a.deleteBuffer(f);a.deleteTexture(g);a.deleteFramebuffer(h);a.detachShader(e,c);a.deleteShader(c);a.detachShader(e,d);a.deleteShader(d);a.deleteProgram(e);if(2<Math.abs(k[0]-127)||2<Math.abs(k[1]-127)||2<Math.abs(k[2]-127))b=null}a.s=b; +return!!b}function mq(a){B(a.l)||(Co()?a.l=a.getExtension("ANGLE_instanced_arrays"):a.l=null);return a.l}r.bufferData=function(a,b,c){this.c.bufferData(a,b,c)};r.bufferSubData=function(a,b,c){this.c.bufferSubData(a,b,c)};r.clear=function(a){this.c.clear(a)};r.compileShader=function(a){this.c.compileShader(a)};r.copyTexImage2D=function(a,b,c,d,e,f,g){a=jq(this,a);Ro(a,f,g,c,5121,b);var h=So(a);a.bind();a.a.copyTexImage2D(h,b,c,d,e,f,g,0)}; +r.copyTexSubImage2D=function(a,b,c,d,e,f,g,h){a=jq(this,a);var k=So(a);a.bind();a.a.copyTexSubImage2D(k,b,c,d,e,f,g,h)};r.createBuffer=function(){return this.c.createBuffer()};r.createFramebuffer=function(){return this.c.createFramebuffer()};r.createRenderbuffer=function(){return this.c.createRenderbuffer()};r.createShader=function(a){return this.c.createShader(a)};r.createTexture=function(){return new Io(this.c,this.b,this.a)};r.deleteBuffer=function(a){this.c.deleteBuffer(a)}; +r.deleteFramebuffer=function(a){this.c.deleteFramebuffer(a)};r.deleteRenderbuffer=function(a){this.c.deleteRenderbuffer(a)};r.deleteShader=function(a){this.c.deleteShader(a)};r.deleteTexture=function(a){a&&a.deleteTexture()};r.drawArrays=function(a,b,c){this.c.drawArrays(a,b,c)};r.framebufferRenderbuffer=function(a,b,c,d){this.c.framebufferRenderbuffer(a,b,c,d)};r.framebufferTexture2D=function(a,b,c,d,e){this.c.framebufferTexture2D(a,b,c,d.h,e)}; +r.getParameter=function(a){switch(a){case 32873:return this.a.c[Po(this.b)-33984];case 34068:return this.a.g[Po(this.b)-33984];case 35725:return this.f}a=this.c.getParameter(a);if(null===a&&this.isContextLost())throw new aq("getParameter",this);return a};r.getError=function(){return this.c.getError()};r.readPixels=function(a,b,c,d,e,f,g){this.c.readPixels(a,b,c,d,e,f,g)};r.renderbufferStorage=function(a,b,c,d){this.c.renderbufferStorage(a,b,c,d)}; +r.shaderSource=function(a,b){this.c.shaderSource(a,b)};r.texParameteri=function(a,b,c){a=jq(this,a);switch(b){case 10241:No(a,c);break;case 10240:Oo(a,c);break;case 10242:Ko(a,c);break;case 10243:Lo(a,c)}};r.vertexAttribPointer=function(a,b,c,d,e,f){this.c.vertexAttribPointer(a,b,c,d,e,f)};function nq(a){a.h.clear();a.f=null;a.a.clear();a.b.clear()}r.Ff=function(a){a.b();nq(this);E();this.dispatchEvent("webglcontextlost")}; +r.Gf=function(){nq(this);if(this.g&&(this.g=void 0,!this.Zc()))throw Error("Lost compressed textures extension.");if(this.s&&(this.s=void 0,!lq(this)))throw Error("Lost texture float extension.");if(this.m&&(this.m=void 0,B(this.m)||(this.m=this.getExtension("WEBGL_depth_texture")),!this.m))throw Error("Lost depth texture extension.");B(this.l)&&(this.l=void 0,mq(this));E();this.dispatchEvent("webglcontextrestored")};function oq(a,b,c,d){this.top=a;this.right=b;this.bottom=c;this.left=d}oq.prototype.ceil=function(){this.top=Math.ceil(this.top);this.right=Math.ceil(this.right);this.bottom=Math.ceil(this.bottom);this.left=Math.ceil(this.left);return this};oq.prototype.floor=function(){this.top=Math.floor(this.top);this.right=Math.floor(this.right);this.bottom=Math.floor(this.bottom);this.left=Math.floor(this.left);return this}; +oq.prototype.round=function(){this.top=Math.round(this.top);this.right=Math.round(this.right);this.bottom=Math.round(this.bottom);this.left=Math.round(this.left);return this};function pq(a,b,c,d){this.left=a;this.top=b;this.width=c;this.height=d}pq.prototype.ceil=function(){this.left=Math.ceil(this.left);this.top=Math.ceil(this.top);this.width=Math.ceil(this.width);this.height=Math.ceil(this.height);return this};pq.prototype.floor=function(){this.left=Math.floor(this.left);this.top=Math.floor(this.top);this.width=Math.floor(this.width);this.height=Math.floor(this.height);return this}; +pq.prototype.round=function(){this.left=Math.round(this.left);this.top=Math.round(this.top);this.width=Math.round(this.width);this.height=Math.round(this.height);return this};function qq(a){this.b=a+15>>4;this.a=new Uint16Array(this.b)}function rq(a,b){var c=a.b;b=b+15>>4;var d=a.a,e=new Uint16Array(b);c=b>c?c:b;for(var f=0;f<c;f++)e[f]=d[f];a.b=b;a.a=e}function sq(a,b){return(4294967295<<a&4294967295>>>32-b-1)>>>0}function tq(a){for(var b=0;32>b;b++)if(a&1<<b)return b;return 0}function uq(a){for(var b=0;b<a.b;b++)a.a[b]=0} +function vq(a,b,c){var d=b>>4,e=c-1>>4;b&=15;c=c-1&15;if(d==e)a.a[d]|=sq(b,c);else{a.a[d]|=sq(b,15);for(d+=1;d<e;d++)a.a[d]=65535;a.a[e]|=sq(0,c)}}function wq(a,b,c){var d=b>>4,e=c-1>>4;b&=15;c=c-1&15;if(d==e)a.a[d]&=~sq(b,c);else{a.a[d]&=~sq(b,15);for(d+=1;d<e;d++)a.a[d]=0;a.a[e]&=~sq(0,c)}} +function xq(a,b,c,d){for(var e=!1,f=b>>4,g=c-1>>4;f<=g&&65535==a.a[f];)e=!0,f++;if(f>g)return-1;for(e&&(b=f<<4);b<=c-d;){e=!1;for(f=b+d-1;f>=b;f--)if(a.a[f>>4]>>(f&15)&1){b=f+1;e=!0;break}if(!e)return b}return-1}function yq(a,b,c){if(c<=b)return c;var d=b>>4,e=c-1>>4,f=b&15;b=c-1&15;if(d==e)return f=a.a[d]&sq(f,b),0==f?c:tq(f)+(d<<4);if(f=a.a[d]&sq(f,15))return tq(f)+(d<<4);for(d+=1;d<e;d++)if(f=a.a[d])return tq(f)+(d<<4);a=a.a[e]&sq(0,b);return 0==a?c:tq(a)+(e<<4)};function zq(a,b,c,d){d=d||32;this.l=a;this.c=b;this.B=B(c)?c:0;this.A=d;this.o=Math.ceil(this.l/d);this.u=new qq(this.c);this.j=new qq(this.c*this.o);this.a=null;this.g=-1;this.h=[];this.i=[];this.s=-1;this.m=new Int32Array(b);this.b=null;this.f=-1;this.v=0;this.clear()}function Aq(a,b){var c=a.c;b=c+b;if(a.B&&b>a.B)return!1;rq(a.u,b);rq(a.j,b*a.o);var d=a.m,e=new Int32Array(b);for(e.set(d);c<b;c++)e[c]=-1;a.c=b;a.m=e;return!0} +zq.prototype.clear=function(){uq(this.u);uq(this.j);this.a=null;this.g=-1;this.b=null;this.f=-1;Bq(this);Cq(this);for(var a=0;a<this.c;a++)this.m[a]=-1;this.h=[];this.i=[];this.s=-1};function Dq(a,b,c){b=6*b+5;var d=a.b[b];a.b[b]=c?d|2:d&-3}function Eq(a,b){a.b[6*b+1]=0;a.b[6*b+2]=0;a.b[6*b+3]=0;a.b[6*b+4]=0;a.b[6*b+5]=0;a.b[6*b+0]=a.f;a.f=b}function Bq(a){var b=a.b,c=b?b.length:0,d=c/6,e=d+1024,f=new Int32Array(6*e);if(b)for(var g=0;g<c;g++)f[g]=b[g];a.b=f;for(g=d;g<e;g++)Eq(a,g)} +function Fq(a,b){a.a[6*b+2]=0;a.a[6*b+3]=0;a.a[6*b+4]=0;a.a[6*b+5]=a.l;a.a[6*b+0]=a.g;a.a[6*b+1]=-1;a.g=b}function Gq(a){-1==a.g&&Cq(a);var b=a.g;a.g=a.a[6*a.g+0];a.a[6*b+0]=-1;return b}function Cq(a){var b=a.a,c=b?b.length:0,d=c/6,e=d+128,f=new Int32Array(6*e);if(b)for(var g=0;g<c;g++)f[g]=b[g];a.a=f;for(g=d;g<e;g++)Fq(a,g)}function Hq(a,b,c){var d=a.i[c];B(d)?(a.a[6*b+1]=d,a.a[6*b+0]=-1,a.a[6*d+0]=b):a.h[c]=b;a.i[c]=b} +function Iq(a,b,c){var d=a.a[6*b+1],e=a.a[6*b+0];b==a.h[c]&&(0<=e?a.h[c]=e:delete a.h[c]);b==a.i[c]&&(0<=d?a.i[c]=d:delete a.i[c]);-1!=d&&(a.a[6*d+0]=e);-1!=e&&(a.a[6*e+1]=d);a.a[6*b+1]=-1;a.a[6*b+0]=-1}function Jq(a,b,c){var d=a.a[6*b+2];a.m[d]=-1;wq(a.u,d,d+c);Fq(a,b)} +function Kq(a,b){var c=a.b[6*b+2],d=a.b[6*b+4],e=Math.ceil(a.A/d),f=Math.floor(a.l/e),g=a.m[c];c=c*a.o+a.b[6*b+1]/e;e=a.b[6*b+3]/e;wq(a.j,c,c+e);Eq(a,b);c=a.a[6*g+4];b=c-e;a.a[6*g+4]=b;a.a[6*g+5]=a.l;c==f?(f=a.a[6*g+1],e=a.a[6*g+0],g==a.s&&(a.s=e),-1!=f&&(a.a[6*f+0]=e),-1!=e&&(a.a[6*e+1]=f),a.a[6*g+1]=-1,a.a[6*g+0]=-1,0==b?Jq(a,g,d):Hq(a,g,d)):0==b&&(Iq(a,g,d),Jq(a,g,d))} +function Lq(a,b,c){a:{var d=[b];b=Math.ceil(a.A/c);var e=Math.floor(a.l/b),f=d[0],g=Math.ceil(f/b);if(f>a.l)c=-1;else{var h=-1,k=-1,l=-1,m=-1,n=-1,p=a.h[c];if(B(p))for(;-1!=p;p=a.a[6*p+0])if(m=a.a[6*p+4],!(m+g>e||a.a[6*p+5]<=g))if(h=a.a[6*p+2],k=h*a.o,l=k+e,n=xq(a.j,k,l,g),-1!=n)break;else a.a[6*p+5]=g;if(-1==n){n=xq(a.u,0,a.c,c);-1==n?p=-1:(h=Gq(a),a.a[6*h+2]=n,a.a[6*h+3]=c,vq(a.u,n,n+c),p=a.m[n]=h);if(-1==p){c=-1;break a}Hq(a,p,c);h=a.a[6*p+2];k=h*a.o;l=k+e;m=0;n=k}g=n+g;for(var q=1,t=1;t<d.length;t++){f+= +d[t];var v=n+Math.ceil(f/b);if(v>l)break;if(yq(a.j,g,v)==v)g=v,q++;else break}f=g-n;-1==a.f&&Bq(a);d=a.f;a.f=a.b[6*a.f+0];a.b[6*d+0]=-1;a.b[6*d+1]=(n-k)*b;a.b[6*d+2]=h;a.b[6*d+3]=(g-n)*b;a.b[6*d+4]=c;m+=f;a.a[6*p+4]=m;m==e&&(Iq(a,p,c),c=p,b=a.s,a.a[6*c+1]=-1,a.a[6*c+0]=b,-1!=b&&(a.a[6*b+1]=c),a.s=c);vq(a.j,n,g);c=d}}-1!=c&&a.v++;return c};function Mq(a,b,c,d,e,f,g,h){this.h=a;this.i=!1;this.I=a.i;this.D=h?h.width:1;this.o=h?h.height:1;this.f=new zq(Math.floor(b/this.D),Math.floor(c/this.o),Math.floor(this.I/this.o),h?1:32);this.m=d;this.b=null;this.c=b;this.a=c;this.J=e;this.K=f;this.l=this.g=0;this.v=g||128;this.j={};this.B=this.s=this.C=void 0;this.H=new Uint8Array(64);this.G=[];this.A=this.u=0;this.clear()}F(Mq,Pp);Mq.prototype.X=function(){this.b&&(this.h.deleteTexture(this.b),this.b=null);Mq.R.X.call(this)}; +function Nq(a){this.block=a;this.source=null;this.a=1}function Oq(a){return Math.ceil(a.f.c*a.o/a.v)*a.v}function Pq(a){for(var b in a.j){var c=a.j[b];c.source=null;0<=c.block&&Dq(a.f,c.block,!1)}a.u=0}Mq.prototype.clear=function(){this.f.clear();this.b&&(this.h.deleteTexture(this.b),this.b=null);this.l=this.g=0;this.j={};this.B=this.s=this.C=void 0;this.u=0;this.a=Oq(this);this.b=Qq(this,this.c,this.a);this.A++};function Rq(a){Pq(a);a.b&&a.h.deleteTexture(a.b);a.a=Oq(a);a.b=Qq(a,a.c,a.a);a.A++} +function Sq(a){a.i=!0;a.h=null;a.b=null;Pq(a)}function Tq(a,b){a.i&&(a.i=!1,a.h=b,a.I=b.i,Rq(a))}function Qq(a,b,c){if(a.i)return null;var d=a.h,e=d.createTexture();if(!e||!e.h)return null;d.a.xa(d.a.vb()+1-1,e);d.texParameteri(3553,10240,a.J);d.texParameteri(3553,10241,a.J);d.texParameteri(3553,10242,33071);d.texParameteri(3553,10243,33071);a=a.m;Uo(jq(d,3553),null,b,c,a,5121,0);return e} +function Uq(a){if(6406!=a.m&&!a.i&&0<a.g){var b=a.h,c=a.c,d=a.a,e=a.b,f=Oq(a),g=Qq(a,c,f);if(g){var h=b.createFramebuffer();if(h){var k=Fp(b.b),l=b.a.f;b.bindFramebuffer(36160,h);b.framebufferTexture2D(36160,36064,3553,e,0);b.a.xa(b.a.vb()+1-1,g);b.copyTexSubImage2D(3553,0,0,0,0,0,c,d);b.texSubImage2D(3553,0,0,d,c,f-d,a.m,5121,new Uint8Array(c*(f-d)*4));b.bindFramebuffer(36160,l);b.viewport(k[0],k[1],k[2],k[3]);b.deleteFramebuffer(h);b.deleteTexture(e);a.b=g;a.c=c;a.a=f}else b.deleteTexture(g)}}} +function Vq(a){a.l=0;a.g=0}function Wq(a){if(!a.O()&&!a.i)if(a.g)a.g++;else if(a.b){Oq(a)>a.a&&6408!=a.m&&Rq(a);a.g=1;Oq(a)>a.a&&Uq(a);var b=a.h,c=b.a.vb()+1-1;a.C=Po(b.b);a.s=b.a.c[c];b.a.xa(c,a.b);a.B=yp(b.b,37441);b.pixelStorei(37441,a.K?1:0);for(b=0;b<a.u;b++)c=a.G[b],Xq(a,c.left,c.top,c.width,c.height);a.u=0}} +function Yq(a){if(!a.i&&a.g)if(1<a.g)a.g--;else{var b=a.h;B(a.B)&&(b.pixelStorei(37441,a.B),a.B=void 0);B(a.s)&&(a.s&&a.s.m||b.bindTexture(3553,a.s),a.s=void 0);B(a.C)&&(b.activeTexture(a.C),a.C=void 0);a.g=0}}function Xq(a,b,c,d,e){var f=d*e*4;f>a.H.length&&(a.H=new Uint8Array(f));f=a.m;var g=a.H;Vo(jq(a.h,3553),g,b,c,d,e,f,5121,0)} +function Zq(a,b,c){if(0>=b||b>a.c||0>=c)return-1;b=Math.ceil(b/a.D);c=Math.ceil(c/a.o);var d=Lq(a.f,b,c);if(-1!=d)return d;d=Oq(a)+a.v;if(d>a.I||!Aq(a.f,Math.floor(d/a.o)-a.f.c))return-1;0<a.g&&Oq(a)>a.a&&Uq(a);a=Lq(a.f,b,c);return-1!=a?a:-1} +function $q(a,b,c,d,e,f,g,h,k){if(!(a.i||0>b||!(0<a.g)||0>=g||0>=h||0>e||0>f||e+g>ar(a,b)||f+h>br(a,b))){if(null!==c){var l=a.j[c];if(!l||l.block!=b||d&&l.source&&l.source==d)return}e=cr(a,b)+e;f=dr(a,b)+f;k instanceof Uint8Array?(l=a.m,Vo(jq(a.h,3553),k,e,f,g,h,l,5121,0)):(g=a.m,h=jq(a.h,3553),l=So(h),h.bind(),To(h,k.width,g,5121),h.a.texSubImage2D(l,0,e,f,g,5121,k),h.g.ub(3317));Dq(a.f,b,!0);c&&d&&(a.j[c].source=d)}} +function er(a,b){if(!(0>b)){if(a.f.b[6*b+5]&2)if(0<a.g)Xq(a,cr(a,b),dr(a,b),ar(a,b),br(a,b));else{a.u==a.G.length&&a.G.push(new pq(0,0,0,0));var c=a.G[a.u++];c.left=cr(a,b);c.top=dr(a,b);c.width=ar(a,b);c.height=br(a,b)}a=a.f;Kq(a,b);a.v--}}function fr(a,b){!a.i&&a.b&&(a.l?a.l++:(a.h.a.xa(b,a.b),a.l=1))}function gr(a){!a.i&&a.l&&(1<a.l?a.l--:a.l=0)}function cr(a,b){return a.f.b[6*b+1]*a.D}function dr(a,b){return a.f.b[6*b+2]*a.o}function ar(a,b){return a.f.b[6*b+3]*a.D} +function br(a,b){return a.f.b[6*b+4]*a.o};function hr(a){this.arrayBuffer=new ArrayBuffer(a);this.a=0;new Float32Array(this.arrayBuffer);new Int32Array(this.arrayBuffer);this.g=new Uint32Array(this.arrayBuffer);this.c=new Int16Array(this.arrayBuffer);this.f=new Uint16Array(this.arrayBuffer);new Int8Array(this.arrayBuffer);this.b=new Uint8Array(this.arrayBuffer)};function ir(a,b,c,d){this.a=a;this.f=b;0==c&&(c=1);this.i=c;this.c=d||65536;this.c-=this.c%c;this.j=this.c/c;this.b=new zq(this.j,1,0,4);this.g=[];this.h=[]}function jr(a,b,c){this.a=b;this.buffer=null;this.b=c;this.c=a}function kr(a,b,c,d,e){this.start=a;this.size=b;this.c=b/c;this.b=a/c;this.a=e;this.f=d}function lr(a,b){for(var c=[],d=b,e=a.f*a.c;0<d;){var f=Math.min(d,e);d-=f;c.push(mr(a,f))}a=new jr(b,c,a);B(!1)||(a.buffer=new hr(b));return a} +function mr(a,b){var c=b/a.f/a.i,d=Lq(a.b,c,1);0>d&&(Aq(a.b,1),d=Lq(a.b,c,1));c=a.b.b[6*d+2];var e=a.g[c];if(!e){a.g[c]=e=a.a.createBuffer();a.h[c]=0;var f=a.a.a.b||null;a.a.a.Ua(e);a.a.bufferData(34962,a.f*a.c,35048);a.a.a.Ua(f)}a.h[c]++;return new kr(a.b.b[6*d+1]*a.i*a.f,b,a.f,d,e)} +function nr(a,b,c){c=B(c)?c:b.buffer.b;for(var d=0,e=0;e<b.a.length;++e){var f=b.a[e],g=c.byteLength==f.size?c:new Uint8Array(c.buffer,c.byteOffset+d,f.size),h=a.a.a.b||null;a.a.a.Ua(f.a);a.a.bufferSubData(34962,f.start,g);a.a.a.Ua(h);d+=f.size}b.buffer=null};function or(){this.a=new Int32Array(4096);this.b=-1;this.c={};for(var a=4095;0<=a;a--)this.a[a]=-1-this.b,this.b=a;this.g=this.f=null}function pr(a,b){var c=a.c[b];if(B(c))a.a[c]++;else{if(0>a.b){var d=2*a.a.length;c=new Int32Array(d);c.set(a.a);for(--d;d>=a.a.length;d--)c[d]=-1-a.b,a.b=d;a.a=c}c=a.b;a.b=-1-a.a[c];a.a[c]=1;a.c[b]=c}return c}function qr(a,b){a=a.c[b];return B(a)?a:-1};var rr=function(a){return function(){return a}}(!1);function sr(a){return a};function tr(a){x.setTimeout(function(){throw a;},0)}function ur(a,b,c){var d=a;b&&(d=D(a,b));d=vr(d);!ya(x.setImmediate)||!c&&x.Window&&x.Window.prototype&&!fb("Edge")&&x.Window.prototype.setImmediate==x.setImmediate?(wr||(wr=xr()),wr(d)):x.setImmediate(d)}var wr; +function xr(){var a=x.MessageChannel;"undefined"===typeof a&&"undefined"!==typeof window&&window.postMessage&&window.addEventListener&&!fb("Presto")&&(a=function(){var a=document.createElement("IFRAME");a.style.display="none";a.src="";document.documentElement.appendChild(a);var b=a.contentWindow;a=b.document;a.open();a.write("");a.close();var c="callImmediate"+Math.random(),d="file:"==b.location.protocol?"*":b.location.protocol+"//"+b.location.host;a=D(function(a){if(("*"==d||a.origin==d)&&a.data== +c)this.port1.onmessage()},this);b.addEventListener("message",a,!1);this.port1={};this.port2={postMessage:function(){b.postMessage(c,d)}}});if("undefined"!==typeof a&&!fb("Trident")&&!fb("MSIE")){var b=new a,c={},d=c;b.port1.onmessage=function(){if(B(c.next)){c=c.next;var a=c.be;c.be=null;a()}};return function(a){d.next={be:a};d=d.next;b.port2.postMessage(0)}}return"undefined"!==typeof document&&"onreadystatechange"in document.createElement("SCRIPT")?function(a){var b=document.createElement("SCRIPT"); +b.onreadystatechange=function(){b.onreadystatechange=null;b.parentNode.removeChild(b);b=null;a();a=null};document.documentElement.appendChild(b)}:function(a){x.setTimeout(a,0)}}var vr=sr;Hb(function(a){vr=a});function yr(){this.m=sa;this.f=this.g=!1;this.h=null;this.s=x.requestAnimationFrame||x.webkitRequestAnimationFrame||x.mozRequestAnimationFrame||x.oRequestAnimationFrame||x.msRequestAnimationFrame||function(a){x.setTimeout(a,16)};var a=this;this.j=function(){a.a=!1;zr(a)};this.l=function(){a.c=!1;a.g=!1;zr(a)};this.c=this.a=!1;this.b=!0;this.i=0;lo(D(this.o,this),void 0,void 0)}function zr(a){a.f=!0;try{a.h.xb()}catch(b){throw a.m(b),b;}a.g&&(a.a&&a.b||Ar(a));a.f=!1} +function Br(a){a.b?a.a||a.c||(a.s.call(x,a.j),a.a=!0):Ar(a)}function Cr(a){zc?Br(a):a.f?a.g=!0:a.b&&a.a||Ar(a)}function Ar(a){a.c||!a.b&&E()>a.i||(ur(a.l),a.c=!0)}yr.prototype.o=function(a){(this.b=a)&&!this.a?Ar(this):this.i=E()+1E4};function Dr(){};var Er=[];function Fr(a,b,c){this.b=a||new yr;this.b.h=this;E();this.m=Gr;this.D=this.s=this.c=0;this.l=this.i=!1;this.g=[];this.f=[];this.h=[];this.a=[];this.a[0]=[];this.a[1]=[];this.a[2]=[];this.a[3]=[];this.a[4]=[];this.a[5]=[];this.A=[];this.G=!!b;this.B=!c;this.o=!1;this.u=this.v=0;Er.push(this)}var Gr=1E3/60,Hr=1E4/60;r=Fr.prototype;r.Te=function(a){this.g.push(a);Br(this.b)};r.Pd=function(a){this.f.push(a);Br(this.b)};r.Ue=function(a){this.h.push(a);Br(this.b)};r.Mb=function(a,b){Ir(this,a,Jr(b,!1))}; +r.ed=function(a,b){Ir(this,a,Jr(b,!0))};function Jr(a,b){a*=2;b&&(a+=1);return a}function Ir(a,b,c){var d=b.__maps_realtime_JobScheduler_next_step;d&&d!=Dr||(b.__maps_realtime_JobScheduler_next_step=b.start,b.__maps_realtime_JobScheduler_priority=c,a.a[c].push(b),a.i||Cr(a.b))}r.Pe=function(a){a.__maps_realtime_JobScheduler_next_step=null}; +r.qd=function(a,b){var c=a.__maps_realtime_JobScheduler_next_step;if(c&&c!=Dr&&(c=a.__maps_realtime_JobScheduler_priority,b=1==c||3==c||5==c?Jr(b,!0):Jr(b,!1),c!=b)){for(var d=this.a[c].length,e=0;e<d;++e)if(this.a[c][e]==a){this.a[c][e]=null;break}a.__maps_realtime_JobScheduler_priority=b;this.a[b].push(a)}}; +r.zc=function(){try{this.i=!0;for(var a=E()+2,b=5;0<=b&&Kr(this,b,a);b--);}finally{this.i=!1,(0<this.a[5].length||0<this.a[4].length||0<this.a[3].length||0<this.a[2].length||0<this.a[1].length||0<this.a[0].length)&&Cr(this.b)}}; +r.xb=function(){var a=E();this.i=!0;var b=0,c=this.A;if(0<c.length){for(b=0;b<c.length;b++)this.Mb(c[b].Df,c[b].priority);this.A=[]}try{E();var d=this.g;this.g=[];var e=d.length;for(c=0;c<e;c++){var f=d[c];Lr();Mr(f)}E();if(this.G){Nr(this);Or(this,a);var g=Infinity}else if(this.B)if(a-this.s<this.m-(6+this.c))g=a+this.m-3;else{Nr(this);Or(this,a);var h=E();d=h-a;this.c*=.97;this.c+=.03*d;var k=Math.ceil(1/Gr*(this.c+3+6))*Gr;k=k<Gr?Gr:k;this.m=k=k>Hr?Hr:k;g=Pr(this,a,h)}else{Nr(this);Or(this,a); +var l=E();g=Pr(this,a,l)}this.l=!1;for(b=5;0<=b&&Kr(this,b,g);b--);}finally{this.i=!1,b=0<this.h.length||0<this.f.length||0<this.g.length,g=0<this.a[5].length||0<this.a[4].length||0<this.a[3].length||0<this.a[2].length||0<this.a[1].length||0<this.a[0].length,b?Br(this.b):g&&Cr(this.b),this.o&&(this.u+=E()-a),this.o=g||b}};function Nr(a){E();var b=a.f;a.f=[];a=b.length;for(var c=0;c<a;c++){var d=b[c];Lr();Qr(d)}E()}function Pr(a,b,c){a=b+a.m-3;c-=a;0<c&&(a+=Math.ceil(c/Gr)*Gr);return a} +Hb(function(a){Fr.prototype.xb=a(Fr.prototype.xb)}); +function Kr(a,b,c){E();if(a.l&&E()>=c)return!1;var d=a.a[b];if(0==d.length)return!0;for(var e=[],f=!1,g=0;g<d.length&&!f;g++){var h=d[g];if(h)for(;;){var k=h.__maps_realtime_JobScheduler_next_step;if(!k||k==Dr)break;k=E();if(a.l&&k>=c){f=!0;e.push(g);break}Lr();k=Dr;try{k=h.__maps_realtime_JobScheduler_next_step()}finally{h.__maps_realtime_JobScheduler_next_step=k,a.l=!0}if(k==Dr)break}}E();k=[];for(var l=0;l<e.length;l++)if(h=d[e[l]]){var m=h.__maps_realtime_JobScheduler_next_step;m&&m!=Dr&&k.push(h)}if(f)return a.a[b]= +k.concat(d.slice(g-1)),!1;a.a[b]=k;return E()<c}function Or(a,b){E();var c=b-a.s;a.o&&(a.D++,a.v+=c,a.u=0);a.s=b;b=a.h;a.h=[];a=b.length;for(c=0;c<a;c++){var d=b[c];Lr();vo(d)}E()}Fr.prototype.C=function(){if(0<this.h.length||0<this.f.length||0<this.g.length)return!0;if(!B(void 0))return!1;for(var a=Jr(void 0,!1);5>=a;a++)if(this.a[a].length)return!0;return!1};function Lr(){x.performance&&x.performance.now||E()}Fr.prototype.j=function(){return sa};function Rr(a){this.byteLength=a;this.a=Array(a);for(var b=0;b<a;b++)this.a[b]=0}function Sr(){}function Tr(a,b,c){if(a instanceof Rr)for(this.length=c||a.byteLength/this.a,this.buffer=new Rr(a.byteLength),b=0;b<this.length;b++)this[b]=a.a[b];else{if(xa(a)){for(b=0;b<a.length;b++)this[b]=a[b];this.length=a.length}else for(this.length=a||0,b=0;b<this.length;b++)this[b]=0;this.buffer=new Rr(this.length*this.a)}this.buffer.a=this;this.byteLength=this.length*this.a}F(Tr,Sr); +Tr.prototype.set=function(a,b){b=b||0;for(var c=0;c<a.length;c++)this[b+c]=a[c]};Tr.prototype.slice=function(){};Tr.prototype.subarray=function(){return null};function Ur(a,b,c){Tr.call(this,a,b,c)}F(Ur,Tr);Ur.prototype.a=1;function Vr(a,b,c){Tr.call(this,a,b,c)}F(Vr,Tr);Vr.prototype.a=1;function Wr(a,b,c){Tr.call(this,a,b,c)}F(Wr,Tr);Wr.prototype.a=2;function Xr(a,b,c){Tr.call(this,a,b,c)}F(Xr,Tr);Xr.prototype.a=2;function Yr(a,b,c){Tr.call(this,a,b,c)}F(Yr,Tr);Yr.prototype.a=4; +function Zr(a,b,c){Tr.call(this,a,b,c)}F(Zr,Tr);Zr.prototype.a=4;function $r(a,b,c){Tr.call(this,a,b,c)}F($r,Tr);$r.prototype.a=4;function as(a,b,c){Tr.call(this,a,b,c)}F(as,Tr);as.prototype.a=4;function bs(){}F(bs,Sr);"undefined"==typeof ArrayBuffer&&(x.ArrayBuffer=Rr);"undefined"==typeof Int8Array&&(x.Int8Array=Ur);"undefined"==typeof Uint8Array&&(x.Uint8Array=Vr);"undefined"==typeof Int16Array&&(x.Int16Array=Wr);"undefined"==typeof Uint16Array&&(x.Uint16Array=Xr); +"undefined"==typeof Int32Array&&(x.Int32Array=Yr);"undefined"==typeof Uint32Array&&(x.Uint32Array=Zr);"undefined"==typeof Float32Array&&(x.Float32Array=$r);"undefined"==typeof Float64Array&&(x.Float64Array=as);"undefined"==typeof DataView&&(x.DataView=bs);function cs(a,b){var c=this;a?this.canvas=a:(this.canvas={},this.canvas.attachEvent=function(){},this.canvas.width=0,this.canvas.height=0,this.canvas.getBoundingClientRect=function(){return{left:0,right:c.canvas.width,top:0,bottom:c.canvas.height,width:c.canvas.width,height:c.canvas.height}});this.C=new ds;if(b)for(var d in b){if(!(d in this.C))throw Error("Invalid context attribute: "+d);this.C[d]=b[d]}this.m=[];this.o=[];this.c=0;this.g=[0,0,0,0];this.A={};this.A.ANGLE_instanced_arrays={VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE:1, +drawArraysInstancedANGLE:function(){},drawElementsInstancedANGLE:function(){},vertexAttribDivisorANGLE:function(){}};this.u=this.s=this.f=this.b=null;this.h=[0,0,0,0];this.i=[!0,!0,!0,!0];this.l=new pq(0,0,0,0);this.j=new pq(0,0,0,0);this.B={};this.v=[0,1];Object.defineProperty(this,"drawingBufferWidth",{get:function(){return c.canvas.width}});Object.defineProperty(this,"drawingBufferHeight",{get:function(){return c.canvas.height}});this.a=[];this.a[34016]=33984;this.a[33902]=[1,10];this.a[33901]= +[1,63];this.a[3413]=8;this.a[3042]=!1;this.a[32773]=this.g;this.a[32970]=0;this.a[32968]=0;this.a[34877]=32774;this.a[32777]=32774;this.a[32971]=1;this.a[32969]=1;this.a[3412]=8;this.a[3106]=this.h;this.a[3107]=this.i;this.a[34467]=[];this.a[2884]=!1;this.a[2885]=1029;this.a[35725]=null;this.a[3414]=24;this.a[2931]=1;this.a[2932]=513;this.a[2928]=this.v;this.a[2929]=!1;this.a[2930]=!0;this.a[3024]=!0;this.a[2886]=2305;this.a[33170]=4352;this.a[3411]=8;this.a[2849]=1;this.a[35661]=96;this.a[34076]= +8192;this.a[36349]=512;this.a[34024]=8192;this.a[34930]=32;this.a[3379]=8192;this.a[36348]=15;this.a[34921]=16;this.a[35660]=32;this.a[36347]=1024;this.a[3386]=[8192,8192];this.a[3333]=4;this.a[32824]=0;this.a[32823]=!1;this.a[10752]=0;this.a[3410]=8;this.a[7937]="Fake WebGL";this.a[32937]=4;this.a[32936]=1;this.a[32939]=!1;this.a[32938]=1;this.a[3088]=this.j;this.a[3089]=!1;this.a[35724]="WebGL GLSL ES 1.0 (OpenGL ES GLSL ES 1.0 TotallyFake)";this.a[34817]=7680;this.a[34816]=519;this.a[34818]=7680; +this.a[34819]=7680;this.a[36003]=0;this.a[36004]=4294967295;this.a[36005]=4294967295;this.a[3415]=8;this.a[2961]=0;this.a[2964]=7680;this.a[2962]=519;this.a[2965]=7680;this.a[2966]=7680;this.a[2967]=0;this.a[2960]=!1;this.a[2963]=4294967295;this.a[2968]=4294967295;this.a[3408]=8;this.a[3317]=4;this.a[37443]=37444;this.a[37440]=!1;this.a[37441]=!1;this.a[7936]="Fakers";this.a[7938]="WebGL 1.0 (OpenGL ES 2.0 TotallyFake)";this.a[2978]=this.l;this.D=[];for(a=0;a<this.a[35661];++a)this.m[a]=null,this.o[a]= +null;es()}r=cs.prototype;r.createProgram=function(){return new fs};r.deleteProgram=function(a){a.a=!0};r.createShader=function(a){return new gs(a)};r.deleteShader=function(a){a.a=!0};r.shaderSource=function(a,b){a.source=b};r.compileShader=function(a){a.b=!0};r.attachShader=function(a,b){35633==b.type?a.c=b:35632==b.type&&(a.b=b)};r.detachShader=function(a,b){35633==b.type?a.c=null:35632==b.type&&(a.b=null)}; +r.linkProgram=function(a){function b(a){switch(a){case "bool":return 35670;case "bvec2":return 35671;case "bvec3":return 35672;case "bvec4":return 35673;case "int":return 5124;case "ivec2":return 35667;case "ivec3":return 35668;case "ivec4":return 35669;case "float":return 5126;case "vec2":return 35664;case "vec3":return 35665;case "vec4":return 35666;case "mat2":return 35674;case "mat3":return 35675;case "mat4":return 35676;case "sampler2D":return 35678;case "samplerCube":return 35680}}if(a.c&&a.c.b&& +a.b&&a.b.b){var c=a.c.source+a.b.source;c=c.replace(/\n/g," ");for(var d=/uniform (\w+) (.*?);/g,e,f=[],g=[];e=d.exec(c);){var h=e[1],k=e[2].split(",");for(e=0;e<k.length;e++)-1==f.indexOf(k[e].trim())&&(f.push(k[e].trim()),g.push(b(h)))}for(e=0;e<f.length;e++)c=new hs,c.name=f[e],c.type=g[e],d=new is,d.name=f[e],d.index=e,a.i.push(f[e]),a.f.push(c),a.h.push(d);a.g=!0}};r.getError=function(){return 0}; +r.getProgramParameter=function(a,b){switch(b){case 35712:return a.a;case 35714:return a.g;case 35715:return!0;case 35717:return!!a.c+!!a.b;case 35721:return 0;case 35718:return a.f.length}};r.getActiveUniform=function(a,b){return a.f[b]};r.getUniformLocation=function(a,b){return a.h[a.i.indexOf(b)]};r.useProgram=function(){};r.createTexture=function(){return new js};r.deleteTexture=function(){};r.createFramebuffer=function(){return new ks};r.deleteFramebuffer=function(a){a.a=!0}; +r.createRenderbuffer=function(){return new ls};r.deleteRenderbuffer=function(a){a.a=!0};r.createBuffer=function(){return new ms};r.deleteBuffer=function(a){a.a=!0};r.viewport=function(a,b,c,d){this.l.left=a;this.l.top=b;this.l.width=c;this.l.height=d};r.scissor=function(a,b,c,d){this.j.left=a;this.j.top=b;this.j.width=c;this.j.height=d};r.activeTexture=function(a){this.c=a-33984;this.a[34016]=a};r.bindFramebuffer=function(a,b){this.b=b};r.bindRenderbuffer=function(a,b){this.f=b}; +r.bindTexture=function(a,b){3553==a?this.m[this.c]=b:this.o[this.c]=b};function ns(a,b){return 3553==b?a.m[a.c]:a.o[a.c]}r.compressedTexImage2D=function(a,b,c,d,e,f,g){a=ns(this,a);a.format=c;a.width=d;a.height=e;a.data=g};r.copyTexImage2D=function(a,b,c,d,e,f,g){a=ns(this,a);a.format=c;a.width=f;a.height=g;a.data=this.b?this.b.getData()+" from ("+d+", "+e+") with size of "+f+"x"+g:"Screen from ("+d+", "+e+") with size of "+f+"x"+g}; +r.framebufferTexture2D=function(a,b,c,d){switch(b){case 36064:this.b.b=d;break;case 36096:this.b.c=d;break;case 36128:this.b.f=d}};r.framebufferRenderbuffer=function(a,b,c,d){switch(b){case 36064:this.b.b=d;break;case 36096:this.b.c=d;break;case 36128:this.b.f=d;break;case 33306:this.b.g=d}};r.renderbufferStorage=function(a,b,c,d){this.f.format=b;this.f.width=c;this.f.height=d;this.f.data="Empty "+c+"x"+d+" renderbuffer"}; +r.texImage2D=function(a){arguments.length==this.df.length&&this.df.apply(this,arguments);arguments.length==this.cf.length&&this.cf.apply(this,arguments)};r.texSubImage2D=function(){};r.copyTexSubImage2D=function(){};r.df=function(a,b,c,d,e,f){a=ns(this,a);a.format=c;a.width=f.width;a.height=f.height;a.data="Empty "+f.width+"x"+f.height+"texture"};r.cf=function(a,b,c,d,e,f,g,h,k){a=ns(this,a);a.format=c;a.width=d;a.height=e;k?a.data=k:a.data="Empty "+d+"x"+e+"texture"};r.uniform1f=function(){}; +r.uniform1i=function(){};r.uniform2f=function(){};r.uniform4f=function(){};r.uniform2fv=function(){};r.uniform3fv=function(){};r.uniform4fv=function(){};r.uniformMatrix4fv=function(){};r.texParameteri=function(){};r.enable=function(a){this.B[a]=!0};r.disable=function(a){this.B[a]=!1};r.bindBuffer=function(a,b){switch(a){case 34962:this.s=b;break;case 34963:this.u=b;break;default:throw Error("Invalid bindBuffer target.");}}; +r.bufferData=function(a,b){switch(a){case 34962:this.s.arrayBuffer=b;break;case 34963:this.u.arrayBuffer=b;break;default:throw Error("Invalid bindBuffer target.");}};r.bufferSubData=function(){};r.drawArrays=function(){};r.getParameter=function(a){if(34964==a)return this.s;if(34965==a)return this.u;if(36006==a)return this.b;if(36007==a)return this.f;if(32873==a)return this.m[this.c];if(34068==a)return this.o[this.c];a=this.a[a];return a instanceof pq?[a.left,a.top,a.width,a.height]:a}; +r.vertexAttribPointer=function(){};r.blendColor=function(a,b,c,d){this.g[0]=a;this.g[1]=b;this.g[2]=c;this.g[3]=d};r.blendEquation=function(a){this.a[32777]=a;this.a[34877]=a};r.blendEquationSeparate=function(a,b){this.a[32777]=a;this.a[34877]=b};r.blendFunc=function(a,b){this.a[32969]=a;this.a[32968]=b;this.a[32971]=a;this.a[32970]=b};r.blendFuncSeparate=function(a,b,c,d){this.a[32969]=a;this.a[32968]=b;this.a[32971]=c;this.a[32970]=d};r.depthFunc=function(a){this.a[2932]=a}; +r.sampleCoverage=function(a,b){this.a[32938]=a;this.a[32939]=b};r.stencilFunc=function(a,b,c){this.a[2962]=a;this.a[2967]=b;this.a[2963]=c;this.a[34816]=a;this.a[36003]=b;this.a[36004]=c};r.stencilOp=function(a,b,c){this.a[2964]=a;this.a[2965]=b;this.a[2966]=c;this.a[34817]=a;this.a[34818]=b;this.a[34819]=c};r.clearColor=function(a,b,c,d){this.h[0]=a;this.h[1]=b;this.h[2]=c;this.h[3]=d};r.clearDepth=function(a){this.a[2931]=a};r.clearStencil=function(a){this.a[2961]=a}; +r.colorMask=function(a,b,c,d){this.i[0]=a;this.i[1]=b;this.i[2]=c;this.i[3]=d};r.depthMask=function(a){this.a[2930]=a};r.depthRange=function(a,b){this.v[0]=a;this.v[1]=b};r.cullFace=function(a){this.a[2885]=a};r.frontFace=function(a){this.a[2886]=a};r.lineWidth=function(a){this.a[2849]=a};r.polygonOffset=function(a,b){this.a[32824]=a;this.a[10752]=b};r.enableVertexAttribArray=function(a){this.D[a]=!0};r.disableVertexAttribArray=function(a){this.D[a]=!1};r.pixelStorei=function(a,b){this.a[a]=b}; +r.hint=function(a,b){this.a[a]=b};r.isContextLost=function(){return!1};r.clear=function(){};r.getAttribLocation=function(){return 0};r.bindAttribLocation=function(){};r.getSupportedExtensions=function(){return Object.keys(this.A)};r.getExtension=function(a){return this.A[a]||null};r.getShaderPrecisionFormat=function(){return{rangeMin:-64,rangeMax:64,precision:64}};r.readPixels=function(){}; +function ds(){this.depth=this.alpha=!0;this.stencil=!1;this.premultipliedAlpha=this.antialias=!0;this.failIfMajorPerformanceCaveat=this.preferLowPowerToHighPerformance=this.preserveDrawingBuffer=!1}function js(){this.format=null;this.height=this.width=0;this.data="None"}function fs(){this.b=this.c=null;this.a=this.g=!1;this.i=[];this.f=[];this.h=[]}function gs(a){this.type=a;this.source=null;this.a=this.b=!1}function ks(){this.g=this.f=this.c=this.b=null;this.a=!1} +function ms(){this.arrayBuffer=null;this.a=!1}ks.prototype.getData=function(){return this.b.data};function ls(){this.height=this.width=0;this.format=null;this.data="None";this.a=!1}function hs(){this.name="";this.type=-1}function is(){this.name="";this.index=-1}function os(a){this.a=a}function es(){x.WebGLActiveInfo=hs;x.WebGLBuffer=ms;x.WebGLTexture=js;x.WebGLRenderbuffer=ls;x.WebGLFramebuffer=ks;x.WebGLUniformLocation=is;x.WebGLContextEvent=os};function ps(){}var qs=new ps;ps.prototype.b=function(a,b){var c=Array(rs(a,b));ss(a,b,c,0);return c.join("")};var ts=/^([0-9]+)([a-zB])([\s\S]*)/,us=/(\*)/g,vs=/(!)/g,ws=/(\*2A)/gi,xs=/(\*21)/gi;function rs(a,b){var c=0,d;for(d in b.F){var e=parseInt(d,10),f=b.F[e];e=a[e+b.a];if(f&&null!=e)if(3==f.label)for(var g=0;g<e.length;++g)c+=ys(e[g],f);else c+=ys(e,f)}return c}function ys(a,b){var c=4;"m"==b.type&&(c+=rs(a,b.N));return c} +function ss(a,b,c,d){for(var e in b.F){var f=parseInt(e,10),g=b.F[f],h=a[f+b.a];if(g&&null!=h)if(3==g.label)for(var k=0;k<h.length;++k)d=zs(h[k],f,g,c,d);else d=zs(h,f,g,c,d)}return d} +function zs(a,b,c,d,e){d[e++]="!";d[e++]=""+b;if("m"==c.type)d[e++]=c.type,d[e++]="",b=e,e=ss(a,c.N,d,e),d[b-1]=""+(e-b>>2);else{c=c.type;if("b"==c)a=a?"1":"0";else if("i"==c||"j"==c||"u"==c||"v"==c||"n"==c||"o"==c){if(!pa(a)||"j"!=c&&"v"!=c&&"o"!=c)a=""+Math.floor(a)}else if("B"==c)a=pa(a)?Qd(a):xa(a)?Dc(a,!0):""+a,a=Rd(a);else if(a=""+a,"s"==c){var f=a;b=encodeURIComponent(f).replace(/%20/g,"+");var g=b.match(/%[89AB]/ig);f=f.length+(g?g.length:0);if(4*Math.ceil(f/3)-(3-f%3)%3<b.length){c=[];for(f= +b=0;f<a.length;f++)g=a.charCodeAt(f),128>g?c[b++]=g:(2048>g?c[b++]=g>>6|192:(55296==(g&64512)&&f+1<a.length&&56320==(a.charCodeAt(f+1)&64512)?(g=65536+((g&1023)<<10)+(a.charCodeAt(++f)&1023),c[b++]=g>>18|240,c[b++]=g>>12&63|128):c[b++]=g>>12|224,c[b++]=g>>6&63|128),c[b++]=g&63|128);a=Dc(c,!0);a=Rd(a);c="z"}else-1!=a.indexOf("*")&&(a=a.replace(us,"*2A")),-1!=a.indexOf("!")&&(a=a.replace(vs,"*21"))}d[e++]=c;d[e++]=a}return e}function As(a){return-1!=a.indexOf("*21")?a.replace(xs,"!"):a} +function Bs(a){var b=a.charCodeAt(0).toString(16),c=new RegExp("(\\*"+b+")","gi");b="*"+b;var d=b.toLowerCase();return function(e){return-1!=e.indexOf(b)||-1!=e.indexOf(d)?e.replace(c,a):e}}ps.prototype.a=function(a,b,c){var d=As,e="!",f=a[0];if("0">f||"9"<f)a=a.substr(1),f!=e&&(e=f,d=Bs(e));a=a.split(e);b.length=0;return Cs(0,a.length,a,d,c,b)}; +function Cs(a,b,c,d,e,f){if(a+b>c.length)return!1;var g=a;for(a+=b;g<a;++g){var h=ts.exec(c[g]);if(!h)return!1;b=parseInt(h[1],10);var k=h[2],l=h[3];l=d(l);if(-1!=l.indexOf("*2A")||-1!=l.indexOf("*2a"))l=l.replace(ws,"*");var m=0;if("m"==k&&(m=parseInt(l,10),isNaN(m)))return!1;var n=e.F[b];if(n){h=h[2];if("z"==h){h="s";l=Fc(l);k=[];for(var p=0,q=0;p<l.length;){var t=l[p++];if(128>t)k[q++]=String.fromCharCode(t);else if(191<t&&224>t){var v=l[p++];k[q++]=String.fromCharCode((t&31)<<6|v&63)}else if(239< +t&&365>t){v=l[p++];var u=l[p++],w=l[p++];t=((t&7)<<18|(v&63)<<12|(u&63)<<6|w&63)-65536;k[q++]=String.fromCharCode(55296+(t>>10));k[q++]=String.fromCharCode(56320+(t&1023))}else v=l[p++],u=l[p++],k[q++]=String.fromCharCode((t&15)<<12|(v&63)<<6|u&63)}l=k.join("")}if(n.type!=h)return!1;if("m"==n.type){n=n.N;l=[];if(!Cs(g+1,m,c,d,n,l))return!1;g+=m}a:{m=l;h=b;l=e;b=f;n=l.F[h];if("B"==n.type)m=Sd(String(m));else if("s"!=n.type&&"m"!=n.type&&!pa(n.tf)){k="f"!=n.type&&"d"!=n.type?parseInt(m,10):parseFloat(m); +if(isNaN(k)){b=!1;break a}"b"==n.type?m=0!=k:m=k}h+=l.a||0;3==n.label?Nd(b,h).push(m):b[h]=m;b=!0}if(!b)return!1}else"m"==k&&(g+=m)}return!0};function Ds(a){var b="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_."[ye(a,0,0)&63];b=b+":"+a.wa();for(var c=0;c<Fe(a,3);++c)b+=":",b+=ze(new Qn(Ee(a,3,c)),0),b+=":",b+=(new Qn(Ee(a,3,c))).na();xe(a,7)&&(b+=":tkn:",a=new Bn(a.data[7]),c=Nn(),a=te.b(a.data,c),b+=a);return b};function Es(a){this.a=a?a.slice():[];this.b=Array(this.a.length)}function Fs(a,b,c){for(var d=Array(a.a.length),e=0;e<a.a.length;++e){var f=a.a[e],g=a.b[e];g||(g=a.b[e]=Ds(f));var h=null;c&&(h=(g=c.a[g])?g.a.h(b):null);h||(h=xe(f,2)?X(f,2):null);d[e]=h}return d} +function Gs(a,b){if(a==b)return!0;if(ye(a,0,0)!=ye(b,0,0)||a.wa()!=b.wa()||xe(a,7)!=xe(b,7))return!1;var c=Fe(a,3);if(c!=Fe(b,3))return!1;for(var d=0;d<c;++d){var e=new Qn(Ee(a,3,d)),f=new Qn(Ee(b,3,d));if(ze(e,0)!=ze(f,0)||e.na()!=f.na())return!1}return xe(a,7)&&!Ge(new Bn(a.data[7]),new Bn(b.data[7]))?!1:!0}var Hs=new On;Hs.data[1]="m";Hs.data[0]=0;var Is=new Es([Hs]);function Js(a){this.a=a?a.slice():[]}function Ks(a,b){if(a.a.length!=b.a.length)return!1;for(var c=0;c<a.a.length;++c)if(!Ge(a.a[c],b.a[c]))return!1;return!0}function Ls(a){if(1==a.a.length&&(a=a.a[0],68==ye(a,0,37)))for(var b=Fe(a,1),c=0;c<b;c++){var d=new Un(Ee(a,1,c));if("set"==ze(d,0))return d.na()}return null} +function Ms(a){for(var b="",c=0;c<a.a.length;++c){0<c&&(b+=",");var d=a.a[c];b+=ye(d,0,37);for(var e=0;e<Fe(d,1);++e)b+=":",b+=ze(new Un(Ee(d,1,e)),0),b+=":",b+=(new Un(Ee(d,1,e))).na()}return b}var Ns=new Js;function Os(a,b,c,d,e,f){this.c=a||Ns;this.a=b||Is;this.h=c||"";this.g=d||"";this.f=e||null;this.b=f||null;this.i=""}function Ps(a,b){var c;if(!(c=a==b)){if(c=Ks(a.c,b.c))a:{c=a.a;var d=b.a;if(d&&c.a.length==d.a.length){for(var e=0;e<c.a.length;++e)if(!Ge(c.a[e],d.a[e])){c=!1;break a}c=!0}else c=!1}c=c&&a.h==b.h&&a.g==b.g&&a.f==b.f&&(a.b?!!b.b&&Ps(a.b,b.b):!b.b)}return c} +function Qs(a){if(!a.i){for(var b=a.a,c="",d=0;d<b.a.length;++d){0<d&&(c+=",");var e=b.b[d];e||(e=b.b[d]=Ds(b.a[d]));c+=e}a.i=c+":"+Ms(a.c)+":"+a.h+":"+a.g}return a.i}var Rs=new Os(void 0,new Es);function Ss(){this.a={};this.c=!1}function Ts(a,b){return(a=a.a[b])&&a.loaded?a.bb:null}function Us(a,b,c){var d=a.a[b];if(d)d.loaded?c(!0,d.bb):d.pd.push(c);else{var e=go("IMG");0!=b.indexOf("data:")&&(e.crossOrigin=a.c?"use-credentials":"");d=a.a[b]={bb:e,loaded:!1,pd:[c]};d.Kf=ec(e,"load",D(a.b,a,d,b,!0));d.Jf=ec(e,"error",D(a.b,a,d,b,!1));e.src=b}}function Vs(a,b){a.c=b} +Ss.prototype.b=function(a,b,c){mc(c?a.Jf:a.Kf);(a.loaded=c)||this.a[b]===a&&delete this.a[b];b=a.pd;for(var d=0;d<b.length;++d)b[d](c,a.bb);a.pd.length=0};ta(Ss);function Ws(a,b){this.a=a;this.b=b;this.c=0==a.indexOf("data:")}function Xs(a,b,c){if(!a.a)return"";var d=a.a;if(a.c)return d;null===a.b&&(a=-1!=d.indexOf("?"),d+=(a?"&scale=":"?scale=")+b);c&&(a=-1!=d.indexOf("?"),d+=(a?"&text=":"?text=")+encodeURIComponent(String(c)));return d}function Ys(a,b,c){return a.a?(a=Xs(a,b,c),Ts(Ss.sc(),a)):null} +function Zs(a,b,c,d,e){if((a=Ys(a,d,e))&&(a.width!=b||a.height!=c)){d=go("CANVAS");d.width=b;d.height=c;e=d.getContext("2d");try{return e.drawImage(a,0,0,b,c),d}catch(f){}}return a}function $s(a,b,c){var d=new pq(0,0,0,0);if(a=Ys(a,b,c))d.width=a.width,d.height=a.height;return d}function at(a,b,c){a=$s(a,b,c);a.width/=b;a.height/=b;a.left=-a.width/2;a.top=-a.height/2;return a};function bt(){this.a=this.b=null}bt.prototype.w=function(){var a=[];if(null!==this.b){var b=this.b;a[0]=b}null!==this.a&&(b=this.a,a[1]=b);return a};bt.prototype.getExtension=function(){return null};function ct(a,b){for(;G(b);)switch(b.a){case 1:var c=N(b);a.b=c;break;case 2:c=L(b);a.a=c;break;default:H(b)}}bt.prototype.wa=function(){return null==this.a?"":this.a};function dt(){this.b=this.a=null}function et(){this.a=null}dt.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;b=b.slice();for(var c=0;c<b.length;c++)b[c]=b[c].w();a[0]=b}null!==this.b&&(b=this.b,a[1]=b);return a};dt.prototype.getExtension=function(){return null};function ft(){return new dt}function gt(a){if(null===a)a=null;else{var b=new dt;if(b.a)for(var c=0;c<b.a.length;c++){var d=b.a[c];d&&ht(d)}b.a=null;b.b=null;b.a=Bd(a.a,it);b.b=a.b;a=b}return a}function jt(){} +function kt(a,b){for(;G(b);)switch(b.a){case 1:var c=new et;O(b,c,lt);a.a=a.a||[];a.a.push(c);break;case 2:c=L(b);a.b=c;break;default:H(b)}}function mt(a,b){return a===b?!0:null===a||null===b?!1:Dd(a.a,b.a,nt)&&a.b===b.b?!0:!1}et.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;b=b.w();a[2]=b}return a};function ht(a){var b=a.a;b&&(b.b=null,b.a=null);a.a=null}et.prototype.getExtension=function(){return null}; +function it(a){if(null===a)var b=null;else{b=new et;ht(b);if(a.a){var c=new bt;a=a.a;c.b=null;c.a=null;c.b=a.b;c.a=a.a}else c=null;b.a=c}return b}function lt(a,b){for(;G(b);)switch(b.a){case 3:var c=new bt;O(b,c,ct);a.a=c;break;default:H(b)}}function nt(a,b){a===b?b=!0:null===a||null===b?b=!1:(a=a.a,b=b.a,b=a===b||(null===a||null===b?0:a.b===b.b&&a.a===b.a)?!0:!1);return b};function ot(){this.c=this.h=this.b=this.i=this.g=this.a=this.f=null}function pt(){this.h=this.c=this.f=this.i=this.g=this.a=this.b=null}function qt(){this.a=this.b=null}function rt(){this.b=this.a=null}function st(){this.c=this.a=this.f=this.b=null}function tt(){this.a=null} +ot.prototype.w=function(){var a=[];if(null!==this.f){var b=this.f;a[0]=b}if(null!==this.a){b=this.a;b=b.slice();for(var c=0;c<b.length;c++)b[c]=b[c].w();a[1]=b}null!==this.g&&(b=this.g,a[2]=b);null!==this.i&&(b=this.i,a[3]=b);null!==this.b&&(b=this.b,b=b.w(),a[4]=b);null!==this.h&&(b=this.h,a[5]=b);null!==this.c&&(b=this.c,b=b.w(),a[6]=b);return a};ot.prototype.getExtension=function(){return null};function ut(){return new ot} +function vt(a){if(null===a)var b=null;else{b=new ot;b.f=null;if(b.a)for(var c=0;c<b.a.length;c++){var d=b.a[c];d&&wt(d)}b.a=null;b.g=null;b.i=null;(c=b.b)&&kf(c);b.b=null;b.h=null;(c=b.c)&&xt(c);b.c=null;b.f=a.f;b.a=Bd(a.a,yt);b.g=a.g;b.i=a.i;b.b=a.b?jf(a.b):null;b.h=a.h;a.c?(a=a.c,c=new tt,xt(c),c.a=a.a?zt(a.a):null,a=c):a=null;b.c=a}return b}function At(){} +function Bt(a,b){for(;G(b);)switch(b.a){case 1:var c=L(b);a.f=c;break;case 2:c=new pt;O(b,c,Ct);a.a=a.a||[];a.a.push(c);break;case 3:c=J(b);a.g=c;break;case 4:c=K(b);a.i=c;break;case 5:c=new hf;O(b,c,lf);a.b=c;break;case 6:c=J(b);a.h=c;break;case 7:c=new tt;O(b,c,Dt);a.c=c;break;default:H(b)}} +function Et(a,b){if(a===b)b=!0;else if(null===a||null===b)b=!1;else{var c;if(c=a.f===b.f&&Dd(a.a,b.a,Ft)&&a.g===b.g&&a.i===b.i&&mf(a.b,b.b)&&a.h===b.h)a=a.c,b=b.c,c=a===b?!0:null===a||null===b?!1:Gt(a.a,b.a)?!0:!1;b=c?!0:!1}return b}ot.prototype.wa=function(){return null==this.f?"":this.f}; +pt.prototype.w=function(){var a=[];if(null!==this.b){var b=this.b;a[0]=b}null!==this.a&&(b=this.a,b=b.slice(),a[1]=b);null!==this.g&&(b=this.g,a[2]=b);null!==this.i&&(b=this.i,a[3]=b);null!==this.f&&(b=this.f,a[4]=b);null!==this.c&&(b=this.c,b=b.w(),a[6]=b);null!==this.h&&(b=this.h,a[7]=b);return a};function wt(a){a.b=null;a.a=null;a.g=null;a.i=null;a.f=null;var b=a.c;b&&rf(b);a.c=null;a.h=null}pt.prototype.getExtension=function(){return null}; +function yt(a){if(null===a)a=null;else{var b=new pt;wt(b);b.b=a.b;b.a=Ad(a.a);b.g=a.g;b.i=a.i;b.f=a.f;if(a.c){var c=new qf;var d=a.c;rf(c);c.b=d.b?jf(d.b):null;c.a=d.a?jf(d.a):null}else c=null;b.c=c;b.h=a.h;a=b}return a}function Ct(a,b){for(;G(b);)switch(b.a){case 1:var c=L(b);a.b=c;break;case 2:c=L(b);a.a=a.a||[];a.a.push(c);break;case 3:c=L(b);a.g=c;break;case 4:c=L(b);a.i=c;break;case 5:c=b.c.da();a.f=c;break;case 7:c=new qf;O(b,c,sf);a.c=c;break;case 8:c=b.c.da();a.h=c;break;default:H(b)}} +function Ft(a,b){if(a===b)a=!0;else if(null===a||null===b)a=!1;else{var c;if(c=a.b===b.b&&Cd(a.a,b.a)&&a.g===b.g&&a.i===b.i&&a.f===b.f){c=a.c;var d=b.c;c=c===d?!0:null===c||null===d?!1:mf(c.b,d.b)&&mf(c.a,d.a)?!0:!1}a=c&&a.h===b.h?!0:!1}return a}pt.prototype.wa=function(){return null==this.b?"":this.b};qt.prototype.w=function(){var a=[];if(null!==this.b){var b=this.b;b=b.slice();a[0]=b}if(null!==this.a){b=this.a;b=b.slice();for(var c=0;c<b.length;c++)b[c]=b[c].w();a[1]=b}return a}; +qt.prototype.getExtension=function(){return null};function Ht(){return new qt}function It(a){if(null===a)a=null;else{var b=new qt;b.b=null;if(b.a)for(var c=0;c<b.a.length;c++){var d=b.a[c];d&&(d.a=null,d.b=null)}b.a=null;b.b=Ad(a.b);b.a=Bd(a.a,Jt);a=b}return a}function Kt(){}function Lt(a,b){for(;G(b);)switch(b.a){case 1:var c=L(b);a.b=a.b||[];a.b.push(c);break;case 2:c=new rt;O(b,c,Mt);a.a=a.a||[];a.a.push(c);break;default:H(b)}} +function Nt(a,b){return a===b?!0:null===a||null===b?!1:Cd(a.b,b.b)&&Dd(a.a,b.a,Ot)?!0:!1}rt.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;a[0]=b}null!==this.b&&(b=this.b,a[1]=b);return a};rt.prototype.getExtension=function(){return null};function Jt(a){if(null===a)a=null;else{var b=new rt;b.a=null;b.b=null;b.a=a.a;b.b=a.b;a=b}return a}function Mt(a,b){for(;G(b);)switch(b.a){case 1:var c=L(b);a.a=c;break;case 2:c=b.c.da();a.b=c;break;default:H(b)}} +function Ot(a,b){return a===b?!0:null===a||null===b?!1:a.a!==b.a||a.b!==b.b?!1:!0}st.prototype.w=function(){var a=[];if(null!==this.b){var b=this.b;a[0]=b}null!==this.f&&(b=this.f,a[1]=b);null!==this.a&&(b=this.a,b=b.w(),a[2]=b);null!==this.c&&(b=this.c,a[3]=b);return a};function zt(a){var b=new st;Pt(b);b.b=a.b;b.f=a.f;b.a=a.a?bj(a.a):null;b.c=a.c;return b}function Pt(a){a.b=null;a.f=null;var b=a.a;b&&cj(b);a.a=null;a.c=null}st.prototype.getExtension=function(){return null}; +function Qt(a,b){for(;G(b);)switch(b.a){case 1:var c=L(b);a.b=c;break;case 2:c=L(b);a.f=c;break;case 3:c=new $i;O(b,c,dj);a.a=c;break;case 4:c=L(b);a.c=c;break;default:H(b)}}function Gt(a,b){return a===b?!0:null===a||null===b?!1:a.b===b.b&&a.f===b.f&&ej(a.a,b.a)&&a.c===b.c?!0:!1}tt.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;b=b.w();a[0]=b}return a};function xt(a){var b=a.a;b&&Pt(b);a.a=null}tt.prototype.getExtension=function(){return null}; +function Dt(a,b){for(;G(b);)switch(b.a){case 1:var c=new st;O(b,c,Qt);a.a=c;break;default:H(b)}};function Rt(){this.f=this.h=this.a=this.b=this.i=this.c=this.g=null}function St(){this.i=this.c=this.g=this.f=this.h=this.a=this.b=null}function Tt(){this.f=this.b=this.c=this.a=null}function Ut(){this.j=this.b=this.h=this.f=this.c=this.i=this.a=this.g=null}function Vt(){this.g=this.f=this.b=this.c=this.a=null} +function Wt(){this.g=this.f=this.G=this.H=this.K=this.A=this.B=this.J=this.s=this.l=this.O=this.C=this.D=this.M=this.v=this.m=this.I=this.j=this.a=this.L=this.u=this.c=this.h=this.o=this.i=this.b=null}function Xt(){this.I=this.f=this.G=this.H=this.A=this.B=this.C=this.g=this.o=this.h=this.m=this.u=this.s=this.i=this.v=this.D=this.l=this.c=this.b=this.a=this.j=null} +Rt.prototype.w=function(){var a=[];null!=this.c&&null==this.g&&(this.g=Gd(this.f,this.c,this.i));if(null!==this.g){var b=this.g;b=Dc(b);a[0]=b}null!=this.a&&null==this.b&&(this.b=Gd(this.f,this.a,this.h));null!==this.b&&(b=this.b,b=Dc(b),a[1]=b);return a};function Yt(a){a.g=null;a.c=null;a.i=null;a.b=null;a.a=null;a.h=null}Rt.prototype.getExtension=function(){return null};function Zt(a){a&&Yt(a)} +function $t(a,b){for(a.f=jd(b);G(b);)switch(b.a){case 1:null===a.c&&(a.c=b.b);kd(b);a.i=id(b);break;case 2:null===a.a&&(a.a=b.b);kd(b);a.h=id(b);break;case 1E3:H(b);break;case 1001:H(b);break;default:H(b)}}function au(a){return null!==a.g?Zc(a.g):a.f&&null!=a.c&&null!=a.i?(a=Zc(a.f,a.c,a.i-a.c),a.ca(),a.ca(),a):Zc()} +St.prototype.w=function(){var a=[];null!=this.a&&null==this.b&&(this.b=Gd(this.i,this.a,this.h));if(null!==this.b){var b=this.b;b=Dc(b);a[0]=b}null!==this.f&&(b=this.f,a[1]=b);null!==this.g&&(b=this.g,a[2]=b);null!==this.c&&(b=this.c,a[3]=b);return a};function bu(a){a.b=null;a.a=null;a.h=null;a.f=null;a.g=null;a.c=null}St.prototype.getExtension=function(){return null};function cu(a){a&&bu(a)} +function du(a,b){for(a.i=jd(b);G(b);)switch(b.a){case 1:null===a.a&&(a.a=b.b);kd(b);a.h=id(b);break;case 2:var c=J(b);a.f=c;break;case 3:c=J(b);a.g=c;break;case 4:c=J(b);a.c=c;break;case 1E3:H(b);break;default:H(b)}}Tt.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;b=b.w();a[0]=b}null!==this.c&&(b=this.c,a[1]=b);null!==this.b&&(b=this.b,a[3]=b);null!==this.f&&(b=this.f,b=b.w(),a[4]=b);return a};Tt.prototype.getExtension=function(){return null}; +function eu(a,b){for(;G(b);)switch(b.a){case 1:var c=new Rt;O(b,c,$t);a.a=c;break;case 2:c=N(b);a.c=c;break;case 4:c=J(b);a.b=c;break;case 5:c=new St;O(b,c,du);a.f=c;break;default:H(b)}}function fu(a){null===a.a&&(a.a=new Rt);return a.a}function gu(a){return null!=a.b?!0:!1} +Ut.prototype.w=function(){var a=[];null!=this.a&&null==this.g&&(this.g=Gd(this.j,this.a,this.i));if(null!==this.g){var b=this.g;b=Dc(b);a[0]=b}null!==this.c&&(b=this.c,a[1]=b);null!==this.f&&(b=this.f,a[2]=b);null!==this.h&&(b=this.h,a[3]=b);null!==this.b&&(b=this.b,a[4]=b);return a};Ut.prototype.getExtension=function(){return null}; +function hu(a,b){for(a.j=jd(b);G(b);)switch(b.a){case 1:null===a.a&&(a.a=b.b);kd(b);a.i=id(b);break;case 2:var c=J(b);a.c=c;break;case 3:c=J(b);a.f=c;break;case 4:c=N(b);a.h=c;break;case 5:c=J(b);a.b=c;break;case 1E3:H(b);break;default:H(b)}} +Vt.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;b=b.slice();for(var c=0;c<b.length;c++)b[c]=b[c].w();a[0]=b}null!==this.c&&(b=this.c,a[1]=b);null!==this.b&&(b=this.b,b=Oc(b,!0),a[2]=b);null!==this.f&&(b=this.f,a[3]=b);null!==this.g&&(b=this.g,a[999]=b);return a}; +function iu(a){if(a.a)for(var b=0;b<a.a.length;b++){var c=a.a[b];if(c){c.b=null;c.i=null;c.o=null;c.h=null;c.c=null;c.u=null;c.L=null;c.a=null;c.j=null;c.I=null;c.m=null;c.v=null;c.M=null;c.D=null;c.C=null;c.O=null;c.l=null;c.s=null;c.J=null;c.B=null;c.A=null;c.K=null;c.H=null;c.G=null;if(c.f)for(var d=0;d<c.f.length;d++)wd(c.f[d]);c.f=null}}a.a=null;a.c=null;a.b=null;a.f=null;a.g=null}Vt.prototype.getExtension=function(){return null}; +function ju(a,b){for(;G(b);)switch(b.a){case 1:var c=new Wt;O(b,c,ku);a.a=a.a||[];a.a.push(c);break;case 2:c=J(b);a.c=c;break;case 3:c=qd(b);a.b=c;break;case 4:c=N(b);a.f=c;break;case 1E3:c=J(b);a.g=c;break;default:H(b)}}function lu(a){return null==a.b?"\u00ffffffff\u00ffffff\u00ffff\u00ff\u00ffffffff\u00ffffff\u00ffff\u00ff":a.b}function mu(a){return null==a.f?1:a.f} +Wt.prototype.w=function(){var a=[];if(null!==this.b){var b=this.b;a[0]=b}null!==this.i&&(b=this.i,a[1]=b);null!==this.o&&(b=this.o,a[2]=b);null!==this.h&&(b=this.h,b=Oc(b,!0),a[3]=b);nu(this);null!==this.c&&(b=this.c,b=b.slice(),a[5]=b);ou(this);null!==this.a&&(b=this.a,b=b.slice(),a[6]=b);pu(this);null!==this.m&&(b=this.m,b=b.slice(),a[7]=b);null!=this.C&&null==this.D&&(this.D=Fd(Wc.prototype.da,this.g,this.C,this.O));null!==this.D&&(b=this.D,b=b.slice(),a[8]=b);qu(this);null!==this.l&&(b=this.l, +b=b.slice(),a[9]=b);null!=this.A&&null==this.B&&(this.B=Fd(Wc.prototype.da,this.g,this.A,this.K));null!==this.B&&(b=this.B,b=b.slice(),a[10]=b);null!==this.H&&(b=this.H,a[999]=b);null!==this.G&&(b=this.G,a[1E3]=b);return a};var ru=[];Wt.prototype.getExtension=function(a){var b=!1;25E6<=a&&536870912>a&&(b=!0);return b?Id(this.f,a):null}; +function ku(a,b){for(a.g=jd(b);G(b);)switch(b.a){case 1:var c=L(b);a.b=c;break;case 2:c=J(b);a.i=c;break;case 3:c=K(b);a.o=c;break;case 4:c=qd(b);a.h=c;break;case 6:null===a.u&&(a.u=b.b);kd(b);a.L=id(b);break;case 7:null===a.j&&(a.j=b.b);kd(b);a.I=id(b);break;case 8:null===a.v&&(a.v=b.b);kd(b);a.M=id(b);break;case 9:null===a.C&&(a.C=b.b);kd(b);a.O=id(b);break;case 10:null===a.s&&(a.s=b.b);kd(b);a.J=id(b);break;case 11:null===a.A&&(a.A=b.b);kd(b);a.K=id(b);break;case 1E3:c=J(b);a.H=c;break;case 1001:c= +L(b);a.G=c;break;default:a.f=a.f||[],c=Jd(b,ru),a.f.push(c)}}function su(a){return null==a.b?"":a.b}function tu(a){return null!=a.c||null!=a.u?!0:!1}function uu(a){nu(a);return a.c?a.c.length:0}function vu(a,b){nu(a);return a.c[b]}function nu(a){null!=a.u&&null==a.c&&(a.c=Fd(Wc.prototype.Ma,a.g,a.u,a.L))}function ou(a){null!=a.j&&null==a.a&&(a.a=Fd(Wc.prototype.Ma,a.g,a.j,a.I))}function wu(a){return null!=a.m||null!=a.v?!0:!1}function xu(a,b){pu(a);return a.m[b]} +function pu(a){null!=a.v&&null==a.m&&(a.m=Fd(Wc.prototype.da,a.g,a.v,a.M))}function qu(a){null!=a.s&&null==a.l&&(a.l=Fd(Wc.prototype.da,a.g,a.s,a.J))} +Xt.prototype.w=function(){var a=[];if(null!==this.j){var b=this.j;b=b.w();a[0]=b}null!==this.a&&(b=this.a,b=b.w(),a[1]=b);null!==this.b&&(b=this.b,b=b.w(),a[2]=b);null!==this.c&&(b=this.c,b=b.w(),a[3]=b);null!==this.l&&(b=this.l,b=Oc(b,!0),a[4]=b);null!==this.D&&(b=this.D,a[5]=b);null!==this.v&&(b=this.v,a[6]=b);null!==this.i&&(b=this.i,a[7]=b);null!==this.s&&(b=this.s,a[8]=b);null!==this.u&&(b=this.u,a[9]=b);null!==this.m&&(b=this.m,a[10]=b);null!==this.h&&(b=this.h,a[11]=b);null!==this.o&&(b=this.o, +a[12]=b);null!==this.g&&(b=this.g,a[13]=b);null!==this.C&&(b=this.C,b=Oc(b,!1),a[14]=b);null!=this.A&&null==this.B&&(this.B=Fd(Wc.prototype.Ma,this.I,this.A,this.H));null!==this.B&&(b=this.B,b=b.slice(),a[15]=b);null!==this.G&&(b=this.G,a[999]=b);return a};var yu=[];Xt.prototype.getExtension=function(a){var b=!1;25E6<=a&&536870912>a&&(b=!0);return b?Id(this.f,a):null};function zu(a){a.f=a.f||[];return a.f} +function Au(a){if(a){var b=a.j;b&&iu(b);a.j=null;(b=a.a)&&iu(b);a.a=null;if(b=a.b)Zt(b.a),b.a=null,b.c=null,b.b=null,cu(b.f),b.f=null;a.b=null;if(b=a.c)b.g=null,b.a=null,b.i=null,b.c=null,b.f=null,b.h=null,b.b=null;a.c=null;a.l=null;a.D=null;a.v=null;a.i=null;a.s=null;a.u=null;a.m=null;a.h=null;a.o=null;a.g=null;a.C=null;a.B=null;a.A=null;a.H=null;a.G=null;if(a.f)for(b=0;b<a.f.length;b++)wd(a.f[b]);a.f=null}} +function Bu(a,b){for(a.I=jd(b);G(b);)switch(b.a){case 1:var c=new Vt;O(b,c,ju);a.j=c;break;case 2:c=new Vt;O(b,c,ju);a.a=c;break;case 3:c=new Tt;O(b,c,eu);a.b=c;break;case 4:c=new Ut;O(b,c,hu);a.c=c;break;case 5:c=qd(b);a.l=c;break;case 6:c=M(b);a.D=c;break;case 7:c=N(b);a.v=c;break;case 8:c=J(b);a.i=c;break;case 9:c=J(b);a.s=c;break;case 10:c=nd(b);a.u=c;break;case 11:c=J(b);a.m=c;break;case 12:c=J(b);a.h=c;break;case 13:c=J(b);a.o=c;break;case 14:c=J(b);a.g=c;break;case 15:c=pd(b);a.C=c;break;case 16:null=== +a.A&&(a.A=b.b);kd(b);a.H=id(b);break;case 1E3:c=J(b);a.G=c;break;default:a.f=a.f||[],c=Jd(b,yu),a.f.push(c)}}function Cu(a){null===a.j&&(a.j=new Vt);return a.j}function Du(a){null===a.a&&(a.a=new Vt);return a.a}function Eu(a){null===a.b&&(a.b=new Tt);return a.b}function Fu(a){null===a.c&&(a.c=new Ut);return a.c}function Gu(a){return null==a.l?"\u00ffffffff\u00ffffff\u00ffff\u00ff\u00ffffffff\u00ffffff\u00ffff\u00ff":a.l};function Hu(){this.l=this.i=this.b=this.c=this.h=this.j=this.g=this.a=this.f=null}function Iu(){this.g=this.f=this.c=this.a=this.b=null}function Ju(){this.a=this.b=null}function Ku(){this.h=this.f=this.g=this.j=this.c=this.b=this.a=this.i=null}function Lu(){this.f=this.g=this.c=this.a=this.b=null} +function Mu(){this.a=this.T=this.j=this.c=this.s=this.o=this.Y=this.K=this.u=this.O=this.B=this.g=this.W=this.J=this.m=this.U=this.G=this.l=this.Z=this.L=this.v=this.V=this.H=this.I=this.S=this.D=this.i=this.P=this.C=this.h=this.M=this.A=this.f=this.b=null}function Nu(){this.f=this.g=this.i=this.c=this.b=this.a=this.h=null}function Ou(){this.i=this.j=this.l=this.b=this.c=this.h=this.g=this.f=this.a=null} +function Pu(){this.B=this.l=this.u=this.s=this.v=this.i=this.A=this.j=this.g=this.h=this.m=this.a=this.c=this.b=this.o=this.f=null}function Qu(){this.c=this.f=this.g=this.b=this.i=this.j=this.h=this.a=null}function Ru(){this.f=this.c=this.g=this.h=this.a=this.b=null}function Su(){this.I=this.s=this.C=this.D=this.G=this.A=this.B=this.j=this.v=this.u=this.H=this.g=this.b=this.i=this.h=this.a=this.f=this.c=this.l=this.o=this.m=null} +function Tu(){this.v=this.o=this.a=this.b=this.s=this.h=this.m=this.u=this.j=this.l=this.f=this.c=this.i=this.g=null}function Uu(){this.B=this.m=this.u=this.o=this.s=this.b=this.v=this.f=this.A=this.i=this.c=this.g=this.h=this.l=this.j=this.a=null}function Vu(){this.b=this.a=null}function Wu(){this.b=this.a=null}function Xu(){this.b=this.c=this.a=null}function Yu(){this.c=this.f=this.b=this.g=this.a=null}function Zu(){this.h=this.g=this.c=this.f=this.a=this.b=null} +Hu.prototype.w=function(){var a=[];if(null!==this.f){var b=this.f;b=Oc(b,!1);a[0]=b}$u(this);if(null!==this.a){b=this.a;b=b.slice();for(var c=0;c<b.length;c++)b[c]=b[c].w();a[1]=b}null!==this.h&&(b=this.h,a[2]=b);null!==this.c&&(b=this.c,a[3]=b);if(null!==this.b){b=this.b;b=b.slice();for(c=0;c<b.length;c++)b[c]=b[c].w();a[4]=b}null!==this.i&&(b=this.i,a[999]=b);return a};Hu.prototype.getExtension=function(){return null}; +function av(a,b){for(a.l=jd(b);G(b);)switch(b.a){case 1:var c=pd(b);a.f=c;break;case 2:null===a.g&&(a.g=b.b);kd(b);a.j=id(b);break;case 3:c=L(b);a.h=c;break;case 4:c=K(b);a.c=c;break;case 5:c=new Iu;O(b,c,bv);a.b=a.b||[];a.b.push(c);break;case 1E3:c=J(b);a.i=c;break;default:H(b)}}Hu.prototype.wa=function(){return null==this.f?"\x00\x00\x00\x00\x00\x00\x00\x00":this.f};function $u(a){null!=a.g&&null==a.a&&(a.a=Hd(cv,dv,a.l,a.g,a.j))} +Iu.prototype.w=function(){var a=[];if(null!==this.b){var b=this.b;b=b.slice();a[0]=b}null!=this.c&&null==this.a&&(this.a=Hd(cv,dv,this.g,this.c,this.f));if(null!==this.a){b=this.a;b=b.slice();for(var c=0;c<b.length;c++)b[c]=b[c].w();a[1]=b}return a};Iu.prototype.getExtension=function(){return null};function ev(a){if(a){a.b=null;if(a.a)for(var b=0;b<a.a.length;b++)fv(a.a[b]);a.a=null;a.c=null;a.f=null}} +function bv(a,b){for(a.g=jd(b);G(b);)switch(b.a){case 1:var c=N(b);a.b=a.b||[];a.b.push(c);break;case 2:null===a.c&&(a.c=b.b);kd(b);a.f=id(b);break;default:H(b)}}Ju.prototype.w=function(){var a=[];if(null!==this.b){var b=this.b;a[0]=b}null!==this.a&&(b=this.a,a[1]=b);return a};Ju.prototype.getExtension=function(){return null};function gv(){return new Ju}function hv(a,b){for(;G(b);)switch(b.a){case 1:var c=J(b);a.b=c;break;case 2:c=J(b);a.a=c;break;default:H(b)}} +Ku.prototype.w=function(){var a=[];if(null!==this.i){var b=this.i;a[0]=b}null!==this.a&&(b=this.a,b=b.w(),a[1]=b);null!==this.b&&(b=this.b,b=b.w(),a[2]=b);null!==this.c&&(b=this.c,b=b.w(),a[3]=b);null!==this.j&&(b=this.j,b=b.w(),a[4]=b);null!==this.g&&(b=this.g,b=b.w(),a[5]=b);null!==this.f&&(b=this.f,b=b.w(),a[7]=b);return a};var iv=[];Ku.prototype.getExtension=function(a){var b=!1;1E3<=a&&536870912>a&&(b=!0);return b?Id(this.h,a):null}; +function fv(a){if(a){a.i=null;var b=a.a;b&&jv(b);a.a=null;(b=a.b)&&kv(b);a.b=null;(b=a.c)&&lv(b);a.c=null;if(b=a.j){var c=b.a;c&&(c.a=null,c.b=null);b.a=null;b.c=null;b.b=null}a.j=null;(b=a.g)&&mv(b);a.g=null;(b=a.f)&&nv(b);a.f=null;if(a.h)for(b=0;b<a.h.length;b++)wd(a.h[b]);a.h=null}}function cv(){return new Ku} +function dv(a,b){for(;G(b);)switch(b.a){case 1:var c=J(b);a.i=c;break;case 2:c=new Ou;O(b,c,ov);a.a=c;break;case 3:c=new Pu;O(b,c,pv);a.b=c;break;case 4:c=new Uu;O(b,c,qv);a.c=c;break;case 5:c=new Xu;O(b,c,rv);a.j=c;break;case 6:c=new Yu;O(b,c,sv);a.g=c;break;case 8:c=new Zu;O(b,c,tv);a.f=c;break;default:a.h=a.h||[],c=Jd(b,iv),a.h.push(c)}}Ku.prototype.getZoom=function(){return null==this.i?0:this.i}; +Lu.prototype.w=function(){var a=[];if(null!==this.b){var b=this.b;b=Oc(b,!0);a[0]=b}uv(this);if(null!==this.a){b=this.a;b=b.slice();for(var c=0;c<b.length;c++)b[c]=b[c].w();a[1]=b}return a};Lu.prototype.getExtension=function(){return null};function vv(a,b){for(a.f=jd(b);G(b);)switch(b.a){case 1:a.b=qd(b);break;case 2:null===a.c&&(a.c=b.b);kd(b);a.g=id(b);break;default:H(b)}}Lu.prototype.wa=function(){return null==this.b?"\x00\x00\x00\x00\x00\x00\x00\x00":this.b}; +function uv(a){null!=a.c&&null==a.a&&(a.a=Hd(wv,xv,a.f,a.c,a.g))} +function yv(a,b){for(a.a=jd(b);G(b);)switch(b.a){case 1:var c=new Lu;O(b,c,vv);a.b=a.b||[];a.b.push(c);break;case 2:null===a.A&&(a.A=b.b);kd(b);a.M=id(b);break;case 3:null===a.C&&(a.C=b.b);kd(b);a.P=id(b);break;case 4:null===a.D&&(a.D=b.b);kd(b);a.S=id(b);break;case 5:null===a.H&&(a.H=b.b);kd(b);a.V=id(b);break;case 6:null===a.L&&(a.L=b.b);kd(b);a.Z=id(b);break;case 7:null===a.G&&(a.G=b.b);kd(b);a.U=id(b);break;case 8:null===a.J&&(a.J=b.b);kd(b);a.W=id(b);break;case 9:null===a.B&&(a.B=b.b);kd(b); +a.O=id(b);break;case 10:null===a.K&&(a.K=b.b);kd(b);a.Y=id(b);break;case 11:c=L(b);a.o=c;break;case 12:c=L(b);a.s=c;break;case 13:null===a.j&&(a.j=b.b);kd(b);a.T=id(b);break;default:H(b)}} +Mu.prototype.w=function(){var a=[];if(null!==this.b){var b=this.b;b=b.slice();for(var c=0;c<b.length;c++)b[c]=b[c].w();a[0]=b}zv(this);if(null!==this.f){b=this.f;b=b.slice();for(c=0;c<b.length;c++)b[c]=b[c].w();a[1]=b}Av(this);if(null!==this.h){b=this.h;b=b.slice();for(c=0;c<b.length;c++)b[c]=b[c].w();a[2]=b}Bv(this);if(null!==this.i){b=this.i;b=b.slice();for(c=0;c<b.length;c++)b[c]=b[c].w();a[3]=b}Cv(this);if(null!==this.I){b=this.I;b=b.slice();for(c=0;c<b.length;c++)b[c]=b[c].w();a[4]=b}Dv(this); +if(null!==this.v){b=this.v;b=b.slice();for(c=0;c<b.length;c++)b[c]=b[c].w();a[5]=b}Ev(this);if(null!==this.l){b=this.l;b=b.slice();for(c=0;c<b.length;c++)b[c]=b[c].w();a[6]=b}Fv(this);if(null!==this.m){b=this.m;b=b.slice();for(c=0;c<b.length;c++)b[c]=b[c].w();a[7]=b}Gv(this);if(null!==this.g){b=this.g;b=b.slice();for(c=0;c<b.length;c++)b[c]=b[c].w();a[8]=b}Hv(this);null!==this.u&&(b=this.u,b=b.slice(),a[9]=b);null!==this.o&&(b=this.o,a[10]=b);null!==this.s&&(b=this.s,a[11]=b);Iv(this);if(null!==this.c){b= +this.c;b=b.slice();for(c=0;c<b.length;c++)b[c]=b[c].w();a[12]=b}return a};Mu.prototype.getExtension=function(){return null};function zv(a){null!=a.A&&null==a.f&&(a.f=Hd(Jv,ov,a.a,a.A,a.M))}function Av(a){null!=a.C&&null==a.h&&(a.h=Hd(Kv,pv,a.a,a.C,a.P))}function Bv(a){null!=a.D&&null==a.i&&(a.i=Hd(Lv,qv,a.a,a.D,a.S))}function Cv(a){null!=a.H&&null==a.I&&(a.I=Hd(Mv,rv,a.a,a.H,a.V))}function Dv(a){null!=a.L&&null==a.v&&(a.v=Hd(Nv,sv,a.a,a.L,a.Z))} +function Ev(a){null!=a.G&&null==a.l&&(a.l=Hd(Ov,tv,a.a,a.G,a.U))}function Pv(a,b){Fv(a);return a.m[b]}function Fv(a){null!=a.J&&null==a.m&&(a.m=Hd(Qv,Rv,a.a,a.J,a.W))}function Sv(a,b){Gv(a);return a.g[b]}function Gv(a){null!=a.B&&null==a.g&&(a.g=Hd(Tv,Uv,a.a,a.B,a.O))}function Hv(a){if(null!=a.K&&null==a.u){var b=a.a,c=a.K,d=a.Y;var e=Wc.prototype.Lf;if(b&&null!=c&&null!=d){b=Zc(b,c,d-c);for(c=[];!b.kb();)b.ca(),c.push(e.call(b));Vc(b);e=c}else e=null;a.u=e}} +function Iv(a){null!=a.j&&null==a.c&&(a.c=Hd(gv,hv,a.a,a.j,a.T))}Nu.prototype.w=function(){var a=[];if(null!==this.h){var b=this.h;a[0]=b}null!==this.a&&(b=this.a,a[1]=b);null!==this.b&&(b=this.b,a[2]=b);null!==this.c&&(b=this.c,a[3]=b);null!==this.i&&(b=this.i,a[4]=b);null!==this.g&&(b=this.g,a[5]=b);null!==this.f&&(b=this.f,a[6]=b);return a};Nu.prototype.getExtension=function(){return null};function wv(){return new Nu} +function xv(a,b){for(;G(b);)switch(b.a){case 1:var c=J(b);a.h=c;break;case 2:c=J(b);a.a=c;break;case 3:c=J(b);a.b=c;break;case 4:c=J(b);a.c=c;break;case 5:c=J(b);a.i=c;break;case 6:c=J(b);a.g=c;break;case 7:c=J(b);a.f=c;break;default:H(b)}}Nu.prototype.getZoom=function(){return null==this.h?0:this.h}; +Ou.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;b=b.slice();for(var c=0;c<b.length;c++)b[c]=b[c].w();a[0]=b}null!==this.f&&(b=this.f,a[1]=b);null!==this.g&&(b=this.g,a[2]=b);null!==this.h&&(b=this.h,a[3]=b);null!==this.c&&(b=this.c,a[4]=b);null!==this.b&&(b=this.b,b=b.slice(),a[5]=b);null!==this.l&&(b=this.l,a[6]=b);null!==this.j&&(b=this.j,a[7]=b);null!==this.i&&(b=this.i,a[8]=b);return a}; +function jv(a){if(a.a)for(var b=0;b<a.a.length;b++){var c=a.a[b];c&&Vv(c)}a.a=null;a.f=null;a.g=null;a.h=null;a.c=null;a.b=null;a.l=null;a.j=null;a.i=null}Ou.prototype.getExtension=function(){return null};function Jv(){return new Ou} +function ov(a,b){for(;G(b);)switch(b.a){case 1:var c=new Tu;O(b,c,Rv);a.a=a.a||[];a.a.push(c);break;case 2:c=nd(b);a.f=c;break;case 3:c=J(b);a.g=c;break;case 4:c=K(b);a.h=c;break;case 5:c=K(b);a.c=c;break;case 6:c=J(b);a.b=a.b||[];a.b.push(c);break;case 7:c=L(b);a.l=c;break;case 8:c=J(b);a.j=c;break;case 9:c=J(b);a.i=c;break;default:H(b)}} +Pu.prototype.w=function(){var a=[];if(null!==this.f){var b=this.f;a[0]=b}null!==this.o&&(b=this.o,a[1]=b);if(null!==this.b){b=this.b;b=b.slice();for(var c=0;c<b.length;c++)b[c]=b[c].w();a[2]=b}null!==this.c&&(b=this.c,b=b.w(),a[3]=b);null!==this.a&&(b=this.a,b=b.w(),a[4]=b);null!==this.m&&(b=this.m,a[5]=b);null!==this.h&&(b=this.h,a[6]=b);Wv(this);null!==this.g&&(b=this.g,b=b.slice(),a[7]=b);null!==this.i&&(b=this.i,a[8]=b);null!==this.v&&(b=this.v,a[9]=b);null!==this.s&&(b=this.s,a[10]=b);null!== +this.u&&(b=this.u,a[11]=b);null!==this.l&&(b=this.l,a[12]=b);return a}; +function Xv(a,b){kv(a);a.f=b.f;a.o=b.o;a.b=Bd(b.b,Yv);if(b.c){var c=b.c;var d=new Ru;Zv(d);d.b=c.b;d.a=c.a;d.h=c.h;d.g=c.g;d.c=c.c;d.f=c.f;c=d}else c=null;a.c=c;b.a?(c=b.a,d=new Su,$v(d),d.m=c.m,d.o=c.o,d.l=c.l,d.c=c.c,d.f=c.f,d.a=Bd(c.a,Yv),d.h=c.h,d.i=c.i,d.b=Ad(c.b),d.g=c.g,d.H=c.H,d.u=c.u,d.v=c.v,d.j=Ad(c.j),d.B=c.B,d.A=c.A,d.G=c.G,d.D=c.D,d.C=c.C,d.s=c.s,d.I=c.I,c=d):c=null;a.a=c;a.m=b.m;a.h=b.h;a.g=Ad(b.g);a.j=b.j;a.A=b.A;a.i=b.i;a.v=b.v;a.s=b.s;a.u=b.u;a.l=b.l;a.B=b.B} +function kv(a){a.f=null;a.o=null;if(a.b)for(var b=0;b<a.b.length;b++){var c=a.b[b];c&&aw(c)}a.b=null;(b=a.c)&&Zv(b);a.c=null;(b=a.a)&&$v(b);a.a=null;a.m=null;a.h=null;a.g=null;a.j=null;a.A=null;a.i=null;a.v=null;a.s=null;a.u=null;a.l=null}Pu.prototype.getExtension=function(){return null};function Kv(){return new Pu} +function pv(a,b){for(a.B=jd(b);G(b);)switch(b.a){case 1:var c=nd(b);a.f=c;break;case 2:c=nd(b);a.o=c;break;case 3:c=new Qu;O(b,c,Uv);a.b=a.b||[];a.b.push(c);break;case 4:c=new Ru;O(b,c,bw);a.c=c;break;case 5:c=new Su;O(b,c,cw);a.a=c;break;case 6:c=J(b);a.m=c;break;case 7:c=K(b);a.h=c;break;case 8:null===a.j&&(a.j=b.b);kd(b);a.A=id(b);break;case 9:c=N(b);a.i=c;break;case 10:c=N(b);a.v=c;break;case 11:c=b.c.da();a.s=c;break;case 12:c=b.c.da();a.u=c;break;case 13:c=b.c.da();a.l=c;break;default:H(b)}} +function dw(a){null===a.c&&(a.c=new Ru);return a.c}function ew(a){null===a.a&&(a.a=new Su);return a.a}function Wv(a){null!=a.j&&null==a.g&&(a.g=Fd(Wc.prototype.Ma,a.B,a.j,a.A))}Qu.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;a[0]=b}null!==this.h&&(b=this.h,a[1]=b);null!==this.j&&(b=this.j,a[2]=b);null!==this.i&&(b=this.i,a[3]=b);null!==this.b&&(b=this.b,a[4]=b);null!==this.g&&(b=this.g,a[5]=b);null!==this.f&&(b=this.f,a[6]=b);return a}; +function aw(a){a.a=null;a.h=null;a.j=null;a.i=null;a.b=null;a.g=null;a.f=null;if(a.c)for(var b=0;b<a.c.length;b++)wd(a.c[b]);a.c=null}var fw=[];Qu.prototype.getExtension=function(a){var b=!1;1E6<=a&&536870912>a&&(b=!0);return b?Id(this.c,a):null};function Tv(){return new Qu}function Yv(a){if(null===a)a=null;else{var b=new Qu;aw(b);b.a=a.a;b.h=a.h;b.j=a.j;b.i=a.i;b.b=a.b;b.g=a.g;b.f=a.f;b.c=xd(a.c);a=b}return a} +function Uv(a,b){for(;G(b);)switch(b.a){case 1:var c=L(b);a.a=c;break;case 2:c=J(b);a.h=c;break;case 3:c=J(b);a.j=c;break;case 4:c=J(b);a.i=c;break;case 5:c=J(b);a.b=c;break;case 6:c=nd(b);a.g=c;break;case 7:c=nd(b);a.f=c;break;default:a.c=a.c||[],c=Jd(b,fw),a.c.push(c)}} +Ru.prototype.w=function(){var a=[];if(null!==this.b){var b=this.b;a[0]=b}null!==this.a&&(b=this.a,a[1]=b);null!==this.h&&(b=this.h,a[2]=b);null!==this.g&&(b=this.g,a[3]=b);null!==this.c&&(b=this.c,a[4]=b);null!==this.f&&(b=this.f,a[5]=b);return a};function Zv(a){a.b=null;a.a=null;a.h=null;a.g=null;a.c=null;a.f=null}Ru.prototype.getExtension=function(){return null}; +function bw(a,b){for(;G(b);)switch(b.a){case 1:var c=J(b);a.b=c;break;case 2:c=J(b);a.a=c;break;case 3:c=J(b);a.h=c;break;case 4:c=J(b);a.g=c;break;case 5:c=L(b);a.c=c;break;case 6:c=J(b);a.f=c;break;default:H(b)}} +Su.prototype.w=function(){var a=[];if(null!==this.m){var b=this.m;a[0]=b}null!==this.o&&(b=this.o,a[1]=b);null!==this.l&&(b=this.l,a[2]=b);null!==this.c&&(b=this.c,a[3]=b);null!==this.f&&(b=this.f,a[4]=b);if(null!==this.a){b=this.a;b=b.slice();for(var c=0;c<b.length;c++)b[c]=b[c].w();a[5]=b}null!==this.h&&(b=this.h,a[6]=b);null!==this.i&&(b=this.i,a[7]=b);gw(this);null!==this.b&&(b=this.b,b=b.slice(),a[8]=b);null!==this.u&&(b=this.u,a[9]=b);null!==this.v&&(b=this.v,a[10]=b);null!==this.j&&(b=this.j, +b=b.slice(),a[11]=b);null!==this.B&&(b=this.B,a[12]=b);null!==this.A&&(b=this.A,a[13]=b);null!==this.G&&(b=this.G,a[14]=b);null!==this.D&&(b=this.D,a[15]=b);null!==this.C&&(b=this.C,a[16]=b);null!==this.s&&(b=this.s,a[17]=b);return a};function $v(a){a.m=null;a.o=null;a.l=null;a.c=null;a.f=null;if(a.a)for(var b=0;b<a.a.length;b++){var c=a.a[b];c&&aw(c)}a.a=null;a.h=null;a.i=null;a.b=null;a.g=null;a.H=null;a.u=null;a.v=null;a.j=null;a.B=null;a.A=null;a.G=null;a.D=null;a.C=null;a.s=null} +Su.prototype.getExtension=function(){return null}; +function cw(a,b){for(a.I=jd(b);G(b);)switch(b.a){case 1:var c=nd(b);a.m=c;break;case 2:c=J(b);a.o=c;break;case 3:c=nd(b);a.l=c;break;case 4:c=J(b);a.c=c;break;case 5:c=J(b);a.f=c;break;case 6:c=new Qu;O(b,c,Uv);a.a=a.a||[];a.a.push(c);break;case 7:c=md(b);a.h=c;break;case 8:c=md(b);a.i=c;break;case 9:null===a.g&&(a.g=b.b);kd(b);a.H=id(b);break;case 10:c=J(b);a.u=c;break;case 11:c=J(b);a.v=c;break;case 12:c=N(b);a.j=a.j||[];a.j.push(c);break;case 13:c=J(b);a.B=c;break;case 14:c=J(b);a.A=c;break;case 15:c= +N(b);a.G=c;break;case 16:c=J(b);a.D=c;break;case 17:c=nd(b);a.C=c;break;case 18:c=K(b);a.s=c;break;default:H(b)}}function gw(a){null!=a.g&&null==a.b&&(a.b=Fd(Wc.prototype.Ma,a.I,a.g,a.H))} +Tu.prototype.w=function(){var a=[];if(null!==this.g){var b=this.g;a[0]=b}null!==this.i&&(b=this.i,a[1]=b);null!==this.c&&(b=this.c,b=b.slice(),a[2]=b);null!==this.f&&(b=this.f,a[3]=b);null!=this.j&&null==this.l&&(this.l=Fd(Wc.prototype.Eb,this.v,this.j,this.u));null!==this.l&&(b=this.l,b=b.slice(),a[4]=b);null!==this.m&&(b=this.m,a[5]=b);null!==this.h&&(b=this.h,a[7]=b);null!==this.s&&(b=this.s,a[8]=b);null!==this.b&&(b=this.b,b=b.w(),a[9]=b);null!==this.a&&(b=this.a,b=b.w(),a[10]=b);null!==this.o&& +(b=this.o,a[11]=b);return a};function Vv(a){a.g=null;a.i=null;a.c=null;a.f=null;a.l=null;a.j=null;a.u=null;a.m=null;a.h=null;a.s=null;var b=a.b;b&&(b.a=null,b.b=null);a.b=null;if(b=a.a)b.a=null,b.b=null;a.a=null;a.o=null}Tu.prototype.getExtension=function(){return null};function Qv(){return new Tu} +function hw(a){if(null===a)a=null;else{var b=new Tu;Vv(b);b.g=a.g;b.i=a.i;b.c=Ad(a.c);b.f=a.f;b.l=Ad(a.l);b.j=a.j;b.u=a.u;b.m=a.m;b.h=a.h;b.s=a.s;b.b=a.b?iw(a.b):null;b.a=a.a?iw(a.a):null;b.o=a.o;b.v=a.v;a=b}return a} +function Rv(a,b){for(a.v=jd(b);G(b);)switch(b.a){case 1:var c=nd(b);a.g=c;break;case 2:c=J(b);a.i=c;break;case 3:c=J(b);a.c=a.c||[];a.c.push(c);break;case 4:c=L(b);a.f=c;break;case 5:null===a.j&&(a.j=b.b);kd(b);a.u=id(b);break;case 6:c=J(b);a.m=c;break;case 8:c=b.c.da();a.h=c;break;case 9:c=J(b);a.s=c;break;case 10:c=new Vu;O(b,c,jw);a.b=c;break;case 11:c=new Vu;O(b,c,jw);a.a=c;break;case 12:c=J(b);a.o=c;break;default:H(b)}} +Uu.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;b=b.slice();for(var c=0;c<b.length;c++)b[c]=b[c].w();a[0]=b}null!==this.j&&(b=this.j,a[1]=b);null!==this.l&&(b=this.l,a[2]=b);null!==this.h&&(b=this.h,a[3]=b);null!==this.g&&(b=this.g,a[4]=b);kw(this);null!==this.c&&(b=this.c,b=b.slice(),a[5]=b);null!==this.f&&(b=this.f,a[6]=b);null!==this.v&&(b=this.v,a[7]=b);null!==this.b&&(b=this.b,a[8]=b);null!==this.s&&(b=this.s,a[9]=b);null!==this.o&&(b=this.o,a[10]=b);null!==this.u&&(b=this.u, +a[11]=b);null!==this.m&&(b=this.m,a[12]=b);return a};function lv(a){if(a.a)for(var b=0;b<a.a.length;b++){var c=a.a[b];c&&Vv(c)}a.a=null;a.j=null;a.l=null;a.h=null;a.g=null;a.c=null;a.i=null;a.A=null;a.f=null;a.v=null;a.b=null;a.s=null;a.o=null;a.u=null;a.m=null}Uu.prototype.getExtension=function(){return null};function Lv(){return new Uu} +function qv(a,b){for(a.B=jd(b);G(b);)switch(b.a){case 1:var c=new Tu;O(b,c,Rv);a.a=a.a||[];a.a.push(c);break;case 2:c=nd(b);a.j=c;break;case 3:c=J(b);a.l=c;break;case 4:c=J(b);a.h=c;break;case 5:c=K(b);a.g=c;break;case 6:null===a.i&&(a.i=b.b);kd(b);a.A=id(b);break;case 7:c=L(b);a.f=c;break;case 8:c=J(b);a.v=c;break;case 9:c=L(b);a.b=c;break;case 10:c=J(b);a.s=c;break;case 11:c=md(b);a.o=c;break;case 12:c=J(b);a.u=c;break;case 13:c=md(b);a.m=c;break;default:H(b)}} +function kw(a){null!=a.i&&null==a.c&&(a.c=Fd(Wc.prototype.Ma,a.B,a.i,a.A))}Vu.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;a[0]=b}null!==this.b&&(b=this.b,a[2]=b);return a};function iw(a){var b=new Vu;b.a=null;b.b=null;b.a=a.a;b.b=a.b;return b}Vu.prototype.getExtension=function(){return null};function jw(a,b){for(;G(b);)switch(b.a){case 1:var c=L(b);a.a=c;break;case 3:c=J(b);a.b=c;break;default:H(b)}} +Wu.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;a[0]=b}null!==this.b&&(b=this.b,a[1]=b);return a};Wu.prototype.getExtension=function(){return null};function lw(a,b){for(;G(b);)switch(b.a){case 1:var c=nd(b);a.a=c;break;case 2:c=nd(b);a.b=c;break;default:H(b)}}Xu.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;b=b.w();a[0]=b}null!==this.c&&(b=this.c,a[1]=b);null!==this.b&&(b=this.b,a[2]=b);return a};Xu.prototype.getExtension=function(){return null}; +function Mv(){return new Xu}function rv(a,b){for(;G(b);)switch(b.a){case 1:var c=new Wu;O(b,c,lw);a.a=c;break;case 2:c=J(b);a.c=c;break;case 3:c=K(b);a.b=c;break;default:H(b)}}Yu.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;a[0]=b}null!==this.g&&(b=this.g,a[1]=b);null!==this.b&&(b=this.b,a[2]=b);null!==this.f&&(b=this.f,a[3]=b);null!==this.c&&(b=this.c,a[4]=b);return a};function mv(a){a.a=null;a.g=null;a.b=null;a.f=null;a.c=null}Yu.prototype.getExtension=function(){return null}; +function Nv(){return new Yu}function sv(a,b){for(;G(b);)switch(b.a){case 1:var c=nd(b);a.a=c;break;case 2:c=J(b);a.g=c;break;case 3:c=nd(b);a.b=c;break;case 4:c=J(b);a.f=c;break;case 5:c=K(b);a.c=c;break;default:H(b)}}Zu.prototype.w=function(){var a=[];if(null!==this.b){var b=this.b;a[1]=b}null!==this.a&&(b=this.a,a[2]=b);null!=this.c&&null==this.f&&(this.f=Fd(Wc.prototype.zd,this.h,this.c,this.g));null!==this.f&&(b=this.f,b=b.slice(),a[3]=b);return a}; +function nv(a){a.b=null;a.a=null;a.f=null;a.c=null;a.g=null}Zu.prototype.getExtension=function(){return null};function Ov(){return new Zu}function tv(a,b){for(a.h=jd(b);G(b);)switch(b.a){case 2:var c=J(b);a.b=c;break;case 3:c=K(b);a.a=c;break;case 4:null===a.c&&(a.c=b.b);kd(b);a.g=id(b);break;default:H(b)}};function mw(){this.f=this.b=this.a=this.c=null}mw.prototype.w=function(){var a=[];if(null!==this.c){var b=this.c;a[0]=b}null!==this.a&&(b=this.a,a[1]=b);null!==this.b&&(b=this.b,a[2]=b);null!==this.f&&(b=this.f,a[3]=b);return a};mw.prototype.getExtension=function(){return null};function nw(a,b){for(;G(b);)switch(b.a){case 1:var c=J(b);a.c=c;break;case 2:c=J(b);a.a=c;break;case 3:c=J(b);a.b=c;break;case 4:c=J(b);a.f=c;break;default:H(b)}}mw.prototype.getZoom=function(){return null==this.c?0:this.c};function ow(){this.g=this.b=this.J=this.D=this.H=this.I=this.L=this.A=this.B=this.h=this.C=this.G=this.l=this.i=this.o=this.u=this.s=this.m=this.K=this.j=this.a=this.v=this.c=this.f=null}function pw(){this.a=this.T=this.I=this.J=this.V=this.G=this.B=this.L=this.j=this.m=this.U=this.D=this.v=this.K=this.i=this.l=this.M=this.c=this.b=this.O=this.o=this.h=this.S=this.C=this.g=this.P=this.A=this.f=this.H=this.s=this.u=null} +function qw(){this.b=this.v=this.m=this.s=this.u=this.l=this.g=this.c=this.o=this.j=this.i=this.h=this.f=this.a=null}function rw(){this.b=this.c=this.a=null}function sw(){this.b=this.g=this.A=this.i=this.a=this.v=this.j=this.l=this.B=this.o=this.f=this.C=this.s=this.u=this.m=this.c=this.h=null}function tw(){this.b=this.s=this.m=this.o=this.f=this.l=this.j=this.i=this.h=this.g=this.c=this.a=null}function uw(){this.o=this.a=this.l=this.b=this.h=this.g=this.f=this.j=this.m=this.i=this.c=null} +function vw(){this.j=this.g=this.f=this.a=this.i=this.b=this.c=this.h=null}function ww(){this.a=this.i=this.f=this.c=this.j=this.h=this.g=this.b=null}function xw(){this.i=this.c=this.f=this.h=this.a=this.b=this.g=null}function yw(){this.a=this.b=this.c=this.g=this.f=null}function zw(){this.g=this.a=this.f=this.c=this.b=null}function Aw(){this.a=this.b=null}function Bw(){this.b=this.c=this.a=null}function Cw(){this.h=this.a=this.g=this.b=this.c=this.f=null}function Dw(){this.a=null} +function Ew(){}function Fw(){this.b=this.a=null}function Gw(){this.b=this.a=null}function Hw(){this.b=this.a=null}function Iw(){this.b=this.a=null}function Jw(){this.Aa=null}function Kw(){this.b=this.a=null}function Lw(){this.a=this.b=null}function Mw(){this.g=this.s=this.m=this.B=this.v=this.A=this.a=this.l=this.i=this.j=this.o=this.C=this.f=this.h=this.b=this.u=this.c=null} +ow.prototype.w=function(){var a=[];null!=this.c&&null==this.f&&(this.f=Gd(this.g,this.c,this.v));if(null!==this.f){var b=this.f;b=Dc(b);a[0]=b}Nw(this);null!==this.a&&(b=this.a,b=b.slice(),a[1]=b);null!==this.m&&(b=this.m,a[2]=b);null!==this.s&&(b=this.s,a[3]=b);null!==this.u&&(b=this.u,a[4]=b);null!==this.o&&(b=this.o,a[5]=b);null!==this.i&&(b=this.i,a[6]=b);null!==this.l&&(b=this.l,a[7]=b);null!==this.G&&(b=this.G,a[8]=b);null!==this.C&&(b=this.C,a[9]=b);null!==this.h&&(b=this.h,b=Oc(b,!0),a[10]= +b);null!=this.A&&null==this.B&&(this.B=Fd(Wc.prototype.De,this.g,this.A,this.L));null!==this.B&&(b=this.B,b=b.slice(),b=Pc(b,!0),a[11]=b);null!==this.I&&(b=this.I,a[12]=b);null!==this.H&&(b=this.H,a[13]=b);null!==this.D&&(b=this.D,a[14]=b);null!==this.J&&(b=this.J,a[1E3]=b);return a};var Ow=[];ow.prototype.getExtension=function(a){var b=!1;25E6<=a&&536870912>a&&(b=!0);return b?Id(this.b,a):null};function Pw(a){a.b=a.b||[];return a.b} +function Qw(a){if(a){a.f=null;a.c=null;a.v=null;a.a=null;a.j=null;a.K=null;a.m=null;a.s=null;a.u=null;a.o=null;a.i=null;a.l=null;a.G=null;a.C=null;a.h=null;a.B=null;a.A=null;a.L=null;a.I=null;a.H=null;a.D=null;a.J=null;if(a.b)for(var b=0;b<a.b.length;b++)wd(a.b[b]);a.b=null}} +function Rw(a,b){for(a.g=jd(b);G(b);)switch(b.a){case 1:null===a.c&&(a.c=b.b);kd(b);a.v=id(b);break;case 2:null===a.j&&(a.j=b.b);kd(b);a.K=id(b);break;case 3:var c=J(b);a.m=c;break;case 4:c=J(b);a.s=c;break;case 5:c=nd(b);a.u=c;break;case 6:c=N(b);a.o=c;break;case 7:c=J(b);a.i=c;break;case 8:c=N(b);a.l=c;break;case 9:c=M(b);a.G=c;break;case 10:c=J(b);a.C=c;break;case 11:c=qd(b);a.h=c;break;case 12:null===a.A&&(a.A=b.b);kd(b);a.L=id(b);break;case 13:c=J(b);a.I=c;break;case 14:c=J(b);a.H=c;break;case 15:c= +N(b);a.D=c;break;case 1001:c=J(b);a.J=c;break;case 1E3:H(b);break;default:a.b=a.b||[],c=Jd(b,Ow),a.b.push(c)}}function Sw(a){return null!==a.f?Zc(a.f):a.g&&null!=a.c&&null!=a.v?(a=Zc(a.g,a.c,a.v-a.c),a.ca(),a.ca(),a):Zc()}function Tw(a){return null!=a.a||null!=a.j?!0:!1}function Uw(a){Nw(a);return a.a?a.a.length:0}function Nw(a){null!=a.j&&null==a.a&&(a.a=Fd(Wc.prototype.Ma,a.g,a.j,a.K))}function Vw(a){return null==a.o?1:a.o}function Ww(a){return null==a.l?1:a.l} +pw.prototype.w=function(){var a=[];null!=this.s&&null==this.u&&(this.u=Gd(this.a,this.s,this.H));if(null!==this.u){var b=this.u;b=Dc(b);a[0]=b}Xw(this);null!==this.f&&(b=this.f,b=b.slice(),a[1]=b);Yw(this);null!==this.g&&(b=this.g,b=b.slice(),a[2]=b);Zw(this);null!==this.h&&(b=this.h,b=b.slice(),a[3]=b);null!==this.b&&(b=this.b,a[4]=b);null!==this.c&&(b=this.c,a[5]=b);null!==this.M&&(b=this.M,a[6]=b);null!=this.i&&null==this.l&&(this.l=Gd(this.a,this.i,this.K));null!==this.l&&(b=this.l,b=Dc(b),a[7]= +b);$w(this);null!==this.v&&(b=this.v,b=b.slice(),a[8]=b);null!=this.j&&null==this.m&&(this.m=Gd(this.a,this.j,this.L));null!==this.m&&(b=this.m,b=Dc(b),a[9]=b);ax(this);null!==this.B&&(b=this.B,b=b.slice(),a[10]=b);null!=this.I&&null==this.J&&(this.J=Fd(Wc.prototype.zd,this.a,this.I,this.T));null!==this.J&&(b=this.J,b=b.slice(),a[11]=b);return a}; +function bx(a){a.u=null;a.s=null;a.H=null;a.f=null;a.A=null;a.P=null;a.g=null;a.C=null;a.S=null;a.h=null;a.o=null;a.O=null;a.b=null;a.c=null;a.M=null;a.l=null;a.i=null;a.K=null;a.v=null;a.D=null;a.U=null;a.m=null;a.j=null;a.L=null;a.B=null;a.G=null;a.V=null;a.J=null;a.I=null;a.T=null}pw.prototype.getExtension=function(){return null};function cx(a){a&&bx(a)} +function dx(a,b){for(a.a=jd(b);G(b);)switch(b.a){case 1:null===a.s&&(a.s=b.b);kd(b);a.H=id(b);break;case 2:null===a.A&&(a.A=b.b);kd(b);a.P=id(b);break;case 3:null===a.C&&(a.C=b.b);kd(b);a.S=id(b);break;case 4:null===a.o&&(a.o=b.b);kd(b);a.O=id(b);break;case 5:var c=J(b);a.b=c;break;case 6:c=J(b);a.c=c;break;case 7:c=J(b);a.M=c;break;case 8:null===a.i&&(a.i=b.b);kd(b);a.K=id(b);break;case 9:null===a.D&&(a.D=b.b);kd(b);a.U=id(b);break;case 10:null===a.j&&(a.j=b.b);kd(b);a.L=id(b);break;case 11:null=== +a.G&&(a.G=b.b);kd(b);a.V=id(b);break;case 12:null===a.I&&(a.I=b.b);kd(b);a.T=id(b);break;case 1E3:H(b);break;case 1001:H(b);break;case 1002:H(b);break;default:H(b)}}function ex(a){return null!==a.u?Zc(a.u):a.a&&null!=a.s&&null!=a.H?(a=Zc(a.a,a.s,a.H-a.s),a.ca(),a.ca(),a):Zc()}function fx(a){return null!=a.f||null!=a.A?!0:!1}function gx(a){Xw(a);return a.f?a.f.length:0}function hx(a){Xw(a);return a.f}function ix(a){return null===a.f?zd(a.a,a.A,a.P):Tc(null,null,a.f)} +function Xw(a){null!=a.A&&null==a.f&&(a.f=Fd(Wc.prototype.Ma,a.a,a.A,a.P))}function jx(a){Yw(a);return a.g?a.g.length:0}function kx(a){Yw(a);return a.g}function Yw(a){null!=a.C&&null==a.g&&(a.g=Fd(Wc.prototype.Ma,a.a,a.C,a.S))}function lx(a){Zw(a);return a.h}function Zw(a){null!=a.o&&null==a.h&&(a.h=Fd(Wc.prototype.Ma,a.a,a.o,a.O))}function mx(a){return null!==a.l?Zc(a.l):a.a&&null!=a.i&&null!=a.K?(a=Zc(a.a,a.i,a.K-a.i),a.ca(),a.ca(),a):Zc()}function nx(a){$w(a);return a.v} +function $w(a){null!=a.D&&null==a.v&&(a.v=Fd(Wc.prototype.Ma,a.a,a.D,a.U))}function ox(a){return null!==a.m?Zc(a.m):a.a&&null!=a.j&&null!=a.L?(a=Zc(a.a,a.j,a.L-a.j),a.ca(),a.ca(),a):Zc()}function px(a){ax(a);return a.B}function ax(a){null!=a.G&&null==a.B&&(a.B=Fd(Wc.prototype.Ma,a.a,a.G,a.V))} +qw.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;b=b.w();a[0]=b}null!==this.f&&(b=this.f,a[1]=b);null!==this.h&&(b=this.h,a[2]=b);null!==this.i&&(b=this.i,a[3]=b);null!==this.j&&(b=this.j,a[4]=b);null!==this.o&&(b=this.o,a[5]=b);null!==this.c&&(b=this.c,a[6]=b);null!==this.g&&(b=this.g,b=Oc(b,!0),a[7]=b);null!==this.l&&(b=this.l,b=Oc(b,!1),a[9]=b);null!==this.u&&(b=this.u,a[10]=b);null!==this.s&&(b=this.s,a[11]=b);null!==this.m&&(b=this.m,a[12]=b);null!==this.v&&(b=this.v,a[999]= +b);return a};var qx=[];qw.prototype.getExtension=function(a){var b=!1;25E6<=a&&536870912>a&&(b=!0);return b?Id(this.b,a):null};function rx(a){a.b=a.b||[];return a.b}function sx(a){if(a){cx(a.a);a.a=null;a.f=null;a.h=null;a.i=null;a.j=null;a.o=null;a.c=null;a.g=null;a.l=null;a.u=null;a.s=null;a.m=null;a.v=null;if(a.b)for(var b=0;b<a.b.length;b++)wd(a.b[b]);a.b=null}} +function tx(a,b){for(;G(b);)switch(b.a){case 1:var c=new pw;O(b,c,dx);a.a=c;break;case 2:c=K(b);a.f=c;break;case 3:c=J(b);a.h=c;break;case 4:c=J(b);a.i=c;break;case 5:c=nd(b);a.j=c;break;case 6:c=M(b);a.o=c;break;case 7:c=K(b);a.c=c;break;case 8:c=qd(b);a.g=c;break;case 10:c=pd(b);a.l=c;break;case 11:c=J(b);a.u=c;break;case 12:c=J(b);a.s=c;break;case 13:c=N(b);a.m=c;break;case 1E3:c=J(b);a.v=c;break;default:a.b=a.b||[],c=Jd(b,qx),a.b.push(c)}}function ux(a){null===a.a&&(a.a=new pw);return a.a} +rw.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;b=b.w();a[0]=b}null!==this.c&&(b=this.c,a[1]=b);null!==this.b&&(b=this.b,a[2]=b);return a};rw.prototype.getExtension=function(){return null};function vx(a,b){for(;G(b);)switch(b.a){case 1:var c=new pw;O(b,c,dx);a.a=c;break;case 2:c=J(b);a.c=c;break;case 3:c=J(b);a.b=c;break;default:H(b)}}function wx(a){null===a.a&&(a.a=new pw);return a.a} +sw.prototype.w=function(){var a=[];null!=this.c&&null==this.h&&(this.h=Gd(this.b,this.c,this.m));if(null!==this.h){var b=this.h;b=Dc(b);a[0]=b}null!=this.s&&null==this.u&&(this.u=Gd(this.b,this.s,this.C));null!==this.u&&(b=this.u,b=Dc(b),a[1]=b);xx(this);null!==this.f&&(b=this.f,b=b.slice(),a[2]=b);null!=this.j&&null==this.l&&(this.l=Fd(Wc.prototype.Ma,this.b,this.j,this.v));null!==this.l&&(b=this.l,b=b.slice(),a[3]=b);yx(this);null!==this.a&&(b=this.a,b=b.slice(),a[4]=b);null!==this.g&&(b=this.g, +a[5]=b);return a};sw.prototype.getExtension=function(){return null};function zx(a,b){for(a.b=jd(b);G(b);)switch(b.a){case 1:null===a.c&&(a.c=b.b);kd(b);a.m=id(b);break;case 2:null===a.s&&(a.s=b.b);kd(b);a.C=id(b);break;case 3:null===a.o&&(a.o=b.b);kd(b);a.B=id(b);break;case 4:null===a.j&&(a.j=b.b);kd(b);a.v=id(b);break;case 5:null===a.i&&(a.i=b.b);kd(b);a.A=id(b);break;case 6:a.g=J(b);break;case 1E3:H(b);break;case 1001:H(b);break;case 1002:H(b);break;default:H(b)}} +function Ax(a){return null!==a.h?Zc(a.h):a.b&&null!=a.c&&null!=a.m?(a=Zc(a.b,a.c,a.m-a.c),a.ca(),a.ca(),a):Zc()}function Bx(a){xx(a);return a.f?a.f.length:0}function Cx(a){xx(a);return a.f}function xx(a){null!=a.o&&null==a.f&&(a.f=Fd(Wc.prototype.Ma,a.b,a.o,a.B))}function Dx(a){yx(a);return a.a?a.a.length:0}function Ex(a){yx(a);return a.a}function yx(a){null!=a.i&&null==a.a&&(a.a=Fd(Wc.prototype.Ma,a.b,a.i,a.A))} +tw.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;b=b.slice();for(var c=0;c<b.length;c++)b[c]=b[c].w();a[0]=b}null!==this.c&&(b=this.c,b=b.w(),a[1]=b);null!==this.g&&(b=this.g,a[2]=b);null!==this.h&&(b=this.h,a[3]=b);null!==this.i&&(b=this.i,a[4]=b);null!==this.j&&(b=this.j,b=Oc(b,!1),a[5]=b);null!==this.l&&(b=this.l,a[6]=b);null!==this.f&&(b=this.f,b=Oc(b,!0),a[7]=b);null!==this.o&&(b=this.o,a[8]=b);null!==this.m&&(b=this.m,a[9]=b);null!==this.s&&(b=this.s,a[999]=b);return a}; +var Fx=[];tw.prototype.getExtension=function(a){var b=!1;25E6<=a&&536870912>a&&(b=!0);return b?Id(this.b,a):null};function Gx(a){a.b=a.b||[];return a.b} +function Hx(a){if(a){if(a.a)for(var b=0;b<a.a.length;b++){var c=a.a[b];c&&(cx(c.a),c.a=null,c.c=null,c.b=null)}a.a=null;if(b=a.c)b.h=null,b.c=null,b.m=null,b.u=null,b.s=null,b.C=null,b.f=null,b.o=null,b.B=null,b.l=null,b.j=null,b.v=null,b.a=null,b.i=null,b.A=null,b.g=null;a.c=null;a.g=null;a.h=null;a.i=null;a.j=null;a.l=null;a.f=null;a.o=null;a.m=null;a.s=null;if(a.b)for(b=0;b<a.b.length;b++)wd(a.b[b]);a.b=null}} +function Ix(a,b){for(;G(b);)switch(b.a){case 1:var c=new rw;O(b,c,vx);a.a=a.a||[];a.a.push(c);break;case 2:c=new sw;O(b,c,zx);a.c=c;break;case 3:c=J(b);a.g=c;break;case 4:c=J(b);a.h=c;break;case 5:c=nd(b);a.i=c;break;case 6:c=pd(b);a.j=c;break;case 7:c=M(b);a.l=c;break;case 8:c=qd(b);a.f=c;break;case 9:c=J(b);a.o=c;break;case 10:c=J(b);a.m=c;break;case 1E3:c=J(b);a.s=c;break;default:a.b=a.b||[],c=Jd(b,Fx),a.b.push(c)}}function Jx(a){null===a.c&&(a.c=new sw);return a.c} +uw.prototype.w=function(){var a=[];Kx(this);if(null!==this.c){var b=this.c;b=Dc(b);a[0]=b}null!==this.j&&(b=this.j,a[1]=b);null!==this.f&&(b=this.f,a[2]=b);null!==this.g&&(b=this.g,a[3]=b);null!==this.h&&(b=this.h,a[4]=b);null!==this.b&&(b=this.b,b=Oc(b,!0),a[5]=b);null!==this.l&&(b=this.l,a[999]=b);return a};var Lx=[];uw.prototype.getExtension=function(a){var b=!1;25E6<=a&&536870912>a&&(b=!0);return b?Id(this.a,a):null}; +function Mx(a){if(a){a.c=null;a.i=null;a.m=null;a.j=null;a.f=null;a.g=null;a.h=null;a.b=null;a.l=null;if(a.a)for(var b=0;b<a.a.length;b++)wd(a.a[b]);a.a=null}}function Nx(a,b){for(a.o=jd(b);G(b);)switch(b.a){case 1:null===a.i&&(a.i=b.b);kd(b);a.m=id(b);break;case 2:var c=M(b);a.j=c;break;case 3:c=J(b);a.f=c;break;case 4:c=J(b);a.g=c;break;case 5:c=nd(b);a.h=c;break;case 6:c=qd(b);a.b=c;break;case 1E3:c=J(b);a.l=c;break;default:a.a=a.a||[],c=Jd(b,Lx),a.a.push(c)}} +uw.prototype.getImageData=function(){Kx(this);return this.c};function Kx(a){null!=a.i&&null==a.c&&(a.c=Gd(a.o,a.i,a.m))} +vw.prototype.w=function(){var a=[];if(null!==this.h){var b=this.h;a[0]=b}if(null!=this.b&&null==this.c){var c=this.j,d=this.b,e=this.i;if(c&&null!=d&&null!=e){b=[];for(c=gd(c,d,e-d);G(c);)b.push(od(c));hd(c)}else b=null;this.c=b}if(null!==this.c){b=this.c;b=b.slice();for(c=0;c<b.length;c++)b[c]=Dc(b[c]);a[1]=b}null!==this.a&&(b=this.a,b=b.w(),a[2]=b);null!==this.f&&(b=this.f,a[3]=b);null!==this.g&&(b=this.g,a[4]=b);return a};vw.prototype.getExtension=function(){return null}; +function Ox(a,b){for(a.j=jd(b);G(b);)switch(b.a){case 1:var c=N(b);a.h=c;break;case 2:null===a.b&&(a.b=b.b);kd(b);a.i=id(b);break;case 3:c=new pw;O(b,c,dx);a.a=c;break;case 4:c=J(b);a.f=c;break;case 5:c=J(b);a.g=c;break;default:H(b)}} +ww.prototype.w=function(){var a=[];if(null!==this.b){var b=this.b;b=b.w();a[0]=b}null!==this.g&&(b=this.g,a[1]=b);null!==this.h&&(b=this.h,a[2]=b);null!==this.j&&(b=this.j,a[3]=b);null!==this.c&&(b=this.c,a[4]=b);null!==this.f&&(b=this.f,b=Oc(b,!0),a[5]=b);null!==this.i&&(b=this.i,a[999]=b);return a};var Px=[];ww.prototype.getExtension=function(a){var b=!1;25E6<=a&&536870912>a&&(b=!0);return b?Id(this.a,a):null}; +function Qx(a){if(a){var b=a.b;b&&(b.h=null,b.c=null,b.b=null,b.i=null,cx(b.a),b.a=null,b.f=null,b.g=null);a.b=null;a.g=null;a.h=null;a.j=null;a.c=null;a.f=null;a.i=null;if(a.a)for(b=0;b<a.a.length;b++)wd(a.a[b]);a.a=null}} +function Rx(a,b){for(;G(b);)switch(b.a){case 1:var c=new vw;O(b,c,Ox);a.b=c;break;case 2:c=J(b);a.g=c;break;case 3:c=J(b);a.h=c;break;case 4:c=nd(b);a.j=c;break;case 5:c=M(b);a.c=c;break;case 6:c=qd(b);a.f=c;break;case 1E3:c=J(b);a.i=c;break;default:a.a=a.a||[],c=Jd(b,Px),a.a.push(c)}} +xw.prototype.w=function(){var a=[];if(null!==this.g){var b=this.g;a[0]=b}null!=this.a&&null==this.b&&(this.b=Fd(Wc.prototype.Ce,this.i,this.a,this.h));null!==this.b&&(b=this.b,b=b.slice(),b=Pc(b,!1),a[1]=b);null!==this.f&&(b=this.f,a[2]=b);null!==this.c&&(b=this.c,a[3]=b);return a};xw.prototype.getExtension=function(){return null}; +function Sx(a,b){for(a.i=jd(b);G(b);)switch(b.a){case 1:var c=N(b);a.g=c;break;case 2:null===a.a&&(a.a=b.b);kd(b);a.h=id(b);break;case 3:c=J(b);a.f=c;break;case 4:c=J(b);a.c=c;break;default:H(b)}}yw.prototype.w=function(){var a=[];if(null!==this.f){var b=this.f;a[0]=b}null!==this.g&&(b=this.g,a[1]=b);null!==this.c&&(b=this.c,a[2]=b);null!==this.b&&(b=this.b,a[3]=b);null!==this.a&&(b=this.a,b=Oc(b,!1),a[6]=b);return a};yw.prototype.getExtension=function(){return null}; +function Tx(a){a&&(a.f=null,a.g=null,a.c=null,a.b=null,a.a=null)}function Ux(a,b){for(;G(b);)switch(b.a){case 1:var c=J(b);a.f=c;break;case 2:c=J(b);a.g=c;break;case 3:c=J(b);a.c=c;break;case 4:c=J(b);a.b=c;break;case 7:c=pd(b);a.a=c;break;default:H(b)}}function Vx(a){return null==a.f?0:a.f}function Wx(a){return null==a.g?0:a.g}function Xx(a){return null==a.c?0:a.c}function Yx(a){return null==a.b?0:a.b} +zw.prototype.w=function(){var a=[];Zx(this);if(null!==this.b){var b=this.b;b=Dc(b);a[0]=b}if(null!==this.a){b=this.a;b=b.slice();for(var c=0;c<b.length;c++)b[c]=b[c].w();a[1]=b}return a};zw.prototype.getExtension=function(){return null};function $x(a,b){for(a.g=jd(b);G(b);)switch(b.a){case 1:null===a.c&&(a.c=b.b);kd(b);a.f=id(b);break;case 2:var c=new yw;O(b,c,Ux);a.a=a.a||[];a.a.push(c);break;default:H(b)}}function Zx(a){null!=a.c&&null==a.b&&(a.b=Gd(a.g,a.c,a.f))} +function ay(a,b){return a.a[b]}Aw.prototype.w=function(){var a=[];if(null!==this.b){var b=this.b;a[0]=b}null!==this.a&&(b=this.a,a[1]=b);return a};Aw.prototype.getExtension=function(){return null};function by(a,b){for(;G(b);)switch(b.a){case 1:var c=N(b);a.b=c;break;case 2:c=N(b);a.a=c;break;default:H(b)}}Bw.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;a[0]=b}null!==this.c&&(b=this.c,a[1]=b);null!==this.b&&(b=this.b,a[2]=b);return a};Bw.prototype.getExtension=function(){return null}; +function cy(a){a&&(a.a=null,a.c=null,a.b=null)}function dy(a,b){for(;G(b);)switch(b.a){case 1:var c=J(b);a.a=c;break;case 2:c=J(b);a.c=c;break;case 3:c=J(b);a.b=c;break;default:H(b)}}Cw.prototype.w=function(){var a=[];if(null!==this.f){var b=this.f;a[0]=b}null!=this.b&&null==this.c&&(this.c=Gd(this.h,this.b,this.g));null!==this.c&&(b=this.c,b=Dc(b),a[1]=b);null!==this.a&&(b=this.a,b=b.slice(),a[2]=b);return a};Cw.prototype.getExtension=function(){return null}; +function ey(a){a&&(a.f=null,a.c=null,a.b=null,a.g=null,a.a=null)}function fy(a,b){for(a.h=jd(b);G(b);)switch(b.a){case 1:var c=L(b);a.f=c;break;case 2:null===a.b&&(a.b=b.b);kd(b);a.g=id(b);break;case 3:c=J(b);a.a=a.a||[];a.a.push(c);break;default:H(b)}}Dw.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;b=b.slice();for(var c=0;c<b.length;c++)b[c]=b[c].w();a[0]=b}return a};Dw.prototype.getExtension=function(){return null}; +function gy(a,b){for(;G(b);)switch(b.a){case 1:var c=new Cw;O(b,c,fy);a.a=a.a||[];a.a.push(c);break;default:H(b)}}Ew.prototype.w=function(){return[]};Ew.prototype.getExtension=function(){return null};function hy(a,b){for(;G(b);)H(b)}Fw.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;b=b.slice();for(var c=0;c<b.length;c++)b[c]=b[c].w();a[0]=b}null!==this.b&&(b=this.b,b=b.w(),a[1]=b);return a};Fw.prototype.getExtension=function(){return null}; +function iy(a,b){for(;G(b);)switch(b.a){case 1:var c=new ow;O(b,c,Rw);a.a=a.a||[];a.a.push(c);break;case 2:c=new Bw;O(b,c,dy);a.b=c;break;default:H(b)}}function jy(a){return null!=a.a?!0:!1}Gw.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;b=b.slice();for(var c=0;c<b.length;c++)b[c]=b[c].w();a[0]=b}null!==this.b&&(b=this.b,b=b.w(),a[1]=b);return a};Gw.prototype.getExtension=function(){return null}; +function ky(a,b){for(;G(b);)switch(b.a){case 1:var c=new qw;O(b,c,tx);a.a=a.a||[];a.a.push(c);break;case 2:c=new Bw;O(b,c,dy);a.b=c;break;default:H(b)}}function ly(a){return null!=a.a?!0:!1}Hw.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;b=b.slice();for(var c=0;c<b.length;c++)b[c]=b[c].w();a[0]=b}null!==this.b&&(b=this.b,b=b.w(),a[1]=b);return a};Hw.prototype.getExtension=function(){return null}; +function my(a,b){for(;G(b);)switch(b.a){case 1:var c=new tw;O(b,c,Ix);a.a=a.a||[];a.a.push(c);break;case 2:c=new Bw;O(b,c,dy);a.b=c;break;default:H(b)}}function ny(a){return null!=a.a?!0:!1}Iw.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;b=b.slice();for(var c=0;c<b.length;c++)b[c]=b[c].w();a[0]=b}null!==this.b&&(b=this.b,b=b.w(),a[1]=b);return a};Iw.prototype.getExtension=function(){return null}; +function oy(a,b){for(;G(b);)switch(b.a){case 1:var c=new Xt;O(b,c,Bu);a.a=a.a||[];a.a.push(c);break;case 2:c=new Bw;O(b,c,dy);a.b=c;break;default:H(b)}}function py(a){return null!=a.a?!0:!1}Jw.prototype.w=function(){var a=[];if(null!==this.Aa){var b=this.Aa;b=b.slice();for(var c=0;c<b.length;c++)b[c]=b[c].w();a[0]=b}return a};Jw.prototype.getExtension=function(){return null};function qy(a,b){for(;G(b);)switch(b.a){case 1:var c=new uw;O(b,c,Nx);a.Aa=a.Aa||[];a.Aa.push(c);break;default:H(b)}} +function ry(a){return null!=a.Aa?!0:!1}Kw.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;b=b.slice();for(var c=0;c<b.length;c++)b[c]=b[c].w();a[0]=b}null!==this.b&&(b=this.b,b=b.w(),a[1]=b);return a};Kw.prototype.getExtension=function(){return null};function sy(a,b){for(;G(b);)switch(b.a){case 1:var c=new ww;O(b,c,Rx);a.a=a.a||[];a.a.push(c);break;case 2:c=new Bw;O(b,c,dy);a.b=c;break;default:H(b)}} +Lw.prototype.w=function(){var a=[];if(null!==this.b){var b=this.b;a[0]=b}null!==this.a&&(b=this.a,a[1]=b);return a};Lw.prototype.getExtension=function(){return null};function ty(a,b){for(;G(b);)switch(b.a){case 1:var c=L(b);a.b=c;break;case 2:c=J(b);a.a=c;break;default:H(b)}} +function uy(a,b){for(;G(b);)switch(b.a){case 1:var c=new mw;O(b,c,nw);a.c=c;break;case 2:c=new Aw;O(b,c,by);a.u=c;break;case 3:c=new Hu;O(b,c,av);a.b=a.b||[];a.b.push(c);break;case 4:c=new zw;O(b,c,$x);a.h=c;break;case 5:c=new xw;O(b,c,Sx);a.f=a.f||[];a.f.push(c);break;case 6:c=new Ew;O(b,c,hy);a.C=c;break;case 7:c=new Fw;O(b,c,iy);a.o=c;break;case 8:c=new Gw;O(b,c,ky);a.j=c;break;case 9:c=new Hw;O(b,c,my);a.i=c;break;case 10:c=new Iw;O(b,c,oy);a.l=c;break;case 11:c=new Jw;O(b,c,qy);a.a=c;break;case 12:c= +new Kw;O(b,c,sy);a.A=c;break;case 13:c=new Dw;O(b,c,gy);a.v=c;break;case 14:c=J(b);a.B=c;break;case 15:c=new Lw;O(b,c,ty);a.m=a.m||[];a.m.push(c);break;case 16:c=M(b);a.s=c;break;default:a.g=a.g||[],c=Jd(b,vy),a.g.push(c)}} +Mw.prototype.w=function(){var a=[];if(null!==this.c){var b=this.c;b=b.w();a[0]=b}null!==this.u&&(b=this.u,b=b.w(),a[1]=b);if(null!==this.b){b=this.b;b=b.slice();for(var c=0;c<b.length;c++)b[c]=b[c].w();a[2]=b}null!==this.h&&(b=this.h,b=b.w(),a[3]=b);if(null!==this.f){b=this.f;b=b.slice();for(c=0;c<b.length;c++)b[c]=b[c].w();a[4]=b}null!==this.C&&(b=this.C,b=b.w(),a[5]=b);null!==this.o&&(b=this.o,b=b.w(),a[6]=b);null!==this.j&&(b=this.j,b=b.w(),a[7]=b);null!==this.i&&(b=this.i,b=b.w(),a[8]=b);null!== +this.l&&(b=this.l,b=b.w(),a[9]=b);null!==this.a&&(b=this.a,b=b.w(),a[10]=b);null!==this.A&&(b=this.A,b=b.w(),a[11]=b);null!==this.v&&(b=this.v,b=b.w(),a[12]=b);null!==this.B&&(b=this.B,a[13]=b);if(null!==this.m){b=this.m;b=b.slice();for(c=0;c<b.length;c++)b[c]=b[c].w();a[14]=b}null!==this.s&&(b=this.s,a[15]=b);return a};var vy=[];Mw.prototype.getExtension=function(a){var b=!1;25E6<=a&&536870912>a&&(b=!0);return b?Id(this.g,a):null}; +function wy(a){a.g=a.g||[];a=a.g;var b=vy,c=Id(a,96629873);if(c)a=c;else{c=null;if(b)for(var d=0;d<b.length;d++)if(96629873==b[d].c){c=b[d];break}if(c&&11==c.b&&null!=c.a){c=c.a();b:{var e=null;if(b)for(d=0;d<b.length;d++)if(96629873==b[d].c){e=b[d];break}if(e){b=vd(96629873,c,null,null,null,e);for(d=0;d<a.length;d++)if((e=a[d])&&96629873==e.c){a[d]=b;break b}a.push(b)}}a=c}else a=null}return a}function Ay(a){null===a.c&&(a.c=new mw);return a.c}function By(a){null===a.c&&(a.c=new mw);return a.c} +function Cy(a){null===a.u&&(a.u=new Aw);return a.u}function Dy(a){null===a.h&&(a.h=new zw);return a.h}function Ey(a){return null!=a.o?!0:!1}function Fy(a){null===a.o&&(a.o=new Fw);return a.o}function Gy(a){return null!=a.j?!0:!1}function Hy(a){null===a.j&&(a.j=new Gw);return a.j}function Iy(a){null===a.i&&(a.i=new Hw);return a.i}function Jy(a){return null!=a.l?!0:!1}function Ky(a){null===a.l&&(a.l=new Iw);return a.l}function Ly(a){null===a.a&&(a.a=new Jw);return a.a};function My(){this.b=this.a=null}function Ny(){this.b=this.a=null}My.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;b=b.w();a[1]=b}null!==this.b&&(b=this.b,a[2]=b);return a};My.prototype.getExtension=function(){return null};Ny.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;b=Oc(b,!1);a[0]=b}null!==this.b&&(b=this.b,b=Oc(b,!1),a[1]=b);return a};Ny.prototype.getExtension=function(){return null}; +function Oy(a,b){for(;G(b);)switch(b.a){case 1:var c=pd(b);a.a=c;break;case 2:c=pd(b);a.b=c;break;default:H(b)}};function Py(){this.a=this.f=this.b=this.g=this.c=null}Py.prototype.w=function(){var a=[];if(null!==this.c){var b=this.c;a[0]=b}null!==this.g&&(b=this.g,b=Oc(b,!1),a[1]=b);null!==this.b&&(b=this.b,a[2]=b);null!==this.f&&(b=this.f,a[3]=b);null!==this.a&&(b=this.a,a[4]=b);return a};Py.prototype.getExtension=function(){return null};function Qy(){this.c=this.b=this.a=null}Qy.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;a[0]=b}null!==this.b&&(b=this.b,a[1]=b);null!==this.c&&(b=this.c,a[2]=b);return a};Qy.prototype.getExtension=function(){return null};function Ry(){this.a=this.f=this.h=this.c=this.b=this.g=null}Ry.prototype.w=function(){var a=[];if(null!==this.g){var b=this.g;b=Oc(b,!1);a[0]=b}null!==this.b&&(b=this.b,a[1]=b);null!==this.c&&(b=this.c,a[2]=b);null!==this.h&&(b=this.h,a[3]=b);null!==this.f&&(b=this.f,a[4]=b);null!==this.a&&(b=this.a,b=b.slice(),a[5]=b);return a};Ry.prototype.getExtension=function(){return null};function Sy(){this.b=this.a=null}function Ty(){}Sy.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;b=b.w();a[0]=b}null!==this.b&&(b=this.b,b=b.w(),a[2]=b);return a};Sy.prototype.getExtension=function(){return null};Ty.prototype.w=function(){return[]};Ty.prototype.getExtension=function(){return null};function Uy(a,b){for(;G(b);)H(b)};function Vy(){this.a=null}function Wy(){this.c=this.a=this.b=null}function Xy(){this.b=this.a=null}function Yy(){this.b=this.a=null}function Zy(){this.c=this.i=this.j=this.h=this.g=this.f=this.b=this.a=null}function $y(){this.f=this.g=this.c=this.a=this.b=null}function az(){this.b=this.a=null}Vy.prototype.w=function(){var a=[];null!==this.a&&(a[0]=this.a);return a};Vy.prototype.getExtension=function(){return null}; +Wy.prototype.w=function(){var a=[];if(null!==this.b){var b=this.b;a[0]=b}null!==this.a&&(b=this.a,b=b.w(),a[1]=b);null!==this.c&&(b=this.c,a[2]=b);return a};Wy.prototype.getExtension=function(){return null};Xy.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;a[0]=b}null!==this.b&&(b=this.b,a[1]=b);return a};Xy.prototype.getExtension=function(){return null};Yy.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;a[0]=b}null!==this.b&&(b=this.b,a[1]=b);return a}; +Yy.prototype.getExtension=function(){return null};function bz(a){if(null===a)a=null;else{var b=new Yy;b.a=null;b.b=null;b.a=a.a;b.b=a.b;a=b}return a}function cz(a,b){for(;G(b);)switch(b.a){case 1:var c=J(b);a.a=c;break;case 2:c=J(b);a.b=c;break;default:H(b)}}function dz(a,b){return a===b?!0:null===a||null===b?!1:a.a!==b.a||a.b!==b.b?!1:!0} +Zy.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;b=b.slice();for(var c=0;c<b.length;c++)b[c]=b[c].w();a[0]=b}null!==this.b&&(b=this.b,b=b.w(),a[1]=b);null!==this.f&&(b=this.f,a[2]=b);null!==this.g&&(b=this.g,a[4]=b);null!==this.h&&(b=this.h,a[5]=b);null!==this.j&&(b=this.j,a[6]=b);null!==this.i&&(b=this.i,a[8]=b);null!==this.c&&(b=this.c,a[9]=b);return a};Zy.prototype.getExtension=function(){return null};function ez(){return new Zy} +function fz(a){if(null===a)a=null;else{var b=new Zy;if(b.a)for(var c=0;c<b.a.length;c++){var d=b.a[c];d&&(d.a=null,d.b=null)}b.a=null;(c=b.b)&&Wk(c);b.b=null;b.f=null;b.g=null;b.h=null;b.j=null;b.i=null;b.c=null;b.a=Bd(a.a,bz);b.b=a.b?Vk(a.b):null;b.f=a.f;b.g=a.g;b.h=a.h;b.j=a.j;b.i=a.i;b.c=a.c;a=b}return a}function gz(){} +function hz(a,b){for(;G(b);)switch(b.a){case 1:var c=new Yy;O(b,c,cz);a.a=a.a||[];a.a.push(c);break;case 2:c=new Sk;O(b,c,Xk);a.b=c;break;case 3:c=J(b);a.f=c;break;case 5:c=J(b);a.g=c;break;case 6:c=J(b);a.h=c;break;case 7:c=J(b);a.j=c;break;case 9:c=N(b);a.i=c;break;case 10:c=N(b);a.c=c;break;default:H(b)}}function iz(a,b){return a===b?!0:null===a||null===b?!1:Dd(a.a,b.a,dz)&&Zk(a.b,b.b)&&a.f===b.f&&a.g===b.g&&a.h===b.h&&a.j===b.j&&a.i===b.i&&a.c===b.c?!0:!1} +$y.prototype.w=function(){var a=[];if(null!==this.b){var b=this.b;a[0]=b}null!==this.a&&(b=this.a,b=b.w(),a[1]=b);null!==this.c&&(b=this.c,a[2]=b);null!==this.g&&(b=this.g,a[3]=b);null!==this.f&&(b=this.f,a[4]=b);return a};$y.prototype.getExtension=function(){return null};az.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;a[0]=b}null!==this.b&&(b=this.b,a[1]=b);return a};az.prototype.getExtension=function(){return null};function jz(){this.a=this.b=this.c=null}function kz(){this.a=null}function lz(){this.a=null}jz.prototype.w=function(){var a=[];if(null!==this.c){var b=this.c;b=b.w();a[0]=b}null!==this.b&&(b=this.b,b=b.w(),a[1]=b);null!==this.a&&(b=this.a,b=b.w(),a[3]=b);return a};jz.prototype.getExtension=function(){return null};function mz(){return new jz} +function nz(a){if(null===a)var b=null;else{b=new jz;var c=b.c;c&&cj(c);b.c=null;if(c=b.b)c.a=null;b.b=null;if(c=b.a)c.a=null;b.a=null;b.c=a.c?bj(a.c):null;if(a.b){c=a.b;var d=new kz;d.a=null;d.a=c.a;c=d}else c=null;b.b=c;a.a?(a=a.a,c=new lz,c.a=null,c.a=a.a,a=c):a=null;b.a=a}return b}function oz(){}function pz(a,b){for(;G(b);)switch(b.a){case 1:var c=new $i;O(b,c,dj);a.c=c;break;case 2:c=new kz;O(b,c,qz);a.b=c;break;case 4:c=new lz;O(b,c,rz);a.a=c;break;default:H(b)}} +function sz(a,b){if(a===b)b=!0;else if(null===a||null===b)b=!1;else{var c;if(c=ej(a.c,b.c)){c=a.b;var d=b.b;c=c===d?!0:null===c||null===d?!1:c.a!==d.a?!1:!0}c&&(a=a.a,b=b.a,c=a===b?!0:null===a||null===b?!1:a.a!==b.a?!1:!0);b=c?!0:!1}return b}kz.prototype.w=function(){var a=[];null!==this.a&&(a[0]=this.a);return a};kz.prototype.getExtension=function(){return null};function qz(a,b){for(;G(b);)switch(b.a){case 1:a.a=N(b);break;default:H(b)}} +lz.prototype.w=function(){var a=[];null!==this.a&&(a[0]=this.a);return a};lz.prototype.getExtension=function(){return null};function rz(a,b){for(;G(b);)switch(b.a){case 1:a.a=L(b);break;default:H(b)}};function tz(){this.a=this.h=this.b=this.c=this.g=this.f=null}tz.prototype.w=function(){var a=[];if(null!==this.f){var b=this.f;a[0]=b}null!==this.g&&(b=this.g,a[1]=b);null!==this.c&&(b=this.c,a[2]=b);null!==this.b&&(b=this.b,a[3]=b);null!==this.h&&(b=this.h,a[4]=b);null!==this.a&&(b=this.a,a[5]=b);return a};tz.prototype.getExtension=function(){return null};function uz(){this.a=null}uz.prototype.w=function(){var a=[];null!==this.a&&(a[0]=this.a);return a};uz.prototype.getExtension=function(){return null};function vz(a,b){for(;G(b);)switch(b.a){case 1:a.a=N(b);break;default:H(b)}};function wz(){this.l=this.s=this.g=this.o=this.f=this.b=this.j=this.i=this.h=this.c=this.a=this.m=null} +wz.prototype.w=function(){var a=[];if(null!==this.m){var b=this.m;a[0]=b}null!==this.a&&(b=this.a,b=b.slice(),a[1]=b);null!==this.c&&(b=this.c,b=b.slice(),a[2]=b);null!==this.h&&(b=this.h,b=b.w(),a[3]=b);null!==this.i&&(b=this.i,a[4]=b);null!==this.j&&(b=this.j,a[5]=b);null!==this.b&&(b=this.b,b=b.slice(),a[6]=b);null!==this.f&&(b=this.f,b=b.slice(),a[7]=b);null!==this.o&&(b=this.o,a[8]=b);null!==this.g&&(b=this.g,b=b.w(),a[9]=b);null!==this.s&&(b=this.s,a[10]=b);null!==this.l&&(b=this.l,a[11]=b); +return a};function xz(a){a.m=null;a.a=null;a.c=null;var b=a.h;b&&Mi(b);a.h=null;a.i=null;a.j=null;a.b=null;a.f=null;a.o=null;if(b=a.g)b.a=null;a.g=null;a.s=null;a.l=null}wz.prototype.getExtension=function(){return null}; +function yz(a,b){for(;G(b);)switch(b.a){case 1:var c=L(b);a.m=c;break;case 2:c=N(b);a.a=a.a||[];a.a.push(c);break;case 3:c=N(b);a.c=a.c||[];a.c.push(c);break;case 4:c=new Ki;O(b,c,Ni);a.h=c;break;case 5:c=N(b);a.i=c;break;case 6:c=N(b);a.j=c;break;case 7:c=J(b);a.b=a.b||[];a.b.push(c);break;case 8:c=N(b);a.f=a.f||[];a.f.push(c);break;case 9:c=K(b);a.o=c;break;case 10:c=new uz;O(b,c,vz);a.g=c;break;case 11:c=N(b);a.s=c;break;case 12:c=J(b);a.l=c;break;default:H(b)}} +wz.prototype.Gb=function(a){this.i=a};function zz(){this.a=null}zz.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;b=b.w();a[0]=b}return a};zz.prototype.getExtension=function(){return null};function Az(){return new zz} +function Bz(a){if(null===a)var b=null;else{b=new zz;var c=b.a;c&&xz(c);b.a=null;if(a.a){c=new wz;a=a.a;xz(c);c.m=a.m;c.a=Ad(a.a);c.c=Ad(a.c);c.h=a.h?Li(a.h):null;c.i=a.i;c.j=a.j;c.b=Ad(a.b);c.f=Ad(a.f);c.o=a.o;if(a.g){var d=new uz;var e=a.g;d.a=null;d.a=e.a}else d=null;c.g=d;c.s=a.s;c.l=a.l}else c=null;b.a=c}return b}function Cz(){}function Dz(a,b){for(;G(b);)switch(b.a){case 1:var c=new wz;O(b,c,yz);a.a=c;break;default:H(b)}} +function Ez(a,b){if(a===b)a=!0;else if(null===a||null===b)a=!1;else{a=a.a;b=b.a;var c;if(!(c=a===b)){if(null===a||null===b)a=0;else{if(c=a.m===b.m&&Cd(a.a,b.a)&&Cd(a.c,b.c)&&Oi(a.h,b.h)&&a.i===b.i&&a.j===b.j&&Cd(a.b,b.b)&&Cd(a.f,b.f)&&a.o===b.o){c=a.g;var d=b.g;c=c===d?!0:null===c||null===d?!1:c.a!==d.a?!1:!0}a=c&&a.s===b.s&&a.l===b.l}c=a}a=c?!0:!1}return a};function Fz(){this.a=null}Fz.prototype.w=function(){var a=[];null!==this.a&&(a[0]=this.a);return a};Fz.prototype.getExtension=function(){return null};function Gz(){this.a=null}Gz.prototype.w=function(){var a=[];null!==this.a&&(a[0]=this.a);return a};Gz.prototype.getExtension=function(){return null};function Hz(){this.j=this.a=this.c=this.b=this.i=this.h=this.f=this.g=null}function Iz(){this.a=null}Hz.prototype.w=function(){var a=[];if(null!==this.g){var b=this.g;a[0]=b}null!==this.f&&(b=this.f,a[1]=b);null!==this.h&&(b=this.h,b=Oc(b,!1),a[2]=b);null!==this.i&&(b=this.i,b=Oc(b,!1),a[3]=b);null!==this.b&&(b=this.b,a[4]=b);null!==this.c&&(b=this.c,a[5]=b);null!==this.a&&(b=this.a,a[6]=b);null!==this.j&&(b=this.j,a[7]=b);return a};Hz.prototype.getExtension=function(){return null}; +function Jz(){return new Hz}function Kz(a){if(null===a)a=null;else{var b=new Hz;b.g=null;b.f=null;b.h=null;b.i=null;b.b=null;b.c=null;b.a=null;b.j=null;b.g=a.g;b.f=a.f;b.h=a.h;b.i=a.i;b.b=a.b;b.c=a.c;b.a=a.a;b.j=a.j;a=b}return a}function Lz(){} +function Mz(a,b){for(;G(b);)switch(b.a){case 1:var c=L(b);a.g=c;break;case 2:c=L(b);a.f=c;break;case 3:c=pd(b);a.h=c;break;case 4:c=pd(b);a.i=c;break;case 5:c=L(b);a.b=c;break;case 6:c=K(b);a.c=c;break;case 7:c=K(b);a.a=c;break;case 8:c=K(b);a.j=c;break;default:H(b)}}function Nz(a,b){return a===b?!0:null===a||null===b?!1:a.g!==b.g||a.f!==b.f||a.h!==b.h||a.i!==b.i||a.b!==b.b||a.c!==b.c||a.a!==b.a||a.j!==b.j?!1:!0}Iz.prototype.w=function(){var a=[];null!==this.a&&(a[0]=this.a);return a}; +Iz.prototype.getExtension=function(){return null};yd(qx,53863091,11,Jz,Lz,Mz,Kz,Nz);yd(qx,32819068,11,ut,At,Bt,vt,Et);yd(qx,42466818,11,Ht,Kt,Lt,It,Nt);yd(qx,52617685,11,function(){return new st},function(){},Qt,function(a){return null===a?null:zt(a)},Gt);yd(qx,40154408,11,Az,Cz,Dz,Bz,Ez);yd(qx,30096869,11,mz,oz,pz,nz,sz);yd(qx,51650189,11,ft,jt,kt,gt,mt); +yd(qx,177034656,11,function(){return new Iz},function(){},function(a,b){for(;G(b);)switch(b.a){case 1:a.a=K(b);break;default:H(b)}},function(a){if(null===a)a=null;else{var b=new Iz;b.a=null;b.a=a.a;a=b}return a},function(a,b){return a===b?!0:null===a||null===b?!1:a.a!==b.a?!1:!0});yd(Ow,28517612,11,ez,gz,hz,fz,iz); +yd(Ow,48343962,11,function(){return new $y},function(){},function(a,b){for(;G(b);)switch(b.a){case 1:var c=K(b);a.b=c;break;case 2:c=new Sk;O(b,c,Xk);a.a=c;break;case 3:c=L(b);a.c=c;break;case 4:c=L(b);a.g=c;break;case 5:c=L(b);a.f=c;break;default:H(b)}},function(a){if(null===a)a=null;else{var b=new $y;b.b=null;var c=b.a;c&&Wk(c);b.a=null;b.c=null;b.g=null;b.f=null;b.b=a.b;b.a=a.a?Vk(a.a):null;b.c=a.c;b.g=a.g;b.f=a.f;a=b}return a},function(a,b){return a===b?!0:null===a||null===b?!1:a.b===b.b&&Zk(a.a, +b.a)&&a.c===b.c&&a.g===b.g&&a.f===b.f?!0:!1});yd(Ow,49095464,11,function(){return new az},function(){},function(a,b){for(;G(b);)switch(b.a){case 1:var c=J(b);a.a=c;break;case 2:c=J(b);a.b=c;break;default:H(b)}},function(a){if(null===a)a=null;else{var b=new az;b.a=null;b.b=null;b.a=a.a;b.b=a.b;a=b}return a},function(a,b){return a===b?!0:null===a||null===b?!1:a.a!==b.a||a.b!==b.b?!1:!0});yd(Ow,30096869,11,mz,oz,pz,nz,sz); +yd(Ow,132080860,11,function(){return new Fz},function(){},function(a,b){for(;G(b);)switch(b.a){case 1:a.a=L(b);break;default:H(b)}},function(a){if(null===a)a=null;else{var b=new Fz;b.a=null;b.a=a.a;a=b}return a},function(a,b){return a===b?!0:null===a||null===b?!1:a.a!==b.a?!1:!0});yd(Ow,51650189,11,ft,jt,kt,gt,mt);yd(Ow,53863091,11,Jz,Lz,Mz,Kz,Nz); +yd(yu,30929027,11,function(){return new Vy},function(){},function(a,b){for(;G(b);)switch(b.a){case 1:a.a=J(b);break;default:H(b)}},function(a){if(null===a)a=null;else{var b=new Vy;b.a=null;b.a=a.a;a=b}return a},function(a,b){return a===b?!0:null===a||null===b?!1:a.a!==b.a?!1:!0}); +yd(yu,66786615,11,function(){return new Wy},function(){},function(a,b){for(;G(b);)switch(b.a){case 1:var c=J(b);a.b=c;break;case 2:c=new wi;O(b,c,Bi);a.a=c;break;case 3:c=J(b);a.c=c;break;default:H(b)}},function(a){if(null===a)a=null;else{var b=new Wy;b.b=null;var c=b.a;c&&Ai(c);b.a=null;b.c=null;b.b=a.b;b.a=a.a?zi(a.a):null;b.c=a.c;a=b}return a},function(a,b){return a===b?!0:null===a||null===b?!1:a.b===b.b&&Ci(a.a,b.a)&&a.c===b.c?!0:!1});yd(yu,28517612,11,ez,gz,hz,fz,iz); +yd(yu,30511227,11,function(){return new Sy},function(){},function(a,b){for(;G(b);)switch(b.a){case 1:var c=new Ki;O(b,c,Ni);a.a=c;break;case 3:c=new Ty;O(b,c,Uy);a.b=c;break;default:H(b)}},function(a){if(null===a)a=null;else{var b=new Sy,c=b.a;c&&Mi(c);b.a=null;b.b=null;b.a=a.a?Li(a.a):null;b.b=a.b?new Ty:null;a=b}return a},function(a,b){if(a===b)b=!0;else if(null===a||null===b)b=!1;else{var c;if(c=Oi(a.a,b.a))a=a.b,b=b.b,c=a===b?!0:null===a||null===b?!1:!0;b=c?!0:!1}return b}); +yd(yu,30096869,11,mz,oz,pz,nz,sz); +yd(yu,172661375,11,function(){return new tz},function(){},function(a,b){for(;G(b);)switch(b.a){case 1:var c=L(b);a.f=c;break;case 2:c=L(b);a.g=c;break;case 3:c=L(b);a.c=c;break;case 4:c=M(b);a.b=c;break;case 5:c=M(b);a.h=c;break;case 6:c=K(b);a.a=c;break;default:H(b)}},function(a){if(null===a)a=null;else{var b=new tz;b.f=null;b.g=null;b.c=null;b.b=null;b.h=null;b.a=null;b.f=a.f;b.g=a.g;b.c=a.c;b.b=a.b;b.h=a.h;b.a=a.a;a=b}return a},function(a,b){return a===b?!0:null===a||null===b?!1:a.f!==b.f||a.g!== +b.g||a.c!==b.c||a.b!==b.b||a.h!==b.h||a.a!==b.a?!1:!0});yd(yu,33356690,11,function(){return new Gz},function(){},function(a,b){for(;G(b);)switch(b.a){case 1:a.a=N(b);break;default:H(b)}},function(a){if(null===a)a=null;else{var b=new Gz;b.a=null;b.a=a.a;a=b}return a},function(a,b){return a===b?!0:null===a||null===b?!1:a.a!==b.a?!1:!0}); +yd(yu,40251317,11,function(){return new Xy},function(){},function(a,b){for(;G(b);)switch(b.a){case 1:var c=J(b);a.a=c;break;case 2:c=J(b);a.b=c;break;default:H(b)}},function(a){if(null===a)a=null;else{var b=new Xy;b.a=null;b.b=null;b.a=a.a;b.b=a.b;a=b}return a},function(a,b){return a===b?!0:null===a||null===b?!1:a.a!==b.a||a.b!==b.b?!1:!0}); +yd(yu,43229016,11,function(){return new Ry},function(){},function(a,b){for(;G(b);)switch(b.a){case 1:var c=pd(b);a.g=c;break;case 2:c=L(b);a.b=c;break;case 3:c=L(b);a.c=c;break;case 4:c=J(b);a.h=c;break;case 5:c=L(b);a.f=c;break;case 6:c=L(b);a.a=a.a||[];a.a.push(c);break;default:H(b)}},function(a){if(null===a)a=null;else{var b=new Ry;b.g=null;b.b=null;b.c=null;b.h=null;b.f=null;b.a=null;b.g=a.g;b.b=a.b;b.c=a.c;b.h=a.h;b.f=a.f;b.a=Ad(a.a);a=b}return a},function(a,b){return a===b?!0:null===a||null=== +b?!1:a.g===b.g&&a.b===b.b&&a.c===b.c&&a.h===b.h&&a.f===b.f&&Cd(a.a,b.a)?!0:!1});yd(yu,51650189,11,ft,jt,kt,gt,mt);yd(yu,40154408,11,Az,Cz,Dz,Bz,Ez); +yd(yu,60681369,11,function(){return new Qy},function(){},function(a,b){for(;G(b);)switch(b.a){case 1:var c=L(b);a.a=c;break;case 2:c=L(b);a.b=c;break;case 3:c=L(b);a.c=c;break;default:H(b)}},function(a){if(null===a)a=null;else{var b=new Qy;b.a=null;b.b=null;b.c=null;b.a=a.a;b.b=a.b;b.c=a.c;a=b}return a},function(a,b){return a===b?!0:null===a||null===b?!1:a.a!==b.a||a.b!==b.b||a.c!==b.c?!1:!0}); +yd(yu,135491995,11,function(){return new Py},function(){},function(a,b){for(;G(b);)switch(b.a){case 1:var c=L(b);a.c=c;break;case 2:c=qd(b);a.g=c;break;case 3:c=L(b);a.b=c;break;case 4:c=K(b);a.f=c;break;case 5:c=L(b);a.a=c;break;default:H(b)}},function(a){if(null===a)a=null;else{var b=new Py;b.c=null;b.g=null;b.b=null;b.f=null;b.a=null;b.c=a.c;b.g=a.g;b.b=a.b;b.f=a.f;b.a=a.a;a=b}return a},function(a,b){return a===b?!0:null===a||null===b?!1:a.c!==b.c||a.g!==b.g||a.b!==b.b||a.f!==b.f||a.a!==b.a?!1: +!0}); +yd(yu,137907910,11,function(){return new My},function(){},function(a,b){for(;G(b);)switch(b.a){case 2:var c=new Ny;O(b,c,Oy);a.a=c;break;case 3:c=N(b);a.b=c;break;default:H(b)}},function(a){if(null===a)a=null;else{var b=new My,c=b.a;c&&(c.a=null,c.b=null);b.a=null;b.b=null;if(a.a){c=a.a;var d=new Ny;d.a=null;d.b=null;d.a=c.a;d.b=c.b;c=d}else c=null;b.a=c;b.b=a.b;a=b}return a},function(a,b){if(a===b)a=!0;else if(null===a||null===b)a=!1;else{var c=a.a,d=b.a;a=c!==d&&(null===c||null===d||c.a!==d.a|| +c.b!==d.b)||a.b!==b.b?!1:!0}return a});yd(yu,53863091,11,Jz,Lz,Mz,Kz,Nz);yd(yu,42466818,11,Ht,Kt,Lt,It,Nt);yd(Fx,53863091,11,Jz,Lz,Mz,Kz,Nz);yd(Fx,85448653,11,ut,At,Bt,vt,Et);yd(qx,69077470,8);yd(Fx,36512758,8);function Oz(a){this.data=a||[]}var Pz;F(Oz,W);function Qz(){Pz||(Pz={a:-1,F:[]},Pz.F=[,be,be,be,ae(256)]);return Pz}Oz.prototype.getZoom=function(){return X(this,0)};function Rz(){this.b=new Uint8Array(840);this.c=0;this.j=this.s=this.l=this.D=!1;this.B=null;this.C=0;this.u=this.A=this.v=this.m=null;this.o=0;this.i=this.h=this.g=this.a=this.f=null}var Sz={Zd:0,$d:4,Tc:8,nd:10,Tf:12};Rz.prototype.G=function(){return this.B};function Tz(a,b){return a[b]%128*4+a[b+1]/64}function Uz(a,b){return(a.b[b+0]<<16|a.b[b+1]<<8|a.b[b+2]|a.b[b+3]<<24)>>>0} +function Vz(a,b,c,d){var e=a.b[c+3];0==a.b[b+3]?d=1:0==e&&(d=0);e=0|$n(a.b[b],a.b[c],d)<<16;e|=$n(a.b[b+1],a.b[c+1],d)<<8;e|=$n(a.b[b+2],a.b[c+2],d);e|=$n(a.b[b+3],a.b[c+3],d)<<24;return e>>>0}function Wz(a,b){a=a[b];128<a&&(a=-(a-128));return a/8}function Xz(a,b){if(0<a.o)return!1;for(var c=0;c<a.c;c++)if(0!=Yz(a,c,b)||null!=Zz(a,c,b))return!1;return!0}function $z(a){return 0==a.c&&!a.C&&!a.D&&!a.l&&!a.s&&!a.j&&!a.o} +function aA(a,b){var c=Math.floor(b);if(bA(a,c))return aA(cA,b);if(c==b)return Uz(a,36*c+12);var d=Math.ceil(b);return Vz(a,36*c+12,36*d+12,(b-c)/(d-c))}function dA(a,b){var c=Math.floor(b);if(bA(a,c))return 0;if(c==b)return Uz(a,36*c+16);var d=Math.ceil(b);return Vz(a,36*c+16,36*d+16,(b-c)/(d-c))}function eA(a,b){var c=Math.floor(b);if(bA(a,c))return 0;if(c==b)return Uz(a,36*c+20);var d=Math.ceil(b);return Vz(a,36*c+20,36*d+20,(b-c)/(d-c))} +function fA(a,b){return a.m&&a.m[b]&&!bA(a,b)?a.m[b]:null}function gA(a,b){if(!a.a||!a.a[b])return 0;a=dw(a.a[b]);return null==a.a?0:a.a}function hA(a,b){if(!a.a||!a.a[b])return 0;a=dw(a.a[b]);return null==a.b?0:a.b}function iA(a,b){if(!a.a||!a.a[b])return 0;a=dw(a.a[b]);return(null==a.g?0:a.g)/1E3}function jA(a,b){if(!a.a||!a.a[b])return 0;a=a.a[b];return null!=a.a&&(a=ew(a),null!=a.c)?null==a.c?0:a.c:0}function kA(a,b){return a.a&&a.a[b]&&null!=a.a[b].l?!0:!1} +function lA(a,b){if(!a.a||!a.a[b])return 0;a=a.a[b];return null!=a.a&&(a=ew(a),null!=a.f)?null==a.f?0:a.f:0}function mA(a,b){var c=nA;if(!a.a||!a.a[b])return null;a=a.a[b];return null!=a.a?(a=ew(a),c.width=null==a.h?0:a.h,c.height=null==a.i?0:a.i,c):null} +function oA(a,b){if(a.f){if(a.f[b])return a=a.f[b],null==a.g?0:a.g}else if(a.a){if(a.a[b])return a=a.a[b],null==a.m?0:a.m}else if(a.g){if(a.g[b])return a=a.g[b],null==a.h?0:a.h}else if(a.h){if(a.h[b])return a=a.h[b],null==a.b?-1:a.b}else if(a.i&&a.i[b])return a=a.i[b],null==a.f?0:a.f;return 0} +function bA(a,b){if(a.f){if(a.f[b]){var c=a.f[b];if(c=null==c.c?!1:c.c)a=a.f[b],c=null==a.h?!1:a.h;return c}}else if(a.a){if(a.a[b])return a=a.a[b],null==a.h?!1:a.h}else if(a.g){if(a.g[b])return a=a.g[b],null==a.g?!1:a.g}else if(a.h){if(a.h[b])return a=a.h[b],null==a.a?!1:a.a}else if(a.i&&a.i[b])return a=a.i[b],null==a.c?!1:a.c;return!1} +function pA(a,b,c){for(var d=0;12>d;d++)c[d]=a.b[d];d=Math.floor(b);if(bA(a,d))for(b=12,d=0;36>d;d++)c[12+d]=cA.b[b+d];else if(b==d)for(b=12+36*b,d=0;36>d;d++)c[12+d]=a.b[b+d];else{var e=Math.ceil(b),f=qA(a,d);a=qA(a,e);c=c.subarray(12);rA(f,a,c,(b-d)/(e-d),sA(d,e,b))}}function qA(a,b){b=12+36*b;return a.b.subarray(b,b+36)}function tA(a,b,c){var d=Math.floor(c);if(bA(a,d))return 0;if(d==c)return Uz(a,36*c+24+12*b+0);var e=Math.ceil(c);return Vz(a,36*d+24+12*b+0,36*e+24+12*b+0,(c-d)/(e-d))} +function uA(a,b,c){var d=Math.floor(c);if(bA(a,d))return 0;var e=Tz(a.b,36*d+24+12*b+4);if(d==c)return e;var f=Math.ceil(c);a=Tz(a.b,36*f+24+12*b+4);return a==e?e:$n(e,a,sA(d,f,c))}function Yz(a,b,c){var d=Math.floor(c),e=Wz(a.b,36*d+24+12*b+10);if(d==c)return e;var f=Math.ceil(c);a=Wz(a.b,36*f+24+12*b+10);return a==e?e:$n(e,a,sA(d,f,c))}function Zz(a,b,c){c=Math.ceil(c);c=36*c+24+12*b+8;b=a.b[c+0]/2;a=a.b[c+1]/2;return 0==b&&0==a?null:[b,a]}function vA(a,b,c){return a?(a=a[b])&&a[c]||null:null} +function wA(a,b){if(a==b)return!0;if(!a||!b||a.length!=b.length)return!1;for(var c=0;c<a.length;c++)if(!xA(a[c],b[c]))return!1;return!0}function xA(a,b){if(a==b)return!0;if(!a||!b||a.length!=b.length)return!1;for(var c=0;c<a.length;c++){var d=a[c],e=b[c];if(!(d===e||d&&e&&d.a==e.a&&d.b==e.b))return!1}return!0} +function yA(a,b){if(a===b)return!0;if(null==a||null==b||a.c!=b.c||a.D!=b.D||a.l!=b.l||a.s!=b.s||a.j!=b.j)return!1;if(a.C&&b.C){if(!xA(a.m,b.m))return!1}else if(a.C||b.C)return!1;if(a.o&&b.o){if(!wA(a.v,b.v)||!wA(a.A,b.A)||!wA(a.u,b.u))return!1}else if(a.o||b.o)return!1;for(var c=0;840>c;++c)if(a.b[c]!=b.b[c])return!1;return!0}function zA(){this.style=new Rz}function AA(a){var b=null;if(a){b=[];for(var c=0;c<a.length;c++)a[c]&&(b[c]=Va(a[c]))}return b}function BA(a,b){a.style.c>b||(a.style.c=b)} +function CA(a,b,c){if(!a.style.m)if(c)a.style.m=[];else return;a.style.m[b]&&a.style.C--;(a.style.m[b]=c)&&a.style.C++}function DA(a,b,c){a.style.h||(a.style.h=[]);a=a.style.h;var d=new Zu;nv(d);d.b=c.b;d.a=c.a;d.f=Ad(c.f);d.c=c.c;d.g=c.g;d.h=c.h;a[b]=d}function EA(a,b,c){a.style.b[b+0]=c>>16&255;a.style.b[b+1]=c>>8&255;a.style.b[b+2]=c&255;a.style.b[b+3]=c>>24&255}function FA(a,b,c){a=a.style.b;a[b]=Math.floor(c/4%128);a[b+1]=Math.floor(64*c)%256} +function GA(a,b,c,d,e){var f=null;if(!b){if(!e)return null;f=b=[]}if(!b[c]){if(!e)return null;b[c]=[]}(b[c][d]=e)&&a.style.o++;return f}function HA(a,b,c,d){if(b=GA(a,a.style.v,b,c,d))a.style.v=b}function IA(a,b,c,d){if(b=GA(a,a.style.A,b,c,d))a.style.A=b}function JA(a,b,c,d){if(b=GA(a,a.style.u,b,c,d))a.style.u=b} +function KA(a,b,c){if(b>c)KA(a,c,b);else if(!(1>=c-b)){var d=qA(a.style,b);if(d){var e=qA(a.style,c);if(e){for(var f=b+1;f<c;f++){var g=qA(a.style,f);if(!g)return;rA(d,e,g,(f-b)/(c-b),sA(b,c,f))}for(f=b+1;f<c;f++)for(CA(a,f,fA(a.style,b)),d=0;d<a.style.c;d++)HA(a,d,f,vA(a.style.v,d,b)),IA(a,d,f,vA(a.style.A,d,b)),JA(a,d,f,vA(a.style.u,d,b));for(f=b+1;f<c;f++)d=a.style,e=b,g=f,d.f?d.f[g]=d.f[e]:d.a?d.a[g]=d.a[e]:d.g?d.g[g]=d.g[e]:d.h?d.h[g]=d.h[e]:d.i&&(d.i[g]=d.i[e])}}}} +function sA(a,b,c){a=Math.pow(2,a);return(Math.pow(2,c)-a)/(Math.pow(2,b)-a)} +function rA(a,b,c,d,e){function f(e){var f=a[e+3],g=b[e+3];0<f&&0<g?(c[e]=$n(a[e],b[e],d),c[e+1]=$n(a[e+1],b[e+1],d),c[e+2]=$n(a[e+2],b[e+2],d)):0<f?(c[e]=a[e],c[e+1]=a[e+1],c[e+2]=a[e+2]):0<g&&(c[e]=b[e],c[e+1]=b[e+1],c[e+2]=b[e+2]);c[e+3]=$n(a[e+3],b[e+3],d)}function g(d){var f=$n(Tz(a,d),Tz(b,d),e);c[d]=Math.floor(f/4%128);c[d+1]=Math.floor(64*f)%256}function h(d){var f=8*$n(Wz(a,d+l.nd),Wz(b,d+l.nd),e);0>f&&(f=-f+128);c[d+l.nd]=Math.floor(f)}function k(a){c[a+l.Tc]=b[a+l.Tc];c[a+l.Tc+1]=b[a+l.Tc+ +1]}var l=Sz;f(0);f(4);f(8);f(12+l.Zd);g(12+l.$d);h(12);k(12);f(24+l.Zd);g(24+l.$d);h(24);k(24)}var cA=new Rz;function LA(a){Pp.call(this);this.h=a;this.f={};this.f[0]=cA;this.b=0;this.c=this.a=null;this.g=1}F(LA,Pp);function MA(a,b,c){a.a=b;a.c=c||null}LA.prototype.X=function(){this.c=this.a=null};function NA(a){this.f=a;this.b=[];this.a=[];this.c=!1}function OA(a,b){a=qr(a.f,"A"+a.b[b]);return-1==a?0:a};function PA(a,b,c){Pp.call(this);this.j=a;this.h=b;this.a=null;this.g={};this.c=[];this.f=this.b=null;this.i=c}F(PA,Pp);function QA(a){var b=a.c.length-1;a=a.h.b;return b>a?b:a}function RA(a,b){var c=a.c[b];a=c?c:(a=a.h.f[b])?a:cA;return a}function SA(a,b){for(var c=[],d=[],e=a.c,f=0;f<b.length;++f){var g=b[f],h=g.G(),k=e[h];k&&yA(k,g)||(e[h]=g,c.push(h),d.push(g))}c.length&&a.b&&a.b.call(a.f,c,d)} +function TA(a,b){if(a.a){for(var c=[],d=0;d<b.length;++d){var e=b[d],f=a.g[e];B(f)&&(c.push(f),delete a.g[e])}if(c.length){b=a.j;d=a.a;e=[];for(f=0;f<c.length;++f)UA(b,d,c[f],e);SA(a,e)}}}function VA(a,b,c){a.b=b;a.f=c||null}function WA(a){a.b=null;a.f=null}PA.prototype.X=function(){WA(this)};var XA="StopIteration"in x?x.StopIteration:{message:"StopIteration",stack:""};function YA(){}YA.prototype.next=function(){throw XA;};YA.prototype.od=function(){return this};function ZA(a){if(a instanceof YA)return a;if("function"==typeof a.od)return a.od(!1);if(xa(a)){var b=0,c=new YA;c.next=function(){for(;;){if(b>=a.length)throw XA;if(b in a)return a[b++];b++}};return c}throw Error("Not implemented");} +function $A(a,b){if(xa(a))try{Ma(a,b,void 0)}catch(c){if(c!==XA)throw c;}else{a=ZA(a);try{for(;;)b.call(void 0,a.next(),void 0,a)}catch(c){if(c!==XA)throw c;}}};function aB(a,b){this.b={};this.a=[];this.f=this.c=0;var c=arguments.length;if(1<c){if(c%2)throw Error("Uneven number of arguments");for(var d=0;d<c;d+=2)this.set(arguments[d],arguments[d+1])}else if(a)if(a instanceof aB)for(c=a.nb(),d=0;d<c.length;d++)this.set(c[d],a.get(c[d]));else for(d in a)this.set(d,a[d])}r=aB.prototype;r.ob=function(){bB(this);for(var a=[],b=0;b<this.a.length;b++)a.push(this.b[this.a[b]]);return a};r.nb=function(){bB(this);return this.a.concat()}; +r.clear=function(){this.b={};this.f=this.c=this.a.length=0};function bB(a){if(a.c!=a.a.length){for(var b=0,c=0;b<a.a.length;){var d=a.a[b];cB(a.b,d)&&(a.a[c++]=d);b++}a.a.length=c}if(a.c!=a.a.length){var e={};for(c=b=0;b<a.a.length;)d=a.a[b],cB(e,d)||(a.a[c++]=d,e[d]=1),b++;a.a.length=c}}r.get=function(a,b){return cB(this.b,a)?this.b[a]:b};r.set=function(a,b){cB(this.b,a)||(this.c++,this.a.push(a),this.f++);this.b[a]=b}; +r.forEach=function(a,b){for(var c=this.nb(),d=0;d<c.length;d++){var e=c[d],f=this.get(e);a.call(b,f,e,this)}};r.od=function(a){bB(this);var b=0,c=this.f,d=this,e=new YA;e.next=function(){if(c!=d.f)throw Error("The map has changed since the iterator was created");if(b>=d.a.length)throw XA;var e=d.a[b++];return a?e:d.b[e]};return e};function cB(a,b){return Object.prototype.hasOwnProperty.call(a,b)};function dB(a){if(a.ob&&"function"==typeof a.ob)return a.ob();if(pa(a))return a.split("");if(xa(a)){for(var b=[],c=a.length,d=0;d<c;d++)b.push(a[d]);return b}b=[];c=0;for(d in a)b[c++]=a[d];return b} +function eB(a,b,c){if(a.forEach&&"function"==typeof a.forEach)a.forEach(b,c);else if(xa(a)||pa(a))Ma(a,b,c);else{if(a.nb&&"function"==typeof a.nb)var d=a.nb();else if(a.ob&&"function"==typeof a.ob)d=void 0;else if(xa(a)||pa(a)){d=[];for(var e=a.length,f=0;f<e;f++)d.push(f)}else for(f in d=[],e=0,a)d[e++]=f;e=dB(a);f=e.length;for(var g=0;g<f;g++)b.call(c,e[g],d&&d[g],a)}};var fB=/^(?:([^:/?#.]+):)?(?:\/\/(?:([^/?#]*)@)?([^/#?]*?)(?::([0-9]+))?(?=[/#?]|$))?([^?#]+)?(?:\?([^#]*))?(?:#([\s\S]*))?$/;function gB(a,b){if(a){a=a.split("&");for(var c=0;c<a.length;c++){var d=a[c].indexOf("="),e=null;if(0<=d){var f=a[c].substring(0,d);e=a[c].substring(d+1)}else f=a[c];b(f,e?decodeURIComponent(e.replace(/\+/g," ")):"")}}} +function hB(a,b){if(!b)return a;var c=a.indexOf("#");0>c&&(c=a.length);var d=a.indexOf("?");if(0>d||d>c){d=c;var e=""}else e=a.substring(d+1,c);a=[a.substr(0,d),e,a.substr(c)];c=a[1];a[1]=b?c?c+"&"+b:b:c;return a[0]+(a[1]?"?"+a[1]:"")+a[2]}function iB(a,b,c){if(va(b))for(var d=0;d<b.length;d++)iB(a,String(b[d]),c);else null!=b&&c.push(a+(""===b?"":"="+encodeURIComponent(String(b))))}function jB(a,b){var c=[];for(b=b||0;b<a.length;b+=2)iB(a[b],a[b+1],c);return c.join("&")} +function kB(a){var b=[],c;for(c in a)iB(c,a[c],b);return b.join("&")}function lB(a,b){var c=2==arguments.length?jB(arguments[1],0):jB(arguments,1);return hB(a,c)};function mB(a){this.c=this.j=this.b="";this.i=null;this.g=this.h="";this.a=!1;if(a instanceof mB){this.a=B(void 0)?void 0:a.a;nB(this,a.b);this.j=a.j;this.c=a.c;oB(this,a.i);this.h=a.h;var b=a.f;var c=new pB;c.c=b.c;b.a&&(c.a=new aB(b.a),c.b=b.b);qB(this,c);this.g=a.g}else a&&(b=String(a).match(fB))?(this.a=!1,nB(this,b[1]||"",!0),this.j=rB(b[2]||""),this.c=rB(b[3]||"",!0),oB(this,b[4]),this.h=rB(b[5]||"",!0),qB(this,b[6]||"",!0),this.g=rB(b[7]||"")):(this.a=!1,this.f=new pB(null,this.a))} +mB.prototype.toString=function(){var a=[],b=this.b;b&&a.push(sB(b,tB,!0),":");var c=this.c;if(c||"file"==b)a.push("//"),(b=this.j)&&a.push(sB(b,tB,!0),"@"),a.push(encodeURIComponent(String(c)).replace(/%25([0-9a-fA-F]{2})/g,"%$1")),c=this.i,null!=c&&a.push(":",String(c));if(c=this.h)this.c&&"/"!=c.charAt(0)&&a.push("/"),a.push(sB(c,"/"==c.charAt(0)?uB:vB,!0));(c=this.f.toString())&&a.push("?",c);(c=this.g)&&a.push("#",sB(c,wB));return a.join("")}; +function nB(a,b,c){a.b=c?rB(b,!0):b;a.b&&(a.b=a.b.replace(/:$/,""))}function oB(a,b){if(b){b=Number(b);if(isNaN(b)||0>b)throw Error("Bad port number "+b);a.i=b}else a.i=null}function qB(a,b,c){b instanceof pB?(a.f=b,xB(a.f,a.a)):(c||(b=sB(b,yB)),a.f=new pB(b,a.a))}function rB(a,b){return a?b?decodeURI(a.replace(/%25/g,"%2525")):decodeURIComponent(a):""}function sB(a,b,c){return pa(a)?(a=encodeURI(a).replace(b,zB),c&&(a=a.replace(/%25([0-9a-fA-F]{2})/g,"%$1")),a):null} +function zB(a){a=a.charCodeAt(0);return"%"+(a>>4&15).toString(16)+(a&15).toString(16)}var tB=/[#\/\?@]/g,vB=/[#\?:]/g,uB=/[#\?]/g,yB=/[#\?@]/g,wB=/#/g;function pB(a,b){this.b=this.a=null;this.c=a||null;this.f=!!b}function AB(a){a.a||(a.a=new aB,a.b=0,a.c&&gB(a.c,function(b,c){a.add(decodeURIComponent(b.replace(/\+/g," ")),c)}))}r=pB.prototype;r.add=function(a,b){AB(this);this.c=null;a=BB(this,a);var c=this.a.get(a);c||this.a.set(a,c=[]);c.push(b);this.b+=1;return this}; +function CB(a,b){AB(a);b=BB(a,b);cB(a.a.b,b)&&(a.c=null,a.b-=a.a.get(b).length,a=a.a,cB(a.b,b)&&(delete a.b[b],a.c--,a.f++,a.a.length>2*a.c&&bB(a)))}r.clear=function(){this.a=this.c=null;this.b=0};function DB(a,b){AB(a);b=BB(a,b);return cB(a.a.b,b)}r.forEach=function(a,b){AB(this);this.a.forEach(function(c,d){Ma(c,function(c){a.call(b,c,d,this)},this)},this)};r.nb=function(){AB(this);for(var a=this.a.ob(),b=this.a.nb(),c=[],d=0;d<b.length;d++)for(var e=a[d],f=0;f<e.length;f++)c.push(b[d]);return c}; +r.ob=function(a){AB(this);var b=[];if(pa(a))DB(this,a)&&(b=Ua(b,this.a.get(BB(this,a))));else{a=this.a.ob();for(var c=0;c<a.length;c++)b=Ua(b,a[c])}return b};r.set=function(a,b){AB(this);this.c=null;a=BB(this,a);DB(this,a)&&(this.b-=this.a.get(a).length);this.a.set(a,[b]);this.b+=1;return this};r.get=function(a,b){a=a?this.ob(a):[];return 0<a.length?String(a[0]):b}; +r.toString=function(){if(this.c)return this.c;if(!this.a)return"";for(var a=[],b=this.a.nb(),c=0;c<b.length;c++){var d=b[c],e=encodeURIComponent(String(d));d=this.ob(d);for(var f=0;f<d.length;f++){var g=e;""!==d[f]&&(g+="="+encodeURIComponent(String(d[f])));a.push(g)}}return this.c=a.join("&")};function BB(a,b){b=String(b);a.f&&(b=b.toLowerCase());return b} +function xB(a,b){b&&!a.f&&(AB(a),a.c=null,a.a.forEach(function(a,b){var c=b.toLowerCase();b!=c&&(CB(this,b),CB(this,c),0<a.length&&(this.c=null,this.a.set(BB(this,c),Va(a)),this.b+=a.length))},a));a.f=b}r.zf=function(a){for(var b=0;b<arguments.length;b++)eB(arguments[b],function(a,b){this.add(b,a)},this)};function EB(a,b,c,d){c.style.f||(c.style.f=[]);var e=c.style.f,f=new Ou;jv(f);f.a=Bd(a.a,hw);f.f=a.f;f.g=a.g;f.h=a.h;f.c=a.c;f.b=Ad(a.b);f.l=a.l;f.j=a.j;f.i=a.i;e[b]=f;e=[];if(null!=a.a)e=a.a;else if(null!=a.b){f=a.b;for(var g=0;g<f.length;++g)e.push(Pv(d,f[g]))}c.style.c<e.length&&BA(c,e.length);for(g=0;g<e.length;g++)FB(e[g],g,b,c);a=null==a.f?0:a.f;c.style.D=!0;EA(c,36*b+12,a)} +function GB(a,b,c,d,e){d.style.a||(d.style.a=[]);var f=d.style.a,g=new Pu;Xv(g,a);f[b]=g;if(null!=a.a&&(null==a.h||!a.h))if(f=ew(a),null!=f.a||null!=f.b||null!=f.g){if(!fA(d.style,b)){g=[];if(null!=f.b||null!=f.g){gw(f);var h=f.b;for(var k=0;k<h.length;++k)g.push(Sv(e,h[k]))}if(null!=f.a)for(f=f.a,k=0;k<f.length;++k)g.push(f[k]);HB(g,a,b,c,d,e)}}else d.style.j||(g=null==f.l?0:f.l,d.style.j=!0,EA(d,0,g),g=null==f.m?0:f.m,d.style.j=!0,EA(d,4,g),f=(null==f.o?0:f.o)/8,d.style.j=!0,FA(d,8,f));f=null== +a.f?0:a.f;d.style.l=!0;EA(d,36*b+16,f);null!=a.c&&(f=dw(a),0<(null==f.f?0:f.f)&&(f=null==a.o?0:a.o,d.style.s=!0,EA(d,36*b+20,f)));if(null!=a.b||null!=a.g||null!=a.j){f=[];if(null!=a.g||null!=a.j)for(Wv(a),k=a.g,g=0;g<k.length;++g)f.push(Sv(e,k[g]));if(null!=a.b)for(k=a.b,g=0;g<k.length;++g)f.push(k[g]);HB(f,a,b,c,d,e)}} +function HB(a,b,c,d,e,f){if(a.length){var g=[];for(var h=[],k=[],l=!1,m=!1,n=0;n<a.length;n++){var p=a[n];if(null!=p.a&&(null==p.a?0:p.a)||null!=p.b){var q=IB(p,f);if(0==q.lastIndexOf("icon/name=",0)){var t=q.indexOf("&");-1==t&&(t=q.length);g.push(q.substring(10,t));null!=p.g?(l=!0,h.push((null==p.g?4278190080:p.g).toString(16))):h.push("ff000000");null!=p.f?(m=!0,k.push((null==p.f?0:p.f).toString(16))):k.push("00000000")}}}0==g.length?g="":(n="",l&&(n="&highlight="+h.join(",")),h="",m&&(h="&filter="+ +k.join(",")),g="icon/"+["name=",g.join(","),n,h].join(""));g?(f=[],a="ff000000",null!=b.f&&(a=(null==b.f?0:b.f).toString(16)),f.push("color=",a),null!=b.c&&(b=dw(b),null!=b.c&&f.push("&font=",encodeURIComponent(String(null==b.c?"":b.c))),null!=b.b&&f.push("&psize=",null==b.b?0:b.b),null!=b.a&&(b=null==b.a?0:b.a,k=a="",b&1?a="bold":b&8?a="medium":b&16&&(a="light"),b&2&&(k="italic"),a&&f.push("&font_weight=",a),k&&f.push("&font_style=",k))),d=d.a([g,"&",f.join("")].join("")),CA(e,c,new Ws(d,null))): +1==a.length&&(b=a[0],f=IB(b,f),a=new mB(f),a.b||a.c?CA(e,c,new Ws(f,null==b.h?1:b.h)):(d=d.a(f),CA(e,c,new Ws(d,null))))}}function IB(a,b){var c=null==a.a?"":a.a;if(0==c.lastIndexOf("data:",0))return c;null!=a.b&&(a=null==a.b?-1:a.b,Hv(b),c=b.u[a]+c);b&&(c=(null==b.o?"":b.o)+c+(null==b.s?"":b.s));return c} +function JB(a,b,c,d){c.style.g||(c.style.g=[]);var e=c.style.g,f=new Uu;lv(f);f.a=Bd(a.a,hw);f.j=a.j;f.l=a.l;f.h=a.h;f.g=a.g;f.c=Ad(a.c);f.i=a.i;f.A=a.A;f.f=a.f;f.v=a.v;f.b=a.b;f.s=a.s;f.o=a.o;f.u=a.u;f.m=a.m;f.B=a.B;e[b]=f;f=[];if(null!=a.a)f=a.a;else if(null!=a.c||null!=a.i){kw(a);var g=a.c;for(e=0;e<g.length;++e)f.push(Pv(d,g[e]))}d=f.length;g=0;2<d&&(g=d-2,d=2);c.style.c<d&&BA(c,d);for(e=0;e<d;e++)FB(f[e+g],e,b,c);if(null!=a.f)for(f=null==a.f?"":a.f,e=0;e<d;e++)IA(c,e,b,new Ws(f,1));if(null!= +a.b)for(a=null==a.b?"":a.b,e=0;e<d;e++)JA(c,e,b,new Ws(a,1))}function KB(a,b,c){c.style.i||(c.style.i=[]);var d=c.style.i,e=new Yu;mv(e);e.a=a.a;e.g=a.g;e.b=a.b;e.f=a.f;e.c=a.c;d[b]=e;d=null==a.b?0:a.b;c.style.D=!0;EA(c,36*b+12,d);null!=a.a&&(BA(c,1),EA(c,36*b+24,null==a.a?0:a.a))} +function FB(a,b,c,d){EA(d,36*c+24+12*b+0,null==a.g?0:a.g);FA(d,36*c+24+12*b+4,(null==a.i?0:a.i)/8);var e=(null==a.h?0:a.h)/8*8;0>e&&(e=-e+128);d.style.b[36*c+24+12*b+10]=Math.floor(e);e=[];for(var f=0;f<(a.c?a.c.length:0)&&(e.push(a.c[f]/8),2!=e.length);f++);e.length&&(f=36*c+24+12*b+8,e&&2==e.length?(d.style.b[f+0]=Math.floor(2*e[0]),d.style.b[f+1]=Math.floor(2*e[1])):(d.style.b[f+0]=0,d.style.b[f+1]=0));null!=a.f&&HA(d,b,c,new Ws(null==a.f?"":a.f,1));null!=a.b&&(null===a.b&&(a.b=new Vu),e=a.b,null!= +e.a&&(e=null==e.a?"":e.a,IA(d,b,c,new Ws(e,1))));null!=a.a&&(null===a.a&&(a.a=new Vu),a=a.a,null!=a.a&&(e=null==a.a?"":a.a,JA(d,b,c,new Ws(e,1))))} +function LB(a,b){var c;for(c=0;c<a.length-1;++c)KA(b,a[c],a[c+1]);a=a[a.length-1];var d=a+1;c=22;var e=b.style;0>d&&(d=0);22<c&&(c=22);if(!(d>c||d==c&&a==d)){var f=qA(b.style,a);if(f)for(;d<=c;d++)if(d!=a){e.f?e.f[d]=e.f[a]:e.a?e.a[d]=e.a[a]:e.g?e.g[d]=e.g[a]:e.h?e.h[d]=e.h[a]:e.i&&(e.i[d]=e.i[a]);b.style.b.set(f,12+36*d);CA(b,d,fA(b.style,a));for(var g=0;g<b.style.c;g++)HA(b,g,d,vA(b.style.v,g,a)),IA(b,g,d,vA(b.style.A,g,a)),JA(b,g,d,vA(b.style.u,g,a))}}};function MB(a,b){this.a=a;this.b=b||null} +function UA(a,b,c,d){var e=b.b[c];uv(e);var f=e.a?e.a.length:0;if(0!=f){var g=null,h=null,k=null,l=null;c=null;for(var m=[],n=[],p=[],q=[],t=[],v=0;v<f;v++){var u=e;var w=v;uv(u);w=u.a[w];u=w.getZoom();if(null!=w.c){var y=b;var A=null==w.c?0:w.c;Bv(y);y=y.i[A];h||(h=new zA);n.push(u);JB(y,u,h,b)}null!=w.a&&(y=b,A=null==w.a?0:w.a,zv(y),y=y.f[A],g||(g=new zA),m.push(u),EB(y,u,g,b));null!=w.g&&(y=b,A=null==w.g?0:w.g,Dv(y),y=y.v[A],k||(k=new zA),p.push(u),KB(y,u,k));null!=w.b&&(y=b,A=null==w.b?0:w.b, +Av(y),y=y.h[A],l||(l=new zA),q.push(u),GB(y,u,a.b,l,b));null!=w.f&&(y=b,w=null==w.f?0:w.f,Ev(y),w=y.l[w],c||(c=new zA),t.push(u),DA(c,u,w))}b=e.wa();h&&(LB(n,h),h=h.style,n=pr(a.a,"L"+b),h.B=n,d.push(h));g&&(LB(m,g),h=g.style,g=pr(a.a,"A"+b),h.B=g,d.push(h));k&&(LB(p,k),h=k.style,k=pr(a.a,"V"+b),h.B=k,d.push(h));l&&(LB(q,l),h=l.style,l=pr(a.a,"B"+b),h.B=l,d.push(h));c&&(LB(t,c),h=c.style,a=pr(a.a,"R"+b),h.B=a,d.push(h))}};function NB(a,b){this.a=a;this.b=b||null};function OB(a,b){Pp.call(this);this.g=new MB(a,b);this.b=new LA(a,new NB(a,b));this.c=new NA(a);this.a={};a.f=this.f;a.g=this||null}F(OB,Pp);function PB(a,b){b=Ms(b);var c=a.a[b];c||(c=a.a[b]=new PA(a.g,a.b,a.c),Qp(a,c));return c}OB.prototype.f=function(a){for(var b in this.a)this.a[b].c[a]=null};var QB=4/127;function RB(a,b,c){var d=a.i;this.i=a;this.h=b;this.b=new Mq(a,Math.min(Math.ceil(1024*c),d),Math.min(Math.ceil(128*c),d),6408,9729,!0,Math.ceil(128*c));this.a=new Mq(a,1024,64,6408,9728,!1,64,new fo(1,16));this.c=new Mq(a,2048,1024,6406,9729,!1,256,new fo(8,12));this.f=new Mq(a,2048,512,6408,9728,!1,256,new fo(16,3));this.g=new Mq(a,Math.min(Math.ceil(4096*c),d),Math.min(Math.ceil(512*c),d),6406,9729,!1,Math.ceil(128*c),new fo(4,2))}RB.prototype.getContext=function(){return this.i}; +RB.prototype.$=function(){this.b.$();this.a.$();this.c.$();this.f.$();this.g.$()};function SB(a,b,c){this.a=a;this.c=b;this.b=c}function TB(a,b){if(0==b)return 0;if(1==b)return 1;var c=$n(0,a.a,b),d=$n(a.a,a.b,b);a=$n(a.b,1,b);c=$n(c,d,b);d=$n(d,a,b);return $n(c,d,b)}function UB(a,b){if(0==b)return 0;if(1==b)return 1;var c=$n(0,a.c,b);a=$n(a.c,1,b);var d=$n(1,1,b);c=$n(c,a,b);a=$n(a,d,b);return $n(c,a,b)} +function VB(a,b){var c=(b-0)/1;if(0>=c)return 0;if(1<=c)return 1;for(var d=0,e=1,f=0,g=0;8>g;g++){f=TB(a,c);var h=(TB(a,c+1E-6)-f)/1E-6;if(1E-6>Math.abs(f-b))return c;if(1E-6>Math.abs(h))break;else f<b?d=c:e=c,c-=(f-b)/h}for(g=0;1E-6<Math.abs(f-b)&&8>g;g++)f<b?(d=c,c=(c+e)/2):(e=c,c=(c+d)/2),f=TB(a,c);return c};function WB(a,b,c){a=new SB(a,b,c);var d=Array(51);for(b=0;51>b;b++)d[b]=UB(a,VB(a,b/50));return function(a){if(0>=a)return 0;if(1<=a)return 1;var b=50*a;a=Math.floor(b);b-=a;return d[a]*(1-b)+d[a+1]*b}}var XB=WB(0,0,.58);WB(.52,0,.48);WB(.52,0,.25);WB(.36,.67,.533);WB(.24,.67,.533);WB(.56,1,.56);WB(.91,1,.82);function YB(a,b){this.m=b;this.i=this.h=this.f=this.b=this.a=null;this.c=0;this.l=!0;this.j=-1;this.g=!1;MA(a.b,this.o,this)}function ZB(a){return a.l&&E()<a.j}YB.prototype.o=function(a,b){this.c++;this.f&&this.f.call(this.h,[a],[b])};YB.prototype.s=function(a,b){this.f&&this.f.call(this.h,a,b)};function Qr(a){a.i&&a.i.call(null);ZB(a)?(a.g=!0,a.m.Pd(a)):a.g=!1};function $B(a){a&=4294967295;var b="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@#"[a&63];for(a>>=6;a;)b+="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@#"[a&63],a>>=6;return b}function aC(a){return"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@#"[a&63]};function bC(a){var b=a.length;if(!b)return null;for(var c=a[0].b,d=c,e=a[0].a,f=e,g=1;g<b;++g){var h=a[g].b,k=a[g].a;h<c?c=h:h>d&&(d=h);k<e?e=k:k>f&&(f=k)}k=1<<a[0].getZoom();if(0==c&&d==k-1){d=0;c=k-1;for(g=0;g<b;++g)h=a[g].b,h>d&&h<c&&(c-h>h-d?d=h:c=h);c-1==d?(c=0,d=k-1):d+=k}return{oa:c,Yc:d,xc:e,bd:f}}function cC(a,b){var c=30-a.getZoom(),d=a.b<<c;a=a.a<<c;var e=d+(1<<c)-1;c=a+(1<<c)-1;var f=30-b.getZoom(),g=b.b<<f;b=b.a<<f;return g<=e&&d<=g+(1<<f)-1&&b<=c&&a<=b+(1<<f)-1};function dC(a,b,c,d){this.Ha=a;this.a=b||0;this.c=c||Rs;d?a=d:(b=this.c,a=Fs(b.a,a,b.f));this.b=a;c=this.Ha;a=this.b;b=eC(this.a,this.c);b+=":"+c.aa();if(a){c=Array(a.length);for(d=0;d<a.length;++d){var e=a[d];c[d]=null!=e?0<=e?$B(e):"-1":""}b+="@"+c.join(",")}this.h=b;this.g=this.f=null}function eC(a,b){return 0!=a&&4!=a?aC(a):Qs(b)}dC.prototype.aa=function(){return this.h};function fC(a,b){b=b.b;if(a.b.length!=b.length)return!1;for(var c=0,d=b.length;c<d;c++)if(b[c]!=a.b[c])return!1;return!0} +function gC(a){return 0==a.a&&!!a.c.b}function hC(a){if(gC(a)&&null==a.g){var b=a.c.b;var c=a.c;var d=a.b;if(c.b){c=Array(c.b.a.a.length);for(var e=0;e<c.length;++e)c[e]=d[e];d=c}b=new dC(a.Ha,a.a,b,d);a.g=b}}function iC(a){return a.Ha.b}function jC(a){return a.Ha.a}dC.prototype.getZoom=function(){return this.Ha.getZoom()};dC.prototype.Ea=function(){return this.a};dC.prototype.ba=function(){return this.c};function kC(a,b,c){this.b=a;this.a=b;this.f=c;this.c=null}kC.prototype.getZoom=function(){return this.f};kC.prototype.aa=function(){this.c||(this.c=$B(this.b)+","+$B(this.a)+","+aC(this.f));return this.c};function lC(a){for(var b=new Es,c=0;c<Fe(a,1);c++){var d=b,e=mC(a,c);d.a.push(e);d.b.push(void 0)}return b}function nC(a){var b=new Js;a=new oC(a.data[2]);for(var c=0;c<Fe(a,11);c++){var d=new Sn(Ee(a,11,c));b.a.push(d)}return b};function pC(a){this.data=a||[]}var qC;F(pC,W);function rC(a){this.data=a||[]}var sC;F(rC,W);function tC(a){this.data=a||[]}var uC;F(tC,W);function vC(){qC||(qC={a:-1,F:[]},qC.F=[,ae(512),ae(512),Zd(47.651318),Zd(-122.35305),Zd(15),$d,$d,$d,Zd(-212),Zd(40),Zd(13.1),ce,ce,Vd("s","Default"),Vd("s","en"),R,R,R,ge(!0),P,R,ke,R,P,U,ge(!0),R,R,ge(!0),R,R,P,ke,P]);return qC}pC.prototype.getZoom=function(){return X(this,4,15)};pC.prototype.Ea=function(){return Ce(this,11)[void 0]}; +function wC(){var a=uC={a:-1,F:[]},b=V(new pC([]),vC());sC||(sC={a:-1,F:[]},sC.F=[,V(new pC([]),vC()),P]);a.F=[,b,pe(sC),R,ge(!0),ge(!0),Zd(1),$d,$d,R,ae(2),R]};function xC(a){if(!xe(a,0))throw"MultiViewports must have an initial viewport set.";this.a=[new pC(a.data[0])];var b=new pC;He(b,new pC(a.data[0]));for(var c=Fe(a,1),d=0;d<c;d++){var e=new pC((new rC(Ee(a,1,d))).data[0]),f=X(new rC(Ee(a,1,d)),1),g=new pC;xe(e,0)&&(g.data[0]=1*(X(e,0,512)-X(b,0,512))/f);xe(e,1)&&(g.data[1]=1*(X(e,1,512)-X(b,1,512))/f);xe(e,2)&&(g.data[2]=1*(X(e,2,47.651318)-X(b,2,47.651318))/f);xe(e,3)&&(g.data[3]=1*(X(e,3,-122.35305)-X(b,3,-122.35305))/f);if(xe(e,4)){var h=1*(e.getZoom()- +b.getZoom())/f;g.data[4]=h}xe(e,5)&&(g.data[5]=1*(X(e,5)-X(b,5))/f);xe(e,6)&&(g.data[6]=1*(X(e,6)-X(b,6))/f);xe(e,7)&&(g.data[7]=1*(X(e,7)-X(b,7))/f);xe(e,8)&&(g.data[8]=1*(X(e,8,-212)-X(b,8,-212))/f);xe(e,9)&&(g.data[9]=1*(X(e,9,40)-X(b,9,40))/f);xe(e,10)&&(g.data[10]=1*(X(e,10,13.1)-X(b,10,13.1))/f);for(h=0;h<f-1;++h){xe(e,0)&&(b.data[0]=X(b,0,512)+X(g,0,512));xe(e,1)&&(b.data[1]=X(b,1,512)+X(g,1,512));xe(e,2)&&(b.data[2]=X(b,2,47.651318)+X(g,2,47.651318));xe(e,3)&&(b.data[3]=X(b,3,-122.35305)+ +X(g,3,-122.35305));if(xe(e,4)){var k=b.getZoom()+g.getZoom();b.data[4]=k}xe(e,5)&&(b.data[5]=X(b,5)+X(g,5));xe(e,6)&&(b.data[6]=X(b,6)+X(g,6));xe(e,7)&&(b.data[7]=X(b,7)+X(g,7));xe(e,8)&&(b.data[8]=X(b,8,-212)+X(g,8,-212));xe(e,9)&&(b.data[9]=X(b,9,40)+X(g,9,40));xe(e,10)&&(b.data[10]=X(b,10,13.1)+X(g,10,13.1));k=new pC;He(k,b);this.a.push(k)}e=e.data;f=b.data;for(g=0;g<e.length;g++)null!=e[g]&&(f[g]=e[g]);e=new pC(f.slice());He(b,e);this.a.push(e);Be(b,31)}};function yC(){var a=zC;if("undefined"!=typeof window){var b=function(){return this.getAttribute("src")},c=function(b){b=a.call(this,b);this.setAttribute("src",b)},d=this.a=document.createElement;document.createElement=function(a){var e=d.call(this,a);"IMG"==a.toUpperCase()&&Object.defineProperty(e,"src",{enumerable:!0,configurable:!0,get:b,set:c});return e}}}yC.prototype.$=function(){"undefined"!=typeof window&&(document.createElement=this.a)};function AC(){var a=zC,b=this.a=XMLHttpRequest.prototype.open;XMLHttpRequest.prototype.open=function(c,d,e,f,g){for(var h=a.call(this,d),k=Array(arguments.length),l=0;l<k.length;l++)k[l]=1==l?h:arguments[l];b.apply(this,k)}}AC.prototype.$=function(){XMLHttpRequest.prototype.open=this.a};function BC(a,b){this.c=a;this.f=b;this.b=0;this.a=null}BC.prototype.get=function(){if(0<this.b){this.b--;var a=this.a;this.a=a.next;a.next=null}else a=this.c();return a};function CC(a,b){a.f(b);100>a.b&&(a.b++,b.next=a.a,a.a=b)};function DC(){this.b=this.a=null}var FC=new BC(function(){return new EC},function(a){a.reset()});DC.prototype.add=function(a,b){var c=FC.get();c.set(a,b);this.b?this.b.next=c:this.a=c;this.b=c};function GC(){var a=HC,b=null;a.a&&(b=a.a,a.a=a.a.next,a.a||(a.b=null),b.next=null);return b}function EC(){this.next=this.scope=this.a=null}EC.prototype.set=function(a,b){this.a=a;this.scope=b;this.next=null};EC.prototype.reset=function(){this.next=this.scope=this.a=null};function IC(a,b){JC||KC();LC||(JC(),LC=!0);HC.add(a,b)}var JC;function KC(){if(-1!=String(x.Promise).indexOf("[native code]")){var a=x.Promise.resolve(void 0);JC=function(){a.then(MC)}}else JC=function(){ur(MC)}}var LC=!1,HC=new DC;function MC(){for(var a;a=GC();){try{a.a.call(a.scope)}catch(b){tr(b)}CC(FC,a)}LC=!1};function NC(a){switch(a){case 200:case 201:case 202:case 204:case 206:case 304:case 1223:return!0;default:return!1}};function OC(){}OC.prototype.a=null;function PC(a){var b;(b=a.a)||(b={},QC(a)&&(b[0]=!0,b[1]=!0),b=a.a=b);return b};var RC;function SC(){}F(SC,OC);function TC(a){return(a=QC(a))?new ActiveXObject(a):new XMLHttpRequest}function QC(a){if(!a.b&&"undefined"==typeof XMLHttpRequest&&"undefined"!=typeof ActiveXObject){for(var b=["MSXML2.XMLHTTP.6.0","MSXML2.XMLHTTP.3.0","MSXML2.XMLHTTP","Microsoft.XMLHTTP"],c=0;c<b.length;c++){var d=b[c];try{return new ActiveXObject(d),a.b=d}catch(e){}}throw Error("Could not create ActiveXObject. ActiveX might be disabled, or MSXML might not be installed");}return a.b}RC=new SC;function UC(a){a.prototype.then=a.prototype.then;a.prototype.$goog_Thenable=!0}function VC(a){if(!a)return!1;try{return!!a.$goog_Thenable}catch(b){return!1}};function WC(a,b){this.a=0;this.i=void 0;this.f=this.b=this.c=null;this.g=this.h=!1;if(a!=sa)try{var c=this;a.call(b,function(a){XC(c,2,a)},function(a){XC(c,3,a)})}catch(d){XC(this,3,d)}}function YC(){this.next=this.context=this.b=this.c=this.a=null;this.f=!1}YC.prototype.reset=function(){this.context=this.b=this.c=this.a=null;this.f=!1};var ZC=new BC(function(){return new YC},function(a){a.reset()});function $C(a,b,c){var d=ZC.get();d.c=a;d.b=b;d.context=c;return d} +WC.prototype.then=function(a,b,c){return aD(this,ya(a)?a:null,ya(b)?b:null,c)};UC(WC);WC.prototype.cancel=function(a){0==this.a&&IC(function(){var b=new bD(a);cD(this,b)},this)};function cD(a,b){if(0==a.a)if(a.c){var c=a.c;if(c.b){for(var d=0,e=null,f=null,g=c.b;g&&(g.f||(d++,g.a==a&&(e=g),!(e&&1<d)));g=g.next)e||(f=g);e&&(0==c.a&&1==d?cD(c,b):(f?(d=f,d.next==c.f&&(c.f=d),d.next=d.next.next):dD(c),eD(c,e,3,b)))}a.c=null}else XC(a,3,b)} +function fD(a,b){a.b||2!=a.a&&3!=a.a||gD(a);a.f?a.f.next=b:a.b=b;a.f=b}function aD(a,b,c,d){var e=$C(null,null,null);e.a=new WC(function(a,g){e.c=b?function(c){try{var e=b.call(d,c);a(e)}catch(l){g(l)}}:a;e.b=c?function(b){try{var e=c.call(d,b);!B(e)&&b instanceof bD?g(b):a(e)}catch(l){g(l)}}:g});e.a.c=a;fD(a,e);return e.a}WC.prototype.l=function(a){this.a=0;XC(this,2,a)};WC.prototype.m=function(a){this.a=0;XC(this,3,a)}; +function XC(a,b,c){if(0==a.a){a===c&&(b=3,c=new TypeError("Promise cannot resolve to itself"));a.a=1;a:{var d=c,e=a.l,f=a.m;if(d instanceof WC){fD(d,$C(e||sa,f||null,a));var g=!0}else if(VC(d))d.then(e,f,a),g=!0;else{if(za(d))try{var h=d.then;if(ya(h)){hD(d,h,e,f,a);g=!0;break a}}catch(k){f.call(a,k);g=!0;break a}g=!1}}g||(a.i=c,a.a=b,a.c=null,gD(a),3!=b||c instanceof bD||iD(a,c))}} +function hD(a,b,c,d,e){function f(a){h||(h=!0,d.call(e,a))}function g(a){h||(h=!0,c.call(e,a))}var h=!1;try{b.call(a,g,f)}catch(k){f(k)}}function gD(a){a.h||(a.h=!0,IC(a.j,a))}function dD(a){var b=null;a.b&&(b=a.b,a.b=b.next,b.next=null);a.b||(a.f=null);return b}WC.prototype.j=function(){for(var a;a=dD(this);)eD(this,a,this.a,this.i);this.h=!1}; +function eD(a,b,c,d){if(3==c&&b.b&&!b.f)for(;a&&a.g;a=a.c)a.g=!1;if(b.a)b.a.c=null,jD(b,c,d);else try{b.f?b.c.call(b.context):jD(b,c,d)}catch(e){kD.call(null,e)}CC(ZC,b)}function jD(a,b,c){2==b?a.c.call(a.context,c):a.b&&a.b.call(a.context,c)}function iD(a,b){a.g=!0;IC(function(){a.g&&kD.call(null,b)})}var kD=tr;function bD(a){Ja.call(this,a)}F(bD,Ja);bD.prototype.name="cancel";function lD(a,b,c){if(ya(a))c&&(a=D(a,c));else if(a&&"function"==typeof a.handleEvent)a=D(a.handleEvent,a);else throw Error("Invalid listener argument");return 2147483647<Number(b)?-1:x.setTimeout(a,b||0)};function mD(a){rc.call(this);this.headers=new aB;this.s=a||null;this.b=!1;this.m=this.a=null;this.i=this.D=this.B="";this.c=this.A=this.h=this.v=!1;this.g=0;this.j=null;this.f="";this.C=this.l=!1}F(mD,rc);var nD=/^https?$/i,oD=["POST","PUT"],pD=[];function qD(a,b,c,d,e){var f=new mD;pD.push(f);b&&f.cb("complete",b);f.cc("ready",f.pf);rD(f,a,c,d,e)}r=mD.prototype;r.pf=function(){this.$();Ta(pD,this)}; +function rD(a,b,c,d,e){if(a.a)throw Error("[goog.net.XhrIo] Object is active with another request="+a.B+"; newUri="+b);c=c?c.toUpperCase():"GET";a.B=b;a.i="";a.D=c;a.v=!1;a.b=!0;a.a=a.s?TC(a.s):TC(RC);a.m=a.s?PC(a.s):PC(RC);a.a.onreadystatechange=D(a.He,a);try{a.A=!0,a.a.open(c,String(b),!0),a.A=!1}catch(g){sD(a,g);return}b=d||"";var f=new aB(a.headers);e&&eB(e,function(a,b){f.set(b,a)});e=Ra(f.nb());d=x.FormData&&b instanceof x.FormData;!(0<=Ka(oD,c))||e||d||f.set("Content-Type","application/x-www-form-urlencoded;charset=utf-8"); +f.forEach(function(a,b){this.a.setRequestHeader(b,a)},a);a.f&&(a.a.responseType=a.f);"withCredentials"in a.a&&a.a.withCredentials!==a.l&&(a.a.withCredentials=a.l);try{tD(a),0<a.g&&(a.C=uD(a.a),a.C?(a.a.timeout=a.g,a.a.ontimeout=D(a.ef,a)):a.j=lD(a.ef,a.g,a)),a.h=!0,a.a.send(b),a.h=!1}catch(g){sD(a,g)}}function uD(a){return pb&&Ab(9)&&qa(a.timeout)&&B(a.ontimeout)}function Sa(a){return"content-type"==a.toLowerCase()} +r.ef=function(){"undefined"!=typeof oa&&this.a&&(this.i="Timed out after "+this.g+"ms, aborting",this.dispatchEvent("timeout"),this.abort(8))};function sD(a,b){a.b=!1;a.a&&(a.c=!0,a.a.abort(),a.c=!1);a.i=b;vD(a);wD(a)}function vD(a){a.v||(a.v=!0,a.dispatchEvent("complete"),a.dispatchEvent("error"))}r.abort=function(){this.a&&this.b&&(this.b=!1,this.c=!0,this.a.abort(),this.c=!1,this.dispatchEvent("complete"),this.dispatchEvent("abort"),wD(this))}; +r.X=function(){this.a&&(this.b&&(this.b=!1,this.c=!0,this.a.abort(),this.c=!1),wD(this,!0));mD.R.X.call(this)};r.He=function(){this.O()||(this.A||this.h||this.c?xD(this):this.Dd())};r.Dd=function(){xD(this)}; +function xD(a){if(a.b&&"undefined"!=typeof oa&&(!a.m[1]||4!=yD(a)||2!=zD(a)))if(a.h&&4==yD(a))lD(a.He,0,a);else if(a.dispatchEvent("readystatechange"),4==yD(a)){a.b=!1;try{if(AD(a))a.dispatchEvent("complete"),a.dispatchEvent("success");else{try{var b=2<yD(a)?a.a.statusText:""}catch(c){b=""}a.i=b+" ["+zD(a)+"]";vD(a)}}finally{wD(a)}}}function wD(a,b){if(a.a){tD(a);var c=a.a,d=a.m[0]?sa:null;a.a=null;a.m=null;b||a.dispatchEvent("ready");try{c.onreadystatechange=d}catch(e){}}} +function tD(a){a.a&&a.C&&(a.a.ontimeout=null);a.j&&(x.clearTimeout(a.j),a.j=null)}function AD(a){var b=zD(a),c;if(!(c=NC(b))){if(b=0===b)a=String(a.B).match(fB)[1]||null,!a&&x.self&&x.self.location&&(a=x.self.location.protocol,a=a.substr(0,a.length-1)),b=!nD.test(a?a.toLowerCase():"");c=b}return c}function yD(a){return a.a?a.a.readyState:0}function zD(a){try{return 2<yD(a)?a.a.status:-1}catch(b){return-1}}function BD(a){try{return a.a?a.a.responseText:""}catch(b){return""}} +r.$c=function(){try{if(!this.a)return null;if("response"in this.a)return this.a.response;switch(this.f){case "":case "text":return this.a.responseText;case "arraybuffer":if("mozResponseArrayBuffer"in this.a)return this.a.mozResponseArrayBuffer}return null}catch(a){return null}};Hb(function(a){mD.prototype.Dd=a(mD.prototype.Dd)});function CD(){this.i=this.g=this.a=this.h=this.f=this.c=this.b=null}function DD(){this.a=null}CD.prototype.w=function(){var a=[];if(null!==this.b){var b=this.b;a[0]=b}ED(this);null!==this.c&&(b=this.c,b=Dc(b),a[1]=b);null!==this.a&&(b=this.a,a[2]=b);null!==this.g&&(b=this.g,a[3]=b);return a};CD.prototype.getExtension=function(){return null}; +function FD(a,b){for(a.i=jd(b);G(b);)switch(b.a){case 1:var c=L(b);a.b=c;break;case 2:null===a.f&&(a.f=b.b);kd(b);a.h=id(b);break;case 3:c=L(b);a.a=c;break;case 4:c=J(b);a.g=c;break;default:H(b)}}CD.prototype.$c=function(){ED(this);return this.c};function ED(a){null!=a.f&&null==a.c&&(a.c=Gd(a.i,a.f,a.h))}DD.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;b=b.slice();for(var c=0;c<b.length;c++)b[c]=b[c].w();a[0]=b}return a};DD.prototype.getExtension=function(){return null};var GD={},HD=null,ID=null;function zC(a){return GD[a]||a} +function JD(a){HD&&HD.$();HD=new yC;ID&&ID.$();ID=new AC;for(var b in GD)URL.revokeObjectURL(GD[b]);GD={};b=new mD;b.f="arraybuffer";b.cb("complete",function(){if(AD(this)){var b=this.$c(),d=new DD;for(b=gd(b);G(b);)switch(b.a){case 1:var e=new CD;O(b,e,FD);d.a=d.a||[];d.a.push(e);break;default:H(b)}hd(b);for(b=0;b<(d.a?d.a.length:0);b++)e=d.a[b],GD[null==e.b?"":e.b]=URL.createObjectURL(new Blob([e.$c()],{type:null==e.a?"":e.a}));a()}else throw Error("Failed to load dataset.");});rD(b,"load_dataset")} +;var KD={warp:"!1m5!1i1500!2i900!3f40.194678!4f-88.926313!5f16!2m5!1m3!3f47.606198!4f-122.332066!32i5000!2i1!2m5!1m3!3f40.416682!4f-3.700418!32i5000!2i1!2m5!1m3!3f37.767454!4f-122.417656!32i5000!2i1!2m5!1m3!3f53.344089!4f-6.267507!32i5000!2i1!2m5!1m3!3f40.714314!4f-74.005977!32i5000!2i1!2m5!1m3!3f47.373092!4f8.521743!32i5000!2i1!2m5!1m3!3f38.895141!4f-77.036433!32i5000!2i1!2m5!1m3!3f35.689527!4f139.691763!32i5000!2i1!2m5!1m3!3f25.775547!4f-80.194761!32i5000!2i1!2m5!1m3!3f52.52335!4f13.411431!32i5000!2i1!2m5!1m3!3f41.8702!4f-87.673774!32i5000!2i1!9b1", +tilt:"!1m5!1i1024!2i768!3f47.651316!4f-122.353048!5f15!2m3!1m1!8f75!2i50!2m3!1m1!7f360!2i200!2m3!1m1!5f16!2i20!2m3!1m1!7f360!2i200!2m3!1m1!8f15!2i50!2m3!1m1!7f180!2i100!2m3!1m1!8f60!2i50!2m3!1m1!5f20!2i20!2m3!1m1!7f45!2i50!2m3!1m1!5f13!2i30!2m4!1m2!3f47.5!4f-122.1!2i50!2m3!1m1!8f0!2i50!4b0!9b1",stress:"!1m5!1i1500!2i900!3f40.194678!4f-88.926313!5f4!2m5!1m3!3f47.606198!4f-122.332066!32i5000!2i50!2m4!1m2!5f16.25!32i15000!2i250!2m5!1m3!3f47.636198!4f-122.302066!32i5000!2i100!2m5!1m3!3f47.576198!4f-122.302066!32i5000!2i100!2m5!1m3!3f47.636198!4f-122.362066!32i5000!2i100!2m5!1m3!3f47.636198!4f-122.362066!32i5000!2i100!2m4!1m2!5f4!32i5000!2i250!2m5!1m3!3f40.416682!4f-3.700418!32i5000!2i50!2m4!1m2!5f16.25!32i15000!2i250!2m5!1m3!3f40.446682!4f-3.670418!32i5000!2i100!2m5!1m3!3f40.386682!4f-3.670418!32i5000!2i100!2m5!1m3!3f40.386682!4f-3.730418!32i5000!2i100!2m5!1m3!3f40.446682!4f-3.730418!32i5000!2i100!2m4!1m2!5f4!32i5000!2i250!2m5!1m3!3f37.767454!4f-122.417656!32i5000!2i50!2m4!1m2!5f16.25!32i15000!2i250!2m5!1m3!3f37.797454!4f-122.387656!32i5000!2i100!2m5!1m3!3f37.737454!4f-122.387656!32i5000!2i100!2m5!1m3!3f37.737454!4f-122.447656!32i5000!2i100!2m5!1m3!3f37.797454!4f-122.447656!32i5000!2i100!2m4!1m2!5f4!32i5000!2i250!2m5!1m3!3f53.344089!4f-6.267507!32i5000!2i50!2m4!1m2!5f16.25!32i15000!2i250!2m5!1m3!3f53.374089!4f-6.237507!32i5000!2i100!2m5!1m3!3f53.314089!4f-6.237507!32i5000!2i100!2m5!1m3!3f53.314089!4f-6.297507!32i5000!2i100!2m5!1m3!3f53.374089!4f-6.297507!32i5000!2i100!2m4!1m2!5f4!32i5000!2i250!2m5!1m3!3f40.714314!4f-74.005977!32i5000!2i50!2m4!1m2!5f16.25!32i15000!2i250!2m5!1m3!3f40.744314!4f-73.975977!32i5000!2i100!2m5!1m3!3f40.684314!4f-73.975977!32i5000!2i100!2m5!1m3!3f40.684314!4f-74.035977!32i5000!2i100!2m5!1m3!3f40.744314!4f-74.035977!32i5000!2i100!2m4!1m2!5f4!32i5000!2i250!2m5!1m3!3f47.373092!4f8.521743!32i5000!2i50!2m4!1m2!5f16.25!32i15000!2i250!2m5!1m3!3f47.403092!4f8.551743!32i5000!2i100!2m5!1m3!3f47.343092!4f8.551743!32i5000!2i100!2m5!1m3!3f47.343092!4f8.491743!32i5000!2i100!2m5!1m3!3f47.403092!4f8.491743!32i5000!2i100!2m4!1m2!5f4!32i5000!2i250!2m5!1m3!3f38.895141!4f-77.036433!32i5000!2i50!2m4!1m2!5f16.25!32i15000!2i250!2m5!1m3!3f38.925141!4f-77.006433!32i5000!2i100!2m5!1m3!3f38.865141!4f-77.006433!32i5000!2i100!2m5!1m3!3f38.865141!4f-77.066433!32i5000!2i100!2m5!1m3!3f38.925141!4f-77.066433!32i5000!2i100!2m4!1m2!5f4!32i5000!2i250!2m5!1m3!3f35.689527!4f139.691763!32i5000!2i50!2m4!1m2!5f16.25!32i15000!2i250!2m5!1m3!3f35.719527!4f139.721763!32i5000!2i100!2m5!1m3!3f35.659527!4f139.721763!32i5000!2i100!2m5!1m3!3f35.659527!4f139.661763!32i5000!2i100!2m5!1m3!3f35.719527!4f139.661763!32i5000!2i100!2m4!1m2!5f4!32i5000!2i250!2m5!1m3!3f25.775547!4f-80.194761!32i5000!2i50!2m4!1m2!5f16.25!32i15000!2i250!2m5!1m3!3f25.805547!4f-80.164761!32i5000!2i100!2m5!1m3!3f25.745547!4f-80.164761!32i5000!2i100!2m5!1m3!3f25.745547!4f-80.224761!32i5000!2i100!2m5!1m3!3f25.805547!4f-80.224761!32i5000!2i100!2m4!1m2!5f4!32i5000!2i250!2m5!1m3!3f52.52335!4f13.411431!32i5000!2i50!2m4!1m2!5f16.25!32i15000!2i250!2m5!1m3!3f52.55335!4f13.441431!32i5000!2i100!2m5!1m3!3f52.49335!4f13.441431!32i5000!2i100!2m5!1m3!3f52.49335!4f13.381431!32i5000!2i100!2m5!1m3!3f52.55335!4f13.381431!32i5000!2i100!2m4!1m2!5f4!32i5000!2i250!2m5!1m3!3f41.8702!4f-87.673774!32i5000!2i50!2m4!1m2!5f16.25!32i15000!2i250!2m5!1m3!3f41.9002!4f-87.643774!32i5000!2i100!2m5!1m3!3f41.8402!4f-87.643774!32i5000!2i100!2m5!1m3!3f41.8402!4f-87.703774!32i5000!2i100!2m5!1m3!3f41.9002!4f-87.703774!32i5000!2i100!2m4!1m2!5f4!32i5000!2i250!9b1", +midzooms:"!1m5!1i2048!2i1024!3f48.85!4f2.34!5f6!2m5!1m3!3f30.05993!4f31.26202!5f9!2i1!2m4!1m2!3f30.03493!4f31.23702!2i20!2m4!1m2!3f30.05993!4f31.26202!2i20!2m3!1m1!5f10!2i20!2m4!1m2!3f30.03493!4f31.23702!2i20!2m4!1m2!3f30.05993!4f31.26202!2i20!2m3!1m1!5f11!2i20!2m4!1m2!3f30.03493!4f31.23702!2i20!2m4!1m2!3f30.05993!4f31.26202!2i20!2m3!1m1!5f12!2i20!2m4!1m2!3f30.03493!4f31.23702!2i20!2m4!1m2!3f30.05993!4f31.26202!2i20!2m3!1m1!5f13!2i20!2m5!1m3!3f41.00561!4f29.01218!5f9!2i1!2m4!1m2!3f40.98061!4f28.98718!2i20!2m4!1m2!3f41.00561!4f29.01218!2i20!2m3!1m1!5f10!2i20!2m4!1m2!3f40.98061!4f28.98718!2i20!2m4!1m2!3f41.00561!4f29.01218!2i20!2m3!1m1!5f11!2i20!2m4!1m2!3f40.98061!4f28.98718!2i20!2m4!1m2!3f41.00561!4f29.01218!2i20!2m3!1m1!5f12!2i20!2m4!1m2!3f40.98061!4f28.98718!2i20!2m4!1m2!3f41.00561!4f29.01218!2i20!2m3!1m1!5f13!2i20!2m5!1m3!3f40.70596!4f-73.978!5f9!2i1!2m4!1m2!3f40.68096!4f-74.003!2i20!2m4!1m2!3f40.70596!4f-73.978!2i20!2m3!1m1!5f10!2i20!2m4!1m2!3f40.68096!4f-74.003!2i20!2m4!1m2!3f40.70596!4f-73.978!2i20!2m3!1m1!5f11!2i20!2m4!1m2!3f40.68096!4f-74.003!2i20!2m4!1m2!3f40.70596!4f-73.978!2i20!2m3!1m1!5f12!2i20!2m4!1m2!3f40.68096!4f-74.003!2i20!2m4!1m2!3f40.70596!4f-73.978!2i20!2m3!1m1!5f13!2i20!2m5!1m3!3f48.85888!4f2.34706!5f9!2i1!2m4!1m2!3f48.83388!4f2.32206!2i20!2m4!1m2!3f48.85888!4f2.34706!2i20!2m3!1m1!5f10!2i20!2m4!1m2!3f48.83388!4f2.32206!2i20!2m4!1m2!3f48.85888!4f2.34706!2i20!2m3!1m1!5f11!2i20!2m4!1m2!3f48.83388!4f2.32206!2i20!2m4!1m2!3f48.85888!4f2.34706!2i20!2m3!1m1!5f12!2i20!2m4!1m2!3f48.83388!4f2.32206!2i20!2m4!1m2!3f48.85888!4f2.34706!2i20!2m3!1m1!5f13!2i20!2m5!1m3!3f35.67347!4f139.7104!5f9!2i1!2m4!1m2!3f35.64847!4f139.6854!2i20!2m4!1m2!3f35.67347!4f139.7104!2i20!2m3!1m1!5f10!2i20!2m4!1m2!3f35.64847!4f139.6854!2i20!2m4!1m2!3f35.67347!4f139.7104!2i20!2m3!1m1!5f11!2i20!2m4!1m2!3f35.64847!4f139.6854!2i20!2m4!1m2!3f35.67347!4f139.7104!2i20!2m3!1m1!5f12!2i20!2m4!1m2!3f35.64847!4f139.6854!2i20!2m4!1m2!3f35.67347!4f139.7104!2i20!2m3!1m1!5f13!2i20!4b0!9b1", +meshes:"!1m5!1i1024!2i768!3f40.6893!4f-74.0442!5f19!2m3!1m1!5f16!2i80!2m4!1m2!3f40.7125!4f-74.0045!2i100!2m3!1m1!5f18!2i40!2m4!1m2!3f40.702!4f-74.0122!2i300!2m4!1m2!3f40.7135!4f-74.0154!2i400!4b0!9b1",buildings:"!1m5!1i1024!2i768!3f47.620458!4f-122.349422!5f16!2m4!1m2!3f47.602!4f-122.325!2i100!2m4!1m2!3f47.591!4f-122.333!2i30!2m3!1m1!5f18!2i10!2m4!1m2!3f47.626!4f-122.331!2i200!2m3!1m1!5f17!2i20!2m4!1m2!3f47.609!4f-122.336!2i65!4b0!9b1",basic_rasterize:"!1m5!1i2048!2i1024!3f47.651316!4f-122.353048!5f15!2m4!1m2!3f47.75!4f-122.35!2i50!2m4!1m2!3f47.75!4f-122.25!2i50!2m4!1m2!3f47.65!4f-122.25!2i50!2m4!1m2!3f47.65!4f-122.35!2i50!2m4!1m2!3f47.7!4f-122.3!2i50!2m3!1m1!5f16!2i20!2m3!1m1!5f14!2i30!2m3!1m1!5f15!2i5!2m3!1m1!7f360!2i100!2m3!1m1!7f45!2i50!2m3!1m1!5f13!2i30!2m4!1m2!3f47.5!4f-122.1!2i50!5b0!9b1!11b1", +basic_large:"!1m5!1i2048!2i1024!3f47.651316!4f-122.353048!5f15!2m4!1m2!3f47.75!4f-122.35!2i50!2m4!1m2!3f47.75!4f-122.25!2i50!2m4!1m2!3f47.65!4f-122.25!2i50!2m4!1m2!3f47.65!4f-122.35!2i50!2m4!1m2!3f47.7!4f-122.3!2i50!2m3!1m1!5f16!2i20!2m3!1m1!5f14!2i30!2m3!1m1!5f15!2i5!2m3!1m1!7f360!2i100!2m3!1m1!7f45!2i50!2m3!1m1!5f13!2i30!2m4!1m2!3f47.5!4f-122.1!2i50!3b1!9b1",basic:"!1m5!1i800!2i600!3f47.651316!4f-122.353048!5f15!2m4!1m2!3f47.75!4f-122.35!2i50!2m4!1m2!3f47.75!4f-122.25!2i50!2m4!1m2!3f47.65!4f-122.25!2i50!2m4!1m2!3f47.65!4f-122.35!2i50!2m4!1m2!3f47.7!4f-122.3!2i50!2m3!1m1!5f16!2i20!2m3!1m1!5f14!2i30!2m3!1m1!5f15!2i5!2m3!1m1!7f360!2i100!2m3!1m1!7f45!2i50!2m3!1m1!5f13!2i30!2m4!1m2!3f47.5!4f-122.1!2i50!3b1!9b1"};var LD={Transit:"!2m1!2sm!2m2!1e2!2stransit!3m5!12m4!1e68!2m2!1sset!2sTransitFocused",TrafficIncidents:"!2m1!2sm!2m11!1e2!2straffic!4m2!1sincidents!2s1!4m2!1sincidents_text!2s1!4m2!1soffset_polylines!2s0!3m5!12m4!1e68!2m2!1sset!2sRoadmap",Terrain:"!2m2!1e4!2st!2m2!1e0!2sm!3m5!12m4!1e68!2m2!1sset!2sTerrain",Spotlight:"!2m1!2sm!2m11!1e2!2sspotlight!7b0!8m7!2m6!1s0x6b12ae19fd46b025:0xfa7c1eadc6105df0!2sSticky Bar, Sydney!4m2!3d-33.880637!4d151.21542499999998!5e0!3m5!12m4!1e68!2m2!1sset!2sRoadmap",Hybrid:"!2m1!2sh!3m5!12m4!1e68!2m2!1sset!2sRoadmapSatellite", +GlobeSpotlight:"!2m5!1e0!2sm!4m2!1sgm!2s0!2m11!1e2!2sspotlight!7b0!8m7!2m6!1s0x6b12ae19fd46b025:0xfa7c1eadc6105df0!2sSticky Bar, Sydney!4m2!3d-33.880637!4d151.21542499999998!5e0!3m5!12m4!1e68!2m2!1sset!2sRoadmapSatellite",GlobeScreen:"!2m5!1e0!2sm!4m2!1sgm!2s2!3m5!12m4!1e68!2m2!1sset!2sRoadmapSatellite",GlobeNoStyler:"!2m5!1e0!2sm!4m2!1sgm!2s0",GlobeDirectionsSpotlight:"!2m5!1e0!2sm!4m2!1sgm!2s0!2m35!1e2!2sspotlight!8m32!8m27!1m2!1sSeattle,+WA!12sjyFgHHybFbea1URpRmUlEFUz6JMsEJBU!1m2!1sKirkland,+WA!12sG55rHEdtKLdXKHhwqmp3envOUijAEpBU!4i0!6m18!1m1!8e2!2m1!20e3!4b1!6m9!1b1!2i0!3i0!4b1!7i1!9s!17b0!18b0!20i-1!16b1!19m1!3j1431032589!21sSCOrXqvXCksiVzgESAmlsHSqQW9glSXfGVA==,NC-4RRbxusWK9rYm!13m3!18m1!9b1!22m0!3m5!12m4!1e68!2m2!1sset!2sRoadmapSatellite", +Globe:"!2m5!1e0!2sm!4m2!1sgm!2s0!3m5!12m4!1e68!2m2!1sset!2sRoadmapSatellite",GeocodeSpotlight:"!2m1!2sm!2m17!1e2!2sspotlight!8m14!2m7!1s0xc42e3783261bc8b:0xa6ec2c940768a3ec!2sSpain!4m2!3d40.4167515!4d-3.7038639!5e1!6b1!13m3!18m1!9b1!22m0!14b1!19u4!3m5!12m4!1e68!2m2!1sset!2sRoadmap",DirectionsSpotlight:"!2m1!2sm!2m35!1e2!2sspotlight!8m32!8m27!1m2!1sSeattle,+WA!12sjyFgHHybFbea1URpRmUlEFUz6JMsEJBU!1m2!1sKirkland,+WA!12sG55rHEdtKLdXKHhwqmp3envOUijAEpBU!4i0!6m18!1m1!8e2!2m1!20e3!4b1!6m9!1b1!2i0!3i0!4b1!7i1!9s!17b0!18b0!20i-1!16b1!19m1!3j1431032589!21sSCOrXqvXCksiVzgESAmlsHSqQW9glSXfGVA==,NC-4RRbxusWK9rYm!13m3!18m1!9b1!22m0!3m5!12m4!1e68!2m2!1sset!2sRoadmap", +DiffTileRemove:"!2m2!1e0!2sm!2m14!1e2!2sindoor!4m2!1slv!2s0x54901506e5106033:0x40a98c0503df27bc!4m2!1srs!2s1!4m2!1slv_hl!2s1!4m2!1srv_il!2s1!3m5!12m4!1e68!2m2!1sset!2sRoadmap",Default:"!2m1!2sm!3m5!12m4!1e68!2m2!1sset!2sRoadmap",Bike:"!2m1!2sm!2m2!1e2!2sbike!3m5!12m4!1e68!2m2!1sset!2sNonRoadmap",BasemapTransitTraffic:"!2m1!2sm!2m8!1e2!2straffic!4m2!1sincidents!2s1!4m2!1sincidents_text!2s1!3m5!12m4!1e68!2m2!1sset!2sRoadmapMuted",AdsSpotlight:"!2m3!1e0!2sm!3i301074684!2m77!1e2!2sspotlight!8m74!5m27!2m26!4m12!1m4!1i678488253!2i1!3i0!4e0!2m2!3d37.797237!4d-122.436386!3sDentist in san francisco!4sUnion Street Dental Care Offers Affordable Dental!8i2!12e1!4m12!1m4!1i678488253!2i2!3i0!4e0!2m2!3d37.774081!4d-122.50992!3sAffordable Dental Care!4sAffordable General Dentistry. Call Our San Francis!8i3!12e1!12m41!1sdentist!2m2!1s115968771510351694523!2s2a!3m1!3s0x0:0xe103b2b26035a543!3m1!3s0x0:0xad881c743179cb66!3m1!3s0x0:0xb27c54dbda21965e!3m1!3s0x0:0x21266dfd418dac5a!3m1!3s0x0:0xeaa34ede4d366944!3m1!3s0x0:0xde096013c05cc519!3m1!3s0x0:0x81397e9d42c0d33f!3m1!3s0x0:0x2a9386dadae6e2d!3m1!3s0x0:0x9621b25de6467250!3m1!3s0x0:0x2d77bcbfe02df96f!5ssan francisco!8m6!3m2!3d37.703399999999995!4d-122.527!4m2!3d37.812!4d-122.34819999999999!10b0!13m7!1s0x80859a6d00690021:0x4a501367f076adff!2sdentist in san francisco!4m2!3d37.7749295!4d-122.4194155!5e1!6b1!13m2!18m1!9b1!19u4!3m5!12m4!1e68!2m2!1sset!2sRoadmap"};function MD(a){this.data=a||[]}var ND;F(MD,W);function OD(a){this.data=a||[]}var PD;F(OD,W);function QD(a){this.data=a||[]}var RD;F(QD,W);function SD(a){this.data=a||[]}var TD;F(SD,W);function UD(a){this.data=a||[]}var VD;F(UD,W);function WD(a){this.data=a||[]}var XD;F(WD,W);function YD(a){this.data=a||[]}var ZD;F(YD,W);function $D(a){this.data=a||[]}var aE;F($D,W);function bE(a){this.data=a||[]}var cE;F(bE,W);function dE(a){this.data=a||[]}var eE;F(dE,W);function fE(a){this.data=a||[]}var gE;F(fE,W);function hE(a){this.data=a||[]}var iE; +F(hE,W);function jE(a){this.data=a||[]}var kE;F(jE,W);function lE(a){this.data=a||[]}var mE;F(lE,W);function nE(a){this.data=a||[]}var oE;F(nE,W);function pE(a){this.data=a||[]}var qE;F(pE,W);function rE(a){this.data=a||[]}var sE;F(rE,W);function tE(a){this.data=a||[]}var uE;F(tE,W); +function vE(){if(!PD){var a=PD={a:-1,F:[]},b=new QD([]);RD||(RD={a:-1,F:[]},RD.F=[,R,ae(256)]);b=V(b,RD);var c=new SD([]);TD||(TD={a:-1,F:[]},TD.F=[,ae(88),ae(120),ae(12),ae(1),ge(!0),T]);c=V(c,TD);var d=Zd(1),e=new UD([]);VD||(VD={a:-1,F:[]},VD.F=[,R,P,ae(256)]);e=V(e,VD);var f=new WD([]);XD||(XD={a:-1,F:[,ie]});a.F=[,T,b,c,R,d,R,e,V(f,XD),R]}return PD} +function wE(){var a=[];ZD={a:-1,F:a};a[1]=T;a[28]=T;a[2]=P;a[44]=T;a[8]=T;a[16]=T;a[11]=T;a[1021]=ge(!0);a[43]=R;a[7]=R;a[17]=R;a[18]=ge(!0);a[21]=R;a[22]=ce;var b=new hE([]);iE||(iE={a:-1,F:[,R,R,R,R,R,R,R,R,P]});a[26]=V(b,iE);b=new fE([]);gE||(gE={a:-1,F:[,R]});a[59]=V(b,gE);b=new $D([]);aE||(aE={a:-1,F:[]},aE.F=[,Zd(1)]);a[30]=V(b,aE);a[32]=ge(!0);a[36]=R;a[41]=ie;a[42]=ce;a[58]=R;a[33]=T;a[5]=R;a[6]=ge(!0);a[9]=R;a[14]=R;a[29]=R;a[40]=R;a[38]=he(1);a[50]=T;a[10]=R;b=new bE([]);cE||(cE={a:-1,F:[]}, +cE.F=[,T,T,,V(new OD([]),vE())]);a[19]=V(b,cE);b=new dE([]);eE||(eE={a:-1,F:[]},eE.F=[,T,T,V(new OD([]),vE())]);a[20]=V(b,eE);a[25]=R;a[48]=R;a[45]=R;a[51]=he(1);a[52]=P;a[54]=T;a[39]=R;a[57]=R;a[62]=ce;a[63]=ce;a[46]=R;a[60]=R;a[61]=R;a[64]=R;a[65]=R;a[1024]=R;a[12]=ge(!0);a[13]=R;a[15]=R;a[34]=R;a[4]=R;a[24]=R;a[47]=R};function xE(a){this.data=a||[]}var yE;F(xE,W);function oC(a){this.data=a||[]}var zE;F(oC,W);function AE(a){this.data=a||[]}var BE;F(AE,W);function CE(a){this.data=a||[]}var DE;F(CE,W);function EE(a){this.data=a||[]}var FE;F(EE,W);function GE(a){this.data=a||[]}var HE;F(GE,W);function IE(a){this.data=a||[]}var JE;F(IE,W);function KE(a){this.data=a||[]}var LE;F(KE,W);function ME(a){this.data=a||[]}var NE;F(ME,W);function OE(a){return new Oz(Ae(a,0))}EE.prototype.clearRect=function(){Be(this,2)};IE.prototype.getZoom=function(){return X(this,2)};KE.prototype.getZoom=function(){return X(this,1)};function PE(){NE||(NE={a:-1,F:[,de,de]});return NE};function QE(a){this.data=a||[]}var RE;F(QE,W); +function SE(){if(!RE){var a=RE={a:-1,F:[]};if(!FE){var b=[];FE={a:-1,F:b};b[1]=V(new Oz([]),Qz());var c=new GE([]);HE||(HE={a:-1,F:[,P,P]});b[6]=V(c,HE);c=new AE([]);BE||(BE={a:-1,F:[]},BE.F=[,V(new Oz([]),Qz()),P,re]);b[8]=V(c,BE);c=new IE([]);JE||(JE={a:-1,F:[]},JE.F=[,V(new ME([]),PE()),V(new ME([]),PE()),P]);b[3]=V(c,JE);c=new KE([]);LE||(LE={a:-1,F:[]},LE.F=[,V(new ME([]),PE()),Q,V(new ne([]),oe()),pe(oe()),V(new ne([]),oe()),V(new ne([]),oe()),Q,Vd("u",17)]);b[4]=V(c,LE);b[25]=U;c=new CE([]); +DE||(DE={a:-1,F:[]},DE.F=[,Vd("d",1),Yd,Yd,Vd("d",1),Yd,Yd]);b[1001]=V(c,DE)}b=pe(FE);if(!Pn){c=Pn={a:-1,F:[]};Rn||(Rn={a:-1,F:[,je,U]});var d=pe(Rn),e=new $k([]);if(!al){var f=al={a:-1,F:[]};bl||el();var g=pe(bl);cl||fl();var h=pe(cl);dl||gl();f.F=[,g,h,ie,pe(dl)]}c.F=[,T,U,P,d,ce,V(e,al),R,V(new Bn([]),Nn())]}c=pe(Pn);d=new oC([]);zE||(e=zE={a:-1,F:[]},f=new xE([]),yE||(yE={a:-1,F:[,P,P]}),f=V(f,yE),Tn||(Tn={a:-1,F:[]},g=Wd("e",37),h=Tn,Vn||Wn(),h.F=[,g,pe(Vn)]),e.F=[,,U,U,R,T,,f,,,,,pe(Tn),Q,, +U,R,R,R]);d=V(d,zE);e=V(new OD([]),vE());f=new YD([]);ZD||wE();f=V(f,ZD);g=Vd("v","");h=new jE([]);kE||(kE={a:-1,F:[,T,Yd,Yd,P,U,U,U]});h=V(h,kE);var k=new lE([]);mE||(mE={a:-1,F:[]},mE.F=[,T,ge(!0)]);k=V(k,mE);var l=new nE([]);oE||(oE={a:-1,F:[]},oE.F=[,T,R,Zd(1),R,R]);l=V(l,oE);var m=new pE([]);qE||(qE={a:-1,F:[,R]});m=V(m,qE);var n=new MD([]);ND||(ND={a:-1,F:[]},ND.F=[,,he(1),R,,,R,T,R,R,ae(-1),P,P,U,,R]);n=V(n,ND);var p=Vd("j",""),q=new tE([]);uE||(uE={a:-1,F:[,R,T]});q=V(q,uE);var t=new rE([]); +sE||(sE={a:-1,F:[]},sE.F=[,R,ge(!0),R,ge(!0),R,R]);a.F=[,b,c,d,T,e,f,U,g,h,,k,l,P,R,R,R,,m,R,n,p,q,ce,V(t,sE),P]}return RE}function TE(a){return new oC(Ae(a,2))}function mC(a,b){return new On(Ee(a,1,b))}function UE(a){return new On(De(a,1))};function VE(a){var b=new QE,c=LD[a];if(!B(c))throw Error("Unknown template: "+a);var d;if(d=c)d=SE(),d=!qs.a(c,b.data,d);if(d)throw Error("Failed to parse template:"+a);for(a=0;a<Fe(b,1);a++)c=mC(b,a),xe(c,7)&&(c=new Bn(c.data[7]),xe(c,7)&&(c=new wn(c.data[7]),xe(c,5)&&Be(new Fm(c.data[5]),5)));return b};function WE(a,b){Ib.call(this);this.f=b;this.a=[];if(a>this.f)throw Error("[goog.structs.SimplePool] Initial cannot be greater than max");for(b=0;b<a;b++)this.a.push(this.b())}F(WE,Ib);function XE(a,b){a.a.length<a.f?a.a.push(b):a.c(b)}WE.prototype.b=function(){return{}};WE.prototype.c=function(a){if(za(a))if(ya(a.$))a.$();else for(var b in a)delete a[b]};WE.prototype.X=function(){WE.R.X.call(this);for(var a=this.a;a.length;)this.c(a.pop());delete this.a};function YE(){this.a=[];this.f=new aB;this.m=this.o=this.s=this.i=0;this.b=new aB;this.g=this.l=0;this.u=1;this.h=new WE(0,4E3);this.h.b=function(){return new ZE};this.j=new WE(0,50);this.j.b=function(){return new $E};var a=this;this.c=new WE(0,2E3);this.c.b=function(){return String(a.u++)};this.c.c=function(){}}function $E(){this.Ud=this.time=this.count=0} +$E.prototype.toString=function(){var a=[];a.push(this.type," ",this.count," (",Math.round(10*this.time)/10," ms)");this.Ud&&a.push(" [VarAlloc = ",this.Ud,"]");return a.join("")};function ZE(){}function aF(a,b,c,d){var e=[];-1==c?e.push(" "):e.push(bF(a.b-c));e.push(" ",cF(a.b-b));0==a.a?e.push(" Start "):1==a.a?(e.push(" Done "),e.push(bF(a.g-a.startTime)," ms ")):e.push(" Comment ");e.push(d,a);0<a.f&&e.push("[VarAlloc ",a.f,"] ");return e.join("")} +ZE.prototype.toString=function(){return null==this.type?this.c:"["+this.type+"] "+this.c};YE.prototype.Ld=function(){};YE.prototype.reset=function(){for(var a=0;a<this.a.length;a++){var b=this.a[a];b.id&&XE(this.c,b.id);XE(this.h,b)}this.a.length=0;this.f.clear();this.i=E();this.g=this.l=this.m=this.o=this.s=0;a=this.b.nb();for(b=0;b<a.length;b++){var c=this.b.get(a[b]);c.count=0;c.time=0;c.Ud=0;XE(this.j,c)}this.b.clear()}; +YE.prototype.toString=function(){for(var a=[],b=-1,c=[],d=0;d<this.a.length;d++){var e=this.a[d];1==e.a&&c.pop();a.push(" ",aF(e,this.i,b,c.join("")));b=e.b;a.push("\n");0==e.a&&c.push("| ")}if(0!=this.f.c){var f=E();a.push(" Unstopped timers:\n");$A(this.f,function(b){a.push(" ",b," (",f-b.startTime," ms, started at ",cF(b.startTime),")\n")})}b=this.b.nb();for(d=0;d<b.length;d++)c=this.b.get(b[d]),1<c.count&&a.push(" TOTAL ",c,"\n");a.push("Total tracers created ",this.l,"\n","Total comments created ", +this.g,"\n","Overhead start: ",this.s," ms\n","Overhead end: ",this.o," ms\n","Overhead comment: ",this.m," ms\n");return a.join("")};function bF(a){a=Math.round(a);var b="";1E3>a&&(b=" ");100>a&&(b=" ");10>a&&(b=" ");return b+a}function cF(a){a=Math.round(a);return String(100+a/1E3%60).substring(1,3)+"."+String(1E3+a%1E3).substring(1,4)}new YE;function dF(a){Ib.call(this);this.b=a}F(dF,Ib);dF.prototype.a=function(a){return eF(this,a)};function fF(a,b){return(b?"__wrapper_":"__protected_")+(a[Aa]||(a[Aa]=++Ba))+"__"}function eF(a,b){var c=fF(a,!0);b[c]||((b[c]=gF(a,b))[fF(a,!1)]=b);return b[c]} +function gF(a,b){function c(){if(a.O())return b.apply(this,arguments);try{return b.apply(this,arguments)}catch(d){if(!(d&&"object"===typeof d&&d.message&&0==d.message.indexOf("Error in protected function: ")||"string"===typeof d&&0==d.indexOf("Error in protected function: ")))throw a.b(d),new hF(d);}finally{}}c[fF(a,!1)]=b;return c} +function iF(a,b){var c=ra("window"),d=c[b];c[b]=function(b,c){pa(b)&&(b=Ea(Fa,b));arguments[0]=b=eF(a,b);if(d.apply)return d.apply(this,arguments);var e=b;if(2<arguments.length){var f=Array.prototype.slice.call(arguments,2);e=function(){b.apply(this,f)}}return d(e,c)};c[b][fF(a,!1)]=d}dF.prototype.X=function(){var a=ra("window");var b=a.setTimeout;b=b[fF(this,!1)]||b;a.setTimeout=b;b=a.setInterval;b=b[fF(this,!1)]||b;a.setInterval=b;dF.R.X.call(this)}; +function hF(a){Ja.call(this,"Error in protected function: "+(a&&a.message?String(a.message):String(a)));(a=a&&a.stack)&&pa(a)&&(this.stack=a)}F(hF,Ja);function jF(a,b,c){rc.call(this);this.c=b||null;this.b={};this.h=kF;this.g=a;if(!c)if(this.a=null,pb&&!Ab("10"))Db(D(this.f,this));else{this.a=new dF(D(this.f,this));iF(this.a,"setTimeout");iF(this.a,"setInterval");a=this.a;b=ra("window");c=["requestAnimationFrame","mozRequestAnimationFrame","webkitAnimationFrame","msRequestAnimationFrame"];for(var d=0;d<c.length;d++){var e=c[d];c[d]in b&&iF(a,e)}a=this.a;Gb=!0;b=D(a.a,a);for(c=0;c<Eb.length;c++)Eb[c](b);Fb.push(a)}}F(jF,rc); +function lF(a,b){Qb.call(this,"a");this.error=a;this.context=b}F(lF,Qb);function kF(a,b,c,d){qD(a,null,b,c,d)}function mF(a,b){return a.a?eF(a.a,b):null} +jF.prototype.f=function(a,b){a=a.error||a;if(b){var c={};for(d in b)c[d]=b[d];b=c}else b={};a instanceof Error&&ib(b,a.__closure__error__context__984382||{});c=ra("window.location.href");if(pa(a))a={message:a,name:"Unknown error",lineNumber:"Not available",fileName:c,stack:"Not available"};else{var d=!1;try{var e=a.lineNumber||a.line||"Not available"}catch(q){e="Not available",d=!0}try{var f=a.fileName||a.filename||a.sourceURL||x.$googDebugFname||c}catch(q){f="Not available",d=!0}a=!d&&a.lineNumber&& +a.fileName&&a.stack&&a.message&&a.name?a:{message:a.message||"Not available",name:a.name||"UnknownError",lineNumber:e,fileName:f,stack:a.stack||"Not available"}}if(this.c)try{this.c(a,b)}catch(q){}f=a.message.substring(0,1900);e=a.stack;try{var g=lB(this.g,"script",a.fileName,"error",f,"line",a.lineNumber);a:{var h=this.b,k;for(k in h){var l=!1;break a}l=!0}if(!l){l=g;var m=kB(this.b);g=hB(l,m)}m={};m.trace=e;if(b)for(var n in b)m["context."+n]=b[n];var p=kB(m);qa(null)&&(p=p.substring(0,null));this.h(g, +"POST",p,this.i)}catch(q){}try{this.dispatchEvent(new lF(a,b))}catch(q){}};jF.prototype.X=function(){Lb(this.a);jF.R.X.call(this)};function nF(a){var b=a[Aa]||(a[Aa]=++Ba),c=Error();c.message="~#!#~"+b+"~#!#~"+a.message+"~#!#~";throw c;};function oF(a,b){a.imageSmoothingEnabled=b;a.mozImageSmoothingEnabled=b;a.webkitImageSmoothingEnabled=b;a.msImageSmoothingEnabled=b}function pF(a,b){2==a&&zc?(0>=qF&&(qF=go("canvas").getContext("2d").webkitBackingStorePixelRatio||1),a=b/qF):a=b;return a}var qF=-1;function rF(a,b){this.i=a;this.l=[];this.j=b;this.a=!1;this.h=this.b=0;this.f=this.c=this.id=this.g=-1}rF.prototype.cancel=function(){this.a=!0};function sF(){this.j=this.m=this.l=this.o=this.C=0}sF.prototype.u=function(a){var b=this.C+a.C;this.o+=a.o;this.m+=a.m;this.l=Math.max(this.l,a.l);this.j=Math.max(this.j,a.j);this.C=b};function tF(){this.a=[];this.b=[]}function uF(a){0==a.a.length&&(a.a=a.b,a.a.reverse(),a.b=[])}function vF(a){return 0==a.a.length&&0==a.b.length}tF.prototype.clear=function(){this.a=[];this.b=[]};tF.prototype.ob=function(){for(var a=[],b=this.a.length-1;0<=b;--b)a.push(this.a[b]);var c=this.b.length;for(b=0;b<c;++b)a.push(this.b[b]);return a};function wF(){this.a={};this.b=this.c=void 0}function xF(a,b,c){c=Math.floor(c);a.a[c]||(a.a[c]=new tF);a.a[c].b.push(b);if(!B(a.c)||c<a.c)a.c=c;if(!B(a.b)||c>a.b)a.b=c}function yF(a){(a=zF(a))?(uF(a),a=a.a.pop()):a=void 0;return a}function AF(a){if(!B(a.b))return-1;for(var b=a.b;b>=a.c;b--)if(a.a[b]&&!vF(a.a[b]))return b;return-1}function BF(a){(a=zF(a))?(uF(a),a=a.a,a=a[a.length-1]):a=void 0;return a} +function zF(a){if(!B(a.b))return null;for(var b=a.b;b>=a.c;b--)if(a.a[b]&&!vF(a.a[b]))return a.a[b];return null};function CF(a,b){this.h=new sF;for(var c=0;c<a.length;c++){var d=a[c];d.id=c;d.webkitPostMessage&&(d.postMessage=d.webkitPostMessage);d.addEventListener("message",D(this.o,this),!1)}this.i=10*a.length;this.b=a;this.s=new wF;this.c=Array(this.b.length);for(c=0;c<this.b.length;c++)this.c[c]=0;this.g={};this.a=this.j=this.f=0;this.l=b||sa}function DF(a){a=a();for(var b=Array(1),c=0;c<b.length;c++)b[c]=new Worker(a);return new CF(b,void 0)} +CF.prototype.m=function(){var a=this.h,b=new sF;b.C=a.C;b.o=a.o;b.l=a.l;b.m=a.m;b.j=a.j;this.h=new sF;return b};function EF(a,b){b.c=E();FF(a,b,a.a);a.a=(a.a+1)%a.b.length}function GF(a){for(;a.f<a.i;){var b=a.a;if(10>a.c[b]){var c=yF(a.s);if(!B(c))break;FF(a,c,b)}a.a=(a.a+1)%a.b.length}}function FF(a,b,c){if(!b.a){var d=a.j++;b.id=d;b.f=c;var e=b.i,f=b.l,g={};g.id=d;g.command=1;g.payload=e;a.b[c].postMessage(g,f);e=E()-b.c;b.h=e;a.g[d]=b;a.c[c]++;a.f++}} +CF.prototype.o=function(a){var b=a.data.id,c=a.data.payload,d=a.data.logs,e=a.data.complete,f=a.data.time;a=a.data.received;if(d)for(var g=0;g<d.length;g++)this.l(d[g]);B(b)&&(d=this.g[b])&&(d.b+=f,a&&(d.g=a-(d.c+d.h)),e&&(f=this.h,a=d.g,g=d.b,f.o+=a,f.m+=g,a>f.l&&(f.l=a),g>f.j&&(f.j=g),f.C++,delete this.g[b],this.c[d.f]--,this.f--,GF(this)),d.a||d.j(c,e))}; +CF.prototype.abort=function(a){a.cancel();if(!(0>a.id)){var b={};b.abort=a.id;var c=a.f;this.b[c].postMessage(b);this.c[c]--;this.f--;delete this.g[a.id];GF(this)}};function HF(a){this.data=a||[]}F(HF,W);function IF(){var a=JF.sc();return!!ye(a,0,void 0)};function JF(a){this.data=a||[]}F(JF,HF);ta(JF);function KF(a){this.b=a.toString();a="";var b=this.b.indexOf("?");0<=b&&(a=this.b.substring(b+1),this.b=this.b.substring(0,b));this.c=a?"&"+a:"";1<this.b.length&&"/"!=this.b[this.b.length-1]&&(this.b+="/")}KF.prototype.a=function(a){"/"==a[0]&&(a=a.slice(1));return this.b+a+this.c};function LF(){this.G=!0;this.T=this.u=!1;this.L=5;this.s=null;this.la=1;this.v=this.j=["//www.google.com/maps/vt"];this.l=[];this.ga=this.fa=this.I=!0;this.U=["/kh?v=0"];this.ia=["//mt0.google.com/vt?lyrs=t"];this.O=["/vt/stream"];this.K=["/vt"];this.P={};this.C=69;this.c=1;this.B=!1;this.h=null;this.m=!1;this.Y=this.H=null;this.W=this.M=this.V=this.a=!1;this.J=1;this.A=this.D=null;this.Nb=this.i=!1;this.g=null;this.Z=!0;this.f=0;this.S=!0;this.b=this.viewport=null;var a=JF.sc();this.ja=X(a,14);this.ha= +!!ye(a,4,void 0);this.o=function(){return sa}}function MF(a,b){if(a.P[b])return a.P[b];var c=encodeURIComponent(a.f.toString());b=encodeURIComponent(b);c="st?ep="+c+"&cs="+b+"&fmt=compact";0<a.l.length&&(c+="&expIds="+a.l.join(","));return(new KF(a.j[0])).a(c)}function NF(a){if(!a.b)return 0;var b=1;1==a.c&&(b|=2,a.i&&(b|=4));return b};function OF(){this.l=1024;this.j=768;this.v=this.u=null;this.C=this.A=!1;this.g=x.devicePixelRatio||1;this.f="en";this.c="us";this.b=!0;this.m=new Es(Is.a.slice());this.s=new Js;this.a=new Es(Is.a.slice());this.h=new Js;this.i=2;this.B=!0;this.o=this.D=!1}function PF(a,b){for(var c=[],d=0;d<a.length;d++)c[d]=a[d]+b;return c};function QF(){this.b=!1;this.a=null;this.c=0}var RF=1;QF.prototype.clear=function(){this.b=!1};QF.prototype.wait=function(a,b,c){var d=RF++;if(this.b&&(c?!b.call(c,a):!b(a)))return d;this.a||(this.a=[]);this.a.push({handle:d,qc:b,scope:c});return d};function SF(){this.height=this.width=this.o=this.s=this.a=this.b=this.ta=this.c=this.m=this.l=this.j=this.f=this.i=this.h=this.g=void 0}function TF(a,b){return!!b&&a.g==b.g&&a.h==b.h&&a.i==b.i&&a.f==b.f&&a.j==b.j&&a.l==b.l&&a.m==b.m&&a.c==b.c&&a.ta==b.ta&&a.b==b.b&&a.a==b.a&&a.s==b.s&&a.o==b.o&&a.width==b.width&&a.height==b.height};function UF(a){this.length=a.length||a;for(var b=0;b<this.length;b++)this[b]=a[b]||0}UF.prototype.a=4;UF.prototype.set=function(a,b){b=b||0;for(var c=0;c<a.length&&b+c<this.length;c++)this[b+c]=a[c]};UF.prototype.toString=Array.prototype.join;"undefined"==typeof Float32Array&&(UF.BYTES_PER_ELEMENT=4,UF.prototype.BYTES_PER_ELEMENT=UF.prototype.a,UF.prototype.set=UF.prototype.set,UF.prototype.toString=UF.prototype.toString,Ia("Float32Array",UF));function VF(a){this.length=a.length||a;for(var b=0;b<this.length;b++)this[b]=a[b]||0}VF.prototype.a=8;VF.prototype.set=function(a,b){b=b||0;for(var c=0;c<a.length&&b+c<this.length;c++)this[b+c]=a[c]};VF.prototype.toString=Array.prototype.join;if("undefined"==typeof Float64Array){try{VF.BYTES_PER_ELEMENT=8}catch(a){}VF.prototype.BYTES_PER_ELEMENT=VF.prototype.a;VF.prototype.set=VF.prototype.set;VF.prototype.toString=VF.prototype.toString;Ia("Float64Array",VF)};function WF(){return new Float64Array(3)}function XF(a,b,c,d){a[0]=b;a[1]=c;a[2]=d;return a}function YF(a,b,c){c[0]=a[0]+b[0];c[1]=a[1]+b[1];c[2]=a[2]+b[2]}function ZF(a,b,c){c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2]}function $F(a,b,c){c[0]=a[0]*b;c[1]=a[1]*b;c[2]=a[2]*b}function aG(a){var b=a[0],c=a[1];a=a[2];return b*b+c*c+a*a}function bG(a,b){var c=a[0],d=a[1];a=a[2];var e=1/Math.sqrt(c*c+d*d+a*a);b[0]=c*e;b[1]=d*e;b[2]=a*e;return b}function cG(a,b){return a[0]*b[0]+a[1]*b[1]+a[2]*b[2]};function dG(a,b){a[0]=b[0];a[1]=b[1];a[2]=b[2]};function eG(){return new Float64Array(4)}function fG(a,b,c){c[0]=a[0]*b;c[1]=a[1]*b;c[2]=a[2]*b;c[3]=a[3]*b};function gG(){return new Float64Array(16)}function hG(a,b,c,d){var e=-Math.PI,f=Math.PI;a[0]=b;a[1]=0;a[2]=0;a[3]=0;a[4]=0;a[5]=c;a[6]=0;a[7]=0;a[8]=0;a[9]=0;a[10]=d;a[11]=0;a[12]=e;a[13]=f;a[14]=0;a[15]=1}function iG(a,b){a[0]=b[0];a[1]=b[1];a[2]=b[2];a[3]=b[3];a[4]=b[4];a[5]=b[5];a[6]=b[6];a[7]=b[7];a[8]=b[8];a[9]=b[9];a[10]=b[10];a[11]=b[11];a[12]=b[12];a[13]=b[13];a[14]=b[14];a[15]=b[15]}function jG(a,b,c){c[0]=a[b];c[1]=a[b+4];c[2]=a[b+8];c[3]=a[b+12]} +function kG(a,b,c){var d=a[0],e=a[1],f=a[2],g=a[3],h=a[4],k=a[5],l=a[6],m=a[7],n=a[8],p=a[9],q=a[10],t=a[11],v=a[12],u=a[13],w=a[14];a=a[15];var y=b[0],A=b[1],z=b[2],C=b[3],I=b[4],S=b[5],ca=b[6],Z=b[7],ha=b[8],ea=b[9],ja=b[10],Y=b[11],ma=b[12],Ga=b[13],wa=b[14];b=b[15];c[0]=d*y+h*A+n*z+v*C;c[1]=e*y+k*A+p*z+u*C;c[2]=f*y+l*A+q*z+w*C;c[3]=g*y+m*A+t*z+a*C;c[4]=d*I+h*S+n*ca+v*Z;c[5]=e*I+k*S+p*ca+u*Z;c[6]=f*I+l*S+q*ca+w*Z;c[7]=g*I+m*S+t*ca+a*Z;c[8]=d*ha+h*ea+n*ja+v*Y;c[9]=e*ha+k*ea+p*ja+u*Y;c[10]=f*ha+ +l*ea+q*ja+w*Y;c[11]=g*ha+m*ea+t*ja+a*Y;c[12]=d*ma+h*Ga+n*wa+v*b;c[13]=e*ma+k*Ga+p*wa+u*b;c[14]=f*ma+l*Ga+q*wa+w*b;c[15]=g*ma+m*Ga+t*wa+a*b} +function lG(a,b){var c=a[0],d=a[1],e=a[2],f=a[3],g=a[4],h=a[5],k=a[6],l=a[7],m=a[8],n=a[9],p=a[10],q=a[11],t=a[12],v=a[13],u=a[14];a=a[15];var w=c*h-d*g,y=c*k-e*g,A=c*l-f*g,z=d*k-e*h,C=d*l-f*h,I=e*l-f*k,S=m*v-n*t,ca=m*u-p*t,Z=m*a-q*t,ha=n*u-p*v,ea=n*a-q*v,ja=p*a-q*u,Y=w*ja-y*ea+A*ha+z*Z-C*ca+I*S;0!=Y&&(Y=1/Y,b[0]=(h*ja-k*ea+l*ha)*Y,b[1]=(-d*ja+e*ea-f*ha)*Y,b[2]=(v*I-u*C+a*z)*Y,b[3]=(-n*I+p*C-q*z)*Y,b[4]=(-g*ja+k*Z-l*ca)*Y,b[5]=(c*ja-e*Z+f*ca)*Y,b[6]=(-t*I+u*A-a*y)*Y,b[7]=(m*I-p*A+q*y)*Y,b[8]=(g*ea- +h*Z+l*S)*Y,b[9]=(-c*ea+d*Z-f*S)*Y,b[10]=(t*C-v*A+a*w)*Y,b[11]=(-m*C+n*A-q*w)*Y,b[12]=(-g*ha+h*ca-k*S)*Y,b[13]=(c*ha-d*ca+e*S)*Y,b[14]=(-t*z+v*y-u*w)*Y,b[15]=(m*z-n*y+p*w)*Y)}function mG(a,b,c){var d=b[0],e=b[1];b=b[2];var f=1/(d*a[3]+e*a[7]+b*a[11]+a[15]);c[0]=(d*a[0]+e*a[4]+b*a[8]+a[12])*f;c[1]=(d*a[1]+e*a[5]+b*a[9]+a[13])*f;c[2]=(d*a[2]+e*a[6]+b*a[10]+a[14])*f} +function nG(a,b){var c=Math.cos(b);b=Math.sin(b);a[0]=1;a[1]=0;a[2]=0;a[3]=0;a[4]=0;a[5]=c;a[6]=b;a[7]=0;a[8]=0;a[9]=-b;a[10]=c;a[11]=0;a[12]=0;a[13]=0;a[14]=0;a[15]=1}function oG(a,b,c,d){a[12]+=a[0]*b+a[4]*c+a[8]*d;a[13]+=a[1]*b+a[5]*c+a[9]*d;a[14]+=a[2]*b+a[6]*c+a[10]*d;a[15]+=a[3]*b+a[7]*c+a[11]*d} +function pG(a,b){var c=a[4],d=a[5],e=a[6],f=a[7],g=a[8],h=a[9],k=a[10],l=a[11],m=Math.cos(b);b=Math.sin(b);a[4]=c*m+g*b;a[5]=d*m+h*b;a[6]=e*m+k*b;a[7]=f*m+l*b;a[8]=c*-b+g*m;a[9]=d*-b+h*m;a[10]=e*-b+k*m;a[11]=f*-b+l*m}function qG(a,b){var c=a[0],d=a[1],e=a[2],f=a[3],g=a[8],h=a[9],k=a[10],l=a[11],m=Math.cos(b);b=Math.sin(b);a[0]=c*m+g*-b;a[1]=d*m+h*-b;a[2]=e*m+k*-b;a[3]=f*m+l*-b;a[8]=c*b+g*m;a[9]=d*b+h*m;a[10]=e*b+k*m;a[11]=f*b+l*m} +function rG(a,b){var c=a[0],d=a[1],e=a[2],f=a[3],g=a[4],h=a[5],k=a[6],l=a[7],m=Math.cos(b);b=Math.sin(b);a[0]=c*m+g*b;a[1]=d*m+h*b;a[2]=e*m+k*b;a[3]=f*m+l*b;a[4]=c*-b+g*m;a[5]=d*-b+h*m;a[6]=e*-b+k*m;a[7]=f*-b+l*m}function sG(a,b){b[0]=a[12];b[1]=a[13];b[2]=a[14]};function tG(a,b,c,d){a=ao(a);b=ao(b);b=Yn(b,-1.48442222974533,1.48442222974533);d[0]=a;a=Math.sin(b);d[1]=.5*Math.log((1+a)/(1-a));d[2]=c/(6371010*Math.cos(b))}function uG(a,b,c,d,e){vG(a,b,c,d,e);d[0]=180*d[0]/Math.PI;d[1]=180*d[1]/Math.PI}function vG(a,b,c,d,e){b=2*Math.atan(Math.exp(b))-Math.PI/2;c=c*(e||6371010)*Math.cos(b);d[0]=a;d[1]=b;d[2]=c}function wG(a){a=ao(a);a=Yn(a,-1.48442222974533,1.48442222974533);return 1/(6371010*Math.cos(a))} +function xG(a,b,c,d){var e=Math.cos(b);c+=6371010;XF(d,c*e*Math.cos(a),c*e*Math.sin(a),c*Math.sin(b))}function yG(a,b,c,d,e){d=(1<<d)/(2*Math.PI);e[0]=(Math.PI+a)*d;e[1]=(Math.PI-b)*d;e[2]=c*d}function zG(a,b,c,d){c=2*Math.PI/(1<<c);d[0]=a*c-Math.PI;d[1]=-b*c+Math.PI;d[2]=0*c};function AG(a,b){this.o=a;this.c=0;this.a=[];this.l=null!=b?b:24;this.m=0;this.b=new wF;this.g=0;this.i={};this.h=-1;this.j=void 0}function BG(a,b){this.b=a;this.a=this.c=this.f=!1;this.priority=b;this.startTime=0}function CG(a){return(a=a.a[0])?a.length:0} +function DG(a,b,c){var d=b.b;if(!d||d.priority!=c){if(d)a:if(b=d,b.f){d=a.b;for(var e=Math.floor(c),f=d.b;f>=d.c;f--){var g;if(g=d.a[f]){g=d.a[f];var h=b;var k=g.a;var l=La(k,h);0<=l?(Array.prototype.splice.call(k,l,1),k=!0):k=!1;g=k||Ta(g.b,h)}if(g){xF(d,b,e);break}}b.priority=c}else{if(b.c){d=0==a.m;e=AF(a.b)<=c;if(c>b.priority||d||e){a.ec(b);a.Uc(b,c);break a}EG(a,b.b)&&FG(a,b,c)}b.a&&(EG(a,b.b),FG(a,b,c))}else d=new BG(b,c),b.b=d,FG(a,d,c);if(0!=a.l&&a.c==a.l)for(b=!1,d=1;d<c;d++){if(a.a[d]&& +0<a.a[d].length)for(e=a.a[d],f=e.length-1;g=e[f];f--)if(g.b.cancel()){b=!0;g.b.b&&a.ec(g);FG(a,g,d);break}if(b)break}a.Ac()}}r=AG.prototype;r.start=function(){for(var a=0;4>a&&this.Wc();++a){var b=this.Be();if(!b)break;GG(this,b)}for(a=3;1<=a&&!(this.a[a]&&0<this.a[a].length);a--);for(b=1;3>=b;b++)if(b<a){var c=this.i[b];if(c&&0<c.length)for(;0<c.length;){var d=c.pop();d.a=!1;this.g+=-1;d.b.cancel();FG(this,d,b)}}if(this.Wc())return this.start;this.j=void 0;return Dr}; +r.Wc=function(){var a=0==this.l||this.c<this.l;return-1!=AF(this.b)&&a};r.Ac=function(){var a=AF(this.b);if(-1!=a){var b=0;2==a?b=1:3==a&&(b=2);B(this.j)?this.j<b&&(this.o.qd(this,b),this.j=b):(this.o.ed(this,b),this.j=b)}};function GG(a,b){a.Uc(b,b.priority);b.b.start(function(){HG(a,b)})}function FG(a,b,c){b.priority=c;IG(a,b,!0);xF(a.b,b,c)}r.Be=function(){for(var a=yF(this.b);a&&!a.f;)a=yF(this.b);if(!a)return null;IG(this,a,!1);return a}; +r.ec=function(a){this.a[a.priority]&&Ta(this.a[a.priority],a);a.c=!1;this.c+=-1;0==this.c&&-1!=this.h&&(x.clearTimeout(this.h),this.h=-1)};r.Uc=function(a,b){this.a[b]?this.a[b].push(a):this.a[b]=[a];a.startTime=E();a.c=!0;this.c+=1;a.priority=b;-1==this.h&&JG(this)}; +function JG(a){a.h=x.setTimeout(function(){if(0<a.c&&-1!=a.h){for(var b=E(),c=[],d=1;3>=d;d++){var e=a.a[d];if(e)for(var f=0;f<e.length;++f){var g=e[f];1E4<=b-g.startTime&&c.push(g)}}for(b=0;b<c.length;++b)d=a,e=c[b],d.ec(e),d.i[e.priority]?d.i[e.priority].push(e):d.i[e.priority]=[e],f=d,e.a=!0,f.g+=1,d.Ac();0<a.c?JG(a):a.h=-1}},1E4)}function HG(a,b){b&&(b.c?a.ec(b):b.a&&(Ta(a.i[b.priority],b),b.a=!1,a.g+=-1),b.b.b=null);a.Ac()} +function EG(a,b){var c=b.b,d=!1;if(c&&(c.c||c.a)){if(b.cancel()||c.a)HG(a,c),d=!0}else c&&c.f&&(IG(a,c,!1),d=!0);d&&(b.b=null);return d}function IG(a,b,c){b.f=c;a.m+=c?1:-1};function KG(a,b){AG.call(this,a,b);this.f=0}F(KG,AG);r=KG.prototype;r.Uc=function(a,b){KG.R.Uc.call(this,a,b);b>this.f&&(this.f=b)};r.ec=function(a){KG.R.ec.call(this,a);a=a.priority;if(a==this.f&&!this.a[a].length){this.f=0;for(var b=a;0<=b;--b)if(this.a[a].length){this.f=b;break}}};r.Be=function(){for(var a=BF(this.b);a&&!a.f;)yF(this.b),a=BF(this.b);if(!a||a.priority<this.f||0==a.priority&&!(0==this.g&&1>CG(this)))return null;yF(this.b);IG(this,a,!1);return a}; +r.Wc=function(){var a=KG.R.Wc.call(this),b=AF(this.b);0==b&&(a=a&&0==this.g&&1>CG(this));return a&&b>=this.f};r.Ac=function(){AF(this.b)<this.f||KG.R.Ac.call(this)};function LG(a,b){this.a=a;this.b=b};function MG(a,b){return new cs(a,b)};function NG(a,b){if(OG){var c=OG;c.c[a]=b;c.b[a]=!1;c.a[a]=[];c.f[a]=!1}else PG.push({id:a,If:b})}Ia("disposeModuleLoader",function(){OG&&OG.$();OG=null});var OG=null,PG=[];function QG(){this.a=this.s=this.h=0}QG.prototype.u=function(a){this.h+=a.h;this.s+=a.s;this.a+=a.a};QG.prototype.m=function(){var a=new QG;a.h=this.h;a.s=this.s;a.a=this.a;return a};function RG(){this.D=this.v=this.A=this.B=0}RG.prototype.u=function(a){this.B+=a.B;this.A+=a.A;this.v+=a.v;this.D+=a.D};RG.prototype.m=function(){var a=new RG;a.B=this.B;a.A=this.A;a.v=this.v;a.D=this.D;return a};function SG(a,b){this.b=a;this.c=b;this.a={}}SG.prototype.clear=function(){this.a={}};function TG(a,b){return null!=b&&0<b&&null!=a.c&&b<a.c?!1:!0};function UG(a,b,c){this.f=a;this.a=0;this.c=!1;this.b=new SG(b,c)}UG.prototype.h=function(a){var b=this.b.a[a.getZoom()];a=b?(b=b[a.a])?b[a.b]||null:null:null;if(null!==a)return this.f.B++,a;this.c=!0;if(this.a)return this.f.v++,this.a;this.f.A++;return null};UG.prototype.g=function(a){for(var b=null,c=!0,d=0;d<a.length;++d){var e=a[d];null!==e&&-1!=e&&(null===b||e>=b)&&(b=e);-1!=e&&(c=!1)}c&&(b=-1);return b}; +UG.prototype.i=function(a,b,c){if(!(b&&b>c)){b=this.b;var d=a.getZoom();b.a[d]||(b.a[d]={});d=b.a[d];var e=a.a;d[e]||(d[e]={});a=a.b;d=d[e];TG(b,c)&&(null!=c?(B(d[a])?b.b.s++:b.b.h++,d[a]=c):d[a]&&delete d[a]);this.c=!1;TG(this.b,c)&&c>this.a&&(this.a=c)}}; +UG.prototype.j=function(a){var b=this.b,c=new Oz(a.data[1]),d=X(c,1),e=X(c,2),f=c.getZoom();c=Ce(a,3);var g=X(a,2),h=c.length/g;b.a[f]||(b.a[f]={});f=b.a[f];for(var k=0;k<h;++k){var l=e+k;f[l]||(f[l]={});l=f[l];for(var m=0;m<g&&k*g+m<c.length;++m){var n=d+m,p=c[k*g+m];TG(b,p)&&(B(l[n])?b.b.s++:b.b.h++,l[n]=p)}}a=Ce(a,3);for(b=0;b<a.length;++b)TG(this.b,a[b])&&a[b]>this.a&&(this.a=a[b]);0<a.length&&(this.c=!1)};function VG(){this.a={};this.b={};this.c=new QG;this.f=new RG}function WG(a){for(var b in a.a)if(a.a[b].a.c)return!0;return!1}function XG(a,b){this.c=a;this.a=b;this.b=0};/* + Portions of this code are from MochiKit, received by + The Closure Authors under the MIT license. All other code is Copyright + 2005-2009 The Closure Authors. All Rights Reserved. +*/ +function YG(a,b){this.g=[];this.s=a;this.o=b||null;this.f=this.a=!1;this.c=void 0;this.l=this.u=this.i=!1;this.h=0;this.b=null;this.j=0}YG.prototype.cancel=function(a){if(this.a)this.c instanceof YG&&this.c.cancel();else{if(this.b){var b=this.b;delete this.b;a?b.cancel(a):(b.j--,0>=b.j&&b.cancel())}this.s?this.s.call(this.o,this):this.l=!0;this.a||(a=new ZG(this),$G(this),aH(this,!1,a))}};YG.prototype.m=function(a,b){this.i=!1;aH(this,a,b)};function aH(a,b,c){a.a=!0;a.c=c;a.f=!b;bH(a)} +function $G(a){if(a.a){if(!a.l)throw new cH(a);a.l=!1}}YG.prototype.qc=function(a){$G(this);aH(this,!0,a)};function dH(a,b,c){a.g.push([b,c,void 0]);a.a&&bH(a)}YG.prototype.then=function(a,b,c){var d,e,f=new WC(function(a,b){d=a;e=b});dH(this,d,function(a){a instanceof ZG?f.cancel():e(a)});return f.then(a,b,c)};UC(YG);function eH(a){return Pa(a.g,function(a){return ya(a[1])})} +function bH(a){if(a.h&&a.a&&eH(a)){var b=a.h,c=fH[b];c&&(x.clearTimeout(c.a),delete fH[b]);a.h=0}a.b&&(a.b.j--,delete a.b);b=a.c;for(var d=c=!1;a.g.length&&!a.i;){var e=a.g.shift(),f=e[0],g=e[1];e=e[2];if(f=a.f?g:f)try{var h=f.call(e||a.o,b);B(h)&&(a.f=a.f&&(h==b||h instanceof Error),a.c=b=h);if(VC(b)||"function"===typeof x.Promise&&b instanceof x.Promise)d=!0,a.i=!0}catch(k){b=k,a.f=!0,eH(a)||(c=!0)}}a.c=b;d&&(h=D(a.m,a,!0),d=D(a.m,a,!1),b instanceof YG?(dH(b,h,d),b.u=!0):b.then(h,d));c&&(b=new gH(b), +fH[b.a]=b,a.h=b.a)}function cH(a){Ja.call(this);this.a=a}F(cH,Ja);cH.prototype.message="Deferred has already fired";cH.prototype.name="AlreadyCalledError";function ZG(a){Ja.call(this);this.a=a}F(ZG,Ja);ZG.prototype.message="Deferred was canceled";ZG.prototype.name="CanceledError";function gH(a){this.a=x.setTimeout(D(this.c,this),0);this.b=a}gH.prototype.c=function(){delete fH[this.a];throw this.b;};var fH={};function hH(a){return iH&&qa(iH[a])?iH[a]:null}var iH=null;function jH(){if(!x.Worker||null==Xn())return!1;var a=new ArrayBuffer(1);var b=[];var c=x.BlobBuilder||x.WebKitBlobBuilder;if(B(c)){c=new c;for(var d=0;d<b.length;d++)c.append(b[d],void 0);b=c.getBlob("text/javascript")}else if(B(x.Blob))b=new Blob(b,{type:"text/javascript"});else throw Error("This browser doesn't seem to support creating Blobs");c=Xn();if(null==c)throw Error("This browser doesn't seem to support blob URLs");b=c.createObjectURL(b);try{var e=new Worker(b)}catch(f){return!1}e.postMessage(a, +[a]);e.terminate();return 0==a.byteLength};function kH(){if(x.location)return!1;var a=hH("worker");null===a&&(a=hH("workers"));if(0===a)a=!1;else if(1===a)a=!0;else if(a=(!uc||Ab(37))&&jH()&&null!=Xn())(a=x.location)?(new mB(a),a=!1):a=!0;return a};function lH(a,b,c){Pp.call(this);this.b=a;this.s=b;this.g=new so(b.a,void 0,!1);this.o=c;a=go("canvas");this.o.appendChild(a);this.h=this.b.i||2;2==this.h&&(a.style.position="absolute");this.i=new io(a);a=this.h;b=this.i;c=this.b.g;var d=this.b.l,e=this.b.j;try{var f=b.a,g=pF(a,c),h=Math.max(d*g,1),k=Math.max(e*g,1);yc||pb?(h=Math.round(h),k=Math.round(k)):(h=Math.floor(h),k=Math.floor(k));if(f.width!==h||f.height!==k||b.c!==c)b.c=c,f.width=h,f.height=k,f.style.width=d+"px",f.style.height=e+"px"}catch(l){f= +Error(),f.message="setCanvasSize: Error accessing canvas.",nF(f)}if(1==a){g=new wo;g.h=this.b.B;g.i=this.b.D;g.g=this.b.o;g.a=!0;g.f=!0;g.c=!0;g.b=4096;f=this.i;g=g||new wo;h=void 0;g.g&&(h=MG);g=Bo(f.a,g,h);if(!g)throw Error("Could not find a 3d context, error: "+Ao);f=new eq(f,g);Qp(this,f);f=new LG(f,null)}else if(2==a){f=this.i.a;g=null;f.getContext&&(g=f.getContext("2d"));f=g;if(!f)throw Error("Could not create 2D context.");f=new LG(null,f)}else throw Error("Unsupported context type");this.j= +f;this.a=this.l=this.c=this.f=null;this.m=new QF}F(lH,Pp);function mH(a){if(!a.a)throw Error("Not initialized.");return a.a}r=lH.prototype;r.Bf=function(a){a&&a()}; +function nH(a,b,c){if(!OG)throw Error("Module loader requested but none has been injected.");var d=OG;c=D(a.Hf,a,b,c);var e=D(d.h,d,1,D(a.rf,a,c,b)),f=kH(),g=!b.b;f&&g&&(b.b=DF(function(){return null.toString()}));e();oH(d,1);b=a.h;if(1==b)oH(d,2),b=3;else if(2==b)b=4;else throw Error("Unsupported context type");d.h(b,D(a.sf,a,c));oH(d,b)}r.rf=function(a,b){var c=this.s.a;this.c=new pH(b,c,new KG(c,0));a()};r.sf=function(a,b,c){this.l=c.a();a()}; +r.Hf=function(a,b){if(this.c&&this.l){var c=this.l,d=this.j,e=this.i,f=this.g,g=this.c,h=new qH,k=new rH;k=new sH(k,a.i,a.viewport||void 0);var l=a.I;k.h!=l&&(k.h=l,tH(k));1!=k.o&&(k.o=!0,tH(k));1!=k.m&&(k.m=!0,tH(k));uH(k,a.i);l=e.a;var m=e.c,n=vH(k);n.width=Math.ceil(l.width/m);n.height=Math.ceil(l.height/m);wH(k,n);l=new xH(new yH(g.oc));this.a=c.a(a,d,e,h,k,g,l,l,f,void 0);a=this.a.b;var p;c=this.b;d=this.f||void 0;e=c.s;f=c.m;c.b&&c.a.a.length<f.a.length&&Gs(c.a.a[0],f.a[0])&&(p=new Os(c.h,c.a, +c.f,c.c,d));p=new Os(e,f,c.f,c.c,d,p);Ps(a.B,p)||(a.B=p,tH(a));zH(this);this.a.h();p=this.g;p.a=this.a;uo(p);b()}};function zH(a){AH(mH(a).b.a,function(){var b=a.m;if(!b.b&&b.a){b.b=!0;b.c+=1;try{for(var c=0,d=b.a.length;c<d;c++){var e=b.a[c],f=!1;if(e)if(e.scope)f=e.qc.call(e.scope,a);else{var g=e.qc;f=g(a)}f||(1==b.c?(b.a.splice(c,1),--c,--d):b.a[c]=null)}}finally{--b.c}}b.b=!1})}r.X=function(){this.g.$();this.a&&this.a.$();this.a=null;this.c&&this.c.$();this.c=null;lH.R.X.call(this)};function BH(){this.a=this.b=this.c=0};function CH(a,b){this.G=0;this.u=!!a;this.K=b;this.I=a?D(this.Nd,this):sa;this.s=!1;a=document;this.v=(this.b=!(a.hidden||a.webkitHidden||a.mozHidden||a.msHidden))?0:E()+5E3;lo(D(this.M,this));E();this.h=!1;this.i=[];this.f=[];this.g=[];this.a=[];this.a[0]=[];this.a[1]=[];this.a[2]=[];this.a[3]=[];this.a[4]=[];this.a[5]=[];this.D=[];this.J=new BH;this.m=this.l=!1;var c=this;this.L=function(){c.l=!1;c.zc()};this.B=function(){c.m=!1;c.xb()};this.O=x.requestAnimationFrame||x.webkitRequestAnimationFrame|| +x.mozRequestAnimationFrame||x.oRequestAnimationFrame||x.msRequestAnimationFrame;Er.push(this)}function DH(a){a.s||(a.s=!0,x.requestIdleCallback(a.I))}r=CH.prototype;r.Nd=function(a){for(;this.s;){this.s=!1;for(var b=!0;a.timeRemaining()>=this.K;){try{var c=EH(this,!0)}catch(d){c=!0}if(!c){b=!1;break}}if(b){DH(this);break}}};r.Te=function(a){this.i.push(a);this.c()};r.Pd=function(a){this.f.push(a);this.c()};r.Ue=function(a){this.g.push(a);this.c()};r.Mb=function(a,b){FH(this,a,GH(b,!1))}; +r.ed=function(a,b){FH(this,a,GH(b,!0))};function GH(a,b){a*=2;b&&(a+=1);return a}function FH(a,b,c){var d=b.__maps_realtime_JobScheduler_next_step;d&&d!=Dr||(b.__maps_realtime_JobScheduler_next_step=b.start,b.__maps_realtime_JobScheduler_priority=c,a.a[c].push(b),a.u?DH(a):a.h||HH(a))}r.Pe=function(a){a.__maps_realtime_JobScheduler_next_step=null}; +r.qd=function(a,b){if(a.__maps_realtime_JobScheduler_next_step){var c=a.__maps_realtime_JobScheduler_priority;b=1==c||3==c||5==c?GH(b,!0):GH(b,!1);if(c!=b){for(var d=this.a[c].length,e=0;e<d;++e)if(this.a[c][e]==a){this.a[c][e]=null;break}a.__maps_realtime_JobScheduler_priority=b;this.a[b].push(a)}}};r.zc=function(){EH(this,!1)};function EH(a,b){a.h=!0;var c=!1,d=E();try{for(var e=5;0<=e;){if(IH(a,e,b)){if(c=!0,b)break}else e--;if(!b&&1<=E()-d)break}}finally{E(),a.h=!1,a.u||JH(a)}return c} +r.xb=function(){var a=E();this.h=!0;var b=0,c=this.D;if(0<c.length){for(b=0;b<c.length;b++)this.Mb(c[b].Df,c[b].priority);this.D=[]}try{E();var d=this.i;this.i=[];var e=d.length;for(c=0;c<e;c++){var f=d[c];KH();Mr(f)}E();var g=0<this.g.length||0<this.f.length;if(this.b){var h=this.J;d=g;var k=a-h.a;0<h.a&&(h.c++,h.b+=k);h.a=a;d||(h.a=0)}if(0==this.G%1){if(this.b){E();var l=this.f;this.f=[];var m=l.length;for(a=0;a<m;a++){var n=l[a];KH();Qr(n)}E()}E();var p=this.g;this.g=[];var q=p.length;for(l=0;l< +q;l++){var t=p[l];KH();vo(t)}E()}E();for(b=5;0<=b&&!IH(this,b,!0);b--);}finally{E(),this.h=!1,g&&this.b&&this.c(),this.u||JH(this),this.G++}};function JH(a){for(var b=!1,c=0;5>=c;c++)b|=0<a.a[c].length;b&&HH(a)}Hb(function(a){CH.prototype.xb=a(CH.prototype.xb);CH.prototype.zc=a(CH.prototype.zc);CH.prototype.Nd=a(CH.prototype.Nd)}); +function IH(a,b,c){var d=!1,e=a.a[b];if(0==e.length)return d;for(var f=E(),g=0;g<e.length;g++){var h=e[g];if(h){var k=h.__maps_realtime_JobScheduler_next_step;if(k){for(;k!=Dr&&0==E()-f;){d=!0;KH();k=Dr;try{k=h.__maps_realtime_JobScheduler_next_step()}finally{h.__maps_realtime_JobScheduler_next_step=k}if(c)break}k==Dr&&g++;break}}}a.a[b]=e.slice(g);return d} +CH.prototype.C=function(){if(0<this.g.length||0<this.f.length||0<this.i.length)return!0;if(!B(void 0))return!1;for(var a=GH(void 0,!1);5>=a;a++)if(this.a[a].length)return!0;return!1};function KH(){x.performance&&x.performance.now||E()}function HH(a){!a.b&&E()>a.v||a.l||(a.l=!0,ur(a.L,void 0,!0))}CH.prototype.c=function(){!this.b&&E()>this.v||this.m||(this.m=!0,this.b?this.O.call(x,this.B):ur(this.B,void 0,!0))}; +CH.prototype.M=function(a){if(this.b=a)this.m||this.c(),this.u||this.l||HH(this);this.v=this.b?0:E()+5E3};CH.prototype.j=function(){return sa};function LH(){CH.call(this);this.o=0;this.A=!1;var a=this;this.H=function(){a.xb()}}F(LH,CH);LH.prototype.j=function(){var a=this;a.o++;return function(){a.o--;0==a.o&&a.C()&&a.c()}};LH.prototype.zc=function(){MH(this)};LH.prototype.xb=function(){this.A=!1;MH(this);0<this.o||LH.R.xb.call(this)};LH.prototype.c=function(){this.A||(this.A=!0,ur(this.H,void 0,!0))};function MH(a){do var b=EH(a,!1);while(b)};function NH(a){this.f=null;this.b=0;this.c=!0;this.a=0;this.g=a;this.i=this.h=0}NH.prototype.setLineDash=function(a){this.f=a;this.c=!0;this.b=0;this.a=0<a.length?a[0]:0};NH.prototype.moveTo=function(a,b){this.h=a;this.i=b;this.g.moveTo(a,b)}; +NH.prototype.lineTo=function(a,b){var c=this.h,d=this.i,e=a-c,f=b-d,g=Math.sqrt(e*e+f*f);if(0!=g){e/=g;for(f/=g;0<g;){if(g>this.a){var h=this.a;g-=h;this.a=0}else h=g,this.a-=h,g=0;c+=e*h;d+=f*h;this.c?this.g.lineTo(c,d):this.g.moveTo(c,d);0==this.a&&(this.b=this.b==this.f.length-1?0:this.b+1,this.a=this.f[this.b],this.c=!this.c)}this.h=a;this.i=b}};function OH(a){return"rgba("+(a>>16&255)+","+(a>>8&255)+","+(a&255)+","+((a>>24&255)/255).toFixed(2)+")"}function PH(a){return"rgba("+Math.floor(255*a[0])+","+Math.floor(255*a[1])+","+Math.floor(255*a[2])+","+a[3]+")"};function QH(){} +QH.prototype.c=function(a,b,c,d,e){var f=c.g;var g=c.h[c.f];0>g||g>=f.c?f=0:(RH(f,g),f=f.b.length);g=f;if(!(1>g)){f=Array(g);for(var h=0;h<g;++h){var k=h;var l=h;var m=c.g,n=c.h[c.f];0>n||n>=m.c?l=new Float32Array(0):(RH(m,n),l=m.a.subarray(2*(0<l?m.b[l-1]:0),2*m.b[l]));f[k]=l}c=c.ka();if(h=SH(b,c))if(c=b=!1,g=null,h&&h.D&&(a.fillStyle=OH(aA(h,e)),b=!0),h&&0<h.c&&(k=uA(h,0,e),0<k&&(a.lineWidth=k*d,g=Zz(h,0,e),a.strokeStyle=OH(tA(h,0,e)),c=!0)),c||b){if(!(d=!c)&&(d=!g))b:{for(d=0;d<f.length;d++)if(!TH(f[d])){d= +!1;break b}d=!0}if(d)UH(a,f),b&&a.fill("evenodd"),c&&a.stroke();else{b&&(UH(a,f),a.fill("evenodd"));d=g;a.beginPath();e=a;d&&(e=a.setLineDash?a:new NH(a),e.setLineDash(d));e.lineJoin="round";for(b=0;b<f.length;b++){c=f[b];e.moveTo(c[0],c[1]);for(g=2;g<=c.length-2;g+=2)VH(c[g],c[g+1],c[g-2],c[g-1])?e.lineTo(c[g],c[g+1]):e.moveTo(c[g],c[g+1]);VH(c[0],c[1],c[c.length-2],c[c.length-1])&&e.lineTo(c[0],c[1])}a.stroke();d&&e.setLineDash([])}}}}; +function UH(a,b){a.beginPath();for(var c=0;c<b.length;c++){var d=b[c];a.moveTo(d[0],d[1]);for(var e=2;e<d.length;e+=2)a.lineTo(d[e],d[e+1]);a.lineTo(d[0],d[1])}}function TH(a){for(var b=0;b<a.length-2;b+=2)if(!VH(a[b],a[b+1],a[b+2],a[b+3]))return!1;return VH(a[0],a[1],a[a.length-2],a[a.length-1])}function VH(a,b,c,d){return(0<=a||0<=c)&&(256>=a||256>=c)&&(0<=b||0<=d)&&(256>=b||256>=d)};function WH(a,b){this.x=a;this.y=b}F(WH,eo);WH.prototype.add=function(a){this.x+=a.x;this.y+=a.y;return this};var XH=[.2,.2,.2,1],YH=[242/255,239/255,233/255,1],ZH=[0,0,0,1],$H=[0,0,0,0],aI=[1,1,1,0],bI=[1,1,1,.4],cI=[1,1,1,.2],dI=[0,0,0,0],eI=[.4,.4,.4,.4],fI=[.4,.4,.4,.2];function gI(a,b){return 0<=a.indexOf(1)?3:0<=a.indexOf(0)?0<=b.indexOf(1)?2:1:0}function hI(a,b){switch(gI(a,b)){case 1:return YH;case 2:return XH;case 3:return $H;default:return ZH}};function iI(){}function jI(a,b,c,d,e,f){c>e||d>f||(1>b[3]&&a.clearRect(c,d,e,f),0<b[3]&&(a.fillStyle=PH(b),a.fillRect(c,d,e,f)))}function kI(a,b,c,d,e,f,g){var h=(c.y-d.y)/(c.x-d.x);d=c.y-c.x*h;c=c.y-(c.x-e)*h;0>d&&0>c||d>f&&c>f||(a.beginPath(),a.moveTo(0,g),a.lineTo(0,d),a.lineTo(e,c),a.lineTo(e,g),a.closePath(),1>b[3]&&(a.globalCompositeOperation="destination-out",a.fillStyle="#000",a.fill(),a.globalCompositeOperation="source-over"),0<b[3]&&(a.fillStyle=PH(b),a.fill()))};var lI=Math.pow(2,22);function mI(){this.c=this.b=this.a=null}mI.prototype.w=function(){var a=[];if(null!==this.a){var b=this.a;a[0]=b}null!==this.b&&(b=this.b,a[1]=b);null!==this.c&&(b=this.c,a[2]=b);return a};mI.prototype.getExtension=function(){return null};function nI(a){return null==a.a?1:a.a} +yd(vy,96629873,11,function(){return new mI},function(){},function(a,b){for(;G(b);)switch(b.a){case 1:var c=J(b);a.a=c;break;case 2:c=K(b);a.b=c;break;case 3:c=K(b);a.c=c;break;default:H(b)}},function(a){if(null===a)a=null;else{var b=new mI;b.a=null;b.b=null;b.c=null;b.a=a.a;b.b=a.b;b.c=a.c;a=b}return a},function(a,b){return a===b?!0:null===a||null===b?!1:a.a!==b.a||a.b!==b.b||a.c!==b.c?!1:!0});function oI(a,b){return(a&65535|(b&65535)<<16)>>>0}function pI(a,b,c){a=Math.round(1073741824*(a*b+c));return a|0}function qI(a,b,c){a=Math.round(16*(a*b+c));return a&65535};function rI(a,b){return b?12>a:!1};function sI(a,b){this.A=a;this.v=b;this.l=this.j=0;this.u=1;this.s=16;this.h=new Uint32Array(3072);this.b=0;this.f=new Int32Array(1024);this.m=this.o=this.a=0;this.c=[];this.g=0;this.i=!1}sI.prototype.reset=function(a,b,c,d){this.j=B(a)?a:0;this.l=B(b)?b:0;this.u=B(c)?c:1;this.s=B(d)?d:16;this.a=this.b=0;this.i=!1;this.g=0};function tI(a){a.a=0;a.g=0}function uI(a){a.a=0;a.g=0} +function vI(a,b,c){var d=a.a/2,e=0==c?2:1;c=0==c?1:2;for(var f=0;f<d-2;f++)a.index(b),a.index((b+f+e)%d),a.index((b+f+c)%d)}function wI(a,b,c){var d=a.f;var e=a.a+1;e>=d.length&&(e=new Int32Array(2*e),e.set(d),d=e);a.f=d;a.f[a.a]=b;a.f[a.a+1]=c;a.a+=2}sI.prototype.index=function(a){this.i?(this.c[2*this.g]=this.f[2*a],this.c[2*this.g+1]=this.f[2*a+1],this.g=(this.g+1)%3,0==this.g&&xI(this)):yI(this,this.f[2*a],this.f[2*a+1])}; +function xI(a){function b(a,b,c,d){a=c-a;b=d-b;return a*a+b*b}var c=a.c[0],d=a.c[1],e=a.c[2],f=a.c[3],g=a.c[4],h=a.c[5],k=!1;if(262144<b(c,d,e,f)||262144<b(e,f,g,h)||262144<b(g,h,c,d))k=!0;if(k){k=(c+e+g)/3;var l=(d+f+h)/3;zI(a,k,l,c,d,e,f);zI(a,k,l,e,f,g,h);zI(a,k,l,g,h,c,d)}else yI(a,c,d),yI(a,e,f),yI(a,g,h)}function zI(a,b,c,d,e,f,g){f-=d;g-=e;var h=Math.ceil(Math.sqrt(f*f+g*g)/512);f/=h;g/=h;for(var k=0;k<h;k++)yI(a,b,c),yI(a,d+f*k,e+g*k),yI(a,d+f*(k+1),e+g*(k+1))} +function yI(a,b,c){var d=a.h;var e=a.b;e>=d.length&&(e=new Uint32Array(2*e),e.set(d),d=e);a.h=d;d=a.h;e=a.b;if(1==a.v){var f=a.u/a.s;d[e++]=pI(b,f,a.j);d[e++]=pI(c,f,a.l)}else d[e++]=oI(b,c);1==a.A&&(d[e++]=a.o,d[e++]=a.m);a.b=e};function AI(a){var b=a.getExtension(96629873);if(b&&(null==b.c?0:b.c))return lI;(b=null==a.u)||(b=null==Cy(a).a);if(b)return 16;a=Cy(a);switch(null==a.a?0:a.a){case 0:return 16;case 2:return 4;case 3:return 8;case 1:return 16;case 4:return 32;case 5:return 64;case 6:return 128;default:return 16}}function BI(a){for(var b=a.a,c=0;a.a<a.c;)ad(a),ad(a),c++;a.a=b;return c}function CI(a){for(var b=a.a,c=0;a.a<a.c;)ad(a),ad(a),ad(a),c++;a.a=b;return c} +function DI(a,b,c,d){for(var e=0,f=0,g=0;g<2*b;g+=2)e+=a.da(),f+=a.da(),d[g+0]=e/c,d[g+1]=f/c}function EI(a,b,c,d){for(var e=0,f=0,g=0,h=0;h<3*b;h+=3)e+=a.da()/c,f+=a.da()/c,g+=a.da()/c,d[h+0]=e,d[h+1]=f,d[h+2]=g} +function FI(a,b,c,d){var e=Sw(a);a=null===a.a?zd(a.g,a.j,a.K):Tc(null,null,a.a);if(12<=c)d=!1;else{var f=256*Math.pow(2,c-12)*b.C;16>=b.C&&(f=Math.max(f,256*b.C/8))}var g=c=0;b.V=b.a;b.h=0;b.g&&(b.v=[]);b.A=!1;b.B=!1;b.m=!1;b.c=!1;b.M=0;for(var h=b.u=0;!e.kb();h++){var k=e.da();var l=e.da();if(h==a.get())c+=k,g+=l,k=b,k.c=!1,k.h=0,k.u=0,a.next(),GI(b,c,g);else if(0<h&&d){var m=Math.sqrt(k*k+l*l);if(0<m){m=Math.ceil(m/f);for(var n=1;n<=m;n++)GI(b,c+n*k/m|0,g+n*l/m|0);c+=k;g+=l}}else c+=k,g+=l,GI(b, +c,g)}HI(b);Vc(e);Uc(a)}function II(a,b){var c=ex(a);var d=null===a.h?zd(a.a,a.o,a.O):Tc(null,null,a.h);a=null===a.g?zd(a.a,a.C,a.S):Tc(null,null,a.g);var e=0,f=0;JI(b);for(var g=0;!c.kb();g++){e+=c.da();f+=c.da();if(g==d.get()){var h=b;KI(h);JI(h);d.next()}GI(b,e,f);g==a.get()&&(b.c=!1,a.next())}KI(b);Vc(c);Uc(d);Uc(a)} +function LI(a,b,c){function d(a,c,d){var e=1;c&&(e+=c.length);for(var f=0,g=0,h=0,k=0;k<e;k++){var l=-1;c&&k<e-1&&(l=c[k]);if(a.kb())break;for(d?uI(b):b.a=0;!a.kb()&&f!=l;)g+=a.da(),h+=a.da(),wI(b,g,h),f++;if(d)vI(b,0,1);else{l=b;for(var u=l.a/2,w=0;w<u-2;w++){var y=w%2;l.index(w);l.index(w+1+y);l.index(w+2-y)}}}}if(fx(a)||null!=a.c||null!=a.l||null!=a.i||null!=a.m||null!=a.j){b.i=c;if(fx(a)||null!=a.c){(c=null!=a.c?!0:!1)?uI(b):tI(b);for(var e=0,f=0,g=ex(a);!g.kb();)e+=g.da(),f+=g.da(),wI(b,e,f); +Vc(g);if(fx(a)){for(e=ix(a);!e.kb();)b.index(e.next());Uc(e)}c&&vI(b,null==a.c?-1:a.c,0)}if(null!=a.l||null!=a.i)c=mx(a),e=null!=a.v||null!=a.D?nx(a):null,d(c,e,!0),Vc(c);if(null!=a.m||null!=a.j)c=ox(a),a=null!=a.B||null!=a.G?px(a):null,d(c,a,!1),Vc(c)}};function MI(a){this.h=a.a;this.j=a.b;this.g=null;this.b=(this.a=Ey(this.h)&&jy(Fy(this.h))?Fy(this.h).a:null)?this.a.length:0;this.i=-1;this.f=null;this.c=-1}function NI(a,b){if(a.i!=b){var c=a.a[b];if(null!=c.f||null!=c.c){var d=Sw(c);a.c=null!=c.i?null==c.i?0:c.i:BI(d);if(!a.f||a.f.length<2*a.c)a.f=new Float32Array(2*a.c);c=AI(a.h);DI(d,a.c,c,a.f);Vc(d)}a.g=a.j.a[1][b];a.i=b}}MI.prototype.ka=function(a){if(0>a||a>=this.b)return 0;NI(this,a);return this.g.ka()}; +function OI(a,b){Tw(a)&&0<b?(--b,Nw(a),a=a.a[b]):a=0;return a}function PI(a,b,c){Tw(b)&&c<Uw(b)?(Nw(b),a=b.a[c]):a=a.c;return a}function QI(a,b,c){if(0>b||b>=a.b)return 0;NI(a,b);a=Vw(a.a[b]);return 3==a?0==c?0:1:a}function RI(a,b,c){if(0>b||b>=a.b)return 0;NI(a,b);a=Ww(a.a[b]);return 3==a?0==c?0:1:a}function SI(a,b){if(0>b||b>=a.b)return 0;NI(a,b);return a.g.za};function TI(a){this.f=a.a;this.j=a.b;this.b=this.a=this.h=null;this.c=(this.g=Gy(this.f)&&ly(Hy(this.f))?Hy(this.f).a:null)?this.g.length:0;this.i=-1} +function RH(a,b){if(a.i!=b){var c=a.g[b];if(null==c.c?0:c.c){c=4;if(!a.a||a.a.length<2*c)a.a=new Float32Array(2*c);a.a[0]=0;a.a[1]=0;a.a[2]=256;a.a[3]=0;a.a[4]=256;a.a[5]=256;a.a[6]=0;a.a[7]=256;a.b=[c]}else{var d=ux(c),e=ex(d);c=null!=d.b?null==d.b?0:d.b:BI(e);if(!a.a||a.a.length<2*c)a.a=new Float32Array(2*c);var f=AI(a.f);DI(e,c,f,a.a);Vc(e);a.b=null!=d.h||null!=d.o?lx(d):[];a.b.push(c)}a.h=a.j.a[2][b];a.i=b}}TI.prototype.ka=function(a){if(0>a||a>=this.c)return 0;RH(this,a);return this.h.ka()}; +function UI(a,b){if(0>b||b>=a.c)return 0;RH(a,b);return a.h.za};function VI(a){this.g=a.a;this.j=a.b;this.l=a.j;this.h=null;this.i=null!=this.g.a&&ry(Ly(this.g))?Ly(this.g).Aa:[];this.f=0;this.i&&WI(this)}function XI(a){var b=a.f;return 0<=b&&b<a.i.length}r=VI.prototype;r.Sc=function(){return XI(this)};function WI(a){XI(a)&&(a.h=a.j.a[5][a.f])}r.hd=function(){this.f++;this.Sc()&&WI(this)};r.reset=function(){this.f=0;WI(this)};r.ka=function(){return this.h.ka()};r.jd=function(){return this.h.za};function YI(a,b){for(var c=Array(a.length),d=0;d<a.length;d++)c[d]={index:d,value:a[d]};c.sort(ZI);b?(a=b,a.length=c.length):a=Array(c.length);for(d=0;d<c.length;d++)a[d]=c[d].index;return a}function ZI(a,b){return a.value!=b.value?a.value-b.value:a.index-b.index};function $I(a,b){this.b=a;a=this.b;a=null==a.a?0:a.a.length;if(!b||b.length!=a){for(var c=Array(a),d=0;d<a;d++)c[d]=SI(this.b,d);b=YI(c,b)}this.c=b;this.a=0}function aJ(a){var b=new $I(a.b,a.c);b.a=a.a;return b}r=$I.prototype;r.Sc=function(){return this.c.length>this.a};r.hd=function(){this.a++};r.reset=function(){this.a=0};r.ka=function(){return this.b.ka(this.c[this.a])};r.jd=function(){return SI(this.b,this.c[this.a])};function bJ(a){this.g=a;a=this.g.c;for(var b=Array(a),c=0;c<a;c++)b[c]=UI(this.g,c);a=YI(b,void 0);this.h=a;this.f=0}r=bJ.prototype;r.Sc=function(){return this.h.length>this.f};r.hd=function(){this.f++};r.reset=function(){this.f=0};r.ka=function(){return this.g.ka(this.h[this.f])};r.jd=function(){return UI(this.g,this.h[this.f])};function cJ(a,b,c,d){this.type=a;this.c=B(b)?b:0;this.a=B(c)?c:null;this.b="boolean"==typeof d?d:!1}function dJ(a){a=eJ(a.l,a.g,a.f);a.Qb()&&a.Ib(3);return a.Ab()}function fJ(a){this.b=a;this.a=[];var b=a.data;this.a[0]=new $I(new MI(b));this.a[1]=new VI(b);this.a[2]=new bJ(new TI(b));a.b&&(a=a.b.data,this.a[3]=new $I(new MI(a)),this.a[4]=new VI(a),this.a[5]=new bJ(new TI(a)))}function gJ(a,b,c){return c?a.a[3+b]:a.a[b]}function hJ(a){for(var b=0;b<a.a.length;b++)a.a[b].reset()} +function iJ(a,b){this.b=a;this.a=b};function jJ(a,b,c,d){this.m=a;this.j=b;this.l=c;this.o=d;this.i=d.b;this.c=0;this.a=new fJ(d);this.f=this.g=null;this.h=0;this.b=[];a=this.a;b=this.b;c=[];for(d=0;d<a.a.length;d++)c[d]=a.a[d].Sc()?a.a[d].jd():-1;var e=-1,f=null;for(d=0;;d++){for(var g=-1,h=0;h<c.length;h++)0<=c[h]&&(0>g||c[h]<c[g])&&(g=h);if(0>g)break;h=a.a[g];var k=g%3,l=0,m=3<=g;if(0==k){l=m?a.b.b.a.f:a.b.a.f;var n=h.ka();l=SH(l,n).c;n=c[g];if(f){f.a<l&&(f.a=l);var p=h.b;var q=h.c[h.a];0>q||q>=p.b?p=0:(NI(p,q),p=p.g.b);p>e?(f=new iJ(d, +l),e=n):n<e&&(e=n)}else f=new iJ(d,l),f.a=l,e=n}else f&&(f=null);h.hd();c[g]=h.Sc()?h.jd():-1;b.push(new cJ(k,l,f,m))}hJ(a)}function kJ(a){a.h=0;a.c=0;hJ(a.a)} +function lJ(a,b,c,d,e){for(var f=a.b.length,g=0,h=a.h;h<f&&(0>e||g<e);h++){var k=a.b[h],l=gJ(a.a,k.type,k.b),m=k.type,n=(k.b?a.i:a.o).a.f;0==m?k.c>a.c&&(a.m.c(b,n,l,c,d,a.c),g++):(1==m?a.l.c(b,n,l,c,d):a.j.c(b,n,l,c,d),g++);if(k.a)if(h+1==f||a.b[h+1].a!=k.a)if(a.c<k.a.a-1){a.c++;h=k.a.b-1;a.g&&(a.a.a[0]=a.g,a.g=null);a.f&&(a.a.a[3]=a.f,a.f=null);continue}else a.g=null,a.f=null,a.c=0;else k.a.b==h&&a.c<k.a.a-1&&(a.g=aJ(gJ(a.a,0)),a.i&&(a.f=aJ(gJ(a.a,0,!0))));l.hd()}a.h=h};function mJ(){this.c={};this.b=this.a=null;this.f=0}mJ.prototype.has=function(a){a:{if(a=this.c[a]){if(a.b){a=!0;break a}nJ(this,a)}a=!1}return a};mJ.prototype.get=function(a){return this.c[a]};mJ.prototype.add=function(a){if(a&&!a.f){this.c[a.key]=a;a.f=!0;a.next=null;if(a.c=this.a)this.a.next=a;this.a=a;this.b||(this.b=this.a);for(this.f++;1E4<this.f;)this.b&&nJ(this,this.b)}};function nJ(a,b){delete a.c[b.key];b.f=!1;b.c?b.c.next=b.next:a.b=b.next;b.next?b.next.c=b.c:a.a=b.c;a.f--};function oJ(a,b,c,d){this.c=a;this.f=b;this.g=c;this.a=null;this.b=d} +function pJ(a,b,c){c=pF(2,c)/a.b;if(null!==a.a)a=a.a;else{var d=go("canvas"),e=d.getContext("2d"),f=pF(2,a.b);d.width=256*f;d.height=256*f;e.scale(f,f);e.fillStyle=a.c;e.fillRect(0,0,256,256);e.beginPath();e.strokeStyle=a.g;e.lineWidth=1;f=16;for(var g=256/f,h=1;h<g;h++){var k=h*f;e.moveTo(k,0);e.lineTo(k,256);k=h*f;e.moveTo(0,k);e.lineTo(256,k)}e.stroke();e.beginPath();e.lineWidth=2;e.strokeStyle=a.f;f=128;g=256/f;for(h=0;h<=g;h++)k=h*f,e.moveTo(k,0),e.lineTo(k,256),k=h*f,e.moveTo(0,k),e.lineTo(256, +k);e.stroke();a=a.a=d}b.drawImage(a,0,0,a.width*c,a.height*c)};function qJ(){}qJ.prototype.c=function(a,b,c){b=dJ(c);a.drawImage(b,0,0,256,256)};function rJ(){this.b=[];this.a=-1;this.c=0}var sJ=null;function tJ(){sJ||(sJ=new rJ);return sJ}function uJ(a,b,c){if(0==a.c){var d=go("canvas");d.width=b;d.height=c;return d}var e=a.a;for(d=0;d<a.a-1;d++)if(a.b[d]){var f=a.b[d].width>=b,g=a.b[d].height>=c;if(f||g)e=d;if(f&&g)break}d=a.b[e];a.b[e]=void 0;d.width<b||d.height<c?(d.width<b&&(d.width=b),d.height<c&&(d.height=c)):d.getContext("2d").clearRect(0,0,b,c);a.c--;if(0==a.c)a.a=-1;else if(e==a.a)for(;0<=a.a&&!a.b[a.a];)a.a--;return d} +function vJ(a,b){a.c==a.a+1?(a.b[a.c]=b,a.c++,a.a++):(a.b[a.b.indexOf(void 0)]=b,a.c++)};function wJ(){this.a=go("canvas");this.a.width=2048;this.a.height=2E3;this.f=this.c=0;this.b=40;this.g=0;this.h=[];xJ(this)}function xJ(a){for(;a.c!=a.f;)yJ(a);a.c=a.f=0;a.g=a.a.width*Math.floor(a.a.height/a.b)+1;a.h=Array(a.g);for(var b=Math.floor(a.a.height/a.b),c=0;c<b;c++)for(var d=Math.floor(a.a.width/a.b),e=0;e<d;e++){var f=e*a.b;zJ(a,new AJ(f,c*a.b,e==d-1?a.a.width-f:a.b,a.b))}} +function BJ(a,b,c){c>a.b&&(a.b=c,xJ(a));for(var d=0,e=0,f=a.a.width;d<b;){var g=yJ(a);d+=g.width;f=g.x<f?g.x:f;e=g.y;d<b&&g.x+g.width>=a.a.width&&(e=new AJ(f,e,d,a.b),zJ(a,e),d=0,f=a.a.width,e=0)}d-=b;c=new AJ(f,e,b,c);zJ(a,c);0!=d&&(e=new AJ(f+b,e,d,a.b),zJ(a,e));return c}function zJ(a,b){a.h[a.f]=b;a.f=++a.f%a.g}function yJ(a){var b=a.h[a.c];b&&(b.valid=!1);a.h[a.c]=null;a.c=++a.c%a.g;return b}function CJ(a,b){return b&&b.valid?a.a:null}var DJ=pb||!1; +function AJ(a,b,c,d){this.valid=!0;this.x=a;this.y=b;this.width=c;this.height=d};function EJ(a,b,c,d,e){this.canvas=a;this.width=b;this.height=c;this.a=0;this.c=d;this.b=e}function FJ(a){a.a--;0>=a.a&&(vJ(tJ(),a.canvas),a.b&&delete a.b.b[a.c])};function GJ(){this.a=[];this.b=0}GJ.prototype.reset=function(){this.b=0};GJ.prototype.append=function(a,b,c,d,e,f){var g=6*this.b;this.a[g+0]=a;this.a[g+1]=b;this.a[g+2]=c;this.a[g+3]=d;this.a[g+4]=e;this.a[g+5]=f;this.b++};function HJ(a){this.g=!!a;this.f=a?a:0;this.c=Array(this.f);this.a=0;this.b={}}HJ.prototype.has=function(a){return!!this.b[a]};HJ.prototype.get=function(a){return this.b[a]};HJ.prototype.set=function(a,b){this.g&&this.c[this.a]&&delete this.b[this.c[this.a]];this.b[a]=b;this.g&&(this.c[this.a]=a,this.a=(this.a+1)%this.f)};function IJ(){this.a=null;this.g=this.f=this.l=this.i=this.j=this.h=this.b=this.c=this.m=0}IJ.prototype.next=function(){if(0>this.b||this.b>=this.a.a)return!1;for(var a=this.i,b=this.l,c=JJ(this.a,this.b),d=KJ(this.a,this.b),e=c-a,f=d-b,g=this.m*(e*e+f*f),h=c-a,k=d-b,l=this.b+this.c;0<=l&&l<this.a.a;){var m=JJ(this.a,l),n=KJ(this.a,l),p=m-a,q=n-b,t=-p*k+q*h;if(t*t>g)break;c=m;d=n;e=p;f=q;l+=this.c}this.b=l;this.h=a;this.j=b;this.i=c;this.l=d;this.f=Math.atan2(f,e);this.g=Math.sqrt(e*e+f*f);return!0};function LJ(a,b){Pp.call(this);this.width=a;this.height=b}F(LJ,Pp);LJ.prototype.i=sa;function MJ(){return new Float32Array(16)}function NJ(a,b,c,d,e,f,g){a[0]=b;a[1]=0;a[2]=0;a[3]=0;a[4]=0;a[5]=c;a[6]=0;a[7]=0;a[8]=0;a[9]=0;a[10]=d;a[11]=0;a[12]=e;a[13]=f;a[14]=g;a[15]=1}function OJ(a,b){a[0]=b[0];a[1]=b[1];a[2]=b[2];a[3]=b[3];a[4]=b[4];a[5]=b[5];a[6]=b[6];a[7]=b[7];a[8]=b[8];a[9]=b[9];a[10]=b[10];a[11]=b[11];a[12]=b[12];a[13]=b[13];a[14]=b[14];a[15]=b[15]} +function PJ(a,b,c){var d=a[0],e=a[1],f=a[2],g=a[3],h=a[4],k=a[5],l=a[6],m=a[7],n=a[8],p=a[9],q=a[10],t=a[11],v=a[12],u=a[13],w=a[14];a=a[15];var y=b[0],A=b[1],z=b[2],C=b[3],I=b[4],S=b[5],ca=b[6],Z=b[7],ha=b[8],ea=b[9],ja=b[10],Y=b[11],ma=b[12],Ga=b[13],wa=b[14];b=b[15];c[0]=d*y+h*A+n*z+v*C;c[1]=e*y+k*A+p*z+u*C;c[2]=f*y+l*A+q*z+w*C;c[3]=g*y+m*A+t*z+a*C;c[4]=d*I+h*S+n*ca+v*Z;c[5]=e*I+k*S+p*ca+u*Z;c[6]=f*I+l*S+q*ca+w*Z;c[7]=g*I+m*S+t*ca+a*Z;c[8]=d*ha+h*ea+n*ja+v*Y;c[9]=e*ha+k*ea+p*ja+u*Y;c[10]=f*ha+ +l*ea+q*ja+w*Y;c[11]=g*ha+m*ea+t*ja+a*Y;c[12]=d*ma+h*Ga+n*wa+v*b;c[13]=e*ma+k*Ga+p*wa+u*b;c[14]=f*ma+l*Ga+q*wa+w*b;c[15]=g*ma+m*Ga+t*wa+a*b} +function QJ(a,b){var c=a[0],d=a[1],e=a[2],f=a[3],g=a[4],h=a[5],k=a[6],l=a[7],m=a[8],n=a[9],p=a[10],q=a[11],t=a[12],v=a[13],u=a[14];a=a[15];var w=c*h-d*g,y=c*k-e*g,A=c*l-f*g,z=d*k-e*h,C=d*l-f*h,I=e*l-f*k,S=m*v-n*t,ca=m*u-p*t,Z=m*a-q*t,ha=n*u-p*v,ea=n*a-q*v,ja=p*a-q*u,Y=w*ja-y*ea+A*ha+z*Z-C*ca+I*S;0!=Y&&(Y=1/Y,b[0]=(h*ja-k*ea+l*ha)*Y,b[1]=(-d*ja+e*ea-f*ha)*Y,b[2]=(v*I-u*C+a*z)*Y,b[3]=(-n*I+p*C-q*z)*Y,b[4]=(-g*ja+k*Z-l*ca)*Y,b[5]=(c*ja-e*Z+f*ca)*Y,b[6]=(-t*I+u*A-a*y)*Y,b[7]=(m*I-p*A+q*y)*Y,b[8]=(g*ea- +h*Z+l*S)*Y,b[9]=(-c*ea+d*Z-f*S)*Y,b[10]=(t*C-v*A+a*w)*Y,b[11]=(-m*C+n*A-q*w)*Y,b[12]=(-g*ha+h*ca-k*S)*Y,b[13]=(c*ha-d*ca+e*S)*Y,b[14]=(-t*z+v*y-u*w)*Y,b[15]=(m*z-n*y+p*w)*Y)}function RJ(a,b,c){var d=b[0],e=b[1],f=b[2];b=b[3];c[0]=d*a[0]+e*a[4]+f*a[8]+b*a[12];c[1]=d*a[1]+e*a[5]+f*a[9]+b*a[13];c[2]=d*a[2]+e*a[6]+f*a[10]+b*a[14];c[3]=d*a[3]+e*a[7]+f*a[11]+b*a[15]} +function SJ(a,b,c,d){var e=Math.cos(b);b=Math.sin(b);var f=Math.cos(c);c=Math.sin(c);var g=Math.cos(d);d=Math.sin(d);a[0]=e*g-f*b*d;a[1]=f*e*d+g*b;a[2]=d*c;a[3]=0;a[4]=-e*d-g*f*b;a[5]=e*f*g-b*d;a[6]=g*c;a[7]=0;a[8]=c*b;a[9]=-e*c;a[10]=f;a[11]=0;a[12]=0;a[13]=0;a[14]=0;a[15]=1};function TJ(a,b){this.a=a;this.b=b;this.altitude=0;this.screenX=a;this.screenY=b;this.c=!1}var UJ=new Float32Array(2),VJ=new Float32Array(2),WJ=new Float32Array(4);function XJ(){this.a=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];this.c=!1;this.b=this.data=null}function YJ(a){a.data=null;a.b=null}function ZJ(a,b){var c=a.a[12],d=0,e=0,f=0,g=0;b=b.a;for(var h=0;4>h;h++){var k=b[2*h]+c*b[2*h+1],l=b[2*h+1]-c*b[2*h];0==h?(d=e=k,f=g=l):(k<d&&(d=k),k>e&&(e=k),l<f&&(f=l),l>g&&(g=l))}c=a.a[15];b=a.a[16];h=a.a[14];return a.a[13]<=e&&d<=c&&h<=g&&f<=b};function $J(a,b){this.f=a;this.a=[];this.b=0;this.c=b}$J.prototype.get=function(){this.b==this.a.length&&this.a.push(new this.f);return this.a[this.b++]};function aK(a){if(a.c)for(var b=0;b<a.b;b++)a.c(a.a[b]);a.b=0};function bK(){this.a=new $J(XJ,YJ)} +function cK(a,b,c,d,e,f,g,h){a=a.a.get();a.data=g||null;a.b=h||null;g=d-b;h=e-c;var k=Math.sqrt(g*g+h*h);if(0<k){var l=f*-h/(2*k);f=f*g/(2*k)}else l=f/2,f/=2;a.a[0]=b+l;a.a[1]=c+f;a.a[2]=b-l;a.a[3]=c-f;a.a[4]=d+l;a.a[5]=e+f;a.a[6]=d-l;a.a[7]=e-f;l=0<l?l:-l;f=0<f?f:-f;b<d?(a.a[8]=b-l,a.a[10]=d+l):(a.a[8]=d-l,a.a[10]=b+l);c<e?(a.a[9]=c-f,a.a[11]=e+f):(a.a[9]=e-f,a.a[11]=c+f);0!=g&&0!=h?(a.c=!0,g=h/g,a.a[12]=g,c=b=a.a[0]+g*a.a[1],e=d=a.a[1]-g*a.a[0],f=a.a[6]+g*a.a[7],g=a.a[7]-g*a.a[6],f<b&&(b=f),f>c&& +(c=f),g<d&&(d=g),g>e&&(e=g),a.a[13]=b,a.a[15]=c,a.a[14]=d,a.a[16]=e):a.c=!1;return a}bK.prototype.reset=function(){aK(this.a)};function dK(){this.c=[];this.H=this.wb=this.J=this.g=0;this.l=this.G=null;this.v=0;this.B=this.ab=!1;this.f=this.j=0;this.s=!1;this.a=this.b=null;this.u=!1;this.h=-1;this.C=!0;this.m=this.D=0;this.K=22;this.i=this.I=this.A=!1;this.o=new oq(0,0,0,0);this.uc=!1}function eK(a,b){b.label=a;a.c.push(b)}function fK(a,b){return a.g-b.g||a.h-b.h}dK.prototype.Gb=function(a,b,c,d){this.ab!=a&&(c||!this.C?this.j=b-d:(c=this.j+d-b,this.j=0<c?b-c:b),this.ab=a,a=this.j+d,this.D<a&&(this.D=a));return this.D-b}; +function gK(a,b,c){var d=!1;a.ab&&1>a.f?(a.f=0<c?(b-a.j)/c:1,1<a.f&&(a.f=1),d=!0):!a.ab&&0<a.f&&(a.f=0<c?1-(b-a.j)/c:0,0>a.f&&(a.f=0),d=!0);a.A!=a.I&&(a.I=a.A,d=!0);return d}var hK=new oq(0,0,0,0);function iK(a){var b=a.c;0<b.length&&b[0].l(a.o);for(var c=1;c<b.length;++c){b[c].l(hK);var d=a.o,e=hK;d.left=Math.min(d.left,e.left);d.top=Math.min(d.top,e.top);d.right=Math.max(d.right,e.right);d.bottom=Math.max(d.bottom,e.bottom)}} +function jK(a){var b=kK;a=a.c;for(var c=[],d=0;d<a.length;++d)c=c.concat(a[d].s(b));return c}function lK(a){return!(a.H&8)&&a.A}function mK(a){this.type=a;this.label=null;this.o=this.f=this.a=0;this.c=null}function nK(a,b){return a.label.g-b.label.g||a.o-b.o}mK.prototype.A=sa;function oK(a){var b=new mJ;this.g=a;this.c=DJ;this.f=null;this.b=Array(2);this.h=new HJ(this.c?1E3:void 0);this.i=b;this.a=new GJ}var pK=new IJ;function qK(a,b,c,d,e,f,g){if(0!=c.f){for(var h=0;h<c.c.length;++h){var k=c.c[h].type;1!=k&&0!=k||rK(a,b,c.c[h],d,e,f,g)}for(h=0;h<c.c.length;++h)k=c.c[h].type,1!=k&&0!=k&&rK(a,b,c.c[h],d,e,f,g)}} +function rK(a,b,c,d,e,f,g){var h=0==c.type||5==c.type||2==c.type;h&&(b.save(),b.translate(-f,-g));switch(c.type){case 1:f=-1*c.height/2;g=c.width;var k=c.height,l=c.m,m=c.g;d=d.data;e=SH(e,c.a);if(c.label.b){d=sK(a.g,tK(d),uK(d),d.getZoom(),c.label.b,a.b);for(var n=0;n<d;++n){var p=vK(e);wK(b,a.b[2*n]+c.oa,a.b[2*n+1]+c.b+f,g,k,l,p.fill,p.outline,m,a.b[2*n],a.b[2*n+1],c.i,c.label.f)}}break;case 0:a=SH(e,c.a);e=c.label.f;d=c.f;xK(c.label.a,d);yK(b,c,d,e,a);break;case 3:f=c.c;zK(a,f,d.a.Y,e,c,d.data.getZoom()); +if(c.label.b)for(e=sK(a.g,tK(d.data),uK(d.data),d.data.getZoom(),c.label.b,a.b),d=0;d<e;++d)g=a.b[2*d]+c.oa,k=a.b[2*d+1]+c.b,g-=f.h,(l=AK(f))&&BK(b,l,f,g,k,c.label.f);break;case 4:d=d.data;f=d.getZoom();g=nI(wy(d.a));if((k=CK(e,c.a))&&fA(k,f)&&(k=fA(k,f),(g=Zs(k,c.g.width,c.g.height,k.b||g,c.text))&&0!=g.width&&0!=g.height&&(e=SH(e,c.a))&&fA(e,f)&&(e=c.label.f,0!=e&&c.label.b)))for(d=sK(a.g,tK(d),uK(d),d.getZoom(),c.label.b,a.b),f=0;f<d;++f)DK(b,g,a.b[2*f],a.b[2*f+1],c.g,c.h,e);break;case 5:a=d.data; +d=a.getZoom();a=nI(wy(a.a));(f=CK(e,c.a))&&fA(f,d)&&(f=fA(f,d),(a=Zs(f,c.g.width,c.g.height,f.b||a))&&0!=a.width&&0!=a.height&&(e=SH(e,c.a))&&fA(e,d)&&(e=c.label.f,0!=e&&(g=c.label.a,xK(g,c.f),k=EK(g.c,FK(c)),d=JJ(g,k),f=KJ(g,k),g=Math.atan2(KJ(g,Math.ceil(k))-KJ(g,Math.floor(k)),JJ(g,Math.ceil(k))-JJ(g,Math.floor(k))),b.save(),b.translate(d,f),b.rotate(g+(lK(c.label)?Math.PI:0)),DK(b,a,0,0,c.g,c.j,e),b.restore())));break;case 2:if(f=c.c,zK(a,f,d.a.V,e,c,d.data.getZoom()),k=(g=f.a)&&g.b,f.canvas|| +f.b||f.c||k)n=k?null:AK(f),k=c.label.f,l=c.f,lK(c.label)&&c.g&&(l*=-1),g?(m=GK(e,c.a),e=SH(e,c.a),f=HK(g,n,f.b),IK(a,b,m,e,d.data.getZoom(),c,f,lK(c.label),l,k)):JK(b,c,n,lK(c.label),l,k)}h&&b.restore()} +function zK(a,b,c,d,e,f){var g=!!b.canvas||!!b.c||KK(a,b.b);b=b.a;if(!(b&&b.b||g)&&(c=c.j,b=GK(d,e.a),d=SH(d,e.a),e.c))if(e=e.c,e.a)LK(c,e,b,d,f,a.i);else if(e.g)a:{var h=a=null;if((g=e.g)&&g.c&&g.c.complete){if(b=MK(c,g.key,b))if(g.b){h=g.c;var k=g.b;if(d.s){var l=NK(c,k.width,k.height),m=l.getContext("2d");m.globalAlpha=(eA(d,f)>>24&255)/255;m.drawImage(h,k.left,k.top,k.width,k.height,0,0,k.width,k.height);m.globalAlpha=1;h=l}else h=null}else{if(g.a&&g.c){e.c=new OK(g.a,g.c,(dA(d,f)>>24&255)/255); +break a}}else a=PK(c,g.c,f,d,g.a.left,g.a.top,g.a.width,g.a.height),g.b&&(h=PK(c,g.c,f,d,g.b.left,g.b.top,g.b.width,g.b.height,g.b.width));k=g.a;h&&(k=(g.b.width-g.a.width)/2,l=(g.b.height-g.a.height)/2,k=Math.floor(k),l=1==g.b.height%2?Math.floor(l):Math.floor(l+.5),e.h=k,e.j=l,m=h.getContext("2d"),m.globalCompositeOperation="source-over",b?(d.l&&(m.globalAlpha=(dA(d,f)>>24&255)/255),m.drawImage(g.c,g.a.left,g.a.top,g.a.width,g.a.height,k,l,g.a.width,g.a.height),m.globalAlpha=1):m.drawImage(a,0, +0,g.a.width,g.a.height,k,l,g.a.width,g.a.height),a=h,k=g.b);a&&(c.a?e.b=QK(a,k):e.canvas=a)}}else e.f&&(a=e.f)&&(g=a.text,b=a.a,h=a.b,k=b+10,l=NK(c,a.width+10,k),m=l.getContext("2d"),RK(m,g,k/2,b,h,c.c,d,f),c.a?e.b=QK(l,new pq(0,0,a.width+10,a.a+10)):e.canvas=l)} +function JK(a,b,c,d,e,f){var g=b.label.a;xK(g,e);e=b.c;var h=SK(g.c,g.f);b=b.b;d?1==g.h?(d=h-b,b=h-b-e.width):(d=h+e.width+b,b=h+b):(d=h+b,b=h+b+e.width);h=EK(g.c,d);b=EK(g.c,b);d=JJ(g,h);h=KJ(g,h);g=Math.atan2(KJ(g,b)-h,JJ(g,b)-d);a.save();a.translate(d,h);a.rotate(g);0!=g?(g=!!(a.imageSmoothingEnabled||a.mozImageSmoothingEnabled||a.webkitImageSmoothingEnabled||a.msImageSmoothingEnabled),oF(a,!0),BK(a,c,e,0,0,f),oF(a,g)):BK(a,c,e,0,0,f);a.restore()} +function IK(a,b,c,d,e,f,g,h,k,l){a.c&&!a.f&&(a.f=new wJ);var m=f.c,n=m.a.j;a.a.reset();TK(f,h,k,a.a);1>l&&(b.globalAlpha=l);for(f=0;f<a.a.b;f++)h=UK(a,c,d,e,m,g,a.a.a[6*f+4],a.a.a[6*f+5]),0<h.width&&0<h.height&&(b.save(),b.translate(a.a.a[6*f+0],a.a.a[6*f+1]),b.rotate(a.a.a[6*f+2]),k=a.a.a[6*f+3],a.c?b.drawImage(CJ(a.f,h),h.x,h.y,h.width,h.height,k,-(h.height/n/2),h.width/n,h.height/n):b.drawImage(h.canvas,0,0,h.width,h.height,k,-(h.height/n/2),h.width/n,h.height/n),b.restore());1>l&&(b.globalAlpha= +1)} +function UK(a,b,c,d,e,f,g,h){var k=e.a;b=VK(k,b);e=b.b;var l=k.c.length/4,m=k.g?Math.floor(l/2):0;if(l=h==l&&g==m)var n=b.a;else{var p=g+"-"+h;n=e[p]}if(!KK(a,n)){n=h-1;var q=[],t=c.s?eA(c,d):0;q.push(c.l?dA(c,d):0);q.push(t);c=k.c[4*g];for(d=g;d<h;d++)q.push(k.i[d]),q.push(k.c[4*d]-c);h=q.join("");c=a.h;if(!c.has(h)||!KK(a,c.get(h))){k=k.c;t=b.c;var v=b.f;q=d=k[4*g];for(var u=n;u>=g;u--){var w=k[4*u]+k[4*u+2];w>q&&(q=w)}u=Math.ceil(q-d);q=WK(f);if(a.c){var y=BJ(a.f,u,q);w=CJ(a.f,y)}else{w=uJ(tJ(),u, +q);var A=new EJ(w,u,q,h,a.h)}w=w.getContext("2d");a.c&&(w.save(),w.translate(y.x,y.y),w.clearRect(0,0,u,q));if(0<m)for(w.globalAlpha=v/255,u=g;u<=n;u++){v=u-m;var z=k[4*v+2],C=k[4*v+3];if(0!=z&&0!=C){v=(q-C)/2;var I=u-m;w.drawImage(f.a?f.a[I].b:f.f,XK(f,I),f.a?f.a[I].a.top:f.b?f.b.y:0,z,C,k[4*u]-d-(z-k[4*u+2])/2,v,z,C)}}for(w.globalAlpha=t/255;g<=n;g++)m=k[4*g+2],t=k[4*g+3],0!=m&&0!=t&&(v=(q-t)/2,w.drawImage(f.a?f.a[g].b:f.f,XK(f,g),f.a?f.a[g].a.top:f.b?f.b.y:0,m,t,k[4*g]-d,v,m,t));a.c&&w.restore(); +n=a.c?y:A;c.set(h,n)}n=c.get(h);a.c||n.a++;l?b.a=n:e[p]=n}return n} +function TK(a,b,c,d){var e=a.label.a;xK(e,c);var f=a.c;c=f.a.c;var g=f.a.j,h=f.a.g,k=SK(e.c,e.f);a=a.b;a=EK(e.c,b?1==e.h?k-a:k+f.width+a:k+a);if(!(0>a||a>e.a-1))for(pK.a=e,pK.m=5,b=B(b)&&b,pK.c=b?-1:1,e=0|a,pK.b=b&&e!=a?e:e+pK.c,pK.h=0,pK.j=0,pK.i=JJ(pK.a,a),pK.l=KJ(pK.a,a),pK.f=0,pK.g=0,b=c.length/4,h=h?Math.floor(b/2):0,e=0;h<b&&pK.next();){a=e+pK.g;f=a*g;for(var l=k=h;l<b&&!(c[4*l]+c[4*l+2]/2>f);l++)h++;d.append(pK.h,pK.j,pK.f,c[4*k]/g-e,k,h);e=a}}function KK(a,b){return a.c?!!b&&b.valid:!!b} +function AK(a){return a.b&&a.b.valid?YK?CJ(YK,a.b):null:a.c?a.c.a:a.canvas?a.canvas:null} +function yK(a,b,c,d,e){var f=vK(e);if("magenta"!=f.fill){var g=b.label.a,h=SK(g.c,g.f)+b.b,k=EK(g.c,h);g=EK(g.c,h+b.width);1>d&&(a.globalAlpha=d);a.save();h=0;e.j&&(h=Tz(e.b,8));e=b.height+3;if(0<h){var l=b.label.a,m=e/2,n=0<=c?1:-1;c=n*m;m=-n*(m-h);n=0;for(var p=Math.floor(k);p<=Math.ceil(g);++p){var q=Yn(p,k,g);var t=JJ(l,q);q=KJ(l,q);if(t!=z||q!=C){if(0<n){var v=t-z;var u=q-C;var w=1/Math.sqrt(v*v+u*u);v*=w;u*=w;if(1<n){var y=t-y;var A=q-A;w=1/Math.sqrt(y*y+A*A);y*=w;A*=w;a.lineTo(z+-A*c,C+y*c)}else A= +2*v,y=2*u,a.beginPath(),a.moveTo(z-A+-u*m,C-y+v*m),a.lineTo(z-A+-u*c,C-y+v*c)}y=z;A=C;var z=t;var C=q;++n}}0<n&&(A=2*v,y=2*u,a.lineTo(t+A+-u*c,q+y+v*c),a.lineTo(t+A+-u*m,q+y+v*m));a.strokeStyle=f.outline;a.lineWidth=2*h;a.lineCap="butt";a.stroke()}b=b.label.a;z=JJ(b,k);C=KJ(b,k);v=Math.ceil(k);v==k&&(v+=1);t=z-JJ(b,v);v=C-KJ(b,v);u=Math.sqrt(t*t+v*v);a.beginPath();a.moveTo(z+2*t/u,C+2*v/u);for(k=Math.ceil(k);k<g;++k)z=JJ(b,k),C=KJ(b,k),a.lineTo(z,C);z=JJ(b,g);C=KJ(b,g);k=Math.floor(g);k==g&&--k;t= +z-JJ(b,k);v=C-KJ(b,k);u=Math.sqrt(t*t+v*v);a.lineTo(z+2*t/u,C+2*v/u);a.strokeStyle=f.fill;a.lineWidth=e;a.stroke();a.restore();1>d&&(a.globalAlpha=1)}} +function wK(a,b,c,d,e,f,g,h,k,l,m,n,p){var q=b+f/2,t=c+f/2,v=d-f,u=e-f;1>p&&(a.globalAlpha=p);a.lineWidth=f;a.strokeStyle=h;a.fillStyle=g;0<n&&(a.shadowOffsetX=n,a.shadowOffsetY=n,a.shadowBlur=2,a.shadowColor="rgba(0, 0, 0, 0.2)");"magenta"!=g&&(0<k?(ZK(a,b,c,b+d,c+e,l,m,k,0),a.fill()):a.fillRect(b,c,d,e));0<n&&(a.shadowOffsetX=0,a.shadowOffsetY=0,a.shadowBlur=0);"magenta"!=h&&0<f&&(k?(ZK(a,b,c,b+d,c+e,l,m,k,f/2),a.stroke()):a.strokeRect(q,t,v,u));1>p&&(a.globalAlpha=1)} +function ZK(a,b,c,d,e,f,g,h,k){b+=k;c+=k;d-=k;e-=k;h-=k;a.beginPath();a.moveTo(b,c);g<c&&(a.lineTo(f-h,c),a.lineTo(f,c-h),a.lineTo(f+h,c));a.lineTo(d,c);f>d&&(a.lineTo(d,g-h),a.lineTo(d+h,g),a.lineTo(d,g+h));a.lineTo(d,e);g>e&&(a.lineTo(f+h,e),a.lineTo(f,e+h),a.lineTo(f-h,e));a.lineTo(b,e);f<b&&(a.lineTo(b,g+h),a.lineTo(b-h,g),a.lineTo(b,g-h));a.lineTo(b,c)} +function BK(a,b,c,d,e,f){f*=c.c?c.c.b:1;1>f&&(a.globalAlpha=f);var g=c.f,h=c.g,k=c.b||c.c;c=h?h.la:1;var l=k?k.x:0,m=k?k.y:0;if(k){var n=k.width;g=k.height}else g?(n=g.width+10,g=g.a+10):h&&h.b?(n=h.b.width,g=h.b.height):h&&h.a?(n=h.a.width,g=h.a.height):(n=b.width,g=b.height);a.drawImage(b,l,m,n,g,Math.floor(d+.5),Math.floor(e+.5-g/c/2),n/c,g/c);1>f&&(a.globalAlpha=1)} +function DK(a,b,c,d,e,f,g){1>g&&(a.globalAlpha=g);a.drawImage(b,e.left,e.top,e.width,e.height,Math.floor(c+.5+f.left),Math.floor(d+.5+f.top),f.width,f.height);1>g&&(a.globalAlpha=1)}function vK(a){var b="magenta",c="magenta";a.j&&(b=OH(Uz(a,0)),c=OH(Uz(a,4)));return{fill:b,outline:c}};function $K(a){this.a=a}function aL(a,b,c,d,e,f){d=pF(2,d);b.save();b.scale(d,d);d=[];for(var g=0;g<c.length;++g)for(var h=c[g];h;){for(var k=h.a.j,l=0;l<k.length;++l)d.push({label:k[l],Md:h});h=h.b}d.sort(function(a,b){return a.label.g-b.label.g||a.label.h-b.label.h});for(l=0;l<d.length;++l)c=d[l].label,h=d[l].Md,qK(a.a,b,c,h,h.a.f,e,f);b.restore()};function bL(){this.b=0;this.a=new Float32Array(0)}function cL(a,b,c){a.a.length<b&&(a.a=new Float32Array(b));a.b=b;a=a.a;for(var d=c[0],e=c[1],f=a[0]=0,g=1;g<b;g++){var h=2*g,k=c[h];h=c[h+1];d-=k;e-=h;f+=Math.sqrt(d*d+e*e);a[g]=f;d=k;e=h}}function SK(a,b){var c=Math.min(Math.max(Math.floor(b),0),a.b-2);b-=c;return(1-b)*a.a[c]+b*a.a[c+1]} +function EK(a,b){if(0==b)return 0;for(var c=0,d=a.b-1;1<d-c;){var e=Math.floor((c+d)/2);b>a.a[e]?c=e:d=e}e=a.a[c];d=a.a[d];return e==d?0<Math.sign(b)?a.b:-1:c+(b-e)/(d-e)};function dL(a){this.l=a;this.a=this.l.length/2;var b=this.l,c=b.length/2,d=new Float32Array(c);if(!(2>c))for(var e=1;e<c-1;++e){var f=e-1,g=e,h=e+1;var k=b[2*g+0],l=b[2*g+1];g=k-b[2*f+0];f=l-b[2*f+1];k=b[2*h+0]-k;h=b[2*h+1]-l;l=(g*g+f*f)*(k*k+h*h);if(0==l)g=0;else{l=Math.sqrt(l);var m=k*f-h*g;g=0==m?0:(l-(g*k+f*h))/m}d[e]=g}this.i=d;this.g=new Float32Array(a.length);for(b=0;b<a.length;++b)this.g[b]=a[b];this.b=new bL;cL(this.b,this.a,this.l);a=this.b;b=new bL;b.b=a.b;b.a=new Float32Array(a.a.length); +for(c=0;c<a.b;++c)b.a[c]=a.a[c];this.c=b;this.m=this.altitude=0;this.j=null;this.o=!1;this.f=0;this.h=1}function eL(a,b){b=Math.ceil(b);for(var c=0,d=Math.floor(0)+1;d<b;++d)c+=a.i[d];return 2*c}function xK(a,b){if(a.m!=b){a.j||(a.j={},a.j[0]=a.g);if(a.j[b])a.j[a.m]=a.g,a.g=a.j[b];else{var c=new Float32Array(a.j[0].subarray(0));fL(c,a.a,b);a.j[b]=c;a.g=c}cL(a.c,a.a,a.g);a.m=b}} +function fL(a,b,c){for(var d=a[0],e=a[1],f=0;f<b;++f){var g=Math.min(b-1,f+1),h=a[2*f],k=a[2*f+1],l=a,m=f,n=h,p=k,q=a[2*g];g=a[2*g+1];var t=c;q-=n;g-=p;n-=d;p-=e;d=Math.sqrt(q*q+g*g);e=Math.sqrt(n*n+p*p);0==d?(l[2*m]+=-p/e*t,l[2*m+1]+=n/e*t):0==e?(l[2*m]+=-g/d*t,l[2*m+1]+=q/d*t):(n=(n/e+q/d)/2,p=(p/e+g/d)/2,e=n*n+p*p,.25>e&&(e=.25),l[2*m]-=p/e*t,l[2*m+1]+=n/e*t);d=h;e=k}}function JJ(a,b){var c=Math.min(Math.max(Math.floor(b),0),a.a-2);b-=c;return(1-b)*a.g[2*c]+b*a.g[2*(c+1)]} +function KJ(a,b){var c=Math.min(Math.max(Math.floor(b),0),a.a-2);b-=c;return(1-b)*a.g[2*c+1]+b*a.g[2*(c+1)+1]}function gL(a,b){var c=Math.min(Math.max(Math.floor(b),0),a.a-2);b-=c;return(1-b)*a.l[2*c]+b*a.l[2*(c+1)]}function hL(a,b){var c=Math.min(Math.max(Math.floor(b),0),a.a-2);b-=c;return(1-b)*a.l[2*c+1]+b*a.l[2*(c+1)+1]};function iL(a){this.b=pF(2,a);this.f=go("canvas");this.f.width=this.f.height=256*this.b;this.a=this.f.getContext("2d");this.a.scale(this.b,this.b);this.a.lineJoin="round";this.ff=new Float32Array(128)} +iL.prototype.c=function(a,b,c,d,e,f){var g=c.ka();if(g=SH(b,g)){var h=g.c;if(!(f>=h)){var k=tA(g,f,e)>>24&255;if(0!=k){b=null;var l=Zz(g,f,e);l&&(b=l.map(function(a){return a*d}));l=Yz(g,f,e)*d;var m;if(b)var n=m=0;else n=QI(c.b,c.c[c.a],f),m=RI(c.b,c.c[c.a],f);a.lineCap=0!=n||0!=m?"round":"butt";a.lineJoin="round";n=uA(g,f,e)*d;m=OH(tA(g,f,e));0==f&&1<h&&255>(tA(g,1,e)>>24&255)?jL(this,a,c,l,g,d,e):(255>k&&(e=a.globalCompositeOperation,a.globalCompositeOperation="destination-out",kL(this,a,c,l,n, +"rgba(0,0,0,1.00)",b),a.globalCompositeOperation=e),kL(this,a,c,l,n,m,b))}}}}; +function jL(a,b,c,d,e,f,g){a.a.clearRect(0,0,256,256);var h=QI(c.b,c.c[c.a],0);var k=RI(c.b,c.c[c.a],0);var l=QI(c.b,c.c[c.a],1);var m=RI(c.b,c.c[c.a],1);a.a.globalCompositeOperation="source-over";a.a.lineCap=0!=h||0!=k?"round":"butt";kL(a,a.a,c,d,uA(e,0,g)*f,OH(tA(e,0,g)),Zz(e,0,g));a.a.globalCompositeOperation="destination-out";a.a.lineCap=0!=l||0!=m?"round":"butt";kL(a,a.a,c,d,uA(e,1,g)*f,"black",null);b.drawImage(a.f,0,0,Math.floor(256*a.b),Math.floor(256*a.b),0,0,256,256)} +function kL(a,b,c,d,e,f,g){if(0!=e){var h=b;g&&(h=b.setLineDash?b:new NH(b),h.setLineDash(g));b.lineWidth=e;b.strokeStyle=f;b.beginPath();e=c.b;f=c.c[c.a];0>f||f>=e.b?e=0:(e=e.a[f],e=Tw(e)?Uw(e)+1:1);for(f=0;f<e;f++){var k=c.b;var l=c.c[c.a],m=f;if(0>l||l>=k.b)k=0;else{NI(k,l);l=k.a[l];var n=OI(l,m);k=PI(k,l,m)-n}m=a;n=c.b;var p=c.c[c.a],q=f;l=a.ff;if(0>p||p>=n.b)l=l||new Float32Array(0);else{NI(n,p);var t=n.a[p];p=OI(t,q);q=PI(n,t,q);n=n.f.subarray(2*p,2*q);l?(l.length<n.length&&(l=new Float32Array(n.length)), +l.set(n)):l=n}m=m.ff=l;0!=d&&fL(m,k,-d);h.moveTo(m[0],m[1]);for(l=2;l<2*k-1;l+=2)h.lineTo(m[l],m[l+1])}b.stroke();g&&h.setLineDash([])}};function lL(a){this.f=a;this.a=this.g=this.b=null;this.c=0}function XK(a,b){return a.a?a.a[b].a.left:(a.b?a.b.x:0)+a.g[b]}function WK(a){if(!a.c)if(a.b)a.c=a.b.height;else if(a.a)for(var b=0;b<a.a.length;b++)a.a[b].a.height>a.c&&(a.c=a.a[b].a.height);else a.c=a.f.height;return a.c};function mL(a,b,c,d,e,f,g,h,k){this.key=a;this.height=b;this.i=c;this.b=null;this.h=d;this.a=e;this.l=f;this.c=g;this.j=h;this.g=k;this.f={}}function nL(){this.a=null;this.b={};this.f=this.c=255}function HK(a,b,c){b=new lL(b);a.b?b.a=a.b:(b.b=c,b.g=a.l);return b}function VK(a,b){a.f[b]||(a.f[b]=new nL);return a.f[b]};function oL(a,b){LJ.call(this,a,b);this.a=this.g=this.f=this.c=this.b=this.canvas=null;this.j=this.h=0;this.l=DJ}F(oL,LJ);oL.prototype.i=function(){this.c=this.b=this.canvas=null;this.a&&(this.a.b=null)};oL.prototype.X=function(){if(!this.l){var a=tJ();this.canvas&&vJ(a,this.canvas);if(this.a)for(var b in this.a.f){a=this.a.f[b];if(a.a){var c=a.a;FJ(c)}for(var d in a.b)c=a.b[d],FJ(c)}}oL.R.X.call(this)}; +function OK(a,b,c){this.x=a.left;this.y=a.top;this.width=a.width;this.height=a.height;this.a=b;this.b=c};function pL(a){this.key=a;this.a=this.b=null;this.f=!1;this.c=this.next=null};function qL(a,b,c){var d="";b&2&&(d+="italic ");var e="";b&16&&(e="300 ");b&8&&(e="500 ");b&1&&(e="700 ");return d=d+e+(a+"px ")+c};function RK(a,b,c,d,e,f,g,h){d=qL(d,e,f);a.font!=d&&(a.font=d);a.textBaseline="middle";d=e="magenta";g.l&&(e=OH(dA(g,h)));g.s&&(d=OH(eA(g,h)));g=e;h=d;"magenta"!=h&&(a.strokeStyle=h,a.lineWidth=2,a.strokeText(b,0,c));"magenta"!=g&&(a.fillStyle=g,a.lineWidth=2,a.fillText(b,0,c))};function rL(a){this.c=a;this.a=DJ;this.b={}}var sL=null,tL=null,uL=null,YK=null;function QK(a,b){YK||(YK=new wJ);var c=YK;b=BJ(c,b.width,b.height);c=CJ(c,b).getContext("2d");c.clearRect(b.x,b.y,b.width,b.height);c.drawImage(a,0,0,b.width,b.height,b.x,b.y,b.width,b.height);return b}function MK(a,b,c){var d=a.b[b];if(void 0==d)a.b[b]=c;else if(d!=c)return!1;return!0} +function LK(a,b,c,d,e,f){if(b=b.a){var g=[],h=[];var k=[];var l=b.i.length,m={};if(d.l){var n=dA(d,e);if(0==(n&4278190080))k=null;else{var p=d.s?eA(d,e):0;if(MK(a,b.key,c)){var q=VK(b,c);q.c=n>>24&255;q.f=p>>24&255}for(q=0;q<l;q++){var t=b.g&&q<Math.floor(l/2),v=(t?p:n)+b.i[q];if(f.has(v))var u=f.get(v);else m[v]?u=m[v]:(u=new pL(v),m[v]=u,t?h.push(q):g.push(q));k.push(u)}}}else k=null;b.b=k;if(0!=g.length||0!=h.length)if(MK(a,b.key,c)){for(a=0;a<g.length;a++)d=g[a],e=b.b[d],e.b=b.h[d],e.a=new pq(b.a[4* +d],b.a[4*d+1],b.a[4*d+2],b.a[4*d+3]),f.add(e);for(a=0;a<h.length;a++)d=h[a],e=b.b[d],e.b=b.h[d],e.a=new pq(b.a[4*d],b.a[4*d+1],b.a[4*d+2],b.a[4*d+3]),f.add(e)}else{c=b.b;for(p=n=k=0;p<h.length;p++)l=h[p],m=c[l],m.a=new pq(k,0,b.c[4*l+2],b.c[4*l+3]),k+=Math.ceil(b.c[4*l+2]);for(p=0;p<g.length;p++)l=g[p],m=c[l],m.a=new pq(n+k,0,b.c[4*l+2],b.c[4*l+3]),n+=Math.ceil(b.c[4*l+2]);l=k+n;m=b.height;n=vL(b,l,m,g,h);if(a=PK(a,n,e,d,0,0,l,m,b.g?k:void 0)){for(d=0;d<h.length;d++)l=h[d],m=c[l],m.b=a,f.add(m);for(h= +0;h<g.length;h++)l=g[h],m=c[l],m.b=a,f.add(m);f=!0}else f=!1;f||(b.b=null)}}}function NK(a,b,c){if(a.a){tL||(tL=go("canvas"));uL||(uL=go("canvas"));a=tL;tL=uL;uL=a;var d=a.getContext("2d");d.globalCompositeOperation="source-over";a.width<b||a.height<c?(a.width<b&&(a.width=b),a.height<c&&(a.height=c)):d.clearRect(0,0,b,c)}else a=uJ(tJ(),b,c);return a} +function vL(a,b,c,d,e){var f=a.b;sL||(sL=go("canvas"),sL.height=60);var g=sL;g.width<b&&(g.width=b);g.height<c&&(g.height=c);65536<g.width*g.height&&65536>=b*c&&(g.width=b,g.height=c);g=g.getContext("2d");g.clearRect(0,0,b,c);b=[e,d];for(c=0;c<b.length;c++)for(d=b[c],e=0;e<d.length;e++){var h=d[e],k=f[h];g.drawImage(a.h[h],a.a[4*h],a.a[4*h+1],a.a[4*h+2],a.a[4*h+3],k.a.left,k.a.top,k.a.width,k.a.height)}return sL} +function PK(a,b,c,d,e,f,g,h,k){if(!d.l)return null;var l=OH(dA(d,c));a=NK(a,g,h);var m=a.getContext("2d");k?(m.fillStyle=OH(eA(d,c)),m.fillRect(0,0,k,h),m.fillStyle=l,m.fillRect(k,0,g-k,h)):(m.fillStyle=l,m.fillRect(0,0,g,h));m.globalCompositeOperation="destination-in";m.drawImage(b,e,f,g,h,0,0,g,h);return a};function wL(a,b,c,d,e){this.key=a;this.c=b;this.a=c;this.b=d;this.la=e};function xL(a,b,c,d){this.text=a;this.width=b;this.a=c;this.b=d};function yL(a,b,c,d){this.j=new rL(d);this.h=b;this.a=a;this.i=d;this.b=[];this.g=!1;this.c=2*c;this.f=c}var zL=null; +yL.prototype.Rc=function(){if(!this.g){var a=this.a.a;if(Jy(a)&&py(Ky(a))){a=Ky(a).a;for(var b=0;b<a.length;b++){var c=a[b];if(null!=c.c||null!=c.b&&gu(Eu(c))){var d=b;c=Cu(c).a;for(var e=0;e<c.length;++e){var f=c[e],g=AL(this.a,d,0,e);if(tu(f)){var h=f;f=g;g=""+f;var k=uu(h);ou(h);var l=h.a?h.a.length:0;var m=k+l,n=[],p=[],q=Array(4*m),t=Array(m);t[0]=0;m=Array(4*m);BL(this.a);for(var v=0,u=0;u<l;++u){var w=u;if(null!=h.l||null!=h.s){var y=h;var A=u;qu(y);y=y.l[A]/8}else y=0;A=h;var z=u;ou(A);w= +CL(this,A.a[z],w,y,n,p,q,t,m);v=v>w.height?v:w.height}for(u=z=A=0;u<k;++u)w=u+l,y=wu(h)?xu(h,u)/8:0,w=CL(this,vu(h,u),w,y,n,p,q,t,m),z=z>w.Se?z:w.Se,A=A>w.height?A:w.height,v=v>w.height?v:w.height;l=new oL(z/this.c,A/this.c);l.a=new mL(g,Math.ceil(v),n,p,q,t,m,this.c,null!=h.a||null!=h.j?!0:!1);this.b[f]=l}else null!=f.b&&(h=g,f=su(f),n=CK(this.h,h),p=this.a.getZoom(),g=hA(n,p),n=gA(n,p),p=DL(this,f,g,n),q=new oL(p,g),q.f=new xL(f,p,g,n),this.b[h]=q)}}else if(null!=c.b)for(d=c,c=b,e=this.a.getZoom(), +h=null!=d.a?2:1,f=0;f<h;++f)for(g=0==f?Cu(d).a:Du(d).a,n=0;n<g.length;++n)if(q=g[n],p=AL(this.a,c,f,n),t=CK(this.h,p),!fA(t,e))if(tu(q)){l=q;k=this.a.a;q=vu(l,0);q=ay(Dy(k),q);q=new pq(Vx(q),Wx(q),Xx(q),Yx(q));t=null;if(null!=l.a||null!=l.j)ou(l),t=l.a[0],t=ay(Dy(k),t),t=new pq(Vx(t),Wx(t),Xx(t),Yx(t));k=q.width/this.f;m=q.height/this.f;l=BL(this.a);l.Qb()&&l.Ib(3);k=new oL(k,m);k.g=new wL("restyle_index"+p,l.Ab(),q,t,this.f);this.b[p]=k}else null!=q.b&&(l=t,q=su(q),k=this.a.getZoom(),t=hA(l,k),l= +gA(l,k),k=DL(this,q,t,l),m=new oL(k,t),m.f=new xL(q,k,t,l),this.b[p]=m)}this.g=!0}}};function CL(a,b,c,d,e,f,g,h,k){var l=EL(a.a,b),m=BL(a.a);d=1E4<d||0>d?0:d;var n=ay(Dy(a.a.a),b);b=Xx(n);var p=Yx(n),q=d*a.c+b;e.push(l);f.push(m.Ab());g[4*c]=Vx(n);g[4*c+1]=Wx(n);g[4*c+2]=Xx(n);g[4*c+3]=Yx(n);e=c+1;e<h.length&&(h[e]=h[c]+b);k[4*c]=d*a.c;k[4*c+1]=0;k[4*c+2]=b;k[4*c+3]=p;return{height:p,Se:q}} +function DL(a,b,c,d){a=qL(c,d,a.i);zL||(c=go("canvas"),c.width=c.height=128,zL=c.getContext("2d"));c=zL;c.font!=a&&(c.font=a);return Math.ceil(c.measureText(b).width)}yL.prototype.Tb=function(a){return this.b[a]||null};function FL(a,b,c){this.b=a;this.c=b;this.a=c;this.a.sort(nK)};function GL(){this.a=[];this.b=0};function HL(a){mK.call(this,a);this.b=this.h=this.i=this.v=0}F(HL,mK);function IL(a,b,c,d){var e=a.label.a,f=JJ(e,b),g=KJ(e,b),h=JJ(e,c),k=KJ(e,c),l=a.f;if(l){b=e.i[Math.floor(b)];c=e.i[Math.ceil(c)];var m=h-f,n=k-g,p=Math.sqrt(m*m+n*n);e=-n/p;var q=m/p;m/=p;n/=p;f=f+e*l-m*l*b;g=g+q*l-n*l*b;h=h+e*l+m*l*c;k=k+q*l+n*l*c}return cK(d,f,g,h,k,a.m()+2*a.v,a)}HL.prototype.A=function(){var a=this.label.a,b=SK(a.c,a.f),c=this.b,d=b+c+this.u();this.i=EK(a.c,b+c);this.h=EK(a.c,d)}; +HL.prototype.s=function(a){for(var b=[],c=this.h,d=this.i;d<c;d=Math.floor(d+1))b.push(IL(this,d,Math.min(Math.floor(d+1),c),a));return b}; +HL.prototype.l=function(a){var b=this.i,c=this.h,d,e,f=this.label.a;var g=d=JJ(f,b);var h=e=KJ(f,b);for(var k=Math.floor(b+1);k<c;++k){b=JJ(f,k);var l=KJ(f,k);g=Math.min(b,g);d=Math.max(b,d);h=Math.min(l,h);e=Math.max(l,e)}b=JJ(f,c);l=KJ(f,c);g=Math.min(b,g);d=Math.max(b,d);h=Math.min(l,h);e=Math.max(l,e);c=this.m()/2+Math.abs(this.f);a.left=g-c;a.right=d+c;a.top=h-c;a.bottom=e+c};function JL(){HL.call(this,2);this.g=!1}F(JL,HL);JL.prototype.m=function(){return this.c.height};JL.prototype.u=function(){return this.c.width}; +function KL(){HL.call(this,0);this.height=this.width=0}F(KL,HL);KL.prototype.m=function(){return this.height};KL.prototype.u=function(){return this.width};function LL(a,b){HL.call(this,5);this.g=a;this.j=b}F(LL,HL);LL.prototype.m=function(){return this.j.height};LL.prototype.u=function(){return this.j.width};function FK(a){var b=a.label.a,c=SK(b.c,b.f),d=a.b+a.j.width/2;return 1==b.h&&lK(a.label)?c-d:c+d}function ML(a){mK.call(this,a);this.height=this.width=this.b=this.oa=0}F(ML,mK); +ML.prototype.s=function(a){var b=this.label.b;return[cK(a,b.screenX+this.oa,b.screenY+this.b,b.screenX+this.oa+this.width,b.screenY+this.b,this.height,this,this.label.l||this.label)]};ML.prototype.l=function(a){var b=this.label.b;a.left=b.screenX+this.oa;a.right=b.screenX+this.oa+this.width;a.top=b.screenY+this.b-this.height/2;a.bottom=b.screenY+this.b+this.height/2}; +function NL(a,b,c){ML.call(this,4);this.oa=b.left;this.b=b.top+b.height/2;this.width=b.width;this.height=b.height;this.g=a;this.h=b;this.text=c||""}F(NL,ML);function OL(){ML.call(this,3)}F(OL,ML);function PL(){ML.call(this,1);this.j=null;this.i=this.h=this.g=this.m=0}F(PL,ML);var QL={RIGHT:0,TOP:1,BOTTOM:2,LEFT:3}; +PL.prototype.s=function(a){var b=this.label.b,c=b.screenX+this.oa,d=b.screenX+this.oa+this.width,e=b.screenY+this.b-this.height/2;b=b.screenY+this.b+this.height/2;0<this.g&&(3==this.h?c-=this.g:0==this.h?d+=this.g:1==this.h?e-=this.g:2==this.h&&(b+=this.g));d+=this.i;b+=this.i;var f=(e+b)/2;return[cK(a,c,f,d,f,b-e,this,this.label.l||this.label)]}; +PL.prototype.l=function(a){var b=this.label.b;a.left=b.screenX+this.oa;a.right=b.screenX+this.oa+this.width+this.i;a.top=b.screenY+this.b-this.height/2;a.bottom=b.screenY+this.b+this.height/2+this.i;0<this.g&&(3==this.h?a.left-=this.g:0==this.h?a.right+=this.g:1==this.h?a.top-=this.g:2==this.h&&(a.bottom+=this.g))};function RL(a,b,c){this.a=b;this.c=this.b=0;this.h=[];this.f=[];this.g=!1;var d=0,e=0,f=0,g=0;a:{if(a=a.f)for(var h=0;h<a.length;h++)if(30511227==a[h].c){a=!0;break a}a=!1}a=a?0:2;for(h=0;h<b.length;++h){var k=new SL;k.a=g;k.b=e;this.f.push(k);d=Math.max(d,b[h].height);e+=b[h].width;c[h]||h==b.length-1?(k=new TL,k.b=d,k.lineWidth=e,k.a=f,this.h.push(k),this.c+=d,this.b=Math.max(this.b,e),f=this.c,e=d=0,g+=1):e+=a}}function TL(){this.a=this.b=this.lineWidth=0}function SL(){this.b=this.a=0};function UL(a,b,c,d,e){this.b=a;this.a=Array(2*a.a.length);a=this.b;var f=d[0],g=d[1],h=d[2];d=d[3];var k=e.x;e=e.y;for(var l=0;l<a.a.length;++l){var m=a.a[l],n=a.f[l],p=a.h[n.a],q=p.b-m.height;this.a[2*l+1]=p.a+.5*q+m.height/2}switch(c){case 2:m=0;break;case 3:m=1;break;default:m=.5}for(l=0;l<a.f.length;++l)n=a.f[l],p=a.h[n.a],q=a.b-p.lineWidth,this.a[2*l]=n.b+q*m;switch(b){case 7:case 11:case 15:k=g+k;break;case 6:case 10:case 14:k=d-a.b-k;break;default:k=a.b/-2}if(9==b||13==b)l=(g-d)/2,2==c?(k= +d-l,e=0):3==c&&(k=g+l-a.b,e=0);switch(b){case 9:case 10:case 11:b=f-a.c-e;break;case 13:case 15:case 14:b=h+e;break;default:b=a.c/-2+(f+h)/2}for(l=0;l<this.a.length;l+=2)this.a[l]+=k,this.a[l+1]+=b}function VL(a,b){for(var c=a.b,d=0,e=0,f=0;f<c.a.length;++f){var g=a.a[2*f+1]-c.a[f].height/2,h=a.a[2*f];if(0==f||g<d)d=g;if(0==f||h<e)e=h}a=d+c.c;c=e+c.b;b[0]=d;b[1]=c;b[2]=a;b[3]=e};function WL(a){this.data=a||[]}F(WL,W);WL.prototype.Gb=function(a){this.data[4]=a};function XL(){this.a=Array(4);this.b=new WH(0,0)}var nA=new fo(0,0),YL=new WH(1,0);function ZL(a,b){b=b.c;var c=Fu(a);null!==c.g?a=Zc(c.g):c.j&&null!=c.a&&null!=c.i?(a=Zc(c.j,c.a,c.i-c.a),a.ca(),a.ca()):a=Zc();c=null!=c.f?null==c.f?0:c.f:BI(a);var d=new Float32Array(2*c);DI(a,c,b,d);Vc(a);return d}function $L(a){var b;if(b=null!=a.c?!0:!1)b=null!=Fu(a).c?!0:!1;b?(a=Fu(a),a=(null==a.c?0:a.c)/8):a=0;return a} +function aM(a){var b;if(b=null!=a.c?!0:!1)b=null!=Fu(a).b?!0:!1;b?(a=Fu(a),a=(null==a.b?0:a.b)/8):a=0;return a}function bM(a){for(var b=0;b<Fe(a,1);b++){var c=b;if(31==Ce(a,1)[c])return!0}return!1} +function cM(a,b,c,d,e,f){var g=e.data,h=e.a.f,k=g.getZoom(),l=dM(e,b,c);if(IF()){var m=eM(g,l.J);m&&(m=new WL((new fM(m.data[8])).data[0]),bM(m))&&(l.B=!0)}l.b=new TJ(d.x,d.y);m=CK(h,g.b.a[4][c].ka());if(m.a&&m.a[k]&&null!=m.a[k].i)if(m.a&&m.a[k]&&null!=m.a[k].i){var n=m.a[k];n=null==n.i?1:n.i}else n=1;else n=Eu(b),n=null==n.c?1:n.c;var p=n;n=g.b.a[4][c].j;var q=CK(h,n),t=q.j,v=!1,u=-1,w=null;null!=b.a&&(u=g.b.a[4][c].l,w=CK(h,u),v=w.j);g=gM(b,c,e,l,t||v);var y=g[0];g=g[1];var A=hM(e,b);t&&(A||(A= +new WH(0,0)),iM(p,k,q,A));h=a.a;A?(h[0]=A.y,h[1]=A.x,h[2]=A.y,h[3]=A.x):(h[0]=0,h[1]=0,h[2]=0,h[3]=0);p=jM(p);h=new UL(y,p,mu(Cu(b)),h,kM(a,m,k));if(g){var z=a.a;VL(h,z);m=lM(a,m,k);z=new UL(g,mM(b,f),mu(Du(b)),z,m)}t&&nM(a,y,h,q,k,n);v&&nM(a,g,z,w,k,u);f=y.a;for(a=0;a<f.length;++a)eK(l,f[a]);y.g&&(l.u=!0);a=!1;g&&(a=!0,k=null==b.g?0:b.g,f=k&1?k&2?2:1:0,k=k&16?0:k&2?2:1,(m=0!=f)||1!=k||(a=!1),f==k&&m&&(a=!1));if(a){b=dM(e,b,c,!0);b.b=new TJ(d.x,d.y);b.l=l;l.G=b;d=g.a;for(a=0;a<d.length;++a)eK(b,d[a]); +g.g&&(b.u=!0);oM(l,h);oM(b,z);b.i=l.i;l.B&&(b.B=!0);pM(e,l);pM(e,b)}else{if(g){d=g.a;for(a=0;a<d.length;++a)eK(l,d[a]);g.g&&(l.u=!0)}oM(l,h,z);pM(e,l)}}function hM(a,b){b=fu(Eu(b));if(null!=b.b||null!=b.a){a=a.data.c;null!==b.b?b=Zc(b.b):b.f&&null!=b.a&&null!=b.h?(b=Zc(b.f,b.a,b.h-b.a),b.ca(),b.ca()):b=Zc();var c=b.da()/a;a=b.da()/a;Vc(b);return new WH(c,a)}return null} +function iM(a,b,c,d){var e=jA(c,b);if(e&&0==d.x&&0==d.y)switch(a){case 2:d.x=-e;d.y=0;break;case 3:d.x=e;d.y=0;break;case 4:d.x=0;d.y=-e;break;case 5:d.x=2*e;d.y=-e;break;case 6:d.x=2*-e;d.y=-e;break;case 7:d.x=0;d.y=e;break;case 8:d.x=2*e;d.y=e;break;case 9:d.x=2*-e,d.y=e}if((b=mA(c,b))&&(b.width||b.height)){switch(a){case 5:case 2:case 8:d.x-=b.width;break;case 6:case 3:case 9:d.x+=b.width}switch(a){case 5:case 4:case 6:d.y-=b.height;break;case 8:case 7:case 9:d.y+=b.height}}} +function dM(a,b,c,d){var e=a.data,f=null==b.g?0:b.g;f=d?f&16?0:f&2?2:1:f&1?f&2?2:1:0;d=new dK;d.g=null==b.m?0:b.m;d.J=e.b.a[4][c].ka();d.H=null==b.g?0:b.g;d.wb=f;d.C=!a.a.s;d.uc=a.a.Pa;a=e.getZoom();null!=b.h&&(d.m=a+(null==b.h?0:b.h)/8);null!=b.o&&(d.K=a+(null==b.o?0:b.o)/8);return d}function pM(a,b){b.h=a.a.j.length;var c=a.data,d=22-c.getZoom(),e=32767-b.g;b.v=(b.l?1:0)|(tK(c)&1)<<1|(uK(c)&1)<<2|(d&31)<<3|(e&32767)<<8|(0!=b.wb?0:8388608);a.a.j.push(b)} +function gM(a,b,c,d,e){var f=c.data,g=nI(wy(f.a)),h=c.a.f,k=f.getZoom();c=c.a.Y;for(var l=null!=a.a?2:1,m=Array(l),n=!1,p=!1,q=!1,t=0;t<l;++t){for(var v=0==t?Cu(a):Du(a),u=[],w=[],y=0;y<(v.a?v.a.length:0);++y){var A=v.a[y],z;(z=y+1==(v.a?v.a.length:0))||(z=v.a[y+1],z=null==z.o?!1:z.o);var C=AL(f,b,t,y),I=CK(h,C),S=fA(I,k);if(S)p=su(A),A=S.b||g,I=$s(S,A,p),S=at(S,A,p),p=new NL(I,S,p),p.a=C,C=p,p=!0,u.push(C),w.push(z);else if(tu(A)||null!=A.b)if(S=c.Tb(C),0!=S.width&&0!=S.height){A=S;var ca=new OL; +ca.a=C;ca.height=A.height;ca.width=A.width;ca.c=A;A=ca;I.j?(q=!0,ca=mA(I,k),C=qM(S.width,S.height,jA(I,k),lA(I,k),ca,Tz(I.b,8),C),u.push(C),w.push(z),C.j=A,255!=(Uz(I,0)>>24&255)&&(n=!0)):(u.push(A),w.push(z))}}m[t]=new RL(a,u,w)}d.i=p&&!q&&!e;n&&(d.u=!0);return m}function jM(a){switch(a){case 2:return 6;case 3:return 7;case 4:return 9;case 5:return 10;case 6:return 11;case 7:return 13;case 8:return 14;case 9:return 15}return 5}function kM(a,b,c){if(!kA(b,c))return YL;a=a.b;a.x=0;a.y=0;return a} +function lM(a,b,c){if(!kA(b,c))return YL;kA(b,c)?(b=b.a[c],b=(null==b.l?0:b.l)/8):b=0;a=a.b;a.x=b;a.y=b;return a}function mM(a,b){switch(null==a.v?9:a.v){case 6:return 6;case 9:return 7;case 2:return 9;case 1:return 10;case 3:return 11;case 13:return b?9:13;case 12:return b?10:14;case 14:return b?11:15}return 5}function qM(a,b,c,d,e,f,g){var h=new PL;h.m=f;h.g=c;h.i=d;h.width=a+2*e.width+2*f;h.height=b+2*e.height+2*f;h.a=g;return h} +function oM(a,b,c){for(var d=a.c,e=null,f=0;f<d.length;f++){var g=b,h=0;f>=b.a.length/2&&(g=c,h=-(b.a.length/2));var k=d[f];k.oa=g.a[2*(f+h)];k.b=g.a[2*(f+h)+1];4==k.type?(g=k,g.h.top=k.b-g.h.height/2,g.h.left=k.oa):1==k.type&&(g=k,h=QL,g.g&&(g.h=0<k.oa?h.LEFT:0>k.oa+k.width?h.RIGHT:0<k.b-k.height/2?h.TOP:h.BOTTOM),g.j&&(h=g.j,h.oa=k.oa+(k.width-h.width)/2,h.b=k.b,g.j=null,e||(e=[]),e.push(h)))}if(e)for(f=0;f<e.length;f++)eK(a,e[f])} +function rM(a,b,c){var d=c.data,e=nI(wy(d.a)),f=d.getZoom(),g=c.a.f;c=c.a.V;for(var h=0,k=0;k<a.length;++k){var l=AL(d,b,0,k),m=fA(CK(g,l),f);if(m)l=at(m,m.b||e),0==k&&(h+=2),h+=l.width;else{l=c.Tb(l);if(!l)return-1;h+=l.width}}return h+=2*(a.length-1)}function sM(a,b,c,d,e,f){e=new LL(e,f);e.i=0;e.h=b;e.b=d;e.a=a;e.f=c;return e}function tM(a,b,c,d,e,f){var g=new JL;g.i=0;g.h=b;g.c=e;g.g=f;c&&!f&&(g.v=-2);g.a=a;g.f=c;g.b=d;return g} +function uM(a,b,c,d,e,f){var g=new KL;g.i=0;g.h=b;g.width=e;g.height=f;g.a=a;g.b=c;g.f=d;return g}function nM(a,b,c,d,e,f){a=a.a;VL(c,a);var g=a[1]-a[3],h=a[2]-a[0],k=mA(d,e),l=Tz(d.b,8),m=a[0]+(a[2]-a[0])/2;c.a.push(a[3]-k.width-l);c.a.push(m);c=qM(g,h,jA(d,e),lA(d,e),k,l,f);b.a.push(c);255!=(Uz(d,0)>>24&255)&&(b.g=!0)};function vM(a){this.Nb=a;this.u=new XL} +vM.prototype.b=function(a){if(a.data.g&&(this.j(a),!a.a.Qa)){var b=a.data.a;if(Jy(b)&&py(Ky(b))){var c=Ky(b).a,d=a.data.c;for(b=0;b<c.length;b++){var e=c[b];if(null!=e.b){var f=Eu(e);if(!gu(f)){f=au(fu(f));var g=f.da()/d,h=f.da()/d;Vc(f);0>g||256<g||0>h||256<h||cM(this.u,e,b,new eo(g,h),a,this.Nb)}}}c=a.a.j;d=a.N.getZoom();c.sort(fK);e=0;f=c.length/2;for(b=g=0;b<c.length-1;b++){h=c[b];var k=d-e;0<k&&0==h.m&&(h.m=k);g++;g>=f&&(e++,f/=2,g=0)}}wM(a);d=a.a.j;b=new GL;c=!0;for(e=0;e<d.length;++e){f=d[e]; +g=f.c;for(h=0;h<g.length;h++){k=b;var l=g[h],m=l.type;k.a[m]=k.a[m]||[];k.a[m].push(l);l.o=k.b++}2!=f.wb&&(c=!1)}a.a.j.sort(fK);d=[];for(e=0;e<b.a.length;++e)if(b.a[e]){f=e;g=[];h=[];for(k=0;k<b.a[e].length;++k)l=b.a[e][k],l.label.u?h.push(l):g.push(l);g.length&&(g.sort(nK),d.push(new FL(0,f,g)));h.length&&(h.sort(nK),d.push(new FL(1,f,h)))}a.a.v=d;a.a.Ga=!c;this.g(a)}a.a.Qa=!0};vM.prototype.g=sa; +function wM(a){var b=a.data.a;if(Jy(b)&&py(Ky(b))){b=Ky(b).a;for(var c=0;c<b.length;c++){var d=b[c];if(null!=d.c)a:{var e=d,f=c;d=a;var g=d.data,h=wy(g.a),k=d.a.f,l=ZL(e,g),m=new dL(l),n=m.a,p=SK(m.b,n-1),q=Cu(e).a;l=rM(q,f,d);if(-1!=l){var t=Fu(e);var v=null==t.h?1:t.h;var u=aM(e);t=$L(e);h=nI(h);var w=g.getZoom(),y=d.a.V;e=dM(d,e,f);e.a=m;e.a.h=v;e.m<w&&(e.m=w);var A=n-1,z=0;switch(v){case 2:z=u;e.a.f=0;break;case 1:z=-l/2;e.a.f=EK(m.b,p/2);break;case 3:e.a.f=n-1,z=-l-u}for(p=m=n=0;p<q.length;++p){v= +AL(g,f,0,p);var C=fA(CK(k,v),w);if(C){var I=C.b||h;u=$s(C,I);C=at(C,I);I=C.height;m=I>m?I:m;0==p&&(n+=2);v=sM(v,A,t,z+n,u,C);eK(e,v);n+=C.width}else{u=y.Tb(v);if(0==u.width||0==u.height)break a;I=u.height;m=I>m?I:m;v=tM(v,A,t,z+n,u,!1);eK(e,v);n+=u.width}n+=2}f=g.b.a[4][f].j;CK(k,f).j&&(k=uM(f,A,z,t,l,m),eK(e,k),e.C=!1);pM(d,e)}}else if(null!=d.b&&gu(Eu(d)))a:{h=d;d=c;k=a;f=k.a.V;g=k.data;l=g.getZoom();q=k.a.f;t=nI(wy(g.a));y=w=0;e=Cu(h).a;for(A=0;A<e.length;++A){z=AL(g,d,0,A);m=CK(q,z);if(m=fA(m, +l))n=m.b||t,n=at(m,n),m=n.height,z=n.width;else{n=f.Tb(z);if(!n)break a;m=n.height;z=n.width}w+=m;z>y&&(y=z)}z=g.c;m=Eu(h);n=au(fu(m));A=n.da()/z;z=n.da()/z;Vc(n);if(!(0>A||256<A||0>z||256<z)){m=null==m.b?0:m.b;n=(y+1)/Math.pow(2,(null==h.h?0:h.h)/8);y=n*Math.cos(m*Math.PI/1800)/2;m=n*Math.sin(m*Math.PI/1800)/2;n=new Float32Array(4);n[0]=A-y;n[1]=z-m;n[2]=A+y;n[3]=z+m;y=new dL(n);w=-w/2;h=dM(k,h,d);h.a=y;h.a.f=EK(y.b,SK(y.b,y.a-1)/2);for(A=0;A<e.length;++A)z=AL(g,d,0,A),m=CK(q,z),(m=fA(m,l))?(n=m.b|| +t,y=$s(m,n),n=at(m,n),m=n.height,w+=m/2,p=-n.width/2,y=sM(z,1,w,p,y,n),eK(h,y),w+=m/2):(n=f.Tb(z),w+=n.height/2,p=-n.width/2,y=tM(z,1,w,p,n,!0),eK(h,y),w+=n.height/2);pM(k,h)}}}}};function xM(a){if(a.a&&!(a.H&8)){for(var b=a.a,c=b.a-1,d=0,e=0;e<a.c.length;++e){var f=a.c[e];f.i<c&&(c=f.i);f.h>d&&(d=f.h)}a.A=Math.abs(Math.atan2(KJ(b,d)-KJ(b,c),JJ(b,d)-JJ(b,c))-.02)>Math.PI/2}};function yM(a,b){vM.call(this,!1);this.c=a;this.a=b}F(yM,vM);yM.prototype.j=function(a){a.a.Y||(a.a.Y=a.a.V=new yL(a.data,a.a.f,this.c,this.a));a.a.Y.Rc()};yM.prototype.g=function(a){a=a.a.j;for(var b=0;b<a.length;++b)xM(a[b])};function zM(a,b,c,d,e,f,g){this.context=a.getContext("2d");this.canvas=a;this.x=b;this.y=c;this.width=d;this.height=e;this.a=0!=b||0!=c||d!=a.width||e!=a.height;this.b=f;this.c=g}function AM(a,b,c){c/=a.c;var d=Math.floor(a.width),e=Math.floor(a.height);a.a?b.drawImage(a.canvas,a.x,a.y,d,e,0,0,d*c,e*c):b.drawImage(a.canvas,0,0,d*c,e*c)}function BM(a){a.a&&a.b&&a.b.c(a)};function CM(a){this.a=a}CM.prototype.c=function(){};CM.prototype.f=function(a,b){var c=pF(2,this.a);a*=c;b*=c;var d=go("CANVAS");d.width=a;d.height=b;d.getContext("2d").scale(c,c);return new zM(d,0,0,a,b,this,this.a)};function DM(a){this.g=[];this.b=[];this.a=a}DM.prototype.c=function(a){var b=pF(2,this.a);a.context.clearRect(a.x/b,a.y/b,a.width/b,a.height/b);this.b.push(a)};DM.prototype.f=function(a,b){if(0==this.b.length){var c=go("CANVAS"),d=pF(2,this.a);c.width=1536*d;c.height=1024*d;this.g.push(c);c.getContext("2d").scale(d,d);for(var e=0;4>e;e++)for(var f=0;6>f;f++){var g=new zM(c,256*d*f,256*d*e,256*d,256*d,this,this.a);this.b.push(g)}}c=pF(2,this.a);a*=c;b*=c;c=this.b.pop();c.width=a;c.height=b;return c};function EM(){}F(EM,Error);function FM(){this.a="pending";this.f=[];this.c=this.g=void 0}UC(FM);function GM(){Ja.call(this,"Multiple attempts to set the state of this Result")}F(GM,Ja);r=FM.prototype;r.getState=function(){return this.a};r.na=function(){return this.g};r.getError=function(){return this.c};r.wait=function(a,b){"pending"==this.a?this.f.push({qc:a,scope:b||null}):a.call(b,this)};function HM(a,b){if("pending"==a.a)a.g=b,a.a="success",IM(a);else if(!JM(a))throw new GM;} +function KM(a,b){if("pending"==a.a)a.c=b,a.a="error",IM(a);else if(!JM(a))throw new GM;}function IM(a){var b=a.f;a.f=[];for(var c=0;c<b.length;c++){var d=b[c];d.qc.call(d.scope,a)}}r.cancel=function(){return"pending"==this.a?(KM(this,new EM),!0):!1};function JM(a){return"error"==a.a&&a.c instanceof EM}r.then=function(a,b,c){var d,e,f=new WC(function(a,b){d=a;e=b});this.wait(function(a){JM(a)?f.cancel():"success"==a.getState()?d(a.na()):"error"==a.getState()&&e(a.getError())});return f.then(a,b,c)};function LM(a,b,c){a.wait(b,c)}function MM(a,b,c){LM(a,function(a){"success"==a.getState()&&b.call(c,a.na(),a)},c)}function NM(a,b){var c=new OM([a]);LM(a,function(a){"success"==a.getState()?HM(c,b(a.na())):KM(c,a.getError())});return c}function PM(a,b,c){var d=new OM([a]);LM(a,function(a){"success"==a.getState()?(a=b.call(c,a),d.b.push(a),LM(a,function(a){"success"==a.getState()?HM(d,a.na()):KM(d,a.getError())})):KM(d,a.getError())});return d} +function QM(a){function b(){"pending"==e.getState()&&Qa(d,c)&&HM(e,d)}function c(a){return"pending"!=a.getState()}var d=Va(arguments),e=new OM(d);Ma(d,function(a){a.wait(b,void 0)});return e}function RM(a){function b(a){return"success"==a.getState()}var c=Va(arguments),d=new OM(c);LM(QM.apply(QM,c),function(a){a=a.na();Qa(a,b)?HM(d,a):KM(d,a)});return d}function OM(a){FM.call(this);this.b=a}F(OM,FM);function SM(a){this.f=a}function TM(a,b){if(!b.data||UM(b.data))return!0;for(;"success"==a.Od(b).getState(););return a.Ub(b)}function VM(a,b){function c(){0==--d&&(g&&g(),HM(f,!0))}for(var d=0,e=Ss.sc(),f=new FM,g=null,h=0;h<b.length;h++){var k=b[h];Ts(e,k)||(g=g||a.f(),d++,Us(e,k,c))}0==d&&HM(f,!0);return f} +function WM(a,b){var c=b.data;b=b.a.f;var d=c.a;if(Jy(d)&&py(Ky(d))){var e=nI(wy(d)),f=c.getZoom();c=c.b;var g={};d=Ky(d).a;for(var h=0;h<d.length;++h)for(var k=d[h],l=c.a[4][h],m=null!=k.a?2:1,n=0;n<m;++n){var p=0==n?Cu(k):Du(k);if(null!=p.a){p=p.a;for(var q=0;q<p.length;++q){var t=XM(l,n,q);(t=fA(CK(b,t),f))&&t.a&&(t=Xs(t,e,su(p[q])),g[t]=!0)}}}b=Object.keys(g)}else b=[];return VM(a,b)};var YM=null,ZM=null;function $M(){YM||(YM=new FM,HM(YM,!0));return YM}function aN(){ZM||(ZM=new FM,KM(ZM));return ZM}function bN(a,b,c){LM(a,function(a){JM(a)||b.call(this,a)},c)}function cN(a){if(JM(a)){var b=!1;a=a.b;for(var c=0;c<a.length;c++)b|=a[c].cancel()}}function dN(a){function b(){"pending"==d.getState()&&HM(d,c)}if(1==arguments.length)return arguments[0];var c=Va(arguments),d=new FM;Ma(c,function(a){a.wait(b,void 0)});return d};function eN(a,b,c,d,e,f){this.f=f.o;this.j=a;this.h=b;this.l=c;this.g=e;(a=fN[d])?d=a:(a=pb?new DM(d):new CM(d),d=fN[d]=a);this.i=d;this.a=[this.gf,this.Ad,this.Wd,this.qf,this.Le,this.Qe,this.Me];this.b=this.a.indexOf(this.Ad);this.c=this.a.indexOf(this.Wd)}F(eN,SM);var gN=$M(),hN=aN(),fN={};function iN(a,b){b=b.a;b.i.length||(b.i=Array(a.a.length))}r=eN.prototype; +r.Od=function(a){iN(this,a);for(var b=a.a,c=0;c<this.a.length;++c){var d=b.i[c];if(!d){d=this.a[c];if(d==this.Le||d==this.Qe||d==this.Me){var e="success"==b.i[this.c].getState(),f="success"==b.i[this.b].getState();if(!e||!f)continue}b.i[c]=d.call(this,a);return gN}}a=[];for(c=0;c<this.a.length;++c)(d=b.i[c])&&"pending"==d.getState()&&a.push(d);return a.length?dN.apply(null,a):hN};r.Ub=function(a){for(var b=0;b<this.a.length;++b){var c=a.a.i[b];if(!c||"success"!=c.getState())return!1}return!0}; +r.Wd=function(a){function b(){0==--c.l&&HM(d,!0)}var c=a.a;c.l=0;var d=new FM;c.l+=jN(a,b);c.l+=kN(a,b);a=a.b;if(a){var e=a.a;iN(this,a);var f=e.i[this.c];f||(f=this.Wd(a),e.i[this.c]=f)}return f&&"pending"==f.getState()?c.l?RM(f,d):f:c.l?d:gN};function jN(a,b){var c=a.data.a;a=a.data.j;for(var d=null!=c.a&&ry(Ly(c))?Ly(c).Aa:[],e=0,f=0;f<d.length;f++){var g=eJ(a,c,f);g&&(e+=lN(g,b))}return e}function kN(a,b){var c=0;a=a.data;null!=a.a.h&&(a=BL(a),c+=lN(a,b));return c} +r.Ad=function(a){var b=WM(this,a);a=a.b;if(a){var c=a.a;iN(this,a);var d=c.i[this.b];d||(d=this.Ad(a),c.i[this.b]=d)}return d&&"pending"==d.getState()?"pending"==b.getState()?RM(d,b):d:"pending"==b.getState()?b:gN};r.gf=function(a){var b=a.a;if(a.b){var c=a.b,d=a.N.ba().c,e=PB(this.g,d),f=c.data.i;f.length&&TA(e,f);this.gf(c)}b.f||(c=a.data.m,d=a.N.ba().c,e=PB(this.g,d),f=a.data.i,f.length&&TA(e,f),SA(e,c),d=mN(a.data,d,e),b.f=d,a.data.s=d,nN(a.data));return gN};r.qf=function(a){oN(this,a);return gN}; +r.Le=function(a){a.a.j.length||this.h.b(a);(a=a.b)&&this.h.b(a);return gN}; +function pN(a,b){var c=b.a.j;if(c.length&&b.a.f)for(var d=0;d<c.length;d++)for(var e=a.l,f=c[d],g=b,h=b.a.f,k=0;k<f.c.length;k++){var l=f.c[k];switch(l.type){case 3:zK(e,l.c,g.a.Y,h,l,g.data.getZoom());break;case 2:var m=e,n=l,p=h,q=n.c,t=g.a.V;l=g.data.getZoom();var v=lK(n.label);zK(m,q,t,p,n,l);var u=q.a;t=u&&u.b;var w=!!q.canvas||!!q.b||!!q.c;if(u&&(w||t)){var y=null;w&&!t&&(y=AK(q));if(y||t)for(t=GK(p,n.a),p=SH(p,n.a),w=n.f,v&&n.g&&(w*=-1),q=HK(u,y,q.b),y=w,m.c&&!m.f&&(m.f=new wJ),u=n.c,m.a.reset(), +TK(n,v,y,m.a),n=0;n<m.a.b;n++)UK(m,t,p,l,u,q,m.a.a[6*n+4],m.a.a[6*n+5])}}}}r.Me=function(a){pN(this,a);a.b&&pN(this,a.b);return gN};r.Qe=function(a){return qN(this,a)?gN:null};function lN(a,b){a.Qb()&&a.Ib(3);return!a.Db()&&!a.bc()||0==a.Ab().src.length?(ec(a.Ab(),"load",function(){b()}),!0):!1} +function qN(a,b,c){if(b.a.s||4==b.N.Ea())return!0;var d=b.a.rc;if(0<d.h||1!=d.b.length)var e=null;else e=d.b[0],1!=e.type?e=null:(d.h=1,e=dJ(gJ(d.a,e.type,e.b)));if(e)return b.a.Ia=e,!0;e=b.a.D;e||(e=a.i.f(256,256),b.a.D=e);a=e;if(a.a){a.context.save();a.context.setTransform(1,0,0,1,a.x,a.y);a.context.beginPath();a.context.rect(0,0,a.width,a.height);a.context.clip();var f=pF(2,a.c);a.context.scale(f,f)}a=e.context;b=b.data.getZoom();f=25;c&&(kJ(d),f=-1);lJ(d,a,1,b,f);e.a&&e.context.restore();return d.b.length== +d.h&&null==d.f&&null==d.g}function oN(a,b){if(!b.a.rc){var c=b.a;a=a.j;a=new jJ(a.Ra,a.La,a.Qa,b);c.rc=a}return b.a.rc};function rN(a,b){this.start=a<b?a:b;this.a=a<b?b:a};function sN(){this.f=[];this.g=[];this.a=[];this.h=[];this.lng=this.lat=this.c=this.b=0;for(var a=256,b=0;21>b;b++){var c=a/2;this.f.push(a/360);this.g.push(a/(2*Math.PI));this.a.push(c);this.h.push(a);a*=2}};var tN=2*Math.PI;function uN(a){var b=Math.floor(a+1E-6);return 1E-6>a-b?b:a};function vN(a,b){this.origin=new Float64Array(3);a&&dG(this.origin,a);this.a=new Float64Array(3);b&&dG(this.a,b)}vN.prototype.set=function(a,b){dG(this.origin,a);dG(this.a,b)};function wN(a){function b(b,c){xN(a,b,c,f);return f.origin[0]-f.a[0]*f.origin[2]/f.a[2]}var c=a.c,d=a.a,e=Yn(yN(a)+1,0,d),f=new vN,g=b(0,e),h=b(0,d);e=b(c,e);c=b(c,d);return new rN(Math.min(g,h,e,c),Math.max(g,h,e,c))}function zN(a){var b=wN(a);a=Math.floor(b.start/tN+.5);b=Math.ceil(b.a/tN-.5);-5>a&&(a=-5);5<b&&(b=5);return new rN(a,b)}function AN(a){return a.a/2/Math.tan(a.g/2)/a.s*2*Math.PI} +function BN(a){var b=MJ();SJ(b,0,a.b,a.o);var c=a.a,d=c/2/Math.tan(a.g/2),e=MJ();e[0]=2/a.c*d;e[1]=0;e[2]=0;e[3]=0;e[4]=0;e[5]=2/c*-d;e[6]=0;e[7]=0;e[8]=0;e[9]=0;e[10]=-1;e[11]=-1;e[12]=0;e[13]=0;e[14]=2/3*2*d-d;e[15]=d;a=MJ();PJ(e,b,a);return a};function CN(a){this.j=null;this.i=new rN(0,0);this.a=new rN(0,0);this.l=a;this.f=2;this.h=this.g=this.c=this.b=0;this.o=new Float32Array(4);this.m=MJ()} +function DN(a,b,c,d,e,f){var g=a.j,h=a.c;if(0==a.f||1==a.f){g=1==a.f;var k=1/Math.pow(2,d);h=Math.pow(2,a.b-d);b=b*k+e;if(b+k<a.i.start/tN+.5||b>a.i.a/tN+.5)f=!1;else{b*=a.c;d=c*k*a.c;c=(g?Math.floor(b):b)-a.g;e=(g?Math.floor(d):d)-a.h;var l=k=h;g&&(g=Math.floor(d+256*h)-a.h,k=(Math.floor(b+256*h)-a.g-c)/256,l=(g-e)/256);NJ(f,k,l,1,c,e,0);f=!0}return f}k=1/(1<<d);d=h/256*k;f[0]=d;f[1]=0;f[2]=0;f[3]=0;f[4]=0;f[5]=d;f[6]=0;f[7]=0;f[8]=0;f[9]=0;f[10]=1;f[11]=0;f[12]=0;f[13]=0;f[14]=0;f[15]=1;c=c*k-(-g.i/ +tN+.5);f[12]=(b*k-(g.h/tN+.5)+e)*h;f[13]=c*h;a=a.m;SJ(a,0,g.b,g.o);PJ(a,f,f);f[12]+=g.c/2;f[13]+=g.a/2;return!0}function EN(a,b,c){var d=0!=c[4]||0!=c[1],e=Math.floor(c[0]+.5),f=Math.floor(c[5]+.5),g=1E-6<Math.abs(c[0]-e)||1E-6<Math.abs(c[5]-f),h=pF(2,a.l);a=c[12]*h;h*=c[13];if(d||g)return b.transform(c[0],c[1],c[4],c[5],a,h),1/Math.sqrt(c[0]*c[0]+c[1]*c[1]);b.transform(e,0,0,f,Math.floor(a+.5),Math.floor(h+.5));return 1/Math.sqrt(e*e)} +function sK(a,b,c,d,e,f){for(var g=a.o,h=MJ(),k=0,l=a.a.start;l<=a.a.a;l++)if(DN(a,b,c,d,l,h)){var m=h,n=g,p=e.b,q=WJ;q[0]=e.a;q[1]=p;q[2]=0;q[3]=1;RJ(m,WJ,n);f[2*k]=g[0];f[2*k+1]=g[1];k++}return k};var FN=1/512,kK=new bK;function GN(a,b,c){a=new oq(-256,a.width+256,a.height+256,-256);var d=Math.floor((a.right-a.left)/128),e=Math.floor((a.bottom-a.top)/128),f=d*e,g=HN(f);IN(b,a,d,e,g);a=[];JN(g,f,b,a);f={};for(g=0;g<a.length;g++)d=a[g],f[d]||(f[d]=jK(b[d]));d=[];for(g=0;g<a.length;g+=2){e=a[g];var h=a[g+1];KN(b[e],f[e],b[h],f[h],d,c)}kK.reset();d.sort(function(a,b){c&&a[0].uc==b[0].uc&&a[0].ab!=b[0].ab?b=a[0].ab?-1:1:(a=a[0],b=b[0],b=a.v-b.v||a.h-b.h);return b});return d} +function IN(a,b,c,d,e){for(var f,g,h,k,l=0;l<a.length;l++)if(g=a[l],2!=g.wb)for(f=g.o,g=LN(b.left,f.left,c),h=LN(b.left,f.right,c),k=LN(b.top,f.top,d),f=LN(b.top,f.bottom,d);k<=f;k++)for(var m=g;m<=h;m++)e[k*c+m].push(l)}function JN(a,b,c,d){for(var e,f,g,h,k,l,m=0;m<b;m++)for(var n=0;n<a[m].length-1;n++)for(var p=n+1;p<a[m].length;p++)e=a[m][n],f=c[e],g=a[m][p],h=c[g],k=f.o,l=h.o,k.top>l.bottom-FN||k.bottom<l.top+FN||k.left>l.right-FN||k.right<l.left+FN||(1!=f.wb||1!=h.wb)&&d.push(e,g)} +function KN(a,b,c,d,e,f){for(var g=0;g<b.length;g++)for(var h=0;h<d.length;h++){var k=b[g],l=d[h];if(!(k.b&&k.b===l.b||k.a[8]>l.a[10]||l.a[8]>k.a[10]||k.a[9]>l.a[11]||l.a[9]>k.a[11]||k.c&&!ZJ(k,l)||l.c&&!ZJ(l,k))){b=0>(a.v-c.v||a.h-c.h);f&&a.uc==c.uc&&a.ab!=c.ab&&(b=a.ab);1==a.wb&&(b=!0);1==c.wb&&(b=!1);b?e.push([a,c]):e.push([c,a]);return}}}function HN(a){for(var b=Array(a),c=0;c<a;c++)b[c]=[];return b}function LN(a,b,c){a=Math.floor((b-a)/128);return 0>a?0:a>=c?c-1:a};function MN(){this.g=[];this.h=!1;this.a=null;this.f=new WH(0,0);this.c=new WH(0,0);this.b=new WH(0,0)}MN.prototype.reset=function(a){this.f.x=0;this.f.y=0;this.b.x=0;this.b.y=0;this.c.x=0;this.c.y=0;this.a=NN(a);ON(this,a);this.h=!1};function NN(a){return{lat:PN(a),lng:QN(a),zoom:a.getZoom(),rotation:RN(a),ta:SN(a),width:TN(a),height:UN(a)}}function ON(a,b){if(a.a){var c=QN(b),d=PN(b);if(c!=a.b.x||d!=a.b.y)b=b.l,VN(b,a.a.lng,a.a.lat,a.f),VN(b,c,d,a.c),a.b.x=c,a.b.y=d}} +function WN(a){return a.c.x-a.f.x}function XN(a){return a.c.y-a.f.y}function YN(a){return a.data.g&&0!=a.a.j.length?a.a.Ga:!1}MN.prototype.getZoom=function(){return this.a?this.a.zoom:-1};function ZN(a,b,c,d,e,f,g){this.m=a;this.a=b;this.g=c;this.o=d;this.j=-1;this.f=null;this.l=-1;this.h=null;this.s=e;this.u=f;this.v=g;this.b=this.za=-1;this.i=this.c=!1}ZN.prototype.ka=function(){return this.o};function XM(a,b,c){a=0==b?a.f:a.h;return!a||c>=a.length?-1:a[c]};function $N(a,b,c,d){this.b=a;this.o=b;this.f=c;this.m=d;this.a=new MN;this.c=!1;this.g=-1;this.h=null;this.j=0}var aO=Math.tan(ao(60)/2); +function bO(a,b,c,d,e,f){var g=a.f,h=a.c^d&&0<g,k=h||a.g>e,l=!1;!d&&a.c&&(l=!0);a.c=d;if(!a.c||k){k=[];for(var m=[],n=[],p={},q=!1,t=0;t<b.length;++t){var v=b[t],u=c[t];p[v.N.aa()]||(p[v.N.aa()]=!0,v.data.g&&(k.push(v),m.push(u),v.a.Ga?q=q||v.a.s:n.push(v)),(v=v.b)&&!p[v.N.aa()]&&(p[v.N.aa()]=!0,v.data.g&&(k.push(v),m.push(u),v.a.Ga||n.push(v))))}b=q;c=a.a;p=Na(k,YN);if(p.length!=c.g.length)c.h=!0;else for(q=0;q<p.length;q++)p[q].N.aa()!=c.g[q].N.aa()&&(c.h=!0);c.g=p;if(!(h=h||b||l))a:if(h=a.a,l= +a.b,f=!!f,h.h||!h.a)h=!0;else if(b=NN(l),b.zoom!=h.a.zoom||b.rotation!=h.a.rotation||b.ta!=h.a.ta||b.width!=h.a.width||b.height!=h.a.height)h=!0;else{if(0<SN(l)||f)if(b.lat!=h.a.lat||b.lng!=h.a.lng){h=!0;break a}h=!1}if(h)n=a.h,a.h=a.b.ba(),n=a.m&&(!n||Ps(a.h,n)),a.a.reset(a.b),cO(a,k),dO(a,k,m,d,n,e),a.j++;else if(ON(a.a,a.b),0<n.length)for(cO(a,n),d=0;d<n.length;++d)for(m=n[d].a.j,f=0;f<m.length;f++)h=m[f],l=!h.s,h.b?(h.b.screenX+=WN(a.a),h.b.screenY+=XN(a.a),h.b.c&&(l=!1)):h.a&&h.a.o&&(l=!1),iK(h), +h.Gb(l,e,!0,a.f);for(n=0;n<k.length;++n)for(d=k[n],m=d.a.j,f=0;f<m.length;++f)h=m[f],gK(h,e,g)&&a.l(d,h)}}$N.prototype.l=sa; +function dO(a,b,c,d,e,f){for(var g=new fo(TN(a.b),UN(a.b)),h=[],k=[],l=g.height,m=0;m<b.length;++m){var n=a,p=b[m],q=c[m],t=l,v=f,u=h,w=k;if(p.a.Ra!=v){p.a.Ra=v;p=p.a.j;for(var y=0;y<p.length;++y){var A=p[y],z;if(!(z=A.B))if(A.b){z=t-q.top;var C=t-q.bottom;z=0<z&&A.b.screenY<z||C<t&&A.b.screenY>C}else z=!1;z||eO(A)?A.Gb(!1,v,!0,n.f):2==A.wb?w.push(A):u.push(A)}}}b=a.f;q=a.b.getZoom();c=0;m=[];for(l=0;l<h.length;++l)n=h[l],d||n.s||q<n.m-1E-4||q>n.K+1E-4||(n.b?n.b.c:n.a&&n.a.o)?(n=n.Gb(!1,f,!1,b),n> +c&&(c=n)):m.push(n);for(l=0;l<m.length;l++)iK(m[l]);for(l=0;l<k.length;l++)iK(k[l]);d=GN(g,m,e);for(l=0;l<m.length;l++)e=m[l],n=e.Gb(!0,f,0!=e.wb,b),n>c&&(c=n);for(l=0;l<d.length;l++)e=d[l],e[0].ab&&(n=e[1].Gb(!1,f,!1,b),n>c&&(c=n),e[1].G&&(n=e[1].G.Gb(!1,f,!1,b),n>c&&(c=n)));for(l=0;l<k.length;++l)n=k[l],n=n.Gb((!n.l||n.l.ab)&&!(n.b?n.b.c:n.a&&n.a.o),f,!0,b),n>c&&(c=n);k=c;0<k&&(f+=k,f>a.g&&(a.o(f),a.g=f))} +function eO(a){if(!a.a)return!1;for(var b=a.a,c=0;c<a.c.length;++c){var d=a.c[c];if(0>d.i||d.h>a.a.a-1)return!0;var e=Math.floor(d.i)+1;d=Math.ceil(d.h)-1;if(0<=d-e)for(;e<=d;++e){var f=b.i[e];if(f>aO||f<-aO)return!0}}return!1} +function cO(a,b){for(var c={},d=a.b.l,e=0;e<b.length;++e){var f=b[e],g=f.data,h=c[g.getZoom()];h||(h=fO(d,g.getZoom()),c[g.getZoom()]=h);var k=256*tK(g);g=256*uK(g);f=f.a.j;for(var l=0;l<f.length;++l){var m=f[l];if(m.b)a.i(m,h,k,g);else if(m.a){var n=m.a;n.o=h.gd(n.a,n.l,n.g,k,g,n.altitude);cL(n.c,n.a,n.g);n.m=0;n.j=null;n=m.c;for(var p=0;p<n.length;++p)n[p].A();xM(m)}}}}$N.prototype.i=function(a,b,c,d){if(a=a.b)UJ[0]=a.a,UJ[1]=a.b,a.c=b.gd(1,UJ,VJ,c,d,a.altitude),a.screenX=VJ[0],a.screenY=VJ[1]};function gO(a,b){$N.call(this,a,sa,0,b)}F(gO,$N);function hO(a){this.i=a;this.c=[];this.j=[];this.h=[];this.g=[];this.l=[];this.b=this.a=0;this.f=-1}function iO(a,b){var c=a.i.createTexture();a.c.push(c);a.a+=b;return a.c.length-1}function jO(a,b){a.j.push(b);a.a+=b.c}function kO(a,b,c){a.h.push(b);a.g.push(0);a.l.push(c);return a.h.length-1}function lO(a){a.f=$p(a.i.h,a,function(){a.f=-1;mO(a)},a.a,a.c.length);a.b=1} +function mO(a){if(1==a.b){a.b=2;-1!=a.f&&(Vp(a.i.h.a,a.f),a.f=-1);for(var b=0;b<a.c.length;++b)a.i.deleteTexture(a.c[b]);for(b=0;b<a.h.length;++b)a.l[b].call(a.h[b]);for(b=0;b<a.j.length;b++){for(var c=a.j[b],d=c.b,e=0;e<c.a.length;++e){var f=d.b.b[6*c.a[e].f+2],g=d.b;Kq(g,c.a[e].f);g.v--;0==--d.h[f]&&(d.a.deleteBuffer(d.g[f]),d.g[f]=null)}c.buffer=null;c.a.length=0}a.c=[];a.h=[];a.g=[];a.l=[];a.j=[]}};function nO(){Pp.call(this);this.b=this.m=this.h=this.g=0;this.la=1;this.Pa=this.s=!1;this.I=this.ja=this.G=this.L=this.Ba=this.ga=this.c=null;this.T=[];this.ha=[];this.U=[];this.W=[];this.P=[];this.S=[];this.Y=this.H=this.V=this.o=this.va=this.ya=this.C=null;this.j=[];this.v=[];this.Ga=!1;this.Ra=-1;this.A=this.u=null;this.Z=-1;this.Sa=!1;this.Ia=this.D=this.rc=null;this.K=-1;this.l=this.J=null;this.pa=this.ra=0;this.Ja=!1;this.Za=this.Wa=-1;this.Qa=!1;this.i=[];this.jb=this.f=this.fa=this.a=null; +this.ia=this.B=0;this.ib=-1;this.$a=this.Oa=!1;this.Ca=-1;this.La=0}F(nO,Pp);function oO(a){mO(a.a);a.a=null}nO.prototype.X=function(){for(;this.J&&"pending"==this.J.getState();)this.J.cancel();this.a&&oO(this);this.D&&(BM(this.D),this.D=null);this.fa&&(this.fa.$(),this.fa=null)};function pO(a,b){this.N=a;this.data=b;this.a=new nO;this.c=this.b=null;if(b){a=this.a;var c=tK(b),d=uK(b),e=b.getZoom(),f=1/Math.pow(2,e);a.g=c*f;a.h=d*f;a.m=e;a.b=f/256;a.Z=c%3+1+d%3*3+10*e;if(b=b.a.getExtension(96629873))a.la=nI(b),a.s=null==b.b?!1:b.b,a.Pa=null==b.b?!1:b.b}}function qO(a){return!a.data&&null!==a.c}function rO(a){var b=a.a.a;b&&1==b.b&&1==b.b&&Wp(b.i.h.a,b.f);a.b&&rO(a.b)}function sO(a,b){a=new pO(a,null);a.c=b;return a};function tO(){this.g=-1;this.b=!0;this.a=new uO(-1);this.h=this.f=this.i=this.j=this.c=0}var vO=[0,1,1],wO=5/255; +function xO(a,b,c,d,e,f){var g=d.zoom;d=0>a.a.zoom?0:g-a.a.zoom;var h=E();var k=c.length;var l=a.g;a.g=h;0>l?k=Infinity:(h-=l,0<d&&(a.c=0),0!=k||a.a.a.length?(d=a.c-h,0<=d?(a.c=d,h=0):(a.c=0,h=-d)):a.c=400,k=h);d=new uO(g);yO(d,c,e,f);if(f){g=c.length?c[0].N.getZoom():b.length?b[0].N.getZoom():g;h=[];for(l=0;l<b.length;l++)if(b[l].N.getZoom()==g){var m=sO(b[l].N,0);h.push(m)}yO(d,h,e,f)}e=d.zoom;f=Infinity;g=-Infinity;h=Infinity;l=-Infinity;for(m=0;m<b.length;m++){var n=b[m].N;if(n.getZoom()==e){var p= +iC(n);n=jC(n);p<f&&(f=p);n<h&&(h=n);p>g&&(g=p);n>l&&(l=n)}}for(m=0;m<c.length;m++)n=c[m].N,p=iC(n),n=jC(n),p<f&&(f=p),n<h&&(h=n),p>g&&(g=p),n>l&&(l=n);a.j=h;a.i=g;a.f=l;a.h=f;if(0<k)for(b=a.a,c=k,k=0;k<b.a.length;k++)zO(b.a[k],c);b=a.a;c=a.h;k=a.j;e=a.i;f=a.f;g=d.zoom-b.zoom;for(h=0;h<b.a.length;h++)if(l=b.a[h],l.a!=l.b||0!=l.a)if(0==g)p=l.x,n=l.y,p>=c&&p<=e&&n>=k&&n<=f&&AO(d,p,n,l);else if(0<g){var q=1<<g;p=l.x<<g;n=l.y<<g;m=p+q-1;q=n+q-1;if(!(m<c||q<k||p>e||n>f)){var t=Math.max(c,p);p=Math.max(k, +n);m=Math.min(e,m);q=Math.min(f,q);for(n=p;n<=q;n++)for(p=t;p<=m;p++)AO(d,p,n,l)}}else p=l.x>>-g,n=l.y>>-g,p<c||n<k||p>e||n>f||AO(d,p,n,l);a:{for(b=0;b<d.a.length;b++)if(c=d.a[b],c.a!=c.b){b=!1;break a}b=!0}a.b=b;a.a=d} +function yO(a,b,c,d){if(0!=b.length){for(var e=b[0].N.getZoom(),f=0;f<b.length;f++){var g=b[f],h=g.N,k=c?-1:g.c;g=0>k;if(g||d)var l=k=1;else 0>k?k=1:17<=k&&17<=e?k=0:(k=e-k,k=3<=k?vO[2]:2<=k?vO[1]+k%1*(vO[2]-vO[1]):1<=k?vO[0]+k%1*(vO[1]-vO[0]):0),l=0;BO(a,new CO(iC(h),jC(h),g,k,l))}a.zoom=e}}function AO(a,b,c,d){var e=(e=a.b[67108864*b+c])?a.a[e-1]:void 0;e||(e=new CO(b,c,!0,1,0),BO(a,e),e.b=0,e.c=!1);e.a=d.a}function zO(a,b){var c=a.b-a.a;a.a=Math.abs(c)<wO?a.b:a.a+c*(1-Math.exp(3*-b/80))} +function CO(a,b,c,d,e){this.x=a;this.y=b;this.c=c;this.a=e;this.b=d}function uO(a){this.b=[];this.a=[];this.zoom=a}function BO(a,b){var c=67108864*b.x+b.y,d=a.b[c];d||(a.a.push(b),d=a.a.length);a.b[c]=d};function DO(){this.j=this.l=0}var EO=0,FO=0,GO=0,HO=0;DO.prototype.u=function(a){this.l+=a.l;this.j+=a.j};DO.prototype.m=function(){var a=new DO;a.l=this.l;a.j=this.j;return a};function IO(a){this.g=a;this.b=this.c=0;this.a=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];this.f=0}function JO(a){a.c=0;for(var b=a.b=0;b<a.a.length;b++)a.a[b]=0;a.f=0}function KO(a,b){var c=a.b,d=a.a,e=a.f;b.m=a.c;b.l=c;for(a=b.a=0;a<d.length;a++)b.a+=d[a]*(a<LO.length?LO[a]:1);b.g=e} +function MO(a,b){for(var c=0;c<b.length;++c)for(var d=b[c].a,e=0;e<d.length;++e)for(var f=d[e].a,g=d[e].b,h=0;h<f.length;++h){var k=a,l=f[h],m=g.zoom;if(qO(l))0>l.c?k.f++:(k.b++,k.a[Yn(m-l.c,0,k.a.length-1)]++);else{var n=l.a;n.Oa&&(n.$a?(k.g.l++,0==n.La&&GO++):(k.g.j++,0==n.La&&HO++),n.La++);l.data&&l.N.getZoom()==m&&4!=l.N.Ea()&&k.c++}}};function NO(a,b,c,d){this.i=b;this.c=c;this.l=a;a=this.h=a.Pf;a.a=d;for(b=0;b<a.c.length;++b)OO(a)&&a.a.ic(a.c[b].Md,2,!0);this.j=d;this.b=[];this.a=[];this.f=[];this.g=-1}function PO(a){if(-1==a.g){for(var b=a.b,c=0,d=0;d<b.length;++d)for(var e=b[d].a,f=0;f<e.length;++f)for(var g=e[f].a,h=0;h<g.length;++h)qO(g[h])&&c++;a.g=c}return a.g};function QO(){this.height=this.width=this.ta=this.i=this.b=this.zoom=this.lng=this.lat=0;this.h=1;this.g=0;this.c=this.a=!1;this.f=1};function qH(){this.a=0;this.b=null}function RO(a,b){a.b=b}function SO(a){a.a++;a.b&&1==a.a&&a.b(1)};function TO(a){Qb.call(this,"DataEvent",a)}F(TO,Qb);function UO(a,b,c,d,e,f){Qb.call(this,"FrameComplete",a);this.startTime=b;this.h=c;this.g=d;this.f=e;this.c=f}F(UO,Qb);function VO(a,b){Qb.call(this,"FrameStart",a);this.startTime=b}F(VO,Qb);function WO(a,b,c){this.l=a;this.j=b;this.m=c}WO.prototype.u=function(a){this.l+=a.l;this.j+=a.j;this.m+=a.m};function XO(a,b){this.o=YO();this.b=null;this.j=a;this.i=b?b.j:null;this.c=-1;this.s=b?b.c:-1;this.h=-1;this.u=b?b.h:-1;this.v=b?b.f:-1;this.f=-1;this.g=this.a=this.l=this.m=0}var LO=[0,.1,.22,.5,.78,.9];function YO(){return x.performance&&x.performance.now?x.performance.now():E()} +function ZO(a){var b=a.b?a.b-a.o:YO()-a.o;if(a.i){var c=a.i;var d=a.j;c=!(c.h===d.h&&c.i===d.i&&c.m===d.m&&c.s===d.s&&c.j===d.j&&c.l===d.l&&c.f===d.f&&c.o===d.o&&c.b===d.b&&c.v===d.v&&c.g===d.g&&c.B===d.B&&c.A===d.A&&c.c===d.c&&c.a===d.a)}else c=1;c=c||a.c!=a.s||a.h!=a.u||a.f!=a.v?b:0;d=a.m+a.l+a.g;a=a.a+a.g;b*=0<d?a/d:0;return new WO(b,0<c?b:0,c)};function $O(){this.a=null;this.b=new WO(0,0,0)};var aP=WF();function bP(){this.height=this.width=this.b=this.ta=this.rotation=this.zoom=this.a=this.lng=this.lat=0}function cP(a,b){b=b||new bP;b.lat=a.lat;b.lng=a.lng;b.a=a.a;b.zoom=a.zoom;b.rotation=a.rotation;b.ta=a.ta;b.b=a.b;b.width=a.width;b.height=a.height;return b}function dP(a){var b=a.lat;90<b?a.lat=90:-90>b&&(a.lat=-90);b=a.lng;if(180<=b||-180>b)a.lng=Zn(b+180)-180;0>=a.zoom&&(a.zoom=0);b=a.rotation;if(360<=b||0>b)a.rotation=Zn(b);b=a.ta;0>b?a.ta=0:179.9<b&&(a.ta=179.9)};function eP(a,b,c){c=c||fP[0];vG(a.j,a.l,a.f,gP);var d=a.b,e=a.g,f=-a.o,g=gP;nG(c,-d);oG(c,0,0,-(g[2]+6371010));pG(c,-Math.PI/2);qG(c,-f);pG(c,g[1]);rG(c,-g[0]-Math.PI/2);a=a.c/a.a;f=fP[1];g=gP[2];var h=Math.abs(d)-e/2;g=h>=Math.PI/2?0:(g+6371010-6379856)*Math.cos(e/2)/Math.cos(h);h=2.5/Math.tan(e/2);g=g<h?.95*h:.95*g;var k=gP[2]+6371010;d=Math.tan(Math.abs(d)+Math.atan(Math.sqrt(a*a+1)/2/(1/(2*Math.tan(e/2)))));h=d*d+1;var l=-2*k;k=k*k-40451024652544;var m=l*l-4*h*k;0>=m||0>=d?d=(0<k?Math.sqrt(k): +0)+Math.sqrt(251537928192):(h=(-l-Math.sqrt(m))/(2*h),d*=h,d=Math.sqrt(h*h+d*d));h=e/2;e=d-g;l=Math.sin(h);0!=e&&0!=l&&0!=a&&(h=Math.cos(h)/l,f[0]=h/a,f[1]=0,f[2]=0,f[3]=0,f[4]=0,f[5]=h,f[6]=0,f[7]=0,f[8]=0,f[9]=0,f[10]=-(d+g)/e,f[11]=-1,f[12]=0,f[13]=0,f[14]=-(2*g*d)/e,f[15]=0);kG(f,c,b)}var gP=WF(),fP=[gG(),gG()];function hP(){this.a=WF()}var iP=eG(),jP=WF();function kP(a,b,c,d){ZF(b,a.a,iP);var e=aG(iP);a=-cG(iP,c);40589768420100>e||0>a?d&&$F(iP,6371010/Math.sqrt(e),d):($F(c,a,jP),YF(iP,jP,jP),e=aG(jP),40589768420100<=e?d&&$F(bG(jP,d),6371010,d):d&&($F(c,a-Math.sqrt(40589768420100-e),d),YF(b,d,d)))};function lP(a){this.a=a;this.b=!1}var mP=new WH(0,0),nP=WF(),oP=[eG(),eG(),eG(),eG(),eG()],pP=[gG(),gG(),gG()],qP=new vN;function fO(a,b){return a.b?new rP(a.a,b):new sP(a.a,b)}function VN(a,b,c,d){tG(b,c,0,nP);tP(a,d)} +function tP(a,b){var c=nP[0],d=nP[1];if(a.b){var e=new Float32Array(2),f=new Float32Array(2);a=fO(a,0);e[0]=128+128*c/Math.PI;e[1]=128-128*d/Math.PI;a.gd(1,e,f,0,0,0);b.x=f[0];b.y=f[1]}else{XF(nP,c,d,0);c=a.a;d=nP||WF();f=1/c.s;e=c.L;a=nP[1];var g=nP[2];e[0]=(nP[0]-c.h)*f;e[1]=(a-c.i)*f;e[2]=(g-c.m)*f;e[3]=1;iG(c.C,uP(c));f=c.C;a=e[0];g=e[1];var h=e[2],k=e[3];e[0]=a*f[0]+g*f[4]+h*f[8]+k*f[12];e[1]=a*f[1]+g*f[5]+h*f[9]+k*f[13];e[2]=a*f[2]+g*f[6]+h*f[10]+k*f[14];e[3]=a*f[3]+g*f[7]+h*f[11]+k*f[15];f= +1/e[3];e[0]*=f;e[1]*=f;e[2]*=f;vP(c,e,d);b.x=nP[0];b.y=nP[1]}}function sP(a,b){var c=gG(),d=pP[0],e=tN/(1<<b)/256;hG(c,e,-e,e);e=1/a.s;var f=a.C;f[0]=e;f[1]=0;f[2]=0;f[3]=0;f[4]=0;f[5]=e;f[6]=0;f[7]=0;f[8]=0;f[9]=0;f[10]=e;f[11]=0;f[12]=0;f[13]=0;f[14]=0;f[15]=1;oG(f,-a.h,-a.i,-a.m);kG(f,c,c);iG(d,uP(a));kG(d,c,c);iG(d,wP(a));kG(d,c,c);d=WF();yG(a.h,0,0,b,d);a=256*d[0];b=256<<b;this.a=a-b/2;this.b=a+b/2;this.f=b;this.c=c} +sP.prototype.gd=function(a,b,c,d,e,f){for(var g=this.a,h=this.b,k=this.f,l=this.c,m=0;m<a;m++){var n=b[2*m]+d,p=b[2*m+1]+e;n>h?n-=k:n<g&&(n+=k);var q=l[0]*n+l[4]*p+l[8]*f+l[12],t=l[1]*n+l[5]*p+l[9]*f+l[13];n=l[3]*n+l[7]*p+l[11]*f+l[15];.01>n&&(n=.01);c[2*m]=q/n;c[2*m+1]=t/n}return!1};function rP(a,b){var c=gG();this.c=c;b=tN/(1<<b)/256;hG(c,b,-b,b);b=pP[0];c=pP[1];eP(a,b,c);this.b=gG();var d=pP[2];iG(d,wP(a));kG(d,b,this.b);a=pP[2];lG(c,a);this.a=WF();sG(a,this.a)} +rP.prototype.gd=function(a,b,c,d,e,f){for(var g=oP[1],h=oP[2],k=oP[3],l=oP[4],m=this.c,n=this.b,p=!1,q=0;q<a;q++){h[0]=b[2*q]+d;h[1]=b[2*q+1]+e;h[2]=f;mG(m,h,g);var t=2*Math.atan(Math.exp(g[1]))-Math.PI/2;xG(g[0],t,6371010*g[2]*Math.cos(t),k);if(!p){t=this.a;var v=t[0]-k[0],u=t[1]-k[1],w=t[2]-k[2];t=cG(t,t)-40589768420100<v*v+u*u+w*w;p=p||t}mG(n,k,l);c[2*q]=l[0];c[2*q+1]=l[1]}return p};function xP(a,b,c,d,e,f,g,h,k){rc.call(this);this.L=a;this.a=b;this.canvas=h;this.Ba=c;this.gc=e;this.C=g;this.f=new NO(c,a,b,d);this.c=new QO;this.i=0;this.V=k;this.Ja=new $O;this.Ka=new DO;this.v=new IO(this.Ka);this.ya=this.I=0;this.P=!0;this.ha=-1;yP(this);var l=this;zP(this.Ba,function(a){l.P=!0;!a&&0<l.L.a||l.Wb()})}F(xP,rc);r=xP.prototype; +r.wc=function(){if(this.Qd()){this.a.f=this.canvas.c;this.vc();var a=this.Ja,b=new XO(this.a.a,a.a);a.a&&(a.a.b=YO(),a.b.u(ZO(a.a)));a.a=b;this.cd(b);this.dispatchEvent(new UO(this,this.i,E(),this.f.a.length,this.ya,PO(this.f)));b.c=this.C.j;b.h=this.Xa();b.f=0}};function yP(a){var b=a.L,c=a.gc;RO(b,function(a){1!=a||0<b.a||uo(c);2!=a||uo(c)})}r.Qd=function(){this.i=E();this.dispatchEvent(new VO(this,this.i));return!0}; +r.vc=function(){if(!this.rd()){this.P=!1;this.ha=this.a.s();var a=this.f;a.b=a.l.getData(a.c.a,a.c.f,a.c.ba(),a.c.c,a.a,a.c.g,a.j,0<a.i.a);var b=a.h.getData(a.c.a);a.b=a.b.concat(b);a.a=[];a.f=[];b=a.b;for(var c=a.a,d=a.f,e=0;e<b.length;e++)for(var f=b[e].a,g=0;g<f.length;g++)for(var h=f[g].b,k=f[g].a,l=0;l<k.length;l++){var m=k[l];m.data&&!UM(m.data)&&-1==c.indexOf(m)&&(c.push(m),d.push(h))}a.g=-1;this.dispatchEvent(new TO(this,this.f.a))}a=0<this.L.a;a=!(0<PO(this.f))||!a;d=yN(this.a.a)+1;this.Td(); +b=this.c;c=this.a;b.lat=PN(c);b.lng=QN(c);b.zoom=c.getZoom();b.b=Math.floor(b.zoom+1E-6);b.width=TN(c);b.height=UN(c);b.f=c.f;b.g=Yn(d,0,b.height);b.h=wG(b.lat);d=RN(c);b.i=d;b.ta=-ao(SN(c));b.a=!1;b.c=a};r.Xa=function(){return this.a.f};r.cd=function(){};r.rd=function(){return!AP(this)};function AP(a){return a.P||a.ha<a.a.s()}r.Td=function(){bO(this.C,this.f.a,this.f.f,!this.a.h,this.i)};r.Wb=function(){uo(this.gc)};function BP(){this.b=this.a=this.i=this.c=this.g=this.f=0}function CP(a){return a.b/a.g}BP.prototype.u=function(a){this.f+=a.f;this.g+=a.g;this.c+=a.c;this.i+=a.i;this.a+=a.a;this.b+=a.b};function DP(){FM.call(this);this.b=1}F(DP,FM);DP.prototype.cancel=function(){this.b--;return this.b?!1:DP.R.cancel.call(this)};function EP(a,b){this.h=a;this.g=b;this.b=new BP;this.a=[];this.c=[];this.f=[]}function FP(a,b){return a.a.K-b.a.K}function GP(a,b,c){if(UM(b.data))return a=new FM,HM(a,b),a;if(-1==b.a.K){var d=new DP;d.wait(D(a.j,a,b));b.a.J=d;b.a.K=c;-1!=a.f.indexOf(b)?(Ta(a.f,b),a.c.push(b)):(a.a.unshift(b),a.a.sort(FP),HP(a));a.b.f++}else b.a.J.b++,c>b.a.K&&(b.a.K=c,a.a.sort(FP),HP(a));return b.a.J} +EP.prototype.start=function(){if(!this.a.length)return Dr;var a=this.a.pop(),b=a.a.J,c=x.performance&&x.performance.now?x.performance.now():E(),d=this.h.Od(a),e=x.performance&&x.performance.now?x.performance.now():E();this.b.b+=e-c;"success"==d.getState()?this.h.Ub(a)?HM(b,a):this.a.push(a):"error"==d.getState()?KM(b):(this.c.push(a),d.wait(D(this.i,this,a)));return HP(this)}; +EP.prototype.i=function(a){-1!=this.c.indexOf(a)?(Ta(this.c,a),this.a.push(a),this.a.sort(FP),HP(this)):-1!=this.f.indexOf(a)&&Ta(this.f,a)};EP.prototype.j=function(a){var b=a.a.J;JM(b)?(-1!=this.a.indexOf(a)?Ta(this.a,a):-1!=this.c.indexOf(a)&&(Ta(this.c,a),this.f.push(a)),this.b.i++):"error"==b.getState()?this.b.c++:this.b.g++;a.a.K=-1;a.a.J=null};function HP(a){if(!a.a.length)return Dr;var b=a.a[a.a.length-1].a.K;a.g.Mb(a,b);a.g.qd(a,b);return a.start};function IP(a,b){this.g=1;this.c=a;this.a=go("DIV");this.a.className="canvas-container";this.a.style.position="absolute";this.a.style.left="0px";this.a.style.top="0px";this.a.style.zIndex=0;this.c.appendChild(this.a);this.j=a.clientWidth;this.i=a.clientHeight;this.h=new Float64Array(2);this.l=new Float64Array(2);this.m=new sN;this.b=new Float64Array(2);this.s=uN(b.zoom);this.o=this.c.style.backgroundColor;this.f=null;JP(this,b,this.h);KP(this)} +function KP(a){var b="translate3d("+-a.b[0]+"px, "+-a.b[1]+"px, 0) scale(1)";a.a.style.transform=b;a.a.style.webkitTransform=b}function JP(a,b,c){var d=a.m,e=b.lat,f=uN(b.zoom);if(f==Math.floor(f)&&f<d.a.length){var g=d.a[f];var h=d.f[f];f=d.g[f]}else f=256*Math.pow(2,f),g=f/2,h=f/360,f/=2*Math.PI;d.b=g+b.lng*h;b=Yn(Math.sin(ao(e)),-.9999,.9999);d.c=g-.5*Math.log((1+b)/(1-b))*f;d=a.m.c-a.i/2;c[0]=Math.round((a.m.b-a.j/2)*a.g)/a.g;c[1]=Math.round(d*a.g)/a.g} +function LP(a,b){var c=!1;if(a.j!=b.width||a.i!=b.height){c=b.width;var d=b.height;if(c!=a.j||d!=a.i)a.j=c,a.i=d,a.c.style.width=c+"px",a.c.style.height=d+"px";c=!0}c||a.s!=uN(b.zoom)?(a.s=uN(b.zoom),JP(a,b,a.h),b=a.l,c=a.h,b[0]=c[0],b[1]=c[1],b=a.b,b[0]=0,b[1]=0):(JP(a,b,a.l),b=a.l,c=a.h,d=a.b,d[0]=b[0]-c[0],d[1]=b[1]-c[1]);KP(a)};function MP(a,b,c){this.bottom=a;this.top=b;this.zoom=c};function NP(a,b,c,d,e,f,g,h){var k=Math.floor(256*Yn(h.la,1,2))/256;this.h=new CN(k);xP.call(this,a,b,d,this,g,h,new gO(b,!0),f,c);this.b=e;this.Ra=new iL(k);this.La=new QH;this.Qa=new qJ;this.Sa=new yM(k,"arial,sans-serif");this.Da=new oK(this.h);this.Ia=new $K(this.Da);this.J=this.m=null;this.B=new tO;this.Pa=h.u;this.Ca=h.T;this.Oa=h.G;this.Ga=this.ra=this.va=this.pa=this.ja=null;this.H=!1;this.U=0;this.G=k;this.M={};this.j=!1;this.l=this.g=this.D=null;this.W={};this.ia=-1;this.K=!1;this.Y=!0; +this.Z=!1;this.ga=this.fa=-1;this.T=!1;this.A=1;this.S=h.Z;this.s=null;OP(this,h)}F(NP,xP);var PP=1/Math.pow(2,19);r=NP.prototype;r.wc=function(){this.canvas.c=(this.D||this.canvas).c;NP.R.wc.call(this)}; +function OP(a,b){function c(a,b){var c=a[3];return[c*a[0]+(1-c)*b[0],c*a[1]+(1-c)*b[1],c*a[2]+(1-c)*b[2],c+(1-c)*b[3]]}var d=a.Ba.oc;a.m=new eN(a,a.Sa,a.Da,a.G,d,b);a.J=new EP(a.m,a.gc.b);MA(d.b,function(){a.dd()},a);a.ja=new oJ(PH(aI),PH(bI),PH(cI),a.G);a.pa=new oJ(PH(c(aI,YH)),PH(c(bI,YH)),PH(c(cI,YH)),a.G);a.va=new oJ(PH(dI),PH(eI),PH(fI),a.G);a.ra=new oJ(PH(c(dI,XH)),PH(c(eI,XH)),PH(c(fI,XH)),a.G);a.Ga=new iI;QP(a.a,D(a.dd,a))}r.dd=function(a){a?(this.U=this.i,this.H=!1):this.H=!0;uo(this.gc)}; +r.getContext=function(){return this.b};r.Vd=function(){return this.i<this.I||AP(this)||this.c.a||this.i<=this.U||!this.B.b?!1:!0};function RP(a){var b=gI(a.a.i,a.a.c);a.M[b]||(a.M[b]=PH(hI(a.a.i,a.a.c)));return a.M[b]} +r.cd=function(a){var b=this.h,c=this.a.a,d=this.Xa();b.l=d;var e=AN(c);b.j=c;b.i=wN(c);b.a=zN(c);b.b=Math.log(e/256)/Math.LN2;b.c=e;b.f=2;0==c.o&&0==c.b&&0==c.v&&(1E-9>Math.abs(b.b-Math.round(b.b))?(b.f=0,b.b=Math.round(b.b)):(b.f=1,b.b=uN(b.b)),b.c=256*Math.pow(2,b.b),e=(.5-c.i/tN)*b.c-c.a/2,b.g=Math.round(((c.h/tN+.5)*b.c-c.c/2)*d)/d,b.h=Math.round(e*d)/d);this.K=1E-4<Math.abs(this.a.getZoom()-this.ia);a:if(b=SP(this),c=this.f.a,this.j){d=!this.B.b;if(!this.A){e=TP(this,c);var f=!!PO(this.f);if(e|| +f||d||!this.Y)this.A=3}e=this.Xa()!=this.fa;f=this.h;f=f.a.a-f.a.start+1;var g=UP(c),h=g||this.Z;if(0!=this.ga||this.K||b||e||1<f||h||this.T)this.A=1;if(this.A){--this.A;if(0==this.A){this.W=[];VP(this,c);this.ia=this.a.getZoom();this.fa=this.Xa();this.ga=0;this.Z=g;this.Y=!d;this.T=!1;b=!0;break a}this.H=!0}b=!1}else b=!0;try{this.b.setTransform(1,0,0,1,0,0)}catch(t){c=Error(),c.message="initContext_: Error accessing canvas.",nF(c)}if(b){b=this.f.a;bO(this.C,b,this.f.f,!this.a.h,this.i);JO(this.v); +this.j&&(c=this.l,d=RP(this),c.g=this.Xa(),d!=c.o&&(c.c.style.backgroundColor=d,c.o=d),LP(this.l,this.c));this.U=0;this.S||oF(this.b,!1);this.l&&this.b.clearRect(0,0,this.b.canvas.width,this.b.canvas.height);this.b.save();c=WP(this);d=pF(2,this.Xa());this.b.translate(-c.x*d,-c.y*d);c=this.f.b;this.b.save();this.b.scale(d,d);h=this.a;d=this.b;f=h.a;e=f.c;f=f.a;g=hI(h.i,h.c);var k=h.l,l=267.1960013541594/Math.PI;h=new WH(0,0);VN(k,-180,l,h);var m=new WH(0,0);VN(k,180,l,m);var n=new WH(0,0);VN(k,-180, +-l,n);var p=new WH(0,0);VN(k,180,-l,p);k=1>Math.abs(h.x-m.x);l=1>Math.abs(h.y-m.y);if(!k&&h.x>m.x||k&&h.x>n.x){var q=h;h=n;n=q;q=m;m=p;p=q}l?(jI(d,g,0,0,e,h.y),jI(d,g,0,n.y,e,f)):k?(jI(d,g,0,0,h.x,f),jI(d,g,n.x,0,e,f)):(kI(d,g,h,m,e,f,0),kI(d,g,n,p,e,f,f));this.b.restore();MO(this.v,c);for(d=0;d<c.length;++d)c[d].a.length&&(e=c[d].a[0],0<e.a.length&&XP(this,e.a,d));this.S||oF(this.b,!0);if(!this.c.a&&this.a.h){c=[];for(d=0;d<b.length;d++)e=b[d],YP(e),(UM(e.data)||this.m.Ub(e)||e.a.s)&&c.push(e);0< +c.length&&(b=this.C,aL(this.Ia,this.b,c,this.Xa(),WN(b.a),XN(b.a)))}this.b.restore();this.j&&(b=this.l,c=WP(this),b.f&&(c="translate("+(b.b[0]+c.x)+"px, "+(b.b[1]+c.y)+"px) scale(1)",b.f.style.transform=c,b.f.style.webkitTransform=c))}else LP(this.l,this.c);this.H&&this.dd(!0);a&&KO(this.v,a)};r.fb=function(a){return UM(a.data)?!0:this.m.Ub(a)};r.ic=function(a,b,c){return c&&TM(this.m,a)?$M():GP(this.J,a,b)};r.wd=function(){return this.J.b}; +function XP(a,b,c){for(var d=[],e=[],f=[],g=0;g<b.length;++g){var h=b[g];h.data||null===h.c?h.data&&(a.c.a?h.N.getZoom()==a.c.b&&(h=sO(h.N,-1),e.push(h)):(d.push(h),4!=h.N.Ea()&&f.push(h))):e.push(h)}b=gI(a.a.i,a.a.c);g=a.Pa&&a.Oa||a.Ca;if(2===b){var k=a.va;var l=a.ra}else 1===b&&(k=a.ja,l=a.pa);if(g&&k&&l)b=new MP(0,a.c.height,a.c.b),xO(a.B,f,e,b,a.c.a,a.Ca),!a.B.b&&a.dd(),ZP(a,f,e,k,l,!0),a.c.a||$P(a,d,c),ZP(a,f,e,k,l,!1);else{if(!g&&l)for(f=l,k=a.Xa(),l=MJ(),b=0;b<e.length;b++){g=e[b].N;h=a.h.a.a; +for(var m=a.h.a.start;m<=h;m++)DN(a.h,iC(g),jC(g),g.getZoom(),m,l)&&(a.b.save(),EN(a.h,a.b,l),pJ(f,a.b,k),a.b.restore())}a.c.a||$P(a,d,c)}} +function $P(a,b,c){if(b.length){b.sort(aQ||Za);var d=pF(2,a.Xa()),e=a.b,f=!1;if(0<c&&b[0].N.getZoom()!=a.c.b){f=!0;e=null;if(!a.s)e=go("canvas");else if(a.s.canvas.width<a.b.canvas.width||a.s.canvas.height<a.b.canvas.height)e=a.s.canvas;e&&(e.width=a.b.canvas.width,e.height=a.b.canvas.height,a.s=e.getContext("2d"),a.S||oF(a.s,!1));e=a.s;e.setTransform(1,0,0,1,0,0);e.clearRect(0,0,a.b.canvas.width,a.b.canvas.height);c=WP(a);e.translate(-c.x*d,-c.y*d)}c=MJ();for(var g=0;g<b.length;g++){var h=b[g],k= +h.data;if(!UM(k)){bQ(a.V,h);h.a.s||UM(h.data)||a.m.Ub(h)||4!=h.N.Ea()||GP(a.J,h,2);var l=h.a.f;if(h.a.Sa||l.i.length){h.a.Sa=!1;l=a.m;var m=h,n=m.a;n.rc=null;n.D&&(BM(n.D),n.D=null);n.Ia=null;oN(l,m);qN(l,m,!0)}l=a.h.a.a;for(m=a.h.a.start;m<=l;m++)if(DN(a.h,tK(k),uK(k),k.getZoom(),m,c)){e.save();var p=EN(a.h,e,c);f&&e.clearRect(0,0,256*d,256*d);if(h.a.s||4==h.N.Ea()){e.save();e.beginPath();e.rect(0,0,256*d,256*d);e.clip();e.scale(d,d);n=oN(a.m,h);p<PP&&(p=PP);var q=e,t=a.a.getZoom();kJ(n);lJ(n,q, +p,t,-1);e.restore()}else q=a,t=h,n=e,(p=t.a.Ia)?(q=pF(2,q.Xa()),n.drawImage(p,0,0,256*q,256*q)):(p=t.a.D)&&AM(p,n,q.Xa());e.restore()}}}f&&(a.b.save(),a.b.setTransform(1,0,0,1,0,0),a.b.drawImage(e.canvas,0,0,a.b.canvas.width,a.b.canvas.height,0,0,a.b.canvas.width,a.b.canvas.height),a.b.restore())}}function YP(a){a=a.a;if(a.j.length)for(var b=a.f.j,c=0;c<b.length;++c)for(var d=b[c],e=0;e<a.v.length;++e)for(var f=a.v[e].a,g=0;g<f.length;++g){var h=f[g];h.a==d&&h&&h.c&&h.c.i()}} +function ZP(a,b,c,d,e,f){if(c.length||b.length){b=a.B.a.a;c=a.B.a.zoom;for(var g=a.Xa(),h=MJ(),k=0;k<b.length;k++){var l=b[k];if(0<l.a&&l.c==f){a.b.globalAlpha=l.a;for(var m=a.h.a.a,n=a.h.a.start;n<=m;n++)DN(a.h,l.x,l.y,c,n,h)&&(a.b.save(),EN(a.h,a.b,h),l.c?pJ(e,a.b,g):pJ(d,a.b,g),a.b.restore())}}a.b.globalAlpha=1}}r.Je=function(){return!1};r.Xa=function(){return Math.floor(256*this.a.f)/256};r.vc=function(){NP.R.vc.call(this);this.c.f=this.Xa()};r.Td=function(){var a=this.C;ON(a.a,a.b)}; +function SP(a){var b=!1;if(a.j){var c=a.D.a,d=a.canvas.a,e=c.width/parseInt(c.style.width,10),f=function(a){return 256*(Math.floor(a/256)+2)};f=a.K?sr:f;a=f(parseInt(c.style.width,10));c=f(parseInt(c.style.height,10));if(d.style.width!=a+"px"||d.style.height!=c+"px")d.style.width=a+"px",d.style.height=c+"px";a=a*e|0;e=c*e|0;if(d.width!=a||d.height!=e)d.width=a,d.height=e,b=!0}return b} +r.X=function(){if(this.j){this.j=!1;this.l=null;var a=this.g;a&&a.parentNode&&a.parentNode.removeChild(a);this.g=null;this.canvas=this.D;a=this.canvas.a;this.b=a.getContext("2d");a.style.display=""}NP.R.X.call(this)};function TP(a,b){for(var c=0;c<b.length;c++){var d=!(!b[c].data||!a.fb(b[c])&&!b[c].a.s);if(!a.W[b[c].N.aa()]==d)return!0}return!1}function UP(a){for(var b=0;b<a.length;b++)if(a[b].a.s)return!0;return!1} +function VP(a,b){for(var c=0;c<b.length;c++){var d=b[c];a.W[d.N.aa()]=a.fb(d)||d.a.s}} +function WP(a){if(a.K||!a.j)return new WH(0,0);var b=WF(),c=a.a.l;if(c.b){c=c.a;var d=pP[1];eP(c,pP[0],d);var e=pP[2];lG(d,e);var f=WF(),g=WF();sG(e,f);var h=c.a/2,k=c.c/2,l=Math.tan(c.g/2);d=WF();d[0]=(0-k)/k*l*(k/h);d[1]=(0-h)/h*-l;d[2]=-1;mG(e,d,g);ZF(g,f,g);bG(g,g);e=new vN(f,g);kP(new hP,e.origin,e.a,d);mP.x=Math.atan2(d[1],d[0]);mP.y=Math.atan2(d[2],Math.sqrt(d[0]*d[0]+d[1]*d[1]));c=Math.atan2(c.j,c.l);mP.x<c-Math.PI&&(mP.x+=2*Math.PI);mP.x>c+Math.PI&&(mP.x-=2*Math.PI);tG(180*mP.x/Math.PI,180* +mP.y/Math.PI,0,b)}else xN(c.a,0,0,qP),c=-qP.origin[2]/qP.a[2],b[0]=qP.origin[0]+qP.a[0]*c,b[1]=qP.origin[1]+qP.a[1]*c,b[2]=0;c=WF();e=Math.ceil(a.c.zoom-1E-6);yG(b[0],b[1],b[2],e,c);b=new WH(0,0);a=a.a.l;zG(Math.floor(c[0]),Math.floor(c[1]),e,nP);tP(a,b);b.x|=0;b.y|=0;return b}function aQ(a,b){return a.N||b.N?a.N?b.N?a.N.getZoom()-b.N.getZoom():1:-1:0};function cQ(a){this.a=a}cQ.prototype.m=function(){var a=this.a,b=new BP;b.f=a.f;b.g=a.g;b.c=a.c;b.i=a.i;b.a=a.a;b.b=a.b;return b};function dQ(a,b,c,d,e){Pp.call(this);this.a=d;this.b=b;this.i=e}F(dQ,Pp);dQ.prototype.wc=function(){this.a.wc()};dQ.prototype.g=function(){return this.a};dQ.prototype.f=function(){return new cQ(new BP)};dQ.prototype.h=sa;function eQ(a,b,c,d,e,f,g){dQ.call(this,a,b,c,d,e,f,g);this.c=d}F(eQ,dQ);eQ.prototype.g=function(){return this.c};eQ.prototype.f=function(){return new cQ(this.c.wd())};eQ.prototype.X=function(){this.c.$();eQ.R.X.call(this)}; +eQ.prototype.h=function(){eQ.R.h.call(this);var a=this.c;a.j=!0;a.D=a.canvas;var b=a.D.a;b.style.display="none";a.canvas=new io;SP(a);var c=a.canvas.a;b.parentNode&&b.parentNode.insertBefore(c,b.nextSibling);a.b=c.getContext("2d");a.g=go("DIV");a.g.className="canvas-renderer";a.g.style.overflow="hidden";a.g.style.position="absolute";a.g.style.width=b.width+"px";a.g.style.height=b.height+"px";a.g.style.backgroundColor=RP(a);a.g.style.direction="ltr";a.g.style.webkitUserSelect="none";a.g.style.b="none"; +a.g.style.a="none";b.parentNode.insertBefore(a.g,b);c.style.backgroundColor="rgba(0,0,0,0)";c.style.position="absolute";c.style.zIndex=100;a.l=new IP(a.g,a.c);b=a.l;b.f=c;b.a.appendChild(b.f);a.T=!0};function rH(){this.D=MJ();this.J=MJ();this.M=MJ();this.K=MJ();this.u=WF();this.L=eG();this.P=WF();this.O=XF(WF(),1,1,1);this.C=gG();this.H=!0;this.m=this.i=this.h=0;this.s=1;this.v=this.b=this.o=this.f=this.l=this.j=0;this.g=.4363323129985824;this.B=1/3;this.A=Number.MAX_VALUE;this.G=this.a=this.c=1;this.I=[]} +function fQ(a,b){var c=!1,d=!1,e=!1,f=!1,g=!1;B(b.g)&&(b.g!=a.h&&(g=!0,a.h=b.g),c=!0);B(b.h)&&(b.h!=a.i&&(g=!0,a.i=b.h),c=!0);B(b.i)&&(b.i!=a.m&&(g=!0,a.m=b.i),c=!0);B(b.f)&&(b.f!=a.s&&(g=!0,a.s=b.f),d=!0);B(b.j)&&(b.j!=a.j&&(g=!0,a.j=b.j),e=!0);B(b.l)&&(b.l!=a.l&&(g=!0,a.l=b.l),e=!0);B(b.m)&&(b.m!=a.f&&(g=!0,a.f=b.m),e=!0);B(b.c)&&(b.c!=a.o&&(g=!0,a.o=b.c),f=!0);B(b.ta)&&(b.ta!=a.b&&(g=!0,a.b=b.ta),f=!0);B(b.b)&&(b.b!=a.v&&(g=!0,a.v=b.b),f=!0);B(b.a)&&b.a!=a.g&&(g=!0,a.g=b.a);B(b.s)&&b.s!=a.B&&(g= +!0,a.B=b.s);B(b.o)&&b.o!=a.A&&(g=!0,a.A=b.o);B(b.width)&&b.width!=a.c&&(g=!0,a.c=b.width);B(b.height)&&b.height!=a.a&&(g=!0,a.a=b.height);g&&(!f||c||e||(e=!0),!d&&e&&c&&(b=a.j-a.h,d=a.l-a.i,f=a.f-a.m,a.s=Math.sqrt(b*b+d*d+f*f)),e&&!c&&gQ(a),c&&!e&&hQ(a),a.H=!0,a.G++,iQ(a))}function jQ(a,b){b=b||new SF;b.g=a.h;b.h=a.i;b.i=a.m;b.f=a.s;b.j=a.j;b.l=a.l;b.m=a.f;b.c=a.o;b.ta=a.b;b.b=a.v;b.a=a.g;b.s=a.B;b.o=a.A;b.width=a.c;b.height=a.a;return b}function AH(a,b){a.I.push(b)} +function iQ(a){for(var b=0;b<a.I.length;b++)a.I[b]()}function uP(a){kQ(a);return a.D}function wP(a){var b=a.M,c=a.u,d=a.L;vP(a,a.P,c);vP(a,a.O,d);ZF(d,c,d);NJ(b,d[0],d[1],d[2],c[0],c[1],c[2]);return b} +function kQ(a){if(a.H){var b=a.D,c=a.c/a.a,d=a.B,e=a.A,f=a.g/2,g=e-d,h=Math.sin(f);0!=g&&0!=h&&0!=c&&(f=Math.cos(f)/h,b[0]=f/c,b[1]=0,b[2]=0,b[3]=0,b[4]=0,b[5]=f,b[6]=0,b[7]=0,b[8]=0,b[9]=0,b[10]=-(e+d)/g,b[11]=-1,b[12]=0,b[13]=0,b[14]=-(2*d*e)/g,b[15]=0);SJ(a.K,-a.v,-a.b,-a.o);PJ(a.D,a.K,a.D);e=1/a.s;b=a.D;c=e*(a.h-a.j);d=e*(a.i-a.l);e*=a.m-a.f;b[12]+=b[0]*c+b[4]*d+b[8]*e;b[13]+=b[1]*c+b[5]*d+b[9]*e;b[14]+=b[2]*c+b[6]*d+b[10]*e;b[15]+=b[3]*c+b[7]*d+b[11]*e;QJ(a.D,a.J);a.H=!1}} +function xN(a,b,c,d){d=d||new vN;var e=a.u,f=a.B,g=a.A;e[0]=b;e[1]=c;e[2]=g/(g-f);b=e||WF();c=e[1];var h=e[2];b[0]=2*e[0]/a.c-1;b[1]=2*-c/a.a+1;b[2]=2*h-1;e[2]=(g+f)/(g-f);f=a.C;kQ(a);iG(f,a.J);f=a.C;g=d.a;b=e[0];c=e[1];e=e[2];g[0]=b*f[0]+c*f[4]+e*f[8]+f[12];g[1]=b*f[1]+c*f[5]+e*f[9]+f[13];g[2]=b*f[2]+c*f[6]+e*f[10]+f[14];bG(d.a,d.a);XF(d.origin,a.j,a.l,a.f)}function vP(a,b,c){c=c||WF();var d=b[1],e=b[2];c[0]=.5*(b[0]+1)*a.c;c[1]=.5*(-d+1)*a.a;c[2]=.5*(e+1)} +function gQ(a){lQ(a,a.u);a.h=a.j+a.u[0];a.i=a.l+a.u[1];a.m=a.f+a.u[2]}function hQ(a){lQ(a,a.u);a.j=a.h-a.u[0];a.l=a.i-a.u[1];a.f=a.m-a.u[2]}function mQ(a,b,c){var d=1/Math.tan(a.g/2),e=a.a,f=B(c)?c:a.b;a=2/e*(B(c)?a.s*Math.cos(c)+a.m:a.f)*d;b=d*Math.cos(f)-(1-2*b/e)*Math.sin(f);return 0>b?Infinity:a/(b*b)}function yN(a){return(1-1/Math.tan(a.g/2)/Math.tan(a.b))*a.a/2} +function lQ(a,b){XF(b,0,0,-a.s);var c=a.C,d=a.o,e=a.b,f=a.v,g=Math.cos(d);d=Math.sin(d);var h=Math.cos(e);e=Math.sin(e);var k=Math.cos(f);f=Math.sin(f);c[0]=g*k-h*d*f;c[1]=h*g*f+k*d;c[2]=f*e;c[3]=0;c[4]=-g*f-k*h*d;c[5]=g*h*k-d*f;c[6]=k*e;c[7]=0;c[8]=e*d;c[9]=-g*e;c[10]=h;c[11]=0;c[12]=0;c[13]=0;c[14]=0;c[15]=1;a=a.C;c=b[0];g=b[1];f=b[2];b[0]=c*a[0]+g*a[4]+f*a[8];b[1]=c*a[1]+g*a[5]+f*a[9];b[2]=c*a[2]+g*a[6]+f*a[10]};function sH(a,b,c){this.a=a;this.l=new lP(a);new sN;this.b=new bP;this.f=1;this.D=new oq(0,0,0,0);this.H=0;this.A=[];this.i=[0];this.c=[0];this.B=new Os;this.v=this.u=0;this.m=this.o=this.h=!0;this.G=-1;this.j=new SF;this.I=c||null;this.C=0;this.J=b;this.g=!1;var d=this;AH(this.a,function(){tH(d)})}sH.prototype.s=function(){return this.H};function QP(a,b){a.A.push(b)}function tH(a){a.H++;for(var b=0;b<a.A.length;b++)a.A[b].call(null)}sH.prototype.ba=function(){return this.B}; +function vH(a,b){nQ(a);return cP(a.b,b)}function wH(a,b){dP(b);a.b=cP(b,a.b);b=a.b;var c=a.j;c.j=void 0;c.l=void 0;c.m=void 0;c.s=void 0;c.o=void 0;c.c=-ao(b.rotation);c.ta=ao(b.ta);c.b=0;c.a=ao(b.b);c.width=b.width;c.height=b.height;c.f=1/Math.tan(c.a/2)*c.height/2*(tN/256/Math.pow(2,b.zoom));tG(b.lng,b.lat,b.a,aP);c.g=aP[0];c.h=aP[1];c.i=aP[2];fQ(a.a,a.j)} +function nQ(a){if(a.G!=a.a.G){jQ(a.a,a.j);0!=a.j.b&&(a.j.b=0,fQ(a.a,a.j));var b=a.j,c=a.b;c.rotation=-(180*b.c/Math.PI);c.ta=180*b.ta/Math.PI;c.b=180*b.a/Math.PI;c.width=b.width;c.height=b.height;uG(b.g,b.h,b.i,aP);c.lng=aP[0];c.lat=aP[1];c.a=aP[2];c.zoom=Math.log(1/Math.tan(b.a/2)*(b.height/2)/b.f*tN/256)/Math.LN2;dP(a.b);a.I?(b=a.I,c=a.a,b=a.g?oQ(c):pQ(b.a,c,a.f)):b=a.b.zoom;1E-6<=Math.abs(b-a.C)&&(a.C=b);a.G=a.a.G}}function UN(a){nQ(a);return a.b.height}function TN(a){nQ(a);return a.b.width} +function PN(a){nQ(a);return a.b.lat}function QN(a){nQ(a);return a.b.lng}sH.prototype.getZoom=function(){nQ(this);return this.C};function RN(a){nQ(a);return a.b.rotation}function SN(a){nQ(a);return a.b.ta}sH.prototype.ud=function(){nQ(this);return this.b.a};function uH(a,b){a.g!=b&&a.J&&(a.g=b,a.l.b=b,tH(a))};function xH(a){this.b=a;this.a={}} +function bQ(a,b){var c=b.a.f,d=0,e=c.l;if(0!=e){for(var f=Object.keys(c.h),g=f.length-1;0<=g;--g){var h=f[g];if(!a.a[h]){var k=c,l=h,m=k.h[l];if(m){for(var n=0;n<m.length;++n)for(var p=m[n],q=k.g[p],t=0;t<q.length;++t)if(q[t].key==l)if(t==q.length-1)k.f[p]=!0,q.length=t;else{q.splice(t,1);break}delete k.h[l]}}}f=b.N.ba();for(h in a.a)if(h>e&&(d++,m=a.a[h],l=m.b.dg(b.data,f)))for(g=c,k=h,m=m.a,g.h[k]=l,n=0;n<l.length;++n)p=l[n],(q=g.g[p])?q.push({key:k,modifier:m}):g.g[p]=[{key:k,modifier:m}],g.f[p]= +!0}a=a.b;c.l=0;c.j.length=0;c.i.length=0;b=Object.keys(c.f);if(b.length){for(d=0;d<b.length;++d)h=parseInt(b[d],10),c.o[h]?c.j.push(h):c.i.push(h),(e=c.g[h])&&e.length?(f=a.G(c.a[h],c.s,e[e.length-1].modifier),e=c,f!=e.a[h]?(void 0===e.b[h]&&e.c++,e.b[h]=f):void 0!==e.b[h]&&(delete e.b[h],e.c--)):void 0!==c.b[h]&&(c.c--,delete c.b[h]);c.f={}}};function yH(a){this.b=a;this.a=a.b}yH.prototype.G=function(a,b,c){a=RA(PB(this.b,b),a);var d=c.apply(a);if($z(d))c=0;else{c=this.a;a=pr(c.h,"localStyle!"+ ++c.g);b=new zA;if(d){var e=b.style;e.c=d.c;e.D=d.D;e.l=d.l;e.s=d.s;e.j=d.j;e.C=d.C;e.m=d.m?Va(d.m):null;e.o=d.o;e.v=AA(d.v);e.A=AA(d.A);e.u=AA(d.u);e.f=d.f;e.a=d.a;e.g=d.g;e.h=d.h;e.i=d.i;e.b=new Uint8Array(840);d=d.b;e=e.b;for(var f=0;840>f;f++)e[f]=d[f]}b=b.style;a>c.b&&(c.b=a);c.f[a]=b;c.a&&c.a.call(c.c,a,b);c=a}return c};function qQ(a,b,c,d,e,f,g){this.c=a;this.a=b;this.b=c;this.priority=d;this.type=e;this.g=f;this.f=g;this.h=null}function rQ(a,b){return new qQ(b,a.a,a.b,a.priority,a.type,a.g,a.f)}qQ.prototype.mb=function(){if(!this.h){for(var a=this.c.length,b=Array(a),c=0;c<a;++c)b[c]=new dC(this.c[c],this.b,this.a);this.h=b}return this.h};function sQ(){this.c=B(void 0)?void 0:2;this.b=B(void 0)?void 0:3}sQ.prototype.a=function(a,b,c,d,e,f){for(var g=[],h=0;h<d.length;++h){for(var k=[],l=tQ(e,a,b,f).a,m=0;m<l.length;++m)k.push.apply(k,l[m].a);k.length&&g.push(new qQ(k,c,d[h],this.c,this.b,!1,!1))}return g};function uQ(){}uQ.prototype.Xc=function(a,b,c,d){return b.Xc(new sQ,c,d)};function vQ(){}F(vQ,uQ);vQ.prototype.a=function(a,b,c,d,e,f,g,h,k){b=new NP(d,e,h,f,b.b,c,k,a);c=this.Xc(a,f,b,d);return new eQ(d,e,f,b,c,g,a.b)};function wQ(){}wQ.prototype.a=function(){return new vQ};NG(4,new wQ);function xQ(){this.a=0;this.b=2;this.c=0;this.j=this.g=this.h=this.f=this.i=null}function yQ(a,b,c){a.f=b;a.h=c||null}xQ.prototype.cancel=function(){if(3==this.a)return!1;var a=!1;this.f&&(a=this.f.call(this.h))&&(this.a=3);return a};xQ.prototype.start=function(a){if(0!=this.a)throw Error("Trying to reuse an Rpc object. Status is not INACTIVE");this.a=1;this.i=a};xQ.prototype.done=function(){};function zQ(a,b){if(0==b)throw Error("Trying to set the Rpc status to INACTIVE.");a.a=b} +function AQ(a,b){a.b=b;a.g&&a.g.call(a.j)}function BQ(a){var b=new xQ;b.b=a.b;return b};function CQ(a,b){this.b=a;this.c=b}CQ.prototype.a=function(a,b,c,d){d=d||new xQ;a=new DQ(a,b,c?c:null,d,this.b,this.c);DG(this.b,a,d.b)};function DQ(a,b,c,d,e,f){this.s=a;this.l=b;this.o=c;this.c=d;this.f=!1;this.a=null;this.g=e;this.m=f;this.h=!1;this.b=null;yQ(this.c,this.i,this);a=this.c;a.g=this.j;a.j=this||null} +DQ.prototype.start=function(a){this.a=BQ(this.c);this.a.start(this.c.i+".RequestSchedulerChannel");zQ(this.a,1);var b=this;this.m.a(this.s,function(a){b.h=!0;b.l(a);++b.c.c},function(){var c=b.o;b.a.done();zQ(b.c,b.a.a);c&&c();a()},this.a)};DQ.prototype.cancel=function(){return!this.a||this.h&&!this.f?!1:this.a.cancel()};DQ.prototype.i=function(){this.f=!0;return EG(this.g,this)};DQ.prototype.j=function(){DG(this.g,this,this.c.b)};function EQ(a){a=(new mB(a)).toString();this.b=a+=-1==a.indexOf("?")?"?":"&"}EQ.prototype.a=function(a){if(0==a.length)return this.b.slice(0,this.b.length-1);if("?"==a[0]||"&"==a[0])a=a.slice(1);return this.b+a};function FQ(a,b){this.f=pa(a)||a instanceof mB?new EQ(a):a;this.c=b;this.b=!1}function GQ(a,b,c,d){function e(a){nc(c);3!=d.a&&a&&b()}dc(c,"success",function(){e(!0)});dc(c,"abort",function(){e(!1)});dc(c,"error",function(){zQ(d,2);e(!0)});dc(c,"timeout",function(){zQ(d,2);e(!0)});dc(c,"readystatechange",function(){var b=c.$c();AD(c)&&4==yD(c)&&a(b)})} +FQ.prototype.a=function(a,b,c,d){d=d||new xQ;c=c||sa;var e=new mD;e.l=this.b;B(this.c)&&(e.f=this.c);yQ(d,function(){e.abort();return!0});GQ(b,c,e,d);a=this.f.a(a);rD(e,a)};var HQ=[];function IQ(a,b,c){this.b=a;this.f=b;this.g=c;this.a={};this.c={};for(a=0;a<HQ.length;++a)JQ(this,HQ[a].$f,HQ[a].result)}function JQ(a,b,c){"success"==c.getState()?KQ(a,b,c.na()):(a.a[b]=c,c.wait(function(){KQ(a,b,c.na());delete a.a[b]}))}function LQ(a){var b=new Sn;b.data[0]=68;var c=new Un(De(b,1));c.data[0]="set";c.data[1]=a;return new Js([b])} +function KQ(a,b,c){var d=PB(a.g,LQ(b)),e=new Mu;c=gd(c);yv(e,c);hd(c);d.a=e;if(null!=d.a.b)for(e=d.a.b,c=0;c<e.length;++c)d.g[e[c].wa()]=c;e=d.i;c=d.a;if(!e.c){if(null!=c.c||null!=c.j){Iv(c);c=c.c;for(var f=0;f<c.length;f++){var g=c[f],h=null==g.a?0:g.a;g=0>h;h=Math.abs(h);var k=h>>>0;h=Math.floor((h-k)/4294967296);h>>>=0;g&&(h=~h>>>0,k=(~k>>>0)+1,4294967295<k&&(k=0,h++,4294967295<h&&(h=0)));Ic=k;Jc=h;g=Lc(Ic,Jc);e.a.push(g);k=c[f];e.b[null==k.b?0:k.b]=g}}e.c=!0}TA(d,d.i.a);a.c[b]=!0} +function MQ(a,b,c){if(a.c[b])return $M();var d=a.a[b];if(d)return d;var e=new FM;a.a[b]=e;var f=MF(a.b,b);d=new xQ;AQ(d,c);c=NQ(a.f,f,a.b.M);var g=a.b.o();c.a("",D(function(a){g();KQ(this,b,a);HM(e,!0);delete this.a[b]},a),void 0,d);return e}function NQ(a,b,c){b=new FQ(b,"arraybuffer");b.b=c;return new CQ(a,b)};function OQ(){this.b=[];this.f=[];this.c=[];this.a=[[],[],[],[],[],[],[]]}function PQ(a){return a.b.length+a.c.length}function QQ(a,b){b=a.b[b];return a.a[b.a].indexOf(b)}OQ.prototype.G=function(a){return a<this.b.length?this.b[a].s:this.f[a-this.b.length]};function RQ(a,b,c,d,e,f,g,h){b=new ZN(b,c,e,a.b.length,f,g,h);a.b.push(b);return a.a[c][d]=b}function SQ(a,b,c){a.c.push(b);a.f.push(c);return PQ(a)-1};var TQ=null; +function UQ(a,b,c){var d=new Uint32Array(b*c);TQ||(TQ=new Uint32Array(4));var e=TQ,f=b/4;c/=4;for(var g=0;g<c;g++)for(var h=0;h<f;h++){var k=0+4*(g*f+h),l=a[k],m=l>>11,n=l>>5&63,p=l&31;m=m<<3|m>>2;n=n<<2|n>>4;p=p<<3|p>>2;e[0]=m|n<<8|p<<16|-16777216;var q=a[k+1],t=q>>11,v=q>>5&63,u=q&31;t=t<<3|t>>2;v=v<<2|v>>4;u=u<<3|u>>2;e[1]=t|v<<8|u<<16|-16777216;l<=q?(e[2]=m+t>>1|n+v>>1<<8|p+u>>1<<16|-16777216,e[3]=0):(e[2]=5*m+3*t>>3|5*n+3*v>>3<<8|5*p+3*u>>3<<16|-16777216,e[3]=3*m+5*t>>3|3*n+5*v>>3<<8|3*p+5*u>> +3<<16|-16777216);l=a[k+2];m=4*g*b+4*h;d[m+0]=e[l&3];d[m+1]=e[l>>2&3];d[m+2]=e[l>>4&3];d[m+3]=e[l>>6&3];m+=b;d[m+0]=e[l>>8&3];d[m+1]=e[l>>10&3];d[m+2]=e[l>>12&3];d[m+3]=e[l>>14];l=a[k+3];m+=b;d[m+0]=e[l&3];d[m+1]=e[l>>2&3];d[m+2]=e[l>>4&3];d[m+3]=e[l>>6&3];m+=b;d[m+0]=e[l>>8&3];d[m+1]=e[l>>10&3];d[m+2]=e[l>>12&3];d[m+3]=e[l>>14]}return d};function VQ(a,b,c,d){this.data=a;this.width=b;this.height=c;this.format=d||1};function WQ(){}function XQ(a,b){if(b.Db())if(b=b.Yb(),1==b.format){var c=b.width,d=b.height;b=b.data;Uo(jq(a,3553),b,c,d,6408,5121,0)}else 4==b.format?(c=b.width,d=b.height,b=b.data,Uo(jq(a,3553),b,c,d,6406,5121,0)):2==b.format?a.compressedTexImage2D(3553,0,33776,b.width,b.height,0,b.data):3==b.format&&a.compressedTexImage2D(3553,0,33779,b.width,b.height,0,b.data);else b.bc()&&(b=b.Ab(),Qo(jq(a,3553),b,6408,5121,0))};function YQ(a,b){b=B(b)?b:0;var c=B(void 0)?void 0:a.byteLength-b;this.a=new Uint8Array(a,b,c);new Int8Array(a,b,c)}function ZQ(a,b){return a.a[b]+(a.a[b+1]<<8)+(a.a[b+2]<<16)+16777216*a.a[b+3]};function $Q(){this.g=!1;this.b=this.a=null;this.f=!1;this.c=null;var a=x.URL;a&&a.createObjectURL&&a.revokeObjectURL?(this.a=D(a.createObjectURL,a),this.b=D(a.revokeObjectURL,a)):(a=x.webkitURL)&&a.createObjectURL&&a.revokeObjectURL&&(this.a=D(a.createObjectURL,a),this.b=D(a.revokeObjectURL,a));if(this.a&&this.b){try{100==(new x.Blob([new Uint8Array(100)])).size&&(this.g=!0)}catch(b){}this.g||(this.f=!0,x.ArrayBuffer&&x.ArrayBuffer.prototype.slice?x.BlobBuilder?this.c=x.BlobBuilder:x.WebKitBlobBuilder? +this.c=x.WebKitBlobBuilder:x.a?this.c=x.a:this.f=!1:this.f=!1)}}function aR(a){var b=2*(a[0]<<23)+(a[1]<<16)+(a[2]<<8)+a[3];switch(b){case 2303741511:var c="image/png";break;case 4292411360:c="image/jpeg";break;case 1195984440:c="image/gif";break;case 1145328416:c="image/x-dds";break;case 1380533830:c="image/unknown";12<a.length&&(b=2*(a[8]<<23)+(a[9]<<16)+(a[10]<<8)+a[11],1464156752==b&&(c="image/webp"));break;default:c="image/unknown"}return c};/* + + Copyright 2012 Mozilla Foundation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +function bR(){this.b=this.i=0;this.h=!1;this.buffer=null}function cR(a,b){var c=a.buffer,d=c?c.byteLength:0;if(b<d)return c;for(var e=512;e<b;)e<<=1;b=new Uint8Array(e);if(c)for(e=0;e<d;++e)b[e]=c[e];return a.buffer=b}function dR(a){for(var b,c=a.i;!a.h;)eR(a);b=a.b;b||(a.buffer=new Uint8Array(0));a.i=b;return a.buffer.subarray(c,b)}bR.prototype.reset=function(){this.i=0};function fR(a){this.g=null;this.c=this.f=this.a=0;a&&gR(this,a);bR.call(this)}F(fR,bR); +function gR(a,b){var c=0;c++;c++;a.g=b;a.a=c;a.f=0;a.c=0;a.i=0;a.b=0;a.h=!1}function hR(a,b){this.a=a;this.b=b} +var iR=new Uint32Array([16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]),jR=new Uint8Array(iR.length),kR=new Uint8Array(320),lR=new Uint32Array(512),mR=new Uint32Array(512),nR=new Uint32Array(512),oR=new Uint32Array([3,4,5,6,7,8,9,10,65547,65549,65551,65553,131091,131095,131099,131103,196643,196651,196659,196667,262211,262227,262243,262259,327811,327843,327875,327907,258,258,258]),pR=new Uint32Array([1,2,3,4,65541,65543,131081,131085,196625,196633,262177,262193,327745,327777,393345,393409,459009, +459137,524801,525057,590849,591361,657409,658433,724993,727041,794625,798721,868353,876545]),qR=new hR(new Uint32Array([459008,524368,524304,524568,459024,524400,524336,590016,459016,524384,524320,589984,524288,524416,524352,590048,459012,524376,524312,589968,459028,524408,524344,590032,459020,524392,524328,59E4,524296,524424,524360,590064,459010,524372,524308,524572,459026,524404,524340,590024,459018,524388,524324,589992,524292,524420,524356,590056,459014,524380,524316,589976,459030,524412,524348, +590040,459022,524396,524332,590008,524300,524428,524364,590072,459009,524370,524306,524570,459025,524402,524338,590020,459017,524386,524322,589988,524290,524418,524354,590052,459013,524378,524314,589972,459029,524410,524346,590036,459021,524394,524330,590004,524298,524426,524362,590068,459011,524374,524310,524574,459027,524406,524342,590028,459019,524390,524326,589996,524294,524422,524358,590060,459015,524382,524318,589980,459031,524414,524350,590044,459023,524398,524334,590012,524302,524430,524366, +590076,459008,524369,524305,524569,459024,524401,524337,590018,459016,524385,524321,589986,524289,524417,524353,590050,459012,524377,524313,589970,459028,524409,524345,590034,459020,524393,524329,590002,524297,524425,524361,590066,459010,524373,524309,524573,459026,524405,524341,590026,459018,524389,524325,589994,524293,524421,524357,590058,459014,524381,524317,589978,459030,524413,524349,590042,459022,524397,524333,590010,524301,524429,524365,590074,459009,524371,524307,524571,459025,524403,524339, +590022,459017,524387,524323,589990,524291,524419,524355,590054,459013,524379,524315,589974,459029,524411,524347,590038,459021,524395,524331,590006,524299,524427,524363,590070,459011,524375,524311,524575,459027,524407,524343,590030,459019,524391,524327,589998,524295,524423,524359,590062,459015,524383,524319,589982,459031,524415,524351,590046,459023,524399,524335,590014,524303,524431,524367,590078,459008,524368,524304,524568,459024,524400,524336,590017,459016,524384,524320,589985,524288,524416,524352, +590049,459012,524376,524312,589969,459028,524408,524344,590033,459020,524392,524328,590001,524296,524424,524360,590065,459010,524372,524308,524572,459026,524404,524340,590025,459018,524388,524324,589993,524292,524420,524356,590057,459014,524380,524316,589977,459030,524412,524348,590041,459022,524396,524332,590009,524300,524428,524364,590073,459009,524370,524306,524570,459025,524402,524338,590021,459017,524386,524322,589989,524290,524418,524354,590053,459013,524378,524314,589973,459029,524410,524346, +590037,459021,524394,524330,590005,524298,524426,524362,590069,459011,524374,524310,524574,459027,524406,524342,590029,459019,524390,524326,589997,524294,524422,524358,590061,459015,524382,524318,589981,459031,524414,524350,590045,459023,524398,524334,590013,524302,524430,524366,590077,459008,524369,524305,524569,459024,524401,524337,590019,459016,524385,524321,589987,524289,524417,524353,590051,459012,524377,524313,589971,459028,524409,524345,590035,459020,524393,524329,590003,524297,524425,524361, +590067,459010,524373,524309,524573,459026,524405,524341,590027,459018,524389,524325,589995,524293,524421,524357,590059,459014,524381,524317,589979,459030,524413,524349,590043,459022,524397,524333,590011,524301,524429,524365,590075,459009,524371,524307,524571,459025,524403,524339,590023,459017,524387,524323,589991,524291,524419,524355,590055,459013,524379,524315,589975,459029,524411,524347,590039,459021,524395,524331,590007,524299,524427,524363,590071,459011,524375,524311,524575,459027,524407,524343, +590031,459019,524391,524327,589999,524295,524423,524359,590063,459015,524383,524319,589983,459031,524415,524351,590047,459023,524399,524335,590015,524303,524431,524367,590079]),9),rR=new hR(new Uint32Array([327680,327696,327688,327704,327684,327700,327692,327708,327682,327698,327690,327706,327686,327702,327694,0,327681,327697,327689,327705,327685,327701,327693,327709,327683,327699,327691,327707,327687,327703,327695,0]),5); +function sR(a,b){for(var c=a.f,d=a.c,e=a.g,f=a.a,g;c<b;)g=e[f++],d|=g<<c,c+=8;a.c=d>>b;a.f=c-b;a.a=f;return d&(1<<b)-1}function tR(a,b){var c=b.a,d=b.b;b=a.f;for(var e=a.c,f=a.g,g=a.a;b<d;){var h=f[g++];e|=h<<b;b+=8}c=c[e&(1<<d)-1];d=c>>16;a.c=e>>d;a.f=b-d;a.a=g;return c&65535} +function uR(a,b,c,d){for(var e=0,f=b;f<c;++f)a[f]>e&&(e=a[f]);var g=1<<e;d=g<=d.length?d:new Uint32Array(g);for(var h=1,k=0,l=2;h<=e;++h,k<<=1,l<<=1)for(var m=b;m<c;++m)if(a[m]==h){var n=0,p=k;for(f=0;f<h;++f)n=n<<1|p&1,p>>=1;for(f=n;f<g;f+=l)d[f]=h<<16|m-b;++k}return new hR(d,e)} +function eR(a){var b=sR(a,3);b&1&&(a.h=!0);b>>=1;if(0==b){b=a.g;var c=a.a,d,e=d=b[c++];d=b[c++];e|=d<<8;c++;c++;a.c=0;a.f=0;d=a.b;var f=cR(a,d+e);e=d+e;a.b=e;for(var g=d;g<e;++g){if("undefined"==typeof(d=b[c++])){a.h=!0;break}f[g]=d}a.a=c}else{c=qR;d=rR;if(1!=b&&2==b){f=sR(a,5)+257;e=sR(a,5)+1;b=sR(a,4)+4;for(c=0;c<jR.length;++c)jR[c]=0;for(c=0;c<b;++c)jR[iR[c]]=sR(a,3);d=uR(jR,0,jR.length,lR);c=b=0;for(e=f+e;c<e;){g=tR(a,d);if(16==g){var h=2,k=3;g=b}else if(17==g)k=h=3,g=b=0;else if(18==g)h=7,k= +11,g=b=0;else{kR[c++]=b=g;continue}for(h=sR(a,h)+k;0<h--;)kR[c++]=g}c=uR(kR,0,f,mR);d=uR(kR,f,e,nR)}e=(f=a.buffer)?f.length:0;for(g=a.b;;)if(h=tR(a,c),256>h)g+1>=e&&(f=cR(a,g+1),e=f.length),f[g++]=h;else{if(256==h){a.b=g;break}h-=257;h=oR[h];k=h>>16;0<k&&(k=sR(a,k));b=(h&65535)+k;h=tR(a,d);h=pR[h];k=h>>16;0<k&&(k=sR(a,k));h=(h&65535)+k;g+b>=e&&(f=cR(a,g+b),e=f.length);for(k=0;k<b;++k,++g)f[g]=f[g-h]}}};/* + + MIT LICENSE + Copyright (c) 2011 Devon Govett + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +function vR(){this.v=new fR;this.data=new Uint8Array(0);this.a=8;this.g=[];this.o=null;this.b={};this.h=null;this.text={};this.j=this.s=0;this.m=null;this.c=this.l=this.f=this.height=this.width=0;this.i=!1;this.u=0} +function wR(a){for(var b=null;;){var c=xR(a),d=a,e=String.fromCharCode(d.data[d.a++]);e+=String.fromCharCode(d.data[d.a++]);e+=String.fromCharCode(d.data[d.a++]);e+=String.fromCharCode(d.data[d.a++]);switch(e){case "IHDR":c=a;c.width=xR(c);c.height=xR(c);c.l=c.data[c.a++];c.c=c.data[c.a++];c.a++;c.a++;c.a++;break;case "acTL":c=a;c.h={hg:xR(c),ig:xR(c)||Infinity,frames:[]};break;case "PLTE":d=a;d.s=d.a;d.j=c;d.a+=c;break;case "fcTL":b&&a.h.frames.push(b);b=a;b.a+=4;c={width:xR(b),height:xR(b),mg:xR(b), +ng:xR(b)};d=yR(b);e=yR(b)||100;c.bg=1E3*d/e;c.cg=b.data[b.a++];c.Yf=b.data[b.a++];c.ag=[];b=c;break;case "fdAT":a.a+=4,c-=4;case "IDAT":d=a;if(b){e=b.data;for(var f=0;f<c;f++)e.push(d.data[d.a++])}else d.g.push(d.a),d.g.push(c),d.a+=c;break;case "tRNS":d=a;d.b={};switch(d.c){case 3:e=c;255>e&&(e=255);d.b.yd=Array(e);for(f=0;f<c;f++)d.b.yd[f]=d.data[d.a++];for(f=c;f<e;f++)d.b.yd[f]=255;break;case 0:d.b.gg=zR(d,c)[0];break;case 2:d.b.kg=zR(d,c)}break;case "tEXt":d=a;c=zR(d,c);e=c.indexOf(0);f=String.fromCharCode.apply(String, +c.slice(0,e));d.text[f]=String.fromCharCode.apply(String,c.slice(e+1));break;case "IEND":b&&a.h.frames.push(b);b=void 0;switch(a.c){case 0:case 3:case 4:a.f=1;break;case 2:case 6:a.f=3}a.i=4===(b=a.c)||6===b;a.u=a.l*(a.f+(a.i?1:0));b=a.g;if(2==b.length)d=new Uint8Array(a.data.buffer.slice(a.data.byteOffset+b[0],a.data.byteOffset+b[0]+b[1]));else{d=0;for(c=1;c<b.length;c+=2)d+=b[c];d=new Uint8Array(d);e=0;f=a.data;for(c=0;c<b.length;c+=2)for(var g=b[c],h=b[c+1],k=0;k<h;k++)d[e++]=f[g+k]}a.o=d;a.g= +[];return;default:a.a+=c}a.a+=4;if(a.a>a.data.length)throw Error("Incomplete or corrupt PNG file");}}function zR(a,b){for(var c=Array(b),d=0;d<b;d++)c[d]=a.data[a.a++];return c}function xR(a){var b=a.data[a.a++]<<24;var c=a.data[a.a++]<<16;var d=a.data[a.a++]<<8;a=a.data[a.a++];return b|c|d|a}function yR(a){var b=a.data[a.a++]<<8;a=a.data[a.a++];return b|a} +function AR(a){var b=null,c,d,e,f,g,h,k,l,m,n;null==b&&(b=a.o);if(0===b.length)return new Uint8Array(0);gR(a.v,b);var p=a.v;p=dR(p);b=a.u/8;var q=b*a.width;var t=new Uint8Array(q*a.height);var v=p.length;for(c=e=f=0;e<v;){switch(p[e++]){case 0:for(h=0;h<q;h+=1)t[c++]=p[e++];break;case 1:for(d=k=0;k<q;d=k+=1){a=p[e++];var u=d<b?0:t[c-b];t[c++]=(a+u)%256}break;case 2:for(d=l=0;l<q;d=l+=1){a=p[e++];var w=(d-d%b)/b;var y=f&&t[(f-1)*q+w*b+d%b];t[c++]=(y+a)%256}break;case 3:for(d=m=0;m<q;d=m+=1)a=p[e++], +w=(d-d%b)/b,u=d<b?0:t[c-b],y=f&&t[(f-1)*q+w*b+d%b],t[c++]=(a+Math.floor((u+y)/2))%256;break;case 4:for(d=n=0;n<q;d=n+=1){a=p[e++];w=(d-d%b)/b;u=d<b?0:t[c-b];0===f?y=g=0:(y=t[(f-1)*q+w*b+d%b],g=w&&t[(f-1)*q+(w-1)*b+d%b]);var A=u+y-g;w=Math.abs(A-u);d=Math.abs(A-y);A=Math.abs(A-g);u=w<=d&&w<=A?u:d<=A?y:g;t[c++]=(a+u)%256}break;default:throw Error("Invalid filter algorithm: "+p[e-1]);}f++}return t} +function BR(a){var b=a.s,c=a.data,d=a.b.yd||null;a=a.j;for(var e=new Uint8Array(a/3*4),f=0,g=0,h=0;h<a;h+=3)e[f++]=c[b+h],e[f++]=c[b+h+1],e[f++]=c[b+h+2],e[f++]=d?d[g++]:255;return e} +function CR(a,b,c){var d=a.f;var e=null;var f=a.i;a.j&&(e=a.m=a.m||BR(a),d=4,f=!0);a=b.length;if(1===d)if(e)if(f)for(f=d=0;d<a;d+=4,f++){var g=4*c[f];var h=e[g];b[d]=h;b[d+1]=h;b[d+2]=h;b[d+3]=e[g+1]}else for(f=d=0;d<a;d+=4,f++)g=4*c[f],h=e[g],b[d]=h,b[d+1]=h,b[d+2]=h,b[d+3]=255;else if(f)for(f=d=0;d<a;d+=4,f+=2)h=c[f],b[d]=h,b[d+1]=h,b[d+2]=h,b[d+3]=c[f+1];else for(f=d=0;d<a;d+=4,f++)h=c[f],b[d]=h,b[d+1]=h,b[d+2]=h,b[d+3]=255;else if(e)if(f)for(f=d=0;d<a;d+=4,f++)g=4*c[f],b[d]=e[g],b[d+1]=e[g+1], +b[d+2]=e[g+2],b[d+3]=e[g+3];else for(f=d=0;d<a;d+=4,f++)g=4*c[f],b[d]=e[g],b[d+1]=e[g+1],b[d+2]=e[g+2],b[d+3]=255;else if(f)for(d=0;d<a;d+=4)b[d]=c[d],b[d+1]=c[d+1],b[d+2]=c[d+2],b[d+3]=c[d+3];else for(f=d=0;d<a;d+=4,f+=3)b[d]=c[f],b[d+1]=c[f+1],b[d+2]=c[f+2],b[d+3]=255};var DR=null;function ER(a,b){if(!a.Db()){var c=a.b,d=new YQ(c.buffer,c.byteOffset+4),e=ZQ(d,0)+4;var f=ZQ(d,8);var g=ZQ(d,12),h=ZQ(d,76);d=ZQ(d,80);h&4&&(827611204==d||894720068==d)?b?(b=new Uint16Array(c.buffer,c.byteOffset+e,c.byteLength-e>>1),b=UQ(b,g,f),f=new VQ(new Uint8Array(b.buffer),g,f,1)):(b=new Uint8Array(c.buffer,c.byteOffset+e,c.byteLength-e),f=new VQ(b,g,f,827611204==d?2:3)):f=null;a.a=f;a.b=null;a.c=null;a.ld()}} +function FR(a,b){this.b=a;this.g=!0;this.c=b;this.mimeType=aR(a);this.f=this.bb=this.a=null}F(FR,WQ);r=FR.prototype;r.Ab=function(){return this.bb};r.Yb=function(){return this.a};r.Yd=function(){return this.a?this.a.width:this.bb?this.bb.width:0};r.Xd=function(){return this.a?this.a.height:this.bb?this.bb.height:0};r.Db=function(){return!!this.a};r.bc=function(){return!(!this.bb||!this.bb.complete)};r.Qb=function(){return this.g}; +r.Ib=function(a){if(this.g&&this.c){this.g=!1;var b=this.c,c=this.mimeType;if(!this.Db()&&!this.bc())if(1==a&&"image/x-dds"==c)ER(this,!1);else if(2==a&&"image/x-dds"==c)ER(this,!0);else if(2==a&&"image/png"==c)this.Db()||(DR||(DR=new vR),b=DR,b.data=this.b,b.a=8,b.g=[],b.o=null,b.b={},b.h=null,b.text={},b.s=0,b.j=0,b.m=null,b.width=0,b.height=0,b.f=0,b.l=0,b.c=0,b.i=!1,b.u=0,wR(b),a=new Uint8Array(b.width*b.height*4),CR(b,a,AR(b)),b=b.height,a=new VQ(a,a.length/b/4,b),this.c=this.b=null,this.a=a, +this.ld());else if(!this.Ab()){a=b.a;c=this.b;var d=null;b=aR(c);if(a.g)d=new x.Blob([c],{type:b});else if(a.f){var e=new a.c;d=c.buffer;if(0!=c.byteOffset||c.byteLength!=c.buffer.byteLength)d=c.buffer.slice(c.byteOffset,c.byteOffset+c.byteLength);e.append(d);d=e.getBlob(b)}e=go("IMG");d&&a.a&&a.b?(b=a.a(d),ec(e,"load",D(a.b,a,b))):(a=Dc(c),b="data:"+b+";base64,"+a);e.src=b;this.c=this.b=null;this.bb=e;e.complete?this.ld():this.f&&ec(e,"load",D(this.ld,this))}}}; +r.sd=function(a){var b=this.mimeType;return 1==a?"image/x-dds"==b:2==a?"image/x-dds"==b||"image/png"==b:3==a?"image/x-dds"!=b:!1};r.ld=function(){this.f&&(this.f(this),this.f=null)};function GR(){this.b=null;this.a=[]}var HR=new function(){this.a=new $Q};function eJ(a,b,c){if(B(a.a[c]))return a.a[c];b=Ly(b).Aa[c].getImageData();b=new FR(b,HR);return a.a[c]=b};function IR(a,b,c,d){this.a=a;this.o=b;this.s=c;this.m=d;this.b={};this.c=0;this.g={};this.h={};this.f={};this.j=[];this.i=[];this.l=0}function GK(a,b){var c=a.b[b];void 0===c&&(c=a.a[b]);return c}function SH(a,b){return RA(a.m,GK(a,b))}function CK(a,b){return RA(a.m,a.a[b])}function JR(a){for(var b=Object.keys(a.b),c=Array(b.length),d=0;d<b.length;d++)c[d]=a.b[parseInt(b[d],10)];return c};function KR(a,b,c){this.a=a;this.b=b;this.g=c;this.f=this.c=-1}function LR(a,b){return a.a!=b.a?a.a-b.a:a.b!=b.b?a.b-b.b:a.g-b.g}function MR(a,b,c){for(var d=0;d<a.length;){for(var e=a[d].a,f=a[d].b,g=d+1;g<a.length;g++){var h=a[g];if(h.a!=e||h.b!=f)break}for(e=d;e<g;e++)0>a[e].f?a[e].f=b:b=a[e].f,b+=c;for(e=d;e<g;e++)0>a[e].c?a[e].c=b:b=a[e].c,b+=c;d=g}};function NR(){this.c=!1;this.b=[];this.a=[]}function OR(a,b){a.c||(a.a.sort(LR),a.c=!0);for(var c=0;c<a.a.length;c++)a.a[c].f=-1,a.a[c].c=-1;if(b){b=b.a;a=a.a;c=Array(b.length+a.length);for(var d=0,e=0;;){var f=b[d],g=a[e];if(!f)break;if(!g)break;0<LR(f,g)?(c[d+e]=g,e++):(c[d+e]=f,d++)}for(;d<b.length;)c[d+e]=b[d],d++;for(;e<a.length;)c[d+e]=a[e],e++;MR(c,1,1)}else MR(a.a,10,10)};function PR(a){this.data=a||[]}F(PR,W);function fM(a){this.data=a||[]}F(fM,W);function QR(a){this.data=a||[]}F(QR,W);function RR(a,b,c,d){Pp.call(this);this.a=a;this.l=b;this.b=new OQ;this.m=[];this.o=[];this.i=[];this.u={};this.f=this.s=null;this.g=!1;this.h=null;this.j=c||new GR;this.v=d||null;this.B=SR++;this.A=null;this.c=16;this.c=AI(this.a);TR(this);UR(this)}F(RR,Pp);var SR=0; +RR.prototype.X=function(){var a=this.a;if(a){var b=a.c;b&&(b.c=null,b.a=null,b.b=null,b.f=null);a.c=null;if(b=a.u)b.b=null,b.a=null;a.u=null;if(a.b)for(b=0;b<a.b.length;b++){var c=a.b[b];if(c){c.f=null;if(c.a)for(var d=0;d<c.a.length;d++)fv(c.a[d]);c.a=null;c.g=null;c.j=null;c.h=null;c.c=null;if(c.b)for(d=0;d<c.b.length;d++)ev(c.b[d]);c.b=null;c.i=null}}a.b=null;if(b=a.h){b.b=null;b.c=null;b.f=null;if(b.a)for(c=0;c<b.a.length;c++)Tx(b.a[c]);b.a=null}a.h=null;if(a.f)for(b=0;b<a.f.length;b++)if(c=a.f[b])c.g= +null,c.b=null,c.a=null,c.h=null,c.f=null,c.c=null;a.f=null;a.C=null;if(b=a.o){if(b.a)for(c=0;c<b.a.length;c++)Qw(b.a[c]);b.a=null;cy(b.b);b.b=null}a.o=null;if(b=a.j){if(b.a)for(c=0;c<b.a.length;c++)sx(b.a[c]);b.a=null;cy(b.b);b.b=null}a.j=null;if(b=a.i){if(b.a)for(c=0;c<b.a.length;c++)Hx(b.a[c]);b.a=null;cy(b.b);b.b=null}a.i=null;if(b=a.l){if(b.a)for(c=0;c<b.a.length;c++)Au(b.a[c]);b.a=null;cy(b.b);b.b=null}a.l=null;if(b=a.a){if(b.Aa)for(c=0;c<b.Aa.length;c++)Mx(b.Aa[c]);b.Aa=null}a.a=null;if(b=a.A){if(b.a)for(c= +0;c<b.a.length;c++)Qx(b.a[c]);b.a=null;cy(b.b);b.b=null}a.A=null;if(b=a.v){if(b.a)for(c=0;c<b.a.length;c++)ey(b.a[c]);b.a=null}a.v=null;a.B=null;if(a.m)for(b=0;b<a.m.length;b++)if(c=a.m[b])c.b=null,c.a=null;a.m=null;a.s=null;if(a.g)for(b=0;b<a.g.length;b++)wd(a.g[b]);a.g=null}if(this.l)for(a=0;a<this.o.length;++a)b=this.l,c=this.o[a],d=b.c[c],!B(d)||0>d||(b.a[d]--,b.a[d]||(b.a[d]=-1-b.b,b.b=d,delete b.c[c],b.f&&b.f.call(b.g,d)))}; +function TR(a){if(null!=a.a.b&&a.v)for(var b=a.a.b,c=0;c<b.length;++c){var d=b[c],e=a.v,f=d,g=d.wa();d=a.m;var h=a.o,k=f;$u(k);var l=k.a?k.a.length:0;if(0!=l){var m=null,n=null,p=null,q=null;k=null;for(var t=[],v=[],u=[],w=[],y=[],A=0;A<l;A++){var z=f;var C=A;$u(z);C=z.a[C];z=null==f.c||f.c||1<l?C.getZoom():0;if(null!=C.c){var I=C;null===I.c&&(I.c=new Uu);I=I.c;n||(n=new zA);v.push(z);JB(I,z,n)}null!=C.a&&(I=C,null===I.a&&(I.a=new Ou),I=I.a,m||(m=new zA),t.push(z),EB(I,z,m));null!=C.g&&(I=C,null=== +I.g&&(I.g=new Yu),I=I.g,p||(p=new zA),u.push(z),KB(I,z,p));null!=C.b&&(I=C,null===I.b&&(I.b=new Pu),I=I.b,q||(q=new zA),w.push(z),GB(I,z,e.b,q));null!=C.f&&(null===C.f&&(C.f=new Zu),C=C.f,k||(k=new zA),y.push(z),DA(k,z,C))}n&&(LB(v,n),f=n.style,l="L"+g,h&&h.push(l),l=pr(e.a,l),f.B=l,d.push(f));m&&(LB(t,m),f=m.style,l="A"+g,h&&h.push(l),m=pr(e.a,l),f.B=m,d.push(f));p&&(LB(u,p),f=p.style,l="V"+g,h&&h.push(l),p=pr(e.a,l),f.B=p,d.push(f));q&&(LB(w,q),f=q.style,l="B"+g,h&&h.push(l),q=pr(e.a,l),f.B=q,d.push(f)); +k&&(LB(y,k),f=k.style,l="R"+g,h&&h.push(l),e=pr(e.a,l),f.B=e,d.push(f))}}} +function UR(a){var b=a.b;if(Ey(a.a)&&jy(Fy(a.a)))for(var c=Fy(a.a).a,d=0;d<c.length;d++){var e=c[d],f=null!=e.h?VR(a,null==e.h?"\u00ffffffff\u00ffffff\u00ffff\u00ff\u00ffffffff\u00ffffff\u00ffff\u00ff":e.h,!0,"L"):WR(a,null==e.m?-1:e.m,"L");f=RQ(b,e,1,d,0,f,null==e.s?0:e.s,null==e.u?0:e.u);if(e=e.getExtension(53863091))f.c=!0,null!=e.a&&(f.i=null==e.a?!1:e.a)}if(Gy(a.a)&&ly(Hy(a.a)))for(c=Hy(a.a).a,d=0;d<c.length;d++)if(e=c[d],f=null!=e.g?VR(a,null==e.g?"\u00ffffffff\u00ffffff\u00ffff\u00ff\u00ffffffff\u00ffffff\u00ffff\u00ff": +e.g,!0,"A"):WR(a,null==e.h?-1:e.h,"A"),f=RQ(b,e,2,d,0,f,null==e.i?0:e.i,null==e.j?0:e.j),e=e.getExtension(53863091))f.c=!0,null!=e.a&&(f.i=null==e.a?!1:e.a);if(null!=a.a.i&&ny(Iy(a.a)))for(c=Iy(a.a).a,d=0;d<c.length;d++)if(e=c[d],f=null!=e.f?VR(a,null==e.f?"\u00ffffffff\u00ffffff\u00ffff\u00ff\u00ffffffff\u00ffffff\u00ffff\u00ff":e.f,!0,"V"):WR(a,null==e.g?-1:e.g,"V"),f=RQ(b,e,3,d,0,f,null==e.h?0:e.h,null==e.i?0:e.i),e=e.getExtension(53863091))f.c=!0,null!=e.a&&(f.i=null==e.a?!1:e.a);if(Jy(a.a)&& +py(Ky(a.a)))for(c=Ky(a.a),d=0;d<(c.a?c.a.length:0);d++)if(e=c.a[d],f=null!=e.l?VR(a,Gu(e),!0,"B"):WR(a,null==e.i?-1:e.i,"B"),f=RQ(b,e,4,d,null==e.m?0:e.m,f,null==e.s?0:e.s,null==e.u?0:e.u),e=e.getExtension(53863091))f.c=!0,null!=e.a&&(f.i=null==e.a?!1:e.a);if(null!=a.a.a&&ry(Ly(a.a)))for(e=Ly(a.a).Aa,d=0;d<e.length;d++)c=e[d],f=null!=c.b?VR(a,null==c.b?"\u00ffffffff\u00ffffff\u00ffff\u00ff\u00ffffffff\u00ffffff\u00ffff\u00ff":c.b,!0,"R"):WR(a,null==c.f?-1:c.f,"R"),RQ(b,c,5,d,0,f,null==c.g?0:c.g,null== +c.h?0:c.h);if(Jy(a.a)&&py(Ky(a.a)))for(c=Ky(a.a),d=0;d<(c.a?c.a.length:0);d++)e=c.a[d],XR(a,e,d)} +function XR(a,b,c){if(null!=b.j){var d=a.b,e=-1;null!=b.l?e=VR(a,Gu(b),!0,"B"):null!=b.i&&(e=WR(a,null==b.i?-1:b.i,"B"));c=d.a[4][c];var f=Cu(b);if(null!=f.b||null!=f.c){var g=null!=f.b?VR(a,lu(f),!0,"B"):WR(a,null==f.c?-1:f.c,"B");g=SQ(d,c,g);c.j=g}YR(a,c,e,f,0);if(null!=b.a){b=Du(b);if(null!=b.b||null!=b.c)g=null!=b.b?VR(a,lu(b),!0,"B"):WR(a,null==b.c?-1:b.c,"B"),g=SQ(d,c,g),c.l=g;YR(a,c,e,b,1)}a.g=!0}} +function YR(a,b,c,d,e){for(var f=0;f<(d.a?d.a.length:0);f++){var g=d.a[f],h=c;null!=g.h?h=VR(a,null==g.h?"\u00ffffffff\u00ffffff\u00ffff\u00ff\u00ffffffff\u00ffffff\u00ffff\u00ff":g.h,!0,"B"):null!=g.i&&(h=WR(a,null==g.i?-1:g.i,"B"));g=SQ(a.b,b,h);0==e?(h=b,h.f||(h.f=[]),h.f.push(g)):(h=b,h.h||(h.h=[]),h.h.push(g))}} +function nN(a){var b=a.b.b.length;if(!a.f){a.f=new NR;for(var c=0;c<b;c++){var d=a.b.b[c];if(4!=d.a&&3!=d.a){d=a;var e=c,f=d.getZoom();d=oA(CK(d.s,e),f);e=a.f;f=c;for(var g=a.b.b[c].u,h=a.b.b[c].v,k=e.a,l=null,m=0;m<k.length;m++)if(k[m].a==d&&k[m].b==g&&k[m].g==h){l=k[m];break}l||(l=new KR(d,g,h),e.a.push(l));e.b[f]=l}}}a.h&&a.h.f?OR(a.f,a.h.f):OR(a.f);for(c=0;c<b;c++)d=a.b.b[c],4!=d.a&&3!=d.a&&(d.za=a.f.b[c].c,d.b=a.f.b[c].f)} +function VR(a,b,c,d){d+=b;if(c)return a.u[b]||(a.u[b]=!0,a.i.push(b)),pr(a.l,d);a=qr(a.l,d);return-1==a?0:a}function WR(a,b,c){if(null==a.a.b)return b;if(0>b)return 0;var d=a.a.b;if(b>=d.length)return 0;b=d[b];c=VR(a,b.wa(),(null==b.c?!0:b.c)&&!(null!=b.a||null!=b.g),c);0==c&&(tK(a),uK(a),a.getZoom());return c}function tK(a){a=Ay(a.a);return null==a.a?0:a.a}function uK(a){a=Ay(a.a);return null==a.b?0:a.b}RR.prototype.getZoom=function(){return Ay(this.a).getZoom()}; +function BL(a){var b=a.j;b.b?b=b.b:(a=Dy(a.a),Zx(a),a=new FR(a.b,HR),b=b.b=a);return b}function EL(a,b){var c=ay(Dy(a.a),b);return null!=c.a?null==c.a?"\x00\x00\x00\x00\x00\x00\x00\x00":c.a:"g_"+a.B+"_"+b} +function eM(a,b){if(a.O())return null;var c=a.b.b[b];c=4==c.a?zu(ZR(a,b)):1==c.a?Pw($R(a,b)):2==c.a?rx(aS(a,b)):3==c.a?Gx(bS(a,b)):null;if(!c)return null;a=a.b.b[b];if(2==a.a){a=new QR;if(b=Id(c,32819068))b=b.w(),a.data[5]=b;if(b=Id(c,42466818))b=b.w(),a.data[9]=b;if(b=Id(c,30096869))b=b.w(),a.data[4]=b;if(b=Id(c,52617685))b=b.w(),a.data[14]=b;if(b=Id(c,51650189))c=b.w(),a.data[13]=c;return a}if(1==a.a){a=new QR;if(b=Id(c,28517612))b=b.w(),a.data[1]=b;if(b=Id(c,30096869))b=b.w(),a.data[4]=b;if(b= +Id(c,48343962))b=b.w(),a.data[11]=b;if(b=Id(c,49095464))b=b.w(),a.data[12]=b;if(b=Id(c,132080860))b=b.w(),a.data[17]=b;if(b=Id(c,51650189))c=b.w(),a.data[13]=c;return a}if(4==a.a){a=new QR;if(b=Id(c,30929027))b=b.w(),a.data[3]=b;if(b=Id(c,66786615))b=b.w(),a.data[16]=b;if(b=Id(c,28517612))b=b.w(),a.data[1]=b;if(b=Id(c,30511227))b=b.w(),a.data[2]=b;if(b=Id(c,30096869))b=b.w(),a.data[4]=b;if(b=Id(c,33356690))b=b.w(),a.data[6]=b;if(b=Id(c,40251317))b=b.w(),a.data[7]=b;if(b=Id(c,43229016))b=b.w(),a.data[10]= +b;if(b=Id(c,51650189))b=b.w(),a.data[13]=b;if(b=Id(c,40154408))b=b.w(),a.data[8]=b;if(b=Id(c,60681369))b=b.w(),a.data[15]=b;if(b=Id(c,42466818))b=b.w(),a.data[9]=b;(b=Id(c,53863091))&&!xe(a,4)&&((new Ml(Ae(new PR(Ae(a,4)),0))).data[1]=null==b.b?"":b.b);return a}return 3==a.a?a=new QR:null}function AL(a,b,c,d){return XM(a.b.a[4][b],c,d)}function UM(a){var b;if(b=!a.h&&0==a.b.b.length&&0==a.m.length&&null==a.a.h)a=a.a,b=0==(a.f?a.f.length:0);return b} +function ZR(a,b){b=QQ(a.b,b);return Ky(a.a).a[b]}function $R(a,b){b=QQ(a.b,b);return Fy(a.a).a[b]}function aS(a,b){b=QQ(a.b,b);return Hy(a.a).a[b]}function bS(a,b){b=QQ(a.b,b);return Iy(a.a).a[b]}function mN(a,b,c){for(var d=PQ(a.b),e=Array(d),f=Array(d),g=0;g<d;++g)e[g]=a.b.G(g),f[g]=g>=a.b.b.length?!0:4==a.b.b[g].a;return new IR(e,f,b,c)};function cS(a,b){this.a=a;this.b=b};function dS(a){this.a=a};function eS(a,b){this.g=a;this.f=b;this.b=this.a=null;this.c=[];LQ("Roadmap")}eS.prototype.getData=function(a){if(!this.a)return[];a=new MP(0,a.a,0);for(var b=[],c=0;c<this.c.length;++c){var d=this.c[c];if(d.b()){var e=d.Md;if(OO(this))if(this.a.fb(e))d=new dS([new cS([e],a)]),b.push(d);else if(!d.a||"pending"!=d.a.getState()){d.a=this.a.ic(e,2,!0);var f=d.a.getState();"success"==f&&this.a.fb(e)?(d=new dS([new cS([e],a)]),b.push(d)):"pending"==f&&MM(d.a,this.f)}}}return b}; +function OO(a){a.b||(a.b=MQ(a.g,"Roadmap",3),"pending"==a.b.getState()&&MM(a.b,a.f));return"success"==a.b.getState()};function fS(){this.a=this.b=this.c=this.h=this.f=null;this.g=0}function gS(a){var b={};null!=a.f&&(b.uri=a.f);null!=a.h&&(b.xdc=a.h);null!=a.c&&(b.streaming=a.c);null!=a.b&&(b.chunked=a.b);null!=a.a&&(b.deferred=a.a);null!=a.g&&(b.workerOptions=a.g);return b}function hS(){this.i=this.g=this.h=this.a=this.c=this.f=this.b=this.status=null}function iS(a){return a?new VQ(a.data,a.width,a.height,a.format):null};function jS(a){this.f=a}jS.prototype.a=function(a){for(var b=0;b<this.f.length;++b)if(this.f[b].a(a))return!0;return!1};jS.prototype.b=function(a){for(var b=0;b<this.f.length;++b)if(this.f[b].a(a))return this.f[b].b(a);return null};jS.prototype.c=function(a,b,c){for(var d=0,e=0;e<this.f.length;++e){for(var f=[],g=[],h=0;h<a.length;++h)this.f[e].a(a[h].N)?f.push(a[h]):g.push(a[h]);a=g;0<f.length&&(this.f[e].c(f,b,c),d++)}};function kS(a){this.start=a;this.cancel=rr;this.b=null};function lS(a,b){this.type=a;this.N=b;this.data=B(void 0)?void 0:null;this.priority=2;this.result=new FM};function mS(a,b,c,d){this.h=a;this.g=b;this.f=c;this.i=d||!1}mS.prototype.a=function(a){return a.Ea()==this.g&&21>=a.getZoom()};mS.prototype.b=function(a){return this.a(a)?0:null};mS.prototype.c=function(a,b){for(var c=0;c<a.length;++c)nS(this,a[c],b)}; +function nS(a,b,c){if(b.N&&a.a(b.N)){var d=a.f.a(b.N),e=go("IMG");b.data=e;e.crossOrigin=a.i?"use-credentials":"";DG(a.h,new kS(function(a){var c=new no;c.cc(e,"load",function(){a();oS(e,b,c,!0)});c.cc(e,"error",function(){a();oS(e,b,c,!1)});e.src=d}),c)}else KM(b.result,"")}function oS(a,b,c,d){Lb(c);"pending"==b.result.getState()&&(d&&a.complete?HM(b.result,!0):KM(b.result))};function pS(){this.b=SE()}pS.prototype.a=function(a){a=qs.b(a.data,this.b);return"pb="+encodeURIComponent(a).replace(/%20/g,"+")};var qS={ae:!0,ar:!0,bh:!0,cn:!0,dz:!0,eg:!0,es:!0,gb:!0,gi:!0,gr:!0,"in":!0,iq:!0,jo:!0,jp:!0,kr:!0,kw:!0,lb:!0,ly:!0,ma:!0,mk:!0,mm:!0,om:!0,pk:!0,qa:!0,ru:!0,sa:!0,tn:!0,tr:!0,tw:!0,ua:!0,uk:!0};function rS(a){return!!a&&!!qS[a.toLowerCase()]};function sS(a){this.b=a}sS.prototype.a=function(a){for(var b=0,c=0;c<a.length;++c)b+=a.charCodeAt(c);return this.b[b%this.b.length].a(a)};function tS(a){if(1==a.length)a=new KF(a[0]);else{for(var b=Array(a.length),c=0;c<a.length;++c)b[c]=new KF(a[c]);a=new sS(b)}return a};function uS(a,b){this.c=b;this.f=tS(a);this.b=new pS}uS.prototype.a=function(a){var b=new QE;He(b,this.c);var c=a.ba().g;c&&rS(c)&&(TE(b).data[2]=c);c=new EE(De(b,0));OE(c).data[1]=iC(a);OE(c).data[2]=jC(a);c=OE(c);a=a.getZoom();c.data[0]=a;b=this.b.a(b);return this.f.a(b)};function vS(a){this.b=a}vS.prototype.a=function(a){a=a.Ha;var b=this.b;b=b[(a.b+a.a)%b.length];return b+=(-1==b.indexOf("?")?"?":"&")+"x="+a.b+"&y="+a.a+"&z="+a.getZoom()};function wS(){this.b=new pS}wS.prototype.a=function(a){var b=this.b.a(a);a:{if(a instanceof QE)for(var c=0;c<Fe(a,1);c++){var d=mC(a,c);if(2==ye(d,0,0)){a=!0;break a}}a=!1}return a?b+"&authuser=0":b};function xS(){}xS.prototype.b=function(a,b,c){for(var d=0;d<a.length;++d){var e=a[d].N;if(this.a(e)){var f=new EE(De(c,0));OE(f).data[1]=iC(e);OE(f).data[2]=jC(e);f=OE(f);e=e.getZoom();f.data[0]=e;b.push(a[d])}else KM(a[d].result,"")}};xS.prototype.a=function(a){return 0==a.Ea()&&22>=a.getZoom()};function yS(a,b,c,d){this.b=a;this.f=b;this.g=c;this.c=d;this.a=sa}function zS(a,b,c,d){B(b.xd)&&b.xd()&&B(b.vd)&&b.vd();b=a.f.a(b);var e=d||new xQ;e.start(a.c);a.b.a(b,function(b){try{3!=e.a&&(++e.c,1==e.c&&c(AS(a,b,e)))}catch(g){throw a.a(g),g;}},function(){try{3!=e.a&&(0==e.c&&(zQ(e,2),c(null)),e.done())}catch(f){throw a.a(f),f;}},e)} +function BS(a,b,c,d,e){b=a.f.a(b);var f=e||new xQ;f.start(a.c);a.b.a(b,function(b){try{if(3!=f.a){++f.c;var d=AS(a,b,f);null!=d&&c(d)}}catch(k){throw a.a(k),k;}},function(){try{3!=f.a&&(d&&d(),f.done())}catch(g){throw a.a(g),g;}},f)}function AS(a,b,c){var d=null;try{d=a.g.a(b)}catch(e){zQ(c,2),d=null}return d};function CS(a,b,c,d,e){b=new CQ(a,b);this.a=new yS(b,c,d,e)};function DS(a){return 255<a&&ES[a]?ES[a]:a}var ES,FS=[];FS[8364]=128;FS[8218]=130;FS[402]=131;FS[8222]=132;FS[8230]=133;FS[8224]=134;FS[8225]=135;FS[710]=136;FS[8240]=137;FS[352]=138;FS[8249]=139;FS[338]=140;FS[381]=142;FS[8216]=145;FS[8217]=146;FS[8220]=147;FS[8221]=148;FS[8226]=149;FS[8211]=150;FS[8212]=151;FS[732]=152;FS[8482]=153;FS[353]=154;FS[8250]=155;FS[339]=156;FS[382]=158;FS[376]=159;ES=FS;function GS(){this.b=2;this.a=0;this.c=-1;this.g=0;this.f=sa}var HS=function(){if(!pb||Ab(12))return!1;if(Ab(11)){var a=new Uint8Array(1);a[0]=128;a=x.URL.createObjectURL(new Blob([a]));var b=new XMLHttpRequest;b.open("GET",a,!1);b.overrideMimeType("application/octet-stream; charset=x-user-defined");b.send();x.URL.revokeObjectURL(a);if(128==(b.responseText.charCodeAt(0)&255))return!1}return!0}(); +function IS(a,b){for(a.g=b.length;;)switch(a.b){case 2:var c=a;b.length<c.a+4?c=!1:"X"!=b[c.a]||"H"!=b[c.a+1]||"R"!=b[c.a+2]||"1"!=b[c.a+3]?(c.b=1,c=!1):(c.a+=4,c.b=3,c=!0);if(!c)return!1;break;case 3:c=a;b.length<c.a+4?c=!1:(c.c=JS(b,c.a)<<24|JS(b,c.a+1)<<16|JS(b,c.a+2)<<8|JS(b,c.a+3),c.a+=4,0>c.c?(c.b=1,c=!1):(c.b=4,c=!0));if(!c)return!1;break;case 4:return b.length<a.a+a.c?b=!1:(a.f(b.substr(a.a,a.c)),a.a+=a.c,a.c=-1,a.b=3,b=b.length>a.a),b?!0:!1;default:return!1}} +function JS(a,b){return HS?DS(a.charCodeAt(b)):a.charCodeAt(b)&255};function KS(a,b,c,d){this.b=a;this.g=b;this.c=c;this.f=d||!1;this.a=null}KS.prototype.getData=function(){return this.c};function LS(a){this.b=a}LS.prototype.a=function(a){if(2>a.length)throw"Invalid number of bytes in streaming paint response";var b=2==a.length?null:a.subarray(2);return new KS(a[0],a[1],b,this.b)};function MS(a){this.b=a}MS.prototype.a=function(a,b,c,d){this.b.a(a,D(this.c,this,b,d),c,d)};MS.prototype.c=function(a,b,c){if(!b||3!=b.a&&2!=b.a){c=new Uint8Array(c,0,c.byteLength);if(4>c.length||88!=c[0]||72!=c[1]||82!=c[2]||49!=c[3])a=!1;else{for(var d=4;d+4<c.length;){var e=c[d]<<24|c[d+1]<<16|c[d+2]<<8|c[d+3];d+=4;if(d+e>c.length)break;var f=c.subarray(d,d+e);a(f);d+=e}a=d!=c.length?!1:!0}!a&&b&&zQ(b,2)}};function NS(a,b,c,d){b=new FQ(b,"arraybuffer");b.b=!!d;CS.call(this,a,new MS(b),c,new LS,"NonStreamedMegatilePaintService.streamingPaint")}F(NS,CS);NS.prototype.b=function(a,b,c,d){BS(this.a,a,b,c,d)};function OS(a,b){if(!a.D){var c=new QE;c.data[3]=1;var d=new YD(Ae(c,5));d.data[43]=a.c;d.data[0]=12;d.data[1]=2;d.data[49]=0;if(1==a.c&&a.h){var e=new OD(Ae(c,4));e.data[0]=4;e=new WD(Ae(e,7));Ce(e,0).push(0);Ce(e,0).push(1)}2==a.c&&a.g&&(d.data[27]=3);e=Yn(a.la,1,2);1!=e&&((new $D(Ae(d,29))).data[0]=e);a.ha&&Ce(d,40).push(1);TE(c).data[4]=a.C;for(d=0;d<a.l.length;++d)e=a.l[d],Ce(c,22).push(e);a.D=c}this.b=a.D;this.c=a.B;this.a=b} +function PS(a,b,c){var d=new QE;He(d,a.b);var e=new YD(Ae(d,5)),f=b[0].N;a.c&&(gC(f)?e.data[10]=2:(new hE(Ae(e,25))).data[3]=!0);Ls(f.ba().c)&&(e.data[38]=!0);e=b[0].N.ba();f=e.a;for(var g=f.a.length,h=Array(g),k=0;k<g;++k)h[k]=Array(b.length);for(k=0;k<b.length;++k)for(var l=b[k].N.b,m=0;m<l.length;++m)h[m][k]=l[m];for(k=0;k<g;++k){l=null;if(e.f?e.a.b[k]:1)l=e.f?(l=e.a.b[k])?(l=e.f.a[l])?l.a.g(h[k]):null:null:null;-1!=l&&(m=UE(d),He(m,f.a[k]),null!==l&&(m.data[2]=l))}e=TE(d);f=b[0].N;g=f.ba().c; +for(h=0;h<g.a.length;++h)He(new Sn(De(e,11)),g.a[h]);f.ba().h&&(e.data[1]=f.ba().h);(g=f.ba().g)&&(gC(f)||rS(g))&&(e.data[2]=g);a.a.b(b,c,d);return d};function QS(a){this.f=a}QS.prototype.a=function(a){return this.f.a(a)};QS.prototype.b=function(a){return this.f.b(a)}; +QS.prototype.c=function(a,b,c){if(0!=a.length){var d=a;for(a=[];0<d.length;){for(var e=[],f=d[0].N,g=[d[0]],h=1;h<d.length;++h){var k=d[h].N,l=k;if(l=f.Ea()==l.Ea()){l=f.ba();var m=k.ba();l=l.h==m.h&&l.g==m.g}if(l)a:if(l=f.ba().a,m=k.ba().a,l.a.length!=m.a.length)l=!1;else{for(var n=0;n<l.a.length;++n)if(!Gs(l.a[n],m.a[n])){l=!1;break a}l=!0}l&&Ks(f.ba().c,k.ba().c)?g.push(d[h]):e.push(d[h])}a.push(g);d=e}RS(a.length);for(d=0;d<a.length;++d)this.f.c(a[d],b,c)}};var RS=sa;function SS(a,b,c,d){this.a=c;this.b=d}SS.prototype.start=function(){this.b?this.a.call(this.b):this.a();return Dr};function TS(){this.a=this.b=this.c=null};function US(a,b,c){this.h=a;this.f=b;this.g=c}US.prototype.a=function(a){return this.f.a.a(a)};US.prototype.b=function(a){return this.f.a.a(a)?5:null}; +US.prototype.c=function(a,b){if(0!=a.length){var c=[],d=PS(this.f,a,c);if(0<Fe(d,0)){var e=new xQ;AQ(e,b);var f=function(a){if(1==e.a&&a&&0==a.g){var b=a.b;0>b||b>=c.length||(b=c[b],"pending"==b.result.getState()&&(b.data=new TS,a.f?b.data.b=a.getData():b.data.c=a.getData(),b.data.a=a.a,HM(b.result,!0)))}},g=this.g.j(),h=function(){g();VS(c,e)},k=this.h;this.g.ed(new WS(function(){k.b(d,f,h,e)}),b-1);for(a=0;a<c.length;++a)b=c[a],"pending"==b.result.getState()&&XS(this,b,c,e)}}}; +function XS(a,b,c,d){LM(b.result,function(){for(var a=!1,b=0;b<c.length;++b){var g=c[b].result;if("pending"==g.getState())return;a=a||JM(g)}a&&d.cancel()&&VS(c,d)},a)}function VS(a,b){for(var c=0;c<a.length;++c){var d=a[c].result;"pending"==d.getState()&&(3==b.a?d.cancel():KM(d))}}function WS(a){this.a=a;this.b=void 0}F(WS,SS);function YS(a,b,c,d){d=!!d;b=new FQ(b,"arraybuffer");b.b=d;CS.call(this,a,b,c,new ZS,"SingleTilePaintService.streamingPaint")}F(YS,CS);YS.prototype.b=function(a,b,c,d){zS(this.a,a,function(a){a&&b(a);c&&c()},d)};function ZS(){}ZS.prototype.a=function(a){return new KS(0,0,a)};function $S(a,b,c){this.s=a;this.o=b;this.h=c;this.l=1;this.a=aT(this);this.i="";this.j=500;this.c=!1;this.b=null;this.f=0;this.g=!1}function bT(a,b,c){B(c)&&(a.l=c);a.g=!0;rD(a.a,b,void 0,void 0);a.g=!1}function cT(a){return a.a?BD(a.a):a.i}function dT(a){return a.a?zD(a.a):a.j}$S.prototype.cancel=function(){var a=this.a;eT(this,!1);a&&a.abort()}; +function aT(a){var b=new mD;b.g=Math.max(0,0);dc(b,"readystatechange",function(){fT(this,!1)},void 0,a);dc(b,"success",function(){fT(this,!0)},void 0,a);dc(b,"error",a.m,void 0,a);dc(b,"abort",a.m,void 0,a);return b}function fT(a,b){b&&eT(a,!0);if(!(a.c||null!==a.b||a.g&&0==cT(a).length)){var c=E();!b&&10>c-a.f?a.b=x.setTimeout(function(){gT(a)},a.f+10-c):gT(a)}}function gT(a){a.b=null;if(a.h)a.c=!0,a.h.Mb(a,a.l);else for(var b=a.start();b!==Dr;)b=b.apply(a)} +$S.prototype.start=function(){this.f=E();if(this.s())return this.start;this.c=!1;return Dr};$S.prototype.m=function(){this.o();eT(this,!1)};function eT(a,b){!b&&a.c&&(a.c=!1,a.h.Pe(a));null!=a.b&&(x.clearTimeout(a.b),a.b=null);a.a&&(a.i=BD(a.a),a.j=zD(a.a),nc(a.a),a.a=null)};function hT(a,b){this.g=a;this.h=!!b;this.f=this.a=this.b=null;this.c=new GS}function iT(a,b,c,d,e){a.b=new $S(D(a.i,a),D(a.j,a),a.g);a.a=e||null;a.c.f=c;a.f=d||sa;if(e){var f=a.b;yQ(e,function(){f.cancel();return!0})}a.b.a.l=a.h;bT(a.b,b,e?jT(e.b):void 0)}hT.prototype.i=function(){if(null!=this.a&&3==this.a.a)return!1;var a=cT(this.b);a=IS(this.c,a);!a&&null===this.b.a&&kT(this);return a};hT.prototype.j=function(){null!=this.a&&3==this.a.a||kT(this)}; +function kT(a){var b=a.c;if(3!=b.b||b.g>b.a||!NC(dT(a.b)))switch(dT(a.b)){case 400:a.a&&zQ(a.a,4);break;case 404:a.a&&zQ(a.a,5);break;default:a.a&&zQ(a.a,2)}a.f()}function jT(a){switch(a){case 3:return 2;case 2:return 1;case 1:return 0;default:return 1}};function lT(a,b){this.f=pa(a)||a instanceof mB?new EQ(a):a;this.c=b;this.b=!1}lT.prototype.a=function(a,b,c,d){var e=new hT(this.c,this.b);a=this.f.a(a);iT(e,a,b,c,d)};function mT(a,b,c,d,e){b=new lT(c,b);b.b=!!e;CS.call(this,a,b,d,new nT,"StreamingPaintService.streamingPaint")}F(mT,CS);mT.prototype.b=function(a,b,c,d){BS(this.a,a,b,c,d)};function nT(){} +nT.prototype.a=function(a){if(2>a.length)throw"Invalid number of bytes in streaming paint response";var b=JS(a,0),c=JS(a,1);var d=B(void 0)?NaN:a.length;d>a.length&&(d=a.length);if(2>=d||2>=a.length)a=null;else{var e=new Uint8Array(d-2);if(HS)for(var f=2;f<d;++f)e[f-2]=DS(a.charCodeAt(f));else for(f=2;f<d;++f)e[f-2]=a.charCodeAt(f)&255;a=e.buffer}return new KS(b,c,a)};function oT(){}oT.prototype.b=function(a,b,c){a.sort(pT);for(var d=0;d<a.length;++d)if(this.a(a[d].N)){var e=new qT,f=rT(this,e,a,d);sT(this,d,f,e,c,a,b);d=f-1}else KM(a[d].result,"")};oT.prototype.a=function(a){return 0==a.Ea()&&22>=a.getZoom()};function qT(a,b,c,d){this.a=a;this.b=b;this.c=c;this.f=d}qT.prototype.reset=function(a,b,c,d){this.a=a;this.b=b;this.c=c;this.f=d};function tT(a,b){return iC(b)>=a.a&&iC(b)<=a.c&&jC(b)>=a.b&&jC(b)<=a.f} +qT.prototype.split=function(a,b){var c=this.c-this.a+1,d=this.f-this.b+1;return a&&b?[new qT(this.a,this.b,this.a+c/2,this.b+d/2),new qT(this.a+c/2+1,this.b,this.c,this.b+d/2),new qT(this.a,this.b+d/2,this.a+c/2,this.f),new qT(this.a+c/2+1,this.b+d/2,this.c,this.f)]:a?[new qT(this.a,this.b,this.a+c/2,this.f),new qT(this.a+c/2+1,this.b,this.c,this.f)]:b?[new qT(this.a,this.b,this.c,this.b+d/2),new qT(this.a,this.b+d/2,this.c,this.f)]:[]}; +function pT(a,b){a=a.N;b=b.N;var c=uT(a.getZoom(),b.getZoom());if(0!=c)return c;c=uT(jC(a),jC(b));return 0!=c?c:uT(iC(a),iC(b))}function rT(a,b,c,d,e,f){for(var g=B(e)?e:c.length,h,k,l,m,n=c[d].N.getZoom();d<g;++d){var p=c[d].N;if(a.a(p)){if(!B(e)&&p.getZoom()!=n){g=d;break}if(!B(f)||tT(f,p))B(h)?(h=Math.min(h,iC(p)),k=Math.min(k,jC(p)),l=Math.max(l,iC(p)),m=Math.max(m,jC(p))):(h=iC(p),k=jC(p),l=h,m=k)}}B(h)&&b.reset(h,k,l,m);return g}function uT(a,b){return a<b?-1:a>b?1:0} +function sT(a,b,c,d,e,f,g){var h=d.c-d.a+1,k=d.f-d.b+1;if(64>=h&&64>=k){e=new AE(Ae(new EE(De(e,0)),7));k=f[b].N;(new Oz(Ae(e,0))).data[1]=d.a;(new Oz(Ae(e,0))).data[2]=d.b;var l=new Oz(Ae(e,0));k=k.getZoom();l.data[0]=k;e.data[1]=h;for(h=b;h<c;++h)if(k=f[h].N,a.a(k)){if(tT(d,k)){b=e;l=(jC(k)-X(new Oz(b.data[0]),2))*X(b,1)+(iC(k)-X(new Oz(b.data[0]),1));k=Math.floor(l/32);l%=32;if(Fe(b,2)<k+1)for(var m=Fe(b,2);m<k+1;++m)Ce(b,2).push(0);m=k;0!=(Ce(b,2)[m]&1<<l)?b=!1:(m=k,m=Ce(b,2)[m],l=(m|1<<l)>>> +0,Ce(b,2)[k]=l,b=!0);b?g.push(f[h]):KM(f[h].result,"Could not be handled by TileBitmapPaintRegionBuilder.")}}else KM(f[h].result,"")}else for(d=d.split(64<h,64<k),k=[],h=0;h<d.length;++h)k=k.concat(vT(a,b,c,d[h],e,f,g))}function vT(a,b,c,d,e,f,g){var h=new qT;rT(a,h,f,b,c,d);B(h.a)&&sT(a,b,c,h,e,f,g)};function wT(a,b,c,d,e){this.f=pa(b)||b instanceof mB?new EQ(b):b;this.h=c;this.g=d;this.b=!1;this.c=a;this.i=e}wT.prototype.a=function(a,b,c,d){a=this.f.a(a);xT(new yT(this.b,this.h,this.g,this.i),a,b,this.c,c,d)};function yT(a,b,c,d){this.c=a;this.g=b;this.f=c;this.h=d;this.a=null}function xT(a,b,c,d,e,f){a.a=f||null;c=D(a.b,a,c,e||sa);e=new fS;e.f=b;e.h=a.c;e.c=a.g;e.b=a.f;e.g=a.h;var g=new rF(gS(e),c);f&&yQ(f,function(){d.abort(g);return!0});EF(d,g)} +yT.prototype.b=function(a,b,c,d){if(null==this.a||3!=this.a.a){var e=new hS;B(c.status)&&(e.status=c.status);B(c.prIndex)&&(e.b=c.prIndex);B(c.prStatus)&&(e.f=c.prStatus);B(c.prData)&&(e.c=c.prData);B(c.prChunks)&&(e.a=c.prChunks);B(c.spritemapImage)&&(e.h=iS(c.spritemapImage));if(B(c.rasterRenderOpImages))for(var f=e.g=[],g=0;g<c.rasterRenderOpImages.length;g++)f[g]=iS(c.rasterRenderOpImages[g]);B(c.computedWaterCoverage)&&(e.i=iS(c.computedWaterCoverage));null==e.b&&null==e.a||a(e);d&&(a=e.status, +!this.a||2!=a&&4!=a&&5!=a||zQ(this.a,a),b())}};function zT(a,b,c,d,e,f,g){a=new wT(a,c,!1,!0,e);a.b=!!g;a=new AT(a);CS.call(this,b,a,d,new LS(!0),"WorkerNonStreamedMegatilePaintService.streamingPaint")}F(zT,CS);zT.prototype.b=function(a,b,c,d){BS(this.a,a,b,c,d)};function AT(a){this.b=a}AT.prototype.a=function(a,b,c,d){this.b.a(a,D(this.c,this,b,d),c,d)};AT.prototype.c=function(a,b,c){if(!b||3!=b.a&&2!=b.a)for(b=c.a,c=0;c<b.length;c++)a(b[c])};function BT(){this.a=this.Oe=null};function CT(a){this.a=a}F(CT,WQ);r=CT.prototype;r.Ab=function(){return null};r.Yb=function(){return this.a};r.Yd=function(){return this.a.width};r.Xd=function(){return this.a.height};r.Db=function(){return!0};r.bc=function(){return!1};r.Qb=function(){return!1};r.Ib=function(){};r.sd=function(){return!1};function DT(){}DT.prototype.a=function(a){var b=new KS(a.b,a.f,a.c,!0);b.a=new BT;var c=b.a;var d=a.h;var e=a.g;if(d||e){var f=new GR;if(d){var g=new CT(d);f.b=g}if(e)for(d=0;d<e.length;d++)if(g=e[d])g=new CT(g),f.a[d]=g;e=f}else e=null;c.Oe=e;b.a.a=a.i;return b};function ET(a,b,c,d,e,f,g){a=new wT(a,c,!1,!1,e);a.b=!!g;CS.call(this,b,a,d,new DT,"WorkerSingleTilePaintService.streamingPaint")}F(ET,CS);ET.prototype.b=function(a,b,c,d){zS(this.a,a,function(a){a&&b(a);c&&c()},d)};function FT(a,b,c,d,e,f,g){a=new wT(a,c,!0,!0,e);a.b=!!g;CS.call(this,b,a,d,new DT,"WorkerStreamingPaintService.streamingPaint")}F(FT,CS);FT.prototype.b=function(a,b,c,d){BS(this.a,a,b,c,d)};function GT(a){this.f=a}GT.prototype.a=function(a){return this.f.a(a)};GT.prototype.b=function(a){return this.f.b(a)};GT.prototype.c=function(a,b,c){for(var d=0;d<a.length;++d)this.f.c([a[d]],b,c)};function HT(a,b,c,d,e){var f,g=new wS,h=NF(b)&1;switch(a){case 1:var k=tS(b.j);h?f=new ET(b.b,c,k,g,NF(b),e,b.a):f=new YS(c,k,g,b.a);return new GT(new US(f,new OS(b,new xS),d));case 2:case 3:case 0:return k=tS(b.O),3==a?h?f=new zT(b.b,c,k,g,NF(b),e,b.a):f=new NS(c,k,g,b.a):h?f=new FT(b.b,c,k,g,NF(b),e,b.a):f=new mT(c,d,k,g,b.a),b=new OS(b,new oT),2==a?new GT(new US(f,b,d)):new QS(new US(f,b,d));default:throw"Invalid fetcher type "+a;}};function IT(a,b,c,d){this.f={};this.h=!0;this.f[0]=HT(0,a,b,c,d);this.f[1]=HT(1,a,b,c,d);this.f[2]=HT(2,a,b,c,d);this.f[3]=HT(3,a,b,c,d);this.g=a.J}IT.prototype.a=function(a){return(this.f[this.g]||this.f[0]).a(a)};IT.prototype.b=function(a){return(this.f[this.g]||this.f[0]).b(a)};IT.prototype.c=function(a,b,c){var d=this.g,e=this.f[this.g];4==d&&(c?d=3:(d=!1,gC(a[0].N)?d=!0:this.h&&(this.h=!1,d=!0),d=d?0:1),e=this.f[d]);JT(d);e.c(a,b,c)};var JT=sa;function KT(a,b){this.a=a;this.result=b}function LT(a){this.i=a;this.f=[]}function MT(a,b){if("success"!=b.result.getState())return aN();var c=b.priority,d=a.f[c];d||(d=new NT(a,a.i,c),a.f[c]=d);a=new FM;d.a.push(new KT(b,a));d.f.Mb(d,d.c);return a}function NT(a,b,c){this.f=b;this.b=a;this.c=c;this.a=[]} +NT.prototype.start=function(){if(!this.a.length)return Dr;for(var a=this.a.shift();"pending"!=a.result.getState();){if(!this.a.length)return Dr;a=this.a.shift()}this.b.c(a.a,a.result);return this.a.length?this.start:Dr};function OT(a,b){LT.call(this,a);this.b=b}F(OT,LT);OT.prototype.a=function(a){for(var b=0;b<this.b.length;++b){var c=this.b[b].a(a);if(null!==c)return c}return null};function PT(a){this.a=a}F(PT,WQ);r=PT.prototype;r.Ab=function(){return this.a};r.Yb=function(){return null};r.Yd=function(){return this.a.width};r.Xd=function(){return this.a.height};r.Db=function(){return!1};r.bc=function(){return!B(this.a.complete)||this.a.complete};r.Qb=function(){return!1};r.Ib=function(){};r.sd=function(){return!1};function QT(a){LT.call(this,a)}F(QT,LT);QT.prototype.a=function(a){return 0!=a.type?null:MT(this,a)};QT.prototype.c=function(a,b){var c=a.N,d=new GR;d.a[0]=new PT(a.data);var e=a.data.width/256;a=new Mw;By(a).a=iC(c);By(a).b=jC(c);var f=By(a),g=c.getZoom();f.c=g;wy(a).a=e;null===a.a&&(a.a=new Jw);e=a.a;f=new uw;e.Aa=e.Aa||[];e.Aa.push(f);d=new RR(a,null,d);HM(b,new pO(c,d))};function RT(a,b,c){c=b+c;var d=b+3&-4,e=c&-4;if(e>d){var f=e-d>>2,g=new Uint8Array(a);for(a=new Int32Array(a,d,f);b<d;b++)g[b]^=155;for(b=0;b<f;b++)a[b]^=2610666395;b=e}else g=new Uint8Array(a);for(;b<c;b++)g[b]^=155};function ST(a,b,c,d,e){LT.call(this,a);this.g=b;this.j=c;this.b=B(e)?e:null;this.h=d||null}F(ST,LT);ST.prototype.a=function(a){return 5!=a.type?null:MT(this,a)}; +ST.prototype.c=function(a,b){var c=a.data;a=a.N;var d=null,e=null,f=!0;if(c){if(c.b){var g=c.b;f=!1}else g=c.c;c.a&&(d=c.a.Oe,e=c.a.a)}g&&g instanceof ArrayBuffer&&(g=new Uint8Array(g));var h=g&&0==g.length;if(null==c||null==g||h)e=new Mw,By(e).a=iC(a),By(e).b=jC(a),g=By(e),d=a.getZoom(),g.c=d,wy(e).a=this.g,e=new RR(e,null,void 0,this.h||void 0),HM(b,new pO(a,e));else{f&&(c=g,f=B(void 0)?void 0:0,c.buffer?RT(c.buffer,c.byteOffset+f,c.length-f):RT(c,f,c.byteLength-f));d=d||void 0;c=new Mw;g=gd(g); +uy(c,g);hd(g);wy(c).a=this.g;g=new RR(c,this.j,d,this.h||void 0);if(iC(a)!=tK(g)||jC(a)!=uK(g)||a.getZoom()!=g.getZoom())throw e=Error("ParsingFailed"),e.file=a.aa(),e.name="TileError",KM(b),e;null!==this.b&&(d=g.a,null==d.s||this.b!=(null==d.s?0:d.s))&&(KM(b),c=Error(),c.message="EpochMismatch,"+(null==d.s?0:d.s)+","+this.b,nF(c));e&&(g.A=e);HM(b,new pO(a,g))}};function TT(a){this.b=a}TT.prototype.a=function(a,b,c){var d=new xQ,e=new FM;e.wait(function(a){JM(a)&&d.cancel()});AQ(d,b);UT(this.b,a,function(b){1!=d.a?(c(a,null),KM(e,"")):(c(a,b),HM(e,!0))},d);return e};function VT(a){this.data=a||[]}F(VT,W);function WT(a){this.data=a||[]}F(WT,W);function XT(){this.c=WT;this.b=sa}XT.prototype.a=function(a){")]}'\n"==a.substr(0,5)&&(a=a.substr(5));try{var b=JSON.parse(a)}catch(c){}if(!(b instanceof Array))throw this.b(a),Error("JspbDeserializer parse error.");return new this.c(b)};function YT(a,b,c){var d=new wS;c=!!c;b=new FQ(b);b.b=c;this.a=new yS(new CQ(a,b),d||new pS,new XT,"PertileService.paint")}function UT(a,b,c,d){zS(a.a,b,c,d)};function ZT(a){this.b=a} +ZT.prototype.a=function(a,b,c){a:{var d=Fe(a,1);if(!(2>d)){d=Array(d);for(var e=0;e<d.length;++e){d[e]=mC(a,e);for(var f=d[e].wa(),g=0;g<e;++g)if(d[g].wa()==f){d=!0;break a}}}d=!1}if(!d)return this.b.a(a,b,c);e=Array(Fe(a,1));for(f=0;f<e.length;++f)e[f]=mC(a,f);d=[];for(f=e.length-1;0<=f;--f){g=e[f].wa();for(var h=f-1;0<=h;--h)if(g==e[h].wa()){var k=new QE;He(k,a);Be(k,1);He(UE(k),mC(a,h));d.push(k);k=h;Ce(a,1).splice(k,1);--f}}d.push(a);a=Array(d.length);for(e=0;e<d.length;++e)a[e]=this.b.a(d[e], +b,c);b=RM.apply(null,a);b.wait(cN,void 0);return b};function $T(){rc.call(this)}F($T,rc);function aU(a){Qb.call(this,"ViewportLoaded",a)}F(aU,Qb);function bU(a,b){Qb.call(this,"ViewportMissingData",a);this.c=b}F(bU,Qb);bU.prototype.mb=function(){return this.c};function cU(a){Qb.call(this,"ViewportReady",a)}F(cU,Qb);function dU(a,b){rc.call(this);this.b=a;this.c=b}F(dU,$T); +function eU(a,b,c,d,e,f,g,h,k){var l=[],m=[];b=fU(a.b,c,b);c=l;for(var n=m,p=0;p<d.length;++p){var q=d[p],t=b?gU(b,q):null;t?a.a(t,k)?c.push(t):(h.push(q),t=null):(g.push(q),t=null);t||((t=b?hU(a,b,q,k):null)?c.push(t):n.push(q))}f&&0<m.length&&(l=[],m=d.slice());if(0<m.length&&!a.c){if(k)for(d=m,f=l,g=0;g<e.length;g++)if(h=e[g],h.data&&k.fb(h)){c=h.N;n=!1;for(p=0;p<d.length;p++)if(q=d[p],c.a!=q.a?0:cC(c.Ha,q.Ha))n=!0,c.getZoom()<=q.getZoom()&&(d.splice(p--,1),c.getZoom()!=q.getZoom()&&f.push(sO(q, +c.getZoom())));n&&f.push(h)}if(0<m.length&&b)a:{e=m;d=l;f=Array(e.length);for(g=0;g<e.length;++g)f[g]=e[g].Ha;if(c=bC(f))for(n=e[0].getZoom(),p=Math.max(0,n-1),q=n-p,f=c.oa>>q,g=c.Yc>>q,h=c.xc>>q,c=c.bd>>q,n=6>n?0:6;p>=n;--p){0==p&&(g=f=0);for(q=f;q<=g;++q)for(t=h;t<=c;++t){for(var v,u=null,w=0;w<e.length;++w)if(iU(q,t,p,e[w])){if(!(u||(v=e[w],v=new dC(new kC(q,t,p),v.a,v.c),u=gU(b,v),u&&a.a(u,k))||(u=hU(a,b,v,k),u)))break;u&&(d.push(sO(e[w],p)),e.splice(w--,1))}u&&d.push(u);if(0==e.length)break a}f>>= +1;g>>=1;h>>=1;c>>=1}}}for(a=0;a<m.length;a++)l.push(sO(m[a],-1));return l}function hU(a,b,c,d){var e=c.Ha.aa(),f=b.a[e];c=f&&!fC(f.N,c)?f:(b=b.b[e])&&!fC(b.N,c)?b:null;return c&&a.a(c,d)?c:null}function iU(a,b,c,d){var e=d.getZoom()-c;if(b!=jC(d)>>e)return!1;b=1<<c;a>=b&&(a-=b);return a==iC(d)>>e}dU.prototype.a=function(a,b){return!b||b.fb(a)?!0:!1};function jU(a,b){dU.call(this,a,b)}F(jU,dU);jU.prototype.a=function(a,b){return gC(a.N)&&a.data&&!UM(a.data)&&!a.b?!1:jU.R.a.call(this,a,b)};function kU(a,b,c,d){this.f=0;this.a={};this.b={};this.g=a;this.h=b;this.c=c;this.i=d}function lU(a,b){a&&fC(a.N,b)||(a=null);return a}function mU(a,b,c){var d=b.N;a.i&&hC(d);var e=gU(a,d);if(!e||!fC(d,e.N)){e=d.Ha.aa();var f=a.a[e];if(!f)a.a[e]=b,a.f++;else if(!fC(f.N,d)){var g=a.b[e];g&&nU(a,a.b,g.N,!1);a.a[e]=b;a.b[e]=f;a.f++}b.a.Oa=!0;b.a.$a=!!c;b.a.Ca=a.c.add(1,function(){nU(a,a.b,d,nU(a,a.a,d,!1))},1);a.g(b);c?EO++:FO++}} +function nU(a,b,c,d){var e=c.Ha.aa(),f=b[e];if(!f||!d&&!fC(f.N,c))return!1;delete b[e];a.f--;a.h(f);Vp(a.c,f.a.Ca);f.a&&f.a.$();f.data&&f.data.$();return!0}function gU(a,b){var c=b.Ha.aa(),d=lU(a.a[c],b);d||(d=lU(a.b[c],b));if(!d||!d.data)return null;Wp(a.c,d.a.Ca);d.b&&Wp(a.c,d.b.a.Ca);return d};function oU(a,b){rc.call(this);this.a={};this.b=new Rp;Tp(this.b,a);this.h=b;this.f=D(this.g,this);this.c=D(function(a){this.dispatchEvent(new TO(this,[a]))},this)}F(oU,rc);oU.prototype.g=function(a){a=a.N;a.f||(a.f=eC(a.a,a.c));a=a.f;var b=this.a[a];b&&0==b.f&&(nc(b),delete this.a[a])};function fU(a,b,c){b=eC(b,c);return a.a[b]||null};function pU(a,b){this.b=a;this.a=b}function qU(a,b,c){"success"==b.getState()?a=rU(a,b.na().N,c):(a=PM(b,function(a){return rU(this,a.na().N,c)},a),a.wait(cN,void 0));return a}function rU(a,b,c){if(b){var d=fU(a.b,b.Ea(),b.ba());if(d&&(b=gU(d,b)))if(a.a.fb(b)){var e=new FM;HM(e,b)}else e=a.a.ic(b,c)}e||(e=new FM,KM(e,""));return e};function sU(a,b,c,d,e,f){this.h=a;this.o=b;this.f=new no(this);Qp(this,this.f);po(this.f,d,"ViewportMissingData",this.i,!1,this);po(this.f,d,"ViewportReady",this.j,!1,this);this.l=e;this.m=f;this.b=!0;this.g=c;this.c=this.a=null}F(sU,Pp);function tU(a,b,c,d,e,f){b=a.h.a(b,c,d,e,a.g,f);b=uU(a,b,!0);if("pending"==b.getState()){var g=a.m;SO(g);b.wait(function(){g.a--;g.b&&0==g.a&&g.b(1)})}a.a&&a.a.cancel();a.a=b;a.b=!1;return a.a} +function uU(a,b,c){for(var d=[],e=0;e<b.length;e++)for(var f=a.o.a(b[e]),g=0;g<f.length;++g){var h=f[g];"success"!=h.getState()&&d.push(h)}if(!d.length)return $M();1==d.length?b=d[0]:(b=RM.apply(null,d),b.wait(cN,void 0));c&&a.l(d);return b}sU.prototype.i=function(a){this.c=a;this.b&&vU(this,a)}; +function vU(a,b){var c=b.mb();for(b=[];0<c.length;){var d=[],e=c[0],f=e.Ea(),g=e.ba();e=[e.Ha];for(var h=1;h<c.length;++h){var k=c[h];Ps(g,k.ba())&&f==k.Ea()?e.push(k.Ha):d.push(k)}b.push(new qQ(e,g,f,2,3,!1,!1));c=d}c=a.a;a.a=uU(a,b,!0);c&&c.cancel()}sU.prototype.j=function(){this.c=null;this.b&&(this.a&&this.a.cancel(),this.a=null)};function wU(a,b,c){this.b=a;this.c=b;this.f=c} +wU.prototype.a=function(a){if(0!=a.b||!a.a.b)return this.b.a(a);for(var b=a.c,c=Array(b.length),d=a.a.b,e=[],f=[],g=0;g<b.length;++g){var h=b[g];xU(h,a.a,d)&&(e.push(h),c[g]=new FM,f.push(c[g]))}if(0==e.length)return this.b.a(a);h=[];d=[];if(e.length<b.length){for(g=0;g<b.length;++g)c[g]||(h.push(b[g]),d.push(g));b=this.b.a(rQ(a,h));for(g=0;g<b.length;++g)c[d[g]]=b[g]}var k=this;this.c.Mb(new yU(function(){for(var b=0;b<e.length;++b){var c=f[b];if("pending"==c.getState()){var d=e[b];var g=k;var h= +d.b,t=d.a,v=d.getZoom(),u=new Mw;By(u).a=h;By(u).b=t;By(u).c=v;wy(u).a=g.f;g=new RR(u,null);HM(c,new pO(new dC(d,a.b,a.a),g))}}}),a.priority);return c};function xU(a,b,c){b=Fs(b.a,a,b.f);a=Fs(c.a,a,c.f).length;if(a==b.length)return!0;for(;a<b.length;++a)if(-1!=b[a])return!1;return!0}function yU(a){this.a=a;this.b=void 0}F(yU,SS);function zU(a,b,c){this.f=a;this.c=b;this.b=c}function AU(a,b){b=b.na();a=a.na();a.b=b;var c=a.data;b=b.data;c.h!==b&&(c.h=b);return a}zU.prototype.a=function(a){var b=this.c.a(a);if(0!=a.b||!a.a.b)return b;a=new qQ(a.c,a.a.b,a.b,a.priority,a.type,a.g,a.f);this.f||(a.type=1);a=this.b.a(a);for(var c=0;c<a.length;++c)b[c]=BU(a[c],b[c]);return b}; +function BU(a,b){var c=new FM;if("success"==a.getState())return LM(b,function(){"error"==b.getState()?KM(c):"success"==b.getState()&&HM(c,AU(b,a))}),c;LM(a,function(){"pending"==c.getState()&&("error"==a.getState()?KM(c):"success"==b.getState()&&HM(c,AU(b,a)))});LM(b,function(){"pending"==c.getState()&&("error"==b.getState()?KM(c):"success"==a.getState()&&HM(c,AU(b,a)))});LM(c,function(){JM(c)&&(b.cancel(),a.cancel())});return c};function CU(a,b){this.c=a;this.b=b}CU.prototype.a=function(a){for(var b=this.b.a(a),c=0;c<b.length;++c){var d=b[c];if("error"!=d.getState()){var e=a.mb()[c];DU(e,d,this.c)}}return b};function DU(a,b,c){MM(b,function(b){b=b.N;if(a&&b&&b.aa()!=a.aa()){b=b.b;for(var d=a.b,f=a.ba().a,g=0;g<b.length;++g){var h=b[g];if(null!==h&&h!=d[g]){var k=c,l=a.Ha,m=d[g],n=Ds(f.a[g]);(k=k.a[n])&&k.a.i(l,m,h)}}}})};function EU(a,b){this.b=a;this.c=b}EU.prototype.a=function(a){if(2==a.type){var b=a.mb();var c=Array(b.length);for(var d=0;d<b.length;d++)c[d]=rU(this.b,b[d],a.priority)}else if(3==a.type)for(c=this.c.a(a),d=0;d<c.length;d++)c[d]=qU(this.b,c[d],a.priority);else c=this.c.a(a);return c};function FU(){this.a=this.c=this.f=100}FU.prototype.b=0;FU.prototype.reset=function(){this.a=this.c=this.f;this.b=0};FU.prototype.na=function(){return this.c};function GU(a){this.result=a;this.a=new FU;this.b=-1};function HU(a,b,c){this.g=a;this.j=b;this.i=c;this.c={};this.f={};this.h=.707+.707*Math.random();this.b=new BP} +HU.prototype.a=function(a){for(var b=a.mb(),c=[],d={},e=[],f=0;f<b.length;++f){var g=b[f];var h=g.aa();h=this.c[h]?this.c[h]:(h=this.f[h])&&h.b>E()?h.result:null;h?(c[f]=h,this.b.a++):B(d[g.aa()])?(h=new FM,KM(h,""),c[f]=h,this.b.a++):(h=this.g.b(g),h=new lS(h,g),h.priority=a.priority,e.push(h),d[g.aa()]=f)}0<e.length&&IU(this,e,d,a.priority,a.g,c);for(f=0;f<b.length;++f)c[f]||(a=b[f].aa(),h=new FM,this.c[a]=h,KM(h,""),c[f]=h,this.b.f++,this.b.c++);return c}; +function IU(a,b,c,d,e,f){var g=E(),h=d+1,k=a.g;a.i.ed(new JU(function(){k.c(b,h,e)}),d);for(var l=0;l<b.length;++l){var m=b[l];a.b.f++;var n=m.N,p=n.aa(),q=new FM;f[c[p]]=q;m.priority=d;KU(a,q,m.result,g);LU(a,n,q,m)}}function KU(a,b,c,d){var e=a.b;LM(b,function(a){JM(a)?(e.i++,c.cancel()):"error"==a.getState()?e.c++:(e.g++,e.b+=E()-d)})} +function LU(a,b,c,d){LM(d.result,function(){if("pending"==c.getState()){var a=b.aa();if("success"==d.result.getState())MU(this,b,c,d),delete this.f[a];else{var f=this.f[a];f||(this.f[a]=new GU(c),f=this.f[a]);if(6>f.a.b){a=f;f=E();var g=this.h,h=a.a.na();B(g)&&(h*=g);a.b=f+h;a=a.a;a.a=Math.min(6400,2*a.a);a.c=Math.min(6400,a.a+0);a.b++}else this.c[a]=f.result,delete this.f[a];KM(c,"")}}},a)} +function MU(a,b,c,d){var e=a.j.a(d);e?(LM(c,function(a){JM(a)&&e.cancel()}),LM(e,function(){if("pending"==c.getState()){var a=e.na();a?HM(c,a):JM(e)||(this.c[b.aa()]=c,KM(c))}},a)):(d=b.aa(),a.c[d]=c,KM(c,""))}function JU(a){this.a=a;this.b=void 0}F(JU,SS);function NU(a,b,c,d,e){this.l=a;this.b=b;this.i=c;this.j=d;this.g=D(this.m,this);this.c=!1;this.f=D(function(){this.c=!1},this);this.h=e.C} +NU.prototype.a=function(a){if((1==a.type||3==a.type)&&!this.c&&WG(this.b)){var b=this;this.j.Mb(new OU(function(){for(var c=a.c,d=a.a,e=new QE,f=d.a,g=0;g<f.a.length;++g){var h=f.a[g],k=b.b,l=Ds(h);k.a[l]&&(k=UE(e),He(k,h),l=b.b,h=Ds(h),(h=(h=l.a[h])?h.c:null)&&(k.data[2]=h))}e.data[3]=4;g=new lE(Ae(e,10));g.data[0]=2;g.data[1]=!0;g=TE(e);g.data[4]=b.h;d.h&&(g.data[1]=d.h);rS(d.g)&&(g.data[2]=d.g);g=c;for(c=[];0<g.length;){d=[];k=g[0];f=k.getZoom();k=[k];for(h=1;h<g.length;++h)l=g[h],f==l.getZoom()? +k.push(l):d.push(l);c.push(k);g=d}for(g=0;g<c.length;++g)if(h=bC(c[g])){f=256*h.oa;d=256*(h.Yc-h.oa+1);k=256*h.xc;h=256*(h.bd-h.xc+1);2048<d&&(f+=(d-2048)/2,d=2048);2048<h&&(k+=(h-2048)/2,h=2048);l=new IE(Ae(new EE(De(e,0)),2));var m=c[g][0].getZoom();l.data[2]=m;m=new ME(Ae(l,0));m.data[0]=f;m.data[1]=k;f=new ME(Ae(l,1));f.data[0]=d;f.data[1]=h}b.l.a(e,1,b.g).wait(b.f)}),0);this.c=!0}return this.i.a(a)}; +NU.prototype.m=function(a,b){if(b){for(var c={},d=Fe(a,1),e=0;e<d;++e){var f=mC(a,e);c[f.wa()]=f}a=Fe(b,0);for(e=0;e<a;++e){var g=new VT(Ee(b,0,e));if(f=c[ze(g,0)])a:{d=this.b;if(f)f=Ds(f);else{if(!xe(g,0))break a;f=d.b[ze(g,0)];if(!f)break a}if(f=d.a[f])f.a.j(g),f.b++}}}};function OU(a){this.a=a;this.b=void 0}F(OU,SS);function PU(a){this.h=a;this.c=[];this.f=[];this.b=[]}PU.prototype.a=function(a){a=this.h.a(a);for(var b=[],c=0;c<a.length;c++){var d=a[c],e=this.c.indexOf(d);0>e?(e=new DP,b.push(e),this.f.push(e),this.c.push(d),this.b.push(!1),d.wait(this.g,this)):(this.f[e].b++,b.push(this.f[e]))}return b};PU.prototype.g=function(a){a=this.c.indexOf(a);this.b[a]=!0;if(0==a)for(;this.b[0];){this.b.shift();a=this.c.shift();var b=this.f.shift();a.na()?HM(b,a.na()):a.getError()&&KM(b,a.getError())}};function QU(a,b){this.b=a;this.c=b}QU.prototype.a=function(a){for(var b=a.mb(),c=Array(b.length),d=[],e=[],f=fU(this.b.c,a.b,a.a),g=0;g<b.length;++g){var h=b[g];var k=this.b;var l=f,m=h,n=m.aa();(n=k.a[n])?(k.b.a++,n.b++,k=n):l?(l=gU(l,m))&&l.data?(k.b.a++,k=new FM,HM(k,l)):k=null:k=null;k?c[g]=k:(d.push(h.Ha),e.push(g))}if(d.length)for(a=rQ(a,d),d=this.c.a(a),g=0;g<d.length;++g)f=e[g],h=b[f],k=d[g],"pending"!=k.getState()?(RU(this.b,k,a.f),c[f]=k):c[f]=SU(this.b,h.aa(),k,a.f);return c}; +function TU(a,b){this.c=a;this.a={};this.b=b}function RU(a,b,c){b=b.na();if(!b)return!1;if(b.data&&b.N){var d=b.N.ba(),e=b.N.Ea();a=a.c;d=eC(e,d);a.a[d]||(a.a[d]=new kU(a.c,a.f,a.b,a.h));mU(a.a[d],b,c)}return!0}function SU(a,b,c,d){var e=new DP;e.wait(function(a){JM(a)&&c.cancel()});a.a[b]=e;c.wait(function(c){delete a.a[b];"pending"==e.getState()&&(RU(a,c,d)?HM(e,c.na()):KM(e,c.getError()))});return e};function UU(a,b){this.c=a;this.b=b}UU.prototype.a=function(a){var b=this.b.a(a),c=Ls(a.a.c);if(c&&(a=MQ(this.c,c,a.priority+1),"pending"==a.getState()))for(c=0;c<b.length;++c){var d=RM(b[c],a);d=NM(d,function(a){return a[0].na()});b[c]=d}return b};function VU(){this.a=new Float32Array(6)}VU.prototype.set=function(a,b,c,d,e,f){this.a[0]=a;this.a[1]=b;this.a[2]=c;this.a[3]=d;this.a[4]=e;this.a[5]=f}; +function WU(a,b,c,d,e){var f=a.a[0],g=a.a[1],h=a.a[2],k=a.a[3],l=a.a[4],m=a.a[5];k<g&&(f=h,h=a.a[0],g=k,k=a.a[1]);m<k&&(l=h,h=a.a[4],m=k,k=a.a[5],k<g&&(h=f,f=a.a[4],k=g,g=a.a[5]));if(m<=b)g<b&&d.push(a);else if(g>=b)e.push(a);else if(a=f+(b-g)/(m-g)*(l-f),k==b){var n=c.get();n.set(f,g,h,k,a,b);d.push(n);n=c.get();n.set(h,k,a,b,l,m);e.push(n)}else if(k<b){var p=h+(b-k)/(m-k)*(l-h);XU(f,g,a,b,p,b,h,k,c,d);n=c.get();n.set(a,b,p,b,l,m);e.push(n)}else p=f+(b-g)/(k-g)*(h-f),n=c.get(),n.set(f,g,a,b,p,b), +d.push(n),XU(a,b,l,m,h,k,p,b,c,e)}function XU(a,b,c,d,e,f,g,h,k,l){if((e-a)*(e-a)+(f-b)*(f-b)<(g-c)*(g-c)+(h-d)*(h-d)){var m=k.get();m.set(a,b,c,d,e,f);l.push(m);m=k.get();m.set(a,b,e,f,g,h)}else m=k.get(),m.set(a,b,c,d,g,h),l.push(m),m=k.get(),m.set(c,d,e,f,g,h);l.push(m)}function YU(){this.hb=new Float32Array(4)}YU.prototype.set=function(a,b,c,d){b<d?(this.hb[0]=a,this.hb[1]=b,this.hb[2]=c,this.hb[3]=d):(this.hb[2]=a,this.hb[3]=b,this.hb[0]=c,this.hb[1]=d)};function ZU(a){this.b=a;this.a=Array(6)}ZU.prototype.mb=function(a,b){var c=this.a[b];c||(c=this.a[b]={});var d=Qs(a);if(a.f){var e=a.a;for(var f=a.f,g=Array(e.a.length),h=0;h<e.a.length;++h){var k=e.a[h],l=e.b[h];l||(l=e.b[h]=Ds(k));k=f.a[l];g[h]=k?k.b:null}e=g}else e=[];f=null;if(h=c[d])if(g=h.wf,e.length==g.length)for(f=h.uf,h=0;h<g.length;++h)if(e[h]!=g[h]){f=null;break}if(f)return f;g=this.b.length;f=Array(g);for(h=0;h<g;++h)f[h]=new dC(this.b[h],b,a);c[d]={wf:e,uf:f};return f};function $U(a,b){this.a=a;this.b=b;this.c=new ZU(a)}function aV(a,b){var c=a.b,d=b.b;if(c.bottom!=d.bottom||c.top!=d.top||c.zoom!=d.zoom)return!1;b=b.a;if(a.a.length!=b.length)return!1;for(c=0;c<a.a.length;++c){d=a.a[c];var e=b[c];if(!e||d.getZoom()!=e.getZoom()||d.b!=e.b||d.a!=e.a)return!1}return!0}$U.prototype.mb=function(a,b){return this.c.mb(a,b)};function bV(a){this.a=a}function cV(a,b){if(!b)return!1;b=b.a;if(a.a.length!=b.length)return!1;for(var c=0;c<a.a.length;++c)if(!aV(a.a[c],b[c]))return!1;return!0};function dV(a){this.c=new $J(YU);this.a=new $J(VU);this.h=new SF;this.f=new SF;this.b=new bV([]);this.g=a.ja} +function eV(a,b,c){var d=b.c,e=.02*b.a,f=[],g=0,h=b.a,k=Math.floor(pQ(a,b,c)+1E-6);if(b.b){var l=b.b,m=b.g;if(-.7854<=l&&.7854>=l&&1.0472>=m)k=Math.floor(fV(a,b,c,0)+1E-6)-(m<.1828/l?0:1);else{for(c=k;0<=c&&g<h;){var n=Math.round(gV(c,k,h,b));(0==g||n-g>=e)&&f.push(new MP(g,n,c));g=n;--c}var p=c+1}}f.length?n===h&&(f[f.length-1].top=h,f[f.length-1].zoom=p):f.push(new MP(0,h,k));e=[];for(g=0;g<f.length;++g){n=a;var q=d;h=f[g];var t=b;k=1<<h.zoom;var v=new vN;m=new eo;p=t.a-h.top;var u=t.a-h.bottom; +hV(t,0,p,k,k,v,m);var w=m.x;c=m.y;hV(t,q,p,k,k,v,m);var y=m.x;p=m.y;hV(t,0,u,k,k,v,m);var A=m.x;l=m.y;hV(t,q,u,k,k,v,m);q=m.x;m=m.y;t=n.a.get();t.set(w,c,y,p,A,l);w=n.a.get();w.set(A,l,q,m,y,p);w=[t,w];y=[];for(A=0;2>A;++A)WU(w[A],k,n.a,y,[]);w=[];for(A=0;A<y.length;++A)WU(y[A],0,n.a,[],w);if(0==w.length)h=null;else if(y=c,y>p&&(y=p),y>l&&(y=l),y>m&&(y=m),c<p&&(c=p),c<l&&(c=l),c<m&&(c=m),y=Yn(y,0,k),c=Yn(c,0,k),k=iV(n,w,y,c,k),aK(n.a),0==k.length)h=null;else{n=Array(k.length>>1);for(c=0;c<k.length;c+= +2)n[c>>1]=new kC(k[c],k[c+1],h.zoom);h=new $U(n,h)}h&&e.push(h)}return new bV(e)}function hV(a,b,c,d,e,f,g){xN(a,b,c,f);a=e/(2*Math.PI);b=f.origin[2]/f.a[2];g.x=d/2+d/(2*Math.PI)*(f.origin[0]-f.a[0]*b);g.y=e/2-(f.origin[1]-f.a[1]*b)*a} +function iV(a,b,c,d,e){for(var f=[],g=0;g<b.length;++g){var h=b[g],k=a.c,l=f,m=k.get();m.set(h.a[0],h.a[1],h.a[2],h.a[3]);l.push(m);m=k.get();m.set(h.a[0],h.a[1],h.a[4],h.a[5]);l.push(m);m=k.get();m.set(h.a[2],h.a[3],h.a[4],h.a[5]);l.push(m)}if(0==f.length)return[];b=[];d=Math.floor(d-.0078125);for(c=Math.floor(c+.0078125);c<=d;++c){k=1E100;h=0;l=c+1;for(g=0;g<f.length;++g){m=f[g].hb[1];var n=f[g].hb[3];if(!(m>l||n<c)){var p=n-m;if(0!=p){var q=f[g].hb[0],t=f[g].hb[2];p=(t-q)/p;n>l&&(t=q+(l-m)*p); +m<c&&(q+=(c-m)*p);q<t?(q<k&&(k=q),t>h&&(h=t)):(t<k&&(k=t),q>h&&(h=q))}}}k=Math.floor(k+.0078125);h=Math.floor(h-.0078125);h-k>=e&&(k=0,h=Math.max(0,e-1));for(g=k;g<=h;g++)k=g%e,0>k&&(k+=e),b.push(k),b.push(c)}aK(a.c);return b}function pQ(a,b,c){var d=fV(a,b,c);a=fV(a,b,c,0);return d<a?a:d}function fV(a,b,c,d){var e=0;1<a.g&&(e=a.g-1);1>c&&(e=Math.log(1/c)/Math.LN2,e-=.5,e=0<e?e:0);a=Math.log(1/mQ(b,b.a,d)*(tN/1/256))/Math.LN2;a-=e;22<a&&(a=22);0>a&&(a=0);return a} +function gV(a,b,c,d){a=Math.floor(a)-.5;var e=1/Math.tan(d.g/2);var f=d.a;var g=d.b,h=e*Math.cos(g)/Math.sin(g);b=-Math.sqrt(2/f*d.f*e/(Math.pow(2,b-a)*mQ(d,c)))/Math.sin(g);a=h+b;h-=b;f=(1-(a<h?-1.01>a||1.01<a?h:a:-1.01>h||1.01<h?a:h))*f/2;return 0>f||isNaN(f)||Infinity==f?c:c-f};function jV(a,b){jG(b,3,kV);var c=kV,d=kV;d[0]=-c[0];d[1]=-c[1];d[2]=-c[2];d[3]=-c[3];for(c=0;3>c;c++){d=2*c;jG(b,c,lV);var e=a[d],f=e,g=kV,h=lV;f[0]=g[0]-h[0];f[1]=g[1]-h[1];f[2]=g[2]-h[2];f[3]=g[3]-h[3];fG(e,1/Math.sqrt(e[0]*e[0]+e[1]*e[1]+e[2]*e[2]),e);e=d=a[d+1];f=kV;g=lV;e[0]=f[0]+g[0];e[1]=f[1]+g[1];e[2]=f[2]+g[2];e[3]=f[3]+g[3];fG(d,1/Math.sqrt(d[0]*d[0]+d[1]*d[1]+d[2]*d[2]),d)}}var kV=eG(),lV=eG();function mV(){this.c=new SF;this.f=new SF;this.a=new bV([]);this.g=new hP;this.b=[eG(),eG(),eG(),eG(),eG(),eG()]}var nV=[WF(),WF(),WF(),WF()]; +function oV(a,b){var c=[];b=[b];for(var d={};b.length;){var e=b.shift();if(!d[e.aa()]){d[e.aa()]=!0;var f=e;for(var g=0;4>g;g++){zG(f.b+g%2,f.a+(g>>1),f.getZoom(),nV[g]);var h=nV[g];xG(h[0],2*Math.atan(Math.exp(h[1]))-Math.PI/2,6371010*h[2],nV[g])}f=nV;a:{g=a.b;h=0;b:for(;6>h;++h){for(var k=0;k<f.length;k++){var l=f[k];if(0==(63&1<<h)||0>=cG(g[h],l)+g[h][3])continue b}f=!1;break a}f=!0}if(f){c.push(e);if(100<c.length)break;f=b;g=Math.pow(2,e.getZoom());h=(e.b+1)%g;f.push(new kC((e.b+g-1)%g,e.a,e.getZoom())); +f.push(new kC(h,e.a,e.getZoom()));if(0==e.a){if(256>g)for(h=0;h<g;h++)f.push(new kC(h,e.a,e.getZoom()))}else f.push(new kC(e.b,e.a-1,e.getZoom()));if(e.a==g-1){if(256>g)for(h=0;h<g;h++)f.push(new kC(h,e.a,e.getZoom()))}else f.push(new kC(e.b,e.a+1,e.getZoom()))}}}return c}function oQ(a){return Math.max(3,Math.log(a.a/256/(2*a.f*Math.tan(a.g/2))*2*Math.PI)/Math.LN2)};function pV(a){this.a=new dV(a);this.b=new mV} +function tQ(a,b,c,d){if(d){c=a.b;jQ(b,c.f);a=!1;TF(c.c,c.f)||(jQ(b,c.c),a=!0);if(a){a=b.a;d=Math.floor(oQ(b)+1E-6);var e=gG(),f=gG();eP(b,e,f);b=gG();lG(f,b);f=WF();var g=WF();sG(b,f);jV(c.b,e);e=nV[0];bG(f,e);var h=c.b[5];h[0]=-e[0];h[1]=-e[1];h[2]=-e[2];h[3]=0;e=WF();e[2]=-1;mG(b,e,g);ZF(g,f,g);bG(g,g);b=new vN(f,g);kP(c.g,b.origin,b.a,e);b=Math.atan2(e[1],e[0])/Math.PI;f=Math.PI-Math.log(Math.tan(Math.PI/4+Math.asin(Math.min(.999,Math.max(-.999,e[2]/6371010)))/2));f=.5*f/Math.PI;f=Math.min(1,Math.max(0, +f));b=Math.floor((b+1)/2*Math.pow(2,d));f=Math.floor(f*Math.pow(2,d));b=Math.min(b,Math.pow(2,d)-1);f=Math.min(f,Math.pow(2,d)-1);d=new kC(b,f,d);for(b=oV(c,d);100<b.length;)d=new kC(d.b>>1,d.a>>1,d.getZoom()-1),b=oV(c,d);a=new $U(b,new MP(0,a,d.getZoom()));a=new bV([a]);c.a&&cV(c.a,a)||(c.a=a)}c=c.a}else a=a.a,d=jQ(b,a.h),f=!1,TF(a.f,d)||(jQ(b,a.f),f=!0),f&&(c=eV(a,b,c),a.b&&cV(a.b,c)||(a.b=c)),c=a.b;return c};function pH(a,b,c){rc.call(this);this.a=a;this.G=b;Vs(Ss.sc(),a.a);this.h=new or;pr(this.h,"");this.i=a.B;this.I=new NB(this.h,tS(a.v));this.oc=new OB(this.h,tS(a.v));Jb(this,this.oc);this.l=qV(this,b,c,this.oc.c);b=500;pb&&2==a.c&&(b=Math.min(b,250));this.c=new oU(b,this.i);this.D=new TU(this.c,this.l.b);this.f=this.i?new jU(this.c,!1):new dU(this.c,!1);this.H=0;this.B=a.viewport||new pV(a);this.b=[];this.j=[];this.g=a.H;this.J=a.m&&this.g?rV(this,c):null;this.C=a.W;this.v=a.m;this.K=[];this.m=null; +this.A=new IQ(this.a,c,this.oc);var d=this;this.Pf=new eS(this.A,function(){sV(d,!0)});a=new no(this);Jb(this,a);a.cb(this.f,"ViewportReady",this.dispatchEvent);a.cb(this.f,"ViewportLoaded",this.dispatchEvent);a.cb(this.f,"ViewportMissingData",this.dispatchEvent);a.cb(this.c,"DataEvent",this.dispatchEvent)}F(pH,rc);pH.prototype.s=function(){return this.H}; +function qV(a,b,c,d){d=new IT(a.a,c,b,d);var e=new mS(c,1,new vS(a.a.U),a.a.V),f=a.a.j,g=a.a;if(!g.A){var h=new QE,k=UE(h);k.data[1]="shading";k.data[0]=5;k=UE(h);k.data[1]="contours";k.data[0]=6;UE(h);h.data[3]=0;(new OD(Ae(h,4))).data[5]=!0;(new OD(Ae(h,4))).data[4]=g.la;k=TE(h);k.data[4]=g.C;(new Sn(De(k,11))).data[0]=67;(new Sn(De(k,11))).data[0]=63;(new Sn(De(k,11))).data[0]=3;g.A=h}c=new mS(c,2,new uS(f,g.A),a.a.a);return new HU(new jS([d,e,c]),new OT(b,[new ST(b,Yn(a.a.la,1,2),a.h,a.I,a.a.S? +a.a.f:void 0),new QT(b)]),b)}function rV(a,b){var c=tS(a.a.K);a=new YT(b,c,a.a.a);return new ZT(new TT(a))}function sV(a,b){a.H++;a.m&&a.m(b)}function tV(a,b){var c=new pU(a.c,b),d=a.l;a.v&&a.g&&(d=new CU(a.g,d));var e=d;a.v&&a.i&&(e=new wU(e,a.G,Yn(a.a.la,1,2)));a.v&&a.J&&a.g&&(e=new NU(a.J,a.g,e,a.G,a.a));a.C&&(e=new PU(e));e=new UU(a.A,e);a.i&&(b=b.Je(),d=new QU(a.D,d),a.C&&(d=new PU(d)),b&&(d=new UU(a.A,d),d=new EU(c,d)),e=new zU(b,e,d));e=new QU(a.D,e);return e=new EU(c,e)} +pH.prototype.Xc=function(a,b,c){b=tV(this,b);var d=this;a=new sU(a,b,this.B,this.f,function(a){for(var b=0;b<a.length;++b)MM(a[b],function(){sV(d,!1)},d)},c,[this.l]);Jb(this,a);this.K.push(a);return a}; +pH.prototype.getData=function(a,b,c,d,e,f,g,h){var k=tQ(this.B,a,b,f),l=this.f,m=!!h,n=[],p=[];h=[];k=k.a;for(var q=0;q<d.length;++q){for(var t=[],v=0;v<k.length;++v){var u=k[v],w=u.mb(c,d[q]);w=eU(l,c,d[q],w,e,m,n,p,g);t.push(new cS(w,u.b))}h.push(new dS(t))}0==n.length&&(l.dispatchEvent(new aU(l)),0==p.length&&l.dispatchEvent(new cU(l)));0==n.length&&0==p.length||l.dispatchEvent(new bU(l,n.concat(p)));c=[];for(d=0;d<this.b.length;++d)if(e=this.b[d]){n="cat"+String(2+d);p=tQ(this.B,a,b,f);l=g;m= +new On;m.data[1]=n;m.data[0]=2;n=p.a;p=n.length;k=[];for(q=0;q<p;++q){t=[];v=n[q].a;u=m;w=l;var y=[],A=Array(v.length);e.mb(v,A);for(var z=0;z<A.length;++z){var C=A[z];if(C){var I=fU(this.c,C.Ea(),C.ba());(I=I?gU(I,C):null)&&I.data&&I.a&&(C=uV(C,u),C=new pO(C,I.data),C.a=I.a,I=!0,w&&(I=vV(C,w)),I&&y.push(C))}}u=y;0<u.length&&(t=u.concat(t));u=l;w=[];y=Array(v.length);A=new Os(void 0,new Es([m]));for(z=0;z<v.length;++z)if(C=y[z])I=new dC(v[z],4,A),C=new RR(C,this.h,void 0,this.I),I=new pO(I,C),C=!0, +u&&(C=vV(I,u)),C&&w.push(I);v=w;0<v.length&&(t=v.concat(t));t.length&&k.push(new cS(t,n[q].b))}c.push(new dS(k))}return h.concat(c)};function uV(a,b){var c=a.ba(),d=new Es(c.a.a.slice());d.a.push(b);d.b.push(void 0);return new dC(a.Ha,a.a,new Os(c.c,d,c.h,c.g,c.f||void 0,c.b||void 0))}function vV(a,b){return b.fb(a)?!0:"success"==b.ic(a,2,a.a.s).getState()}function zP(a,b){a.m=b} +pH.prototype.X=function(){for(var a=0;a<this.b.length;++a){var b=this.b[a];if(b)a:for(var c=0;c<this.b.length;++c)if(this.b[c]===b){this.b[c]=null;this.j[c]&&mc(this.j[c]);this.j[c]=null;sV(this,!0);break a}}pH.R.X.call(this)};NG(1,new function(){});NG(2,new function(){});var wV=[],xV=[];function yV(a,b){var c=a.wa();if(void 0==wV[c]){wV[c]=[];xV[c]=[];var d=new no;d.cc(a.j,"webglcontextlost",function(){wV[c]=null;xV[c]=null});Kb(a,function(){wV[c]=null;xV[c]=null;d.$()})}a=wV[c].indexOf(b);-1!=a?a=xV[c][a]:(a=new b,wV[c].push(b),xV[c].push(a));return a} +function zV(a,b,c,d){var e=a.createShader(35632);a.shaderSource(e,c);a.compileShader(e);c=a.createShader(35633);a.shaderSource(c,b);a.compileShader(c);b=a.createProgram();a.attachShader(b,c);a.attachShader(b,e);for(e=0;e<d.length;e++)a.bindAttribLocation(b,e,d[e]);a.linkProgram(b);return b};function AV(){this.o=this.b=this.ea=this.C=this.m=this.s=this.v=this.i=this.h=this.g=this.f=this.c=this.D=this.j=this.l=this.G=this.H=this.u=this.A=this.B=null;this.I={}}var BV="#define _b 8\n#define _c 8000\n#define _d "+QB+"\n#define _e 2\n#define _f 16\n#define _g 8\n#define _h vec4(0., 0., 0., 0.2)\n#define _i 2\n#define _j 9\n#define _k 6\n#define _l 3\n#define _m 0\n#define _n 1\n#define _o 2\n#define _p 4\n#define _q 5\n#define _r 12\n#define _s 0\n#define _t 8\n#define _u 2\n#define _v 1\n#define _w 22\n\n"; +AV.prototype.a=function(a,b){b="#define _a "+b.f+"\n";var c=this.I[b];c||(c=zV(a,BV+b+"precision highp float;uniform vec4 d,f,j;uniform sampler2D e,g;vec2 M(vec2 A,float B){float C=float(_r);A.y=C*A.y+B;return (A+.5)*d.zw;}vec2 N(vec4 A){return vec2(A.g+A.b*256.,A.a);}vec2 O(vec2 u){vec4 A=texture2D(g,(floor(u*65535.+.5)+.5)*f.zw);A=floor(A*255.+.5);return N(A);}\n#if _a==1\nuniform float h;varying vec3 i;\n#endif\nuniform vec3 k,l;uniform mat4 m;uniform float o,s;\n#if _a==1\nuniform mat4 p;vec3 P(vec3 A){const float B=6371010.;float C,D,E,F,G,H,I,J,K,L;C=A.x;D=exp(A.y);E=D*D;F=2.*D/(1.+E);G=(E-1.)/(1.+E);H=A.z*B*F;I=H+B;J=I*F*cos(C);K=I*F*sin(C);L=I*G;return vec3(J,K,L);}vec4 Q(vec3 A){vec4 B,D;B=m*vec4(A,1);vec3 t,C;t=A;t/=o;t+=k+l;t.xy-=.5;t.y=-t.y;t*=3.141592653589793*2.;C=P(t);D=p*vec4(C,1);D/=D.w;B/=B.w;return mix(B,D,h);}vec3 R(vec3 t){t/=o;t+=k+l;t.xy-=.5;t.y=-t.y;t*=3.141592653589793*2.;vec3 A=mat3(p)*P(t);return normalize(A);}\n#else\nvec4 Q(vec3 A){return m*vec4(A,1);}\n#endif\nvec3 S(vec3 A,vec3 B){vec3 t=A-k+(B-l);return t*o;}vec3 T(vec2 A,vec2 B,vec2 C){vec3 D,E;D=vec3(A.x,B.x,C.x)*65535.+.5;\n#if _a==1\nD-=fract(D);\n#else\nD=floor(D);\n#endif\nD=D/65536.;D=(fract(D+.5)-.5)*4.;E=vec3(A.y,B.y,C.y)*65535.;E/=1073741824.;return S(D,E);}float U(vec4 A){float B,C;B=1./float(_w+1);C=1.-B-j.z*B;return A.z*B+A.w*C;}void V(vec3 A){\n#if _a==1\ni=R(A);\n#endif\n}precision highp float;varying vec4 r;attribute vec4 t;attribute vec2 u;attribute float v;uniform vec2 w;void main(){vec3 A=T(t.yx,t.wz,vec2(0));V(A);gl_Position=Q(A);gl_Position.xy+=w*gl_Position.w;gl_Position.z=gl_Position.w*v;vec2 B,C;B=O(u);C=M(B,float(_l));r=texture2D(e,C);gl_Position.z=U(gl_Position);gl_Position.xy*=sign(r.a*abs(s-floor(r.a)));}", +BV+b+"precision highp float;precision highp float;\n#if _a==1\nuniform float h;varying vec3 i;\n#endif\nfloat C(){\n#if _a==1\nfloat x,A;x=dot(i,vec3(-1.,1,-1.));A=clamp((x-.5)/4.+1.,.5,1.);return mix(1.,A,h);\n#else\nreturn 1.;\n#endif\n}precision highp float;varying vec4 r;void main(){float x=C();gl_FragColor=vec4(r.rgb*x,r.a);}",["t","u","v"]),this.I[b]=c);this.b=c}; +AV.prototype.bind=function(a,b){this.a(a,b);if(this.o!=this.b){var c=this.b,d=function(b){return a.getUniformLocation(c,b)};this.B=d("a");this.A=d("b");this.u=d("c");this.H=d("d");this.G=d("e");this.l=d("f");this.j=d("g");this.D=d("h");this.c=d("j");this.f=d("k");this.g=d("l");this.h=d("m");this.i=d("n");this.v=d("o");this.s=d("p");this.m=d("q");this.C=d("s");this.ea=d("w");this.o=this.b}a.useProgram(this.o);this.B&&a.uniform4fv(this.B,b.s.value);this.A&&a.uniform4fv(this.A,b.o.value);this.u&&a.uniform1f(this.u, +b.b.value);this.H&&a.uniform4fv(this.H,b.B.value);this.G&&a.uniform1i(this.G,b.A.value);this.l&&a.uniform4fv(this.l,b.v.value);this.j&&a.uniform1i(this.j,b.u.value);this.D&&a.uniform1f(this.D,b.c.value);this.c&&a.uniform4fv(this.c,b.C.value);this.f&&a.uniform3fv(this.f,b.g.value);this.g&&a.uniform3fv(this.g,b.h.value);this.h&&a.uniformMatrix4fv(this.h,!1,b.i.value);this.i&&a.uniform1f(this.i,b.j.value);this.v&&a.uniform1f(this.v,b.m.value);this.s&&a.uniformMatrix4fv(this.s,!1,b.a.value);this.m&&a.uniform1i(this.m, +b.l.value);this.C&&a.uniform1f(this.C,b.La.value);this.ea&&a.uniform2fv(this.ea,b.ea.value)};var CV={5120:1,5121:1,5122:2,5123:2,5124:4,5125:4,5126:4};function DV(a,b,c,d,e){this.index=a;this.arity=b;this.a=c;this.b=d;this.c=e}function EV(a,b){for(var c=[],d=0,e=[],f=0,g=0;g<b.length;g++){var h=b[g][0],k=b[g][1],l=2<b[g].length?b[g][2]:!1,m=h*CV[k];h=new DV(g,h,k,5126!=k,l?f:d);m=m+3&-4;l?(e.push(h),f+=m):(c.push(h),d+=m)}this.c=c;this.b=a;this.a=d;this.f=d/4;this.h=d*a/4;this.g=e;this.i=f} +function FV(a,b){if(b.g.length){for(var c=mq(a),d=0;d<b.c.length;d++){var e=b.c[d];a.enableVertexAttribArray(e.index);c.vertexAttribDivisorANGLE(e.index,1)}for(d=0;d<b.g.length;d++)e=b.g[d],a.enableVertexAttribArray(e.index),c.vertexAttribDivisorANGLE(e.index,0)}else for(d=0;d<b.c.length;d++)e=b.c[d],a.enableVertexAttribArray(e.index)} +function GV(a,b){if(b.g.length){for(var c=mq(a),d=0;d<b.c.length;d++){var e=b.c[d];a.disableVertexAttribArray(e.index);c.vertexAttribDivisorANGLE(e.index,0)}for(d=0;d<b.g.length;d++)e=b.g[d],a.disableVertexAttribArray(e.index),c.vertexAttribDivisorANGLE(e.index,0)}else for(d=0;d<b.c.length;d++)e=b.c[d],a.disableVertexAttribArray(e.index)}function HV(a,b){var c=a.createBuffer(),d=a.a.b;B(d)||(d=null);a.a.Ua(c);a.bufferData(34962,new Float32Array(b),35044);a.a.Ua(d);return c} +function IV(a,b,c,d,e,f){var g=[];b=(b-a)/c;e=(e-d)/f;for(var h=0;h<f;h++)for(var k=d+e*h,l=d+e*(h+1),m=0;m<c;m++){var n=a+b*m,p=a+b*(m+1);g.push(n);g.push(k);g.push(n);g.push(l);g.push(p);g.push(k);g.push(p);g.push(k);g.push(n);g.push(l);g.push(p);g.push(l)}return g}function JV(a,b,c,d,e,f,g){b=IV(b,c,d,e,f,g);return{buffer:HV(a,b),size:b.length/2}} +function KV(a,b,c,d){var e=!1;a.a.b!=b&&(a.a.Ua(b),e=!0);if(e||B(d))for(b=B(d)?d:0,d=0;d<c.c.length;d++)e=c.c[d],a.vertexAttribPointer(e.index,e.arity,e.a,e.b,c.a,e.c+b)}function LV(a,b,c){a.a.b!=b&&a.a.Ua(b);for(b=0;b<c.g.length;b++){var d=c.g[b];a.vertexAttribPointer(d.index,d.arity,d.a,d.b,c.i,d.c)}}function MV(a,b,c){c.a!=a.a.b&&KV(a,c.a,b);a.drawArrays(4,c.b,c.c)}function NV(a,b,c,d){c&&MV(a,b,c);d&&MV(a,b,d)} +function OV(a,b,c,d){var e=mq(a);c&&(KV(a,c.a,b,c.b*b.a),e.drawArraysInstancedANGLE(4,0,6,c.c));d&&(KV(a,d.a,b,d.b*b.a),e.drawArraysInstancedANGLE(4,0,6,d.c))}function PV(a,b,c){c=B(c)?c:b.length;var d=lr(a,4*c);c<b.length&&(b=b.subarray(0,c));nr(a,d,b);return d} +function QV(a,b,c,d,e,f){var g=b.l,h=b.o,k=h.left,l=b.j-h.right,m=h.bottom;h=b.i-h.top;f>h&&(f=h);e>l&&(e=l);d<m&&(d=m);c<k&&(c=k);c-=.01;e+=.01;f+=.01;d-=.01;e<c&&(e=c);f<d&&(f=d);c=c*g+b.a.x;f=f*g+b.a.y;e=e*g+b.a.x;d=d*g+b.a.y;c=c+.5|0;d=d+.5|0;a.scissor(c,d,(e+.5|0)-c,(f+.5|0)-d)}function RV(a,b){QV(a,b,0,0,b.j,b.i)} +function SV(a,b,c,d,e,f){if(b.B)a.stencilFunc(514,c,255);else{c=d-b.H;var g=e+256*f-b.I;d=d+256*f-b.H;e-=b.I;c*=b.m;d*=b.m;g*=b.m;e*=b.m;c+=b.j/2;d+=b.j/2;g=-g+b.i/2;e=-e+b.i/2;QV(a,b,c,g,d,e)}} +function TV(a,b,c,d,e,f,g){switch(c){case 1:a.colorMask(!1,!1,!1,!1);a.enable(3042);break;case 2:a.colorMask(!0,!0,!0,!0);a.disable(3042);break;case 3:a.colorMask(!0,!0,!0,!0);a.enable(3042);a.blendFuncSeparate(770,771,1,771);a.blendEquation(32774);break;case 4:a.colorMask(!0,!0,!0,!0);a.enable(3042);a.blendFuncSeparate(1,771,1,771);a.blendEquation(32774);break;case 5:a.colorMask(!0,!0,!0,!0),a.enable(3042),a.blendFuncSeparate(770,0,1,0),a.blendEquation(32774)}switch(d){case 1:a.depthMask(!1);a.disable(2929); +break;case 2:a.depthMask(!0);a.disable(2929);break;case 3:a.depthMask(!0);a.enable(2929);a.depthFunc(515);break;case 4:a.depthMask(!0),a.enable(2929),a.depthFunc(513)}2==e&&0==b.B&&(e=1);switch(e){case 1:a.disable(2960);a.stencilOp(7680,7680,7680);break;case 2:a.enable(2960);a.stencilOp(7680,7680,7680);break;case 3:a.enable(2960);a.stencilOp(7680,7681,7681);break;case 4:a.enable(2960),a.stencilFunc(514,0,4294967295),a.stencilOp(7680,7680,7682)}switch(f){case 2:a.enable(3089);RV(a,b);break;case 1:a.disable(3089)}switch(g){case 1:a.disable(2884); +break;case 2:a.enable(2884);a.cullFace(1029);break;case 3:a.enable(2884),a.cullFace(1028)}}function UV(a,b,c){c&&(c&16384&&(a.colorMask(!0,!0,!0,!0),b=b.clearColor,a.clearColor(b[0],b[1],b[2],b[3])),c&256&&(a.depthMask(!0),a.clearDepth(1)),c&1024&&a.clearStencil(0),a.disable(3089),a.clear(c))};function VV(a,b,c){var d=a.a,e=a.data;if(UM(e))return!1;22<c&&(c=22);a=Math.floor(c);c=c!=a;var f=b.c,g=c?a+.5:a;if(f==d.Wa&&g==d.Za)return d.Ja;var h=!1;e=e.b.a[2];for(var k=0;k<e.length;k++){var l=e[k].ka(),m=GK(d.f,l);l=WV(RA(b.a,m),c,a);if(2==l){h=!0;break}if(ZB(b)){m=WV(RA(b.b,m),c,a);if(2==m){h=!0;break}if((0==m||0==l)&&m!=l){h=!0;break}}}d.Ja=h;d.Wa=f;d.Za=g;return d.Ja}function WV(a,b,c){return a.D?0<(aA(a,c)>>24&255)%255||b&&0<(aA(a,c+1)>>24&255)%255?2:1:0};function XV(a,b){this.u=a;this.v=b;this.D=yV(a,AV);this.a=new EV(3,[[4,5123],[2,5123],[2,5123]]);this.A=new ir(this.u,this.a.a,this.a.b,65536);this.C=new sI(1,!0);this.B=new sI(1,!0);this.c=[];this.f=[];this.h=[];this.g=[];this.i=[];this.j=[];this.l=[];this.o=[];this.m=[];this.s=[]} +function YV(a,b,c,d){var e=a.u,f=a.v;if(d){var g=a.j;if(c){var h=a.o;c=a.s}else h=a.l,c=a.m}else g=a.c,c?(h=a.h,c=a.i):(h=a.f,c=a.g);if(g.length){TV(e,b,3,d?4:3,2,2,2);f.La.set(d?1:0);d=g;e=h;f=a.u;var k=a.v;h=a.D;g=a.a;FV(f,g);k.ea.set(b.Va.x,b.Va.y);var l=hq(f);h.bind(l,k);for(k=0;k<e.length;k++){var m=d[k],n=e[k]||[],p=c[k]||[];l.uniform4f(h.c,m.g,m.h,m.m,m.b);SV(f,b,m.Z,m.g,m.h,m.b);for(m=0;m<n.length;m++)MV(f,g,n[m]);for(m=0;m<p.length;m++)MV(f,g,p[m])}GV(f,a.a);iq(f)}} +XV.prototype.b=function(a,b){var c=a.a,d=a.data,e=d.a;if(c.ga||!e||!Gy(e)||!ly(Hy(e)))return 2;var f=rI(d.getZoom(),b),g=this.C;b=this.B;g.reset(c.g,c.h,c.b,d.c);b.reset(c.g,c.h,c.b,d.c);g.i=f;b.i=f;d=d.b.a[2];for(var h=a.a.c,k=a.data.b.a[5],l=a=0;l<k.length;l++){var m=k[l].za;m>a&&(a=m)}e=Hy(e).a;for(k=0;k<e.length;k++)if(l=e[k],(m=null==l.c?!1:l.c)||null!=l.a){var n=d[k].ka(),p=d[k].za,q=l.getExtension(177034656);f&&q&&(null==q.a?0:q.a)||(q=p<a?g:b,n=ZV(h,n),q.o=oI(n.x,n.y),q.m=oI(65535-p,0),m? +(uI(q),wI(q,0,0),wI(q,4096,0),wI(q,4096,4096),wI(q,0,4096),vI(q,0,0)):(l=ux(l),LI(l,q,f)))}if(0!=g.b||0!=g.a)f=PV(this.A,g.h.subarray(0,g.b)),jO(c.a,f),c.ga=f.a;if(0!=b.b||0!=b.a)f=PV(this.A,b.h.subarray(0,b.b)),jO(c.a,f),c.Ba=f.a;return 2};function $V(){this.D=this.c=this.h=this.g=this.m=this.f=this.i=this.j=this.l=this.ea=this.C=this.G=this.I=this.v=this.u=this.s=this.o=this.b=this.L=this.A=this.B=this.M=this.O=this.H=this.J=this.K=null;this.P={}}var aW="#define _b 8\n#define _c 8000\n#define _d "+QB+"\n#define _e 2\n#define _f 16\n#define _g 8\n#define _h vec4(0., 0., 0., 0.2)\n#define _i 2\n#define _j 9\n#define _k 6\n#define _l 3\n#define _m 0\n#define _n 1\n#define _o 2\n#define _p 4\n#define _q 5\n#define _r 12\n#define _s 0\n#define _t 8\n#define _u 2\n#define _v 1\n#define _w 22\n\n"; +$V.prototype.a=function(a,b){b="#define _a "+b.f+"\n";var c=this.P[b];c||(c=zV(a,aW+b+"precision highp float;uniform vec4 d,f,j;uniform sampler2D e,g;vec2 S(vec2 G,float H){float I=float(_r);G.y=I*G.y+H;return (G+.5)*d.zw;}vec2 T(vec4 G){return vec2(G.g+G.b*256.,G.a);}vec2 U(vec2 u){vec4 G=texture2D(g,(floor(u*65535.+.5)+.5)*f.zw);G=floor(G*255.+.5);return T(G);}\n#if _a==1\nuniform float h;varying vec3 i;\n#endif\nuniform vec3 k,l,w,x,A,B,C,D;uniform mat4 m;uniform float o,E;\n#if _a==1\nuniform mat4 p;vec3 V(vec3 G){const float H=6371010.;float I,J,K,L,M,N,O,P,Q,R;I=G.x;J=exp(G.y);K=J*J;L=2.*J/(1.+K);M=(K-1.)/(1.+K);N=G.z*H*L;O=N+H;P=O*L*cos(I);Q=O*L*sin(I);R=O*M;return vec3(P,Q,R);}vec4 W(vec3 G){vec4 H,K;H=m*vec4(G,1);vec3 I,J;I=G;I/=o;I+=k+l;I.xy-=.5;I.y=-I.y;I*=3.141592653589793*2.;J=V(I);K=p*vec4(J,1);K/=K.w;H/=H.w;return mix(H,K,h);}\n#else\nvec4 W(vec3 G){return m*vec4(G,1);}\n#endif\nvec3 X(vec3 G,vec3 H){vec3 I=G-k+(H-l);return I*o;}vec3 Y(vec3 G){vec3 H,I;H=vec3(j.x,j.y,0);I=G*j.w;I.xy*=1./float(_f);return X(H,I);}vec4 Z(vec3 G){vec3 H=Y(G);return W(H);}varying vec4 r;attribute vec4 s;attribute vec4 t;attribute vec2 u;uniform vec2 v;vec4 aa(vec4 G,vec3 H,float I){float J,L,N;J=mix(E,1.,I);vec3 K,M,O,P;K=mix(A,x,(H.z+1.)*.5)*J;L=clamp(dot(H,C),0.,1.);M=w*L*J;N=clamp(dot(H,D),0.,1.);O=B*N;P=K+M-K*M;P=P+O-P*O;G.rgb*=P;return G;}void main(){vec3 G,L;G=floor(s.xyz*32767.+.5);G.z/=float(_f);gl_Position=Z(G);vec4 H,K;H=Z(vec3(G.xy,0));float I=clamp((H.z+H.w)/(H.w-gl_Position.w+H.z-gl_Position.z+.001),0.,1.);gl_Position=Z(vec3(G.xy,I*G.z));gl_Position.xy+=v*gl_Position.w;vec2 J=U(u);K=texture2D(e,S(J,float(_l)));L=normalize(t.xyz-127./254.);r=aa(K,L,clamp(s.z/s.w,0.,1.));}", +aW+b+"precision highp float;precision highp float;\n#if _a==1\nvarying vec3 i;\n#endif\nvarying vec4 r;void main(){gl_FragColor=r;}",["s","t","u"]),this.P[b]=c);this.c=c}; +$V.prototype.bind=function(a,b){this.a(a,b);if(this.D!=this.c){var c=this.c,d=function(b){return a.getUniformLocation(c,b)};this.K=d("a");this.J=d("b");this.H=d("c");this.O=d("d");this.M=d("e");this.B=d("f");this.A=d("g");this.L=d("h");this.b=d("j");this.o=d("k");this.s=d("l");this.u=d("m");this.v=d("n");this.I=d("o");this.G=d("p");this.C=d("q");this.ea=d("v");this.l=d("w");this.j=d("x");this.i=d("A");this.f=d("B");this.m=d("C");this.g=d("D");this.h=d("E");this.D=this.c}a.useProgram(this.D);this.K&& +a.uniform4fv(this.K,b.s.value);this.J&&a.uniform4fv(this.J,b.o.value);this.H&&a.uniform1f(this.H,b.b.value);this.O&&a.uniform4fv(this.O,b.B.value);this.M&&a.uniform1i(this.M,b.A.value);this.B&&a.uniform4fv(this.B,b.v.value);this.A&&a.uniform1i(this.A,b.u.value);this.L&&a.uniform1f(this.L,b.c.value);this.b&&a.uniform4fv(this.b,b.C.value);this.o&&a.uniform3fv(this.o,b.g.value);this.s&&a.uniform3fv(this.s,b.h.value);this.u&&a.uniformMatrix4fv(this.u,!1,b.i.value);this.v&&a.uniform1f(this.v,b.j.value); +this.I&&a.uniform1f(this.I,b.m.value);this.G&&a.uniformMatrix4fv(this.G,!1,b.a.value);this.C&&a.uniform1i(this.C,b.l.value);this.ea&&a.uniform2fv(this.ea,b.ea.value);this.l&&a.uniform3fv(this.l,b.ra.value);this.j&&a.uniform3fv(this.j,b.pa.value);this.i&&a.uniform3fv(this.i,b.ja.value);this.f&&a.uniform3fv(this.f,b.fa.value);this.m&&a.uniform3fv(this.m,b.va.value);this.g&&a.uniform3fv(this.g,b.ga.value);this.h&&a.uniform1f(this.h,b.ia.value)};function bW(){this.u=this.b=this.o=this.ea=this.s=this.m=this.v=this.B=this.i=this.h=this.g=this.f=this.c=this.G=this.j=this.l=this.H=this.I=this.A=this.C=this.D=null;this.J={}}var cW="#define _b 8\n#define _c 8000\n#define _d "+QB+"\n#define _e 2\n#define _f 16\n#define _g 8\n#define _h vec4(0., 0., 0., 0.2)\n#define _i 2\n#define _j 9\n#define _k 6\n#define _l 3\n#define _m 0\n#define _n 1\n#define _o 2\n#define _p 4\n#define _q 5\n#define _r 12\n#define _s 0\n#define _t 8\n#define _u 2\n#define _v 1\n#define _w 22\n\n"; +bW.prototype.a=function(a,b){b="#define _a "+b.f+"\n";var c=this.J[b];c||(c=zV(a,cW+b+"precision highp float;uniform vec4 d,f,j;uniform sampler2D e,g;vec2 M(vec2 A,float B){float C=float(_r);A.y=C*A.y+B;return (A+.5)*d.zw;}vec2 N(vec4 A){return vec2(A.g+A.b*256.,A.a);}vec2 O(vec2 u){vec4 A=texture2D(g,(floor(u*65535.+.5)+.5)*f.zw);A=floor(A*255.+.5);return N(A);}\n#if _a==1\nuniform float h;varying vec3 i;\n#endif\nuniform vec3 k,l;uniform mat4 m;uniform float o,r,w;\n#if _a==1\nuniform mat4 p;vec3 P(vec3 A){const float B=6371010.;float C,D,E,F,G,H,I,J,K,L;C=A.x;D=exp(A.y);E=D*D;F=2.*D/(1.+E);G=(E-1.)/(1.+E);H=A.z*B*F;I=H+B;J=I*F*cos(C);K=I*F*sin(C);L=I*G;return vec3(J,K,L);}vec4 Q(vec3 A){vec4 B,E;B=m*vec4(A,1);vec3 C,D;C=A;C/=o;C+=k+l;C.xy-=.5;C.y=-C.y;C*=3.141592653589793*2.;D=P(C);E=p*vec4(D,1);E/=E.w;B/=B.w;return mix(B,E,h);}\n#else\nvec4 Q(vec3 A){return m*vec4(A,1);}\n#endif\nvec3 R(vec3 A,vec3 B){vec3 C=A-k+(B-l);return C*o;}vec3 S(vec3 A){vec3 B,C;B=vec3(j.x,j.y,0);C=A*j.w;C.xy*=1./float(_f);return R(B,C);}vec4 T(vec3 A){vec3 B=S(A);return Q(B);}attribute vec4 s;attribute vec4 t;attribute vec2 u;uniform vec2 v;void main(){vec3 A,D;A=floor(s.xyz*32767.+.5);vec2 B,C,E;B=normalize(vec2(sin(w),cos(w)));C=max(0.,A.z)/tan(r)*B;C/=2.;D=vec3(A.xy+C,0);gl_Position=T(D);gl_Position.xy+=v*gl_Position.w;E=O(u);vec4 F=texture2D(e,M(E,float(_l)));gl_Position*=ceil(F.a);}", +cW+b+"precision highp float;precision highp float;\n#if _a==1\nvarying vec3 i;\n#endif\nvoid main(){gl_FragColor=vec4(0,.18,.33,.03);}",["s","t","u"]),this.J[b]=c);this.b=c}; +bW.prototype.bind=function(a,b){this.a(a,b);if(this.u!=this.b){var c=this.b,d=function(b){return a.getUniformLocation(c,b)};this.D=d("a");this.C=d("b");this.A=d("c");this.I=d("d");this.H=d("e");this.l=d("f");this.j=d("g");this.G=d("h");this.c=d("j");this.f=d("k");this.g=d("l");this.h=d("m");this.i=d("n");this.B=d("o");this.v=d("p");this.m=d("q");this.s=d("r");this.ea=d("v");this.o=d("w");this.u=this.b}a.useProgram(this.u);this.D&&a.uniform4fv(this.D,b.s.value);this.C&&a.uniform4fv(this.C,b.o.value); +this.A&&a.uniform1f(this.A,b.b.value);this.I&&a.uniform4fv(this.I,b.B.value);this.H&&a.uniform1i(this.H,b.A.value);this.l&&a.uniform4fv(this.l,b.v.value);this.j&&a.uniform1i(this.j,b.u.value);this.G&&a.uniform1f(this.G,b.c.value);this.c&&a.uniform4fv(this.c,b.C.value);this.f&&a.uniform3fv(this.f,b.g.value);this.g&&a.uniform3fv(this.g,b.h.value);this.h&&a.uniformMatrix4fv(this.h,!1,b.i.value);this.i&&a.uniform1f(this.i,b.j.value);this.B&&a.uniform1f(this.B,b.m.value);this.v&&a.uniformMatrix4fv(this.v, +!1,b.a.value);this.m&&a.uniform1i(this.m,b.l.value);this.s&&a.uniform1f(this.s,b.Ga.value);this.ea&&a.uniform2fv(this.ea,b.ea.value);this.o&&a.uniform1f(this.o,b.Da.value)};function dW(a,b){this.f=a;this.h=b;this.c=yV(a,$V);this.g=yV(a,bW);this.a=new EV(3,[[4,5122],[4,5121],[2,5123]]);this.i=new ir(a,this.a.a,this.a.b,void 0)} +function eW(a,b){a=a.h;var c=b.S;0>=c&&(c=1);var d=Math.PI/180,e=b.P*d;c*=d;var f=Math.sin(e),g=Math.cos(e),h=Math.sin(c),k=Math.cos(c);a.Da.set(e);a.Ga.set(c);a.va.set(-f*k,-g*k,h);a.ga.set(-Math.sin(e+150*d),-Math.cos(e+150*d),0);a.ra.set(1/h,1/h,.85/h);a.pa.set(.85,.85,1);a.ja.set(.9,.9,.85);a.fa.set(.25,.3,.35);a.ia.set(.9);a.ea.set(b.Va.x,b.Va.y)} +function fW(a){for(var b=0;b<a.length;b++)for(var c=a[b],d=0;d<c.a.length;d++)for(var e=c.a[d],f=0;f<e.a.length;++f){var g=e.a[f];if(g.a.L||g.b&&g.b.a.L)return!0}return!1} +function gW(a,b,c,d){for(var e=0;e<c.length;e++)for(var f=c[e],g=0;g<f.a.length;g++)for(var h=f.a[g],k=0;k<h.a.length;++k){var l=h.a[k];if(l){var m=a,n=l.a,p=n.L,q=l.b?l.b.a.L:null;if(p||q){b.uniform4f(d,n.g,n.h,n.m,n.b);if(q){n=m.f;l=m.a;for(var t=0;t<q.length;t++)MV(n,l,q[t])}if(p)for(n=m.f,m=m.a,l=0;l<p.length;l++)MV(n,m,p[l])}}}} +dW.prototype.b=function(a){var b=a.data,c=b.a;if(!c||null==c.i||!ny(Iy(c)))return 2;var d=a.a;if(d.L)return 2;var e=0,f=Iy(c).a;for(c=0;c<f.length;c++){var g=f[c],h=0;if(null!=g.a)for(var k=g.a,l=0;l<k.length;l++){var m=wx(k[l]);if(null!=m.b)var n=null==m.b?0:m.b;else{var p=ex(m);n=BI(p);Vc(p)}h=null!=m.c?h+3*(n-2):h+gx(m);h+=6*(n-jx(m))}null!=g.c&&(g=Jx(g),h+=3*(Bx(g)-2),h-=6*Dx(g));e+=2*h}e*=this.a.a;c=new hr(e);h=b.b.a[3];a=a.a.c;b=b.c;for(g=0;g<f.length;g++){k=h[g].ka();k=ZV(a,k);l=h[g].m;if(null!= +l.a)for(m=l.a,n=0;n<m.length;n++){var q=m[n],t=b;p=k;var v=c,u=wx(q);q=(null==q.b?0:q.b)/t;var w=ex(u),y=null!=u.b?null==u.b?0:u.b:BI(w),A=new Float32Array(2*y);DI(w,y,t,A);Vc(w);if(fx(u)){var z=hx(u);for(t=0;t<z.length;t+=3){w=z[t+0];var C=z[t+1],I=z[t+2];hW(this,A,w,C,I,q,p,v)}}else if(null!=u.c){z=null==u.c?-1:u.c;var S=y-2;for(t=0;t<S;t++)w=z,C=(z+t+1)%y,I=(z+t+2)%y,hW(this,A,w,I,C,q,p,v)}z=0;I=null!=u.h||null!=u.o?lx(u):null;S=0;u=null!=u.g||null!=u.C?kx(u):null;var ca=0;for(t=0;t<y;t++){var Z= +!0;w=t;C=t+1;u&&u[ca]==w&&(Z=!1,ca++);if(C==y||I&&I[S]==C){var ha=C;C=z;z=ha;S++}Z&&iW(this,A,C,w,q,p,v)}}if(null!=l.c){p=Jx(l);n=b;l=c;v=Ax(p);q=null!=p.g?null==p.g?0:p.g:CI(v);m=new Float32Array(3*q);EI(v,q,n,m);Vc(v);n=-Infinity;for(v=0;v<m.length;v+=3)q=m[v+2],q>n&&(n=q);v=Cx(p);q=2;p=null!=p.a||null!=p.i?Ex(p):null;y=0;t=v[0];w=v[1];for(C=!0;q<v.length;)A=t,t=w,w=v[q++],C?jW(this,m,A,w,t,n,k,l):jW(this,m,A,t,w,n,k,l),C=!C,p&&q==p[y]&&(t=v[q++],w=v[q++],y++,C=!0)}}g=c.g;h=c.c;f=c.b;a=c.a;k=a>> +1>>1;a/=this.a.a;for(b=0;b<k;b++)g[k+b]=g[b];for(b=a;b<2*a;b+=3)g=8*b,k=8*(b+2),l=h[g],m=h[g+1],n=h[g+2],h[g]=h[k],h[g+1]=h[k+1],h[g+2]=h[k+2],h[k]=l,h[k+1]=m,h[k+2]=n;for(b=a;b<2*a;b++)h=16*b,f[h+8]=254-f[h+8],f[h+9]=254-f[h+9],f[h+10]=254-f[h+10];c.a*=2;e=lr(this.i,e);nr(this.i,e,c.b);jO(d.a,e);d.L=e.a;return 2};function hW(a,b,c,d,e,f,g,h){var k=b[2*d+0];d=b[2*d+1];var l=b[2*e+0];e=b[2*e+1];kW(a,b[2*c+0],b[2*c+1],f,0,0,1,f,g,h);kW(a,k,d,f,0,0,1,f,g,h);kW(a,l,e,f,0,0,1,f,g,h)} +function jW(a,b,c,d,e,f,g,h){var k=b[3*c+0],l=b[3*c+1];c=b[3*c+2];var m=b[3*d+0],n=b[3*d+1];d=b[3*d+2];var p=b[3*e+0],q=b[3*e+1];b=b[3*e+2];e=-(q-l)*(d-c)+(b-c)*(n-l);var t=+(p-k)*(d-c)-(b-c)*(m-k),v=-(p-k)*(n-l)+(q-l)*(m-k),u=Math.sqrt(e*e+t*t+v*v);e=e/u*-1;t=t/u*-1;v=v/u*-1;kW(a,k,l,c,e,t,v,f,g,h);kW(a,m,n,d,e,t,v,f,g,h);kW(a,p,q,b,e,t,v,f,g,h)} +function iW(a,b,c,d,e,f,g){var h=b[2*c+0];c=b[2*c+1];var k=b[2*d+0];b=b[2*d+1];d=c-b;var l=k-h,m=Math.sqrt(d*d+l*l);d/=m;l/=m;kW(a,h,c,0,d,l,0,e,f,g);kW(a,k,b,0,d,l,0,e,f,g);kW(a,k,b,e,d,l,0,e,f,g);kW(a,k,b,e,d,l,0,e,f,g);kW(a,h,c,e,d,l,0,e,f,g);kW(a,h,c,0,d,l,0,e,f,g)}function kW(a,b,c,d,e,f,g,h,k,l){var m=l.c,n=l.b,p=l.f,q=l.a,t=q>>1;m[t]=16*b;m[t+1]=16*c;m[t+2]=16*d;m[t+3]=16*h;n[q+8]=127*(e+1);n[q+9]=127*(f+1);n[q+10]=127*(g+1);n[q+11]=0;p[t+6]=k.x;p[t+7]=k.y;l.a+=a.a.a};function lW(){this.s=this.g=this.C=this.f=this.h=this.c=this.ea=this.o=this.u=this.A=this.m=this.l=this.j=this.i=this.b=this.G=this.v=this.B=this.D=null;this.H={}}var mW="#define _b 8\n#define _c 8000\n#define _d "+QB+"\n#define _e 2\n#define _f 16\n#define _g 8\n#define _h 22\n\n"; +lW.prototype.a=function(a,b){b="#define _a "+b.f+"\n";var c=this.H[b];c||(c=zV(a,mW+b+"precision highp float;\n#if _a==1\nuniform float d;varying vec3 e;\n#endif\nuniform vec4 f;uniform vec3 g,h;uniform mat4 i;uniform float k,q,r;\n#if _a==1\nuniform mat4 l;vec3 H(vec3 t){const float u=6371010.;float v,w,x,A,B,C,D,E,F,G;v=t.x;w=exp(t.y);x=w*w;A=2.*w/(1.+x);B=(x-1.)/(1.+x);C=t.z*u*A;D=C+u;E=D*A*cos(v);F=D*A*sin(v);G=D*B;return vec3(E,F,G);}vec4 I(vec3 t){vec4 u,x;u=i*vec4(t,1);vec3 v,w;v=t;v/=k;v+=g+h;v.xy-=.5;v.y=-v.y;v*=3.141592653589793*2.;w=H(v);x=l*vec4(w,1);x/=x.w;u/=u.w;return mix(u,x,d);}vec3 J(vec3 t){t/=k;t+=g+h;t.xy-=.5;t.y=-t.y;t*=3.141592653589793*2.;vec3 u=mat3(l)*H(t);return normalize(u);}\n#else\nvec4 I(vec3 t){return i*vec4(t,1);}\n#endif\nvec3 K(vec3 t,vec3 u){vec3 v=t-g+(u-h);return v*k;}vec3 L(vec3 t){vec3 u,v;u=vec3(f.x,f.y,0);v=t*f.w;v.xy*=1./float(_f);return K(u,v);}vec4 M(vec3 t){vec3 u=L(t);return I(u);}float N(vec4 t){float u,v;u=1./float(_h+1);v=1.-u-f.z*u;return t.z*u+t.w*v;}void O(vec3 f){\n#if _a==1\nvec3 t=L(f);e=J(t);\n#endif\n}varying vec2 n;attribute vec2 o;uniform vec2 p;void main(){vec3 f=vec3(o.x,o.y,0);O(f);gl_Position=M(f);gl_Position.xy+=p*gl_Position.w;gl_Position.z=gl_Position.w*q;gl_Position.z=N(gl_Position);n=f.xy/(256.*float(_f));n*=r;}",mW+ +b+"precision highp float;\n#if _a==1\nuniform float d;varying vec3 e;\n#endif\nfloat w(){\n#if _a==1\nfloat u,v;u=dot(e,vec3(-1.,1,-1.));v=clamp((u-.5)/4.+1.,.5,1.);return mix(1.,v,d);\n#else\nreturn 1.;\n#endif\n}precision highp float;varying vec2 n;uniform float s;uniform sampler2D t;void main(){vec4 u=texture2D(t,n);if(u.a==0.)discard;float v=w();gl_FragColor=vec4(u.rgb*v,u.a*s);}",["o"]),this.H[b]=c);this.g=c}; +lW.prototype.bind=function(a,b){this.a(a,b);if(this.s!=this.g){var c=this.g,d=function(b){return a.getUniformLocation(c,b)};this.D=d("a");this.B=d("b");this.v=d("c");this.G=d("d");this.b=d("f");this.i=d("g");this.j=d("h");this.l=d("i");this.m=d("j");this.A=d("k");this.u=d("l");this.o=d("m");this.ea=d("p");this.c=d("q");this.h=d("r");this.f=d("s");this.C=d("t");this.s=this.g}a.useProgram(this.s);this.D&&a.uniform4fv(this.D,b.s.value);this.B&&a.uniform4fv(this.B,b.o.value);this.v&&a.uniform1f(this.v, +b.b.value);this.G&&a.uniform1f(this.G,b.c.value);this.b&&a.uniform4fv(this.b,b.C.value);this.i&&a.uniform3fv(this.i,b.g.value);this.j&&a.uniform3fv(this.j,b.h.value);this.l&&a.uniformMatrix4fv(this.l,!1,b.i.value);this.m&&a.uniform1f(this.m,b.j.value);this.A&&a.uniform1f(this.A,b.m.value);this.u&&a.uniformMatrix4fv(this.u,!1,b.a.value);this.o&&a.uniform1i(this.o,b.l.value);this.ea&&a.uniform2fv(this.ea,b.ea.value);this.c&&a.uniform1f(this.c,b.I.value);this.h&&a.uniform1f(this.h,b.M.value);this.f&& +a.uniform1f(this.f,b.L.value);this.C&&a.uniform1i(this.C,b.K.value)};function nW(a,b){this.a=a;this.o=b;this.c=yV(a,lW);this.f=new EV(1,[[2,5126]]);this.m=this.g=this.l=0;this.i=this.h=null;this.j=0;this.b=new tO}function oW(a,b,c,d,e,f){for(var g=new Uint32Array(b*b),h=0,k=0;k<b;k++)for(var l=0;l<b;l++)0==l||0==k||l==b-1||k==b-1?g[h++]=e:l%c&&k%c?g[h++]=d:g[h++]=f;c=a.a.createTexture();Jo(c,3);No(c,9729);Oo(c,9729);Mo(c,10497);g=new Uint8Array(g.buffer);Uo(c,g,b,b,6408,5121,0);a.h=c} +function pW(a,b,c,d){function e(a){var b=0|Math.round(255*a[0]);b|=Math.round(255*a[1])<<8;b|=Math.round(255*a[2])<<16;return b|=Math.round(255*a[3])<<24}if(2==c){c=dI;var f=eI;var g=fI}else c=aI,f=bI,g=cI;b=Yn(Math.round(b),1,2);oW(a,128*b,16*b,e(c),e(f),e(g));d=JV(a.a,0,4096,d,0,4096,d);a.i=d.buffer;a.j=d.size} +function qW(a,b,c,d,e,f,g){for(var h=0;h<c.length;++h)for(var k=c[h].a,l=0;l<k.length;++l){var m=a,n=b,p=k[l],q=d,t=e,v=f,u=g,w=m.a;RV(w,q);for(var y=[],A=[],z=p.a,C=0;C<z.length;++C){var I=z[C];qO(I)?A.push(I):I.data&&t?I.N.getZoom()==p.b.zoom&&A.push(sO(I.N,-1)):I.data&&4!=I.N.Ea()&&y.push(I)}xO(m.b,y,A,p.b,t,u);p=m.b.a.zoom;n.uniform1f(m.c.h,.5<v-p?4:2);t=m.b.a.a;if(t.length)for(u=m.a,y=1/Math.pow(2,p),A=0;A<t.length;A++)v=t[A],0>=v.a||(z=v.x*y,C=v.y*y,n.uniform1f(m.c.f,v.a),n.uniform4f(m.c.b, +z,C,p,y/256),u.drawArrays(4,0,m.j));RV(w,q)}};function rW(){this.u=this.b=this.l=this.s=this.m=this.B=this.o=this.v=this.C=this.h=this.g=this.f=this.c=this.K=this.H=this.i=this.j=this.I=this.J=this.A=this.D=this.G=null;this.L={}}var sW="#define _b 8\n#define _c 8000\n#define _d "+QB+"\n#define _e 2\n#define _f 16\n#define _g 8\n#define _h vec4(0., 0., 0., 0.2)\n#define _i 2\n#define _j 9\n#define _k 6\n#define _l 3\n#define _m 0\n#define _n 1\n#define _o 2\n#define _p 4\n#define _q 5\n#define _r 12\n#define _s 0\n#define _t 8\n#define _u 2\n#define _v 1\n#define _w 22\n\n"; +rW.prototype.a=function(a,b){b="#define _a "+b.f+"\n";var c=this.L[b];c||(c=zV(a,sW+b+"precision highp float;uniform vec4 a,b,f,B;uniform float c,n,o,A,C;vec2 Q(vec2 E){return (E*b.xy+b.xy)*.5;}vec2 R(vec2 E){return (E*b.zw-vec2(.5))*2.;}vec2 S(vec4 E){return vec2(E.g+E.b*256.,E.a);}uniform sampler2D g;float T(float E){return mod(E,32.)/31.;}void U(vec2 E,out float F,out vec2 G){vec4 H=texture2D(g,(floor(E*65535.+.5)+.5)*f.zw);H=floor(H*255.+.5);F=T(H.r);G=S(H);}\n#if _a==1\nuniform float h;varying vec3 i;\n#endif\nuniform vec3 k,l;uniform mat4 m;\n#if _a==1\nuniform mat4 p;vec3 V(vec3 E){const float F=6371010.;float G,H,I,J,K,L,M,N,O,P;G=E.x;H=exp(E.y);I=H*H;J=2.*H/(1.+I);K=(I-1.)/(1.+I);L=E.z*F*J;M=L+F;N=M*J*cos(G);O=M*J*sin(G);P=M*K;return vec3(N,O,P);}vec4 W(vec3 E){vec4 F,I;F=m*vec4(E,1);vec3 G,H;G=E;G/=o;G+=k+l;G.xy-=.5;G.y=-G.y;G*=3.141592653589793*2.;H=V(G);I=p*vec4(H,1);I/=I.w;F/=F.w;return mix(F,I,h);}\n#else\nvec4 W(vec3 E){return m*vec4(E,1);}\n#endif\nvec3 X(vec3 E,vec3 F){vec3 G=E-k+(F-l);return G*o;}vec3 Y(vec2 E,vec2 F,vec2 G){vec3 H,I;H=vec3(E.x,F.x,G.x)*65535.+.5;\n#if _a==1\nH-=fract(H);\n#else\nH=floor(H);\n#endif\nH=H/65536.;H=(fract(H+.5)-.5)*4.;I=vec3(E.y,F.y,G.y)*65535.;I/=1073741824.;return X(H,I);}vec4 Z(vec2 E,vec2 F,vec2 G){vec3 H=Y(E,F,G);return W(H);}varying vec2 r;varying float s,t;attribute vec4 u;attribute vec4 v;attribute vec2 w;attribute vec4 x;void main(){vec2 E,I,J;E=floor(x.xy*32767.+.5)*(1./float(_f));bool F,G;F=w.y>=.5;G=fract(2.*w.y)>0.;if(G)E.y*=sin(n);r=floor(x.zw*32767.+.5)*B.zw;vec4 H=Z(u.yx,u.wz,v.yx);I=Q(H.xy/H.w);I+=vec2(E.x,-E.y)*c;I=mix(I,floor(I+.5),A);gl_Position.xy=R(I);gl_Position.z=w.x;gl_Position.w=1.;if(!G&&F)gl_Position.y+=sin(n)*C/a.y;t=float(G);U(v.zw,s,J);float K=(J.x+J.y)*s*H.w;if(K<=0.)gl_Position=vec4(0);}", +sW+b+"precision highp float;precision highp float;\n#if _a==1\nvarying vec3 i;\n#endif\nprecision highp float;varying vec2 r;varying float s,t;uniform sampler2D D;const vec4 E=vec4(1);void main(){vec4 F=texture2D(D,r);if(t!=0.)F=E;F*=s;if(F.a==0.)discard;gl_FragColor=F;}",["u","v","w","x"]),this.L[b]=c);this.b=c}; +rW.prototype.bind=function(a,b){this.a(a,b);if(this.u!=this.b){var c=this.b,d=function(b){return a.getUniformLocation(c,b)};this.G=d("a");this.D=d("b");this.A=d("c");this.J=d("d");this.I=d("e");this.j=d("f");this.i=d("g");this.H=d("h");this.K=d("j");this.c=d("k");this.f=d("l");this.g=d("m");this.h=d("n");this.C=d("o");this.v=d("p");this.o=d("q");this.B=d("A");this.m=d("B");this.s=d("C");this.l=d("D");this.u=this.b}a.useProgram(this.u);this.G&&a.uniform4fv(this.G,b.s.value);this.D&&a.uniform4fv(this.D, +b.o.value);this.A&&a.uniform1f(this.A,b.b.value);this.J&&a.uniform4fv(this.J,b.B.value);this.I&&a.uniform1i(this.I,b.A.value);this.j&&a.uniform4fv(this.j,b.v.value);this.i&&a.uniform1i(this.i,b.u.value);this.H&&a.uniform1f(this.H,b.c.value);this.K&&a.uniform4fv(this.K,b.C.value);this.c&&a.uniform3fv(this.c,b.g.value);this.f&&a.uniform3fv(this.f,b.h.value);this.g&&a.uniformMatrix4fv(this.g,!1,b.i.value);this.h&&a.uniform1f(this.h,b.j.value);this.C&&a.uniform1f(this.C,b.m.value);this.v&&a.uniformMatrix4fv(this.v, +!1,b.a.value);this.o&&a.uniform1i(this.o,b.l.value);this.B&&a.uniform1f(this.B,b.H.value);this.m&&a.uniform4fv(this.m,b.G.value);this.s&&a.uniform1f(this.s,b.J.value);this.l&&a.uniform1i(this.l,b.D.value)};function tW(a,b){var c=1-a.label.g/65534;b&&(c-=.5);(0==a.type||1==a.type)&&1>c&&(c+=1/65536);return c};function uW(a,b,c,d){this.g=a;this.i=b;this.h=yV(a,rW);this.f=d;b=6;d&&(b+=6);this.a=new EV(b,[[4,5123],[4,5123],[2,5126],[4,5122]]);this.j=new ir(a,this.a.a,this.a.b,65536);this.c=c} +function vW(a,b,c,d){for(var e=a.g,f=a.i,g=a.a,h=!1,k=0;k<b.length;++k){var l=b[k];if(l.b&&l.b.a.P[d]){h=!0;break}if(l.a.P[d]){h=!0;break}}if(h){TV(e,c,4,3,1,2,1);fr(a.c,5);f.D.set(5);k=a.c.c;l=a.c.a;f.G.set(k,l,1/k,1/l);f.H.set(c.C);f.J.set(143);c=hq(e);a.h.bind(c,f);FV(e,g);for(k=0;k<b.length;++k)l=b[k],l.b?(f=l.b.a.P[d],c=l.a.P[d]):(f=l.a.P[d],c=null),(f||c)&&NV(e,g,f,c);iq(e);GV(e,g);gr(a.c)}} +uW.prototype.b=function(a,b){a=a.a;var c=a.a,d=a.u,e=a.f,f=a.c,g=this.a.f,h=b.a;if(!h.length)return 2;for(var k=new Uint32Array(h.length*this.a.h),l=new Float32Array(k.buffer),m=0,n=0;n<h.length;++n){var p=h[n],q=p,t=q.label.i&&this.f,v=p.label.b,u=pI(v.a,a.b,a.g),w=pI(v.b,a.b,a.h);v=pI(v.altitude,a.b,0);var y=0,A=0,z=0,C=0,I=0,S=0,ca=0,Z=0,ha=wW(d,e.a[p.a],q.text,c);ha&&(A=q.oa,C=q.b,y=A,A+=q.width,z=C-q.height/2,C+=q.height/2,y*=16,A*=16,z*=16,C*=16,S=ha.left+q.g.left,Z=ha.top+q.g.top,I=S,S+=q.g.width, +ca=Z,Z+=q.g.height);p=ZV(f,p.a);q=tW(q,this.f);p=oI(p.x,p.y);ha=this.f?1:0;for(var ea,ja,Y,ma,Ga,wa,Kd=0;Kd<=ha;Kd++)wa=t?.5:0,Kd?(ea=-8,ja=8,Y=t?-1144:0,ma=0,wa+=.25,Ga=.5):(ea=y,ja=A,Y=z,ma=C,Ga=q),k[m+0]=u,k[m+1]=w,k[m+2]=v,k[m+3]=p,l[m+4]=Ga,l[m+5]=wa,k[m+6]=oI(ea,ma),k[m+7]=oI(I,Z),m+=g,k[m+0]=u,k[m+1]=w,k[m+2]=v,k[m+3]=p,l[m+4]=Ga,l[m+5]=wa,k[m+6]=oI(ea,Y),k[m+7]=oI(I,ca),m+=g,k[m+0]=u,k[m+1]=w,k[m+2]=v,k[m+3]=p,l[m+4]=Ga,l[m+5]=wa,k[m+6]=oI(ja,Y),k[m+7]=oI(S,ca),m+=g,k[m+0]=u,k[m+1]=w,k[m+ +2]=v,k[m+3]=p,l[m+4]=Ga,l[m+5]=wa,k[m+6]=oI(ea,ma),k[m+7]=oI(I,Z),m+=g,k[m+0]=u,k[m+1]=w,k[m+2]=v,k[m+3]=p,l[m+4]=Ga,l[m+5]=wa,k[m+6]=oI(ja,Y),k[m+7]=oI(S,ca),m+=g,k[m+0]=u,k[m+1]=w,k[m+2]=v,k[m+3]=p,l[m+4]=Ga,l[m+5]=wa,k[m+6]=oI(ja,ma),k[m+7]=oI(S,Z),m+=g}m&&(c=PV(this.j,k),jO(a.a,c),a.P[b.b]=c.a[0]);return 2};function xW(a,b){this.f=a;this.j=b;this.i=yV(a,lW);this.c=new EV(1,[[2,5126]]);this.h=0;this.g=null;this.a=0}function yW(a,b){a=a.b||a;return 2!=a.N.Ea()&&b.u?null:a.a.C}function zW(a){return a.b?a.a.C:null} +xW.prototype.b=function(a){var b,c=this.f;if(!a.a.C)return 2;var d=a.a.a,e=a.data.b.a[5];for(b=0;b<a.a.C.length;b++){var f=a.a.C[b],g=f.b,h=4;g.Db()&&1!=g.Yb().format&&(h=1);var k=f;h=iO(d,g.Yd()*g.Xd()*h);k.Xb=d.c[h];Jo(f.Xb,3);Mo(f.Xb,33071);k=f.Xb;No(k,9729);Oo(k,9729);XQ(c,g);f.a=1-e[b].za/65535}return 2};function AW(){this.s=this.b=this.m=this.l=this.v=this.o=this.u=this.B=this.h=this.g=this.f=this.c=this.J=this.G=this.i=this.j=this.H=this.I=this.A=this.C=this.D=null;this.K={}}var BW="#define _b 8\n#define _c 8000\n#define _d "+QB+"\n#define _e 2\n#define _f 16\n#define _g 8\n#define _h vec4(0., 0., 0., 0.2)\n#define _i 2\n#define _j 9\n#define _k 6\n#define _l 3\n#define _m 0\n#define _n 1\n#define _o 2\n#define _p 4\n#define _q 5\n#define _r 12\n#define _s 0\n#define _t 8\n#define _u 2\n#define _v 1\n#define _w 22\n\n"; +AW.prototype.a=function(a,b){b="#define _a "+b.f+"\n";var c=this.K[b];c||(c=zV(a,BW+b+"precision highp float;uniform vec4 a,f;uniform float c,o,r;vec2 pa(vec4 F){return vec2(F.g+F.b*256.,F.a);}uniform sampler2D g;float qa(float F){return mod(F,32.)/31.;}void ra(vec2 F,out float G,out vec2 H,out bool I){vec4 J=texture2D(g,(floor(F*65535.+.5)+.5)*f.zw);J=floor(J*255.+.5);G=qa(J.r);I=mod(J.r/32.,2.)>=1.;H=pa(J);}\n#if _a==1\nuniform float h;varying vec3 i;\n#endif\nuniform vec3 k,l;uniform mat4 m;\n#if _a==1\nuniform mat4 p;vec3 sa(vec3 F){const float G=6371010.;float H,I,J,K,L,M,N,O,P,Q;H=F.x;I=exp(F.y);J=I*I;K=2.*I/(1.+J);L=(J-1.)/(1.+J);M=F.z*G*K;N=M+G;O=N*K*cos(H);P=N*K*sin(H);Q=N*L;return vec3(O,P,Q);}vec4 ta(vec3 F){vec4 G,J;G=m*vec4(F,1);vec3 H,I;H=F;H/=o;H+=k+l;H.xy-=.5;H.y=-H.y;H*=3.141592653589793*2.;I=sa(H);J=p*vec4(I,1);J/=J.w;G/=G.w;return mix(G,J,h);}\n#else\nvec4 ta(vec3 F){return m*vec4(F,1);}\n#endif\nvec3 ua(vec3 F,vec3 G){vec3 H=F-k+(G-l);return H*o;}vec3 va(vec2 F,vec2 G,vec2 H){vec3 I,J;I=vec3(F.x,G.x,H.x)*65535.+.5;\n#if _a==1\nI-=fract(I);\n#else\nI=floor(I);\n#endif\nI=I/65536.;I=(fract(I+.5)-.5)*4.;J=vec3(F.y,G.y,H.y)*65535.;J/=1073741824.;return ua(I,J);}varying vec3 s;varying vec4 t;attribute vec2 u;attribute vec4 v;attribute vec4 w;attribute vec4 x;attribute vec4 A;attribute vec4 B;attribute vec2 C;attribute vec4 D;void main(){vec2 F,G,I,Y,ba,ja,ka,la,oa;F=a.xy*.5;G=2.*a.zw;float H,L,M,N,O,P,Q,R,S,T,ca,ea,fa,ga,ha,ma,na;bool J,K;ra(x.zw,H,I,J);K=D.x>0.;L=floor(A.w*32767.+.5)/float(_f);M=floor(C.x*32767.+.5)/float(_f);N=floor(C.y*32767.+.5);N=N>0.?N:65536.+N;O=floor(N/256.);P=O*.5;Q=mod(N,256.)*.5;R=floor(D.y*255.+.5);S=1.;if(R<=1.)S=-1.;T=1.;if(R==1.)T=-1.;if(R==2.)T=-1.;vec3 U,V,W,Z,da;U=va(v.yx,v.wz,x.yx);V=va(w.yx,w.wz,x.yx);W=S==-1.?U:V;vec4 X,aa,ia;X=ta(W);Y=F*X.xy/X.w;Z=S==-1.?V:U;aa=ta(Z);ba=F*aa.xy/aa.w;ca=length(ba.xy-Y.xy);da=floor(A.xyz*32767.+.5)/float(_c);M+=P;M=J&&K?M*-1.:M;ea=u.x*ca-M;ea+=L*da.z;fa=ca+L*(da.x+da.y);ga=-ea/fa;ha=step(ga,0.)+step(1.,ga);ia=vec4(Y,ba);ja=normalize(ba-Y);ka=vec2(-ja.y,ja.x);la=S==1.?da.yx:da.xy;ia+=ka.xyxy*L*S;ia+=vec4(-la.xx,la.yy)*ja.xyxy*L;ga=S<0.?ga:1.-ga;Y=mix(ia.xy,ia.zw,ga);ma=1./c-r/c;Y-=(P+ma)*ja;Y+=(Q+ma)*ka*T*S;na=u.y;gl_Position=vec4(Y*G,na,1);gl_Position.xy*=1.-ha;t.zw=vec2(P,Q)*2.*c;t.xy=vec2(S,T)*(.5-float(J))*(t.zw+2.*ma)/t.zw;gl_Position.xy*=sign(H);gl_Position.xy*=sign(I.x+I.y);oa=mix(floor(B.xy*32767.+.5),floor(B.zw*32767.+.5),t.xy+.5)/float(_e);s=vec3(oa,H);}", +BW+b+"precision highp float;precision highp float;\n#if _a==1\nvarying vec3 i;\n#endif\nprecision highp float;uniform float r;varying vec3 s;varying vec4 t;uniform sampler2D E;uniform vec4 F;void main(){vec2 G,I;G=s.xy*F.zw;vec4 H=texture2D(E,G);I=.5-(abs(t.xy)-.5)*t.zw;float J=clamp(min(I.x,I.y),0.,1.);J=min(r+J,1.);H*=s.z*J;if(step(H.a,0.)>.5)discard;gl_FragColor=H;}","uvwxABCD".split("")),this.K[b]=c);this.b=c}; +AW.prototype.bind=function(a,b){this.a(a,b);if(this.s!=this.b){var c=this.b,d=function(b){return a.getUniformLocation(c,b)};this.D=d("a");this.C=d("b");this.A=d("c");this.I=d("d");this.H=d("e");this.j=d("f");this.i=d("g");this.G=d("h");this.J=d("j");this.c=d("k");this.f=d("l");this.g=d("m");this.h=d("n");this.B=d("o");this.u=d("p");this.o=d("q");this.v=d("r");this.l=d("E");this.m=d("F");this.s=this.b}a.useProgram(this.s);this.D&&a.uniform4fv(this.D,b.s.value);this.C&&a.uniform4fv(this.C,b.o.value); +this.A&&a.uniform1f(this.A,b.b.value);this.I&&a.uniform4fv(this.I,b.B.value);this.H&&a.uniform1i(this.H,b.A.value);this.j&&a.uniform4fv(this.j,b.v.value);this.i&&a.uniform1i(this.i,b.u.value);this.G&&a.uniform1f(this.G,b.c.value);this.J&&a.uniform4fv(this.J,b.C.value);this.c&&a.uniform3fv(this.c,b.g.value);this.f&&a.uniform3fv(this.f,b.h.value);this.g&&a.uniformMatrix4fv(this.g,!1,b.i.value);this.h&&a.uniform1f(this.h,b.j.value);this.B&&a.uniform1f(this.B,b.m.value);this.u&&a.uniformMatrix4fv(this.u, +!1,b.a.value);this.o&&a.uniform1i(this.o,b.l.value);this.v&&a.uniform1f(this.v,b.Bb.value);this.l&&a.uniform1i(this.l,b.D.value);this.m&&a.uniform4fv(this.m,b.G.value)};function CW(a,b,c){this.f=a;this.h=b;this.g=yV(a,AW);this.a=new EV(6,[[2,5126],[4,5123],[4,5123],[4,5123],[4,5122],[4,5122],[2,5122],[4,5121]]);this.i=new ir(a,this.a.a,this.a.b,65536);this.c=c} +function DW(a,b,c,d){for(var e=a.f,f=a.h,g=a.a,h=a.g,k=!1,l=0;l<b.length;++l){var m=b[l];if(m.b&&m.b.a.S[d]){k=!0;break}if(m.a.S[d]){k=!0;break}}if(k){TV(e,c,4,3,1,2,1);fr(a.c,5);f.D.set(5);l=a.c.c;c=a.c.a;f.G.set(l,c,1/l,1/c);FV(e,g);l=hq(e);h.bind(l,f);for(l=0;l<b.length;++l)b[l].b?(f=b[l].b.a.S[d],h=b[l].a.S[d]):(f=b[l].a.S[d],h=null),(f||h)&&NV(e,g,f,h);iq(e);GV(e,g);gr(a.c)}} +CW.prototype.b=function(a,b){a=a.a;var c=a.c,d=a.a,e=a.u,f=a.f,g=this.a.f,h=b.a;if(!h.length)return 2;e&&0==e.a&&e.Na(d);for(var k=0,l=0;l<h.length;++l){var m=h[l],n=m.label.a.a-1;k+=n*this.a.h}var p=[0,1,2,0,2,3];k=new Uint32Array(k);var q=new Float32Array(k.buffer),t=0;for(l=0;l<h.length;++l){m=h[l];var v=ZV(c,m.a),u=0,w=0,y=0,A=0;n=wW(e,f.a[m.a],"",d);var z=m.g;n&&(u=n.left+z.left,w=n.top+z.top,y=u+z.width,A=w+z.height);u*=2;w*=2;y*=2;A*=2;z=m.label.a;n=z.a-1;var C=m.j.width,I=m.j.height,S=tW(m), +ca=0,Z=0,ha=SK(z.b,z.f),ea=0!=m.f?eL(z,n):0,ja=0;0<=ea&&(1==z.h?ja=ea/2:3==z.h&&(ja=ea));var Y=pI(z.altitude,a.b,0);v=oI(v.x,v.y);u=oI(u,w);y=oI(y,A);A=oI(16*m.b,C<<8|I);w=1==z.h;for(var ma=I=C=0;ma<n;++ma){var Ga=pI(gL(z,ma),a.b,a.g),wa=pI(hL(z,ma),a.b,a.h),Kd=pI(gL(z,ma+1),a.b,a.g),xy=pI(hL(z,ma+1),a.b,a.h);0!=m.f&&(ca=z.i[Math.floor(ma)],Z=z.i[Math.ceil(ma+1)],0>ea&&(0==ma&&(ca=-ea/2),ma==n-1&&(Z=-ea/2)));for(var qj=SK(z.b,ma+1)-SK(z.b,ma),rj=qj?(C-ha)/qj:0,yy=oI(8E3*Yn(ca,-4,4),8E3*Yn(Z,-4,4)), +jZ=oI(8E3*Yn(I-ja,-4,4),16*m.f),zy=0;zy<p.length;zy++){var kZ=((w?1:0)&255|(p[zy]&255)<<8|0)>>>0;q[t+0]=rj;q[t+1]=S;k[t+2]=Ga;k[t+3]=wa;k[t+4]=Kd;k[t+5]=xy;k[t+6]=Y;k[t+7]=v;k[t+8]=yy;k[t+9]=jZ;k[t+10]=u;k[t+11]=y;k[t+12]=A;k[t+13]=kZ;t+=g}C+=qj;I+=ca+Z}}t&&(c=PV(this.i,k),jO(a.a,c),a.S[b.b]=c.a[0]);return 2};function EW(a){this.g=a;this.ga=this.fa=0;this.va=1;this.C=16;this.f=this.g?new EV(1,[[4,5123],[4,5123],[4,5123],[4,5121],[2,5126],[1,5126,!0]]):new EV(1,[[4,5122],[4,5123],[4,5121],[1,5126,!0]]);this.b=new Uint32Array(1024*this.f.f);this.H=new Float32Array(this.b.buffer);this.u=this.M=this.l=this.G=this.S=this.P=this.j=this.i=this.s=this.D=this.V=this.a=0;this.v=[];this.c=this.m=this.B=this.A=!1;this.h=this.U=0;this.T=!0;this.o=this.Z=this.I=this.O=this.K=this.J=this.Y=this.W=this.L=this.ha=this.ja= +this.ia=this.ra=this.pa=0}EW.prototype.reset=function(a,b,c,d){this.fa=a;this.ga=b;this.va=c;this.C=d;this.l=this.G=this.S=this.P=this.j=this.i=this.s=this.D=this.a=0;this.c=this.m=this.B=this.A=!1;this.o=this.Z=this.I=this.O=this.K=this.J=this.Y=this.W=this.L=this.ha=0}; +function FW(a,b,c){a.s=0;a.i=0;a.j=0;switch(b){case 0:a.s=0;break;case 1:case 2:case 4:a.s=10;break;case 3:a.s=8;break;default:a.s=0}switch(c){case 0:a.i=0;break;case 1:case 2:case 4:a.i=20;break;case 3:a.i=16;break;default:a.i=0}2==b&&(a.j|=32);2==c&&(a.j|=64)}function GW(a,b){a.O=oI(b.x,b.y)}function HI(a){a.c=!1;GI(a,0,0);a.g&&HW(a);a.c=!1}function JI(a){a.V=a.a;a.h=0;a.g&&(a.v=[]);a.A=!1;a.B=!1;a.m=!1;a.c=!1;a.M=0;a.u=0;a.T=!1} +function KI(a){if(3>a.h)HI(a);else if(a.c)if(GI(a,a.pa,a.ra),a.T){GI(a,a.ia,a.ja);var b=a.g?6:4,c=a.V+b;b=a.a-a.f.f+b;a.b[c]&=-1342242561;a.b[c]|=256-(a.b[b]>>16&255)<<8;a.c=!1}else HI(a);else HI(a)} +function GI(a,b,c){0==a.h&&(a.pa=b,a.ra=c);1==a.h&&(a.ia=b,a.ja=c);a.h++;var d=a.P;a.P=b;var e=a.S;a.S=c;var f=a.M;a.M=a.u;var g=a.U;1<a.h&&(a.U=Math.sqrt((b-d)*(b-d)+(c-e)*(c-e))/a.C,a.u+=a.U);a.A=a.B;a.B=a.m;a.m=a.c;var h=a.va/a.C;a.g?(a.W=a.J,a.Y=a.K,a.J=pI(d,h,a.fa),a.K=pI(e,h,a.ga),a.Z=g?f/g:0):(a.ha=a.L,a.L=qI(d,h,a.fa)|qI(e,h,a.ga)<<16);f=a.G;a.G=Math.round(Math.atan2(c-e,b-d)/Math.PI*128)&255;b=256-a.l&255;a.l=a.G-f&255;d=20/360*256;c=!1;a.c&&a.l>128-d&&a.l<128+d&&(a.l=0,c=!0);a.B?(d=a.D| +(a.A?0:a.s)|(a.m?0:a.i)|a.j,c&&(d|=a.i,d&=-65),a.I=f|(a.A?b:0)<<8|(a.m?a.l:0)<<16|d<<24,3==a.h&&(a.T=!0),a.g&&a.v.push(g),IW(a)):a.g&&HW(a);a.c=!0}function HW(a){for(var b=a.v.length,c=0,d=a.f.f,e=a.a-d+8,f=0;f<b;f++){var g=a.v[b-1-f];a.H[e-f*d]=c/g;c+=g}a.v=[]} +function IW(a){var b=a.f.f;if(a.a==a.b.length){if(a.a>=65536*b)return;var c=new Uint32Array(2*a.a);c.set(a.b);a.b=c;a.H=new Float32Array(a.b.buffer)}c=a.b;var d=a.a;a.g?(c[d+0]=a.W,c[d+1]=a.Y,c[d+2]=a.J,c[d+3]=a.K,c[d+4]=a.O,c[d+5]=a.o,c[d+6]=a.I,a.H[d+7]=a.Z,a.H[d+8]=0):(c[d+0]=a.ha,c[d+1]=a.L,c[d+2]=a.O,c[d+3]=a.o,c[d+4]=a.I);a.a+=b};function JW(a){this.c=a;this.b=[];this.i=[];this.a=0;this.j=-1}function KW(a,b){return cr(a.c,a.b[b])}function LW(a,b){return dr(a.c,a.b[b])}function MW(a,b){return-1!=a.b[b]?ar(a.c,a.b[b]):0}function NW(a,b){return-1!=a.b[b]?br(a.c,a.b[b]):0} +function OW(a,b,c,d,e,f,g){var h=a.c,k=a.b[b];a=a.i[b];-1!=k&&((b=0<h.g)||Wq(h),g instanceof Uint8Array?a?a&&$q(h,k,a,"array",c,d,e,f,g):$q(h,k,null,null,c,d,e,f,g):a?a&&$q(h,k,a,g.src,c,d,g.width,g.height,g):$q(h,k,null,null,c,d,g.width,g.height,g),b||Yq(h))}r=JW.prototype;r.Pb=function(){return 0==this.a?!1:this.j!=this.c.A?!0:1==this.a};r.ac=function(){}; +r.Na=function(a){for(var b=this.Ob(),c=0,d=0;d<b;d++){var e=this.zb(d),f=this.yb(d);var g=this.ac(d);if(e>this.c.c)this.b.push(-1),this.i.push(g),g=-1;else{if(g){var h=this.c;var k=g;if(k){var l=h.j[k];l?(l.a++,h=l.block):(e=Zq(h,e,f),-1!=e&&(h.j[k]=new Nq(e)),h=e)}else h=-1}else h=Zq(this.c,e,f);this.b.push(h);this.i.push(g);g=-1!=h?this.b.length-1:-1}-1!=g&&(c+=MW(this,g)*NW(this,g))}b=4;switch(this.c.m){case 6406:case 6409:b=1;break;case 6410:b=2;break;case 6407:b=3;break;case 6408:b=4}c*=b;b= +kO(a,this,sa);a.a-=a.g[b];a.g[b]=c;a.a+=a.g[b];this.a=1;return!0};r.Sb=function(){for(var a=0;a<this.b.length;a++){var b=this.b[a],c=this.i[a];if(-1!=b)if(c){var d=this.c;if(c&&!(0>b)){var e=d.j[c];e&&e.block==b&&(e.a--,0<e.a||(delete d.j[c],er(d,b)))}}else er(this.c,b)}this.b=[];this.i=[];this.a=0};r.Fa=function(a){0!=this.a||this.Na(a);if(this.Pb()){a=this.Ob();for(var b=0;b<a;b++)if(-1!=this.b[b]){var c=this.$b(b);c&&OW(this,b,0,0,this.zb(b),this.yb(b),c)}this.j=this.c.A;this.a=2}};function PW(a,b,c,d,e,f,g){this.b=a;this.a=b;this.zoom=c;this.type=d;this.width=e;this.height=f;this.name=g}function QW(a,b,c){JW.call(this,a);this.g=b;this.f=[];this.h={};this.l=-1;for(b=0;b<c.length;++b){var d=c[b],e=d.height;"stamp"==d.type&&(e=d.width);a&&e>a.v||this.f.push(d)}}F(QW,JW);r=QW.prototype;r.Ob=function(){return this.f.length};r.ac=function(a){return this.f[a].name}; +r.$b=function(a){a=this.f[a];var b=RA(this.g.a,a.b);if(!b)return null;switch(a.type){case "stamp":b=vA(b.v,a.a,a.zoom);break;case "startcap":b=vA(b.A,a.a,a.zoom);break;case "endcap":b=vA(b.u,a.a,a.zoom);break;default:throw"unknown icon type: "+a.type;}if(!b)return null;b=Zs(b,a.width,a.height,1);if("stamp"==a.type){var c=go("CANVAS");c.height=a.width;c.width=a.height+2;var d=c.getContext("2d");d.setTransform(0,1,1,0,0,0);d.drawImage(b,0,1);d.drawImage(b,0,1-a.height);d.drawImage(b,0,a.height+1);return c}return b}; +r.zb=function(a){a=this.f[a];var b=a.width;"stamp"==a.type&&(b=a.height+2);return b+1};r.yb=function(a){a=this.f[a];var b=a.height;"stamp"==a.type&&(b=a.width);a=4*Math.ceil((b+1)/4);8>a&&(a=8);return a};r.Na=function(a){if(a=QW.R.Na.call(this,a))for(var b=0;b<this.f.length;++b){var c=this.f[b],d=c.b+","+c.a+","+c.zoom+","+c.type;if(-1!=this.b[b]){var e=KW(this,b),f=LW(this,b);this.h[d]="stamp"==c.type?new pq(e+1,f,c.height,c.width):new pq(e,f,c.width,c.height)}}return a}; +r.Pb=function(){return this.l!=this.g.c||QW.R.Pb.call(this)};r.Fa=function(a){QW.R.Fa.call(this,a);this.l=this.g.c};function RW(a,b,c,d,e,f){b=b+","+c+","+d+","+e;0!=a.a||a.Na(f);return a.h[b]};function SW(){this.C=this.g=this.h=this.Hb=this.b=this.f=this.c=this.A=this.v=this.B=this.D=this.H=this.o=this.m=this.l=this.j=this.i=this.K=this.s=this.u=this.L=this.M=this.G=this.I=this.J=null;this.O={}}var TW="#define _b 8\n#define _c 8000\n#define _d "+QB+"\n#define _e 2\n#define _f 16\n#define _g 8\n#define _h vec4(0., 0., 0., 0.2)\n#define _i 2\n#define _j 9\n#define _k 6\n#define _l 3\n#define _m 0\n#define _n 1\n#define _o 2\n#define _p 4\n#define _q 5\n#define _r 12\n#define _s 0\n#define _t 8\n#define _u 2\n#define _v 1\n#define _w 22\n\n"; +SW.prototype.a=function(a,b){b="#define _a "+b.f+"\n";var c=this.O[b];c||(c=zV(a,TW+b+"precision highp float;uniform float c,o,J;uniform vec4 d,f,j,s,t,u,v;uniform sampler2D e,g;vec2 Xa(vec2 M,float N){float O=float(_r);M.y=O*M.y+N;return (M+.5)*d.zw;}vec2 Ya(vec4 M){return vec2(M.g+M.b*256.,M.a);}vec2 Za(vec2 M){vec4 N=texture2D(g,(floor(M*65535.+.5)+.5)*f.zw);N=floor(N*255.+.5);return Ya(N);}float ab(vec2 M,vec2 N){vec4 O=texture2D(e,M+N);float P,Q;P=O.r*255.*4.;Q=O.g*(255./64.);return P+Q;}\n#if _a==1\nuniform float h;varying vec3 i;\n#endif\nuniform vec3 k,l;uniform mat4 m;\n#if _a==1\nuniform mat4 p;vec3 bb(vec3 M){const float N=6371010.;float O,P,Q,R,S,T,U,V,W,X;O=M.x;P=exp(M.y);Q=P*P;R=2.*P/(1.+Q);S=(Q-1.)/(1.+Q);T=M.z*N*R;U=T+N;V=U*R*cos(O);W=U*R*sin(O);X=U*S;return vec3(V,W,X);}vec4 cb(vec3 M){vec4 N,Q;N=m*vec4(M,1);vec3 O,P;O=M;O/=o;O+=k+l;O.xy-=.5;O.y=-O.y;O*=3.141592653589793*2.;P=bb(O);Q=p*vec4(P,1);Q/=Q.w;N/=N.w;return mix(N,Q,h);}\n#else\nvec4 cb(vec3 M){return m*vec4(M,1);}\n#endif\nvec3 db(vec3 M,vec3 N){vec3 O=M-k+(N-l);return O*o;}vec3 eb(vec2 M,vec2 N,vec2 O){vec3 P,Q;P=vec3(M.x,N.x,O.x)*65535.+.5;\n#if _a==1\nP-=fract(P);\n#else\nP=floor(P);\n#endif\nP=P/65536.;P=(fract(P+.5)-.5)*4.;Q=vec3(M.y,N.y,O.y)*65535.;Q/=1073741824.;return db(P,Q);}float fb(float M){float N,O;N=1./float(_w+1);O=1.-N-j.z*N;return M*N+O;}varying vec4 w,A,B;varying vec3 x;const float L=1.;attribute vec4 C;attribute vec4 D;attribute vec4 E;attribute vec4 F;attribute vec2 G;attribute float H;uniform bool I;void main(){bool M,N,P,Q,R,S,T,U,V,W,Ha,Qa;M=true;if(H==2.)M=false;if(H==4.)M=false;if(H==5.)M=false;N=true;if(H==1.)N=false;if(H==2.)N=false;if(H==5.)N=false;float O,ba,ca,da,ea,fa,ga,ha,ia,ka,la,ma,na,oa,qa,ra,sa,ta,ua,Ba,Ea,Fa,Ga,Ia,Ja,Ka,La,Ma,Oa,Pa,Ta,Ua,Va,Wa;O=floor(F.w*255.+.5);P=fract(O*(1./4.))>=.5;Q=fract(O*(1./8.))>=.5;R=fract(O*(1./16.))>=.5;S=fract(O*(1./32.))>=.5;T=fract(O*(1./64.))>=.5;U=fract(O*(1./128.))>=.5;V=I?R:P;W=I?S:Q;vec2 X,Y,Z,aa,va,wa,xa,Aa,Na;X=Za(E.xy);Y=vec2(0,1.*d.w);Z=Xa(X,float(_k));aa=Xa(X,float(_j));ba=float(_s);w=texture2D(e,(I?aa:Z)+ba*Y);ca=float(_v);da=ab(Z,ca*Y);ea=ab(aa,ca*Y);fa=I?ea:da;ga=fa*.5;ha=da*.5;ia=float(_i);vec4 ja,Sa;ja=texture2D(e,(I?aa:Z)+ia*Y);ka=ja.r*255./float(_u);la=ja.g*255./float(_u)+ka;ma=ja.z*255.;na=floor(ma/128.);oa=-1.*na*2.+1.;ma=oa*ma+na*128.;ma=ma/float(_t);const float pa=3.141592653589793*2./256.;qa=floor(F.x*255.+.5);ra=floor(F.y*255.+.5)*.5;sa=floor(F.z*255.+.5)*.5;ta=qa+ra;ua=qa+sa;qa*=pa;ra*=pa;sa*=pa;ta*=pa;ua*=pa;va=vec2(sin(ta),-cos(ta));wa=vec2(sin(ua),-cos(ua));va/=cos(ra);wa/=cos(sa);xa=vec2(cos(qa),sin(qa));Aa=M?va:wa;Ba=tan(M?ra:sa);vec3 Ca,Da,Ra;Ca=eb(C.yx,C.wz,vec2(0));Da=eb(D.yx,D.wz,vec2(0));Ca.xy+=ma*va*1.0000001;Da.xy+=ma*wa*1.0000001;Ea=length(Da.xy-Ca.xy);if(W&&U)Ea-=ha;if(V&&T)Ea-=ha;Fa=L/c;Ga=Fa*.5;Ha=M?V:W;Ia=Ha?ga+Ga:0.;Ja=ga+Ga;Ka=M?-1.:1.;La=N?-1.:1.;x.x=M?0.:Ea;x.y=0.;x.x+=Ia*Ka;x.x+=Ja*La*Ba;x.y+=Ja*La;Ma=Ga/fa;x.xy/=Ea;x.z=float(V);x.z+=float(W)*.5;if(u.w>0.||v.w>0.)x.x=0.;B.x=-Ea/Fa;B.y=-.5*fa/Fa+.5;A=vec4(0,1,0,0);B.zw=vec2(1,0);Na=Ea*G;if(Na.x>1e6)Na.x=0.;Oa=0.;if(t.w>0.){vec2 Pa=t.zw*s.xy;float Qa=fa*Pa.x/Pa.y;ka=(la=Qa);}else if(la>0.)Oa=ka/la*.5;else ka=(la=1e6);A.xy=Na.xy;A.x+=Ia*Ka;A.x+=Ja*La*Ba;A.x+=M?0.:Ea;A.y-=Ia*Ka;A.y-=Ja*La*Ba;A.y+=M?Ea:0.;A.z=A.x/J;A.z/=la;A.xy/=fa;A.w=N?-Ma:1.+Ma;A.z-=Oa;Pa=J*.5/Fa;B.z=la*Pa;B.w=.5+(ka-la)*Pa;Qa=M?T:U;if(Ha&&Qa)Ia-=ha;Ra=M?Ca:Da;Ra.xy+=Ia*Ka*xa;Ra.xy+=Ja*La*Aa;Sa=cb(Ra);Ta=E.z;Ua=E.w;Va=I?Ua:Ta;Wa=fb(Va);gl_Position=vec4(Sa.xy/Sa.w,Wa,1);if(Sa.w<0.||t.w==0.&&w.a==0.)gl_Position=vec4(0);}", +TW+b+"precision highp float;precision highp float;\n#if _a==1\nvarying vec3 i;\n#endif\nuniform sampler2D r;uniform vec4 s,t,u,v;varying vec4 w,A,B;varying vec3 x;const float K=1.;float ca(float L){const float M=0.;const float N=1.;const float O=.3;const float P=.3;const float Q=2.*M-2.*N+O+P;const float R=3.*N-3.*M-2.*O-P;const float S=O;const float T=M;return clamp(((Q*L+R)*L+S)*L+T,0.,1.);}void main(){vec2 L=vec2(x.x-clamp(x.x,0.,1.),x.y);float M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z;M=L.x*L.x+L.y*L.y;N=A.z;O=B.z;P=B.w;N=abs(fract(N)*2.-1.);Q=clamp(O*N+P,0.,1.);R=x.z;S=float(L.x<0.)*floor(R);T=float(L.x>0.)*fract(R)*2.;Q=clamp(Q+S+T,0.,1.);U=B.x;V=B.y;W=sqrt(M)*U;X=clamp(W-V+1.,0.,1.);Y=clamp(W+V,0.,1.);if(K>1.){X=ca(X);Y=ca(Y);}Z=clamp(X-Y,0.,1.);Z*=Q;if(Z==0.)discard;if(t.w>0.){float aa=fract(A.z);gl_FragColor=texture2D(r,t.xy+vec2(aa,A.w)*t.zw);}else{gl_FragColor=w;gl_FragColor.rgb*=gl_FragColor.a;gl_FragColor*=Z;}if(v.w>0.&&A.y<.5){vec2 aa=vec2(A.w,.5-A.y)*v.zw;aa.y=max(aa.y,.5*s.w);vec4 ba=texture2D(r,v.xy+aa);gl_FragColor*=ba.a;}else if(u.w>0.){vec2 aa=vec2(A.w,.5-min(.5,A.x))*u.zw;aa.y=max(aa.y,.5*s.w);vec4 ba=texture2D(r,u.xy+aa);gl_FragColor*=ba.a;}}", +"CDEFGH".split("")),this.O[b]=c);this.g=c}; +SW.prototype.bind=function(a,b){this.a(a,b);if(this.C!=this.g){var c=this.g,d=function(b){return a.getUniformLocation(c,b)};this.J=d("a");this.I=d("b");this.G=d("c");this.M=d("d");this.L=d("e");this.u=d("f");this.s=d("g");this.K=d("h");this.i=d("j");this.j=d("k");this.l=d("l");this.m=d("m");this.o=d("n");this.H=d("o");this.D=d("p");this.B=d("q");this.v=d("r");this.A=d("s");this.c=d("t");this.f=d("u");this.b=d("v");this.Hb=d("I");this.h=d("J");this.C=this.g}a.useProgram(this.C);this.J&&a.uniform4fv(this.J, +b.s.value);this.I&&a.uniform4fv(this.I,b.o.value);this.G&&a.uniform1f(this.G,b.b.value);this.M&&a.uniform4fv(this.M,b.B.value);this.L&&a.uniform1i(this.L,b.A.value);this.u&&a.uniform4fv(this.u,b.v.value);this.s&&a.uniform1i(this.s,b.u.value);this.K&&a.uniform1f(this.K,b.c.value);this.i&&a.uniform4fv(this.i,b.C.value);this.j&&a.uniform3fv(this.j,b.g.value);this.l&&a.uniform3fv(this.l,b.h.value);this.m&&a.uniformMatrix4fv(this.m,!1,b.i.value);this.o&&a.uniform1f(this.o,b.j.value);this.H&&a.uniform1f(this.H, +b.m.value);this.D&&a.uniformMatrix4fv(this.D,!1,b.a.value);this.B&&a.uniform1i(this.B,b.l.value);this.v&&a.uniform1i(this.v,b.D.value);this.A&&a.uniform4fv(this.A,b.G.value);this.c&&a.uniform4fv(this.c,b.rb.value);this.f&&a.uniform4fv(this.f,b.sb.value);this.b&&a.uniform4fv(this.b,b.ib.value);this.Hb&&a.uniform1i(this.Hb,b.Hb.value);this.h&&a.uniform1f(this.h,b.Za.value)};function UW(a,b,c){this.f=a;this.h=b;this.g=yV(a,SW);this.a=new EW(!0);this.i=new ir(a,this.a.f.a,this.a.f.b,void 0);this.j=HV(a,[0,2,1,3,4,5]);this.c=c} +function VW(a,b,c){for(var d=a.f,e=a.h,f=a.a.f,g=a.j,h=a.g,k=!1,l=0;l<b.length;l++){var m=b[l],n=b[l].b;if(m.a.G||n&&n.a.G){k=!0;break}}if(k){TV(d,c,3==c.s?2:4,3,2,2,2);fr(a.c,5);e.D.set(5);k=a.c.c;n=a.c.a;e.G.set(k,n,1/k,1/n);FV(d,f);LV(d,g,f);g=hq(d);h.bind(g,e);g.uniform4f(h.c,0,0,0,0);g.uniform4f(h.f,0,0,0,0);g.uniform4f(h.b,0,0,0,0);var p=!0;for(l=0;l<b.length;l++){m=b[l];var q=m.a;if(m.b){e=m.b.a;m=e.G;var t=e.ja;e=q.G;var v=q.ja}else m=q.G,t=q.ja,v=e=null;if(m||e){g.uniform4f(h.i,q.g,q.h,q.m, +q.b);g.uniform1f(h.h,Math.pow(2,(c.zoom-q.m+100)%.25));SV(d,c,q.Z,q.g,q.h,q.b);var u=q.A;q=q.a;for(var w=Math.floor(c.zoom),y=new pq(0,0,0,0),A=0;1>=A;A++){g.uniform1f(h.Hb,A);for(var z=0;1>=z;z++){var C=0==z?m:e;if(C)for(var I=0==z?t:v,S=0;S<C.length;S++){var ca=I[S];-1!=ca&&u?(p=RW(u,ca,A,w,"stamp",q)||y,g.uniform4f(h.c,p.left/k,p.top/n,p.width/k,p.height/n),p=RW(u,ca,A,w,"startcap",q)||y,g.uniform4f(h.f,p.left/k,p.top/n,p.width/k,p.height/n),p=RW(u,ca,A,w,"endcap",q)||y,g.uniform4f(h.b,p.left/ +k,p.top/n,p.width/k,p.height/n),p=!1):p||(g.uniform4f(h.c,0,0,0,0),g.uniform4f(h.f,0,0,0,0),g.uniform4f(h.b,0,0,0,0),p=!0);OV(d,f,C[S],null)}}}}}iq(d);GV(d,f);gr(a.c)}}function WW(a,b,c){if(0!=a.a.a){var d=b.a;b=b.data;var e=PV(a.i,a.a.b,a.a.a);jO(d.a,e);d.G||(d.G=[],d.ja=[]);d.G.push(e.a[0]);d.ja.push(c);a.a.reset(d.g,d.h,d.b,b.c)}} +UW.prototype.b=function(a,b){var c=a.a,d=a.data,e=d.a;if(!e)return 2;var f=Ey(e)&&jy(Fy(e)),g=Gy(e)&&ly(Hy(e));if(!f&&!g||c.I)return 2;f=-1;g=d.b;this.a.reset(c.g,c.h,c.b,d.c);var h=c.a;d=c.f;c=c.A;a.data.getZoom();c&&0==c.a&&c.Na(h);if(Ey(e)){h=Fy(e).a;var k=g.a[1];for(c=0;c<h.length;c++){var l=k[c].ka(),m=d.a[l];l=0<CK(d,l).o?m:-1;l!=f&&(WW(this,a,f),f=l);l=a;m=h[c];var n=k[c],p=b,q=l.a,t=q.f;q=q.c;var v=n.ka();t=CK(t,v);16>=l.data.c&&Xz(t,l.data.getZoom())||(t=this.a,FW(t,Vw(m),Ww(m)),t.D=0,GW(t, +ZV(q,v)),t.o=65535-n.b|65535-n.za<<16,n=rI(l.data.getZoom(),p),FI(m,t,l.data.getZoom(),n))}}WW(this,a,f);f=-1;if(Gy(e))for(b=Hy(e).a,e=g.a[2],c=0;c<b.length;c++)l=a,k=b[c],g=e[c],d=l.a,m=d.f,d=d.c,h=g.ka(),m=CK(m,h),l=l.data.getZoom(),Xz(m,l)||1>m.c||0>=uA(m,0,l)||tA(m,0,l)&0||null==k.a||null==k.f||!k.f||(k=ux(k),l=this.a,FW(l,1,1),GW(l,ZV(d,h)),l.o=65535-(g.za+1)|65535-(g.za+2)<<16,II(k,l));WW(this,a,f);return 2};function XW(){this.o=this.c=this.outline=this.b=this.m=this.s=this.v=this.i=this.h=this.g=this.f=this.H=this.C=this.j=this.l=this.D=this.G=this.u=this.A=this.B=null;this.I={}}var YW="#define _b 8\n#define _c 8000\n#define _d "+QB+"\n#define _e 2\n#define _f 16\n#define _g 8\n#define _h vec4(0., 0., 0., 0.2)\n#define _i 2\n#define _j 9\n#define _k 6\n#define _l 3\n#define _m 0\n#define _n 1\n#define _o 2\n#define _p 4\n#define _q 5\n#define _r 12\n#define _s 0\n#define _t 8\n#define _u 2\n#define _v 1\n#define _w 22\n\n"; +XW.prototype.a=function(a,b){b="#define _a "+b.f+"\n";var c=this.I[b];c||(c=zV(a,YW+b+"precision highp float;uniform vec4 a,d,f;uniform sampler2D e,g;vec2 qa(vec2 F,float G){float H=float(_r);F.y=H*F.y+G;return (F+.5)*d.zw;}vec2 ra(vec4 F){return vec2(F.g+F.b*256.,F.a);}float sa(vec2 F,vec2 G){vec4 H=texture2D(e,F+G);float I,J;I=H.r*255.*4.;J=H.g*(255./64.);return I+J;}float ta(float F){return mod(F,32.)/31.;}void ua(vec2 F,out float G,out vec2 H,out bool I){vec4 J=texture2D(g,(floor(F*65535.+.5)+.5)*f.zw);J=floor(J*255.+.5);G=ta(J.r);I=mod(J.r/32.,2.)>=1.;H=ra(J);}\n#if _a==1\nuniform float h;varying vec3 i;\n#endif\nuniform vec3 k,l;uniform mat4 m;uniform float o,C;\n#if _a==1\nuniform mat4 p;vec3 va(vec3 F){const float G=6371010.;float H,I,J,K,L,M,N,O,P,Q;H=F.x;I=exp(F.y);J=I*I;K=2.*I/(1.+J);L=(J-1.)/(1.+J);M=F.z*G*K;N=M+G;O=N*K*cos(H);P=N*K*sin(H);Q=N*L;return vec3(O,P,Q);}vec4 wa(vec3 F){vec4 G,J;G=m*vec4(F,1);vec3 H,I;H=F;H/=o;H+=k+l;H.xy-=.5;H.y=-H.y;H*=3.141592653589793*2.;I=va(H);J=p*vec4(I,1);J/=J.w;G/=G.w;return mix(G,J,h);}\n#else\nvec4 wa(vec3 F){return m*vec4(F,1);}\n#endif\nvec3 xa(vec3 F,vec3 G){vec3 H=F-k+(G-l);return H*o;}vec3 Aa(vec2 F,vec2 G,vec2 H){vec3 I,J;I=vec3(F.x,G.x,H.x)*65535.+.5;\n#if _a==1\nI-=fract(I);\n#else\nI=floor(I);\n#endif\nI=I/65536.;I=(fract(I+.5)-.5)*4.;J=vec3(F.y,G.y,H.y)*65535.;J/=1073741824.;return xa(I,J);}uniform bool q,D;varying vec4 r,s,t;attribute vec2 u;attribute vec4 v;attribute vec4 w;attribute vec4 x;attribute vec4 A;attribute vec4 B;void main(){vec2 F,G,I,L,X,aa,ia,ka,la,ma;F=a.xy*.5;G=2.*a.zw;float H,K,M,N,O,P,Q,R,S,ba,ca,ea,fa,ga,ha,na,oa,pa;bool J;ua(x.zw,H,I,J);K=float(_o);L=qa(I,K);M=sa(L,vec2(0))*float(D);N=floor(A.w*32767.+.5)/float(_f);O=floor(B.x*32767.+.5)/float(_f);P=floor(B.y*32767.+.5)/float(_f);Q=floor(B.w*32767.+.5);R=1.;if(Q<=1.)R=-1.;S=1.;if(Q==1.)S=-1.;if(Q==2.)S=-1.;vec3 T,U,V,Y,da;T=Aa(v.yx,v.wz,x.yx);U=Aa(w.yx,w.wz,x.yx);V=R==-1.?T:U;vec4 W,Z,ja;W=wa(V);X=F*W.xy/W.w;Y=R==-1.?U:T;Z=wa(Y);aa=F*Z.xy/Z.w;ba=length(aa.xy-X.xy);ca=N<0.?N-M:N+M;da=floor(A.xyz*32767.+.5)/float(_c);ea=floor(B.z*32767.+.5)/float(_f);fa=ba*u.x-O;fa+=ca*da.z;ga=fa+ba;ga+=ca*(da.x+da.y);ha=R<0.?fa-ea:ga+ea;ia=vec2(0,P);ia+=vec2(-M,M);r=vec4(ha,ia,ea);ja=vec4(X,aa);ka=normalize(aa-X);la=vec2(-ka.y,ka.x);ma=R==1.?da.yx:da.xy;ja+=la.xyxy*ca*R;ja+=vec4(-ma.xx,ma.yy)*ka.xyxy*ca;s=R<0.?ja:ja.zwxy;s+=F.xyxy;X=ja.xy;X-=ea*ka;X+=(ea+1.)*la*S*R;na=u.y;gl_Position=vec4(X*G,na,1);oa=step(W.w,1e-4)+step(Z.w,1e-4);pa=min(1.,oa+float(q)*step(ba,P));gl_Position.xy*=1.-pa;gl_Position.xy*=sign(H);t=texture2D(e,qa(I,C));t.a*=H;gl_Position.xy*=sign(t.a);}", +YW+b+"precision highp float;uniform float c;precision highp float;\n#if _a==1\nvarying vec3 i;\n#endif\nprecision highp float;varying vec4 r,s,t;void main(){float E,G,K,M,N;E=r.x;vec2 F,H,I,J,L;F=r.yz;G=1.-max(max(F.x-E,E-F.y)*c,0.);if(G<=0.)discard;H=gl_FragCoord.xy/c;I=H-s.xy;J=s.zw-s.xy;K=clamp(dot(I,J)/dot(J,J),0.,1.);L=H-mix(s.xy,s.zw,K);M=dot(L,L);N=sqrt(M)-r.w;vec4 O=t;O.a=G*clamp(.5-N*c,0.,1.);if(O.a==0.)discard;gl_FragColor=O;}","uvwxAB".split("")),this.I[b]=c);this.c=c}; +XW.prototype.bind=function(a,b){this.a(a,b);if(this.o!=this.c){var c=this.c,d=function(b){return a.getUniformLocation(c,b)};this.B=d("a");this.A=d("b");this.u=d("c");this.G=d("d");this.D=d("e");this.l=d("f");this.j=d("g");this.C=d("h");this.H=d("j");this.f=d("k");this.g=d("l");this.h=d("m");this.i=d("n");this.v=d("o");this.s=d("p");this.m=d("q");this.b=d("C");this.outline=d("D");this.o=this.c}a.useProgram(this.o);this.B&&a.uniform4fv(this.B,b.s.value);this.A&&a.uniform4fv(this.A,b.o.value);this.u&& +a.uniform1f(this.u,b.b.value);this.G&&a.uniform4fv(this.G,b.B.value);this.D&&a.uniform1i(this.D,b.A.value);this.l&&a.uniform4fv(this.l,b.v.value);this.j&&a.uniform1i(this.j,b.u.value);this.C&&a.uniform1f(this.C,b.c.value);this.H&&a.uniform4fv(this.H,b.C.value);this.f&&a.uniform3fv(this.f,b.g.value);this.g&&a.uniform3fv(this.g,b.h.value);this.h&&a.uniformMatrix4fv(this.h,!1,b.i.value);this.i&&a.uniform1f(this.i,b.j.value);this.v&&a.uniform1f(this.v,b.m.value);this.s&&a.uniformMatrix4fv(this.s,!1,b.a.value); +this.m&&a.uniform1i(this.m,b.l.value);this.b&&a.uniform1f(this.b,b.Sa.value);this.outline&&a.uniform1i(this.outline,b.outline.value)};function ZW(a,b){this.c=a;this.g=b;this.f=yV(a,XW);this.a=new EV(6,[[2,5126],[4,5123],[4,5123],[4,5123],[4,5122],[4,5122]]);this.h=new ir(a,this.a.a,this.a.b,65536)} +function $W(a,b,c,d){for(var e=a.c,f=a.g,g=a.a,h=a.f,k=!1,l=0;l<b.length;++l){var m=b[l];if(m.b&&m.b.a.T[d]){k=!0;break}if(m.a.T[d]){k=!0;break}}if(k){TV(e,c,3,3,1,2,1);FV(e,g);c=hq(e);h.bind(c,f);for(l=0;l<b.length;++l)if(b[l].b?(f=b[l].b.a.T[d],k=b[l].a.T[d]):(f=b[l].a.T[d],k=null),f||k)c.uniform1f(h.b,1),c.uniform1f(h.outline,1),NV(e,a.a,f,k),c.uniform1f(h.b,0),c.uniform1f(h.outline,0),NV(e,a.a,f,k);iq(e);GV(e,g)}} +ZW.prototype.b=function(a,b){a=a.a;var c=a.c,d=this.a.f,e=b.a;if(!e.length)return 2;for(var f=0,g=0;g<e.length;++g){var h=e[g],k=h.label.a.a-1;f+=k*this.a.h}var l=[0,1,2,0,2,3];f=new Uint32Array(f);var m=new Float32Array(f.buffer),n=0;for(g=0;g<e.length;++g){h=e[g];var p=h.label.a,q=ZV(c,h.a);k=p.a-1;var t=0!=h.f?eL(p,k):0,v=SK(p.b,p.f),u=0;0<=t&&(1==p.h?u=t/2:3==p.h&&(u=t));var w=pI(p.altitude,a.b,0);q=oI(q.x,q.y);for(var y=oI(16*h.b,16*h.width),A=0,z=0,C=0;C<k;++C){var I=pI(gL(p,C),a.b,a.g),S=pI(hL(p, +C),a.b,a.h),ca=pI(gL(p,C+1),a.b,a.g),Z=pI(hL(p,C+1),a.b,a.h),ha=0,ea=0;0!=h.f&&(ha=p.i[C],ea=p.i[C+1],0==C&&0>t&&(ha=-t/2),C==k-1&&0>t&&(ea=-t/2));for(var ja=SK(p.b,C+1)-SK(p.b,C),Y=ja?(A-v)/ja:0,ma=oI(8E3*Yn(ha,-4,4),8E3*Yn(ea,-4,4)),Ga=oI(8E3*Yn(z-u,-4,4),16*h.f),wa=0;6>wa;wa++){var Kd=oI(16*(h.height+3)/2,l[wa]);m[n+0]=Y;m[n+1]=tW(h);f[n+2]=I;f[n+3]=S;f[n+4]=ca;f[n+5]=Z;f[n+6]=w;f[n+7]=q;f[n+8]=ma;f[n+9]=Ga;f[n+10]=y;f[n+11]=Kd;n+=d}A+=ja;z+=ha+ea}}n&&(c=a.a,d=PV(this.h,f),jO(c,d),a.T[b.b]=d.a[0]); +return 2};var aX=0,bX={};function cX(a){a=(bX[a]||null).b;return new pq(a.left/2+2,a.top/2+2,a.width/2-4,a.height/2-4)}function dX(){this.b=this.a=this.data=null};function eX(){this.A=this.g=this.b=this.K=this.J=this.u=this.text=this.c=this.f=this.O=this.v=this.B=this.D=this.m=this.l=this.j=this.i=this.h=this.I=this.o=this.s=this.L=this.M=this.C=this.G=this.H=null;this.P={}}var fX="#define _b 8\n#define _c 8000\n#define _d "+QB+"\n#define _e 2\n#define _f 16\n#define _g 8\n#define _h vec4(0., 0., 0., 0.2)\n#define _i 2\n#define _j 9\n#define _k 6\n#define _l 3\n#define _m 0\n#define _n 1\n#define _o 2\n#define _p 4\n#define _q 5\n#define _r 12\n#define _s 0\n#define _t 8\n#define _u 2\n#define _v 1\n#define _w 22\n#define _x 2\n\n"; +eX.prototype.a=function(a,b){b="#define _a "+b.f+"\n";var c=this.P[b];c||(c=zV(a,fX+b+"precision highp float;uniform vec4 d,f;uniform sampler2D e,g;vec2 xa(vec2 K,float L){float M=float(_r);K.y=M*K.y+L;return (K+.5)*d.zw;}vec2 Aa(vec4 K){return vec2(K.g+K.b*256.,K.a);}float Ba(float K){return mod(K,32.)/31.;}void Ca(vec2 K,out float L,out vec2 M,out bool N){vec4 O=texture2D(g,(floor(K*65535.+.5)+.5)*f.zw);O=floor(O*255.+.5);L=Ba(O.r);N=mod(O.r/32.,2.)>=1.;M=Aa(O);}\n#if _a==1\nuniform float h;varying vec3 i;\n#endif\nuniform vec3 k,l;uniform mat4 m;uniform float o,F,G;\n#if _a==1\nuniform mat4 p;vec3 Da(vec3 K){const float L=6371010.;float M,N,O,P,Q,R,S,T,U,V;M=K.x;N=exp(K.y);O=N*N;P=2.*N/(1.+O);Q=(O-1.)/(1.+O);R=K.z*L*P;S=R+L;T=S*P*cos(M);U=S*P*sin(M);V=S*Q;return vec3(T,U,V);}vec4 Ea(vec3 K){vec4 L,O;L=m*vec4(K,1);vec3 M,N;M=K;M/=o;M+=k+l;M.xy-=.5;M.y=-M.y;M*=3.141592653589793*2.;N=Da(M);O=p*vec4(N,1);O/=O.w;L/=L.w;return mix(L,O,h);}\n#else\nvec4 Ea(vec3 K){return m*vec4(K,1);}\n#endif\nvec3 Fa(vec3 K,vec3 L){vec3 M=K-k+(L-l);return M*o;}vec3 Ga(vec2 K,vec2 L,vec2 M){vec3 N,O;N=vec3(K.x,L.x,M.x)*65535.+.5;\n#if _a==1\nN-=fract(N);\n#else\nN=floor(N);\n#endif\nN=N/65536.;N=(fract(N+.5)-.5)*4.;O=vec3(K.y,L.y,M.y)*65535.;O/=1073741824.;return Fa(N,O);}const float I=float(_x);const float J=1./float(_f);varying vec2 s;varying vec4 t,u;attribute vec2 v;attribute vec4 w;attribute vec4 x;attribute vec4 A;attribute vec4 B;attribute vec4 C;attribute vec2 D;attribute vec4 E;void main(){bool K,O,T,Y,pa;float L,R,S,U,W,X,Z,aa,ba,ca,da,ea,fa,ga,ha,ma,na,oa,qa,ta,ua,va,wa;vec2 M,N,ia,ja,sa;Ca(A.zw,L,M,K);N=xa(M,F);u=texture2D(e,N);u.a*=L;O=false;if(L<=0.)O=true;vec3 P,Q,V,ka,la;P=Ga(w.yx,w.wz,A.yx);Q=Ga(x.yx,x.wz,A.yx);R=length(P.xy-Q.xy);S=floor(B.w*32767.+.5)/float(_f);T=E.y>0.;U=K&&T?-S:S;V=floor(B.xyz*32767.+.5)/float(_c);W=floor(D.x*32767.+.5)/float(_f);X=floor(D.y*32767.+.5)/float(_f);Y=E.x>0.;W=K&&Y?W*-1.-X:W;Z=v.x*R-W;Z+=U*V.z;aa=R+U*(V.x+V.y);ba=Z+aa;Z+=.001;ba+=.001;ca=max(Z,0.);da=min(ba,X);ea=(ca-Z)/aa;fa=(da-Z)/aa;ga=K?X-da:ca;ha=K?X-ca:da;if(ga>ha)O=true;ia=normalize(Q.xy-P.xy);ja=vec2(-ia.y,ia.x);P.xy-=U*V.x*ia;P.xy+=U*ja;Q.xy+=U*V.y*ia;Q.xy+=U*ja;ka=mix(P,Q,ea);la=mix(P,Q,fa);ma=floor(C.x*65535.+.5)*J;na=floor(C.y*65535.+.5)*J+G+1.;oa=floor(E.z*255.+.5);pa=true;if(oa==2.)pa=false;if(oa==3.)pa=false;qa=1.;if(oa==0.)qa=-1.;if(oa==3.)qa=-1.;ka.xy-=ma*ia;la.xy+=ma*ia;ka.xy+=na*qa*ja;la.xy+=na*qa*ja;vec4 ra=Ea(pa?ka:la);gl_Position=vec4(ra.xy/ra.w,v.y,1);sa=vec2(ga-ma,ha+ma);if(K)sa=sa.yx;ta=pa?sa.x:sa.y;ua=(K?qa:-qa)*na;va=floor(C.z*65535.+.5);wa=floor(C.w*65535.+.5);t.x=va+ta*I;t.y=ua*I;t.z=wa+.5;t.w=wa+1.5;s.x=va+ga*I;s.y=va+ha*I;if(O)gl_Position=vec4(0);}", +fX+b+"precision highp float;precision highp float;\n#if _a==1\nvarying vec3 i;\n#endif\nconst float M=float(_x);const float N=1./float(_f);uniform vec4 r,J;varying vec2 s;varying vec4 t,u;precision highp float;uniform sampler2D H,I;uniform vec2 K,L;void main(){float O,Y;O=floor(t.x)+.5;vec4 P,Q,S;P=texture2D(H,vec2(O,t.z)*r.zw);Q=texture2D(H,vec2(O,t.w)*r.zw);vec2 R,T,U,V,W,X;R=vec2(P.r*255.+P.g*(255./256.),P.b*255.+P.a*(255./256.));R=R-128.;R+=O-t.x;S=Q*J.xyxy+J.zwzw;T=vec2(-R.x,-t.y);U=vec2(-R.y,-t.y);V=S.xy+T*K;W=S.zw+U*K;X=vec2(texture2D(I,V).a,texture2D(I,W).a);X=X*L.x+L.y;if(R.x+t.x<s.x)X.x=0.;if(R.x+t.x>s.y)X.x=0.;if(R.y+t.x<s.x)X.y=0.;if(R.y+t.x>s.y)X.y=0.;if(P.x==0.)X.x=0.;if(P.z==0.)X.y=0.;Y=clamp(max(X.x,X.y),0.,1.);gl_FragColor=vec4(u.r,u.g,u.b,u.a*Y);if(Y==0.)discard;}", +"vwxABCDE".split("")),this.P[b]=c);this.g=c}; +eX.prototype.bind=function(a,b){this.a(a,b);if(this.A!=this.g){var c=this.g,d=function(b){return a.getUniformLocation(c,b)};this.H=d("a");this.G=d("b");this.C=d("c");this.M=d("d");this.L=d("e");this.s=d("f");this.o=d("g");this.I=d("h");this.h=d("j");this.i=d("k");this.j=d("l");this.l=d("m");this.m=d("n");this.D=d("o");this.B=d("p");this.v=d("q");this.O=d("r");this.f=d("F");this.c=d("G");this.text=d("H");this.u=d("I");this.J=d("J");this.K=d("K");this.b=d("L");this.A=this.g}a.useProgram(this.A);this.H&& +a.uniform4fv(this.H,b.s.value);this.G&&a.uniform4fv(this.G,b.o.value);this.C&&a.uniform1f(this.C,b.b.value);this.M&&a.uniform4fv(this.M,b.B.value);this.L&&a.uniform1i(this.L,b.A.value);this.s&&a.uniform4fv(this.s,b.v.value);this.o&&a.uniform1i(this.o,b.u.value);this.I&&a.uniform1f(this.I,b.c.value);this.h&&a.uniform4fv(this.h,b.C.value);this.i&&a.uniform3fv(this.i,b.g.value);this.j&&a.uniform3fv(this.j,b.h.value);this.l&&a.uniformMatrix4fv(this.l,!1,b.i.value);this.m&&a.uniform1f(this.m,b.j.value); +this.D&&a.uniform1f(this.D,b.m.value);this.B&&a.uniformMatrix4fv(this.B,!1,b.a.value);this.v&&a.uniform1i(this.v,b.l.value);this.O&&a.uniform4fv(this.O,b.Wa.value);this.f&&a.uniform1f(this.f,b.Sa.value);this.c&&a.uniform1f(this.c,b.jb.value);this.text&&a.uniform1i(this.text,b.text.value);this.u&&a.uniform1i(this.u,b.Ba.value);this.J&&a.uniform4fv(this.J,b.Qa.value);this.K&&a.uniform2fv(this.K,b.Ra.value);this.b&&a.uniform2fv(this.b,b.$a.value)};function gX(a,b,c,d){this.h=a;this.c=b;this.i=yV(a,eX);this.a=new EV(6,[[2,5126],[4,5123],[4,5123],[4,5123],[4,5122],[4,5123],[2,5122],[4,5121]]);this.j=new ir(a,this.a.a,this.a.b,65536);this.g=c;this.f=d} +function hX(a,b,c,d){for(var e=a.h,f=a.c,g=a.a,h=a.i,k=!1,l=0;l<b.length;++l){var m=b[l];if(m.b&&m.b.a.U[d]){k=!0;break}if(m.a.U[d]){k=!0;break}}if(k){TV(e,c,3,3,1,2,1);l=a.c;k=a.g;fr(k,4);l.text.set(4);l.Wa.set(k.c,k.a,1/k.c,1/k.a);l=a.c;k=a.f;m=k.c;var n=k.a;fr(k,5);l.Ba.set(5);l.Ra.set(1/m,1/n);l.Qa.set(2040/m,3060/n,4/m,6/n);FV(e,g);l=c.l;c=10.625*l;k=-.5*c+.5;m=k+1.5*l;n=hq(e);h.bind(n,f);for(l=0;l<b.length;++l){if(b[l].b){f=b[l].b.a.U[d];var p=b[l].a.U[d]}else f=b[l].a.U[d],p=null;if(f||p){var q= +b[l].a;n.uniform4f(h.h,q.g,q.h,q.m,q.b);n.uniform1f(h.f,5);n.uniform1f(h.c,1.5);n.uniform2f(h.b,c,m);NV(e,g,f,p);n.uniform1f(h.f,4);n.uniform1f(h.c,0);n.uniform2f(h.b,c,k);NV(e,g,f,p)}}iq(e);GV(e,g);gr(a.g);gr(a.f)}} +gX.prototype.b=function(a,b){a=a.a;var c=a.c,d=b.a;if(!d.length)return 2;for(var e=0,f=0;f<d.length;++f){var g=d[f],h=g.label.a.a-1;e+=h*this.a.h}var k=[0,1,2,0,2,3];e=new Uint32Array(e);var l=new Float32Array(e.buffer),m=0;for(f=0;f<d.length;++f){g=d[f];var n=g.label.a,p=g.c;h=ZV(c,g.a);var q=tW(g),t=g.g?1:0,v=1==n.h?1:0,u=pI(n.altitude,a.b,0),w=oI(p.f/2*16,(p.height-2)/2*16),y=oI(p.a,p.b);p=oI(16*g.b,16*p.width);var A=oI(h.x,h.y),z=0!=g.f?eL(n,n.a-1):0,C=SK(n.b,n.f),I=0;0<=z&&(1==n.h?I=z/2:3==n.h&& +(I=z));var S=0,ca=0;h=n.a-1;for(var Z=0;Z<h;Z++){var ha=pI(gL(n,Z),a.b,a.g),ea=pI(hL(n,Z),a.b,a.h),ja=pI(gL(n,Z+1),a.b,a.g),Y=pI(hL(n,Z+1),a.b,a.h),ma=0,Ga=0;0!=g.f&&(ma=n.i[Z],Ga=n.i[Z+1],0==Z&&0>z&&(ma=-z/2),Z==h-1&&0>z&&(Ga=-z/2));for(var wa=SK(n.b,Z+1)-SK(n.b,Z),Kd=wa?(S-C)/wa:0,xy=oI(8E3*Yn(ma,-4,4),8E3*Yn(Ga,-4,4)),qj=oI(8E3*Yn(ca-I,-4,4),16*g.f),rj=0;rj<k.length;rj++){var yy=(v&255|(t&255)<<8|(k[rj]&255)<<16|0)>>>0;l[m+0]=Kd;l[m+1]=q;e[m+2]=ha;e[m+3]=ea;e[m+4]=ja;e[m+5]=Y;e[m+6]=u;e[m+7]=A; +e[m+8]=xy;e[m+9]=qj;e[m+10]=w;e[m+11]=y;e[m+12]=p;e[m+13]=yy;m+=this.a.f}S+=wa;ca+=ma+Ga}}m&&(c=PV(this.j,e),jO(a.a,c),a.U[b.b]=c.a[0]);return 2};function iX(){this.u=this.b=this.G=this.D=this.s=this.B=this.c=this.la=this.o=this.v=this.C=this.j=this.i=this.h=this.g=this.f=this.J=this.l=this.m=this.K=this.L=this.A=this.H=this.I=null;this.M={}}var jX="#define _b 8\n#define _c 8000\n#define _d "+QB+"\n#define _e 2\n#define _f 16\n#define _g 8\n#define _h vec4(0., 0., 0., 0.2)\n#define _i 2\n#define _j 9\n#define _k 6\n#define _l 3\n#define _m 0\n#define _n 1\n#define _o 2\n#define _p 4\n#define _q 5\n#define _r 12\n#define _s 0\n#define _t 8\n#define _u 2\n#define _v 1\n#define _w 22\n\n"; +iX.prototype.a=function(a,b){b="#define _a "+b.f+"\n";var c=this.M[b];c||(c=zV(a,jX+b+"precision highp float;uniform vec4 a,b,d,f;vec2 S(vec2 G){return (G*b.xy+b.xy)*.5;}vec2 T(vec2 G){return (G*b.zw-vec2(.5))*2.;}uniform sampler2D e,g;vec2 U(vec2 G,float H){float I=float(_r);G.y=I*G.y+H;return (G+.5)*d.zw;}vec2 V(vec4 G){return vec2(G.g+G.b*256.,G.a);}float W(float G){return mod(G,32.)/31.;}void X(vec2 G,out float H,out vec2 I){vec4 J=texture2D(g,(floor(G*65535.+.5)+.5)*f.zw);J=floor(J*255.+.5);H=W(J.r);I=V(J);}\n#if _a==1\nuniform float h;varying vec3 i;\n#endif\nuniform vec3 k,l;uniform mat4 m;uniform float n,o,w,D,E;\n#if _a==1\nuniform mat4 p;vec3 Y(vec3 G){const float H=6371010.;float I,J,K,L,M,N,O,P,Q,R;I=G.x;J=exp(G.y);K=J*J;L=2.*J/(1.+K);M=(K-1.)/(1.+K);N=G.z*H*L;O=N+H;P=O*L*cos(I);Q=O*L*sin(I);R=O*M;return vec3(P,Q,R);}vec4 Z(vec3 G){vec4 H,K;H=m*vec4(G,1);vec3 I,J;I=G;I/=o;I+=k+l;I.xy-=.5;I.y=-I.y;I*=3.141592653589793*2.;J=Y(I);K=p*vec4(J,1);K/=K.w;H/=H.w;return mix(H,K,h);}\n#else\nvec4 Z(vec3 G){return m*vec4(G,1);}\n#endif\nvec3 aa(vec3 G,vec3 H){vec3 I=G-k+(H-l);return I*o;}vec3 ba(vec2 G,vec2 H,vec2 I){vec3 J,K;J=vec3(G.x,H.x,I.x)*65535.+.5;\n#if _a==1\nJ-=fract(J);\n#else\nJ=floor(J);\n#endif\nJ=J/65536.;J=(fract(J+.5)-.5)*4.;K=vec3(G.y,H.y,I.y)*65535.;K/=1073741824.;return aa(J,K);}vec4 ca(vec2 G,vec2 H,vec2 I){vec3 J=ba(G,H,I);return Z(J);}varying vec2 r;varying vec4 s,t;varying float u;attribute vec4 x;attribute vec4 A;attribute vec2 B;attribute vec4 C;void main(){vec2 G,H,J,K;G=A.zw;H=floor(C.xy*32767.+.5)*(1./float(_f));r=floor(C.zw*32767.+.5);vec4 I=ca(x.yx,x.wz,A.yx);J=S(I.xy/I.w);J+=vec2(H.x,-H.y)*w;J=mix(J,floor(J+.5),D);gl_Position.xy=T(J);gl_Position.z=B.x;gl_Position.w=1.;float L,N;X(G,L,K);s=texture2D(e,U(K,float(_q)));t=texture2D(e,U(K,float(_p)));s.a*=L;t.a*=L;u=dot(s.rgb,vec3(.2126,.7152,.0722));vec3 M=vec3(mix(1.6,1.,u));s.rgb=pow(s.rgb,M);t.rgb=pow(t.rgb,M);if(B.y!=0.)gl_Position.y+=sin(n)*E/a.y;N=L*I.w;if(N<=0.)gl_Position=vec4(0);}", +jX+b+"precision highp float;precision highp float;\n#if _a==1\nvarying vec3 i;\n#endif\nprecision highp float;varying vec2 r;varying vec4 s,t;varying float u;uniform float v;uniform sampler2D F;uniform vec4 G;void main(){vec2 H,K,L;H=r*G.zw;float I,J;I=texture2D(F,H).a;J=I;K=vec2(G.z*v,0);L=vec2(0,G.w*v);const float M=.9717;const float N=.5454;J+=N*texture2D(F,H-K-L).a+M*texture2D(F,H-K).a+N*texture2D(F,H-K+L).a+M*texture2D(F,H-L).a+M*texture2D(F,H+L).a+N*texture2D(F,H+K-L).a+M*texture2D(F,H+K).a+N*texture2D(F,H+K+L).a;J=min(J,1.);J*=s.a;I*=t.a;vec4 O=mix(vec4(s.rgb*J,J),vec4(t.rgb,1),I);if(O.a==0.)discard;O.rgb/=O.a;vec3 P=vec3(1./mix(1.6,1.,u));O.rgb=pow(O.rgb,P);gl_FragColor=O;}", +["x","A","B","C"]),this.M[b]=c);this.b=c}; +iX.prototype.bind=function(a,b){this.a(a,b);if(this.u!=this.b){var c=this.b,d=function(b){return a.getUniformLocation(c,b)};this.I=d("a");this.H=d("b");this.A=d("c");this.L=d("d");this.K=d("e");this.m=d("f");this.l=d("g");this.J=d("h");this.f=d("j");this.g=d("k");this.h=d("l");this.i=d("m");this.j=d("n");this.C=d("o");this.v=d("p");this.o=d("q");this.la=d("v");this.c=d("w");this.B=d("D");this.s=d("E");this.D=d("F");this.G=d("G");this.u=this.b}a.useProgram(this.u);this.I&&a.uniform4fv(this.I,b.s.value); +this.H&&a.uniform4fv(this.H,b.o.value);this.A&&a.uniform1f(this.A,b.b.value);this.L&&a.uniform4fv(this.L,b.B.value);this.K&&a.uniform1i(this.K,b.A.value);this.m&&a.uniform4fv(this.m,b.v.value);this.l&&a.uniform1i(this.l,b.u.value);this.J&&a.uniform1f(this.J,b.c.value);this.f&&a.uniform4fv(this.f,b.C.value);this.g&&a.uniform3fv(this.g,b.g.value);this.h&&a.uniform3fv(this.h,b.h.value);this.i&&a.uniformMatrix4fv(this.i,!1,b.i.value);this.j&&a.uniform1f(this.j,b.j.value);this.C&&a.uniform1f(this.C,b.m.value); +this.v&&a.uniformMatrix4fv(this.v,!1,b.a.value);this.o&&a.uniform1i(this.o,b.l.value);this.la&&a.uniform1f(this.la,b.la.value);this.c&&a.uniform1f(this.c,b.qb.value);this.B&&a.uniform1f(this.B,b.H.value);this.s&&a.uniform1f(this.s,b.J.value);this.D&&a.uniform1i(this.D,b.Ia.value);this.G&&a.uniform4fv(this.G,b.Ja.value)};function kX(a,b,c,d){this.f=a;this.i=b;this.h=yV(a,iX);this.g=d;this.c=new EV(6,[[4,5123],[4,5123],[2,5126],[4,5122]]);this.j=new ir(a,this.c.a,this.c.b,65536);this.a=c} +function lX(a,b,c,d){for(var e=a.f,f=a.i,g=a.c,h=a.h,k=!1,l=0;l<b.length;++l){var m=b[l];if(m.b&&m.b.a.W[d]){k=!0;break}if(m.a.W[d]){k=!0;break}}if(k){TV(e,c,3,3,1,2,1);fr(a.a,4);f.Ia.set(4);f.Ja.set(a.a.c,a.a.a,1/a.a.c,1/a.a.a);FV(e,g);f.H.set(c.C);f.J.set(143);k=hq(e);h.bind(k,f);for(l=0;l<b.length;++l){m=b[l];if(m.b){f=m.b.a.W[d];var n=m.a.W[d]}else f=m.a.W[d],n=null;if(f||n)m=m.a,k.uniform4f(h.f,m.g,m.h,m.m,m.b),k.uniform1f(h.la,m.la),k.uniform1f(h.c,c.l/m.la),NV(e,g,f,n)}iq(e);GV(e,g);gr(a.a)}} +kX.prototype.b=function(a,b){a=a.a;var c=a.c,d=this.c.f,e=b.a;if(!e.length)return 2;for(var f=new Uint32Array(e.length*this.c.h),g=new Float32Array(f.buffer),h=0,k=0;k<e.length;++k){var l=e[k],m=l,n=m.label.b,p=pI(n.a,a.b,a.g),q=pI(n.b,a.b,a.h);n=pI(n.altitude,a.b,0);l=ZV(c,l.a);l=oI(l.x,l.y);var t=m.c;if(t){var v=m.oa*a.la,u=m.b*a.la,w=t.a,y=t.b,A=Math.round(t.width*a.la),z=Math.round(t.height*a.la);t.c||(A=z=0);var C=A+2,I=-2-z/2,S=z/2+2;z=w+-2;t=y+I;w+=C;y+=S;A=16*(v+-2);I=16*(u+I);v=16*(v+C); +u=16*(u+S);C=this.g&&m.label.i?1:0;m=tW(m,!!C);f[h+0]=p;f[h+1]=q;f[h+2]=n;f[h+3]=l;g[h+4]=m;g[h+5]=C;f[h+6]=oI(A,u);f[h+7]=oI(z,y);h+=d;f[h+0]=p;f[h+1]=q;f[h+2]=n;f[h+3]=l;g[h+4]=m;g[h+5]=C;f[h+6]=oI(A,I);f[h+7]=oI(z,t);h+=d;f[h+0]=p;f[h+1]=q;f[h+2]=n;f[h+3]=l;g[h+4]=m;g[h+5]=C;f[h+6]=oI(v,I);f[h+7]=oI(w,t);h+=d;f[h+0]=p;f[h+1]=q;f[h+2]=n;f[h+3]=l;g[h+4]=m;g[h+5]=C;f[h+6]=oI(A,u);f[h+7]=oI(z,y);h+=d;f[h+0]=p;f[h+1]=q;f[h+2]=n;f[h+3]=l;g[h+4]=m;g[h+5]=C;f[h+6]=oI(v,I);f[h+7]=oI(w,t);h+=d;f[h+0]=p; +f[h+1]=q;f[h+2]=n;f[h+3]=l;g[h+4]=m;g[h+5]=C;f[h+6]=oI(v,u);f[h+7]=oI(w,y);h+=d}}h&&(c=PV(this.j,f),jO(a.a,c),a.W[b.b]=c.a[0]);return 2};function mX(){this.m=this.b=this.Ya=this.i=this.j=this.C=this.D=this.l=this.o=this.u=this.h=this.g=this.f=this.c=this.G=this.B=this.s=this.v=this.A=null;this.H={}}var nX="#define _b 8\n#define _c 8000\n#define _d "+QB+"\n#define _e 2\n#define _f 16\n#define _g 8\n#define _h 22\n#define _i vec4(0., 0., 0., 0.2)\n#define _j 2\n#define _k 9\n#define _l 6\n#define _m 3\n#define _n 0\n#define _o 1\n#define _p 2\n#define _q 4\n#define _r 5\n#define _s 12\n#define _t 0\n#define _u 8\n#define _v 2\n#define _w 1\n\n"; +mX.prototype.a=function(a,b){b="#define _a "+b.f+"\n";var c=this.H[b];c||(c=zV(a,nX+b+"precision highp float;\n#if _a==1\nvarying vec3 e;\n#endif\n#if _a==1\nuniform mat4 l;\n#else\n#endif\nuniform vec4 n;uniform sampler2D o;vec2 J(vec2 t,float v){float w=float(_s);t.y=w*t.y+v;return (t+.5)*n.zw;}precision highp float;varying vec3 r;attribute vec3 s;uniform vec2 t;void main(){vec3 v=mat3(l)*s;e=normalize(v);vec4 w=l*vec4(s,1);w/=w.w;gl_Position=w;vec2 x=J(t,float(_m));r=texture2D(o,x).rgb;}",nX+b+ +"precision highp float;\n#if _a==1\nuniform float d;varying vec3 e;\n#endif\nfloat w(){\n#if _a==1\nfloat u,v;u=dot(e,vec3(-1.,1,-1.));v=clamp((u-.5)/4.+1.,.5,1.);return mix(1.,v,d);\n#else\nreturn 1.;\n#endif\n}precision highp float;precision highp float;varying vec3 r;void main(){float u=w();gl_FragColor=vec4(r*u,1);}",["s"]),this.H[b]=c);this.b=c}; +mX.prototype.bind=function(a,b){this.a(a,b);if(this.m!=this.b){var c=this.b,d=function(b){return a.getUniformLocation(c,b)};this.A=d("a");this.v=d("b");this.s=d("c");this.B=d("d");this.G=d("f");this.c=d("g");this.f=d("h");this.g=d("i");this.h=d("j");this.u=d("k");this.o=d("l");this.l=d("m");this.D=d("n");this.C=d("o");this.j=d("p");this.i=d("q");this.Ya=d("t");this.m=this.b}a.useProgram(this.m);this.A&&a.uniform4fv(this.A,b.s.value);this.v&&a.uniform4fv(this.v,b.o.value);this.s&&a.uniform1f(this.s, +b.b.value);this.B&&a.uniform1f(this.B,b.c.value);this.G&&a.uniform4fv(this.G,b.C.value);this.c&&a.uniform3fv(this.c,b.g.value);this.f&&a.uniform3fv(this.f,b.h.value);this.g&&a.uniformMatrix4fv(this.g,!1,b.i.value);this.h&&a.uniform1f(this.h,b.j.value);this.u&&a.uniform1f(this.u,b.m.value);this.o&&a.uniformMatrix4fv(this.o,!1,b.a.value);this.l&&a.uniform1i(this.l,b.l.value);this.D&&a.uniform4fv(this.D,b.B.value);this.C&&a.uniform1i(this.C,b.A.value);this.j&&a.uniform4fv(this.j,b.v.value);this.i&&a.uniform1i(this.i, +b.u.value);this.Ya&&a.uniform2fv(this.Ya,b.Ya.value)};function oX(){this.a=1;this.f=Array(8192);this.b=Array(8192);this.c=0}function pX(a,b){return a.f[b]!=a.a?(a.f[b]=a.a,(b=!a.b[b])&&a.c++,b):!1}function qX(a,b){return a.f[b]==a.a}function rX(a,b,c){a.b[b]&&!c&&qX(a,b)&&a.c++;a.b[b]=c};function sX(a,b){this.i=a;this.f=null;this.j=this.l=0;this.g=this.c=!1;a=this.b=b;a.f=this.A;a.h=this||null;a=D(this.B,this);this.b.i=a;this.a=new oX;this.m=null;this.h=0;this.v=new Uint8Array(48);this.u=new Uint8Array(48);this.s=new Uint8Array(48);this.o=0} +function tX(a,b){var c=a.i;a.f||(a.f=c.createTexture(),c.activeTexture(33984+c.a.vb()),c.bindTexture(3553,a.f),c.texParameteri(3553,10240,9728),c.texParameteri(3553,10241,9728),c.texParameteri(3553,10242,33071),c.texParameteri(3553,10243,33071),a.l=0,a.j=0,a.c=!1);a.c||(c.activeTexture(33984+c.a.vb()),uX(a),c.a.xa(33984+c.a.vb()-33984,null),a.c=!0);b[0]=a.l;b[1]=a.j;return a.f}function vX(a,b,c,d){var e=a%d;a=Math.floor(a/d);b[c+1]=e&255;b[c+2]=e>>8&255;b[c+3]=a} +function wX(a,b,c){c.x=b%a.i;c.y=Math.floor(b/a.i)}function xX(a,b){for(var c=!1,d=0;d<b.length;++d)c|=pX(a.a,b[d]);c&&(a.c=!1)} +function uX(a){var b=a.i,c=a.f;b.activeTexture(33984+b.a.vb());b.bindTexture(3553,c);var d=a.i.i;var e=a.b;c=QA(e.a)+1;ZB(e)&&(e=QA(e.b)+1,c=c>e?c:e);var f=Math.max(Math.ceil(c/d),1);e=Math.min(512*Math.ceil(c/512),d);var g=!1;e!=a.l&&(g=!0);d=Math.min(12*f,d);d!=a.j&&(g=!0);g&&(a.l=e,a.j=d,Uo(jq(b,3553),null,e,d,6408,5121,0));d=g||a.g;a.g=!1;g=1;ZB(a.b)&&(g=a.b,ZB(g)?(g=1-(g.j-E())/167,g=XB(g)):g=1);for(var h=f=0;h<c;++h)if(qX(a.a,h)){if(d||!a.a.b[h]){if(1!=g){var k=RA(a.b.b,h);pA(RA(a.b.a,h),a.h, +a.u);pA(k,a.h,a.v);var l=a.v,m=a.u,n=a.s;k=g;for(var p=0;12>p;p++)n[p]=m[p];l=l.subarray(12);m=m.subarray(12);n=n.subarray(12);rA(l,m,n,k,k)}else pA(RA(a.b.a,h),a.h,a.s);k=h%e;n=12*Math.floor(h/e);m=a.s;Vo(jq(b,3553),m,k,n,1,12,6408,5121,0);rX(a.a,h,!0);f++}}else d&&rX(a.a,h,!1)}sX.prototype.A=function(a,b){for(var c=!1,d=0;d<a.length;++d){var e=a[d];rX(this.a,e,!1);!c&&qX(this.a,e)&&(c=!0);e=b[d];var f=!0;e&&!($z(e)?0:e.l||e.s||e.j||e.C)&&(f=!1)}c&&(f||this.o++,yX(this))}; +sX.prototype.B=function(){this.g=!0;yX(this)};function yX(a){a.c&&(a.c=!1,a.m&&a.m())};function zX(a){this.b=yV(a,mX);this.c=new EV(1,[[3,5126]]);var b=[],c=Math.sin(83/90*Math.PI/2),d=Math.cos(83/90*Math.PI/2);b.push(0,0,6371010);for(var e=0;10>=e;e++)b.push(6371010*d*Math.sin(e/10*2*Math.PI),6371010*d*Math.cos(e/10*2*Math.PI),6371010*c);b.push(0,0,-6371010);for(e=10;0<=e;e--)b.push(6371010*d*Math.sin(e/10*2*Math.PI),6371010*d*Math.cos(e/10*2*Math.PI),6371010*-c);this.f=HV(a,b);this.a=b.length/3}var AX=new eo;function BX(){this.o=this.b=this.m=this.s=this.v=this.i=this.h=this.g=this.f=this.c=this.C=this.j=this.l=this.D=this.G=this.u=this.A=this.B=null;this.H={}}var CX="#define _b 8\n#define _c 8000\n#define _d "+QB+"\n#define _e 2\n#define _f 16\n#define _g 8\n#define _h vec4(0., 0., 0., 0.2)\n#define _i 2\n#define _j 9\n#define _k 6\n#define _l 3\n#define _m 0\n#define _n 1\n#define _o 2\n#define _p 4\n#define _q 5\n#define _r 12\n#define _s 0\n#define _t 8\n#define _u 2\n#define _v 1\n#define _w 22\n\n"; +BX.prototype.a=function(a,b){b="#define _a "+b.f+"\n";var c=this.H[b];c||(c=zV(a,CX+b+"precision highp float;uniform float c,o;uniform vec4 d,f,j;uniform sampler2D e,g;vec2 xa(vec2 C,float D){float E=float(_r);C.y=E*C.y+D;return (C+.5)*d.zw;}vec2 Aa(vec4 C){return vec2(C.g+C.b*256.,C.a);}vec2 Ba(vec2 C){vec4 D=texture2D(g,(floor(C*65535.+.5)+.5)*f.zw);D=floor(D*255.+.5);return Aa(D);}float Ca(vec2 C,vec2 D){vec4 E=texture2D(e,C+D);float F,G;F=E.r*255.*4.;G=E.g*(255./64.);return F+G;}\n#if _a==1\nuniform float h;varying vec3 i;\n#endif\nuniform vec3 k,l;uniform mat4 m;\n#if _a==1\nuniform mat4 p;vec3 Da(vec3 C){const float D=6371010.;float E,F,G,H,I,J,K,L,M,N;E=C.x;F=exp(C.y);G=F*F;H=2.*F/(1.+G);I=(G-1.)/(1.+G);J=C.z*D*H;K=J+D;L=K*H*cos(E);M=K*H*sin(E);N=K*I;return vec3(L,M,N);}vec4 Ea(vec3 C){vec4 D,G;D=m*vec4(C,1);vec3 E,F;E=C;E/=o;E+=k+l;E.xy-=.5;E.y=-E.y;E*=3.141592653589793*2.;F=Da(E);G=p*vec4(F,1);G/=G.w;D/=D.w;return mix(D,G,h);}\n#else\nvec4 Ea(vec3 C){return m*vec4(C,1);}\n#endif\nvec3 Fa(vec3 C,vec3 D){vec3 E=C-k+(D-l);return E*o;}vec3 Ga(vec3 C){vec3 D,E;D=vec3(j.x,j.y,0);E=C*j.w;E.xy*=1./float(_f);return Fa(D,E);}float Ha(float C){float D,E;D=1./float(_w+1);E=1.-D-j.z*D;return C*D+E;}varying vec4 r,t;varying vec3 s;const float B=1.;attribute vec4 u;attribute vec4 v;attribute vec4 w;attribute float x;void main(){bool C,D,F,G,H,I,J,K,L,M,N,la,qa;C=true;if(x==2.)C=false;if(x==4.)C=false;if(x==5.)C=false;D=true;if(x==1.)D=false;if(x==2.)D=false;if(x==5.)D=false;float E,S,T,U,V,W,X,Y,aa,ba,ca,fa,ia,ja,ka,ma,na,oa,pa,ta,ua,va,wa;E=floor(w.w*255.+.5);F=fract(E*(1./2.))>=.5;G=fract(E*(1./4.))>=.5;H=fract(E*(1./8.))>=.5;I=fract(E*(1./16.))>=.5;J=fract(E*(1./32.))>=.5;K=fract(E*(1./64.))>=.5;L=fract(E*(1./128.))>=.5;M=F?I:G;N=F?J:H;vec2 O,P,Q,R,da,ea;O=Ba(v.xy);P=vec2(0,1.*d.w);Q=xa(O,float(_k));R=xa(O,float(_j));S=float(_s);r=texture2D(e,(F?R:Q)+S*P);T=float(_v);U=Ca(Q,T*P);V=Ca(R,T*P);W=F?V:U;X=W*.5;Y=U*.5;const float Z=3.141592653589793*2./256.;aa=floor(w.x*255.+.5);ba=floor((C?w.y:w.z)*255.+.5)*.5;ca=aa+ba;aa*=Z;ba*=Z;ca*=Z;da=vec2(cos(aa),sin(aa));ea=vec2(sin(ca),-cos(ca))/cos(ba);fa=tan(ba);vec3 ga,ha,ra;ga=Ga(vec3(floor(u.xy*32767.+.5),0));ha=Ga(vec3(floor(u.zw*32767.+.5),0));ia=length(ha.xy-ga.xy);if(N&&L)ia-=Y;if(M&&K)ia-=Y;ja=B/c;ka=ja*.5;la=C?M:N;ma=la?X+ka:0.;na=X+ka;oa=C?-1.:1.;pa=D?-1.:1.;s.x=C?0.:ia;s.y=0.;s.x+=ma*oa;s.x+=na*pa*fa;s.y+=na*pa;s.xy/=ia;s.z=float(M);s.z+=float(N)*.5;t.x=-ia/ja;t.y=-.5*W/ja+.5;qa=C?K:L;if(la&&qa)ma-=Y;ra=C?ga:ha;ra.xy+=ma*oa*da;ra.xy+=na*pa*ea;vec4 sa=Ea(ra);ta=v.z;ua=v.w;va=F?ua:ta;wa=Ha(va);gl_Position=vec4(sa.xy/sa.w,wa,1);if(sa.w<0.||r.a==0.)gl_Position=vec4(0);}", +CX+b+"precision highp float;precision highp float;\n#if _a==1\nvarying vec3 i;\n#endif\nvarying vec4 r,t;varying vec3 s;const float A=1.;float K(float B){const float C=0.;const float D=1.;const float E=.3;const float F=.3;const float G=2.*C-2.*D+E+F;const float H=3.*D-3.*C-2.*E-F;const float I=E;const float J=C;return clamp(((G*B+H)*B+I)*B+J,0.,1.);}void main(){vec2 B=vec2(s.x-clamp(s.x,0.,1.),s.y);float C,D,E,F,G,H,I;C=B.x*B.x+B.y*B.y;D=t.x;E=t.y;F=sqrt(C)*D;G=clamp(F-E+1.,0.,1.);H=clamp(F+E,0.,1.);if(A>1.){G=K(G);H=K(H);}I=clamp(G-H,0.,1.);if(I==0.)discard;gl_FragColor=r;gl_FragColor.a*=I;}", +["u","v","w","x"]),this.H[b]=c);this.b=c}; +BX.prototype.bind=function(a,b){this.a(a,b);if(this.o!=this.b){var c=this.b,d=function(b){return a.getUniformLocation(c,b)};this.B=d("a");this.A=d("b");this.u=d("c");this.G=d("d");this.D=d("e");this.l=d("f");this.j=d("g");this.C=d("h");this.c=d("j");this.f=d("k");this.g=d("l");this.h=d("m");this.i=d("n");this.v=d("o");this.s=d("p");this.m=d("q");this.o=this.b}a.useProgram(this.o);this.B&&a.uniform4fv(this.B,b.s.value);this.A&&a.uniform4fv(this.A,b.o.value);this.u&&a.uniform1f(this.u,b.b.value);this.G&& +a.uniform4fv(this.G,b.B.value);this.D&&a.uniform1i(this.D,b.A.value);this.l&&a.uniform4fv(this.l,b.v.value);this.j&&a.uniform1i(this.j,b.u.value);this.C&&a.uniform1f(this.C,b.c.value);this.c&&a.uniform4fv(this.c,b.C.value);this.f&&a.uniform3fv(this.f,b.g.value);this.g&&a.uniform3fv(this.g,b.h.value);this.h&&a.uniformMatrix4fv(this.h,!1,b.i.value);this.i&&a.uniform1f(this.i,b.j.value);this.v&&a.uniform1f(this.v,b.m.value);this.s&&a.uniformMatrix4fv(this.s,!1,b.a.value);this.m&&a.uniform1i(this.m,b.l.value)};function DX(a,b){this.c=a;this.g=b;this.f=yV(a,BX);this.a=new EW(!1);this.h=new ir(a,this.a.f.a,this.a.f.b,void 0);this.i=HV(a,[0,2,1,3,4,5])}function EX(a,b,c,d,e,f){this.za=a;this.yf=b;this.Ef=c;this.mf=d;this.Hb=e;this.Ie=f} +DX.prototype.b=function(a,b){var c=a.a,d=a.data,e=d.a;b=rI(d.getZoom(),b);if(!e||16<d.c||c.I||!(Ey(e)&&jy(Fy(e))||Gy(e)&&ly(Hy(e))))return 2;var f=d.b,g=c.f,h=d.getZoom();a=a.a.c;var k=[];if(Ey(e)&&jy(Fy(e)))for(var l=Fy(e).a,m=l.length,n=f.a[1],p=0;p<m;p++){var q=n[p],t=q.ka();t=CK(g,t);Xz(t,h)&&(k.push(new EX(q.za,q,l[p],null,1,k.length)),k.push(new EX(q.b,q,l[p],null,0,k.length)))}if(Gy(e)&&ly(Hy(e)))for(e=Hy(e).a,l=e.length,m=f.a[2],p=0;p<l;p++)f=e[p],n=m[p],t=n.ka(),t=CK(g,t),d.getZoom(),Xz(t, +h)&&!(1>t.c)&&null!=f.a&&(null==f.f?0:f.f)&&(k.push(new EX(n.za+1,n,null,f,0,k.length)),k.push(new EX(n.za+2,n,null,f,1,k.length)));k.sort(function(a,b){return a.za-b.za||a.Ie-b.Ie});this.a.reset(0,0,1,d.c);for(p=0;p<k.length;p++)g=k[p],h=g.yf,e=g.Ef,f=g.mf,t=h.ka(),t=ZV(a,t),e?FX(this,e,h,g.Hb,t,b,d.getZoom()):f&&GX(this,f,h,g.Hb,t);0!=this.a.a&&(d=PV(this.h,this.a.b,this.a.a),jO(c.a,d),c.I=d.a[0]);return 2}; +function FX(a,b,c,d,e,f,g){a=a.a;FW(a,Vw(b),Ww(b));a.D=d;GW(a,e);a.o=65535-c.b|65535-c.za<<16;FI(b,a,g,f)}function GX(a,b,c,d,e){a=a.a;FW(a,1,1);a.D=d;GW(a,e);a.o=65535-(c.za+1)|65535-(c.za+2)<<16;II(ux(b),a)};function HX(){this.f=this.b=this.g=this.c=null;this.h={}}HX.prototype.a=function(a){var b=this.h["\n"];b||(b=zV(a,"\n\nprecision highp float;attribute vec2 a;void main(){gl_Position=vec4(a,0,1);}","\n\nprecision highp float;uniform float b,c;void main(){float d,f;d=gl_FragCoord.y/c;if(d<b-40.)discard;vec4 e=d<b?vec4(.9,.9,.9,0):vec4(.7,.8,1,1);f=smoothstep(0.,40.,abs(d-b));gl_FragColor=mix(vec4(.95,.95,.95,1),e,f);}",["a"]),this.h["\n"]=b);this.b=b}; +HX.prototype.bind=function(a,b){this.a(a,b);if(this.f!=this.b){var c=this.b;this.c=a.getUniformLocation(c,"b");this.g=a.getUniformLocation(c,"c");this.f=this.b}a.useProgram(this.f);this.c&&a.uniform1f(this.c,b.P.value);this.g&&a.uniform1f(this.g,b.b.value)};function IX(a){this.c=yV(a,HX);this.a=new EV(1,[[2,5126]]);this.b=HV(a,[-1,-1,-1,1,1,-1,1,1])}function JX(a,b,c,d,e){d.P.set(e);TV(b,c,3,1,1,2,1);FV(b,a.a);KV(b,a.b,a.a);c=hq(b);a.c.bind(c,d);b.drawArrays(5,0,4);iq(b);GV(b,a.a)};function KX(){this.h=this.b=this.f=this.g=this.j=this.l=this.i=this.c=null;this.m={}} +KX.prototype.a=function(a){var b=this.m["\n"];b||(b=zV(a,"\n\nprecision highp float;varying vec2 a;attribute vec2 b;uniform float c;void main(){a=b;a.x*=c;gl_Position=vec4(b,1,1);}","\n\nprecision highp float;varying vec2 a;uniform float d;uniform vec3 e,f,g;uniform vec2 h;void main(){float i,j;i=d;j=length(a-h)/i;if(j<1.)discard;else{j=clamp(pow(j-1.,.5),0.,1.5);vec3 k=mix(mix(g,f,j),e,j-.5);gl_FragColor=vec4(k,1);}}",["b"]),this.m["\n"]=b);this.b=b}; +KX.prototype.bind=function(a,b){this.a(a,b);if(this.h!=this.b){var c=this.b;this.c=a.getUniformLocation(c,"c");this.i=a.getUniformLocation(c,"d");this.l=a.getUniformLocation(c,"e");this.j=a.getUniformLocation(c,"f");this.g=a.getUniformLocation(c,"g");this.f=a.getUniformLocation(c,"h");this.h=this.b}a.useProgram(this.h);this.c&&a.uniform1f(this.c,b.O.value);this.i&&a.uniform1f(this.i,b.Ka.value);this.l&&a.uniform3fv(this.l,b.Pa.value);this.j&&a.uniform3fv(this.j,b.Oa.value);this.g&&a.uniform3fv(this.g, +b.Ca.value);this.f&&a.uniform2fv(this.f,b.ya.value)};function LX(a,b){this.c=yV(a,KX);this.a=new EV(1,[[2,5126]]);this.b=HV(a,[-1,-1,-1,1,1,-1,1,1]);b.Pa.set(.09,.1,.28);b.Oa.set(.53,.81,.98);b.Ca.set(.7,.78,.86)};function MX(a,b){this.h=a;this.j=b;this.i=yV(a,lW);this.a=new EV(1,[[2,5126]]);this.f=0;this.g=a.createTexture();Uo(this.g,new Uint8Array([255,255,255,255]),1,1,6408,5121,0);this.b=null;this.c=0};function NX(){this.o=this.b=this.v=this.m=this.s=this.A=this.i=this.h=this.g=this.f=this.c=this.D=this.j=this.l=this.G=this.H=this.u=this.B=this.C=null;this.I={}}var OX="#define _b 8\n#define _c 8000\n#define _d "+QB+"\n#define _e 2\n#define _f 16\n#define _g 8\n#define _h vec4(0., 0., 0., 0.2)\n#define _i 2\n#define _j 9\n#define _k 6\n#define _l 3\n#define _m 0\n#define _n 1\n#define _o 2\n#define _p 4\n#define _q 5\n#define _r 12\n#define _s 0\n#define _t 8\n#define _u 2\n#define _v 1\n#define _w 22\n\n"; +NX.prototype.a=function(a,b){b="#define _a "+b.f+"\n";var c=this.I[b];c||(c=zV(a,OX+b+"precision highp float;uniform vec4 b,d,f;uniform float c,o,F;vec2 da(vec2 H){return (H*b.xy+b.xy)*.5;}vec2 ea(vec2 H){return (H*b.zw-vec2(.5))*2.;}vec2 fa(vec4 H,vec2 I,vec2 J,float F){I*=vec2(1,-1.);J*=vec2(1,-1.);vec2 K,L,M;K=da(H.xy/H.w);L=K+I;M=floor(L+.5);M+=(1.-F)*(L-M);M+=J;return M;}vec2 ga(vec4 H,vec2 I){return ea(I)*H.w;}uniform sampler2D e,g;vec2 ha(vec2 H,float I){float J=float(_r);H.y=J*H.y+I;return (H+.5)*d.zw;}vec2 ia(vec4 H){return vec2(H.g+H.b*256.,H.a);}float ja(float H){return mod(H,32.)/31.;}void ka(vec2 H,out float I,out vec2 J){vec4 K=texture2D(g,(floor(H*65535.+.5)+.5)*f.zw);K=floor(K*255.+.5);I=ja(K.r);J=ia(K);}\n#if _a==1\nuniform float h;varying vec3 i;\n#endif\nuniform vec3 k,l;uniform mat4 m;\n#if _a==1\nuniform mat4 p;vec3 la(vec3 H){const float I=6371010.;float J,K,L,M,N,O,P,Q,R,S;J=H.x;K=exp(H.y);L=K*K;M=2.*K/(1.+L);N=(L-1.)/(1.+L);O=H.z*I*M;P=O+I;Q=P*M*cos(J);R=P*M*sin(J);S=P*N;return vec3(Q,R,S);}vec4 ma(vec3 H){vec4 I,L;I=m*vec4(H,1);vec3 J,K;J=H;J/=o;J+=k+l;J.xy-=.5;J.y=-J.y;J*=3.141592653589793*2.;K=la(J);L=p*vec4(K,1);L/=L.w;I/=I.w;return mix(I,L,h);}\n#else\nvec4 ma(vec3 H){return m*vec4(H,1);}\n#endif\nvec3 na(vec3 H,vec3 I){vec3 J=H-k+(I-l);return J*o;}vec3 oa(vec2 H,vec2 I,vec2 J){vec3 K,L;K=vec3(H.x,I.x,J.x)*65535.+.5;\n#if _a==1\nK-=fract(K);\n#else\nK=floor(K);\n#endif\nK=K/65536.;K=(fract(K+.5)-.5)*4.;L=vec3(H.y,I.y,J.y)*65535.;L/=1073741824.;return na(K,L);}vec4 pa(vec2 H,vec2 I,vec2 J){vec3 K=oa(H,I,J);return ma(K);}varying float r;varying vec4 s,t,u,w;varying vec2 v;attribute float x;attribute vec4 A;attribute vec4 B;attribute vec4 C;attribute vec2 D;attribute vec2 E;void main(){float H,J,L,N,T,U,V,W,X,aa;H=floor(x*255.+.5);vec2 I,K,M,O,P,Q,R,S,Y,Z,ca;I=vec2(floor(H/2.),mod(floor((H+1.)/2.),2.));ka(C.zw,J,K);L=float(_m);M=ha(K,L);s=texture2D(e,M);N=float(_n);O=ha(K,N);t=texture2D(e,O);r=J;gl_Position=pa(B.yx,B.wz,C.yx);gl_Position/=gl_Position.w;gl_Position.z=D.x;P=c*floor(E*32767.+.5)/float(_f);Q=floor(A.xy*65535.+.5)*c;R=fa(gl_Position,P+vec2(0,Q.y/2.),vec2(0),F);S=fa(gl_Position,P+vec2(Q.x-1.,1.-Q.y/2.),vec2(0),F);T=c*floor(floor(A.w*65535.+.5)/16.);u=vec4(R,S);v=vec2(c*D.y,T);U=c*mod(floor(A.w*65535.+.5),16.);V=floor(A.z*65535.+.5);W=1.-floor(abs(1.5-V));X=2.*mod(V,2.)-1.;Y=X*vec2(W-1.,W);Z=fa(gl_Position,vec2(0),vec2(0),F);Z+=((S+R)*.5-Z)*abs(Y)+Y*((S-R)*.5+vec2(U));aa=sign(U);w=mix(vec4(u.xy,0,0),vec4(Z,U+1.,V),aa);vec4 ba=u;ba.x=min(w.x,ba.x)-1.;ba.y=min(w.y,ba.y)-T-1.;ba.z=max(w.x,ba.z)+T+1.;ba.w=max(w.y,ba.w)+1.;ca=mix(ba.xy,ba.zw,I);gl_Position.xy=ga(gl_Position,ca);gl_Position.xy*=sign(J);}", +OX+b+"precision highp float;precision highp float;\n#if _a==1\nvarying vec3 i;\n#endif\nprecision highp float;varying float r;varying vec4 s,t,u,w;varying vec2 v;float S(vec2 G,vec4 H){vec2 I=max(H.xy-G,G-1.-H.zw);float J=max(I.x,I.y);return clamp(.5-J,0.,1.);}float T(vec2 G,float H){vec2 I=G-w.xy;float J,K,L;J=floor(w.w+.5);I=mix(I,-I.yx,sign(mod(J,3.)));I*=2.*mod(J,2.)-1.;I.x-=H*1.414;K=clamp(I.x-abs(I.y),0.,1.);L=clamp(w.z+.5-I.x,0.,1.);return K*L;}float U(vec2 G){return max(S(G,u),T(G,0.));}void main(){vec2 G=gl_FragCoord.xy;float H,I,K,L,M,N,O;H=U(G);I=v.x;vec4 J,P,Q,R;J=u+vec2(I,-I).xxyy;K=S(G,J);L=T(G,I);M=max(K,L);N=0.;O=v.y;if(O>0.){vec2 P=G+vec2(-O,O);N+=U(P);N+=U(P+vec2(1,0));N+=U(P+vec2(0,-1.));N+=U(P+vec2(1,-1.));N*=s.a*.25;}P=mix(t,s,M);P.a*=H;Q=_h*vec4(1,1,1,N);R.rgb=P.rgb*P.a+Q.rgb*Q.a*(1.-P.a);R.a=1.-(1.-P.a)*(1.-Q.a);if(R.a==0.)discard;R.rgb/=R.a;R.a*=r;gl_FragColor=R;}", +"xABCDE".split("")),this.I[b]=c);this.b=c}; +NX.prototype.bind=function(a,b){this.a(a,b);if(this.o!=this.b){var c=this.b,d=function(b){return a.getUniformLocation(c,b)};this.C=d("a");this.B=d("b");this.u=d("c");this.H=d("d");this.G=d("e");this.l=d("f");this.j=d("g");this.D=d("h");this.c=d("j");this.f=d("k");this.g=d("l");this.h=d("m");this.i=d("n");this.A=d("o");this.s=d("p");this.m=d("q");this.v=d("F");this.o=this.b}a.useProgram(this.o);this.C&&a.uniform4fv(this.C,b.s.value);this.B&&a.uniform4fv(this.B,b.o.value);this.u&&a.uniform1f(this.u, +b.b.value);this.H&&a.uniform4fv(this.H,b.B.value);this.G&&a.uniform1i(this.G,b.A.value);this.l&&a.uniform4fv(this.l,b.v.value);this.j&&a.uniform1i(this.j,b.u.value);this.D&&a.uniform1f(this.D,b.c.value);this.c&&a.uniform4fv(this.c,b.C.value);this.f&&a.uniform3fv(this.f,b.g.value);this.g&&a.uniform3fv(this.g,b.h.value);this.h&&a.uniformMatrix4fv(this.h,!1,b.i.value);this.i&&a.uniform1f(this.i,b.j.value);this.A&&a.uniform1f(this.A,b.m.value);this.s&&a.uniformMatrix4fv(this.s,!1,b.a.value);this.m&&a.uniform1i(this.m, +b.l.value);this.v&&a.uniform1f(this.v,b.H.value)};function PX(a,b){this.c=a;this.g=b;this.f=yV(a,NX);this.a=new EV(6,[[4,5121],[4,5123],[4,5123],[4,5123],[2,5126],[2,5122]]);this.h=new ir(a,this.a.a,this.a.b,65536)} +function QX(a,b,c,d){var e=a.c,f=a.g,g=a.a;a=a.f;for(var h=!1,k=0;k<b.length;++k){var l=b[k];if(l.b&&l.b.a.ha[d]){h=!0;break}if(l.a.ha[d]){h=!0;break}}if(h){TV(e,c,3,3,1,2,1);FV(e,g);f.H.set(c.C);c=hq(e);a.bind(c,f);for(k=0;k<b.length;++k)if(b[k].b?(f=b[k].b.a.ha[d],h=b[k].a.ha[d]):(f=b[k].a.ha[d],h=null),f||h)l=b[k].a,c.uniform4f(a.c,l.g,l.h,l.m,l.b),NV(e,g,f,h);iq(e);GV(e,g)}} +PX.prototype.b=function(a,b){a=a.a;var c=a.c,d=this.a.f,e=b.a;if(!e.length)return 2;for(var f=new Uint32Array(e.length*this.a.h),g=new Float32Array(f.buffer),h=0,k=[0,1,2,0,2,3],l=0;l<e.length;++l)for(var m=e[l],n=m,p=m.label.b,q=ZV(c,m.a),t=0;t<k.length;t++)f[h+0]=k[t],f[h+1]=oI(n.width,n.height),f[h+2]=oI(n.h,n.i<<4|n.g&15),f[h+3]=pI(p.a,a.b,a.g),f[h+4]=pI(p.b,a.b,a.h),f[h+5]=pI(p.altitude,a.b,0),f[h+6]=oI(q.x,q.y),g[h+7]=tW(m),g[h+8]=n.m,f[h+9]=oI(16*n.oa,16*n.b),h+=d;c=PV(this.h,f);jO(a.a,c); +a.ha[b.b]=c.a[0];return 2};function RX(){this.o=this.b=this.c=this.f=this.h=this.g=this.l=this.m=this.i=this.j=null;this.s={}} +RX.prototype.a=function(a){var b=this.s["\n"];b||(b=zV(a,"\n\nprecision highp float;varying vec2 a;uniform vec2 b,d,e;uniform float c,f;attribute vec2 g;void main(){vec2 h,i;h=g*b*c+e;i=2.*(h/d)-1.;i.y*=f;gl_Position=vec4(i,1,1);a=g;}","\n\nprecision highp float;varying vec2 a;uniform sampler2D h;uniform float i,j;void main(){gl_FragColor=texture2D(h,a);gl_FragColor.a=gl_FragColor.a*i+j;}",["g"]),this.s["\n"]=b);this.b=b}; +RX.prototype.bind=function(a,b){this.a(a,b);if(this.o!=this.b){var c=this.b,d=function(b){return a.getUniformLocation(c,b)};this.j=d("b");this.i=d("c");this.m=d("d");this.l=d("e");this.g=d("f");this.h=d("h");this.f=d("i");this.c=d("j");this.o=this.b}a.useProgram(this.o);this.j&&a.uniform2fv(this.j,b.Y.value);this.i&&a.uniform1f(this.i,b.W.value);this.m&&a.uniform2fv(this.m,b.ha.value);this.l&&a.uniform2fv(this.l,b.Z.value);this.g&&a.uniform1f(this.g,b.U.value);this.h&&a.uniform1i(this.h,b.V.value); +this.f&&a.uniform1f(this.f,b.T.value);this.c&&a.uniform1f(this.c,b.S.value)};function SX(a,b){this.c=a;this.g=b;this.f=yV(a,RX);this.a=new EV(1,[[2,5126]]);this.b=HV(a,[0,0,1,0,0,1,1,1])}function TX(a,b,c){var d=b.j,e=b.i,f=a.c,g=a.g,h=f.a.vb()+1-1;f.a.xa(h,b);g.V.set(h);g.Y.set(d,e);g.W.set(1);g.ha.set(d,e);g.Z.set(0,0);g.T.set(B(c)?c:1);g.S.set(0);g.U.set(1);FV(f,a.a);KV(f,a.b,a.a);b=hq(f);a.f.bind(b,g);f.drawArrays(5,0,4);iq(f);GV(f,a.a)};function UX(){this.value=0}UX.prototype.set=function(a){this.value=a};function VX(){this.value=0}VX.prototype.set=function(a){this.value=a};function WX(){this.value=new Float32Array(16)} +WX.prototype.set=function(a,b,c,d,e,f,g,h,k,l,m,n,p,q,t,v){this.value[0]=a;this.value[1]=b;this.value[2]=c;this.value[3]=d;this.value[4]=e;this.value[5]=f;this.value[6]=g;this.value[7]=h;this.value[8]=k;this.value[9]=l;this.value[10]=m;this.value[11]=n;this.value[12]=p;this.value[13]=q;this.value[14]=t;this.value[15]=v};function XX(a,b){for(var c=0;16>c;c++)a.value[c]=b[c]}function YX(){this.value=new Float32Array(2)}YX.prototype.set=function(a,b){this.value[0]=a;this.value[1]=b}; +function ZX(){this.value=new Float32Array(3)}ZX.prototype.set=function(a,b,c){this.value[0]=a;this.value[1]=b;this.value[2]=c};function $X(){this.value=new Float32Array(4)}$X.prototype.set=function(a,b,c,d){this.value[0]=a;this.value[1]=b;this.value[2]=c;this.value[3]=d};function aY(){this.L=new UX;this.O=new UX;this.P=new UX;this.S=new UX;this.T=new UX;this.U=new UX;this.V=new VX;this.W=new UX;this.Y=new YX;this.Z=new YX;this.ha=new YX;this.fa=new ZX;this.ga=new ZX;this.ia=new UX;this.ja=new ZX;this.pa=new ZX;this.ra=new ZX;this.va=new ZX;this.g=new ZX;this.h=new ZX;this.i=new WX;this.j=new UX;this.ya=new YX;this.Zb=new VX;this.Za=new UX;this.I=new UX;this.$a=new YX;this.ib=new $X;this.jb=new UX;this.u=new VX;this.v=new $X;this.Ba=new VX;this.Ca=new ZX;this.D=new VX; +this.G=new $X;this.M=new UX;this.l=new VX;this.J=new UX;this.Da=new UX;this.Ga=new UX;this.a=new WX;this.Bb=new UX;this.outline=new VX;this.b=new UX;this.H=new UX;this.m=new UX;this.Ia=new VX;this.Ja=new $X;this.Ka=new UX;this.qb=new UX;this.la=new UX;this.o=new $X;this.ea=new YX;this.hc=new UX;this.K=new VX;this.s=new $X;this.La=new UX;this.Oa=new ZX;this.Pa=new ZX;this.c=new UX;this.Qa=new $X;this.Ra=new YX;this.rb=new $X;this.sb=new $X;this.Hb=new VX;this.Ya=new YX;this.Sa=new UX;this.A=new VX; +this.B=new $X;this.text=new VX;this.Wa=new $X;this.C=new $X;this.f=0};function bY(a,b,c,d,e){if(b[d+1]==b[e+1]){var f=c;c=e;e=f}else b[c+1]==b[e+1]&&(f=d,d=e,e=f);b[c+1]!=b[d+1]&&(b[c+1]>b[d+1]&&(f=c,c=d,d=f),b[d+1]>b[e+1]&&(f=d,d=e,e=f),b[c+1]>b[d+1]&&(f=c,c=d,d=f));f=b[c];var g=b[d],h=b[e];c=b[c+1];d=b[d+1];b=b[e+1];c!=b&&(e=f+(d-c)/(b-c)*(h-f),cY(a,Math.min(e,g),h,Math.max(e,g),d,b),c!=d&&cY(a,Math.min(e,g),f,Math.max(e,g),d,c))} +function cY(a,b,c,d,e,f){var g=(c-b)/(f-e);c=(c-d)/(f-e);var h=Math.min(e,f);f=Math.max(e,f);h=Math.max(0,Math.floor(.999+h));for(f=Math.min(255,Math.floor(f));h<=f;h++){var k=h-e,l=b+g*k;k=d+c*k;l=Math.max(0,Math.floor(.999+l));for(k=Math.min(255,Math.floor(k));l<=k;l++)a[256*h+l]=255}};function dY(){this.a=new sI(0,!1)};function eY(){this.s=this.c=this.Zb=this.Ya=this.hc=this.ea=this.b=this.o=this.u=this.A=this.j=this.i=this.h=this.g=this.f=this.D=this.l=this.m=this.G=this.H=this.v=this.B=this.C=null;this.I={}}var fY="#define _b 8\n#define _c 8000\n#define _d "+QB+"\n#define _e 2\n#define _f 16\n#define _g 8\n#define _h vec4(0., 0., 0., 0.2)\n#define _i 2\n#define _j 9\n#define _k 6\n#define _l 3\n#define _m 0\n#define _n 1\n#define _o 2\n#define _p 4\n#define _q 5\n#define _r 12\n#define _s 0\n#define _t 8\n#define _u 2\n#define _v 1\n#define _w 22\n\n"; +eY.prototype.a=function(a,b){b="#define _a "+b.f+"\n";var c=this.I[b];c||(c=zV(a,fY+b+"precision highp float;uniform vec4 d,j;uniform sampler2D e;vec2 N(vec2 x,float B){float C=float(_r);x.y=C*x.y+B;return (x+.5)*d.zw;}\n#if _a==1\nuniform float h;varying vec3 i;\n#endif\nuniform vec3 k,l;uniform mat4 m;uniform float o,u,w;\n#if _a==1\nuniform mat4 p;vec3 O(vec3 B){const float C=6371010.;float D,E,F,G,H,I,J,K,L,M;D=B.x;E=exp(B.y);F=E*E;G=2.*E/(1.+F);H=(F-1.)/(1.+F);I=B.z*C*G;J=I+C;K=J*G*cos(D);L=J*G*sin(D);M=J*H;return vec3(K,L,M);}vec4 P(vec3 B){vec4 C,F;C=m*vec4(B,1);vec3 D,E;D=B;D/=o;D+=k+l;D.xy-=.5;D.y=-D.y;D*=3.141592653589793*2.;E=O(D);F=p*vec4(E,1);F/=F.w;C/=C.w;return mix(C,F,h);}vec3 Q(vec3 B){B/=o;B+=k+l;B.xy-=.5;B.y=-B.y;B*=3.141592653589793*2.;vec3 C=mat3(p)*O(B);return normalize(C);}\n#else\nvec4 P(vec3 B){return m*vec4(B,1);}\n#endif\nvec3 R(vec3 B,vec3 C){vec3 D=B-k+(C-l);return D*o;}vec3 S(vec3 B){vec3 C,D;C=vec3(j.x,j.y,0);D=B*j.w;D.xy*=1./float(_f);return R(C,D);}vec4 T(vec3 B){vec3 C=S(B);return P(C);}float U(vec4 B){float C,D;C=1./float(_w+1);D=1.-C-j.z*C;return B.z*C+B.w*D;}void V(vec3 j){\n#if _a==1\nvec3 B=S(j);i=Q(B);\n#endif\n}precision highp float;varying vec2 r;varying vec3 s;attribute vec2 t;uniform vec2 v,x;void main(){vec3 j=vec3(floor(t*32767.+.5),0);V(j);gl_Position=T(j);gl_Position.xy+=v*gl_Position.w;gl_Position.z=gl_Position.w*u;gl_Position.z=U(gl_Position);r=j.xy*w;vec2 B=N(x,float(_l));s=texture2D(e,B).rgb;}", +fY+b+"precision highp float;precision highp float;\n#if _a==1\nuniform float h;varying vec3 i;\n#endif\nfloat D(){\n#if _a==1\nfloat B,C;B=dot(i,vec3(-1.,1,-1.));C=clamp((B-.5)/4.+1.,.5,1.);return mix(1.,C,h);\n#else\nreturn 1.;\n#endif\n}precision highp float;varying vec2 r;varying vec3 s;uniform sampler2D A;void main(){float B,C;B=texture2D(A,r).a;if(B<.5)discard;C=D();gl_FragColor=vec4(s*C,1);}",["t"]),this.I[b]=c);this.c=c}; +eY.prototype.bind=function(a,b){this.a(a,b);if(this.s!=this.c){var c=this.c,d=function(b){return a.getUniformLocation(c,b)};this.C=d("a");this.B=d("b");this.v=d("c");this.H=d("d");this.G=d("e");this.m=d("f");this.l=d("g");this.D=d("h");this.f=d("j");this.g=d("k");this.h=d("l");this.i=d("m");this.j=d("n");this.A=d("o");this.u=d("p");this.o=d("q");this.b=d("u");this.ea=d("v");this.hc=d("w");this.Ya=d("x");this.Zb=d("A");this.s=this.c}a.useProgram(this.s);this.C&&a.uniform4fv(this.C,b.s.value);this.B&& +a.uniform4fv(this.B,b.o.value);this.v&&a.uniform1f(this.v,b.b.value);this.H&&a.uniform4fv(this.H,b.B.value);this.G&&a.uniform1i(this.G,b.A.value);this.m&&a.uniform4fv(this.m,b.v.value);this.l&&a.uniform1i(this.l,b.u.value);this.D&&a.uniform1f(this.D,b.c.value);this.f&&a.uniform4fv(this.f,b.C.value);this.g&&a.uniform3fv(this.g,b.g.value);this.h&&a.uniform3fv(this.h,b.h.value);this.i&&a.uniformMatrix4fv(this.i,!1,b.i.value);this.j&&a.uniform1f(this.j,b.j.value);this.A&&a.uniform1f(this.A,b.m.value); +this.u&&a.uniformMatrix4fv(this.u,!1,b.a.value);this.o&&a.uniform1i(this.o,b.l.value);this.b&&a.uniform1f(this.b,b.I.value);this.ea&&a.uniform2fv(this.ea,b.ea.value);this.hc&&a.uniform1f(this.hc,b.hc.value);this.Ya&&a.uniform2fv(this.Ya,b.Ya.value);this.Zb&&a.uniform1i(this.Zb,b.Zb.value)};function gY(a,b){this.a=a;this.j=b;this.i=yV(a,eY);this.c=new EV(3,[[2,5122]]);this.l=new ir(this.a,this.c.a,this.c.b,void 0);b=IV(-16,4112,8,-16,4112,8);b=new Int16Array(b);b=new Uint32Array(b.buffer);this.g=PV(this.l,b).a[0];this.f=a.createTexture();Uo(this.f,new Uint8Array([255,255,255,255]),1,1,6408,5121,0);this.h=new dY}function hY(){this.b=0;this.a=null}var iY=new eo;function jY(a,b,c){a.hc.set(1/4096);a.Zb.set(2);a.ea.set(b.Va.x,b.Va.y);wX(c,b.md,iY);a.Ya.set(iY.x,iY.y)} +gY.prototype.b=function(a,b){var c=a.a,d=a.data,e=d.a,f=this.a,g=0;if(!rI(d.getZoom(),b))return 2;d=a.data.A;var h;b=[];if(Gy(e)&&ly(Hy(e))){e=Hy(e).a;for(var k=a.data.b.a[2],l=0;l<e.length;l++){var m=e[l],n=m.getExtension(177034656);if(n&&(null==n.a?0:n.a)){g=k[l].za;if(null==m.c?0:m.c){var p=!0;break}null!=m.a&&b.push(ux(m))}}}if(b.length&&!d)a:{d=this.h;a=a.data.c;e=new Uint8Array(65536);for(k=0;k<b.length;k++){m=b[k];n=d.a;l=a;n.reset();LI(m,n,!1);m=n.h.subarray(0,n.b);if(0==m.length)m=null;else{n= +new Float32Array(2*m.length);for(var q=0;q<m.length;q++){var t=m[q];n[2*q+0]=(t<<16>>16)/l;n[2*q+1]=(t>>16)/l}m=n}if(!m){d=null;break a}n=m.length/6;if(0!=n)for(l=e,n=n?6*n:m.length,q=0;q<n;q+=6)bY(l,m,q,q+2,q+4)}d=new VQ(e,256,256,4)}d&&(h=new CT(d));if(!h&&!p)return 2;b=c.a;p=new hY;h&&(d=h.Yb().width,d=iO(b,d*d),b=b.c[d],Mo(b,33071),No(b,9729),Oo(b,9729),XQ(f,h),p.a=b);p.b=1-g/65535;c.ya=p;return 2};function kY(a,b){rc.call(this);this.v=1;this.a=a;this.b=new aY;this.D=new no(this);this.C=this.h=this.J=this.L=this.K=this.j=this.i=this.I=this.G=this.s=this.m=this.l=this.B=this.A=this.H=this.g=this.M=this.c=null;this.f=0;this.P=b;lY(this);a=this.a.getContext();this.D.cb(a,"webglcontextrestored",this.T,!1);this.D.cb(a,"webglcontextlost",this.S,!1)}F(kY,rc);var mY=[];function nY(a){return[a.c,a.H,a.A,a.g]}function oY(a){var b=[];b[0]=a.l;b[1]=a.B;b[2]=a.m;b[3]=a.s;b[4]=a.i;b[5]=a.j;return b} +function pY(a){return[a.G,a.I]}kY.prototype.S=function(){var a=this.a;Sq(a.b);Sq(a.a);Sq(a.f);Sq(a.c);Sq(a.g);this.dispatchEvent("webglcontextlost")};kY.prototype.T=function(){var a=this.a.getContext(),b=this.a.b;Tq(b,a);b.clear();b=this.a.a;Tq(b,a);b.clear();b=this.a.f;Tq(b,a);b.clear();b=this.a.g;Tq(b,a);b.clear();b=this.a.c;Tq(b,a);b.clear();lY(this);this.dispatchEvent("webglcontextrestored")}; +function qY(a,b){var c=a.a.b;Wq(c);for(var d=0;d<b.length;++d){var e=b[d],f=e.a,g=f.a;g&&(f.u&&f.u.Fa(g),f.A&&f.A.Fa(g));e.b&&(f=e.b.a,g=f.a)&&(f.u&&f.u.Fa(g),f.A&&f.A.Fa(g))}Yq(c);c=a.a.a;Wq(c);for(d=0;d<b.length;++d)e=b[d],f=e.a,g=f.a,f.c&&g&&f.c.Fa(g),e.b&&(f=e.b.a,g=f.a,f.c&&g&&f.c.Fa(g));Yq(c);c=a.a.c;Wq(c);for(d=0;d<b.length;++d)e=b[d],f=e.a,g=f.a,f.o&&g&&f.o.f.Fa(g),e.b&&(f=e.b.a,g=f.a,f.o&&g&&f.o.f.Fa(g));Yq(c);c=a.a.f;Wq(c);for(d=0;d<b.length;++d)e=b[d],f=e.a,g=f.a,f.o&&g&&f.o.Fa(g),e.b&& +(f=e.b.a,g=f.a,f.o&&g&&f.o.Fa(g));Yq(c);a=a.a.g;Wq(a);for(d=0;d<b.length;++d)e=b[d],f=e.a,g=f.a,f.H&&g&&f.H.Fa(g),e.b&&(f=e.b.a,g=f.a,f.H&&g&&f.H.Fa(g));Yq(a)} +function rY(a,b,c,d,e,f){var g=a.a.getContext(),h=a.b;if(g&&!g.isContextLost()){for(var k=!1,l=0;l<c.length;l++){var m=c[l];if(m.data.g||m.b&&m.b.data.g)k=!0}l=f.g&&!f.L;m=f.g&&!f.K&&!f.u;k=!f.M&&f.h&&k;var n=!f.v&&(!f.g||f.h),p=f.A;h.f=p?1:0;h.c.set(p?1:0);f.B=p||0!=d.o||0!=d.b;f.b=p?8:1;f.J=p?new rN(0,0):zN(d);f.m=AN(d);h.m.set(f.m);p=BN(d);XX(h.i,p);h.l.set(.2618<=Math.abs(d.b)?1:0);h.j.set(d.b);p=gG();var q=MJ();eP(d,p);OJ(q,p);XX(h.a,q);var t=a.a;p=t.getContext();q=a.b;p.a.Ua(null);Vq(t.b);Vq(t.a); +Vq(t.f);Vq(t.g);Vq(t.c);sY(e,c,f);f.h&&qY(a,c);tY(a);q.s.set(f.j,f.i,1/f.j,1/f.i);q.o.set(f.f,f.c,1/f.f,1/f.c);q.b.set(f.l);t=[0,0];var v=tX(e,t);p.a.xa(0,v);q.A.set(0);q.B.set(t[0],t[1],1/t[0],1/t[1]);uY(a,c);p=a.a.a;fr(p,1);a.b.u.set(1);a.b.v.set(p.c,p.a,1/p.c,1/p.a);for(p=f.J.start;p<=f.J.a;p++){q=f;t=h;var u=2*Math.PI;v=d.h/u+.5;var w=-d.i/u+.5,y=d.m/u;v-=p;u=Math.round(65536*v)/65536;var A=Math.round(65536*w)/65536,z=Math.round(65536*y)/65536;t.g.set(u,A,z);v=new Float32Array([v-u,w-A,y-z]); +t.h.set(v[0],v[1],v[2]);q.H=u+v[0];q.I=A+v[1];l&&(f.A&&(g.depthRange(0,1),q=a.J,t=a.a.getContext(),v=f,w=a.b,1==w.c.value&&(TV(t,v,3,3,1,1,1),FV(t,q.c),KV(t,q.f,q.c),t.b.Fb(!1),u=hq(t),q.b.bind(u,w),wX(t,v.md,AX),u.uniform2f(q.b.Ya,AX.x,AX.y),t.drawArrays(6,0,q.a/2),wX(t,v.G,AX),u.uniform2f(q.b.Ya,AX.x,AX.y),t.drawArrays(6,q.a/2,q.a/2),iq(t),t.b.Fb(!0),GV(t,q.c)),f.D||(q=a.L,t=a.a.getContext(),w=f,v=a.b,A=d,u=WF(),uG(A.j,A.l,A.f,u,1),u=1/((1+u[2])*Math.tan(A.g/2)),A=A.c/A.a,z=new Float32Array(4), +z[3]=1,RJ(v.a.value,z,z),y=z[0]/z[3],z=z[1]/z[3],u*u<(1-z)*(1-z)+A*(1-y)*A*(1-y)&&(TV(t,w,3,3,1,1,1),FV(t,q.a),KV(t,q.b,q.a),v.ya.set(y,z),v.O.set(A),v.Ka.set(u),t.b.Fb(!1),w=hq(t),q.c.bind(w,v),t.drawArrays(5,0,4),iq(t),t.b.Fb(!0),GV(t,q.a)))),vY(a,b,f,e));m&&(g.depthRange(.1,.2),q=a.g,t=b,v=f,w=q.h,u=q.f,fW(t)&&(FV(u,q.a),eW(q,v),TV(u,v,1,3,1,2,2),UV(u,v,1024),A=hq(u),q.c.bind(A,w),gW(q,A,t,q.c.b),TV(u,v,3,3,4,2,2),gW(q,A,t,q.c.b),q.g.bind(A,w),gW(q,A,t,q.g.c),iq(u),GV(u,q.a)));if(k)for(g.depthRange(0, +.1),q=a,t=c,v=f,w=q.a.getContext(),RV(w,v),w=0;2>w;w++)$W(q.l,t,v,w),QX(q.B,t,v,w),hX(q.m,t,v,w),lX(q.s,t,v,w),vW(q.i,t,v,w),DW(q.j,t,v,w);if(n){q=a.h;t=b;v=f;w=q.a;u=q.o;var C=v.l,I=v.s,S=v.b;A=!(v.g||v.h);y=v.zoom;z=v.O;if(q.l!=C||q.g!=I||q.m!=S)pW(q,C,I,S),q.l=C,q.g=I,q.m=S;u.I.set(0);u.ea.set(0,0);u.K.set(3);w.a.xa(3,q.h);FV(w,q.f);KV(w,q.i,q.f);TV(w,v,3,1,1,2,2);C=hq(w);q.c.bind(C,u);qW(q,C,t,v,A,y,z);iq(w);GV(w,q.f)}}f.g&&!f.D&&(g.depthRange(0,1),b=yN(d),0<b&&b<d.a&&JX(a.K,a.a.getContext(), +f,a.b,d.a-b));gr(a.a.a)}}function uY(a,b){for(var c=a.f=0;c<b.length;++c){var d=b[c];rO(d);var e=d.a.a;a.f+=e.a;d.b&&!UM(d.b.data)&&(e=d.b.a.a,a.f+=e.a)}}function tY(a){a=a.a.getContext().a;for(var b=0;6>=b;++b)a.xa(b,null)} +function vY(a,b,c,d){var e=a.a.getContext();b=b.filter(function(a){return a.a.length&&a.a[0].a.length});for(var f=0;f<b.length;++f){var g=b[f],h=.8/b.length,k=1-h*f;e.depthRange(k-h,k);h=[];for(k=0;k<g.a.length;++k)for(var l=g.a[k],m=0;m<l.a.length;++m){var n=l.a[m];n.data&&h.push(n)}h.length&&wY(a,h,c,d)}RV(e,c)} +function sY(a,b,c){if(b.length){var d=a.a;++d.a;d.c=0;pX(a.a,0);xX(a,[c.md,c.G]);for(c=0;c<b.length;++c){d=b[c];var e=d.a.va;e&&e.length&&xX(a,e);e=d.a.f;0<e.c&&(e=JR(e),e.length&&xX(a,e));(d=d.b&&d.b.a.f)&&0<d.c&&(e=JR(d),e.length&&xX(a,e))}}} +function wY(a,b,c,d){var e=a.a.getContext();if(c.B){UV(e,c,1024);e=a.M;var f=e.h,g=e.j,h=e.i;if(e.f!=c.b){var k=JV(f,0,4096,c.b,0,4096,c.b);e.b=k.buffer;e.c=k.size;e.f=c.b}FV(f,e.a);KV(f,e.b,e.a);TV(f,c,1,1,3,2,2);g.K.set(3);g.L.set(1);g.M.set(1);g.I.set(0);g.ea.set(c.Va.x,c.Va.y);f.a.xa(3,e.g);k=hq(f);h.bind(k,g);for(g=0;g<b.length;g++){var l=b[g].a;f.stencilFunc(516,l.Z,255);k.uniform4f(h.b,l.g,l.h,l.m,l.b);f.drawArrays(4,0,e.c)}iq(f);GV(f,e.a)}e=a.c;d=d.b;for(f=0;f<b.length;f++){l=k=null;var m= +null;if(b[f].b){h=b[f].b;k=b[f];g=h.a.ga;var n=h.a.Ba;l=k.a.ga;m=k.a.Ba}else h=b[f],g=h.a.ga,n=h.a.Ba;c.u&&(n=g=null);if(g||l||n||m)if(e.c.push(h.a),e.f.push(g),e.h.push(n),e.g.push(l),e.i.push(m),h&&VV(h,d,c.zoom)||k&&VV(k,d,c.zoom))e.j.push(h.a),e.l.push(g),e.o.push(n),e.m.push(l),e.s.push(m)}YV(a.c,c,!1,!1);YV(a.c,c,!1,!0);d=a.G;e=d.f;l=d.j;f=d.i;n=!1;for(h=0;h<b.length;h++)if(k=yW(b[h],c),g=zW(b[h]),k||g){n=!0;break}if(n){TV(e,c,3,3,2,2,2);d.h!=c.b&&(h=JV(e,-8,4104,c.b,-8,4104,c.b),d.g=h.buffer, +d.a=h.size,d.h=c.b);l.K.set(3);l.L.set(1);l.M.set(1);l.ea.set(0,0);FV(e,d.c);KV(e,d.g,d.c);n=hq(e);f.bind(n,l);for(h=0;h<b.length;++h)if(k=yW(b[h],c),g=zW(b[h]),k||g){l=b[h].a;n.uniform4f(f.b,l.g,l.h,l.m,l.b);SV(e,c,l.Z,l.g,l.h,l.b);if(k)for(l=0;l<k.length;l++)e.a.xa(3,k[l].Xb),n.uniform1f(f.c,k[l].a),e.drawArrays(4,0,d.a);if(g)for(l=0;l<g.length;l++)e.a.xa(3,g[l].Xb),n.uniform1f(f.c,g[l].a),e.drawArrays(4,0,d.a)}iq(e);GV(e,d.c)}YV(a.c,c,!0,!1);d=a.I;e=d.a;g=d.j;f=d.c;h=d.i;TV(e,c,3,3,2,2,2);FV(e, +f);jY(g,c,e);k=hq(e);h.bind(k,g);for(g=0;g<b.length;++g)if(m=b[g],m.b?(l=m.b.a.ya,n=m.a.ya):(l=m.a.ya,n=null),l||n)m=m.a,k.uniform4f(h.f,m.g,m.h,m.m,m.b),SV(e,c,m.Z,m.g,m.h,m.b),l&&(e.a.xa(2,l.a||d.f),k.uniform1f(h.b,l.b),MV(e,f,d.g)),n&&(e.a.xa(2,n.a||d.f),k.uniform1f(h.b,n.b),MV(e,f,d.g));iq(e);GV(e,f);d=a.A;e=d.c;g=d.g;f=d.a.f;h=d.f;l=d.i;n=!1;for(k=0;k<b.length;k++)if(m=b[k].b,b[k].a.I||m&&m.a.I){n=!0;break}if(n){TV(e,c,3==c.s?5:3,3,2,2,2);FV(e,f);LV(e,l,f);l=hq(e);h.bind(l,g);for(k=0;k<b.length;k++)if(b[k].b? +(g=b[k].b.a.I,n=b[k].a.I):(g=b[k].a.I,n=null),g||n)m=b[k].a,l.uniform4f(h.c,m.g,m.h,m.m,m.b),SV(e,c,m.Z,m.g,m.h,m.b),OV(e,f,g,n);iq(e);GV(e,d.a.f)}VW(a.H,b,c);YV(a.c,c,!0,!0);a=a.c;a.c=[];a.f=[];a.h=[];a.g=[];a.i=[];a.j=[];a.l=[];a.o=[];a.m=[];a.s=[]} +function lY(a){var b=a.a.getContext(),c=a.b,d=a.P,e=a.a.c,f=a.a.b,g=a.a.f,h=a.a.g;a.c=new XV(b,c);a.I=new gY(b,c);a.g=new dW(b,c);a.h=new nW(b,c);a.i=new uW(b,c,f,d);a.G=new xW(b,c);a.j=new CW(b,c,f);a.H=new UW(b,c,f);a.l=new ZW(b,c);a.m=new gX(b,c,g,e);a.s=new kX(b,c,h,d);a.A=new DX(b,c);a.L=new LX(b,c);a.J=new zX(b);a.K=new IX(b);a.M=new MX(b,c);a.B=new PX(b,c);a.C=new SX(b,c)};function xY(a,b,c,d,e,f,g){dQ.call(this,a,b,c,d,e,f,g);this.c=d}F(xY,dQ);xY.prototype.f=function(){return new cQ(this.c.wd())};xY.prototype.g=function(){return this.c};xY.prototype.getContext=function(){return this.c.getContext()};xY.prototype.X=function(){this.c.$();xY.R.X.call(this)};function yY(){this.h=this.g=!0;this.A=this.K=this.D=this.L=this.M=this.O=this.v=!1;this.T=0;this.S=this.P=45;this.m=this.zoom=this.I=this.H=0;this.J=new rN(0,0);this.a=new eo(0,0);this.Va=new eo(0,0);this.b=1;this.B=!1;this.i=this.j=this.c=this.f=0;this.l=1;this.s=0;this.clearColor=ZH;this.o=new oq(0,0,0,0);this.C=1;this.u=!1;this.G=this.md=0};function zY(a){this.b=a;this.c=-1;this.a=1}function AY(a,b){var c=a.c!=b;a.c=b;c?(a.a-=.2,0>=a.a&&(a.a=0),a.b()):(a.a+=.2,1<=a.a?a.a=1:a.b());return a.a};function BY(a,b,c){this.h=a;this.i=b;this.l=c;this.f=new SF;this.j=1;this.c=0;this.b={};this.g=this.a=0}BY.prototype.capture=function(a){jQ(this.h,this.f);this.j=this.i.f;this.c=0;this.b={};for(var b=this.a=0;b<a.length;++b){var c=a[b];0<c.a.B&&(this.c++,this.b[c.a.B]=!0);c.a.c&&c.a.c.f>this.a&&(this.a=c.a.c.f);c.b&&c.b.a.c&&c.b.a.c.f>this.a&&(this.a=c.b.a.c.f);c.b&&0<c.b.a.B&&(this.c++,this.b[c.b.a.B]=!0)}this.g=this.l.o};var CY=new SF; +function DY(a,b){jQ(a.h,CY);if(!TF(CY,a.f)||a.j!=a.i.f||a.g!=a.l.o)return!1;for(var c=0,d=0;d<b.length;++d){var e=b[d];if(0<e.a.B){if(!a.b[e.a.B])return!1;c++}if(e.b&&0<e.b.a.B){if(!a.b[e.b.a.B])return!1;c++}if(e.a.c&&e.a.c.f>a.a||e.b&&e.b.a.c&&e.b.a.c.f>a.a)return!1}return c!=a.c?!1:!0};function EY(){this.b=this.c=this.a=null;this.height=this.width=0} +function FY(a,b,c,d,e){if(!a.a||!!a.c!=e||a.width!=c||a.height!=d){var f=b.a.f,g=b.a.h,h=Po(b.b),k=b.a.c[h-33984];a.a&&b.deleteFramebuffer(a.a);a.c&&b.deleteRenderbuffer(a.c);a.b&&b.deleteTexture(a.b);var l=b.createFramebuffer();b.bindFramebuffer(36160,l);var m=null;e&&(m=b.createRenderbuffer(),b.bindRenderbuffer(36161,m),b.renderbufferStorage(36161,34041,c,d),b.framebufferRenderbuffer(36160,33306,36161,m));e=b.createTexture();No(e,9728);Oo(e,9728);Mo(e,33071);b.bindTexture(3553,e);Uo(jq(b,3553), +null,c,d,6408,5121,0);b.framebufferTexture2D(36160,36064,3553,e,0);a.a=l;a.c=m;a.b=e;a.width=c;a.height=d;f&&b.bindFramebuffer(36160,f);g&&b.bindRenderbuffer(36161,g);B(h)&&B(k)&&(b.activeTexture(h),b.bindTexture(3553,k))}}EY.prototype.bind=function(a){a.bindFramebuffer(36160,this.a);a.viewport(0,0,this.width,this.height)};function GY(a,b){a=a.toString();b&&(a+="-"+b);return a};function HY(a,b,c,d,e,f){this.a=a;this.text=b;this.width=c;this.height=d;this.b=e;this.name=f}function IY(a,b,c,d){JW.call(this,a.b);this.g=b;this.f=[];this.h={};this.l=-1;this.m=d;for(a=0;a<c.length;++a)b=c[a],(d=this.c)&&b.height>d.v||this.f.push(b)}F(IY,JW);r=IY.prototype;r.Ob=function(){return this.f.length};r.ac=function(a){return this.f[a].name};r.$b=function(a){a=this.f[a];var b=RA(this.g.a,a.a);return b&&fA(b,this.m)?Zs(fA(b,this.m),a.width,a.height,a.b,a.text):null}; +r.zb=function(a){return this.f[a].width+1};r.yb=function(a){a=4*Math.ceil((this.f[a].height+1)/4);8>a&&(a=8);return a};r.Na=function(a){if(a=IY.R.Na.call(this,a))for(var b=0;b<this.f.length;++b){var c=this.f[b],d=GY(c.a,c.text);-1!=this.b[b]&&(this.h[d]=new pq(KW(this,b),LW(this,b),c.width,c.height))}return a};r.Pb=function(){return this.l!=this.g.c||IY.R.Pb.call(this)};r.Fa=function(a){IY.R.Fa.call(this,a);this.l=this.g.c};function wW(a,b,c,d){b=GY(b,c);0!=a.a||a.Na(d);return a.h[b]};var JY=null;function KY(a){1500>a&&(a=1500);var b=JY;if(!b||b.length<a)b=JY=new Float32Array(a);return b} +function LY(a,b,c,d,e){var f=c.left,g=c.top,h=c.width,k=c.height,l=Math.floor(c.width/2),m=Math.floor(c.height/2);c=h;for(var n=0,p=k,q=0,t=0;t<k;++t)for(var v,u=0;u<h;++u){var w=f+u,y=g+t;w=a[4*(w+b*y)+3];0<w&&(u<c&&(c=u),u>n&&(n=u),t<p&&(p=t),q=t)}e.left=-4-l;e.top=-4-m;e.width=h+8;e.height=k+8;if(c>n||p>q)return d.left=-l,d.width=h,d.top=-1,d.height=1,n=4*Math.ceil(e.width/4),e=new Uint8Array(n*e.height);c-=4;n+=4;p-=4;q+=4;d.left=c-l;d.top=p-m;d.width=n-c+1;d.height=q-p+1;d=n-c+1;l=q-p+1;m=KY(d* +l);var A=-c,z=-p;for(t=p;t<=q;++t){var C=0,I=-100;v=d*(t+z);for(u=c;u<=n;++u){0>u||u>=h||0>t||t>=k?w=0:(w=f+u,y=g+t,w=a[4*(w+b*y)+3]);var S=u+A;if((w==C||1.5>u-I)&&0==w%255)m[S+v]=255==w?u-I:I-u;else{if(w!=C){C=0<w-C?1:-1;var ca=I;I=u+C*(.5-w/255);for(var Z=u-1;Z>=c&&I-Z<=Z-ca;Z--)y=Z+A+v,C*m[y]<Z-I&&(m[y]=C*(Z-I))}m[S+v]=(w-128)/255}C=w}}n=4*Math.ceil(e.width/4);e=new Uint8Array(n*e.height);for(q=0;q<l;++q)for(t=q+p,v=d*q,A=0;A<d;++A){u=A+c;0>u||u>=h||0>t||t>=k?w=0:(w=f+u,y=g+t,w=a[4*(w+b*y)+3]); +if(255==w||0==w){u=w?1:-1;y=A+v;y=u*m[y];w=y*y;for(z=1;6>z&&z*z<w;z=-z+(0<z?0:1))0>q+z||q+z>=l||(y=A+d*(q+z),y=u*m[y],0>=y?(-.5>y&&(y=-.5),y=Math.abs(z)+y,y*=y):y=z*z+y*y,y<w&&(w=y));u=u*Math.sqrt(w)*12+128}else u=12*(w-128)/255+128;0>u&&(u=0);255<u&&(u=255);e[4+c+A+n*(4+p+q)]=u+.5}return e};function MY(a,b){this.b=a;this.a=this.b.getContext("2d");this.c=b}function NY(){this.b=this.a=0;this.text=""}function OY(a){this.a=new NY;this.f=a;this.height=this.width=this.c=this.b=0}var PY={},QY={},RY={};function SY(a,b,c){QY[a]=QY[a]||{};QY[a][b]=QY[a][b]||{};var d=QY[a][b][c];if(!B(d)){var e=(aX++).toString();bX[e.toString()]=new dX;d=QY[a][b][c]=e;var f=new NY;f.a=a;f.b=b;f.text=c;PY[e]=f}return d} +function TY(a,b,c){var d=UY,e=SY(a,b,c);if(!(bX[e]||null).data){var f=RY[e];f||(a=qL(a,b,d.c),d.a.font!=a&&(d.a.font=a),f=Math.ceil(d.a.measureText(c).width)," "!=c&&(f+=2),RY[e]=f)}return e}function VY(a,b){for(var c=0,d=0,e=0,f=0;f<a.length;f++){var g=a[f],h=g.f,k=g.a||new NY,l=PY[h];k.a=l.a;k.b=l.b;k.text=l.text;h=2*(RY[h]+4);e+h>=b&&(d+=c,e=c=0);k=2*g.a.a+4;k*=2;l=d+k/2;l-d+k/2>c&&(c=l-d+k/2);g.width=h;g.height=k;g.b=e;g.c=d;e+=h}a=d;0<e&&(a+=c);return new fo(b,a)} +function WY(a,b){var c=a.a;c.save();c.scale(2,2);c.fillStyle="rgba(255, 255, 255, 1)";c.textAlign="center";c.textBaseline="middle";for(var d=-1,e=0,f=0;f<b.length;f++){var g=b[f],h=g.b+g.width/2,k=g.c+g.height/2;g=g.a;if(g.a!=d||g.b!=e)d=g.a,e=g.b,c.font=qL(d,e,a.c);c.fillText(g.text,h/2,k/2)}c.restore()} +function XY(a,b,c){for(var d=0;d<a.length;d++){var e=a[d],f=bX[e.f]||null;if(!f||!f.data){var g=new pq(0,0,0,0),h=new pq(0,0,0,0);e=LY(b,c,new pq(e.b,e.c,e.width,e.height),g,h);f.data=e;f.b=g;f.a=h}}};function YY(a,b){JW.call(this,b);this.f=[];this.g={}}F(YY,JW);function ZY(a,b){B(a.g[b])||(a.g[b]=a.f.length,a.f.push(b))}function $Y(a,b){b=a.g[b];return-1!=a.b[b]?new eo(KW(a,b)+(MW(a,b)>>1),LW(a,b)+(NW(a,b)>>1)):null}r=YY.prototype;r.Ob=function(){return this.f.length};r.$b=function(a){return(bX[this.f[a]]||null).data};r.zb=function(a){return 8*(Math.ceil((bX[this.f[a]]||null).a.width/8)|1)};r.yb=function(a){return 12*(Math.ceil((bX[this.f[a]]||null).a.height/12)|1)};r.ac=function(a){return this.f[a]}; +r.Fa=function(a){0!=this.a||this.Na(a);if(this.Pb()){a=this.Ob();for(var b=0;b<a;b++){var c=bX[this.f[b]]||null;c.data&&OW(this,b,MW(this,b)/2+c.a.left,NW(this,b)/2+c.a.top,c.a.width,c.a.height,c.data)}this.j=this.c.A;this.a=2}};function aZ(a,b,c,d){LJ.call(this,a,b);this.c=!1;this.a=c;this.b=d;this.f=0}F(aZ,LJ);function bZ(a,b,c,d,e,f,g){JW.call(this,e);this.s=a;this.l=b;this.g=c;this.m=d;this.u=g;this.f=new YY(a,f);this.h=[];this.o=[]}F(bZ,JW);function cZ(a,b){this.a=a;this.b=b;this.c=0;this.kd=null}var dZ=new Uint8Array(2048),UY=null;r=bZ.prototype;r.Ob=function(){return this.h.length};r.ac=function(){};r.zb=function(a){return this.h[a].c};r.yb=function(){return 2}; +r.$b=function(a){var b=this.zb(a),c=this.yb(a),d=dZ;d.length<b*c*4&&(d=dZ=new Uint8Array(b*c*4));for(var e=0;e<b*c*4;e++)d[e]=0;c=this.h[a];if(tu(c.a)){a=d;c=c.a;e=uu(c);for(var f=0;f<e;++f){var g=wu(c)?xu(c,f)/8:0,h=a,k=b;var l=vu(c,f);var m=f,n=EL(this.g,l);l=(bX[n]||null).a;l=new pq(l.left/2+2,l.top/2+2,l.width/2-4,l.height/2-4);(n=$Y(this.f,n))&&eZ(m,n,l,h,k,2+g)}}else for(a=d,h=su(c.a),f=CK(this.m,c.b),k=this.g.getZoom(),c=hA(f,k),e=gA(f,k),f=iA(f,k)*c,h=fZ(h)?[h]:h.split(""),k=2,g=0;g<h.length;g++)if(l= +SY(c,e,h[g]),m=cX(l))if(l=$Y(this.f,l))eZ(g,l,m,a,b,k),k+=m.width,k+=f,k+=1;return d};r.Na=function(a){0!=this.f.a||this.f.Na(a);if(a=bZ.R.Na.call(this,a))for(var b=0;b<this.h.length;b++)if(-1!=this.b[b]){var c=this.h[b].kd;c.c=!0;c.a=KW(this,b);c.b=LW(this,b)}return a};r.Sb=function(){bZ.R.Sb.call(this);0!=this.f.a&&this.f.Sb()};var gZ=new pq(0,0,0,0); +bZ.prototype.Rc=function(){if(!UY){var a=Math.min(this.s.i+1,8193);this.l.height=64;this.l.width=a;UY=new MY(this.l,this.u)}a=this.g.a;if(Jy(a)&&py(Ky(a))){var b=[],c=Ky(a).a;for(a=0;a<c.length;a++){var d=c[a];if(null!=d.c||null!=d.b&&gu(Eu(d)))for(var e=Cu(d).a,f=0;f<e.length;++f){var g=e[f],h=AL(this.g,a,0,f);d=new cZ(g,h);this.h.push(d);this.o[h]=d;if(tu(g))for(d=d.a,g=uu(d),h=0;h<g;++h){var k=vu(d,h),l=EL(this.g,k);B(this.f.g[l])||(ZY(this.f,l),bX[l]||hZ(this,l,k))}else for(g=b,h=su(d.a),k=CK(this.m, +d.b),l=this.g.getZoom(),d=hA(k,l),k=gA(k,l),h=fZ(h)?[h]:h.split(""),l=0;l<h.length;l++){var m=TY(d,k,h[l]);B(this.f.g[m])||(ZY(this.f,m),g.push(m))}}}d=UY;a=[];for(c=0;c<b.length;++c)e=b[c],PY[e]&&((bX[e]||null).data||a.push(new OY(e)));a.length&&(b=VY(a,d.b.width),c=d.b,c.width<b.width&&(c.width=b.width),c.height<b.height&&(c.height=b.height),d.a.clearRect(0,0,b.width,b.height),WY(d,a),d=d.a.getImageData(0,0,b.width,b.height),XY(a,d.data,d.width));for(a=0;a<this.h.length;++a){b=d=this.h[a];if(tu(d.a)){f= +e=c=0;g=d.a;h=uu(g);k=Dy(this.g.a);for(l=0;l<h;++l){var n=ay(k,vu(g,l));m=Xx(n)/2;n=Yx(n)/2;m>c&&(c=m);n>e&&(e=n);n=wu(g)?xu(g,l)/8:0;m+=n;m>f&&(f=m)}e=new aZ(f+4,e,0,0);e.f=c;c=e}else{l=su(d.a);f=CK(this.m,d.b);g=this.g.getZoom();c=hA(f,g);e=gA(f,g);g=iA(f,g)*c;h=5;k=f=0;l=fZ(l)?[l]:l.split("");for(m=0;m<l.length;m++){n=SY(c,e,l[m]);var p=cX(n);n=p.width;p=2*Math.max(-p.top,p.height+p.top)+1;f=n>f?n:f;k=p>k?p:k;h+=n+g+1}c=new aZ(h,k,0,0);c.f=f}b.kd=c;d.c=2*Math.ceil(d.kd.width)+1}}}; +function hZ(a,b,c){var d=new dX;bX[b]=d;b=BL(a.g);b.Qb()&&b.Ib(2);b=b.Yb();a=ay(Dy(a.g.a),c);gZ.left=Vx(a);gZ.top=Wx(a);gZ.width=Xx(a);gZ.height=Yx(a);a=new pq(0,0,0,0);c=new pq(0,0,0,0);b=LY(b.data,b.width,gZ,a,c);d.data=b;d.b=a;d.a=c} +function eZ(a,b,c,d,e,f){var g=a%2,h=f+-c.left;a=b.x;b=b.y;a=a/8-.5;b=b/12-.5;var k=Math.floor(2*(f-2));h*=2;c=Math.ceil(2*(f+c.width+2));k++;h++;c++;k=Math.max(k,0);c=Math.min(c,e);f=2*g+4*k;e=4*e+2*g+4*k;h-=k+.5;g=Math.round(256*(h+128))>>8;for(var l=Math.round(256*(h+128))&254;k<c;++k)Math.abs(h)<=Math.abs(d[f+0]+d[f+1]/256-128)&&(d[f+0]=g,d[f+1]=l,d[e+0]=a,d[e+1]=b),f+=4,e+=4,h--,g--} +function fZ(a){for(var b=0;b<a.length;++b){var c=a.charCodeAt(b||0);(c=1424<=c&&1792>c)||(c=a.charCodeAt(b||0),c=!(0<=c&&1536>c||12288<=c&&65520>c));if(c)return!0}return!1}bZ.prototype.Tb=function(a){return(a=this.o[a])?a.kd:null};function iZ(a,b,c,d){JW.call(this,c);c=wy(a.a);this.g=a;this.m=b;this.l=nI(c);this.o=d;this.h=Math.ceil(2*this.l);this.f=[];this.s=[]}F(iZ,JW);function lZ(a,b){this.f=a;this.g=b;this.b=this.a=0;this.c=null}var mZ=new Uint8Array(7E3),nZ=null;r=iZ.prototype;r.Ob=function(){return this.f.length};r.ac=function(){};r.zb=function(a){return this.f[a].a};r.yb=function(a){return this.f[a].b}; +r.$b=function(a){a=this.f[a];if(tu(a.f)){var b=this.g.a,c=BL(this.g);c.Qb()&&c.Ib(2);c=c.Yb();var d=vu(a.f,0);b=ay(Dy(b),d);a=oZ(c.data,c.width,Vx(b),Wx(b),Xx(b),Yx(b),a.a,a.b,this.h)}else{b=su(a.f);c=this.g.getZoom();var e=CK(this.m,a.g);d=hA(e,c)*this.l;e=gA(e,c);c=pZ().getContext("2d");d=qL(d,e,this.o);c.font!=d&&(c.font=d);d=a.a;a=a.b;c.textBaseline="middle";c.textAlign="left";c.clearRect(0,0,d,a);c.fillText(b,this.h,a/2);b=c.getImageData(0,0,d,a);a=oZ(b.data,b.width,0,0,d,a,d,a,0)}return a}; +r.Tb=function(a){return(a=this.s[a])?a.c:null};function pZ(){nZ||(nZ=go("canvas"),nZ.width=512,nZ.height=128);return nZ} +r.Rc=function(){var a=this.g.a;if(Jy(a)&&py(Ky(a))){for(var b=Ky(a).a,c=this.g.getZoom(),d=0;d<b.length;d++){var e=b[d];if(null!=e.b&&!gu(Eu(e)))for(var f=null!=e.a?2:1,g=0;g<f;++g)for(var h=0==g?Cu(e):Du(e),k=0;k<(h.a?h.a.length:0);++k){var l=AL(this.g,d,g,k),m=CK(this.m,l),n=h.a[k];if(!fA(m,c)&&(tu(n)||null!=n.b)){var p=new lZ(n,l);this.f.push(p);this.s[l]=p}}}b=pZ().getContext("2d");e=this.h;f=this.l;for(d=0;d<this.f.length;d++)p=this.f[d],n=p.f,tu(n)?(m=vu(n,0),n=ay(Dy(a),m),m=Xx(n),n=Yx(n),p.c= +new aZ(m/f,n/f,0,0),p.a=2*e+m,p.b=2*e+n):(g=su(n),m=CK(this.m,p.g),n=hA(m,c)*f,0==n&&(n=2),m=gA(m,c),m=qL(n,m,this.o),b.font!=m&&(b.font=m),m=Math.ceil(b.measureText(g).width),p.c=new aZ(m/f,n/f,0,0),p.a=2*e+m,p.b=2*Math.ceil((2*e+1.3*n)/2)),p.a=4*Math.ceil(p.a/4)}}; +function oZ(a,b,c,d,e,f,g,h,k){var l=g-(k+e),m=h-(k+f),n=mZ;h*=g;n.byteLength<h&&(n=mZ=new Uint8Array(h));for(var p=h=0;p<k*g;p++)n[h++]=0;for(var q=0;q<f;q++){for(p=0;p<k;p++)n[h++]=0;var t=(d+q)*b*4+4*c+3;for(p=0;p<e;p++)n[h++]=a[t],t+=4;for(p=0;p<l;p++)n[h++]=0}for(p=0;p<m*g;p++)n[h++]=0;return n}r.Na=function(a){if(a=iZ.R.Na.call(this,a))for(var b=0;b<this.f.length;b++)if(-1!=this.b[b]){var c=KW(this,b),d=LW(this,b),e=this.f[b];c+=this.h;d+=e.b/2;e.c.c=!0;e.c.a=c;e.c.b=d}return a};function qZ(a,b,c,d){vM.call(this,c);this.c=a;this.v=b;this.m=d;this.s=go("canvas")}F(qZ,vM);qZ.prototype.j=function(a){var b=a.a.a,c=a.a.f,d=a.a.o;d||(d=new bZ(this.c.getContext(),this.s,a.data,c,this.c.f,this.c.c,this.m),d.Rc(),a.a.o=d,a.a.V=d);0!=d.a||d.Na(b);d=a.a.H;d||(d=new iZ(a.data,c,this.c.g,this.m),d.Rc(),a.a.H=d,a.a.Y=d);0!=d.a||d.Na(b)}; +qZ.prototype.g=function(a){for(var b=a.a.c,c=a.a.v,d=0;d<c.length;++d)for(var e=c[d].a,f=0;f<e.length;f++){var g=e[f].label;rZ(b,e[f].a,g.f,lK(g))}a=a.a;if(!a.u){b=a.m;c=a.la;d={};e=[];for(f=0;f<a.v.length;++f)if(g=a.v[f].c,4==g||5==g)for(var h=a.v[f].a,k=0;k<h.length;k++){var l=h[k],m=a.f.a[l.a],n="";if(4==g){var p=l;n=p.text}else p=l;var q=GY(m,n);!d[q]&&(d[q]=!0,q=fA(CK(a.f,l.a),b))&&(l=q.b||c,q=q.a,""!=q&&(q+=":"+l+":"+n),e.push(new HY(m,n,p.g.width,p.g.height,l,q)))}e.length&&(a.u=new IY(this.c, +this.v,e,b))}};function sZ(a,b){this.a=a;this.b=b}sZ.prototype.$=function(){this.a.lg(this.b);this.a=null};sZ.prototype.O=function(){return null==this.a};function tZ(a,b,c,d,e,f){qZ.call(this,a,b,c,d);this.h=e;this.o=f;this.a=WF();this.f=new Float64Array(4);this.l=[];this.i=!1}F(tZ,qZ);function uZ(a,b){a.i=b}tZ.prototype.b=function(a){tZ.R.b.call(this,a);vZ(this,a)}; +function vZ(a,b){if(0==b.a.ia&&!a.i)if(b.data.g){var c=b.a.j;if(0==c.length)b.a.ia=2;else{b.a.ia=1;var d=b.data,e=[],f=[],g=0,h=0;a.f.length<c.length&&(a.f=new Float64Array(c.length));for(var k=0;k<c.length;k++){var l=c[k],m=0,n=0;l.b?(m=l.b.a,n=l.b.b):l.a&&(m=gL(l.a,l.a.f),n=hL(l.a,l.a.f));m=m/256+tK(d);n=n/256+uK(d);zG(m,n,d.getZoom(),a.a);uG(a.a[0],a.a[1],0,a.a);m=a.h.ud();isFinite(m)?(a.f[h]=m,a.l[h]=k,h++):(e[2*g]=a.a[0],e[2*g+1]=a.a[1],f[g]=k,g++);l.s=!0}wZ(a,b,a.l,new Float64Array(a.f.buffer, +0,h));0<e.length?(c=new Float64Array(e),c=a.h.jg(c,function(c){b.a.a&&oO(b.a);c=wZ(a,b,f,c);a.o(b);c&&(b.a.fa.$(),b.a.fa=null,b.a.ia=2)}),b.a.fa=new sZ(a.h,c)):b.a.ia=2}}else b.a.ia=2}function wZ(a,b,c,d){var e=b.a.j;b=b.data;var f=a.a,g=tK(b)+.5,h=uK(b)+.5;zG(g,h,b.getZoom(),f);uG(f[0],f[1],f[2],f);a=wG(a.a[1]);b=tN/(1<<b.getZoom())/256;a/=b;b=!0;for(f=0;f<d.length;f++)g=d[f],h=e[c[f]],isFinite(g)?h.b?(h.b.altitude=g*a,h.s=!1):h.a&&(h.a.altitude=g*a,h.s=!1):b=!1;return b};function xZ(a,b,c){JW.call(this,a.a);this.g=c;this.m=a.getContext().i;this.l=PQ(b.b);this.f=0;a=new Uint8Array(this.zb(0)*this.yb(0)*4);for(b=0;b<this.l;++b)vX(GK(this.g,b),a,4*b,this.m);this.h=a}F(xZ,JW);var yZ=0;xZ.prototype.Ob=function(){return 1};xZ.prototype.$b=function(){return this.h};xZ.prototype.zb=function(){return Math.max(Math.ceil(this.l/this.yb(0)),1)};xZ.prototype.yb=function(){return 16}; +function zZ(a){var b=a.g.i;b.length&&(yZ++,a.f=yZ);b=b.concat(a.g.j);for(var c=0;c<b.length;++c){var d=b[c],e=a;vX(GK(a.g,d),e.h,4*d,e.m);2==e.a&&(e.a=1)}}function ZV(a,b){var c=a.zb(0);return new eo(KW(a,0)+b%c,LW(a,0)+Math.floor(b/c))}function rZ(a,b,c,d){var e=0;0<c&&(e|=31*c);d&&(e|=32);a.h[4*b]=e;2==a.a&&(a.a=1)};function AZ(a){this.b=a;this.Xb=null;this.a=0};function BZ(a,b,c,d,e,f,g,h){this.f=h.o;this.o=a;this.g=b;this.A=c;this.B=d;this.b=e;this.l=f;this.c=g;this.v=a.getContext();this.u=a.getContext().Zc();this.s=h.i;this.a=[this.Qf,this.Fe,this.Ee,this.hf,this.Ke,this.Gd,this.Jd,this.Fd,this.Id,this.Hd,this.Kd];this.h=[this.a.indexOf(this.Ke),this.a.indexOf(this.Gd),this.a.indexOf(this.Jd),this.a.indexOf(this.Fd),this.a.indexOf(this.Id),this.a.indexOf(this.Hd),this.a.indexOf(this.Kd)];this.j=this.a.indexOf(this.Fe);this.i=this.a.indexOf(this.Ee);this.m= +this.a.indexOf(this.hf)}F(BZ,SM);var CZ=$M(),DZ=aN(),EZ=0;r=BZ.prototype; +r.Od=function(a){var b=a.a;b.i.length||(b.i=Array(this.a.length));b.a&&2==b.a.b&&oO(b);if(!b.a){b.a=new hO(this.v);for(var c=0;c<this.h.length;++c)b.i[this.h[c]]=null;b.ra=0;b.pa=0}if(1==b.a.b)return DZ;for(c=0;c<this.a.length;++c){var d=b.i[c];if(!d&&(d=this.a[c],d!=this.Fd&&d!=this.Id||"success"==b.i[this.j].getState())&&(d!=this.Gd&&d!=this.Jd||"success"==b.i[this.i].getState())&&(d!=this.Hd||"success"==b.i[this.m].getState())&&(d!=this.Kd||"success"==b.i[this.j].getState()&&"success"==b.i[this.i].getState()&& +"success"==b.i[this.m].getState()))return b.i[c]=d.call(this,a),CZ}a=[];for(c=0;c<this.a.length;++c)(d=b.i[c])&&"pending"==d.getState()&&a.push(d);return a.length?dN.apply(null,a):DZ};r.Ub=function(a){for(var b=0;b<this.a.length;++b){var c=a.a.i[b];if(!c||"success"!=c.getState())return!1}return!0}; +r.Qf=function(a){var b=a.a;if(!b.f){var c=a.N.ba().c,d=PB(this.g,c),e=a.data.i;e.length&&TA(d,e);SA(d,a.data.m);c=mN(a.data,c,d);b.f=c;b.jb=this.g.c;a.data.s=c;nN(a.data)}(e=a.b)&&!UM(e.data)&&(c=a.N.ba().c,d=PB(this.g,c),e=e.data.i,e.length&&TA(d,e));b.va||FZ(this,a);return CZ}; +function FZ(a,b){for(var c=b.a.f,d={},e=[],f=0;f<c.a.length;++f){var g=c.a[f];d[g]||(d[g]=!0,e.push(g))}if((d=b.b)&&!UM(d.data)){c=d.a.va;c||(FZ(a,d),c=d.a.va);a={};for(d=0;d<e.length;++d)a[e[d]]=!0;for(d=0;d<c.length;++d)a[c[d]]||e.push(c[d])}b.a.va=e}r.Fe=function(a){return WM(this,a)}; +r.Ee=function(a){var b=a.data;a=a.a.f;var c=b.a;if(Ey(c)){wy(c);b=b.b;var d={};c=Fy(c);c=c.a?c.a.length:0;for(var e=0;e<c;++e){var f=b.a[1][e].ka();f=CK(a,f);if(0<f.o)for(var g=f.c,h=0;23>h;h++)for(var k=0;k<g;k++){var l=vA(f.v,k,h);l&&l.a&&(l=Xs(l,1),d[l]=!0);(l=vA(f.A,k,h))&&l.a&&(l=Xs(l,1),d[l]=!0);(l=vA(f.u,k,h))&&l.a&&(l=Xs(l,1),d[l]=!0)}}a=Object.keys(d)}else a=[];return VM(this,a)}; +r.hf=function(a){var b=a.data.a,c=a.data.j,d=a.a;d.l=0;var e=new FM;if(null!=b.a&&ry(Ly(b))){d.C=[];for(var f=Ly(b).Aa,g=0;g<f.length;g++){var h=eJ(c,b,g);GZ(this,a,h,e);d.C.push(new AZ(h))}}return 0<d.l?e:CZ};r.Ke=function(a){var b=a.a,c=b.a,d=a.a,e=d.c;e||(e=new xZ(this.o,a.data,d.f),a.a.c=e);b=b.c;(0==b.a?0:!b.Pb())||b.Fa(c);(a=a.b&&a.b.a.c)&&(0==a.a||a.Pb())&&a.Fa(c);return CZ};r.Fd=function(a){this.B.b(a);return CZ}; +r.Gd=function(a){var b=a.a,c=a.data;a=c.b;var d=c.a;c=b.f;var e=[],f={};if(Ey(d)){d=Fy(d).a;for(var g=0;g<d.length;g++){var h=a.a[1][g].ka(),k=CK(c,h);h=c.a[h];if(0<k.o&&!f[h]){f[h]=!0;for(var l=k.c,m=0;23>m;m++)for(var n=0;n<l;n++){var p=vA(k.v,n,m);if(p&&p.a){var q=$s(p,1);e.push(new PW(h,n,m,"stamp",q.width,q.height,p.a))}(p=vA(k.A,n,m))&&p.a&&(q=$s(p,1),e.push(new PW(h,n,m,"startcap",q.width,q.height,p.a)));(p=vA(k.u,n,m))&&p.a&&(q=$s(p,1),e.push(new PW(h,n,m,"endcap",q.width,q.height,p.a)))}}}}e.length&& +(b.A=new QW(this.o.b,this.A,e));return CZ};r.Jd=function(a){var b=a.a;2==this.b[b.ra].b(a,this.s)&&b.ra++;return b.ra==this.b.length?(b.ra=0,b.B=++EZ,CZ):null};r.Id=function(a){var b=a.a;if(!b.v.length)return CZ;var c=b.v[b.pa];2==this.l[c.c].b(a,c)&&b.pa++;return b.pa==b.v.length?(b.pa=0,CZ):null};function GZ(a,b,c,d){c&&(c.Qb()&&(a.u&&c.sd(1)?c.Ib(1):c.Ib(3)),c.Db()||c.bc()||(ec(c.Ab(),"load",function(){b.a.l--;0==b.a.l&&HM(d,!0)}),b.a.l++))} +r.Hd=function(a){for(var b=0;b<this.c.length;b++)this.c[b].b(a,this.s);b=a.data;var c=0;null!=b.a.a&&(b=Ly(b.a),c+=b.Aa?b.Aa.length:0);0<c&&(EZ++,a.a.B=EZ);return CZ};r.Kd=function(a){var b=a.a;b.ib=-1;b=b.a;kO(b,this,D(this.Cf,this,a));lO(b);return CZ}; +r.Cf=function(a){a=a.a;a.G=null;a.ja=null;a.I=null;a.ga=null;a.L=null;a.T=[];a.ha=[];a.U=[];a.W=[];a.P=[];a.S=[];a.ya=null;if(a.C)for(var b=0;b<a.C.length;b++)a.C[b].Xb=null;a.c&&0!=a.c.a&&a.c.Sb();a.u&&0!=a.u.a&&a.u.Sb();a.A&&0!=a.A.a&&a.A.Sb();a.o&&0!=a.o.a&&a.o.Sb();a.H&&0!=a.H.a&&a.H.Sb()};function HZ(a,b){if(UM(b.data))return!0;var c=b.a;return c.a&&1==c.a.b?a.Ub(b):!1};function IZ(a,b,c,d,e){$N.call(this,a,b,c,d);this.s=e}F(IZ,$N);IZ.prototype.i=function(a,b,c,d){IZ.R.i.call(this,a,b,c,d);(b=a.b)&&this.s&&a.i&&(a=71.5*Math.sin(ao(SN(this.b))),b.screenY-=a)};IZ.prototype.l=function(a,b){for(var c=0;c<b.c.length;c++)rZ(a.a.c,b.c[c].a,b.f,lK(b))};function JZ(a){return function(b){var c=a.a;b=b.N;for(var d=0;d<c.g.length;d++)if(c.g[d].N.aa()==b.aa()){c.h=!0;break}}};function KZ(a){this.context=a}KZ.prototype.getContext=function(){return this.context};function LZ(a){this.context=a;this.a=this.b=0}F(LZ,KZ);function MZ(a,b,c){a.b=b;a.a=c;a.context.bindFramebuffer(36160,null);a.context.bindRenderbuffer(36161,null);a.context.viewport(0,0,b,c)} +LZ.prototype.bindTexture=function(a){var b=this.context.a.f||null,c=Fp(this.context.b);MZ(this,this.b,this.a);this.context.activeTexture(33984+a);a=this.context.h.createTexture(9729);this.context.bindTexture(3553,this.context.h.a.get(a)||null);this.context.copyTexImage2D(3553,0,6408,0,0,this.b,this.a,0);this.context.a.lc(b);c&&this.context.b.nc(c[0],c[1],c[2],c[3]);return!0};function NZ(a,b,c,d,e,f,g,h,k,l){this.b=e;var m=e.a,n=m.getContext().j;this.j=new yY;var p=new IZ(b,D(this.Mf,this),0,!0,l.Nb);xP.call(this,a,b,d,this,m.h,l,p,n,c);this.ja=new zY(D(this.Wb,this));this.fa=l.s?new tZ(m,f,l.Nb,"arial,sans-serif",l.s,JZ(p)):new qZ(m,f,l.Nb,"arial,sans-serif");this.U=new no(this);Jb(this,this.U);this.U.cb(e,"webglcontextrestored",this.Rf,!1);this.M=new BY(b.a,b,g);a=b.D;this.g=new oq(a.top,a.right,a.bottom,a.left);this.B=g;this.H=l.s;this.D=f;this.Z=h;this.J=17664;this.ra= +l.u;this.W=l.T;this.T=l.G;this.pa=l.ga;this.Y=m;this.S=k;this.ia=l.fa;this.K=this.m=b.g;this.j.O=this.W;this.l=new BZ(m,h,f,this.fa,nY(this.b),oY(this.b),pY(this.b),l);this.ga=new EP(this.l,this.Y.h.b);QP(this.a,D(this.Wb,this));b=D(this.Wb,this);this.B.m=b;this.T||(this.D.l=!1);this.G=1<l.L;this.h=0;this.A=new EY;this.s=new EY}F(NZ,xP);NZ.prototype.X=function(){var a=this.b;a.v--;if(0==a.v){for(var b=0;b<mY.length;b++)if(mY[b].td===a){mY.splice(b,1);break}a.a.$();a.D.$()}}; +var OZ=[[0,0],[.2,.4],[-.2,-.4],[.4,-.2],[-.4,.2]];r=NZ.prototype;r.getContext=function(){return this.Y.getContext()};r.Rf=function(){var a=this.l,b=oY(this.b),c=pY(this.b);a.b=nY(this.b);a.l=b;a.c=c;this.c=new QO;a=this.B;b=this.getContext();a.i=b;a.f=null;a.c=!1;a.g=!0;this.G&&(this.A=new EY,this.s=new EY,this.h=0);a=this.f.a;for(b=0;b<a.length;++b)PZ(this,a[b]);this.Wb()};function PZ(a,b){b.b&&!a.fb(b.b)&&PZ(a,b.b);b.a.a&&oO(b.a);TM(a.l,b)} +r.Vd=function(){return QZ(this)||ZB(this.D)||AP(this)||this.c.a?!1:!0};function QZ(a){return AP(a)?!0:a.i<a.I||!a.b.h.b.b}function RZ(a){var b=a.f.a;return a.G&&a.h<OZ.length&&0<b.length&&a.c.c}r.Qd=function(){var a=this.getContext();return!a||a.isContextLost()?!1:NZ.R.Qd.call(this)}; +r.vc=function(){NZ.R.vc.call(this);var a=PB(this.Z,this.a.ba().c),b=this.D;b.a!=a&&(b.b=b.a,b.b&&WA(b.b),b.a=a,VA(b.a,b.s,b),b.c++,b.l&&b.b&&(b.j=E()+167,b.g||(b.g=!0,b.m.Pd(b))));a=this.Z.c;this.j.md=OA(a,23);this.j.G=OA(a,24);a=this.f.a;for(b=0;b<a.length;++b){var c=a[b];bQ(this.V,c);zZ(c.a.c);(c=c.b)&&c.a.c&&(bQ(this.V,c),zZ(c.a.c))}a.length&&this.H&&uZ(this.fa,this.a.a.f>SZ);c=this.getContext();a=this.j;var d=this.a.i;b=this.a.c;a.C=this.pa?AY(this.ja,this.a.a.G):0;a.f=c.c.drawingBufferWidth|| +c.j.a.width;a.c=c.c.drawingBufferHeight||c.j.a.height;a.zoom=this.a.getZoom();a.v=!1;0>d.indexOf(0)&&(a.v=!0);this.W||this.ra&&this.T&&this.a.m||(a.v=!0);a.M=!this.a.h;a.L=!this.a.m;a.D=!this.ia||0>d.indexOf(0);a.K=!this.a.o;a.P=this.a.u;a.S=this.a.v;a.s=gI(d,this.a.c);a.clearColor=hI(d,b);c=this.a.D;a.o.top=c.top;a.o.right=c.right;a.o.bottom=c.bottom;a.o.left=c.left;a.l=this.a.f;a.u=-1<b.indexOf(2);b=this.a.a;a.j=b.c;a.i=b.a;a.T=this.H?this.H.fg():0;a.A=this.m?12>a.zoom:!1;b=this.a.getZoom();a=this.B; +22<b&&(b=22);b!=a.h&&(a.h=b,a.g=!0,a.c=!1)}; +r.cd=function(a){NZ.R.cd.call(this,a);var b=this.b,c=this.B,d=this.getContext(),e=this.a.a,f=this.f.b,g=this.f.a,h=this.j;this.m=this.a.g;if(d&&!d.isContextLost()){var k=this.a.D,l=!1;!this.c.a&&this.c.c&&TZ(this)&&!ZB(this.D)&&DY(this.M,g)&&this.g.top==k.top&&this.g.right==k.right&&this.g.bottom==k.bottom&&this.g.left==k.left&&this.K==this.m&&(l=!0);if(l&&this.G){if(this.h<OZ.length){l=OZ[this.h][0];var m=OZ[this.h][1];h.g=!0;h.h=!1;h.a.x=l;h.a.y=m;h.Va.x=2*l/h.f;h.Va.y=2*m/h.c;FY(this.A,d,h.f,h.c, +!0);this.A.bind(d);UV(d,h,17664);rY(b,f,g,e,c,h);FY(this.s,d,h.f,h.c,!1);this.s.bind(d);l=1/(this.h+1);TV(d,h,3,1,1,2,1);TX(b.C,this.A.b,l);this.h++}h.g=!1;h.h=!0;h.a.x=0;h.a.y=0;h.Va.x=0;h.Va.y=0;MZ(this.S,h.f,h.c);TV(d,h,2,1,1,2,1);TX(b.C,this.s.b,1);UV(d,h,256);rY(b,f,g,e,c,h)}else h.g=!this.c.a,h.h=!this.c.a,h.a.x=0,h.a.y=0,h.Va.x=0,h.Va.y=0,MZ(this.S,h.f,h.c),UV(d,h,this.J),rY(b,f,g,e,c,h),this.h=0,JO(this.v),MO(this.v,f);a&&KO(this.v,a);this.M.capture(g);this.g.top=k.top;this.g.right=k.right; +this.g.bottom=k.bottom;this.g.left=k.left;this.K=this.m;this.ya=b.f;this.c.a||(QZ(this)||RZ(this))&&this.Wb();TV(d,h,3,3,1,1,2)}};r.Td=function(){bO(this.C,this.f.a,this.f.f,!this.a.h,this.i,this.j.A)};function TZ(a){for(var b=a.f.a,c=0;c<b.length;++c){var d=b[c];if(!HZ(a.l,d)||d.b&&(d=d.b.a,!d.a||1!=d.a.b))return!1}return!0}r.Mf=function(a){this.I=Math.max(this.I,a);(QZ(this)||RZ(this))&&this.Wb()};var SZ=2E5/6371010;r=NZ.prototype;r.rd=function(){return TZ(this)&&NZ.R.rd.call(this)}; +r.fb=function(a){return a.b&&!this.fb(a.b)?!1:HZ(this.l,a)};r.ic=function(a,b,c){var d=null;a.b&&!this.fb(a.b)&&(d=this.ic(a.b,b));var e;if((e=c&&TM(this.l,a)?$M():GP(this.ga,a,b))&&d&&"pending"==e.getState()&&"pending"==d.getState()){var f=d;e.wait(function(){JM(e)&&f.cancel()})}return e};r.wd=function(){return this.ga.b};r.Je=function(){return!0};function UZ(){}F(UZ,uQ);UZ.prototype.a=function(a,b,c,d,e,f,g,h,k,l){c=f.oc;a:{var m=b.a;for(var n=Yn(a.la,1,2),p=a.Nb,q=0;q<mY.length;++q){var t=mY[q];if(t.context==m&&t.Nb==p&&t.gc==k&&t.la==n){t.td.v++;m=t.td;break a}}q=new RB(m,k,n);q=new kY(q,p);mY.push({context:m,gc:k,la:n,Nb:p,td:q});m=q}k=new YB(c,k.b);n=new sX(b.a,k);uH(e,a.i);b=new NZ(d,e,h,f,m,k,n,c,l?l:new LZ(b.a),a);b.J=17664;h=this.Xc(a,f,b,d);return new xY(d,e,f,b,h,g,a.b)};function VZ(){}VZ.prototype.a=function(){return new UZ};NG(3,new VZ);function WZ(){Pp.call(this);this.c=[];this.b=[];this.a=[];this.f=[]}F(WZ,Pp);var XZ=[],YZ=!0;WZ.prototype.h=function(a,b){if(this.c[a])if(this.b[a])b(a,this.c[a]);else return this.a[a].push(b),this.a[a].length-1;return-1};WZ.prototype.g=function(a){this.b[a]=!0;var b=this.a[a];this.a[a]=[];if(b)for(var c=0;c<b.length;++c){var d=b[c];d&&d(a,this.c[a])}}; +function oH(a,b){2==b&&!a.b[b]&&a.b[3]&&a.g(b);if(a.c[b]&&!a.b[b]&&!a.f[b]){a.f[b]=!0;if(YZ){var c=XZ[b];void 0===c&&(c=.1>Math.random()?0:Math.floor(Math.random()*Math.random()*2E3),XZ[b]=c)}else c=0;0==c?a.g(b):ho(D(a.g,a,b),c)}}WZ.prototype.X=function(){for(var a=0;a<this.a.length;a++)if(this.a[a])for(var b=0;b<this.a[a].length;b++);this.a=[];this.f=[];this.b=[];this.c=[];WZ.R.X.call(this)};for(OG=new WZ;PG.length;){var ZZ=PG.shift();NG(ZZ.id,ZZ.If)};function $Z(a){this.a=a?new LH:new CH;YZ=!1};function a_(a){this.b=a}a_.prototype.a=function(a,b,c,d,e,f){for(var g=[],h=0;h<this.b.length;h++)g=g.concat(this.b[h].a(a,b,c,d,e,f));return g};function b_(a){this.b=a} +b_.prototype.a=function(a,b,c,d,e,f){for(var g=[],h=0;h<d.length;h++)for(var k=tQ(e,a,b,f).a,l=0;l<k.length;++l){var m=[],n=k[l].a,p=m,q=bC(n);if(q){var t=q.oa,v=q.Yc,u=q.xc;q=q.bd;var w=n.length;if(w){var y=n[0].getZoom();if(0!=y&&0!=this.b){var A=1<<y;t-=this.b;0>t&&(t=A+t);v+=this.b;v-t>=A&&(v=t+A-1);u-=this.b;0>u&&(u=0);q+=this.b;for(q>=A&&(q=A-1);t<=v;++t){var z=t;z>=A&&(z-=A);for(var C=u;C<=q;++C){for(var I=!0,S=0;S<w;++S)if(n[S].b==z&&n[S].a==C){I=!1;break}I&&p.push(new kC(z,C,y))}}}}}0<m.length&& +g.push(new qQ(m,c,d[h],0,3,!1,!0))}return g};function c_(a){this.b=a}function d_(){for(var a=Array(22),b=0;b<a.length;b++)a[b]=Math.max(0,b-2);return new c_(a)} +c_.prototype.a=function(a,b,c,d,e,f){var g=[];a=tQ(e,a,b,f).a;for(b=0;b<a.length;++b){e=[];var h=a[b].a;f=e;var k=bC(h);if(k){var l=h[0].getZoom();h=this.b[l];if(!(0>h||h==l)){var m=l-h,n=k.oa>>m;l=k.Yc>>m;var p=k.xc>>m;k=k.bd>>m;m=1<<h;--n;0>n&&(n=Math.max(0,m+n));l+=1;l-n>=m&&(l=n+m-1);--p;0>p&&(p=0);k+=1;for(k>=m&&(k=m-1);n<=l;++n){var q=n;q>=m&&(q-=m);for(var t=p;t<=k;++t)f.push(new kC(q,t,h))}}}if(0<e.length)for(f=0;f<d.length;f++)g.push(new qQ(e,c,d[f],0,3,!1,!0))}return g};function e_(a,b,c,d){this.a=a;this.h=b;this.l=c;this.c=this.f=!1;this.g=null;0<d&&(a=[new b_(d)],a.push(d_()),this.g=new a_(a));this.b=null;QP(this.a,D(this.j,this))}e_.prototype.j=function(){this.f||this.c||(this.f=!0,this.l.Te(this))};function Mr(a){if(!a.c){var b=tU(a.h,a.a.a,a.a.f,a.a.ba(),a.a.c,a.a.g);a.b&&(a.b.cancel(),a.b=null);bN(b,a.i,a)}a.f=!1} +e_.prototype.i=function(){if(this.g){var a=this.h,b=this.g.a(this.a.a,this.a.f,this.a.ba(),this.a.c,a.g,this.a.g);this.b=uU(a,b,!1)}a=this.h;1!=a.b&&(a.b=!0,a.c&&vU(a,a.c))};function f_(a){this.a=new pB;xB(this.a,!0);for(var b=0;b<arguments.length;b++){var c=arguments[b];c&&(c=c.replace(/^\?/,""),this.a.zf(new pB(c)))}}f_.prototype.has=function(a){return DB(this.a,a)};f_.prototype.get=function(a,b){return this.a.get(a,b)};function g_(a,b){a=a.a.get(b);return""==a||"true"==a||"yes"==a}f_.prototype.numeric=function(a,b){a=this.a.get(a);return"undefined"==typeof a?b||0:parseFloat(a)};function h_(){this.b=new f_(x.location.search,x.testConfig);this.G=this.b.get("testmode","normal");this.g=[];this.I=0;this.C=this.u=!1;this.D=void 0;this.l=0;this.c=null;this.H=new bP;this.s=[];this.o=[];this.j=[];this.m=!1;this.v=this.i=this.B=0;this.h=new $Z(g_(this.b,"nobudget"));var a=this.b.get("viewport"),b=new tC,c=KD[a];if(!B(c))throw Error("Unknown viewport: "+a);var d;if(d=c)uC||wC(),d=!qs.a(c,b.data,uC);if(d)throw Error("Failed to parse viewport:"+a);this.a=new pC(b.data[0]);a=this.b;c= +this.a;d=new OF;d.u=["/vt"];d.v=["/kh?v=0"];d.f="en";d.c="";d.o=g_(a,"nodraw");d.i=g_(a,"canvas")?2:1;var e=VE(ze(c,13,"Default"));d.m=lC(e);d.s=nC(e);d.b=g_(a,"useDiffTiles");d.b&&(e=VE("Default"),d.h=nC(e),d.a=lC(e));a.has("overridePixelRatio")&&(d.g=a.numeric("overridePixelRatio"));d.l=X(c,0,512);d.j=X(c,1,512);this.J=d;a=this.b;c=new LF;c.I=!g_(a,"noLabels");c.u=!g_(a,"noGrids");c.J=1;c.L=0;"false"==a.get("requestDxtTextures","")?c.h=!1:c.h=!0;c.g=g_(a,"rasterizeNonInteractiveFeatures");c.f=100; +c.S=!1;this.A=c;this.A.o=D(this.h.a.j,this.h.a);this.f=this.pb=null;b=new xC(b);for(a=b.a.shift();a;)i_(this,a),a=b.a.shift();this.b.has("title")&&(document.title=this.b.get("title"))}var j_={Uf:"normal",Vf:"static",Wf:"stress"};function i_(a,b){var c=a.H;a.g.push(function(a){vH(a,c);c.lat=X(b,2,47.651318);c.lng=X(b,3,-122.35305);c.zoom=b.getZoom();c.ta=X(b,7);c.rotation=X(b,6);wH(a,c)});xe(b,31)&&a.jf(X(b,31))}r=h_.prototype; +r.jf=function(a){this.g.push(D(function(){this.c=setTimeout(D(function(){this.c=null;this.Ne()},this),a)},this))};r.Sf=function(){var a=D(this.Of,this);"undefined"!=window&&(a=mF(new jF("/error",void 0,void 0),a)||a);if(g_(this.b,"workers")){var b=null;b=g_(this.b,"debugjs")?new Worker("worker-bundle.js"):new Worker("worker.js");var c=this,d=function(e){"dataset_loaded"==e.data&&(b.removeEventListener("message",d),c.A.b=new CF([b]),a())};b.addEventListener("message",d)}else a()}; +r.Of=function(){var a=go("div");a.id="map_div";a.style.display="inline-block";document.body.appendChild(a);a=this.pb=new lH(this.J,this.h,a);var b=D(this.Af,this);var c=a.b;var d=a.h,e=this.A;B(e)||(e=new LF,e.m=!0);if(1==d||2==d){var f=2==d;f&&null==e.g&&(e.g=!0);d=c.b;e.g&&(d=!1);e.c=f?2:1;f=c.u||["//www.google.com/maps/vt"];var g=c.v||["//khms0.google.com/kh?v=0","//khms1.google.com/kh?v=0","//khms2.google.com/kh?v=0","//khms3.google.com/kh?v=0"];e.j=f;e.v=f;e.K=f;e.O=PF(f,"/stream");e.U=g;e.ia= +PF(f,"?lyrs=t");e.B=d;e.la=c.g;e.a=c.A;e.M=c.A;e.V=c.C}c=e;if(c.m){a.f=new VG;c.H=a.f;c.Y=a.f;e=new On;e.data[0]=0;e.data[1]="m";e.data[2]=1E6*c.f;d=a.f;f=c.f;1E6<=f&&(f=(f-f%1E6)/1E6);f=1E6*f+999999;g=Ds(e);var h=d.a[g];h||(h=new XG(xe(e,2)?X(e,2):null,new UG(d.f,d.c,f)),d.a[g]=h,d.b[e.wa()]=g)}null==c.h&&a.j.a&&a.j.a.Zc&&a.j.a.Zc()&&(c.h=!0);nH(a,c,D(a.Bf,a,b))}; +r.Af=function(){var a=mH(this.pb),b=a.b;this.f=new e_(b,a.i,this.h.a,g_(this.b,"noprefetch")?0:1);var c=this.pb.g;c.a=null;uo(c);this.f&&(this.f.c=!0);c=vH(b,this.H);c.lat=X(this.a,2,47.651318);c.lng=X(this.a,3,-122.35305);c.zoom=this.a.getZoom();c.a=X(this.a,5);c.rotation=X(this.a,6);c.ta=X(this.a,7);c.b=X(this.a,10,13.1);wH(b,c);c=X(this.a,8,-212);var d=X(this.a,9,40);if(b.u!=c||b.v!=d)b.u=c,b.v=d,tH(b);c=(0==Fe(this.a,11)?void 0:Ce(this.a,11))||[0];Xa(b.c,c)||(b.c=c.slice(),tH(b));0<Fe(this.a, +12)&&(c=Ce(this.a,12),Xa(b.i,c)||(b.i=c.slice(),tH(b)));a=a.g();"stress"!=this.G&&(dc(a,"FrameComplete",this.lf,!1,this),dc(a,"FrameStart",this.nf,!1,this));dc(a,"FrameComplete",this.Ne,!1,this);a=g_(this.b,"wait")?D(this.xf,this):D(this.Rd,this);JD(a)};r.xf=function(){window?window.startTest=D(this.Rd,this):this.Rd()}; +r.Rd=function(){this.u&&(this.C?(window.wtf.trace.prepare({"wtf.trace.mode":"snapshotting"}),window.wtf.trace.start()):window.wtf.trace.reset(),window.wtf.trace.mark("analysisStart"));var a=this.pb,b=a.g;b.a=a.a;uo(b);this.f&&(this.f.c=!1);this.I=E();setTimeout(D(this.yc,this),0)};r.Ne=function(){this.m&&(this.m=!1,this.yc())}; +r.yc=function(){var a=mH(this.pb);if(null==this.c||0!=a.a.f.a.length&&a.a.Vd())if(0<this.g.length){var b=this.g.shift();this.l=0;this.c&&(clearTimeout(this.c),this.c=null);b(a.b);this.l?setTimeout(D(this.yc,this),this.l):a.a.Vd()?this.yc():this.m=!0}else ur(D(this.Nf,this));else setTimeout(D(this.yc,this),0)};r.vf=function(a,b){this.C=a;this.u=!0;this.D=b}; +r.Nf=function(){var a=E()-this.I-0;this.u&&window.wtf.trace.snapshot(this.D);var b=[];b.push("total="+a);b.push("missed_frames="+60*this.i/1E3);"stress"!=this.G&&(a=CP(mH(this.pb).f().m()),b.push("average_prep_time="+a.toFixed(1)),b.push("num_frames="+this.s.length),b.push("incomplete_frames="+this.j.length),b.push("total_renderables="+this.v),a=bo.apply(null,this.j),b.push("missing_renderables="+a),a=co.apply(null,this.o)/1048576,b.push("average_gpu_memory_mb="+a),a={},a.render=k_(this.s,33),a.gpu_memory= +k_(this.o,0),a.gpu_memory.fd=void 0,gb(a,function(a,d){b.push(d+"="+[a.min,a.pc,a.dc[0],a.dc[1],a.dc[2],a.max].join());"number"==typeof a.fd&&b.push("slow"+d+"="+a.fd)}));x.environment&&(a=x.environment.Variables)&&a.cl&&b.push("cl="+a.cl);a="/metrics?"+b.join("&");x.testMetrics=b.join("&");qD(a,D(function(){x.testDone=!0},this))};r.lf=function(a){this.s.push(a.h-a.startTime);this.v+=a.g;this.o.push(a.f);0<a.c&&this.j.push(a.c)}; +r.nf=function(a){a=a.startTime;this.B&&(this.i+=a-this.B-1E3/60);this.B=a};function k_(a,b){var c={};c.min=a[0];c.max=c.min;c.pc=c.min;for(var d=c.fd=0;d<a.length;++d){var e=a[d];c.pc+=e;e<c.min&&(c.min=e);e>c.max&&(c.max=e);e>b&&c.fd++}c.pc/=a.length;a.sort(Za);c.dc=[];c.dc[0]=a[Math.floor(.5*a.length)];c.dc[1]=a[Math.floor(.9*a.length)];c.dc[2]=a[Math.floor(.995*a.length)];return c}window.getMetrics=function(){return x.testMetrics||!1};Ia("Tracker",h_);h_.TEST_MODE=j_;j_.NORMAL="normal"; +j_.STATIC="static";j_.STRESS="stress";h_.prototype.waitForRender=h_.prototype.jf;h_.prototype.run=h_.prototype.Sf;h_.prototype.enableTracing=h_.prototype.vf;}).call(this);
diff --git a/tools/perf/page_sets/maps_perf_test/worker.js b/tools/perf/page_sets/maps_perf_test/worker.js new file mode 100644 index 0000000..0eaacd2 --- /dev/null +++ b/tools/perf/page_sets/maps_perf_test/worker.js
@@ -0,0 +1,294 @@ +(function(){'use strict';var k,aa=aa||{},l=this;function m(a){return void 0!==a}function ba(a){return"string"==typeof a}function ca(a,b){a=a.split(".");var c=l;a[0]in c||!c.execScript||c.execScript("var "+a[0]);for(var d;a.length&&(d=a.shift());)!a.length&&m(b)?c[d]=b:c[d]&&c[d]!==Object.prototype[d]?c=c[d]:c=c[d]={}}function da(){} +function ea(a){var b=typeof a;if("object"==b)if(a){if(a instanceof Array)return"array";if(a instanceof Object)return b;var c=Object.prototype.toString.call(a);if("[object Window]"==c)return"object";if("[object Array]"==c||"number"==typeof a.length&&"undefined"!=typeof a.splice&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("splice"))return"array";if("[object Function]"==c||"undefined"!=typeof a.call&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("call"))return"function"}else return"null"; +else if("function"==b&&"undefined"==typeof a.call)return"object";return b}function fa(a){var b=typeof a;return"object"==b&&null!=a||"function"==b}function ha(a,b,c){return a.call.apply(a.bind,arguments)}function ia(a,b,c){if(!a)throw Error();if(2<arguments.length){var d=Array.prototype.slice.call(arguments,2);return function(){var c=Array.prototype.slice.call(arguments);Array.prototype.unshift.apply(c,d);return a.apply(b,c)}}return function(){return a.apply(b,arguments)}} +function n(a,b,c){Function.prototype.bind&&-1!=Function.prototype.bind.toString().indexOf("native code")?n=ha:n=ia;return n.apply(null,arguments)}var ja=Date.now||function(){return+new Date};function ka(a,b){function c(){}c.prototype=b.prototype;a.Qa=b.prototype;a.prototype=new c;a.prototype.constructor=a;a.eb=function(a,c,f){for(var d=Array(arguments.length-2),e=2;e<arguments.length;e++)d[e-2]=arguments[e];return b.prototype[c].apply(a,d)}};function la(a,b,c){this.c=a;this.g=b;this.a=null;this.f=c;this.b=-1}la.prototype.abort=function(){return this.a?this.a():!1};la.prototype.postMessage=function(a,b,c){var d={};d.id=this.c;d.payload=a;d.complete=b;d.received=this.b;this.g.postMessage(d,c);b&&this.f(this.c)};var ma=Array.prototype.indexOf?function(a,b){return Array.prototype.indexOf.call(a,b,void 0)}:function(a,b){if(ba(a))return ba(b)&&1==b.length?a.indexOf(b,0):-1;for(var c=0;c<a.length;c++)if(c in a&&a[c]===b)return c;return-1};function na(a){a:{var b=oa;for(var c=a.length,d=ba(a)?a.split(""):a,e=0;e<c;e++)if(e in d&&b.call(void 0,d[e],e,a)){b=e;break a}b=-1}return 0>b?null:ba(a)?a.charAt(b):a[b]} +function pa(a,b,c){return 2>=arguments.length?Array.prototype.slice.call(a,b):Array.prototype.slice.call(a,b,c)};var qa=String.prototype.trim?function(a){return a.trim()}:function(a){return/^[\s\xa0]*([\s\S]*?)[\s\xa0]*$/.exec(a)[1]};function ra(a,b){return a<b?-1:a>b?1:0};var sa;a:{var ta=l.navigator;if(ta){var ua=ta.userAgent;if(ua){sa=ua;break a}}sa=""}function p(a){return-1!=sa.indexOf(a)};var va="constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf".split(" ");function wa(a,b){for(var c,d,e=1;e<arguments.length;e++){d=arguments[e];for(c in d)a[c]=d[c];for(var f=0;f<va.length;f++)c=va[f],Object.prototype.hasOwnProperty.call(d,c)&&(a[c]=d[c])}};function xa(){return(p("Chrome")||p("CriOS"))&&!p("Edge")};function ya(){return p("iPhone")&&!p("iPod")&&!p("iPad")};function za(a){za[" "](a);return a}za[" "]=da;function Ba(a,b){var c=Ca;return Object.prototype.hasOwnProperty.call(c,a)?c[a]:c[a]=b(a)};var Da=p("Opera"),Ea=p("Trident")||p("MSIE"),Fa=p("Edge"),Ga=p("Gecko")&&!(-1!=sa.toLowerCase().indexOf("webkit")&&!p("Edge"))&&!(p("Trident")||p("MSIE"))&&!p("Edge"),Ha=-1!=sa.toLowerCase().indexOf("webkit")&&!p("Edge");function Ia(){var a=l.document;return a?a.documentMode:void 0}var Ja; +a:{var Ka="",La=function(){var a=sa;if(Ga)return/rv:([^\);]+)(\)|;)/.exec(a);if(Fa)return/Edge\/([\d\.]+)/.exec(a);if(Ea)return/\b(?:MSIE|rv)[: ]([^\);]+)(\)|;)/.exec(a);if(Ha)return/WebKit\/(\S+)/.exec(a);if(Da)return/(?:Version)[ \/]?(\S+)/.exec(a)}();La&&(Ka=La?La[1]:"");if(Ea){var Ma=Ia();if(null!=Ma&&Ma>parseFloat(Ka)){Ja=String(Ma);break a}}Ja=Ka}var Na=Ja,Ca={}; +function Oa(a){return Ba(a,function(){for(var b=0,c=qa(String(Na)).split("."),d=qa(String(a)).split("."),e=Math.max(c.length,d.length),f=0;0==b&&f<e;f++){var g=c[f]||"",h=d[f]||"";do{g=/(\d*)(\D*)(.*)/.exec(g)||["","","",""];h=/(\d*)(\D*)(.*)/.exec(h)||["","","",""];if(0==g[0].length&&0==h[0].length)break;b=ra(0==g[1].length?0:parseInt(g[1],10),0==h[1].length?0:parseInt(h[1],10))||ra(0==g[2].length,0==h[2].length)||ra(g[2],h[2]);g=g[3];h=h[3]}while(0==b)}return 0<=b})}var Pa;var Qa=l.document; +Pa=Qa&&Ea?Ia()||("CSS1Compat"==Qa.compatMode?parseInt(Na,10):5):void 0;function Ra(){this.f=this.f;this.j=this.j}Ra.prototype.f=!1;Ra.prototype.h=function(){this.f||(this.f=!0,this.Ga())};Ra.prototype.Ga=function(){if(this.j)for(;this.j.length;)this.j.shift()()};var Sa;(Sa=!Ea)||(Sa=9<=Number(Pa));var Ta=Sa,Ua=Ea&&!Oa("9"),Va=function(){if(!l.addEventListener||!Object.defineProperty)return!1;var a=!1,b=Object.defineProperty({},"passive",{get:function(){a=!0}});l.addEventListener("test",da,b);l.removeEventListener("test",da,b);return a}();function Wa(a,b){this.type=a;this.a=this.target=b;this.Ua=!0}Wa.prototype.b=function(){this.Ua=!1};function Xa(a,b){Wa.call(this,a?a.type:"");this.relatedTarget=this.a=this.target=null;this.button=this.screenY=this.screenX=this.clientY=this.clientX=0;this.key="";this.metaKey=this.shiftKey=this.altKey=this.ctrlKey=!1;this.pointerId=0;this.pointerType="";this.c=null;if(a){var c=this.type=a.type,d=a.changedTouches?a.changedTouches[0]:null;this.target=a.target||a.srcElement;this.a=b;if(b=a.relatedTarget){if(Ga){a:{try{za(b.nodeName);var e=!0;break a}catch(f){}e=!1}e||(b=null)}}else"mouseover"==c?b= +a.fromElement:"mouseout"==c&&(b=a.toElement);this.relatedTarget=b;null===d?(this.clientX=void 0!==a.clientX?a.clientX:a.pageX,this.clientY=void 0!==a.clientY?a.clientY:a.pageY,this.screenX=a.screenX||0,this.screenY=a.screenY||0):(this.clientX=void 0!==d.clientX?d.clientX:d.pageX,this.clientY=void 0!==d.clientY?d.clientY:d.pageY,this.screenX=d.screenX||0,this.screenY=d.screenY||0);this.button=a.button;this.key=a.key||"";this.ctrlKey=a.ctrlKey;this.altKey=a.altKey;this.shiftKey=a.shiftKey;this.metaKey= +a.metaKey;this.pointerId=a.pointerId||0;this.pointerType=ba(a.pointerType)?a.pointerType:Ya[a.pointerType]||"";this.c=a;a.defaultPrevented&&this.b()}}ka(Xa,Wa);var Ya={2:"touch",3:"pen",4:"mouse"};Xa.prototype.b=function(){Xa.Qa.b.call(this);var a=this.c;if(a.preventDefault)a.preventDefault();else if(a.returnValue=!1,Ua)try{if(a.ctrlKey||112<=a.keyCode&&123>=a.keyCode)a.keyCode=-1}catch(b){}};var Za="closure_listenable_"+(1E6*Math.random()|0);function $a(a){return!(!a||!a[Za])}var ab=0;function bb(a,b,c,d,e){this.listener=a;this.a=null;this.src=b;this.type=c;this.capture=!!d;this.Ja=e;this.key=++ab;this.xa=this.Ha=!1}function cb(a){a.xa=!0;a.listener=null;a.a=null;a.src=null;a.Ja=null};function db(a){this.src=a;this.a={};this.b=0}db.prototype.add=function(a,b,c,d,e){var f=a.toString();a=this.a[f];a||(a=this.a[f]=[],this.b++);var g=eb(a,b,d,e);-1<g?(b=a[g],c||(b.Ha=!1)):(b=new bb(b,this.src,f,!!d,e),b.Ha=c,a.push(b));return b};function fb(a,b){var c=b.type;if(!(c in a.a))return!1;var d=a.a[c],e=ma(d,b),f;(f=0<=e)&&Array.prototype.splice.call(d,e,1);f&&(cb(b),0==a.a[c].length&&(delete a.a[c],a.b--));return f} +function gb(a){var b=0,c;for(c in a.a){for(var d=a.a[c],e=0;e<d.length;e++)++b,cb(d[e]);delete a.a[c];a.b--}}function eb(a,b,c,d){for(var e=0;e<a.length;++e){var f=a[e];if(!f.xa&&f.listener==b&&f.capture==!!c&&f.Ja==d)return e}return-1};var hb="closure_lm_"+(1E6*Math.random()|0),ib={},jb=0;function kb(a,b,c,d,e){if(d&&d.once)lb(a,b,c,d,e);else if("array"==ea(b))for(var f=0;f<b.length;f++)kb(a,b[f],c,d,e);else c=mb(c),$a(a)?nb(a,b,c,fa(d)?!!d.capture:!!d,e):ob(a,b,c,!1,d,e)} +function ob(a,b,c,d,e,f){if(!b)throw Error("Invalid event type");var g=fa(e)?!!e.capture:!!e,h=pb(a);h||(a[hb]=h=new db(a));c=h.add(b,c,d,g,f);if(!c.a){d=qb();c.a=d;d.src=a;d.listener=c;if(a.addEventListener)Va||(e=g),void 0===e&&(e=!1),a.addEventListener(b.toString(),d,e);else if(a.attachEvent)a.attachEvent(rb(b.toString()),d);else if(a.addListener&&a.removeListener)a.addListener(d);else throw Error("addEventListener and attachEvent are unavailable.");jb++}} +function qb(){var a=sb,b=Ta?function(c){return a.call(b.src,b.listener,c)}:function(c){c=a.call(b.src,b.listener,c);if(!c)return c};return b}function lb(a,b,c,d,e){if("array"==ea(b))for(var f=0;f<b.length;f++)lb(a,b[f],c,d,e);else c=mb(c),$a(a)?a.U.add(String(b),c,!0,fa(d)?!!d.capture:!!d,e):ob(a,b,c,!0,d,e)} +function tb(a,b,c,d,e){if("array"==ea(b))for(var f=0;f<b.length;f++)tb(a,b[f],c,d,e);else(d=fa(d)?!!d.capture:!!d,c=mb(c),$a(a))?(a=a.U,b=String(b).toString(),b in a.a&&(f=a.a[b],c=eb(f,c,d,e),-1<c&&(cb(f[c]),Array.prototype.splice.call(f,c,1),0==f.length&&(delete a.a[b],a.b--)))):a&&(a=pb(a))&&(b=a.a[b.toString()],a=-1,b&&(a=eb(b,c,d,e)),(c=-1<a?b[a]:null)&&ub(c))} +function ub(a){if("number"==typeof a||!a||a.xa)return!1;var b=a.src;if($a(b))return fb(b.U,a);var c=a.type,d=a.a;b.removeEventListener?b.removeEventListener(c,d,a.capture):b.detachEvent?b.detachEvent(rb(c),d):b.addListener&&b.removeListener&&b.removeListener(d);jb--;(c=pb(b))?(fb(c,a),0==c.b&&(c.src=null,b[hb]=null)):cb(a);return!0}function rb(a){return a in ib?ib[a]:ib[a]="on"+a} +function vb(a,b,c,d){var e=!0;if(a=pb(a))if(b=a.a[b.toString()])for(b=b.concat(),a=0;a<b.length;a++){var f=b[a];f&&f.capture==c&&!f.xa&&(f=wb(f,d),e=e&&!1!==f)}return e}function wb(a,b){var c=a.listener,d=a.Ja||a.src;a.Ha&&ub(a);return c.call(d,b)} +function sb(a,b){if(a.xa)return!0;if(!Ta){if(!b)a:{b=["window","event"];for(var c=l,d=0;d<b.length;d++)if(c=c[b[d]],null==c){b=null;break a}b=c}d=b;b=new Xa(d,this);c=!0;if(!(0>d.keyCode||void 0!=d.returnValue)){a:{var e=!1;if(0==d.keyCode)try{d.keyCode=-1;break a}catch(g){e=!0}if(e||void 0==d.returnValue)d.returnValue=!0}d=[];for(e=b.a;e;e=e.parentNode)d.push(e);a=a.type;for(e=d.length-1;0<=e;e--){b.a=d[e];var f=vb(d[e],a,!0,b);c=c&&f}for(e=0;e<d.length;e++)b.a=d[e],f=vb(d[e],a,!1,b),c=c&&f}return c}return wb(a, +new Xa(b,this))}function pb(a){a=a[hb];return a instanceof db?a:null}var xb="__closure_events_fn_"+(1E9*Math.random()>>>0);function mb(a){if("function"==ea(a))return a;a[xb]||(a[xb]=function(b){return a.handleEvent(b)});return a[xb]};function q(){Ra.call(this);this.U=new db(this);this.D=this;this.B=null}ka(q,Ra);q.prototype[Za]=!0;q.prototype.addEventListener=function(a,b,c,d){kb(this,a,b,c,d)};q.prototype.removeEventListener=function(a,b,c,d){tb(this,a,b,c,d)}; +q.prototype.dispatchEvent=function(a){var b,c=this.B;if(c)for(b=[];c;c=c.B)b.push(c);c=this.D;var d=a.type||a;if(ba(a))a=new Wa(a,c);else if(a instanceof Wa)a.target=a.target||c;else{var e=a;a=new Wa(d,c);wa(a,e)}e=!0;if(b)for(var f=b.length-1;0<=f;f--){var g=a.a=b[f];e=yb(g,d,!0,a)&&e}g=a.a=c;e=yb(g,d,!0,a)&&e;e=yb(g,d,!1,a)&&e;if(b)for(f=0;f<b.length;f++)g=a.a=b[f],e=yb(g,d,!1,a)&&e;return e};q.prototype.Ga=function(){q.Qa.Ga.call(this);this.U&&gb(this.U);this.B=null}; +function nb(a,b,c,d,e){a.U.add(String(b),c,!1,d,e)}function yb(a,b,c,d){b=a.U.a[String(b)];if(!b)return!0;b=b.concat();for(var e=!0,f=0;f<b.length;++f){var g=b[f];if(g&&!g.xa&&g.capture==c){var h=g.listener,r=g.Ja||g.src;g.Ha&&fb(a.U,g);e=!1!==h.call(r,d)&&e}}return e&&0!=d.Ua};var zb="StopIteration"in l?l.StopIteration:{message:"StopIteration",stack:""};function Ab(){}Ab.prototype.next=function(){throw zb;};Ab.prototype.Xa=function(){return this};function Bb(a){switch(a){case 200:case 201:case 202:case 204:case 206:case 304:case 1223:return!0;default:return!1}};function Cb(){}Cb.prototype.a=null;function Db(a){var b;(b=a.a)||(b={},Eb(a)&&(b[0]=!0,b[1]=!0),b=a.a=b);return b};var Fb;function Gb(){}ka(Gb,Cb);function Hb(a){return(a=Eb(a))?new ActiveXObject(a):new XMLHttpRequest}function Eb(a){if(!a.b&&"undefined"==typeof XMLHttpRequest&&"undefined"!=typeof ActiveXObject){for(var b=["MSXML2.XMLHTTP.6.0","MSXML2.XMLHTTP.3.0","MSXML2.XMLHTTP","Microsoft.XMLHTTP"],c=0;c<b.length;c++){var d=b[c];try{return new ActiveXObject(d),a.b=d}catch(e){}}throw Error("Could not create ActiveXObject. ActiveX might be disabled, or MSXML might not be installed");}return a.b}Fb=new Gb;function Ib(a,b){this.b={};this.a=[];this.f=this.c=0;var c=arguments.length;if(1<c){if(c%2)throw Error("Uneven number of arguments");for(var d=0;d<c;d+=2)this.set(arguments[d],arguments[d+1])}else if(a)if(a instanceof Ib)for(c=a.La(),d=0;d<c.length;d++)this.set(c[d],a.get(c[d]));else for(d in a)this.set(d,a[d])}k=Ib.prototype;k.La=function(){Jb(this);return this.a.concat()};k.clear=function(){this.b={};this.f=this.c=this.a.length=0}; +function Jb(a){if(a.c!=a.a.length){for(var b=0,c=0;b<a.a.length;){var d=a.a[b];Object.prototype.hasOwnProperty.call(a.b,d)&&(a.a[c++]=d);b++}a.a.length=c}if(a.c!=a.a.length){var e={};for(c=b=0;b<a.a.length;)d=a.a[b],Object.prototype.hasOwnProperty.call(e,d)||(a.a[c++]=d,e[d]=1),b++;a.a.length=c}}k.get=function(a,b){return Object.prototype.hasOwnProperty.call(this.b,a)?this.b[a]:b};k.set=function(a,b){Object.prototype.hasOwnProperty.call(this.b,a)||(this.c++,this.a.push(a),this.f++);this.b[a]=b}; +k.forEach=function(a,b){for(var c=this.La(),d=0;d<c.length;d++){var e=c[d],f=this.get(e);a.call(b,f,e,this)}};k.Xa=function(a){Jb(this);var b=0,c=this.f,d=this,e=new Ab;e.next=function(){if(c!=d.f)throw Error("The map has changed since the iterator was created");if(b>=d.a.length)throw zb;var e=d.a[b++];return a?e:d.b[e]};return e};function Kb(a,b,c){if("function"==ea(a))c&&(a=n(a,c));else if(a&&"function"==typeof a.handleEvent)a=n(a.handleEvent,a);else throw Error("Invalid listener argument");return 2147483647<Number(b)?-1:l.setTimeout(a,b||0)};var Lb=/^(?:([^:/?#.]+):)?(?:\/\/(?:([^/?#]*)@)?([^/#?]*?)(?::([0-9]+))?(?=[/#?]|$))?([^?#]+)?(?:\?([^#]*))?(?:#([\s\S]*))?$/;function Mb(a){q.call(this);this.headers=new Ib;this.u=a||null;this.b=!1;this.s=this.a=null;this.A="";this.c=this.w=this.i=this.v=!1;this.m=0;this.l=null;this.g="";this.C=this.o=!1}ka(Mb,q);var Nb=/^https?$/i,Ob=["POST","PUT"]; +function Pb(a,b,c,d){if(a.a)throw Error("[goog.net.XhrIo] Object is active with another request="+a.A+"; newUri="+b);c=c?c.toUpperCase():"GET";a.A=b;a.v=!1;a.b=!0;a.a=a.u?Hb(a.u):Hb(Fb);a.s=a.u?Db(a.u):Db(Fb);a.a.onreadystatechange=n(a.Ta,a);try{a.w=!0,a.a.open(c,String(b),!0),a.w=!1}catch(g){Qb(a);return}b=d||"";d=new Ib(a.headers);var e=na(d.La()),f=l.FormData&&b instanceof l.FormData;!(0<=ma(Ob,c))||e||f||d.set("Content-Type","application/x-www-form-urlencoded;charset=utf-8");d.forEach(function(a, +b){this.a.setRequestHeader(b,a)},a);a.g&&(a.a.responseType=a.g);"withCredentials"in a.a&&a.a.withCredentials!==a.o&&(a.a.withCredentials=a.o);try{Rb(a),0<a.m&&(a.C=Sb(a.a),a.C?(a.a.timeout=a.m,a.a.ontimeout=n(a.Wa,a)):a.l=Kb(a.Wa,a.m,a)),a.i=!0,a.a.send(b),a.i=!1}catch(g){Qb(a)}}function Sb(a){return Ea&&Oa(9)&&"number"==typeof a.timeout&&m(a.ontimeout)}function oa(a){return"content-type"==a.toLowerCase()}k=Mb.prototype; +k.Wa=function(){"undefined"!=typeof aa&&this.a&&(this.dispatchEvent("timeout"),this.abort(8))};function Qb(a){a.b=!1;a.a&&(a.c=!0,a.a.abort(),a.c=!1);Tb(a);Ub(a)}function Tb(a){a.v||(a.v=!0,a.dispatchEvent("complete"),a.dispatchEvent("error"))}k.abort=function(){this.a&&this.b&&(this.b=!1,this.c=!0,this.a.abort(),this.c=!1,this.dispatchEvent("complete"),this.dispatchEvent("abort"),Ub(this))};k.Ga=function(){this.a&&(this.b&&(this.b=!1,this.c=!0,this.a.abort(),this.c=!1),Ub(this,!0));Mb.Qa.Ga.call(this)}; +k.Ta=function(){this.f||(this.w||this.i||this.c?Vb(this):this.Za())};k.Za=function(){Vb(this)};function Vb(a){if(a.b&&"undefined"!=typeof aa&&(!a.s[1]||4!=Wb(a)||2!=Xb(a)))if(a.i&&4==Wb(a))Kb(a.Ta,0,a);else if(a.dispatchEvent("readystatechange"),4==Wb(a)){a.b=!1;try{Yb(a)?(a.dispatchEvent("complete"),a.dispatchEvent("success")):Tb(a)}finally{Ub(a)}}}function Ub(a,b){if(a.a){Rb(a);var c=a.a,d=a.s[0]?da:null;a.a=null;a.s=null;b||a.dispatchEvent("ready");try{c.onreadystatechange=d}catch(e){}}} +function Rb(a){a.a&&a.C&&(a.a.ontimeout=null);a.l&&(l.clearTimeout(a.l),a.l=null)}function Yb(a){var b=Xb(a),c;if(!(c=Bb(b))){if(b=0===b)a=String(a.A).match(Lb)[1]||null,!a&&l.self&&l.self.location&&(a=l.self.location.protocol,a=a.substr(0,a.length-1)),b=!Nb.test(a?a.toLowerCase():"");c=b}return c}function Wb(a){return a.a?a.a.readyState:0}function Xb(a){try{return 2<Wb(a)?a.a.status:-1}catch(b){return-1}}function Zb(a){try{return a.a?a.a.responseText:""}catch(b){return""}} +k.Ia=function(){try{if(!this.a)return null;if("response"in this.a)return this.a.response;switch(this.g){case "":case "text":return this.a.responseText;case "arraybuffer":if("mozResponseArrayBuffer"in this.a)return this.a.mozResponseArrayBuffer}return null}catch(a){return null}};function $b(){this.a=0;this.c=this.b=null}function ac(a,b){a.b=b;a.c=null}$b.prototype.cancel=function(){if(3==this.a)return!1;var a=!1;this.b&&(a=this.b.call(this.c))&&(this.a=3);return a};$b.prototype.start=function(){if(0!=this.a)throw Error("Trying to reuse an Rpc object. Status is not INACTIVE");this.a=1};function bc(a,b){if(0==b)throw Error("Trying to set the Rpc status to INACTIVE.");a.a=b};function cc(a,b,c,d){this.data=a;this.width=b;this.height=c;this.a=d||1};function dc(){this.a=this.c=this.f=this.h=this.g=null;this.b=0}function ec(){this.g=this.f=this.i=this.h=this.a=this.c=this.b=this.status=null}function fc(a){if(!a)return null;var b={};b.data=a.data;b.width=a.width;b.height=a.height;b.format=a.a;return b}function gc(){this.a=this.b=0};function hc(){this.b=[];this.a=new gc}function ic(a,b,c){a=new jc(a,b,c);kc.b.push(a);return n(a.g,a)}function lc(a,b,c){var d=a.b;if(!d.length)return!1;for(var e=0;e<d.length;++e){var f=d[e];if(f.h==b){d.splice(e,1);b=f;for(d=0;d<b.a.length;++d)e=b.a[d],c(e.response,e.complete,e.cb);b.a.length=0;b.b=c;a.a.b++;return!0}}for(e=0;e<d.length;++e)f=d[e],f.abort();d.length=0;a.a.a++;return!1}function jc(a,b,c){this.h=a;this.c=b;this.f=c;this.b=null;this.a=[]} +jc.prototype.g=function(a,b,c){this.b?this.b(a,b,c):this.a.push({response:a,complete:b,cb:c})};jc.prototype.abort=function(){this.c&&this.c.cancel();this.f&&this.f.abort()};function mc(a){switch(a){case 5:case 3:case 13:case 4:case 17:case 18:case 8:case 14:case 31:return 0;case 1:case 6:case 16:case 30:return 1;case 9:case 11:case 12:return 2;case 2:case 7:case 15:return 5;default:return-1}};var nc=p("Firefox"),oc=ya()||p("iPod"),pc=p("iPad"),qc=p("Android")&&!(xa()||p("Firefox")||p("Opera")||p("Silk")),rc=xa(),sc=p("Safari")&&!(xa()||p("Coast")||p("Opera")||p("Edge")||p("Silk")||p("Android"))&&!(ya()||p("iPad")||p("iPod"));var tc=null,uc=null;function vc(a){var b=a.length,c=0;"="===a[b-2]?c=2:"="===a[b-1]&&(c=1);var d=new Uint8Array(Math.ceil(3*b/4)-c),e=0;wc(a,function(a){d[e++]=a});return d.subarray(0,e)} +function wc(a,b){function c(b){for(;d<a.length;){var c=a.charAt(d++),e=uc[c];if(null!=e)return e;if(!/^[\s\xa0]*$/.test(c))throw Error("Unknown base64 encoding at char: "+c);}return b}xc();for(var d=0;;){var e=c(-1),f=c(0),g=c(64),h=c(64);if(64===h&&-1===e)break;b(e<<2|f>>4);64!=g&&(b(f<<4&240|g>>2),64!=h&&b(g<<6&192|h))}} +function xc(){if(!tc){tc={};uc={};for(var a=0;65>a;a++)tc[a]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(a),uc[tc[a]]=a,62<=a&&(uc["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.".charAt(a)]=a)}};function yc(a,b){var c=b&2147483648;c&&(a=~a+1>>>0,b=~b>>>0,0==a&&(b=b+1>>>0));a=4294967296*b+a;return c?-a:a};function zc(a,b,c){this.c=this.h=this.a=null;this.g=0;this.b=null;this.f=!0;Ac(this,a,b,c)}function Ac(a,b,c,d){b&&c&&(a.a=b,a.h=c);a.c=d||null;a.g=0;a.b=null;a.f=!a.a&&!a.c;a.next()}var Bc=[];function Cc(a,b,c){if(Bc.length){var d=Bc.pop();Ac(d,a,b,c);return d}return new zc(a,b,c)}function Dc(a){a.clear();100>Bc.length&&Bc.push(a)}zc.prototype.clear=function(){this.a&&Ec(this.a);this.c=this.h=this.a=null;this.g=0;this.b=null;this.f=!0};zc.prototype.get=function(){return this.b};zc.prototype.V=function(){return this.f}; +zc.prototype.next=function(){var a=this.b;this.a?this.a.V()?(this.b=null,this.f=!0):this.b=this.h.call(this.a):this.c&&(this.g==this.c.length?(this.b=null,this.f=!0):this.b=this.c[this.g++]);return a};function Fc(a,b,c){this.b=null;this.f=this.g=this.a=this.c=this.h=0;this.i=!1;a&&Gc(this,a,b,c)}var Hc=[];function Ic(a,b,c){if(Hc.length){var d=Hc.pop();a&&Gc(d,a,b,c);return d}return new Fc(a,b,c)}function Ec(a){a.clear();100>Hc.length&&Hc.push(a)}k=Fc.prototype; +k.clear=function(){this.b=null;this.a=this.c=this.h=0;this.i=!1};function Gc(a,b,c,d){b=b.constructor===Uint8Array?b:b.constructor===ArrayBuffer?new Uint8Array(b):b.constructor===Array?new Uint8Array(b):b.constructor===String?vc(b):new Uint8Array(0);a.b=b;a.h=m(c)?c:0;a.c=m(d)?a.h+d:a.b.length;a.a=a.h}k.reset=function(){this.a=this.h};k.V=function(){return this.a==this.c};k.getError=function(){return this.i||0>this.a||this.a>this.c}; +function Jc(a){for(var b,c=0,d,e=0;4>e;e++)if(b=a.b[a.a++],c|=(b&127)<<7*e,128>b){a.g=c>>>0;a.f=0;return}b=a.b[a.a++];c|=(b&127)<<28;d=0|(b&127)>>4;if(128>b)a.g=c>>>0,a.f=d>>>0;else{for(e=0;5>e;e++)if(b=a.b[a.a++],d|=(b&127)<<7*e+3,128>b){a.g=c>>>0;a.f=d>>>0;return}a.i=!0}} +k.S=function(){var a=this.b;var b=a[this.a+0];var c=b&127;if(128>b)return this.a+=1,c;b=a[this.a+1];c|=(b&127)<<7;if(128>b)return this.a+=2,c;b=a[this.a+2];c|=(b&127)<<14;if(128>b)return this.a+=3,c;b=a[this.a+3];c|=(b&127)<<21;if(128>b)return this.a+=4,c;b=a[this.a+4];c|=(b&15)<<28;if(128>b)return this.a+=5,c>>>0;this.a+=5;128<=a[this.a++]&&128<=a[this.a++]&&128<=a[this.a++]&&128<=a[this.a++]&&this.a++;return c};k.Pa=Fc.prototype.S;function Kc(a){a=a.S();return a>>>1^-(a&1)} +function Lc(a){Jc(a);return yc(a.g,a.f)}function t(a){var b=a.b[a.a+0],c=a.b[a.a+1],d=a.b[a.a+2],e=a.b[a.a+3];a.a+=4;return(b<<0|c<<8|d<<16|e<<24)>>>0}function Mc(a){var b=t(a);a=2*(b>>31)+1;var c=b>>>23&255;b&=8388607;return 255==c?b?NaN:Infinity*a:0==c?a*Math.pow(2,-149)*b:a*Math.pow(2,c-150)*(b+Math.pow(2,23))} +function Nc(a){var b=t(a),c=t(a);a=2*(c>>31)+1;var d=c>>>20&2047;b=4294967296*(c&1048575)+b;return 2047==d?b?NaN:Infinity*a:0==d?a*Math.pow(2,-1074)*b:a*Math.pow(2,d-1075)*(b+4503599627370496)};function Oc(a,b,c){this.b=Ic(a,b,c);this.c=this.b.a;this.f=this.a=-1;this.g=!1}var Pc=[];function Qc(a,b,c){if(Pc.length){var d=Pc.pop();a&&Gc(d.b,a,b,c);return d}return new Oc(a,b,c)}function Rc(a){a.b.clear();a.a=-1;a.f=-1;a.g=!1;100>Pc.length&&Pc.push(a)}Oc.prototype.getError=function(){return this.g||this.b.getError()};Oc.prototype.reset=function(){this.b.reset();this.f=this.a=-1}; +function u(a){if(a.b.V()||a.getError())return!1;a.c=a.b.a;var b=a.b.S(),c=b&7;if(0!=c&&5!=c&&1!=c&&2!=c&&3!=c&&4!=c)return a.g=!0,!1;a.a=b>>>3;a.f=c;return!0}function w(a){if(2!=a.f)x(a);else{var b=a.b.S();a=a.b;a.a+=b}} +function x(a){switch(a.f){case 0:if(0!=a.f)x(a);else{for(a=a.b;a.b[a.a]&128;)a.a++;a.a++}break;case 1:1!=a.f?x(a):(a=a.b,a.a+=8);break;case 2:w(a);break;case 5:5!=a.f?x(a):(a=a.b,a.a+=4);break;case 3:var b=[a.a];do{if(!u(a)){a.g=!0;break}if(3==a.f)b.push(a.a);else if(4==a.f&&a.a!=b.pop()){a.g=!0;break}}while(0<b.length)}} +function Sc(a,b){a.f=mc(b);switch(b){case 1:return Nc(a.b);case 2:return Mc(a.b);case 3:return Lc(a.b);case 4:return a=a.b,Jc(a),4294967296*a.f+a.g;case 5:return y(a);case 6:return a=a.b,b=t(a),4294967296*t(a)+b;case 7:return t(a.b);case 8:return z(a);case 9:return A(a);case 10:case 11:case 12:return Tc(a);case 13:return B(a);case 14:return C(a);case 15:a=a.b;b=a.b[a.a+0];var c=a.b[a.a+1],d=a.b[a.a+2],e=a.b[a.a+3];a.a+=4;return b<<0|c<<8|d<<16|e<<24;case 16:return b=a.b,a=t(b),b=t(b),yc(a,b);case 17:return Kc(a.b); +case 18:return b=a.b,Jc(b),a=b.g,c=b.f,b=a&1,a=(a>>>1|c<<31)>>>0,c>>>=1,b&&(a=a+1>>>0,0==a&&(c=c+1>>>0)),a=4294967296*c+a,b?-a:a;case 30:return D(a);case 31:return E(a)}return 0}function G(a,b,c){var d=a.b.c,e=a.b.S();e=a.b.a+e;a.b.c=e;c(b,a);a.b.a=e;a.b.c=d}function y(a){return a.b.Pa()}function B(a){return a.b.S()}function z(a){return!!a.b.S()}function C(a){return Lc(a.b)} +function A(a){var b=a.b.S();a=a.b;var c=a.b,d=a.a,e=d+b,f=[];for(b="";d<e;){var g=c[d++];if(128>g)f.push(g);else if(192>g)continue;else if(224>g){var h=c[d++];f.push((g&31)<<6|h&63)}else if(240>g){h=c[d++];var r=c[d++];f.push((g&15)<<12|(h&63)<<6|r&63)}else if(248>g){h=c[d++];r=c[d++];var v=c[d++];g=(g&7)<<18|(h&63)<<12|(r&63)<<6|v&63;g-=65536;f.push((g>>10&1023)+55296,(g&1023)+56320)}8192<=f.length&&(b+=String.fromCharCode.apply(null,f),f.length=0)}if(8192>=f.length)f=String.fromCharCode.apply(null, +f);else{c="";for(e=0;e<f.length;e+=8192)c+=String.fromCharCode.apply(null,pa(f,e,e+8192));f=c}a.a=d;return b+f}function Tc(a){var b=a.b.S();a=a.b;if(0>b||a.a+b>a.b.length)a.i=!0,b=new Uint8Array(0);else{var c=a.b.subarray(a.a,a.a+b);a.a+=b;b=c}return b}function E(a){var b=a.b;Jc(b);a=b.g;b=b.f;return String.fromCharCode(a>>>0&255,a>>>8&255,a>>>16&255,a>>>24&255,b>>>0&255,b>>>8&255,b>>>16&255,b>>>24&255)} +function D(a){a=a.b;var b=a.b,c=a.a,d=b[c+0],e=b[c+1],f=b[c+2],g=b[c+3],h=b[c+4],r=b[c+5],v=b[c+6];b=b[c+7];a.a+=8;return String.fromCharCode(d,e,f,g,h,r,v,b)};function Uc(a,b,c,d,e,f,g){this.g=a;this.a=b;this.b=m(c)?c:null;this.i=m(d)?d:null;this.h=m(e)?e:null;this.c=m(f)?f:null;this.f=m(g)?g:null}function Vc(){this.c=-1;this.value=this.a=this.b=this.start=this.buffer=null}var Wc=[],Xc=0;function Yc(a){if(a){null!=a.buffer&&null!=a.start&&null!=a.b&&null!=a.a&&null!=a.value&&(a.a.i&&a.a.i(a.value),a.value=null);a.c=-1;a.buffer=null;a.start=null;a.b=null;a.a=null;a.value=null;var b=Xc;1E3>b&&(Wc[b]=a,Xc++)}} +function Zc(a){if(null==a)return null;for(var b=[],c=0;c<a.length;c++){var d=a[c],e=new Vc;e.c=d.c;null!=d.value&&null!=d.a?(e.a=d.a,d.a.c?e.value=d.a.c(d.value):12==d.a.a?e.value=new Uint8Array(d.value):e.value=d.value):null!=d.buffer&&null!=d.start&&null!=d.b&&(e.buffer=new Uint8Array(d.buffer.buffer.slice(d.start,d.b)),e.start=0,e.b=d.b-d.start);b.push(e)}return b}function H(a,b,c,d,e,f,g,h){c=new Uc(b,c,d,e,f,g,h);for(d=0;d<a.length;d++)if(a[d].g==b){a[d]=c;return}a.push(c)};function $c(a,b,c){var d=Fc.prototype.Pa;return a&&null!=b&&null!=c&&d?(a=Ic(a,b,c-b),a.S(),a.S(),Cc(a,d,null)):Cc()}function I(a){return a?a.slice():null}function J(a,b){if(null===a)return null;for(var c=[],d=0;d<a.length;d++)c.push(b(a[d]));return c}function L(a,b){var c=a?a.length:0;if(c!=(b?b.length:0))return!1;for(var d=0;d<c;++d)if(a[d]!=b[d])return!1;return!0}function M(a,b,c){var d=a?a.length:0;if(d!=(b?b.length:0))return!1;for(var e=0;e<d;++e)if(!c(a[e],b[e]))return!1;return!0} +function ad(a,b){var c=a?a.length:0;if(c!=(b?b.length:0))return!1;for(var d=0;d<c;d++){var e=a[d],f=b[d];if(e.a!==f.a)return!1;if(e.a.f){if(!e.a.f(e.value,f.value))return!1}else if(12==e.a.a){if(!L(e.value,f.value))return!1}else if(e.value!=f.value)return!1}return!0}function bd(a,b,c){var d=Fc.prototype.Pa;if(a&&null!=b&&null!=c){a=Ic(a,b,c-b);a.S();a.S();for(b=[];!a.V();)b.push(d.call(a));Ec(a);return b}return null} +function cd(a,b,c){return a&&null!=b&&null!=c?(a=Qc(a,b,c-b),u(a),b=Tc(a),Rc(a),b):null}function P(a,b){if(!a)return null;a:{for(var c=0;c<a.length;c++)if(a[c].c==b){a=a[c];break a}a=null}a&&a.a?a.value?a=a.value:null==a||null==a.a||null==a.buffer||null==a.start||null==a.b?a=null:(b=Qc(a.buffer,a.start,a.b-a.start),u(b),a.a.b&&a.a.h?(a.value=a.a.b(),G(b,a.value,a.a.h)):a.value=Sc(b,a.a.a),Rc(b),a.buffer=null,a.start=null,a.b=null,a=a.value):a=null;return a} +function Q(a,b){var c=a.a,d=a.b.b,e=a.c;x(a);a=a.b.a;var f=null;if(b)for(var g=0;g<b.length;g++){var h=b[g];if(h.g==c){f=h;break}}b=f;Xc?(Xc--,f=Wc[Xc],Wc[Xc]=null):f=new Vc;g=f;g.c=c;g.buffer=m(d)?d:null;g.start=m(e)?e:null;g.b=m(a)?a:null;g.a=m(b)?b:null;g.value=null;return f};function dd(){this.b=this.a=null}dd.prototype.getExtension=function(){return null};function ed(a,b){for(;u(b);)switch(b.a){case 1:var c=C(b);a.a=c;break;case 2:c=A(b);a.b=c;break;default:x(b)}};function fd(){this.b=this.a=null}function gd(){this.a=null}fd.prototype.getExtension=function(){return null};function hd(){return new fd}function id(a){if(null===a)a=null;else{var b=new fd;if(b.a)for(var c=0;c<b.a.length;c++){var d=b.a[c];d&&jd(d)}b.a=null;b.b=null;b.a=J(a.a,kd);b.b=a.b;a=b}return a}function ld(){}function md(a,b){for(;u(b);)switch(b.a){case 1:var c=new gd;G(b,c,nd);a.a=a.a||[];a.a.push(c);break;case 2:c=A(b);a.b=c;break;default:x(b)}} +function od(a,b){return a===b?!0:null===a||null===b?!1:M(a.a,b.a,pd)&&a.b===b.b?!0:!1}function jd(a){var b=a.a;b&&(b.a=null,b.b=null);a.a=null}gd.prototype.getExtension=function(){return null};function kd(a){if(null===a)var b=null;else{b=new gd;jd(b);if(a.a){var c=new dd;a=a.a;c.a=null;c.b=null;c.a=a.a;c.b=a.b}else c=null;b.a=c}return b}function nd(a,b){for(;u(b);)switch(b.a){case 3:var c=new dd;G(b,c,ed);a.a=c;break;default:x(b)}} +function pd(a,b){a===b?b=!0:null===a||null===b?b=!1:(a=a.a,b=b.a,b=a===b||(null===a||null===b?0:a.a===b.a&&a.b===b.b)?!0:!1);return b};function qd(){this.a=this.b=null}qd.prototype.getExtension=function(){return null};function rd(a,b){for(;u(b);)switch(b.a){case 1:var c=C(b);a.b=c;break;case 2:c=A(b);a.a=c;break;default:x(b)}};function sd(){this.b=this.a=null}function td(a){var b=a.a;b&&(b.b=null,b.a=null);a.a=null;a.b=null}sd.prototype.getExtension=function(){return null};function ud(a,b){for(;u(b);)switch(b.a){case 1:var c=new qd;G(b,c,rd);a.a=c;break;case 2:c=z(b);a.b=c;break;default:x(b)}};function vd(){this.a=null}function wd(a){var b=a.a;b&&td(b);a.a=null}vd.prototype.getExtension=function(){return null};function xd(a,b){for(;u(b);)switch(b.a){case 15:var c=new sd;G(b,c,ud);a.a=c;break;default:x(b)}};function yd(){this.a=null}function zd(a){if(a.a)for(var b=0;b<a.a.length;b++)Yc(a.a[b]);a.a=null}var Ad=[];yd.prototype.getExtension=function(a){var b=!1;4<=a&&2147483647>a&&(b=!0);return b?P(this.a,a):null};function Bd(a,b){for(;u(b);){a.a=a.a||[];var c=Q(b,Ad);a.a.push(c)}};function Cd(){this.a=this.b=this.f=this.c=null}function Dd(a){var b=new Cd;Ed(b);b.c=a.c;b.f=a.f;if(a.b){var c=new yd;var d=a.b;zd(c);c.a=Zc(d.a)}else c=null;b.b=c;if(a.a){c=new vd;d=a.a;wd(c);if(d.a){a=new sd;d=d.a;td(a);if(d.a){var e=new qd;var f=d.a;e.b=null;e.a=null;e.b=f.b;e.a=f.a}else e=null;a.a=e;a.b=d.b}else a=null;c.a=a}else c=null;b.a=c;return b}function Ed(a){a.c=null;a.f=null;var b=a.b;b&&zd(b);a.b=null;(b=a.a)&&wd(b);a.a=null}Cd.prototype.getExtension=function(){return null}; +function Fd(a,b){for(;u(b);)switch(b.a){case 1:var c=t(b.b);a.c=c;break;case 2:c=t(b.b);a.f=c;break;case 15:c=new yd;G(b,c,Bd);a.b=c;break;case 500:c=new vd;G(b,c,xd);a.a=c;break;default:x(b)}} +function Gd(a,b){if(a===b)b=!0;else if(null===a||null===b)b=!1;else{var c;if(c=a.c===b.c&&a.f===b.f){c=a.b;var d=b.b;c=c===d?!0:null===c||null===d?!1:ad(c.a,d.a)?!0:!1}c&&(a=a.a,c=b.a,a===c?b=!0:null===a||null===c?b=!1:(b=a.a,a=c.a,(c=b===a)||(null===b||null===a?b=0:(c=b.a,d=a.a,b=(c===d?!0:null===c||null===d?!1:c.b!==d.b||c.a!==d.a?!1:!0)&&b.b===a.b),c=b),b=c?!0:!1),c=b);b=c?!0:!1}return b};function Hd(){this.a=this.b=null}function Id(a){var b=a.b;b&&Ed(b);a.b=null;(b=a.a)&&Ed(b);a.a=null}Hd.prototype.getExtension=function(){return null};function Jd(a,b){for(;u(b);)switch(b.a){case 1:var c=new Cd;G(b,c,Fd);a.b=c;break;case 2:c=new Cd;G(b,c,Fd);a.a=c;break;default:x(b)}};function Kd(){this.a=this.b=this.c=null}function Ld(){this.b=this.a=null}function Md(a){var b=new Kd;Nd(b);b.c=a.c;b.b=a.b;b.a=a.a;return b}function Nd(a){a.c=null;a.b=null;a.a=null}Kd.prototype.getExtension=function(){return null};function Od(a,b){for(;u(b);)switch(b.a){case 1:var c=E(b);a.c=c;break;case 2:c=t(b.b);a.b=c;break;case 3:c=t(b.b);a.a=c;break;default:x(b)}}function Pd(a,b){return a===b?!0:null===a||null===b?!1:a.c!==b.c||a.b!==b.b||a.a!==b.a?!1:!0} +function Qd(a){var b=new Ld;Rd(b);b.a=a.a?Md(a.a):null;b.b=a.b;return b}function Rd(a){var b=a.a;b&&Nd(b);a.a=null;a.b=null}Ld.prototype.getExtension=function(){return null};function Sd(a,b){for(;u(b);)switch(b.a){case 1:var c=new Kd;G(b,c,Od);a.a=c;break;case 2:c=E(b);a.b=c;break;default:x(b)}}function Td(a,b){return a===b?!0:null===a||null===b?!1:Pd(a.a,b.a)&&a.b===b.b?!0:!1};function Ud(){this.f=this.c=this.a=this.b=null}function Vd(a){var b=a.b;b&&Nd(b);a.b=null;(b=a.a)&&Rd(b);a.a=null;a.c=null;a.f=null}Ud.prototype.getExtension=function(){return null};function Wd(a,b){for(;u(b);)switch(b.a){case 1:var c=new Kd;G(b,c,Od);a.b=c;break;case 2:c=new Ld;G(b,c,Sd);a.a=c;break;case 3:c=y(b);a.c=c;break;case 4:c=C(b);a.f=c;break;default:x(b)}};function Xd(){this.a=null}Xd.prototype.getExtension=function(){return null};function Yd(a,b){for(;u(b);)switch(b.a){case 1:a.a=C(b);break;default:x(b)}};function Zd(){this.g=this.h=this.ya=this.za=this.v=this.ga=this.fa=this.B=this.b=this.l=this.Fa=this.f=this.X=this.o=this.M=this.A=this.Y=this.wa=this.va=this.Ba=this.$=this.C=this.D=this.F=this.G=this.ia=this.sa=this.ma=this.c=this.L=this.Ea=this.ha=this.Aa=this.oa=this.w=this.pa=this.na=this.m=this.ua=this.la=this.j=this.s=this.N=this.I=this.O=this.qa=this.ca=this.da=this.W=this.ea=this.ka=this.K=this.Z=this.T=this.aa=this.J=this.P=this.ba=this.R=this.ra=this.ta=this.Ca=this.a=this.i=this.ja=this.u= +this.H=this.Da=null}function $d(){this.a=this.c=this.b=null}function ae(){this.c=this.f=this.a=this.b=this.g=null}function be(){this.b=this.g=this.a=this.f=this.m=this.l=this.j=this.c=this.i=this.h=null}function ce(){this.a=null}function de(){this.a=this.b=null}function ee(){this.b=this.a=this.c=null}function fe(){this.c=this.g=this.b=this.a=this.h=this.f=null}function ge(){this.b=this.f=this.c=this.a=null}function he(){this.f=this.c=this.b=this.a=this.g=null} +function ie(){this.c=this.f=this.h=this.g=this.i=this.j=this.a=this.m=this.l=this.b=this.o=null}function je(){this.a=this.b=null}function ke(){this.a=this.c=this.b=null}function le(){this.b=this.c=this.a=null}function me(){this.b=this.a=null}function ne(){this.a=this.b=this.g=this.f=this.c=null} +function oe(a,b){for(;u(b);)switch(b.a){case 1:var c=C(b);a.Da=c;break;case 2:c=A(b);a.H=c;break;case 3:c=new $d;G(b,c,pe);a.u=c;break;case 4:c=A(b);a.ja=c;break;case 5:c=new be;G(b,c,qe);a.i=c;break;case 6:c=new be;G(b,c,qe);a.a=a.a||[];a.a.push(c);break;case 7:c=z(b);a.Ca=c;break;case 8:c=B(b);a.ta=c;break;case 9:c=B(b);a.ra=c;break;case 10:c=B(b);a.R=c;break;case 11:c=B(b);a.ba=c;break;case 12:c=B(b);a.P=c;break;case 13:c=B(b);a.J=c;break;case 14:c=B(b);a.aa=c;break;case 15:c=B(b);a.T=c;break; +case 16:c=B(b);a.Z=c;break;case 17:c=B(b);a.K=c;break;case 18:c=B(b);a.ka=c;break;case 19:c=B(b);a.ea=c;break;case 20:c=B(b);a.W=c;break;case 21:c=A(b);a.da=c;break;case 22:c=B(b);a.ca=c;break;case 23:c=C(b);a.qa=c;break;case 24:c=B(b);a.O=c;break;case 25:c=B(b);a.I=c;break;case 26:c=A(b);a.N=c;break;case 27:c=new fe;G(b,c,re);a.s=c;break;case 28:c=new ee;G(b,c,se);a.j=c;break;case 29:c=C(b);a.la=c;break;case 30:c=C(b);a.ua=c;break;case 31:c=C(b);a.m=a.m||[];a.m.push(c);break;case 32:c=B(b);a.na= +c;break;case 33:c=A(b);a.pa=c;break;case 34:c=B(b);a.w=c;break;case 35:c=B(b);a.oa=c;break;case 36:c=B(b);a.Aa=c;break;case 37:c=B(b);a.ha=c;break;case 38:c=z(b);a.Ea=c;break;case 39:c=C(b);a.L=c;break;case 40:c=new be;G(b,c,qe);a.c=a.c||[];a.c.push(c);break;case 41:c=A(b);a.ma=c;break;case 42:c=A(b);a.sa=c;break;case 43:c=z(b);a.ia=c;break;case 44:c=B(b);a.G=c;break;case 45:c=B(b);a.F=c;break;case 46:c=B(b);a.D=c;break;case 47:c=B(b);a.C=c;break;case 48:c=B(b);a.$=c;break;case 49:c=B(b);a.Ba=c;break; +case 50:c=B(b);a.va=c;break;case 51:c=B(b);a.wa=c;break;case 52:c=B(b);a.Y=c;break;case 53:c=B(b);a.A=c;break;case 54:c=B(b);a.M=c;break;case 55:c=new ie;G(b,c,te);a.o=c;break;case 56:c=B(b);a.X=c;break;case 57:c=new le;G(b,c,ue);a.f=a.f||[];a.f.push(c);break;case 58:c=B(b);a.Fa=c;break;case 59:c=new je;G(b,c,ve);a.l=c;break;case 60:c=new ke;G(b,c,we);a.b=a.b||[];a.b.push(c);break;case 62:c=B(b);a.B=c;break;case 63:c=B(b);a.fa=c;break;case 64:c=B(b);a.ga=c;break;case 65:c=new me;G(b,c,xe);a.v=c;break; +case 66:c=B(b);a.za=c;break;case 67:c=B(b);a.ya=c;break;case 68:c=new ne;G(b,c,ye);a.h=c;break;case 69:c=new de;G(b,c,ze);a.g=a.g||[];a.g.push(c);break;default:x(b)}} +function Ae(a,b){Be(a);a.Da=b.Da;a.H=b.H;a.u=b.u?Ce(b.u):null;a.ja=b.ja;a.i=b.i?De(b.i):null;a.a=J(b.a,Ee);a.Ca=b.Ca;a.ta=b.ta;a.ra=b.ra;a.R=b.R;a.ba=b.ba;a.P=b.P;a.J=b.J;a.aa=b.aa;a.T=b.T;a.Z=b.Z;a.K=b.K;a.ka=b.ka;a.ea=b.ea;a.W=b.W;a.da=b.da;a.ca=b.ca;a.qa=b.qa;a.O=b.O;a.I=b.I;a.N=b.N;a.s=b.s?Fe(b.s):null;a.j=b.j?Ge(b.j):null;a.la=b.la;a.ua=b.ua;a.m=I(b.m);a.na=b.na;a.pa=b.pa;a.w=b.w;a.oa=b.oa;a.Aa=b.Aa;a.ha=b.ha;a.Ea=b.Ea;a.L=b.L;a.c=J(b.c,Ee);a.ma=b.ma;a.sa=b.sa;a.ia=b.ia;a.G=b.G;a.F=b.F;a.D=b.D; +a.C=b.C;a.$=b.$;a.Ba=b.Ba;a.va=b.va;a.wa=b.wa;a.Y=b.Y;a.A=b.A;a.M=b.M;a.o=b.o?He(b.o):null;a.X=b.X;a.f=J(b.f,Ie);a.Fa=b.Fa;a.l=b.l?Je(b.l):null;a.b=J(b.b,Ke);a.B=b.B;a.fa=b.fa;a.ga=b.ga;a.v=b.v?Le(b.v):null;a.za=b.za;a.ya=b.ya;a.h=b.h?Me(b.h):null;a.g=J(b.g,Ne)} +function Be(a){a.Da=null;a.H=null;Oe(a.u);a.u=null;a.ja=null;Pe(a.i);a.i=null;if(a.a)for(var b=0;b<a.a.length;b++)Pe(a.a[b]);a.a=null;a.Ca=null;a.ta=null;a.ra=null;a.R=null;a.ba=null;a.P=null;a.J=null;a.aa=null;a.T=null;a.Z=null;a.K=null;a.ka=null;a.ea=null;a.W=null;a.da=null;a.ca=null;a.qa=null;a.O=null;a.I=null;a.N=null;Qe(a.s);a.s=null;Re(a.j);a.j=null;a.la=null;a.ua=null;a.m=null;a.na=null;a.pa=null;a.w=null;a.oa=null;a.Aa=null;a.ha=null;a.Ea=null;a.L=null;if(a.c)for(b=0;b<a.c.length;b++)Pe(a.c[b]); +a.c=null;a.ma=null;a.sa=null;a.ia=null;a.G=null;a.F=null;a.D=null;a.C=null;a.$=null;a.Ba=null;a.va=null;a.wa=null;a.Y=null;a.A=null;a.M=null;Se(a.o);a.o=null;a.X=null;if(a.f)for(b=0;b<a.f.length;b++)Te(a.f[b]);a.f=null;a.Fa=null;Ue(a.l);a.l=null;if(a.b)for(b=0;b<a.b.length;b++)Ve(a.b[b]);a.b=null;a.B=null;a.fa=null;a.ga=null;We(a.v);a.v=null;a.za=null;a.ya=null;Xe(a.h);a.h=null;if(a.g)for(b=0;b<a.g.length;b++)Ye(a.g[b]);a.g=null}Zd.prototype.getExtension=function(){return null}; +function Ze(a,b){oe(a,b)}function Ce(a){var b=new $d;b.b=null;b.c=null;b.a=null;b.b=a.b;b.c=a.c;b.a=a.a;return b}$d.prototype.getExtension=function(){return null};function Oe(a){a&&(a.b=null,a.c=null,a.a=null)}function pe(a,b){for(;u(b);)switch(b.a){case 1:var c=A(b);a.b=c;break;case 2:c=z(b);a.c=c;break;case 3:c=y(b);a.a=c;break;default:x(b)}}function $e(a){a.g=null;a.b=null;a.a=null;a.f=null;a.c=null}ae.prototype.getExtension=function(){return null}; +function af(a,b){for(;u(b);)switch(b.a){case 1:var c=Nc(b.b);a.g=c;break;case 2:c=B(b);a.b=c;break;case 3:c=B(b);a.a=c;break;case 4:c=B(b);a.f=c;break;case 5:c=B(b);a.c=c;break;default:x(b)}}function De(a){var b=new be;bf(b);b.h=a.h;b.i=a.i;b.c=I(a.c);b.j=a.j;b.l=a.l;b.m=a.m;b.f=a.f;b.a=J(a.a,cf);b.g=a.g;if(a.b){var c=new ae;a=a.b;$e(c);c.g=a.g;c.b=a.b;c.a=a.a;c.f=a.f;c.c=a.c}else c=null;b.b=c;return b} +function bf(a){a.h=null;a.i=null;a.c=null;a.j=null;a.l=null;a.m=null;a.f=null;if(a.a)for(var b=0;b<a.a.length;b++){var c=a.a[b];c&&(c.a=null)}a.a=null;a.g=null;(b=a.b)&&$e(b);a.b=null}be.prototype.getExtension=function(){return null};function Pe(a){a&&bf(a)}function Ee(a){return null===a?null:De(a)} +function qe(a,b){for(;u(b);)switch(b.a){case 1:var c=y(b);a.h=c;break;case 2:c=B(b);a.i=c;break;case 3:c=B(b);a.c=a.c||[];a.c.push(c);break;case 4:c=y(b);a.j=c;break;case 5:c=C(b);a.l=c;break;case 6:c=y(b);a.m=c;break;case 7:c=y(b);a.f=c;break;case 8:c=new ce;G(b,c,df);a.a=a.a||[];a.a.push(c);break;case 9:c=C(b);a.g=c;break;case 10:c=new ae;G(b,c,af);a.b=c;break;default:x(b)}} +function ef(a,b){if(a===b)b=!0;else if(null===a||null===b)b=!1;else{var c;if(c=a.h===b.h&&a.i===b.i&&L(a.c,b.c)&&a.j===b.j&&a.l===b.l&&a.m===b.m&&a.f===b.f&&M(a.a,b.a,ff)&&a.g===b.g)a=a.b,b=b.b,c=a===b?!0:null===a||null===b?!1:a.g!==b.g||a.b!==b.b||a.a!==b.a||a.f!==b.f||a.c!==b.c?!1:!0;b=c?!0:!1}return b}ce.prototype.getExtension=function(){return null};function cf(a){if(null===a)a=null;else{var b=new ce;b.a=null;b.a=a.a;a=b}return a} +function df(a,b){for(;u(b);)switch(b.a){case 1:a.a=C(b);break;default:x(b)}}function ff(a,b){return a===b?!0:null===a||null===b?!1:a.a!==b.a?!1:!0}function gf(a){a.b=null;if(a.a)for(var b=0;b<a.a.length;b++)Pe(a.a[b]);a.a=null}de.prototype.getExtension=function(){return null};function Ye(a){a&&gf(a)}function Ne(a){if(null===a)a=null;else{var b=new de;gf(b);b.b=a.b;b.a=J(a.a,Ee);a=b}return a} +function ze(a,b){for(;u(b);)switch(b.a){case 1:var c=A(b);a.b=c;break;case 2:c=new be;G(b,c,qe);a.a=a.a||[];a.a.push(c);break;default:x(b)}}function hf(a,b){return a===b?!0:null===a||null===b?!1:a.b===b.b&&M(a.a,b.a,ef)?!0:!1}function Ge(a){var b=new ee;b.c=null;b.a=null;b.b=null;b.c=a.c;b.a=a.a;b.b=a.b;return b}ee.prototype.getExtension=function(){return null};function Re(a){a&&(a.c=null,a.a=null,a.b=null)} +function se(a,b){for(;u(b);)switch(b.a){case 1:var c=z(b);a.c=c;break;case 2:c=z(b);a.a=c;break;case 3:c=z(b);a.b=c;break;default:x(b)}}function Fe(a){var b=new fe;jf(b);b.f=a.f;b.h=a.h;b.a=a.a;b.b=a.b;b.g=a.g;b.c=a.c;return b}function jf(a){a.f=null;a.h=null;a.a=null;a.b=null;a.g=null;a.c=null}fe.prototype.getExtension=function(){return null};function Qe(a){a&&jf(a)} +function re(a,b){for(;u(b);)switch(b.a){case 1:var c=z(b);a.f=c;break;case 2:c=B(b);a.h=c;break;case 3:c=B(b);a.a=c;break;case 4:c=B(b);a.b=c;break;case 5:c=B(b);a.g=c;break;case 6:c=B(b);a.c=c;break;default:x(b)}}function kf(a){a.a=null;a.c=null;a.f=null;a.b=null}ge.prototype.getExtension=function(){return null};function lf(a,b){for(;u(b);)switch(b.a){case 1:var c=B(b);a.a=c;break;case 2:c=B(b);a.c=c;break;case 3:c=B(b);a.f=c;break;case 4:c=A(b);a.b=c;break;default:x(b)}} +function mf(a){a.g=null;a.a=null;a.b=null;a.c=null;a.f=null}he.prototype.getExtension=function(){return null};function nf(a){if(null===a)a=null;else{var b=new he;mf(b);b.g=a.g;b.a=a.a;b.b=a.b;b.c=a.c;b.f=a.f;a=b}return a}function of(a,b){for(;u(b);)switch(b.a){case 1:var c=z(b);a.g=c;break;case 2:c=z(b);a.a=c;break;case 3:c=z(b);a.b=c;break;case 4:c=B(b);a.c=c;break;case 5:c=B(b);a.f=c;break;default:x(b)}} +function pf(a,b){return a===b?!0:null===a||null===b?!1:a.g!==b.g||a.a!==b.a||a.b!==b.b||a.c!==b.c||a.f!==b.f?!1:!0}function He(a){var b=new ie;qf(b);b.o=a.o;if(a.b){var c=new ge;var d=a.b;kf(c);c.a=d.a;c.c=d.c;c.f=d.f;c.b=d.b}else c=null;b.b=c;b.l=a.l;b.m=a.m;b.a=J(a.a,nf);b.j=a.j;b.i=a.i;b.g=a.g;b.h=a.h;b.f=a.f;b.c=a.c;return b} +function qf(a){a.o=null;var b=a.b;b&&kf(b);a.b=null;a.l=null;a.m=null;if(a.a)for(b=0;b<a.a.length;b++){var c=a.a[b];c&&mf(c)}a.a=null;a.j=null;a.i=null;a.g=null;a.h=null;a.f=null;a.c=null}ie.prototype.getExtension=function(){return null};function Se(a){a&&qf(a)} +function te(a,b){for(;u(b);)switch(b.a){case 1:var c=y(b);a.o=c;break;case 2:c=new ge;G(b,c,lf);a.b=c;break;case 3:c=z(b);a.l=c;break;case 4:c=y(b);a.m=c;break;case 5:c=new he;G(b,c,of);a.a=a.a||[];a.a.push(c);break;case 6:c=y(b);a.j=c;break;case 7:c=y(b);a.i=c;break;case 8:c=y(b);a.g=c;break;case 9:c=y(b);a.h=c;break;case 10:c=y(b);a.f=c;break;case 11:c=y(b);a.c=c;break;default:x(b)}} +function rf(a,b){if(a===b)a=!0;else if(null===a||null===b)a=!1;else{var c;if(c=a.o===b.o){c=a.b;var d=b.b;c=c===d?!0:null===c||null===d?!1:c.a!==d.a||c.c!==d.c||c.f!==d.f||c.b!==d.b?!1:!0}a=c&&a.l===b.l&&a.m===b.m&&M(a.a,b.a,pf)&&a.j===b.j&&a.i===b.i&&a.g===b.g&&a.h===b.h&&a.f===b.f&&a.c===b.c?!0:!1}return a}function Je(a){var b=new je;b.b=null;b.a=null;b.b=a.b;b.a=a.a;return b}je.prototype.getExtension=function(){return null};function Ue(a){a&&(a.b=null,a.a=null)} +function ve(a,b){for(;u(b);)switch(b.a){case 1:var c=B(b);a.b=c;break;case 2:c=B(b);a.a=c;break;default:x(b)}}ke.prototype.getExtension=function(){return null};function Ve(a){a&&(a.b=null,a.c=null,a.a=null)}function Ke(a){if(null===a)a=null;else{var b=new ke;b.b=null;b.c=null;b.a=null;b.b=a.b;b.c=a.c;b.a=a.a;a=b}return a}function we(a,b){for(;u(b);)switch(b.a){case 1:var c=C(b);a.b=c;break;case 2:c=A(b);a.c=c;break;case 3:c=y(b);a.a=c;break;default:x(b)}} +function sf(a,b){return a===b?!0:null===a||null===b?!1:a.b!==b.b||a.c!==b.c||a.a!==b.a?!1:!0}le.prototype.getExtension=function(){return null};function Te(a){a&&(a.a=null,a.c=null,a.b=null)}function Ie(a){if(null===a)a=null;else{var b=new le;b.a=null;b.c=null;b.b=null;b.a=I(a.a);b.c=a.c;b.b=a.b;a=b}return a}function ue(a,b){for(;u(b);)switch(b.a){case 1:var c=B(b);a.a=a.a||[];a.a.push(c);break;case 2:c=B(b);a.c=c;break;case 3:c=y(b);a.b=c;break;default:x(b)}} +function tf(a,b){return a===b?!0:null===a||null===b?!1:L(a.a,b.a)&&a.c===b.c&&a.b===b.b?!0:!1}function Le(a){var b=new me;b.a=null;b.b=null;b.a=a.a;b.b=a.b;return b}me.prototype.getExtension=function(){return null};function We(a){a&&(a.a=null,a.b=null)}function xe(a,b){for(;u(b);)switch(b.a){case 1:var c=y(b);a.a=c;break;case 2:c=y(b);a.b=c;break;default:x(b)}}function Me(a){var b=new ne;uf(b);b.c=a.c;b.f=a.f;b.g=a.g;b.b=a.b;b.a=a.a;return b} +function uf(a){a.c=null;a.f=null;a.g=null;a.b=null;a.a=null}ne.prototype.getExtension=function(){return null};function Xe(a){a&&uf(a)}function ye(a,b){for(;u(b);)switch(b.a){case 1:var c=B(b);a.c=c;break;case 2:c=B(b);a.f=c;break;case 3:c=B(b);a.g=c;break;case 4:c=B(b);a.b=c;break;case 5:c=B(b);a.a=c;break;default:x(b)}};function vf(){this.b=this.a=null}vf.prototype.getExtension=function(){return null};function wf(a,b){for(;u(b);)switch(b.a){case 1:var c=y(b);a.a=a.a||[];a.a.push(c);break;case 2:c=y(b);a.b=c;break;default:x(b)}};function xf(){this.b=this.u=this.a=this.l=this.h=this.c=this.m=this.i=this.j=this.g=this.f=this.s=this.o=null}function yf(a){var b=new xf;zf(b);b.o=a.o;b.s=a.s;b.f=a.f;b.g=a.g;b.j=a.j;b.i=a.i;b.m=a.m;b.c=a.c;b.h=a.h;b.l=a.l;b.a=a.a?Qd(a.a):null;b.u=a.u;if(a.b){var c=new vf;a=a.b;c.a=null;c.b=null;c.a=I(a.a);c.b=a.b}else c=null;b.b=c;return b} +function zf(a){a.o=null;a.s=null;a.f=null;a.g=null;a.j=null;a.i=null;a.m=null;a.c=null;a.h=null;a.l=null;var b=a.a;b&&Rd(b);a.a=null;a.u=null;if(b=a.b)b.a=null,b.b=null;a.b=null}xf.prototype.getExtension=function(){return null}; +function Af(a,b){for(;u(b);)switch(b.a){case 1:var c=y(b);a.o=c;break;case 2:c=y(b);a.s=c;break;case 5:c=y(b);a.f=c;break;case 6:c=y(b);a.g=c;break;case 7:c=y(b);a.j=c;break;case 8:c=y(b);a.i=c;break;case 9:c=y(b);a.m=c;break;case 10:c=z(b);a.c=c;break;case 11:c=y(b);a.h=c;break;case 12:c=D(b);a.l=c;break;case 13:c=new Ld;G(b,c,Sd);a.a=c;break;case 14:c=y(b);a.u=c;break;case 15:c=new vf;G(b,c,wf);a.b=c;break;default:x(b)}} +function Bf(a,b){if(a===b)b=!0;else if(null===a||null===b)b=!1;else{var c;if(c=a.o===b.o&&a.s===b.s&&a.f===b.f&&a.g===b.g&&a.j===b.j&&a.i===b.i&&a.m===b.m&&a.c===b.c&&a.h===b.h&&a.l===b.l&&Td(a.a,b.a)&&a.u===b.u)a=a.b,b=b.b,c=a===b?!0:null===a||null===b?!1:L(a.a,b.a)&&a.b===b.b?!0:!1;b=c?!0:!1}return b};function Cf(){this.g=this.f=this.a=this.c=this.b=null}function Df(a){var b=a.b;b&&Nd(b);a.b=null;(b=a.c)&&zf(b);a.c=null;(b=a.a)&&Rd(b);a.a=null;a.f=null;a.g=null}Cf.prototype.getExtension=function(){return null};function Ef(a,b){for(;u(b);)switch(b.a){case 1:var c=new Kd;G(b,c,Od);a.b=c;break;case 2:c=new xf;G(b,c,Af);a.c=c;break;case 3:c=new Ld;G(b,c,Sd);a.a=c;break;case 4:c=A(b);a.f=c;break;case 5:c=A(b);a.g=c;break;default:x(b)}};function Ff(){this.a=null}function Gf(a){var b=a.a;b&&Df(b);a.a=null}Ff.prototype.getExtension=function(){return null};function Hf(a,b){for(;u(b);)switch(b.a){case 1:var c=new Cf;G(b,c,Ef);a.a=c;break;default:x(b)}};function If(){this.a=this.g=this.h=this.c=this.f=this.j=this.o=this.l=this.b=this.i=this.m=null}function Jf(a){a.m=null;a.i=null;a.b=null;a.l=null;a.o=null;a.j=null;var b=a.f;b&&Vd(b);a.f=null;(b=a.c)&&Gf(b);a.c=null;a.h=null;a.g=null;if(a.a)for(b=0;b<a.a.length;b++)Yc(a.a[b]);a.a=null}var Kf=[]; +If.prototype.getExtension=function(a){var b=!1;67<=a&&68>a&&(b=!0);259<=a&&260>a&&(b=!0);270<=a&&271>a&&(b=!0);271<=a&&272>a&&(b=!0);278<=a&&279>a&&(b=!0);234<=a&&235>a&&(b=!0);291<=a&&292>a&&(b=!0);292<=a&&293>a&&(b=!0);294<=a&&295>a&&(b=!0);296<=a&&297>a&&(b=!0);302<=a&&303>a&&(b=!0);304<=a&&305>a&&(b=!0);312<=a&&313>a&&(b=!0);313<=a&&314>a&&(b=!0);317<=a&&318>a&&(b=!0);319<=a&&320>a&&(b=!0);338<=a&&339>a&&(b=!0);355<=a&&356>a&&(b=!0);356<=a&&357>a&&(b=!0);363<=a&&364>a&&(b=!0);368<=a&&369>a&&(b= +!0);return b?P(this.a,a):null};function Lf(a){if(null===a)a=null;else{var b=new If;Jf(b);b.m=a.m;b.i=a.i;b.b=I(a.b);b.l=a.l;b.o=a.o;b.j=a.j;if(a.f){var c=new Ud;var d=a.f;Vd(c);c.b=d.b?Md(d.b):null;c.a=d.a?Qd(d.a):null;c.c=d.c;c.f=d.f}else c=null;b.f=c;if(a.c){c=new Ff;var e=a.c;Gf(c);e.a?(d=new Cf,e=e.a,Df(d),d.b=e.b?Md(e.b):null,d.c=e.c?yf(e.c):null,d.a=e.a?Qd(e.a):null,d.f=e.f,d.g=e.g):d=null;c.a=d}else c=null;b.c=c;b.h=I(a.h);b.g=I(a.g);b.a=Zc(a.a);a=b}return a} +function Mf(a,b){for(;u(b);)switch(b.a){case 1:var c=y(b);a.m=c;break;case 3:c=y(b);a.i=c;break;case 4:c=y(b);a.b=a.b||[];a.b.push(c);break;case 5:c=A(b);a.l=c;break;case 6:c=C(b);a.o=c;break;case 7:c=y(b);a.j=c;break;case 11:c=new Ud;G(b,c,Wd);a.f=c;break;case 232:c=new Ff;G(b,c,Hf);a.c=c;break;case 260:c=A(b);a.h=a.h||[];a.h.push(c);break;case 330:c=y(b);a.g=a.g||[];a.g.push(c);break;default:a.a=a.a||[],c=Q(b,Kf),a.a.push(c)}} +function Nf(a,b){if(a===b)a=!0;else if(null===a||null===b)a=!1;else{var c;if(c=a.m===b.m&&a.i===b.i&&L(a.b,b.b)&&a.l===b.l&&a.o===b.o&&a.j===b.j){c=a.f;var d=b.f;c=c===d?!0:null===c||null===d?!1:Pd(c.b,d.b)&&Td(c.a,d.a)&&c.c===d.c&&c.f===d.f?!0:!1}c&&(d=a.c,c=b.c,d===c?c=!0:null===d||null===c?c=!1:(d=d.a,c=c.a,c=d===c||(null===d||null===c?0:Pd(d.b,c.b)&&Bf(d.c,c.c)&&Td(d.a,c.a)&&d.f===c.f&&d.g===c.g)?!0:!1));a=c&&L(a.h,b.h)&&L(a.g,b.g)&&ad(a.a,b.a)?!0:!1}return a};function Of(){this.f=this.c=this.b=this.a=null}function Pf(){this.b=this.c=this.a=null}function Qf(){this.b=this.c=this.a=null}function Rf(){this.a=this.b=null}function Sf(a){var b=new Of;Tf(b);if(a.a){var c=a.a;var d=new Pf;d.a=null;d.c=null;d.b=null;d.a=c.a;d.c=c.c;d.b=c.b;c=d}else c=null;b.a=c;a.b?(c=a.b,d=new Qf,d.a=null,d.c=null,d.b=null,d.a=c.a,d.c=c.c,d.b=c.b,c=d):c=null;b.b=c;a.c?(c=a.c,d=new Rf,d.b=null,d.a=null,d.b=c.b,d.a=c.a,c=d):c=null;b.c=c;b.f=a.f;return b} +function Tf(a){var b=a.a;b&&(b.a=null,b.c=null,b.b=null);a.a=null;if(b=a.b)b.a=null,b.c=null,b.b=null;a.b=null;if(b=a.c)b.b=null,b.a=null;a.c=null;a.f=null}Of.prototype.getExtension=function(){return null};function Uf(a,b){for(;u(b);)switch(b.a){case 1:var c=new Pf;G(b,c,Vf);a.a=c;break;case 2:c=new Qf;G(b,c,Wf);a.b=c;break;case 3:c=new Rf;G(b,c,Xf);a.c=c;break;case 4:c=Mc(b.b);a.f=c;break;default:x(b)}} +function Yf(a,b){if(a===b)a=!0;else if(null===a||null===b)a=!1;else{var c=a.a,d=b.a;if(c=c===d?!0:null===c||null===d?!1:c.a!==d.a||c.c!==d.c||c.b!==d.b?!1:!0)c=a.b,d=b.b,c=c===d?!0:null===c||null===d?!1:c.a!==d.a||c.c!==d.c||c.b!==d.b?!1:!0;c&&(c=a.c,d=b.c,c=c===d?!0:null===c||null===d?!1:c.b!==d.b||c.a!==d.a?!1:!0);a=c&&a.f===b.f?!0:!1}return a}Pf.prototype.getExtension=function(){return null}; +function Vf(a,b){for(;u(b);)switch(b.a){case 1:var c=Nc(b.b);a.a=c;break;case 2:c=Nc(b.b);a.c=c;break;case 3:c=Nc(b.b);a.b=c;break;default:x(b)}}Qf.prototype.getExtension=function(){return null};function Wf(a,b){for(;u(b);)switch(b.a){case 1:var c=Mc(b.b);a.a=c;break;case 2:c=Mc(b.b);a.c=c;break;case 3:c=Mc(b.b);a.b=c;break;default:x(b)}}Rf.prototype.getExtension=function(){return null};function Xf(a,b){for(;u(b);)switch(b.a){case 1:var c=y(b);a.b=c;break;case 2:c=y(b);a.a=c;break;default:x(b)}};function Zf(){this.b=this.a=null}function $f(){this.b=this.a=null}function ag(){this.a=this.b=null}function bg(a){var b=new Zf;cg(b);b.a=a.a;b.b=a.b;return b}function cg(a){a.a=null;a.b=null}Zf.prototype.getExtension=function(){return null};function dg(a,b){for(;u(b);)switch(b.a){case 3:var c=Nc(b.b);a.a=c;break;case 4:c=Nc(b.b);a.b=c;break;default:x(b)}}function eg(a,b){return a===b?!0:null===a||null===b?!1:a.a!==b.a||a.b!==b.b?!1:!0} +function fg(a){var b=new $f;b.a=null;b.b=null;b.a=a.a;b.b=a.b;return b}$f.prototype.getExtension=function(){return null};function gg(a,b){for(;u(b);)switch(b.a){case 1:var c=y(b);a.a=c;break;case 2:c=y(b);a.b=c;break;default:x(b)}}function hg(a,b){return a===b?!0:null===a||null===b?!1:a.a!==b.a||a.b!==b.b?!1:!0}function ig(a){var b=a.b;b&&(b.a=null,b.b=null);a.b=null;if(b=a.a)b.a=null,b.b=null;a.a=null}ag.prototype.getExtension=function(){return null}; +function jg(a){if(null===a)a=null;else{var b=new ag;ig(b);b.b=a.b?fg(a.b):null;b.a=a.a?fg(a.a):null;a=b}return a}function kg(a,b){for(;u(b);)switch(b.a){case 1:var c=new $f;G(b,c,gg);a.b=c;break;case 2:c=new $f;G(b,c,gg);a.a=c;break;default:x(b)}}function lg(a,b){return a===b?!0:null===a||null===b?!1:hg(a.b,b.b)&&hg(a.a,b.a)?!0:!1};function mg(){this.v=this.u=this.f=this.a=this.o=this.l=this.h=this.j=this.i=this.g=this.b=this.c=this.s=this.m=null}function ng(a){var b=new mg;og(b);b.m=a.m;b.s=a.s;b.c=a.c?Sf(a.c):null;b.b=a.b?bg(a.b):null;b.g=a.g;b.i=a.i;b.j=a.j;b.h=a.h;b.l=a.l;b.o=a.o;b.a=a.a?new Uint8Array(a.a):null;b.f=a.f;b.u=a.u;b.v=a.v;return b}function og(a){a.m=null;a.s=null;var b=a.c;b&&Tf(b);a.c=null;(b=a.b)&&cg(b);a.b=null;a.g=null;a.i=null;a.j=null;a.h=null;a.l=null;a.o=null;a.a=null;a.f=null;a.u=null} +mg.prototype.getExtension=function(){return null};function pg(a,b){for(a.v=b.b.b;u(b);)switch(b.a){case 1:var c=A(b);a.m=c;break;case 2:c=A(b);a.s=c;break;case 3:c=new Of;G(b,c,Uf);a.c=c;break;case 4:c=new Zf;G(b,c,dg);a.b=c;break;case 5:c=C(b);a.g=c;break;case 6:c=z(b);a.i=c;break;case 7:c=z(b);a.j=c;break;case 9:c=C(b);a.h=c;break;case 10:c=y(b);a.l=c;break;case 11:c=A(b);a.o=c;break;case 12:null===a.f&&(a.f=b.c);w(b);a.u=b.b.a;break;default:x(b)}} +function qg(a,b){a===b?a=!0:null===a||null===b?a=!1:a.m===b.m&&a.s===b.s&&Yf(a.c,b.c)&&eg(a.b,b.b)&&a.g===b.g&&a.i===b.i&&a.j===b.j&&a.h===b.h&&a.l===b.l&&a.o===b.o?(null!=a.f&&null==a.a&&(a.a=cd(a.v,a.f,a.u)),a=L(a.a,b.a)?!0:!1):a=!1;return a};function rg(){this.c=this.h=this.b=this.i=this.f=this.a=this.g=null}function sg(){this.h=this.b=this.c=this.i=this.g=this.a=this.f=null}function tg(){this.a=this.b=null}function ug(){this.b=this.a=null}function vg(){this.c=this.a=this.f=this.b=null}function wg(){this.a=null}rg.prototype.getExtension=function(){return null};function xg(){return new rg} +function yg(a){if(null===a)var b=null;else{b=new rg;b.g=null;if(b.a)for(var c=0;c<b.a.length;c++){var d=b.a[c];d&&zg(d)}b.a=null;b.f=null;b.i=null;(c=b.b)&&Ed(c);b.b=null;b.h=null;(c=b.c)&&Ag(c);b.c=null;b.g=a.g;b.a=J(a.a,Bg);b.f=a.f;b.i=a.i;b.b=a.b?Dd(a.b):null;b.h=a.h;a.c?(a=a.c,c=new wg,Ag(c),c.a=a.a?Cg(a.a):null,a=c):a=null;b.c=a}return b}function Dg(){} +function Eg(a,b){for(;u(b);)switch(b.a){case 1:var c=A(b);a.g=c;break;case 2:c=new sg;G(b,c,Fg);a.a=a.a||[];a.a.push(c);break;case 3:c=y(b);a.f=c;break;case 4:c=z(b);a.i=c;break;case 5:c=new Cd;G(b,c,Fd);a.b=c;break;case 6:c=y(b);a.h=c;break;case 7:c=new wg;G(b,c,Gg);a.c=c;break;default:x(b)}} +function Hg(a,b){if(a===b)b=!0;else if(null===a||null===b)b=!1;else{var c;if(c=a.g===b.g&&M(a.a,b.a,Ig)&&a.f===b.f&&a.i===b.i&&Gd(a.b,b.b)&&a.h===b.h)a=a.c,b=b.c,c=a===b?!0:null===a||null===b?!1:Jg(a.a,b.a)?!0:!1;b=c?!0:!1}return b}function zg(a){a.f=null;a.a=null;a.g=null;a.i=null;a.c=null;var b=a.b;b&&Id(b);a.b=null;a.h=null}sg.prototype.getExtension=function(){return null}; +function Bg(a){if(null===a)a=null;else{var b=new sg;zg(b);b.f=a.f;b.a=I(a.a);b.g=a.g;b.i=a.i;b.c=a.c;if(a.b){var c=new Hd;var d=a.b;Id(c);c.b=d.b?Dd(d.b):null;c.a=d.a?Dd(d.a):null}else c=null;b.b=c;b.h=a.h;a=b}return a}function Fg(a,b){for(;u(b);)switch(b.a){case 1:var c=A(b);a.f=c;break;case 2:c=A(b);a.a=a.a||[];a.a.push(c);break;case 3:c=A(b);a.g=c;break;case 4:c=A(b);a.i=c;break;case 5:c=Kc(b.b);a.c=c;break;case 7:c=new Hd;G(b,c,Jd);a.b=c;break;case 8:c=Kc(b.b);a.h=c;break;default:x(b)}} +function Ig(a,b){if(a===b)a=!0;else if(null===a||null===b)a=!1;else{var c;if(c=a.f===b.f&&L(a.a,b.a)&&a.g===b.g&&a.i===b.i&&a.c===b.c){c=a.b;var d=b.b;c=c===d?!0:null===c||null===d?!1:Gd(c.b,d.b)&&Gd(c.a,d.a)?!0:!1}a=c&&a.h===b.h?!0:!1}return a}tg.prototype.getExtension=function(){return null};function Kg(){return new tg} +function Lg(a){if(null===a)a=null;else{var b=new tg;b.b=null;if(b.a)for(var c=0;c<b.a.length;c++){var d=b.a[c];d&&(d.a=null,d.b=null)}b.a=null;b.b=I(a.b);b.a=J(a.a,Mg);a=b}return a}function Ng(){}function Og(a,b){for(;u(b);)switch(b.a){case 1:var c=A(b);a.b=a.b||[];a.b.push(c);break;case 2:c=new ug;G(b,c,Pg);a.a=a.a||[];a.a.push(c);break;default:x(b)}}function Qg(a,b){return a===b?!0:null===a||null===b?!1:L(a.b,b.b)&&M(a.a,b.a,Rg)?!0:!1}ug.prototype.getExtension=function(){return null}; +function Mg(a){if(null===a)a=null;else{var b=new ug;b.a=null;b.b=null;b.a=a.a;b.b=a.b;a=b}return a}function Pg(a,b){for(;u(b);)switch(b.a){case 1:var c=A(b);a.a=c;break;case 2:c=Kc(b.b);a.b=c;break;default:x(b)}}function Rg(a,b){return a===b?!0:null===a||null===b?!1:a.a!==b.a||a.b!==b.b?!1:!0}function Cg(a){var b=new vg;Sg(b);b.b=a.b;b.f=a.f;b.a=a.a?ng(a.a):null;b.c=a.c;return b}function Sg(a){a.b=null;a.f=null;var b=a.a;b&&og(b);a.a=null;a.c=null}vg.prototype.getExtension=function(){return null}; +function Tg(a,b){for(;u(b);)switch(b.a){case 1:var c=A(b);a.b=c;break;case 2:c=A(b);a.f=c;break;case 3:c=new mg;G(b,c,pg);a.a=c;break;case 4:c=A(b);a.c=c;break;default:x(b)}}function Jg(a,b){return a===b?!0:null===a||null===b?!1:a.b===b.b&&a.f===b.f&&qg(a.a,b.a)&&a.c===b.c?!0:!1}function Ag(a){var b=a.a;b&&Sg(b);a.a=null}wg.prototype.getExtension=function(){return null};function Gg(a,b){for(;u(b);)switch(b.a){case 1:var c=new vg;G(b,c,Tg);a.a=c;break;default:x(b)}};function Ug(){this.a=this.b=null}function Vg(){this.a=null}function Wg(){}function Xg(){this.a=null}function Yg(){this.a=null}function Zg(){this.a=this.f=this.c=this.i=this.h=this.b=this.g=null}function $g(){this.a=this.b=null}Ug.prototype.getExtension=function(){return null};function ah(a,b){for(;u(b);)switch(b.a){case 1:null===a.b&&(a.b=b.c);w(b);break;case 2:null===a.a&&(a.a=b.c);w(b);break;case 1E3:x(b);break;case 1001:x(b);break;default:x(b)}}Vg.prototype.getExtension=function(){return null}; +function bh(a,b){for(;u(b);)switch(b.a){case 1:null===a.a&&(a.a=b.c);w(b);break;case 2:y(b);break;case 3:y(b);break;case 4:y(b);break;case 1E3:x(b);break;default:x(b)}}Wg.prototype.getExtension=function(){return null};function ch(a,b){for(;u(b);)switch(b.a){case 1:a=new Ug;G(b,a,ah);break;case 2:C(b);break;case 4:y(b);break;case 5:a=new Vg;G(b,a,bh);break;default:x(b)}}Xg.prototype.getExtension=function(){return null}; +function dh(a,b){for(;u(b);)switch(b.a){case 1:null===a.a&&(a.a=b.c);w(b);break;case 2:y(b);break;case 3:y(b);break;case 4:C(b);break;case 5:y(b);break;case 1E3:x(b);break;default:x(b)}}Yg.prototype.getExtension=function(){return null};function eh(a,b){for(;u(b);)switch(b.a){case 1:var c=new Zg;G(b,c,fh);a.a=a.a||[];a.a.push(c);break;case 2:y(b);break;case 3:E(b);break;case 4:C(b);break;case 1E3:y(b);break;default:x(b)}}var gh=[]; +Zg.prototype.getExtension=function(a){var b=!1;25E6<=a&&536870912>a&&(b=!0);return b?P(this.a,a):null}; +function fh(a,b){for(;u(b);)switch(b.a){case 1:A(b);break;case 2:y(b);break;case 3:z(b);break;case 4:E(b);break;case 6:null===a.g&&(a.g=b.c);w(b);break;case 7:null===a.b&&(a.b=b.c);w(b);break;case 8:null===a.h&&(a.h=b.c);w(b);break;case 9:null===a.i&&(a.i=b.c);w(b);break;case 10:null===a.c&&(a.c=b.c);w(b);break;case 11:null===a.f&&(a.f=b.c);w(b);break;case 1E3:y(b);break;case 1001:A(b);break;default:a.a=a.a||[];var c=Q(b,gh);a.a.push(c)}}var R=[]; +$g.prototype.getExtension=function(a){var b=!1;25E6<=a&&536870912>a&&(b=!0);return b?P(this.a,a):null}; +function hh(a,b){for(;u(b);)switch(b.a){case 1:var c=new Yg;G(b,c,eh);break;case 2:c=new Yg;G(b,c,eh);break;case 3:c=new Wg;G(b,c,ch);break;case 4:c=new Xg;G(b,c,dh);break;case 5:E(b);break;case 6:B(b);break;case 7:C(b);break;case 8:y(b);break;case 9:y(b);break;case 10:t(b.b);break;case 11:y(b);break;case 12:y(b);break;case 13:y(b);break;case 14:y(b);break;case 15:D(b);break;case 16:null===a.b&&(a.b=b.c);w(b);break;case 1E3:y(b);break;default:a.a=a.a||[],c=Q(b,R),a.a.push(c)}};function ih(){this.a=this.b=null}function jh(){this.b=this.a=null}ih.prototype.getExtension=function(){return null};function kh(a,b){for(;u(b);)switch(b.a){case 1:D(b);break;case 2:null===a.b&&(a.b=b.c);w(b);break;case 3:A(b);break;case 4:z(b);break;case 5:var c=new jh;G(b,c,lh);a.a=a.a||[];a.a.push(c);break;case 1E3:y(b);break;default:x(b)}}jh.prototype.getExtension=function(){return null}; +function lh(a,b){for(;u(b);)switch(b.a){case 1:var c=C(b);a.a=a.a||[];a.a.push(c);break;case 2:null===a.b&&(a.b=b.c);w(b);break;default:x(b)}};function mh(){this.Oa=null}mh.prototype.getExtension=function(){return null};function nh(a,b){for(;u(b);)switch(b.a){case 1:var c=y(b);a.Oa=c;break;case 2:y(b);break;case 3:y(b);break;case 4:y(b);break;default:x(b)}};function oh(){this.a=this.c=this.f=this.b=null}function ph(){this.a=this.w=this.C=this.j=this.m=this.u=this.c=this.A=this.i=this.l=this.s=this.b=this.f=this.v=this.D=this.B=this.g=this.o=this.h=null}function qh(){this.b=this.c=this.a=null}function rh(){}function sh(){this.c=this.a=this.f=this.g=this.b=null}function th(){this.a=this.b=null}function uh(){this.g=this.b=this.f=this.a=this.c=null}function vh(){this.a=null}function wh(){this.a=null}function xh(){this.a=null}function yh(){} +function zh(){this.Ra=this.a=this.Sa=this.Ka=this.Na=null}function Ah(){this.a=null}function Bh(){}function Ch(){this.a=this.b=null}function Dh(){this.a=null}function Eh(){}function Fh(){this.a=null}function Gh(){this.a=null}function Hh(){this.a=null}function Ih(){this.a=null}function Jh(){this.a=null}function Kh(){this.a=null}function Lh(){}function Mh(){this.h=this.j=this.b=this.a=this.i=this.c=this.l=this.f=this.g=null}var Nh=[]; +oh.prototype.getExtension=function(a){var b=!1;25E6<=a&&536870912>a&&(b=!0);return b?P(this.a,a):null}; +function Oh(a,b){for(;u(b);)switch(b.a){case 1:null===a.b&&(a.b=b.c);w(b);break;case 2:null===a.f&&(a.f=b.c);w(b);break;case 3:y(b);break;case 4:y(b);break;case 5:t(b.b);break;case 6:C(b);break;case 7:y(b);break;case 8:C(b);break;case 9:B(b);break;case 10:y(b);break;case 11:E(b);break;case 12:null===a.c&&(a.c=b.c);w(b);break;case 13:y(b);break;case 14:y(b);break;case 15:C(b);break;case 1001:y(b);break;case 1E3:x(b);break;default:a.a=a.a||[];var c=Q(b,Nh);a.a.push(c)}}ph.prototype.getExtension=function(){return null}; +function Ph(a,b){for(a.a=b.b.b;u(b);)switch(b.a){case 1:null===a.h&&(a.h=b.c);w(b);a.o=b.b.a;break;case 2:null===a.g&&(a.g=b.c);w(b);a.B=b.b.a;break;case 3:null===a.D&&(a.D=b.c);w(b);break;case 4:null===a.v&&(a.v=b.c);w(b);break;case 5:y(b);break;case 6:var c=y(b);a.f=c;break;case 7:y(b);break;case 8:null===a.b&&(a.b=b.c);w(b);a.s=b.b.a;break;case 9:null===a.i&&(a.i=b.c);w(b);a.A=b.b.a;break;case 10:null===a.c&&(a.c=b.c);w(b);a.u=b.b.a;break;case 11:null===a.j&&(a.j=b.c);w(b);a.C=b.b.a;break;case 12:null=== +a.w&&(a.w=b.c);w(b);break;case 1E3:x(b);break;case 1001:x(b);break;case 1002:x(b);break;default:x(b)}}function Qh(a){return a.a&&null!=a.h&&null!=a.o?(a=Ic(a.a,a.h,a.o-a.h),a.S(),a.S(),a):Ic()}function Rh(a){return a.a&&null!=a.b&&null!=a.s?(a=Ic(a.a,a.b,a.s-a.b),a.S(),a.S(),a):Ic()}function Sh(a){null!=a.i&&null==a.l&&(a.l=bd(a.a,a.i,a.A));return a.l}function Th(a){return a.a&&null!=a.c&&null!=a.u?(a=Ic(a.a,a.c,a.u-a.c),a.S(),a.S(),a):Ic()} +function Uh(a){null!=a.j&&null==a.m&&(a.m=bd(a.a,a.j,a.C));return a.m}var U=[];qh.prototype.getExtension=function(a){var b=!1;25E6<=a&&536870912>a&&(b=!0);return b?P(this.b,a):null}; +function Vh(a,b){for(;u(b);)switch(b.a){case 1:var c=new ph;G(b,c,Ph);a.a=c;break;case 2:z(b);break;case 3:y(b);break;case 4:y(b);break;case 5:t(b.b);break;case 6:B(b);break;case 7:c=z(b);a.c=c;break;case 8:E(b);break;case 10:D(b);break;case 11:y(b);break;case 12:y(b);break;case 13:C(b);break;case 1E3:y(b);break;default:a.b=a.b||[],c=Q(b,U),a.b.push(c)}}function Wh(a){null===a.a&&(a.a=new ph);return a.a}rh.prototype.getExtension=function(){return null}; +function Xh(a,b){for(;u(b);)switch(b.a){case 1:G(b,new ph,Ph);break;case 2:y(b);break;case 3:y(b);break;default:x(b)}}sh.prototype.getExtension=function(){return null}; +function Yh(a,b){for(;u(b);)switch(b.a){case 1:null===a.b&&(a.b=b.c);w(b);break;case 2:null===a.g&&(a.g=b.c);w(b);break;case 3:null===a.f&&(a.f=b.c);w(b);break;case 4:null===a.a&&(a.a=b.c);w(b);break;case 5:null===a.c&&(a.c=b.c);w(b);break;case 6:y(b);break;case 1E3:x(b);break;case 1001:x(b);break;case 1002:x(b);break;default:x(b)}}var Zh=[];th.prototype.getExtension=function(a){var b=!1;25E6<=a&&536870912>a&&(b=!0);return b?P(this.a,a):null}; +function $h(a,b){for(;u(b);)switch(b.a){case 1:var c=new rh;G(b,c,Xh);a.b=a.b||[];a.b.push(c);break;case 2:c=new sh;G(b,c,Yh);break;case 3:y(b);break;case 4:y(b);break;case 5:t(b.b);break;case 6:D(b);break;case 7:B(b);break;case 8:E(b);break;case 9:y(b);break;case 10:y(b);break;case 1E3:y(b);break;default:a.a=a.a||[],c=Q(b,Zh),a.a.push(c)}}var ai=[];uh.prototype.getExtension=function(a){var b=!1;25E6<=a&&536870912>a&&(b=!0);return b?P(this.b,a):null}; +function bi(a,b){for(a.g=b.b.b;u(b);)switch(b.a){case 1:null===a.a&&(a.a=b.c);w(b);a.f=b.b.a;break;case 2:B(b);break;case 3:y(b);break;case 4:y(b);break;case 5:t(b.b);break;case 6:E(b);break;case 1E3:y(b);break;default:a.b=a.b||[];var c=Q(b,ai);a.b.push(c)}}uh.prototype.getImageData=function(){null!=this.a&&null==this.c&&(this.c=cd(this.g,this.a,this.f));return this.c};vh.prototype.getExtension=function(){return null}; +function ci(a,b){for(;u(b);)switch(b.a){case 1:C(b);break;case 2:null===a.a&&(a.a=b.c);w(b);break;case 3:var c=new ph;G(b,c,Ph);break;case 4:y(b);break;case 5:y(b);break;default:x(b)}}var di=[];wh.prototype.getExtension=function(a){var b=!1;25E6<=a&&536870912>a&&(b=!0);return b?P(this.a,a):null}; +function ei(a,b){for(;u(b);)switch(b.a){case 1:G(b,new vh,ci);break;case 2:y(b);break;case 3:y(b);break;case 4:t(b.b);break;case 5:B(b);break;case 6:E(b);break;case 1E3:y(b);break;default:a.a=a.a||[];var c=Q(b,di);a.a.push(c)}}xh.prototype.getExtension=function(){return null};function fi(a,b){for(;u(b);)switch(b.a){case 1:C(b);break;case 2:null===a.a&&(a.a=b.c);w(b);break;case 3:y(b);break;case 4:y(b);break;default:x(b)}}yh.prototype.getExtension=function(){return null}; +function gi(a,b){for(;u(b);)switch(b.a){case 1:y(b);break;case 2:y(b);break;case 3:y(b);break;case 4:y(b);break;case 7:D(b);break;default:x(b)}}zh.prototype.getExtension=function(){return null};function hi(a,b){for(a.Ra=b.b.b;u(b);)switch(b.a){case 1:null===a.Ka&&(a.Ka=b.c);w(b);a.Sa=b.b.a;break;case 2:var c=new yh;G(b,c,gi);a.a=a.a||[];a.a.push(c);break;default:x(b)}}Ah.prototype.getExtension=function(){return null}; +function ii(a,b){for(;u(b);)switch(b.a){case 1:C(b);break;case 2:var c=C(b);a.a=c;break;default:x(b)}}Bh.prototype.getExtension=function(){return null};function ji(a,b){for(;u(b);)switch(b.a){case 1:y(b);break;case 2:y(b);break;case 3:y(b);break;default:x(b)}}Ch.prototype.getExtension=function(){return null};function ki(a,b){for(;u(b);)switch(b.a){case 1:A(b);break;case 2:null===a.b&&(a.b=b.c);w(b);break;case 3:var c=y(b);a.a=a.a||[];a.a.push(c);break;default:x(b)}}Dh.prototype.getExtension=function(){return null}; +function li(a,b){for(;u(b);)switch(b.a){case 1:var c=new Ch;G(b,c,ki);a.a=a.a||[];a.a.push(c);break;default:x(b)}}Eh.prototype.getExtension=function(){return null};function mi(a,b){for(;u(b);)x(b)}Fh.prototype.getExtension=function(){return null};function ni(a,b){for(;u(b);)switch(b.a){case 1:var c=new oh;G(b,c,Oh);a.a=a.a||[];a.a.push(c);break;case 2:c=new Bh;G(b,c,ji);break;default:x(b)}}Gh.prototype.getExtension=function(){return null}; +function oi(a,b){for(;u(b);)switch(b.a){case 1:var c=new qh;G(b,c,Vh);a.a=a.a||[];a.a.push(c);break;case 2:c=new Bh;G(b,c,ji);break;default:x(b)}}Hh.prototype.getExtension=function(){return null};function pi(a,b){for(;u(b);)switch(b.a){case 1:var c=new th;G(b,c,$h);a.a=a.a||[];a.a.push(c);break;case 2:c=new Bh;G(b,c,ji);break;default:x(b)}}Ih.prototype.getExtension=function(){return null}; +function qi(a,b){for(;u(b);)switch(b.a){case 1:var c=new $g;G(b,c,hh);a.a=a.a||[];a.a.push(c);break;case 2:c=new Bh;G(b,c,ji);break;default:x(b)}}Jh.prototype.getExtension=function(){return null};function ri(a,b){for(;u(b);)switch(b.a){case 1:var c=new uh;G(b,c,bi);a.a=a.a||[];a.a.push(c);break;default:x(b)}}Kh.prototype.getExtension=function(){return null}; +function si(a,b){for(;u(b);)switch(b.a){case 1:var c=new wh;G(b,c,ei);a.a=a.a||[];a.a.push(c);break;case 2:c=new Bh;G(b,c,ji);break;default:x(b)}}Lh.prototype.getExtension=function(){return null};function ti(a,b){for(;u(b);)switch(b.a){case 1:A(b);break;case 2:y(b);break;default:x(b)}} +function ui(a,b){for(;u(b);)switch(b.a){case 1:var c=new mh;G(b,c,nh);a.g=c;break;case 2:c=new Ah;G(b,c,ii);a.f=c;break;case 3:c=new ih;G(b,c,kh);a.l=a.l||[];a.l.push(c);break;case 4:c=new zh;G(b,c,hi);a.c=c;break;case 5:c=new xh;G(b,c,fi);a.i=a.i||[];a.i.push(c);break;case 6:c=new Eh;G(b,c,mi);break;case 7:c=new Fh;G(b,c,ni);break;case 8:c=new Gh;G(b,c,oi);a.a=c;break;case 9:c=new Hh;G(b,c,pi);break;case 10:c=new Ih;G(b,c,qi);break;case 11:c=new Jh;G(b,c,ri);a.b=c;break;case 12:c=new Kh;G(b,c,si); +break;case 13:c=new Dh;G(b,c,li);break;case 14:y(b);break;case 15:c=new Lh;G(b,c,ti);a.j=a.j||[];a.j.push(c);break;case 16:B(b);break;default:a.h=a.h||[],c=Q(b,vi),a.h.push(c)}}var vi=[];Mh.prototype.getExtension=function(a){var b=!1;25E6<=a&&536870912>a&&(b=!0);return b?P(this.h,a):null};function wi(a){null===a.f&&(a.f=new Ah);return a.f}function xi(a){null===a.a&&(a.a=new Gh);return a.a};function yi(){this.b=this.a=null}function zi(){this.b=this.a=null}yi.prototype.getExtension=function(){return null};zi.prototype.getExtension=function(){return null};function Ai(a,b){for(;u(b);)switch(b.a){case 1:var c=D(b);a.a=c;break;case 2:c=D(b);a.b=c;break;default:x(b)}};function Bi(){this.a=this.f=this.b=this.g=this.c=null}Bi.prototype.getExtension=function(){return null};function Ci(){this.c=this.b=this.a=null}Ci.prototype.getExtension=function(){return null};function Di(){this.a=this.f=this.h=this.c=this.b=this.g=null}Di.prototype.getExtension=function(){return null};function Ei(){this.c=this.a=this.g=this.f=this.b=null}function Fi(a){var b=new Ei;Gi(b);b.b=a.b;b.f=a.f;b.g=a.g;b.a=a.a;b.c=a.c;return b}function Gi(a){a.b=null;a.f=null;a.g=null;a.a=null;a.c=null}Ei.prototype.getExtension=function(){return null};function Hi(a,b){for(;u(b);)switch(b.a){case 1:var c=y(b);a.b=c;break;case 2:c=y(b);a.f=c;break;case 3:c=y(b);a.g=c;break;case 4:c=C(b);a.a=c;break;case 5:c=A(b);a.c=c;break;default:x(b)}} +function Ii(a,b){return a===b?!0:null===a||null===b?!1:a.b!==b.b||a.f!==b.f||a.g!==b.g||a.a!==b.a||a.c!==b.c?!1:!0};function Ji(){this.b=this.a=null}function Ki(){}Ji.prototype.getExtension=function(){return null};Ki.prototype.getExtension=function(){return null};function Li(a,b){for(;u(b);)x(b)};function Mi(){this.b=this.a=null}function Ni(a){if(a.a)for(var b=0;b<a.a.length;b++){var c=a.a[b];c&&ig(c)}a.a=null;a.b=null}Mi.prototype.getExtension=function(){return null};function Oi(a,b){for(;u(b);)switch(b.a){case 1:var c=new ag;G(b,c,kg);a.a=a.a||[];a.a.push(c);break;case 2:c=z(b);a.b=c;break;default:x(b)}};function Pi(){this.u=this.f=this.g=this.v=this.c=this.I=this.J=this.T=this.P=this.s=this.H=this.R=this.l=this.j=this.M=this.N=this.m=this.h=this.K=this.L=this.A=this.B=this.C=this.i=this.F=this.D=this.G=this.b=this.a=this.O=this.w=this.o=null} +function Qi(a,b){Ri(a);a.o=b.o;a.w=b.w;a.O=b.O;a.a=b.a;a.b=b.b;a.G=b.G;a.D=b.D;a.F=b.F;a.i=b.i;a.C=b.C;a.B=b.B;a.A=b.A;a.L=b.L;a.K=b.K;a.h=b.h;a.m=b.m;a.N=b.N;a.M=b.M;a.j=b.j;a.l=b.l;a.R=b.R;a.H=b.H;a.s=b.s;a.P=b.P;a.T=b.T;a.J=b.J;a.I=b.I;a.c=b.c;a.v=b.v;a.g=b.g;a.f=b.f;a.u=b.u} +function Ri(a){a.o=null;a.w=null;a.O=null;a.a=null;a.b=null;a.G=null;a.D=null;a.F=null;a.i=null;a.C=null;a.B=null;a.A=null;a.L=null;a.K=null;a.h=null;a.m=null;a.N=null;a.M=null;a.j=null;a.l=null;a.R=null;a.H=null;a.s=null;a.P=null;a.T=null;a.J=null;a.I=null;a.c=null;a.v=null;a.g=null;a.f=null;a.u=null}Pi.prototype.getExtension=function(){return null}; +function Si(a,b){for(;u(b);)switch(b.a){case 1:var c=z(b);a.o=c;break;case 2:c=y(b);a.w=c;break;case 3:c=y(b);a.O=c;break;case 4:c=z(b);a.a=c;break;case 7:c=y(b);a.b=c;break;case 9:c=A(b);a.G=c;break;case 17:c=z(b);a.D=c;break;case 18:c=z(b);a.F=c;break;case 20:c=y(b);a.i=c;break;case 23:c=z(b);a.C=c;break;case 24:c=y(b);a.B=c;break;case 25:c=z(b);a.A=c;break;case 26:c=y(b);a.L=c;break;case 27:c=y(b);a.K=c;break;case 28:c=Nc(b.b);a.h=c;break;case 29:c=z(b);a.m=c;break;case 32:c=y(b);a.N=c;break;case 33:c= +y(b);a.M=c;break;case 39:c=y(b);a.j=c;break;case 40:c=y(b);a.l=c;break;case 41:c=y(b);a.R=c;break;case 42:c=z(b);a.H=c;break;case 43:c=y(b);a.s=c;break;case 44:c=z(b);a.P=c;break;case 45:c=z(b);a.T=c;break;case 46:c=y(b);a.J=c;break;case 47:c=y(b);a.I=c;break;case 48:c=z(b);a.c=c;break;case 49:c=z(b);a.v=c;break;case 50:c=z(b);a.g=c;break;case 51:c=z(b);a.f=c;break;case 52:c=A(b);a.u=c;break;default:x(b)}};function Ti(){this.a=this.b=this.c=this.f=null}function Ui(a){a.f=null;a.c=null;a.b=null;a.a=null}Ti.prototype.getExtension=function(){return null};function Vi(a,b){for(;u(b);)switch(b.a){case 1:var c=A(b);a.f=c;break;case 2:c=Mc(b.b);a.c=c;break;case 3:c=A(b);a.b=c;break;case 4:c=A(b);a.a=c;break;default:x(b)}};function Wi(){this.f=this.a=this.g=this.s=this.h=this.v=this.i=this.o=this.b=this.m=this.l=this.j=this.c=this.u=this.w=null}function Xi(){this.g=this.f=this.c=this.a=this.b=null}function Yi(){this.a=this.b=null}function Zi(){this.b=this.c=this.a=null}function $i(){this.N=this.u=this.H=this.O=this.M=this.a=this.C=this.G=this.J=this.R=this.w=this.B=this.A=this.l=this.i=this.f=this.F=this.g=this.D=this.K=this.L=this.h=this.P=this.v=this.I=this.s=this.c=this.o=this.m=this.b=this.j=null} +function aj(){this.a=null}function bj(){this.l=this.h=this.b=this.j=this.i=this.a=this.f=this.c=this.g=null}function cj(){this.f=this.j=this.a=this.i=this.c=this.b=this.g=this.h=null}function dj(){this.c=this.b=this.f=this.a=null}function ej(){this.h=this.c=this.a=this.g=this.f=this.b=this.o=this.i=this.j=this.l=this.m=null}function fj(){this.a=null}function gj(){this.a=this.b=null}function hj(){this.a=this.b=null}function ij(){this.l=this.f=this.i=this.g=this.a=this.h=this.j=this.c=this.b=null} +function jj(){this.a=null}function kj(){this.b=this.a=null}function lj(){this.g=this.a=this.b=this.f=this.h=this.c=null}function mj(a){var b=new Wi;nj(b);b.w=a.w;b.u=a.u;b.c=a.c?bg(a.c):null;b.j=a.j;b.l=a.l;b.m=a.m;if(a.b){var c=new Ti;var d=a.b;Ui(c);c.f=d.f;c.c=d.c;c.b=d.b;c.a=d.a}else c=null;b.b=c;b.o=a.o;b.i=a.i;b.v=a.v;b.h=a.h;b.s=a.s;b.g=a.g;if(a.a){d=a.a;c=new jj;oj(c);if(d.a){d=d.a;var e=new kj;pj(e);e.a=d.a?mj(d.a):null;e.b=d.b;d=e}else d=null;c.a=d}else c=null;b.a=c;b.f=a.f;return b} +function nj(a){a.w=null;a.u=null;var b=a.c;b&&cg(b);a.c=null;a.j=null;a.l=null;a.m=null;(b=a.b)&&Ui(b);a.b=null;a.o=null;a.i=null;a.v=null;a.h=null;a.s=null;a.g=null;(b=a.a)&&oj(b);a.a=null;a.f=null}Wi.prototype.getExtension=function(){return null};function qj(a){return null===a?null:mj(a)} +function rj(a,b){for(;u(b);)switch(b.a){case 1:var c=A(b);a.w=c;break;case 2:c=A(b);a.u=c;break;case 3:c=new Zf;G(b,c,dg);a.c=c;break;case 4:c=A(b);a.j=c;break;case 5:c=C(b);a.l=c;break;case 6:c=C(b);a.m=c;break;case 7:c=new Ti;G(b,c,Vi);a.b=c;break;case 8:c=A(b);a.o=c;break;case 9:c=z(b);a.i=c;break;case 11:c=z(b);a.v=c;break;case 12:c=A(b);a.h=c;break;case 13:c=A(b);a.s=c;break;case 14:c=A(b);a.g=c;break;case 16:c=new jj;G(b,c,sj);a.a=c;break;case 17:c=y(b);a.f=c;break;default:x(b)}} +function tj(a,b){if(a===b)a=!0;else if(null===a||null===b)a=!1;else{var c;if(c=a.w===b.w&&a.u===b.u&&eg(a.c,b.c)&&a.j===b.j&&a.l===b.l&&a.m===b.m){c=a.b;var d=b.b;c=c===d?!0:null===c||null===d?!1:c.f!==d.f||c.c!==d.c||c.b!==d.b||c.a!==d.a?!1:!0}if(c=c&&a.o===b.o&&a.i===b.i&&a.v===b.v&&a.h===b.h&&a.s===b.s&&a.g===b.g)d=a.a,c=b.a,d===c?c=!0:null===d||null===c?c=!1:(d=d.a,c=c.a,c=d===c||(null===d||null===c?0:tj(d.a,c.a)&&d.b===c.b)?!0:!1);a=c&&a.f===b.f?!0:!1}return a} +function uj(a){a.b=null;var b=a.a;b&&cg(b);a.a=null;a.c=null;a.f=null;a.g=null}Xi.prototype.getExtension=function(){return null};function vj(a){if(null===a)a=null;else{var b=new Xi;uj(b);b.b=a.b;b.a=a.a?bg(a.a):null;b.c=a.c;b.f=a.f;b.g=a.g;a=b}return a}function wj(a,b){for(;u(b);)switch(b.a){case 1:var c=y(b);a.b=c;break;case 2:c=new Zf;G(b,c,dg);a.a=c;break;case 3:c=A(b);a.c=c;break;case 4:c=Mc(b.b);a.f=c;break;case 5:c=z(b);a.g=c;break;default:x(b)}} +function xj(a,b){return a===b?!0:null===a||null===b?!1:a.b===b.b&&eg(a.a,b.a)&&a.c===b.c&&a.f===b.f&&a.g===b.g?!0:!1}function yj(a,b){a.b=null;a.a=null;a.b=b.b;a.a=b.a}Yi.prototype.getExtension=function(){return null};function zj(a,b){for(;u(b);)switch(b.a){case 1:var c=C(b);a.b=c;break;case 2:c=z(b);a.a=c;break;default:x(b)}}function Aj(a,b){a.a=null;a.c=null;a.b=null;a.a=b.a;a.c=b.c;a.b=b.b}Zi.prototype.getExtension=function(){return null}; +function Bj(a,b){for(;u(b);)switch(b.a){case 1:var c=C(b);a.a=c;break;case 2:c=C(b);a.c=c;break;case 3:c=E(b);a.b=c;break;default:x(b)}} +function Cj(a,b){Dj(a);if(b.j){var c=b.j;var d=new ej;Ej(d);d.m=c.m;d.l=c.l;d.j=c.j;d.i=c.i;d.o=c.o;d.b=I(c.b);d.f=c.f;d.g=c.g;d.a=J(c.a,Fj);if(c.c){var e=c.c;var f=new gj;Gj(f);f.b=e.b;f.a=e.a?Hj(e.a):null;e=f}else e=null;d.c=e;d.h=c.h;c=d}else c=null;a.j=c;b.b?(c=b.b,d=new ij,Ij(d),d.b=c.b,d.c=c.c,d.j=c.j,d.h=c.h,c.a?(e=new bj,Jj(e,c.a)):e=null,d.a=e,d.g=c.g,d.i=c.i,d.f=c.f,d.l=c.l,c=d):c=null;a.b=c;a.m=b.m;a.o=b.o;b.c?(c=new Pi,Qi(c,b.c)):c=null;a.c=c;a.s=b.s;a.I=b.I;a.v=b.v;a.P=b.P;b.h?(c=new Yi, +yj(c,b.h)):c=null;a.h=c;a.L=b.L;a.K=b.K;a.D=b.D;a.g=I(b.g);a.F=b.F;b.f?(c=b.f,d=new dj,Kj(d),d.a=I(c.a),d.f=c.f,d.b=I(c.b),d.c=c.c,c=d):c=null;a.f=c;b.i?(c=new Zi,Aj(c,b.i)):c=null;a.i=c;b.l?(c=b.l,d=new cj,Lj(d),d.h=c.h,d.g=c.g,d.b=c.b,d.c=c.c,d.i=c.i,d.a=c.a,d.j=c.j,d.f=c.f,c=d):c=null;a.l=c;a.A=b.A;a.B=b.B;a.w=b.w;a.R=b.R;a.J=b.J;a.G=b.G;a.C=b.C;a.a=J(b.a,Mj);a.M=b.M;a.O=b.O;a.H=b.H;a.u=b.u;a.N=b.N} +function Dj(a){var b=a.j;b&&Ej(b);a.j=null;(b=a.b)&&Ij(b);a.b=null;a.m=null;a.o=null;(b=a.c)&&Ri(b);a.c=null;a.s=null;a.I=null;a.v=null;a.P=null;if(b=a.h)b.b=null,b.a=null;a.h=null;a.L=null;a.K=null;a.D=null;a.g=null;a.F=null;(b=a.f)&&Kj(b);a.f=null;if(b=a.i)b.a=null,b.c=null,b.b=null;a.i=null;(b=a.l)&&Lj(b);a.l=null;a.A=null;a.B=null;a.w=null;a.R=null;a.J=null;a.G=null;a.C=null;if(a.a)for(b=0;b<a.a.length;b++){var c=a.a[b];c&&(c.a=null)}a.a=null;a.M=null;a.O=null;a.H=null;a.u=null;a.N=null} +$i.prototype.getExtension=function(){return null}; +function Nj(a,b){for(;u(b);)switch(b.a){case 1:var c=new ej;G(b,c,Oj);a.j=c;break;case 2:c=new ij;G(b,c,Pj);a.b=c;break;case 3:c=z(b);a.m=c;break;case 4:c=z(b);a.o=c;break;case 6:c=new Pi;G(b,c,Si);a.c=c;break;case 7:c=z(b);a.s=c;break;case 8:c=z(b);a.I=c;break;case 9:c=C(b);a.v=c;break;case 10:c=z(b);a.P=c;break;case 11:c=new Yi;G(b,c,zj);a.h=c;break;case 12:c=z(b);a.L=c;break;case 13:c=z(b);a.K=c;break;case 14:c=z(b);a.D=c;break;case 15:c=y(b);a.g=a.g||[];a.g.push(c);break;case 16:c=z(b);a.F=c; +break;case 17:c=new dj;G(b,c,Qj);a.f=c;break;case 19:c=new Zi;G(b,c,Bj);a.i=c;break;case 20:c=new cj;G(b,c,Rj);a.l=c;break;case 25:c=z(b);a.A=c;break;case 26:c=z(b);a.B=c;break;case 31:c=z(b);a.w=c;break;case 33:c=z(b);a.R=c;break;case 34:c=z(b);a.J=c;break;case 35:c=z(b);a.G=c;break;case 37:c=z(b);a.C=c;break;case 38:c=new aj;G(b,c,Sj);a.a=a.a||[];a.a.push(c);break;case 39:c=z(b);a.M=c;break;case 40:c=z(b);a.O=c;break;case 41:c=z(b);a.H=c;break;case 42:c=z(b);a.u=c;break;case 43:c=y(b);a.N=c;break; +default:x(b)}}aj.prototype.getExtension=function(){return null};function Mj(a){if(null===a)a=null;else{var b=new aj;b.a=null;b.a=a.a;a=b}return a}function Sj(a,b){for(;u(b);)switch(b.a){case 1:a.a=y(b);break;default:x(b)}}function Tj(a,b){return a===b?!0:null===a||null===b?!1:a.a!==b.a?!1:!0}function Jj(a,b){Uj(a);a.g=b.g;a.c=b.c;a.f=b.f;a.a=b.a;a.i=b.i;a.j=b.j;a.b=b.b;a.h=b.h;a.l=b.l}function Uj(a){a.g=null;a.c=null;a.f=null;a.a=null;a.i=null;a.j=null;a.b=null;a.h=null} +bj.prototype.getExtension=function(){return null};function Vj(a,b){for(a.l=b.b.b;u(b);)switch(b.a){case 2:var c=z(b);a.g=c;break;case 3:c=z(b);a.c=c;break;case 4:c=z(b);a.f=c;break;case 5:c=z(b);a.a=c;break;case 6:c=C(b);a.i=c;break;case 7:c=C(b);a.j=c;break;case 9:c=z(b);a.b=c;break;case 10:c=C(b);a.h=c;break;default:x(b)}}function Lj(a){a.h=null;a.g=null;a.b=null;a.c=null;a.i=null;a.a=null;a.j=null;a.f=null}cj.prototype.getExtension=function(){return null}; +function Rj(a,b){for(;u(b);)switch(b.a){case 1:var c=C(b);a.h=c;break;case 2:c=C(b);a.g=c;break;case 3:c=z(b);a.b=c;break;case 4:c=z(b);a.c=c;break;case 5:c=C(b);a.i=c;break;case 6:c=z(b);a.a=c;break;case 7:c=z(b);a.j=c;break;case 8:c=z(b);a.f=c;break;default:x(b)}}function Kj(a){a.a=null;a.f=null;a.b=null;a.c=null}dj.prototype.getExtension=function(){return null}; +function Qj(a,b){for(;u(b);)switch(b.a){case 1:var c=C(b);a.a=a.a||[];a.a.push(c);break;case 2:c=z(b);a.f=c;break;case 3:c=C(b);a.b=a.b||[];a.b.push(c);break;case 4:c=C(b);a.c=c;break;default:x(b)}}function Ej(a){a.m=null;a.l=null;a.j=null;a.i=null;a.o=null;a.b=null;a.f=null;a.g=null;if(a.a)for(var b=0;b<a.a.length;b++){var c=a.a[b];c&&(c.a=null)}a.a=null;(b=a.c)&&Gj(b);a.c=null;a.h=null}ej.prototype.getExtension=function(){return null}; +function Oj(a,b){for(;u(b);)switch(b.a){case 1:var c=C(b);a.m=c;break;case 2:c=C(b);a.l=c;break;case 3:c=E(b);a.j=c;break;case 5:c=C(b);a.i=c;break;case 6:c=z(b);a.o=c;break;case 7:c=C(b);a.b=a.b||[];a.b.push(c);break;case 8:c=C(b);a.f=c;break;case 9:c=z(b);a.g=c;break;case 10:c=new fj;G(b,c,Wj);a.a=a.a||[];a.a.push(c);break;case 11:c=new gj;G(b,c,Xj);a.c=c;break;case 12:c=C(b);a.h=c;break;default:x(b)}} +function Yj(a,b){if(a===b)a=!0;else if(null===a||null===b)a=!1;else{var c;if(c=a.m===b.m&&a.l===b.l&&a.j===b.j&&a.i===b.i&&a.o===b.o&&L(a.b,b.b)&&a.f===b.f&&a.g===b.g&&M(a.a,b.a,Zj)){var d=a.c;c=b.c;if(d===c)c=!0;else if(null===d||null===c)c=!1;else{var e;if(e=d.b===c.b)d=d.a,c=c.a,e=d===c?!0:null===d||null===c?!1:d.b!==c.b||d.a!==c.a?!1:!0;c=e?!0:!1}}a=c&&a.h===b.h?!0:!1}return a}fj.prototype.getExtension=function(){return null}; +function Fj(a){if(null===a)a=null;else{var b=new fj;b.a=null;b.a=a.a;a=b}return a}function Wj(a,b){for(;u(b);)switch(b.a){case 1:a.a=C(b);break;default:x(b)}}function Zj(a,b){return a===b?!0:null===a||null===b?!1:a.a!==b.a?!1:!0}function Gj(a){a.b=null;var b=a.a;b&&(b.b=null,b.a=null);a.a=null}gj.prototype.getExtension=function(){return null};function Xj(a,b){for(;u(b);)switch(b.a){case 1:var c=C(b);a.b=c;break;case 3:c=new hj;G(b,c,ak);a.a=c;break;default:x(b)}} +function Hj(a){var b=new hj;b.b=null;b.a=null;b.b=a.b;b.a=a.a;return b}hj.prototype.getExtension=function(){return null};function ak(a,b){for(;u(b);)switch(b.a){case 1:var c=y(b);a.b=c;break;case 2:c=y(b);a.a=c;break;default:x(b)}}function Ij(a){a.b=null;a.c=null;a.j=null;a.h=null;var b=a.a;b&&Uj(b);a.a=null;a.g=null;a.i=null;a.f=null;a.l=null}ij.prototype.getExtension=function(){return null}; +function Pj(a,b){for(;u(b);)switch(b.a){case 1:var c=z(b);a.b=c;break;case 2:c=z(b);a.c=c;break;case 3:c=z(b);a.j=c;break;case 4:c=z(b);a.h=c;break;case 5:c=new bj;G(b,c,Vj);a.a=c;break;case 6:c=z(b);a.g=c;break;case 7:c=z(b);a.i=c;break;case 8:c=z(b);a.f=c;break;case 20:c=C(b);a.l=c;break;default:x(b)}} +function bk(a,b){if(a===b)a=!0;else if(null===a||null===b)a=!1;else{var c;if(c=a.b===b.b&&a.c===b.c&&a.j===b.j&&a.h===b.h){c=a.a;var d=b.a;c=c===d?!0:null===c||null===d?!1:c.g!==d.g||c.c!==d.c||c.f!==d.f||c.a!==d.a||c.i!==d.i||c.j!==d.j||c.b!==d.b||c.h!==d.h?!1:!0}a=c&&a.g===b.g&&a.i===b.i&&a.f===b.f&&a.l===b.l?!0:!1}return a}function oj(a){var b=a.a;b&&pj(b);a.a=null}jj.prototype.getExtension=function(){return null}; +function sj(a,b){for(;u(b);)switch(b.a){case 1:var c=new kj;G(b,c,ck);a.a=c;break;default:x(b)}}function pj(a){var b=a.a;b&&nj(b);a.a=null;a.b=null}kj.prototype.getExtension=function(){return null};function ck(a,b){for(;u(b);)switch(b.a){case 1:var c=new Wi;G(b,c,rj);a.a=c;break;case 2:c=z(b);a.b=c;break;default:x(b)}}function dk(a){a.c=null;a.h=null;a.f=null;a.b=null;a.a=null;a.g=null}lj.prototype.getExtension=function(){return null}; +function ek(a,b){for(;u(b);)switch(b.a){case 1:var c=C(b);a.c=c;break;case 2:c=z(b);a.h=c;break;case 3:c=z(b);a.f=c;break;case 4:c=y(b);a.b=a.b||[];a.b.push(c);break;case 5:c=y(b);a.a=a.a||[];a.a.push(c);break;case 6:c=z(b);a.g=c;break;default:x(b)}};function fk(){this.b=this.a=null}function gk(a){var b=a.a;b&&Rd(b);a.a=null;(b=a.b)&&Rd(b);a.b=null}fk.prototype.getExtension=function(){return null};function hk(a){if(null===a)a=null;else{var b=new fk;gk(b);b.a=a.a?Qd(a.a):null;b.b=a.b?Qd(a.b):null;a=b}return a}function ik(a,b){for(;u(b);)switch(b.a){case 1:var c=new Ld;G(b,c,Sd);a.a=c;break;case 2:c=new Ld;G(b,c,Sd);a.b=c;break;default:x(b)}}function jk(a,b){return a===b?!0:null===a||null===b?!1:Td(a.a,b.a)&&Td(a.b,b.b)?!0:!1};function kk(){this.a=this.c=this.b=null}kk.prototype.getExtension=function(){return null};function lk(a,b){for(;u(b);)switch(b.a){case 1:var c=z(b);a.b=c;break;case 2:c=A(b);a.c=c;break;case 3:c=A(b);a.a=c;break;default:x(b)}};function mk(){this.B=this.s=this.m=this.i=this.f=this.D=this.b=this.G=this.h=this.l=this.H=this.g=this.j=this.v=this.a=this.A=this.w=this.o=this.c=this.u=this.F=this.C=null} +function nk(a,b){ok(a);a.C=b.C;a.F=b.F;a.u=b.u;a.c=b.c?yf(b.c):null;a.o=b.o;a.w=b.w;a.A=b.A;a.a=J(b.a,Lf);a.v=b.v;a.j=b.j;if(b.g){var c=new Zd;Ae(c,b.g)}else c=null;a.g=c;a.H=b.H;a.l=b.l;if(b.h){c=new kk;var d=b.h;c.b=null;c.c=null;c.a=null;c.b=d.b;c.c=d.c;c.a=d.a}else c=null;a.h=c;a.G=b.G;a.b=J(b.b,hk);a.D=b.D;a.f=I(b.f);b.i?(c=new Xd,d=b.i,c.a=null,c.a=d.a):c=null;a.i=c;a.m=b.m;a.s=b.s;a.B=b.B} +function ok(a){a.C=null;a.F=null;a.u=null;var b=a.c;b&&zf(b);a.c=null;a.o=null;a.w=null;a.A=null;if(a.a)for(b=0;b<a.a.length;b++){var c=a.a[b];c&&Jf(c)}a.a=null;a.v=null;a.j=null;(b=a.g)&&Be(b);a.g=null;a.H=null;a.l=null;if(b=a.h)b.b=null,b.c=null,b.a=null;a.h=null;a.G=null;if(a.b)for(b=0;b<a.b.length;b++)(c=a.b[b])&&gk(c);a.b=null;a.D=null;a.f=null;if(b=a.i)b.a=null;a.i=null;a.m=null;a.s=null;a.B=null}mk.prototype.getExtension=function(){return null}; +function pk(a,b){for(;u(b);)switch(b.a){case 1:var c=A(b);a.C=c;break;case 2:c=A(b);a.F=c;break;case 3:c=z(b);a.u=c;break;case 4:c=new xf;G(b,c,Af);a.c=c;break;case 5:c=A(b);a.o=c;break;case 6:c=A(b);a.w=c;break;case 7:c=C(b);a.A=c;break;case 8:c=new If;G(b,c,Mf);a.a=a.a||[];a.a.push(c);break;case 9:c=A(b);a.v=c;break;case 10:c=A(b);a.j=c;break;case 11:c=new Zd;G(b,c,Ze);a.g=c;break;case 12:c=C(b);a.H=c;break;case 13:c=C(b);a.l=c;break;case 14:c=new kk;G(b,c,lk);a.h=c;break;case 15:c=y(b);a.G=c;break; +case 16:c=new fk;G(b,c,ik);a.b=a.b||[];a.b.push(c);break;case 17:c=A(b);a.D=c;break;case 18:c=C(b);a.f=a.f||[];a.f.push(c);break;case 19:c=new Xd;G(b,c,Yd);a.i=c;break;case 20:c=z(b);a.m=c;break;case 21:c=z(b);a.s=c;break;case 22:c=z(b);a.B=c;break;default:x(b)}};function qk(){this.h=this.i=this.f=this.b=this.g=this.s=this.o=this.m=this.l=this.c=this.a=this.j=null}function rk(a){a.j=null;a.a=null;a.c=null;a.l=null;a.m=null;a.o=null;a.s=null;a.g=null;a.b=null;a.f=null;a.i=null;a.h=null}qk.prototype.getExtension=function(){return null}; +function sk(a,b){for(;u(b);)switch(b.a){case 1:var c=A(b);a.j=c;break;case 2:c=A(b);a.a=c;break;case 3:c=A(b);a.c=c;break;case 4:c=A(b);a.l=c;break;case 5:c=A(b);a.m=c;break;case 6:c=A(b);a.o=c;break;case 7:c=A(b);a.s=c;break;case 8:c=A(b);a.g=c;break;case 10:c=A(b);a.b=c;break;case 11:c=A(b);a.f=c;break;case 12:c=A(b);a.i=c;break;case 13:c=A(b);a.h=c;break;default:x(b)}};function tk(){this.a=null}function uk(a){a.a=null}tk.prototype.getExtension=function(){return null};function vk(a,b){for(;u(b);)switch(b.a){case 1:a.a=C(b);break;default:x(b)}};function wk(){this.M=this.L=this.s=this.i=this.K=this.D=this.h=this.H=this.o=this.u=this.C=this.G=this.B=this.c=this.m=this.A=this.I=this.f=this.F=this.v=this.a=this.j=this.w=this.g=this.J=this.l=this.b=null}function xk(){this.a=null} +function yk(a){var b=new wk;zk(b);b.b=J(a.b,qj);b.l=a.l?Sf(a.l):null;b.J=a.J;if(a.g){var c=new $i;Cj(c,a.g)}else c=null;b.g=c;b.w=a.w;if(a.j){c=new lj;var d=a.j;dk(c);c.c=d.c;c.h=d.h;c.f=d.f;c.b=I(d.b);c.a=I(d.a);c.g=d.g}else c=null;b.j=c;b.a=J(a.a,vj);b.v=a.v;b.F=a.F;a.f?(c=new mk,nk(c,a.f)):c=null;b.f=c;b.I=a.I;b.A=a.A;a.m?(c=a.m,d=new xk,d.a=null,d.a=c.a,c=d):c=null;b.m=c;a.c?(c=new Mi,d=a.c,Ni(c),c.a=J(d.a,jg),c.b=d.b):c=null;b.c=c;b.B=a.B;b.G=a.G;b.C=a.C;b.u=a.u;a.o?(c=new tk,d=a.o,uk(c),c.a= +d.a):c=null;b.o=c;b.H=a.H;a.h?(c=new qk,d=a.h,rk(c),c.j=d.j,c.a=d.a,c.c=d.c,c.l=d.l,c.m=d.m,c.o=d.o,c.s=d.s,c.g=d.g,c.b=d.b,c.f=d.f,c.i=d.i,c.h=d.h):c=null;b.h=c;b.D=a.D;b.K=a.K;b.i=a.i?new Uint8Array(a.i):null;b.s=a.s;b.L=a.L;b.M=a.M;return b} +function zk(a){if(a.b)for(var b=0;b<a.b.length;b++){var c=a.b[b];c&&nj(c)}a.b=null;(b=a.l)&&Tf(b);a.l=null;a.J=null;(b=a.g)&&Dj(b);a.g=null;a.w=null;(b=a.j)&&dk(b);a.j=null;if(a.a)for(b=0;b<a.a.length;b++)(c=a.a[b])&&uj(c);a.a=null;a.v=null;a.F=null;(b=a.f)&&ok(b);a.f=null;a.I=null;a.A=null;if(b=a.m)b.a=null;a.m=null;(b=a.c)&&Ni(b);a.c=null;a.B=null;a.G=null;a.C=null;a.u=null;(b=a.o)&&uk(b);a.o=null;a.H=null;(b=a.h)&&rk(b);a.h=null;a.D=null;a.K=null;a.i=null;a.s=null;a.L=null} +wk.prototype.getExtension=function(){return null}; +function Ak(a,b){for(a.M=b.b.b;u(b);)switch(b.a){case 1:var c=new Wi;G(b,c,rj);a.b=a.b||[];a.b.push(c);break;case 3:c=new Of;G(b,c,Uf);a.l=c;break;case 4:c=y(b);a.J=c;break;case 6:c=new $i;G(b,c,Nj);a.g=c;break;case 7:c=C(b);a.w=c;break;case 8:c=new lj;G(b,c,ek);a.j=c;break;case 9:c=new Xi;G(b,c,wj);a.a=a.a||[];a.a.push(c);break;case 12:c=z(b);a.v=c;break;case 13:c=A(b);a.F=c;break;case 15:c=new mk;G(b,c,pk);a.f=c;break;case 16:c=z(b);a.I=c;break;case 17:c=z(b);a.A=c;break;case 19:c=new xk;G(b,c, +Bk);a.m=c;break;case 20:c=new Mi;G(b,c,Oi);a.c=c;break;case 21:c=A(b);a.B=c;break;case 22:c=z(b);a.G=c;break;case 23:c=y(b);a.C=c;break;case 25:c=z(b);a.u=c;break;case 26:c=new tk;G(b,c,vk);a.o=c;break;case 27:c=z(b);a.H=c;break;case 28:c=new qk;G(b,c,sk);a.h=c;break;case 29:c=C(b);a.D=c;break;case 30:c=C(b);a.K=c;break;case 31:null===a.s&&(a.s=b.c);w(b);a.L=b.b.a;break;default:x(b)}} +function Ck(a,b){if(a===b)a=!0;else if(null===a||null===b)a=!1;else{var c;if(c=M(a.b,b.b,tj)&&Yf(a.l,b.l)&&a.J===b.J){c=a.g;var d=b.g;if(c===d)c=!0;else if(null===c||null===d)c=!1;else{var e;if(e=Yj(c.j,d.j)&&bk(c.b,d.b)&&c.m===d.m&&c.o===d.o){e=c.c;var f=d.c;e=e===f?!0:null===e||null===f?!1:e.o!==f.o||e.w!==f.w||e.O!==f.O||e.a!==f.a||e.b!==f.b||e.G!==f.G||e.D!==f.D||e.F!==f.F||e.i!==f.i||e.C!==f.C||e.B!==f.B||e.A!==f.A||e.L!==f.L||e.K!==f.K||e.h!==f.h||e.m!==f.m||e.N!==f.N||e.M!==f.M||e.j!==f.j|| +e.l!==f.l||e.R!==f.R||e.H!==f.H||e.s!==f.s||e.P!==f.P||e.T!==f.T||e.J!==f.J||e.I!==f.I||e.c!==f.c||e.v!==f.v||e.g!==f.g||e.f!==f.f||e.u!==f.u?!1:!0}if(e=e&&c.s===d.s&&c.I===d.I&&c.v===d.v&&c.P===d.P)e=c.h,f=d.h,e=e===f?!0:null===e||null===f?!1:e.b!==f.b||e.a!==f.a?!1:!0;if(e=e&&c.L===d.L&&c.K===d.K&&c.D===d.D&&L(c.g,d.g)&&c.F===d.F)e=c.f,f=d.f,e=e===f?!0:null===e||null===f?!1:L(e.a,f.a)&&e.f===f.f&&L(e.b,f.b)&&e.c===f.c?!0:!1;e&&(e=c.i,f=d.i,e=e===f?!0:null===e||null===f?!1:e.a!==f.a||e.c!==f.c|| +e.b!==f.b?!1:!0);e&&(e=c.l,f=d.l,e=e===f?!0:null===e||null===f?!1:e.h!==f.h||e.g!==f.g||e.b!==f.b||e.c!==f.c||e.i!==f.i||e.a!==f.a||e.j!==f.j||e.f!==f.f?!1:!0);c=e&&c.A===d.A&&c.B===d.B&&c.w===d.w&&c.R===d.R&&c.J===d.J&&c.G===d.G&&c.C===d.C&&M(c.a,d.a,Tj)&&c.M===d.M&&c.O===d.O&&c.H===d.H&&c.u===d.u&&c.N===d.N?!0:!1}}if(c=c&&a.w===b.w)c=a.j,d=b.j,c=c===d?!0:null===c||null===d?!1:c.c===d.c&&c.h===d.h&&c.f===d.f&&L(c.b,d.b)&&L(c.a,d.a)&&c.g===d.g?!0:!1;if(c=c&&M(a.a,b.a,xj)&&a.v===b.v&&a.F===b.F)if(c= +a.f,d=b.f,c===d)c=!0;else if(null===c||null===d)c=!1;else{if(e=c.C===d.C&&c.F===d.F&&c.u===d.u&&Bf(c.c,d.c)&&c.o===d.o&&c.w===d.w&&c.A===d.A&&M(c.a,d.a,Nf)&&c.v===d.v&&c.j===d.j)if(e=c.g,f=d.g,e===f)e=!0;else if(null===e||null===f)e=!1;else{var g;if(g=e.Da===f.Da&&e.H===f.H){g=e.u;var h=f.u;g=g===h?!0:null===g||null===h?!1:g.b!==h.b||g.c!==h.c||g.a!==h.a?!1:!0}if(g=g&&e.ja===f.ja&&ef(e.i,f.i)&&M(e.a,f.a,ef)&&e.Ca===f.Ca&&e.ta===f.ta&&e.ra===f.ra&&e.R===f.R&&e.ba===f.ba&&e.P===f.P&&e.J===f.J&&e.aa=== +f.aa&&e.T===f.T&&e.Z===f.Z&&e.K===f.K&&e.ka===f.ka&&e.ea===f.ea&&e.W===f.W&&e.da===f.da&&e.ca===f.ca&&e.qa===f.qa&&e.O===f.O&&e.I===f.I&&e.N===f.N)g=e.s,h=f.s,g=g===h?!0:null===g||null===h?!1:g.f!==h.f||g.h!==h.h||g.a!==h.a||g.b!==h.b||g.g!==h.g||g.c!==h.c?!1:!0;g&&(g=e.j,h=f.j,g=g===h?!0:null===g||null===h?!1:g.c!==h.c||g.a!==h.a||g.b!==h.b?!1:!0);if(g=g&&e.la===f.la&&e.ua===f.ua&&L(e.m,f.m)&&e.na===f.na&&e.pa===f.pa&&e.w===f.w&&e.oa===f.oa&&e.Aa===f.Aa&&e.ha===f.ha&&e.Ea===f.Ea&&e.L===f.L&&M(e.c, +f.c,ef)&&e.ma===f.ma&&e.sa===f.sa&&e.ia===f.ia&&e.G===f.G&&e.F===f.F&&e.D===f.D&&e.C===f.C&&e.$===f.$&&e.Ba===f.Ba&&e.va===f.va&&e.wa===f.wa&&e.Y===f.Y&&e.A===f.A&&e.M===f.M&&rf(e.o,f.o)&&e.X===f.X&&M(e.f,f.f,tf)&&e.Fa===f.Fa)g=e.l,h=f.l,g=g===h?!0:null===g||null===h?!1:g.b!==h.b||g.a!==h.a?!1:!0;if(g=g&&M(e.b,f.b,sf)&&e.B===f.B&&e.fa===f.fa&&e.ga===f.ga)g=e.v,h=f.v,g=g===h?!0:null===g||null===h?!1:g.a!==h.a||g.b!==h.b?!1:!0;if(g=g&&e.za===f.za&&e.ya===f.ya)g=e.h,h=f.h,g=g===h?!0:null===g||null=== +h?!1:g.c!==h.c||g.f!==h.f||g.g!==h.g||g.b!==h.b||g.a!==h.a?!1:!0;e=g&&M(e.g,f.g,hf)?!0:!1}if(e=e&&c.H===d.H&&c.l===d.l)e=c.h,f=d.h,e=e===f?!0:null===e||null===f?!1:e.b!==f.b||e.c!==f.c||e.a!==f.a?!1:!0;if(e=e&&c.G===d.G&&M(c.b,d.b,jk)&&c.D===d.D&&L(c.f,d.f))e=c.i,f=d.i,e=e===f?!0:null===e||null===f?!1:e.a!==f.a?!1:!0;c=e&&c.m===d.m&&c.s===d.s&&c.B===d.B?!0:!1}if(c=c&&a.I===b.I&&a.A===b.A)c=a.m,d=b.m,c=c===d?!0:null===c||null===d?!1:c.a!==d.a?!1:!0;c&&(c=a.c,d=b.c,c=c===d?!0:null===c||null===d?!1: +M(c.a,d.a,lg)&&c.b===d.b?!0:!1);if(c=c&&a.B===b.B&&a.G===b.G&&a.C===b.C&&a.u===b.u)c=a.o,d=b.o,c=c===d?!0:null===c||null===d?!1:c.a!==d.a?!1:!0;if(c=c&&a.H===b.H)c=a.h,d=b.h,c=c===d?!0:null===c||null===d?!1:c.j!==d.j||c.a!==d.a||c.c!==d.c||c.l!==d.l||c.m!==d.m||c.o!==d.o||c.s!==d.s||c.g!==d.g||c.b!==d.b||c.f!==d.f||c.i!==d.i||c.h!==d.h?!1:!0;c&&a.D===b.D&&a.K===b.K?(null!=a.s&&null==a.i&&(a.i=cd(a.M,a.s,a.L)),a=L(a.i,b.i)?!0:!1):a=!1}return a}xk.prototype.getExtension=function(){return null}; +function Bk(a,b){for(;u(b);)switch(b.a){case 1:a.a=C(b);break;default:x(b)}};function Dk(){this.a=null}function Ek(){this.c=this.a=this.b=null}function Fk(){this.b=this.a=null}function Gk(){this.b=this.a=null}function Hk(){this.c=this.i=this.j=this.h=this.g=this.f=this.b=this.a=null}function Ik(){this.f=this.g=this.c=this.a=this.b=null}function Jk(){this.b=this.a=null}Dk.prototype.getExtension=function(){return null};Ek.prototype.getExtension=function(){return null};Fk.prototype.getExtension=function(){return null};Gk.prototype.getExtension=function(){return null}; +function Kk(a){if(null===a)a=null;else{var b=new Gk;b.a=null;b.b=null;b.a=a.a;b.b=a.b;a=b}return a}function Lk(a,b){for(;u(b);)switch(b.a){case 1:var c=y(b);a.a=c;break;case 2:c=y(b);a.b=c;break;default:x(b)}}function Mk(a,b){return a===b?!0:null===a||null===b?!1:a.a!==b.a||a.b!==b.b?!1:!0}Hk.prototype.getExtension=function(){return null};function Nk(){return new Hk} +function Ok(a){if(null===a)a=null;else{var b=new Hk;if(b.a)for(var c=0;c<b.a.length;c++){var d=b.a[c];d&&(d.a=null,d.b=null)}b.a=null;(c=b.b)&&zk(c);b.b=null;b.f=null;b.g=null;b.h=null;b.j=null;b.i=null;b.c=null;b.a=J(a.a,Kk);b.b=a.b?yk(a.b):null;b.f=a.f;b.g=a.g;b.h=a.h;b.j=a.j;b.i=a.i;b.c=a.c;a=b}return a}function Pk(){} +function Qk(a,b){for(;u(b);)switch(b.a){case 1:var c=new Gk;G(b,c,Lk);a.a=a.a||[];a.a.push(c);break;case 2:c=new wk;G(b,c,Ak);a.b=c;break;case 3:c=y(b);a.f=c;break;case 5:c=y(b);a.g=c;break;case 6:c=y(b);a.h=c;break;case 7:c=y(b);a.j=c;break;case 9:c=C(b);a.i=c;break;case 10:c=C(b);a.c=c;break;default:x(b)}}function Rk(a,b){return a===b?!0:null===a||null===b?!1:M(a.a,b.a,Mk)&&Ck(a.b,b.b)&&a.f===b.f&&a.g===b.g&&a.h===b.h&&a.j===b.j&&a.i===b.i&&a.c===b.c?!0:!1}Ik.prototype.getExtension=function(){return null}; +Jk.prototype.getExtension=function(){return null};function Sk(){this.a=this.b=this.c=null}function Tk(){this.a=null}function Uk(){this.a=null}Sk.prototype.getExtension=function(){return null};function Vk(){return new Sk}function Wk(a){if(null===a)var b=null;else{b=new Sk;var c=b.c;c&&og(c);b.c=null;if(c=b.b)c.a=null;b.b=null;if(c=b.a)c.a=null;b.a=null;b.c=a.c?ng(a.c):null;if(a.b){c=a.b;var d=new Tk;d.a=null;d.a=c.a;c=d}else c=null;b.b=c;a.a?(a=a.a,c=new Uk,c.a=null,c.a=a.a,a=c):a=null;b.a=a}return b}function Xk(){} +function Yk(a,b){for(;u(b);)switch(b.a){case 1:var c=new mg;G(b,c,pg);a.c=c;break;case 2:c=new Tk;G(b,c,Zk);a.b=c;break;case 4:c=new Uk;G(b,c,$k);a.a=c;break;default:x(b)}}function al(a,b){if(a===b)b=!0;else if(null===a||null===b)b=!1;else{var c;if(c=qg(a.c,b.c)){c=a.b;var d=b.b;c=c===d?!0:null===c||null===d?!1:c.a!==d.a?!1:!0}c&&(a=a.a,b=b.a,c=a===b?!0:null===a||null===b?!1:a.a!==b.a?!1:!0);b=c?!0:!1}return b}Tk.prototype.getExtension=function(){return null}; +function Zk(a,b){for(;u(b);)switch(b.a){case 1:a.a=C(b);break;default:x(b)}}Uk.prototype.getExtension=function(){return null};function $k(a,b){for(;u(b);)switch(b.a){case 1:a.a=A(b);break;default:x(b)}};function bl(){this.a=this.h=this.b=this.c=this.g=this.f=null}bl.prototype.getExtension=function(){return null};function cl(){this.a=null}cl.prototype.getExtension=function(){return null};function dl(a,b){for(;u(b);)switch(b.a){case 1:a.a=C(b);break;default:x(b)}};function el(){this.j=this.o=this.g=this.m=this.f=this.b=this.i=this.s=this.h=this.c=this.a=this.l=null}function fl(a){a.l=null;a.a=null;a.c=null;var b=a.h;b&&Gi(b);a.h=null;a.s=null;a.i=null;a.b=null;a.f=null;a.m=null;if(b=a.g)b.a=null;a.g=null;a.o=null;a.j=null}el.prototype.getExtension=function(){return null}; +function gl(a,b){for(;u(b);)switch(b.a){case 1:var c=A(b);a.l=c;break;case 2:c=C(b);a.a=a.a||[];a.a.push(c);break;case 3:c=C(b);a.c=a.c||[];a.c.push(c);break;case 4:c=new Ei;G(b,c,Hi);a.h=c;break;case 5:c=C(b);a.s=c;break;case 6:c=C(b);a.i=c;break;case 7:c=y(b);a.b=a.b||[];a.b.push(c);break;case 8:c=C(b);a.f=a.f||[];a.f.push(c);break;case 9:c=z(b);a.m=c;break;case 10:c=new cl;G(b,c,dl);a.g=c;break;case 11:c=C(b);a.o=c;break;case 12:c=y(b);a.j=c;break;default:x(b)}};function hl(){this.a=null}hl.prototype.getExtension=function(){return null};function il(){return new hl}function jl(a){if(null===a)var b=null;else{b=new hl;var c=b.a;c&&fl(c);b.a=null;if(a.a){c=new el;a=a.a;fl(c);c.l=a.l;c.a=I(a.a);c.c=I(a.c);c.h=a.h?Fi(a.h):null;c.s=a.s;c.i=a.i;c.b=I(a.b);c.f=I(a.f);c.m=a.m;if(a.g){var d=new cl;var e=a.g;d.a=null;d.a=e.a}else d=null;c.g=d;c.o=a.o;c.j=a.j}else c=null;b.a=c}return b}function kl(){} +function ll(a,b){for(;u(b);)switch(b.a){case 1:var c=new el;G(b,c,gl);a.a=c;break;default:x(b)}}function ml(a,b){if(a===b)a=!0;else if(null===a||null===b)a=!1;else{a=a.a;b=b.a;var c;if(!(c=a===b)){if(null===a||null===b)a=0;else{if(c=a.l===b.l&&L(a.a,b.a)&&L(a.c,b.c)&&Ii(a.h,b.h)&&a.s===b.s&&a.i===b.i&&L(a.b,b.b)&&L(a.f,b.f)&&a.m===b.m){c=a.g;var d=b.g;c=c===d?!0:null===c||null===d?!1:c.a!==d.a?!1:!0}a=c&&a.o===b.o&&a.j===b.j}c=a}a=c?!0:!1}return a};function nl(){this.a=null}nl.prototype.getExtension=function(){return null};function ol(){this.a=null}ol.prototype.getExtension=function(){return null};function pl(){this.j=this.b=this.c=this.a=this.i=this.h=this.f=this.g=null}function ql(){this.a=null}pl.prototype.getExtension=function(){return null};function rl(){return new pl}function sl(a){if(null===a)a=null;else{var b=new pl;b.g=null;b.f=null;b.h=null;b.i=null;b.a=null;b.c=null;b.b=null;b.j=null;b.g=a.g;b.f=a.f;b.h=a.h;b.i=a.i;b.a=a.a;b.c=a.c;b.b=a.b;b.j=a.j;a=b}return a}function tl(){} +function ul(a,b){for(;u(b);)switch(b.a){case 1:var c=A(b);a.g=c;break;case 2:c=A(b);a.f=c;break;case 3:c=D(b);a.h=c;break;case 4:c=D(b);a.i=c;break;case 5:c=A(b);a.a=c;break;case 6:c=z(b);a.c=c;break;case 7:c=z(b);a.b=c;break;case 8:c=z(b);a.j=c;break;default:x(b)}}function vl(a,b){return a===b?!0:null===a||null===b?!1:a.g!==b.g||a.f!==b.f||a.h!==b.h||a.i!==b.i||a.a!==b.a||a.c!==b.c||a.b!==b.b||a.j!==b.j?!1:!0}ql.prototype.getExtension=function(){return null};H(U,53863091,11,rl,tl,ul,sl,vl); +H(U,32819068,11,xg,Dg,Eg,yg,Hg);H(U,42466818,11,Kg,Ng,Og,Lg,Qg);H(U,52617685,11,function(){return new vg},function(){},Tg,function(a){return null===a?null:Cg(a)},Jg);H(U,40154408,11,il,kl,ll,jl,ml);H(U,30096869,11,Vk,Xk,Yk,Wk,al);H(U,51650189,11,hd,ld,md,id,od); +H(U,177034656,11,function(){return new ql},function(){},function(a,b){for(;u(b);)switch(b.a){case 1:a.a=z(b);break;default:x(b)}},function(a){if(null===a)a=null;else{var b=new ql;b.a=null;b.a=a.a;a=b}return a},function(a,b){return a===b?!0:null===a||null===b?!1:a.a!==b.a?!1:!0});H(Nh,28517612,11,Nk,Pk,Qk,Ok,Rk); +H(Nh,48343962,11,function(){return new Ik},function(){},function(a,b){for(;u(b);)switch(b.a){case 1:var c=z(b);a.b=c;break;case 2:c=new wk;G(b,c,Ak);a.a=c;break;case 3:c=A(b);a.c=c;break;case 4:c=A(b);a.g=c;break;case 5:c=A(b);a.f=c;break;default:x(b)}},function(a){if(null===a)a=null;else{var b=new Ik;b.b=null;var c=b.a;c&&zk(c);b.a=null;b.c=null;b.g=null;b.f=null;b.b=a.b;b.a=a.a?yk(a.a):null;b.c=a.c;b.g=a.g;b.f=a.f;a=b}return a},function(a,b){return a===b?!0:null===a||null===b?!1:a.b===b.b&&Ck(a.a, +b.a)&&a.c===b.c&&a.g===b.g&&a.f===b.f?!0:!1});H(Nh,49095464,11,function(){return new Jk},function(){},function(a,b){for(;u(b);)switch(b.a){case 1:var c=y(b);a.a=c;break;case 2:c=y(b);a.b=c;break;default:x(b)}},function(a){if(null===a)a=null;else{var b=new Jk;b.a=null;b.b=null;b.a=a.a;b.b=a.b;a=b}return a},function(a,b){return a===b?!0:null===a||null===b?!1:a.a!==b.a||a.b!==b.b?!1:!0});H(Nh,30096869,11,Vk,Xk,Yk,Wk,al); +H(Nh,132080860,11,function(){return new nl},function(){},function(a,b){for(;u(b);)switch(b.a){case 1:a.a=A(b);break;default:x(b)}},function(a){if(null===a)a=null;else{var b=new nl;b.a=null;b.a=a.a;a=b}return a},function(a,b){return a===b?!0:null===a||null===b?!1:a.a!==b.a?!1:!0});H(Nh,51650189,11,hd,ld,md,id,od);H(Nh,53863091,11,rl,tl,ul,sl,vl); +H(R,30929027,11,function(){return new Dk},function(){},function(a,b){for(;u(b);)switch(b.a){case 1:a.a=y(b);break;default:x(b)}},function(a){if(null===a)a=null;else{var b=new Dk;b.a=null;b.a=a.a;a=b}return a},function(a,b){return a===b?!0:null===a||null===b?!1:a.a!==b.a?!1:!0}); +H(R,66786615,11,function(){return new Ek},function(){},function(a,b){for(;u(b);)switch(b.a){case 1:var c=y(b);a.b=c;break;case 2:c=new Zf;G(b,c,dg);a.a=c;break;case 3:c=y(b);a.c=c;break;default:x(b)}},function(a){if(null===a)a=null;else{var b=new Ek;b.b=null;var c=b.a;c&&cg(c);b.a=null;b.c=null;b.b=a.b;b.a=a.a?bg(a.a):null;b.c=a.c;a=b}return a},function(a,b){return a===b?!0:null===a||null===b?!1:a.b===b.b&&eg(a.a,b.a)&&a.c===b.c?!0:!1});H(R,28517612,11,Nk,Pk,Qk,Ok,Rk); +H(R,30511227,11,function(){return new Ji},function(){},function(a,b){for(;u(b);)switch(b.a){case 1:var c=new Ei;G(b,c,Hi);a.a=c;break;case 3:c=new Ki;G(b,c,Li);a.b=c;break;default:x(b)}},function(a){if(null===a)a=null;else{var b=new Ji,c=b.a;c&&Gi(c);b.a=null;b.b=null;b.a=a.a?Fi(a.a):null;b.b=a.b?new Ki:null;a=b}return a},function(a,b){if(a===b)b=!0;else if(null===a||null===b)b=!1;else{var c;if(c=Ii(a.a,b.a))a=a.b,b=b.b,c=a===b?!0:null===a||null===b?!1:!0;b=c?!0:!1}return b}); +H(R,30096869,11,Vk,Xk,Yk,Wk,al); +H(R,172661375,11,function(){return new bl},function(){},function(a,b){for(;u(b);)switch(b.a){case 1:var c=A(b);a.f=c;break;case 2:c=A(b);a.g=c;break;case 3:c=A(b);a.c=c;break;case 4:c=B(b);a.b=c;break;case 5:c=B(b);a.h=c;break;case 6:c=z(b);a.a=c;break;default:x(b)}},function(a){if(null===a)a=null;else{var b=new bl;b.f=null;b.g=null;b.c=null;b.b=null;b.h=null;b.a=null;b.f=a.f;b.g=a.g;b.c=a.c;b.b=a.b;b.h=a.h;b.a=a.a;a=b}return a},function(a,b){return a===b?!0:null===a||null===b?!1:a.f!==b.f||a.g!== +b.g||a.c!==b.c||a.b!==b.b||a.h!==b.h||a.a!==b.a?!1:!0});H(R,33356690,11,function(){return new ol},function(){},function(a,b){for(;u(b);)switch(b.a){case 1:a.a=C(b);break;default:x(b)}},function(a){if(null===a)a=null;else{var b=new ol;b.a=null;b.a=a.a;a=b}return a},function(a,b){return a===b?!0:null===a||null===b?!1:a.a!==b.a?!1:!0}); +H(R,40251317,11,function(){return new Fk},function(){},function(a,b){for(;u(b);)switch(b.a){case 1:var c=y(b);a.a=c;break;case 2:c=y(b);a.b=c;break;default:x(b)}},function(a){if(null===a)a=null;else{var b=new Fk;b.a=null;b.b=null;b.a=a.a;b.b=a.b;a=b}return a},function(a,b){return a===b?!0:null===a||null===b?!1:a.a!==b.a||a.b!==b.b?!1:!0}); +H(R,43229016,11,function(){return new Di},function(){},function(a,b){for(;u(b);)switch(b.a){case 1:var c=D(b);a.g=c;break;case 2:c=A(b);a.b=c;break;case 3:c=A(b);a.c=c;break;case 4:c=y(b);a.h=c;break;case 5:c=A(b);a.f=c;break;case 6:c=A(b);a.a=a.a||[];a.a.push(c);break;default:x(b)}},function(a){if(null===a)a=null;else{var b=new Di;b.g=null;b.b=null;b.c=null;b.h=null;b.f=null;b.a=null;b.g=a.g;b.b=a.b;b.c=a.c;b.h=a.h;b.f=a.f;b.a=I(a.a);a=b}return a},function(a,b){return a===b?!0:null===a||null===b? +!1:a.g===b.g&&a.b===b.b&&a.c===b.c&&a.h===b.h&&a.f===b.f&&L(a.a,b.a)?!0:!1});H(R,51650189,11,hd,ld,md,id,od);H(R,40154408,11,il,kl,ll,jl,ml); +H(R,60681369,11,function(){return new Ci},function(){},function(a,b){for(;u(b);)switch(b.a){case 1:var c=A(b);a.a=c;break;case 2:c=A(b);a.b=c;break;case 3:c=A(b);a.c=c;break;default:x(b)}},function(a){if(null===a)a=null;else{var b=new Ci;b.a=null;b.b=null;b.c=null;b.a=a.a;b.b=a.b;b.c=a.c;a=b}return a},function(a,b){return a===b?!0:null===a||null===b?!1:a.a!==b.a||a.b!==b.b||a.c!==b.c?!1:!0}); +H(R,135491995,11,function(){return new Bi},function(){},function(a,b){for(;u(b);)switch(b.a){case 1:var c=A(b);a.c=c;break;case 2:c=E(b);a.g=c;break;case 3:c=A(b);a.b=c;break;case 4:c=z(b);a.f=c;break;case 5:c=A(b);a.a=c;break;default:x(b)}},function(a){if(null===a)a=null;else{var b=new Bi;b.c=null;b.g=null;b.b=null;b.f=null;b.a=null;b.c=a.c;b.g=a.g;b.b=a.b;b.f=a.f;b.a=a.a;a=b}return a},function(a,b){return a===b?!0:null===a||null===b?!1:a.c!==b.c||a.g!==b.g||a.b!==b.b||a.f!==b.f||a.a!==b.a?!1:!0}); +H(R,137907910,11,function(){return new yi},function(){},function(a,b){for(;u(b);)switch(b.a){case 2:var c=new zi;G(b,c,Ai);a.a=c;break;case 3:c=C(b);a.b=c;break;default:x(b)}},function(a){if(null===a)a=null;else{var b=new yi,c=b.a;c&&(c.a=null,c.b=null);b.a=null;b.b=null;if(a.a){c=a.a;var d=new zi;d.a=null;d.b=null;d.a=c.a;d.b=c.b;c=d}else c=null;b.a=c;b.b=a.b;a=b}return a},function(a,b){if(a===b)a=!0;else if(null===a||null===b)a=!1;else{var c=a.a,d=b.a;a=c!==d&&(null===c||null===d||c.a!==d.a||c.b!== +d.b)||a.b!==b.b?!1:!0}return a});H(R,53863091,11,rl,tl,ul,sl,vl);H(R,42466818,11,Kg,Ng,Og,Lg,Qg);H(Zh,53863091,11,rl,tl,ul,sl,vl);H(Zh,85448653,11,xg,Dg,Eg,yg,Hg);H(U,69077470,8);H(Zh,36512758,8);function wl(a){return 255<a&&xl[a]?xl[a]:a}var xl,V=[];V[8364]=128;V[8218]=130;V[402]=131;V[8222]=132;V[8230]=133;V[8224]=134;V[8225]=135;V[710]=136;V[8240]=137;V[352]=138;V[8249]=139;V[338]=140;V[381]=142;V[8216]=145;V[8217]=146;V[8220]=147;V[8221]=148;V[8226]=149;V[8211]=150;V[8212]=151;V[732]=152;V[8482]=153;V[353]=154;V[8250]=155;V[339]=156;V[382]=158;V[376]=159;xl=V;function yl(){this.b=2;this.a=0;this.c=-1;this.g=0;this.f=da}var zl=function(){if(!Ea||Oa(12))return!1;if(Oa(11)){var a=new Uint8Array(1);a[0]=128;a=l.URL.createObjectURL(new Blob([a]));var b=new XMLHttpRequest;b.open("GET",a,!1);b.overrideMimeType("application/octet-stream; charset=x-user-defined");b.send();l.URL.revokeObjectURL(a);if(128==(b.responseText.charCodeAt(0)&255))return!1}return!0}(); +function Al(a,b){for(a.g=b.length;;)switch(a.b){case 2:var c=a;b.length<c.a+4?c=!1:"X"!=b[c.a]||"H"!=b[c.a+1]||"R"!=b[c.a+2]||"1"!=b[c.a+3]?(c.b=1,c=!1):(c.a+=4,c.b=3,c=!0);if(!c)return!1;break;case 3:c=a;b.length<c.a+4?c=!1:(c.c=Bl(b,c.a)<<24|Bl(b,c.a+1)<<16|Bl(b,c.a+2)<<8|Bl(b,c.a+3),c.a+=4,0>c.c?(c.b=1,c=!1):(c.b=4,c=!0));if(!c)return!1;break;case 4:return b.length<a.a+a.c?b=!1:(a.f(b.substr(a.a,a.c)),a.a+=a.c,a.c=-1,a.b=3,b=b.length>a.a),b?!0:!1;default:return!1}} +function Bl(a,b){return zl?wl(a.charCodeAt(b)):a.charCodeAt(b)&255};function Cl(){};function Dl(a,b){this.o=a;this.l=b;this.m=1;this.a=El(this);this.f="";this.i=500;this.c=!1;this.b=null;this.g=0;this.h=!1}function Fl(a,b,c){m(c)&&(a.m=c);a.h=!0;Pb(a.a,b,void 0,void 0);a.h=!1}function Gl(a){return a.a?Xb(a.a):a.i}Dl.prototype.cancel=function(){var a=this.a;Hl(this,!1);a&&a.abort()}; +function El(a){var b=new Mb;b.m=Math.max(0,0);kb(b,"readystatechange",function(){Il(this,!1)},void 0,a);kb(b,"success",function(){Il(this,!0)},void 0,a);kb(b,"error",a.j,void 0,a);kb(b,"abort",a.j,void 0,a);return b}function Il(a,b){b&&Hl(a,!0);if(!(a.c||null!==a.b||a.h&&0==(a.a?Zb(a.a):a.f).length)){var c=ja();!b&&10>c-a.g?a.b=l.setTimeout(function(){Jl(a)},a.g+10-c):Jl(a)}}function Jl(a){a.b=null;for(var b=a.start();b!==Cl;)b=b.apply(a)} +Dl.prototype.start=function(){this.g=ja();if(this.o())return this.start;this.c=!1;return Cl};Dl.prototype.j=function(){this.l();Hl(this,!1)};function Hl(a,b){!b&&a.c&&(a.c=!1,(void 0).mb(a));null!=a.b&&(l.clearTimeout(a.b),a.b=null);if(a.a){a.f=Zb(a.a);a.i=Xb(a.a);if(b=a.a)if($a(b))b.U&&gb(b.U);else if(b=pb(b)){var c=0,d;for(d in b.a)for(var e=b.a[d].concat(),f=0;f<e.length;++f)ub(e[f])&&++c}a.a=null}};function Kl(a){this.i=!!a;this.f=this.a=this.b=null;this.c=new yl}function Ll(a,b,c,d,e){a.b=new Dl(n(a.g,a),n(a.h,a));a.a=e||null;a.c.f=c;a.f=d||da;if(e){var f=a.b;ac(e,function(){f.cancel();return!0})}a.b.a.o=a.i;Fl(a.b,b,e?1:void 0)}Kl.prototype.g=function(){if(null!=this.a&&3==this.a.a)return!1;var a=this.b;a=Al(this.c,a.a?Zb(a.a):a.f);!a&&null===this.b.a&&Ml(this);return a};Kl.prototype.h=function(){null!=this.a&&3==this.a.a||Ml(this)}; +function Ml(a){var b=a.c;if(3!=b.b||b.g>b.a||!Bb(Gl(a.b)))switch(Gl(a.b)){case 400:a.a&&bc(a.a,4);break;case 404:a.a&&bc(a.a,5);break;default:a.a&&bc(a.a,2)}a.f()};function Nl(a,b){a=new Uint8Array(a,0,a.byteLength);if(4>a.length||88!=a[0]||72!=a[1]||82!=a[2]||49!=a[3])return!1;for(var c=4;c+4<a.length;){var d=a[c]<<24|a[c+1]<<16|a[c+2]<<8|a[c+3];c+=4;if(c+d>a.length)break;b(a.subarray(c,c+d));c+=d}return c!=a.length?!1:!0};function Ol(a,b){b=m(b)?b:0;a.buffer?Pl(a.buffer,a.byteOffset+b,a.length-b):Pl(a,b,a.byteLength-b)}function Pl(a,b,c){c=b+c;var d=b+3&-4,e=c&-4;if(e>d){var f=e-d>>2,g=new Uint8Array(a);for(a=new Int32Array(a,d,f);b<d;b++)g[b]^=155;for(b=0;b<f;b++)a[b]^=2610666395;b=e}else g=new Uint8Array(a);for(;b<c;b++)g[b]^=155};function Ql(){this.h=new Uint32Array(3072);this.g=0;this.f=new Int32Array(1024);this.a=0;this.c=[];this.b=0;this.i=!1}Ql.prototype.reset=function(){this.a=this.g=0;this.i=!1;this.b=0};function Rl(a){a.a=0;a.b=0}function Sl(a){a.a=0;a.b=0}function Tl(a,b,c){var d=a.a/2,e=0==c?2:1;c=0==c?1:2;for(var f=0;f<d-2;f++)Ul(a,b),Ul(a,(b+f+e)%d),Ul(a,(b+f+c)%d)}function Vl(a,b,c){var d=a.f;var e=a.a+1;e>=d.length&&(e=new Int32Array(2*e),e.set(d),d=e);a.f=d;a.f[a.a]=b;a.f[a.a+1]=c;a.a+=2} +function Ul(a,b){a.i?(a.c[2*a.b]=a.f[2*b],a.c[2*a.b+1]=a.f[2*b+1],a.b=(a.b+1)%3,0==a.b&&Wl(a)):Xl(a,a.f[2*b],a.f[2*b+1])}function Wl(a){function b(a,b,c,d){a=c-a;b=d-b;return a*a+b*b}var c=a.c[0],d=a.c[1],e=a.c[2],f=a.c[3],g=a.c[4],h=a.c[5],r=!1;if(262144<b(c,d,e,f)||262144<b(e,f,g,h)||262144<b(g,h,c,d))r=!0;if(r){r=(c+e+g)/3;var v=(d+f+h)/3;Yl(a,r,v,c,d,e,f);Yl(a,r,v,e,f,g,h);Yl(a,r,v,g,h,c,d)}else Xl(a,c,d),Xl(a,e,f),Xl(a,g,h)} +function Yl(a,b,c,d,e,f,g){f-=d;g-=e;var h=Math.ceil(Math.sqrt(f*f+g*g)/512);f/=h;g/=h;for(var r=0;r<h;r++)Xl(a,b,c),Xl(a,d+f*r,e+g*r),Xl(a,d+f*(r+1),e+g*(r+1))}function Xl(a,b,c){var d=a.h;var e=a.g;e>=d.length&&(e=new Uint32Array(2*e),e.set(d),d=e);a.h=d;d=a.g;a.h[d++]=(b&65535|(c&65535)<<16)>>>0;a.g=d};function W(a){this.length=a.length||a;for(var b=0;b<this.length;b++)this[b]=a[b]||0}W.prototype.a=4;W.prototype.set=function(a,b){b=b||0;for(var c=0;c<a.length&&b+c<this.length;c++)this[b+c]=a[c]};W.prototype.toString=Array.prototype.join;"undefined"==typeof Float32Array&&(W.BYTES_PER_ELEMENT=4,W.prototype.BYTES_PER_ELEMENT=W.prototype.a,W.prototype.set=W.prototype.set,W.prototype.toString=W.prototype.toString,ca("Float32Array",W));function Z(a){this.length=a.length||a;for(var b=0;b<this.length;b++)this[b]=a[b]||0}Z.prototype.a=8;Z.prototype.set=function(a,b){b=b||0;for(var c=0;c<a.length&&b+c<this.length;c++)this[b+c]=a[c]};Z.prototype.toString=Array.prototype.join;if("undefined"==typeof Float64Array){try{Z.BYTES_PER_ELEMENT=8}catch(a){}Z.prototype.BYTES_PER_ELEMENT=Z.prototype.a;Z.prototype.set=Z.prototype.set;Z.prototype.toString=Z.prototype.toString;ca("Float64Array",Z)};function Zl(a,b,c,d,e){if(b[d+1]==b[e+1]){var f=c;c=e;e=f}else b[c+1]==b[e+1]&&(f=d,d=e,e=f);b[c+1]!=b[d+1]&&(b[c+1]>b[d+1]&&(f=c,c=d,d=f),b[d+1]>b[e+1]&&(f=d,d=e,e=f),b[c+1]>b[d+1]&&(f=c,c=d,d=f));f=b[c];var g=b[d],h=b[e];c=b[c+1];d=b[d+1];b=b[e+1];c!=b&&(e=f+(d-c)/(b-c)*(h-f),$l(a,Math.min(e,g),h,Math.max(e,g),d,b),c!=d&&$l(a,Math.min(e,g),f,Math.max(e,g),d,c))} +function $l(a,b,c,d,e,f){var g=(c-b)/(f-e);c=(c-d)/(f-e);var h=Math.min(e,f);f=Math.max(e,f);h=Math.max(0,Math.floor(.999+h));for(f=Math.min(255,Math.floor(f));h<=f;h++){var r=h-e,v=b+g*r;r=d+c*r;v=Math.max(0,Math.floor(.999+v));for(r=Math.min(255,Math.floor(r));v<=r;v++)a[256*h+v]=255}};var am=Math.pow(2,22);function bm(){this.a=this.b=this.c=null}bm.prototype.getExtension=function(){return null};H(vi,96629873,11,function(){return new bm},function(){},function(a,b){for(;u(b);)switch(b.a){case 1:var c=y(b);a.c=c;break;case 2:c=z(b);a.b=c;break;case 3:c=z(b);a.a=c;break;default:x(b)}},function(a){if(null===a)a=null;else{var b=new bm;b.c=null;b.b=null;b.a=null;b.c=a.c;b.b=a.b;b.a=a.a;a=b}return a},function(a,b){return a===b?!0:null===a||null===b?!1:a.c!==b.c||a.b!==b.b||a.a!==b.a?!1:!0});new function(){};function cm(a){return(a=a.exec(sa))?a[1]:""}(function(){if(nc)return cm(/Firefox\/([0-9.]+)/);if(Ea||Fa||Da)return Na;if(rc)return ya()||p("iPad")||p("iPod")?cm(/CriOS\/([0-9.]+)/):cm(/Chrome\/([0-9.]+)/);if(sc&&!(ya()||p("iPad")||p("iPod")))return cm(/Version\/([0-9.]+)/);if(oc||pc){var a=/Version\/(\S+).*Mobile\/(\S+)/.exec(sa);if(a)return a[1]+"."+a[2]}else if(qc)return(a=cm(/Android\s+([0-9.]+)/))?a:cm(/Version\/([0-9.]+)/);return""})();function dm(a){var b=a.getExtension(96629873);if(b&&(null==b.a?0:b.a))return am;(b=null==a.f)||(b=null==wi(a).a);if(b)return 16;a=wi(a);switch(null==a.a?0:a.a){case 0:return 16;case 2:return 4;case 3:return 8;case 1:return 16;case 4:return 32;case 5:return 64;case 6:return 128;default:return 16}} +function em(a,b){function c(a,c,d){var e=1;c&&(e+=c.length);for(var f=0,g=0,h=0,r=0;r<e;r++){var v=-1;c&&r<e-1&&(v=c[r]);if(a.V())break;for(d?Sl(b):b.a=0;!a.V()&&f!=v;)g+=Kc(a),h+=Kc(a),Vl(b,g,h),f++;if(d)Tl(b,0,1);else{v=b;for(var S=v.a/2,K=0;K<S-2;K++){var T=K%2;Ul(v,K);Ul(v,K+1+T);Ul(v,K+2-T)}}}}if(null!=a.g||null!=a.f||null!=a.b||null!=a.c){b.i=!1;if(null!=a.g||null!=a.f){var d=null!=a.f?!0:!1;d?Sl(b):Rl(b);for(var e=0,f=0,g=Qh(a);!g.V();)e+=Kc(g),f+=Kc(g),Vl(b,e,f);Ec(g);if(null!=a.g){for(e= +$c(a.a,a.g,a.B);!e.V();)Ul(b,e.next());Dc(e)}d&&Tl(b,null==a.f?-1:a.f,0)}null!=a.b&&(d=Rh(a),e=null!=a.l||null!=a.i?Sh(a):null,c(d,e,!0),Ec(d));null!=a.c&&(d=Th(a),a=null!=a.m||null!=a.j?Uh(a):null,c(d,a,!1),Ec(d))}};function fm(){this.a=new Ql};function gm(a,b){b=m(b)?b:0;var c=m(void 0)?void 0:a.byteLength-b;this.a=new Uint8Array(a,b,c);new Int8Array(a,b,c)}function hm(a,b){return a.a[b]+(a.a[b+1]<<8)+(a.a[b+2]<<16)+16777216*a.a[b+3]};/* + + Copyright 2012 Mozilla Foundation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +function im(){this.b=this.i=0;this.h=!1;this.buffer=null}function jm(a,b){var c=a.buffer,d=c?c.byteLength:0;if(b<d)return c;for(var e=512;e<b;)e<<=1;b=new Uint8Array(e);if(c)for(e=0;e<d;++e)b[e]=c[e];return a.buffer=b}function km(a){for(var b,c=a.i;!a.h;)lm(a);b=a.b;b||(a.buffer=new Uint8Array(0));a.i=b;return a.buffer.subarray(c,b)}im.prototype.reset=function(){this.i=0};function mm(a){this.g=null;this.c=this.f=this.a=0;a&&nm(this,a);im.call(this)}ka(mm,im); +function nm(a,b){var c=0;c++;c++;a.g=b;a.a=c;a.f=0;a.c=0;a.i=0;a.b=0;a.h=!1}function om(a,b){this.a=a;this.b=b} +var pm=new Uint32Array([16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]),qm=new Uint8Array(pm.length),rm=new Uint8Array(320),sm=new Uint32Array(512),tm=new Uint32Array(512),um=new Uint32Array(512),vm=new Uint32Array([3,4,5,6,7,8,9,10,65547,65549,65551,65553,131091,131095,131099,131103,196643,196651,196659,196667,262211,262227,262243,262259,327811,327843,327875,327907,258,258,258]),wm=new Uint32Array([1,2,3,4,65541,65543,131081,131085,196625,196633,262177,262193,327745,327777,393345,393409,459009, +459137,524801,525057,590849,591361,657409,658433,724993,727041,794625,798721,868353,876545]),xm=new om(new Uint32Array([459008,524368,524304,524568,459024,524400,524336,590016,459016,524384,524320,589984,524288,524416,524352,590048,459012,524376,524312,589968,459028,524408,524344,590032,459020,524392,524328,59E4,524296,524424,524360,590064,459010,524372,524308,524572,459026,524404,524340,590024,459018,524388,524324,589992,524292,524420,524356,590056,459014,524380,524316,589976,459030,524412,524348, +590040,459022,524396,524332,590008,524300,524428,524364,590072,459009,524370,524306,524570,459025,524402,524338,590020,459017,524386,524322,589988,524290,524418,524354,590052,459013,524378,524314,589972,459029,524410,524346,590036,459021,524394,524330,590004,524298,524426,524362,590068,459011,524374,524310,524574,459027,524406,524342,590028,459019,524390,524326,589996,524294,524422,524358,590060,459015,524382,524318,589980,459031,524414,524350,590044,459023,524398,524334,590012,524302,524430,524366, +590076,459008,524369,524305,524569,459024,524401,524337,590018,459016,524385,524321,589986,524289,524417,524353,590050,459012,524377,524313,589970,459028,524409,524345,590034,459020,524393,524329,590002,524297,524425,524361,590066,459010,524373,524309,524573,459026,524405,524341,590026,459018,524389,524325,589994,524293,524421,524357,590058,459014,524381,524317,589978,459030,524413,524349,590042,459022,524397,524333,590010,524301,524429,524365,590074,459009,524371,524307,524571,459025,524403,524339, +590022,459017,524387,524323,589990,524291,524419,524355,590054,459013,524379,524315,589974,459029,524411,524347,590038,459021,524395,524331,590006,524299,524427,524363,590070,459011,524375,524311,524575,459027,524407,524343,590030,459019,524391,524327,589998,524295,524423,524359,590062,459015,524383,524319,589982,459031,524415,524351,590046,459023,524399,524335,590014,524303,524431,524367,590078,459008,524368,524304,524568,459024,524400,524336,590017,459016,524384,524320,589985,524288,524416,524352, +590049,459012,524376,524312,589969,459028,524408,524344,590033,459020,524392,524328,590001,524296,524424,524360,590065,459010,524372,524308,524572,459026,524404,524340,590025,459018,524388,524324,589993,524292,524420,524356,590057,459014,524380,524316,589977,459030,524412,524348,590041,459022,524396,524332,590009,524300,524428,524364,590073,459009,524370,524306,524570,459025,524402,524338,590021,459017,524386,524322,589989,524290,524418,524354,590053,459013,524378,524314,589973,459029,524410,524346, +590037,459021,524394,524330,590005,524298,524426,524362,590069,459011,524374,524310,524574,459027,524406,524342,590029,459019,524390,524326,589997,524294,524422,524358,590061,459015,524382,524318,589981,459031,524414,524350,590045,459023,524398,524334,590013,524302,524430,524366,590077,459008,524369,524305,524569,459024,524401,524337,590019,459016,524385,524321,589987,524289,524417,524353,590051,459012,524377,524313,589971,459028,524409,524345,590035,459020,524393,524329,590003,524297,524425,524361, +590067,459010,524373,524309,524573,459026,524405,524341,590027,459018,524389,524325,589995,524293,524421,524357,590059,459014,524381,524317,589979,459030,524413,524349,590043,459022,524397,524333,590011,524301,524429,524365,590075,459009,524371,524307,524571,459025,524403,524339,590023,459017,524387,524323,589991,524291,524419,524355,590055,459013,524379,524315,589975,459029,524411,524347,590039,459021,524395,524331,590007,524299,524427,524363,590071,459011,524375,524311,524575,459027,524407,524343, +590031,459019,524391,524327,589999,524295,524423,524359,590063,459015,524383,524319,589983,459031,524415,524351,590047,459023,524399,524335,590015,524303,524431,524367,590079]),9),ym=new om(new Uint32Array([327680,327696,327688,327704,327684,327700,327692,327708,327682,327698,327690,327706,327686,327702,327694,0,327681,327697,327689,327705,327685,327701,327693,327709,327683,327699,327691,327707,327687,327703,327695,0]),5); +function zm(a,b){for(var c=a.f,d=a.c,e=a.g,f=a.a,g;c<b;)g=e[f++],d|=g<<c,c+=8;a.c=d>>b;a.f=c-b;a.a=f;return d&(1<<b)-1}function Am(a,b){var c=b.a,d=b.b;b=a.f;for(var e=a.c,f=a.g,g=a.a;b<d;){var h=f[g++];e|=h<<b;b+=8}c=c[e&(1<<d)-1];d=c>>16;a.c=e>>d;a.f=b-d;a.a=g;return c&65535} +function Bm(a,b,c,d){for(var e=0,f=b;f<c;++f)a[f]>e&&(e=a[f]);var g=1<<e;d=g<=d.length?d:new Uint32Array(g);for(var h=1,r=0,v=2;h<=e;++h,r<<=1,v<<=1)for(var F=b;F<c;++F)if(a[F]==h){var X=0,N=r;for(f=0;f<h;++f)X=X<<1|N&1,N>>=1;for(f=X;f<g;f+=v)d[f]=h<<16|F-b;++r}return new om(d,e)} +function lm(a){var b=zm(a,3);b&1&&(a.h=!0);b>>=1;if(0==b){b=a.g;var c=a.a,d,e=d=b[c++];d=b[c++];e|=d<<8;c++;c++;a.c=0;a.f=0;d=a.b;var f=jm(a,d+e);e=d+e;a.b=e;for(var g=d;g<e;++g){if("undefined"==typeof(d=b[c++])){a.h=!0;break}f[g]=d}a.a=c}else{c=xm;d=ym;if(1!=b&&2==b){f=zm(a,5)+257;e=zm(a,5)+1;b=zm(a,4)+4;for(c=0;c<qm.length;++c)qm[c]=0;for(c=0;c<b;++c)qm[pm[c]]=zm(a,3);d=Bm(qm,0,qm.length,sm);c=b=0;for(e=f+e;c<e;){g=Am(a,d);if(16==g){var h=2,r=3;g=b}else if(17==g)r=h=3,g=b=0;else if(18==g)h=7,r= +11,g=b=0;else{rm[c++]=b=g;continue}for(h=zm(a,h)+r;0<h--;)rm[c++]=g}c=Bm(rm,0,f,tm);d=Bm(rm,f,e,um)}e=(f=a.buffer)?f.length:0;for(g=a.b;;)if(h=Am(a,c),256>h)g+1>=e&&(f=jm(a,g+1),e=f.length),f[g++]=h;else{if(256==h){a.b=g;break}h-=257;h=vm[h];r=h>>16;0<r&&(r=zm(a,r));b=(h&65535)+r;h=Am(a,d);h=wm[h];r=h>>16;0<r&&(r=zm(a,r));h=(h&65535)+r;g+b>=e&&(f=jm(a,g+b),e=f.length);for(r=0;r<b;++r,++g)f[g]=f[g-h]}}};/* + + MIT LICENSE + Copyright (c) 2011 Devon Govett + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +function Cm(){this.v=new mm;this.data=new Uint8Array(0);this.a=8;this.g=[];this.o=null;this.b={};this.h=null;this.w={};this.j=this.s=0;this.m=null;this.c=this.l=this.f=this.height=this.width=0;this.i=!1;this.u=0} +function Dm(a){for(var b=null;;){var c=Em(a),d=a,e=String.fromCharCode(d.data[d.a++]);e+=String.fromCharCode(d.data[d.a++]);e+=String.fromCharCode(d.data[d.a++]);e+=String.fromCharCode(d.data[d.a++]);switch(e){case "IHDR":c=a;c.width=Em(c);c.height=Em(c);c.l=c.data[c.a++];c.c=c.data[c.a++];c.a++;c.a++;c.a++;break;case "acTL":c=a;c.h={kb:Em(c),lb:Em(c)||Infinity,frames:[]};break;case "PLTE":d=a;d.s=d.a;d.j=c;d.a+=c;break;case "fcTL":b&&a.h.frames.push(b);b=a;b.a+=4;c={width:Em(b),height:Em(b),ob:Em(b), +pb:Em(b)};d=Fm(b);e=Fm(b)||100;c.hb=1E3*d/e;c.ib=b.data[b.a++];c.fb=b.data[b.a++];c.gb=[];b=c;break;case "fdAT":a.a+=4,c-=4;case "IDAT":d=a;if(b){e=b.data;for(var f=0;f<c;f++)e.push(d.data[d.a++])}else d.g.push(d.a),d.g.push(c),d.a+=c;break;case "tRNS":d=a;d.b={};switch(d.c){case 3:e=c;255>e&&(e=255);d.b.Ma=Array(e);for(f=0;f<c;f++)d.b.Ma[f]=d.data[d.a++];for(f=c;f<e;f++)d.b.Ma[f]=255;break;case 0:d.b.jb=Gm(d,c)[0];break;case 2:d.b.nb=Gm(d,c)}break;case "tEXt":d=a;c=Gm(d,c);e=c.indexOf(0);d.w[String.fromCharCode.apply(String, +c.slice(0,e))]=String.fromCharCode.apply(String,c.slice(e+1));break;case "IEND":b&&a.h.frames.push(b);b=void 0;switch(a.c){case 0:case 3:case 4:a.f=1;break;case 2:case 6:a.f=3}a.i=4===(b=a.c)||6===b;a.u=a.l*(a.f+(a.i?1:0));b=a.g;if(2==b.length)d=new Uint8Array(a.data.buffer.slice(a.data.byteOffset+b[0],a.data.byteOffset+b[0]+b[1]));else{d=0;for(c=1;c<b.length;c+=2)d+=b[c];d=new Uint8Array(d);e=0;f=a.data;for(c=0;c<b.length;c+=2)for(var g=b[c],h=b[c+1],r=0;r<h;r++)d[e++]=f[g+r]}a.o=d;a.g=[];return; +default:a.a+=c}a.a+=4;if(a.a>a.data.length)throw Error("Incomplete or corrupt PNG file");}}function Gm(a,b){for(var c=Array(b),d=0;d<b;d++)c[d]=a.data[a.a++];return c}function Em(a){var b=a.data[a.a++]<<24;var c=a.data[a.a++]<<16;var d=a.data[a.a++]<<8;a=a.data[a.a++];return b|c|d|a}function Fm(a){var b=a.data[a.a++]<<8;a=a.data[a.a++];return b|a} +function Hm(a){var b=null,c,d,e,f,g,h,r,v,F,X;null==b&&(b=a.o);if(0===b.length)return new Uint8Array(0);nm(a.v,b);var N=a.v;N=km(N);b=a.u/8;var Y=b*a.width;var O=new Uint8Array(Y*a.height);var Jm=N.length;for(c=e=f=0;e<Jm;){switch(N[e++]){case 0:for(h=0;h<Y;h+=1)O[c++]=N[e++];break;case 1:for(d=r=0;r<Y;d=r+=1){a=N[e++];var S=d<b?0:O[c-b];O[c++]=(a+S)%256}break;case 2:for(d=v=0;v<Y;d=v+=1){a=N[e++];var K=(d-d%b)/b;var T=f&&O[(f-1)*Y+K*b+d%b];O[c++]=(T+a)%256}break;case 3:for(d=F=0;F<Y;d=F+=1)a=N[e++], +K=(d-d%b)/b,S=d<b?0:O[c-b],T=f&&O[(f-1)*Y+K*b+d%b],O[c++]=(a+Math.floor((S+T)/2))%256;break;case 4:for(d=X=0;X<Y;d=X+=1){a=N[e++];K=(d-d%b)/b;S=d<b?0:O[c-b];0===f?T=g=0:(T=O[(f-1)*Y+K*b+d%b],g=K&&O[(f-1)*Y+(K-1)*b+d%b]);var Aa=S+T-g;K=Math.abs(Aa-S);d=Math.abs(Aa-T);Aa=Math.abs(Aa-g);S=K<=d&&K<=Aa?S:d<=Aa?T:g;O[c++]=(a+S)%256}break;default:throw Error("Invalid filter algorithm: "+N[e-1]);}f++}return O} +function Im(a){var b=a.s,c=a.data,d=a.b.Ma||null;a=a.j;for(var e=new Uint8Array(a/3*4),f=0,g=0,h=0;h<a;h+=3)e[f++]=c[b+h],e[f++]=c[b+h+1],e[f++]=c[b+h+2],e[f++]=d?d[g++]:255;return e} +function Km(a,b,c){var d=a.f;var e=null;var f=a.i;a.j&&(e=a.m=a.m||Im(a),d=4,f=!0);a=b.length;if(1===d)if(e)if(f)for(f=d=0;d<a;d+=4,f++){var g=4*c[f];var h=e[g];b[d]=h;b[d+1]=h;b[d+2]=h;b[d+3]=e[g+1]}else for(f=d=0;d<a;d+=4,f++)g=4*c[f],h=e[g],b[d]=h,b[d+1]=h,b[d+2]=h,b[d+3]=255;else if(f)for(f=d=0;d<a;d+=4,f+=2)h=c[f],b[d]=h,b[d+1]=h,b[d+2]=h,b[d+3]=c[f+1];else for(f=d=0;d<a;d+=4,f++)h=c[f],b[d]=h,b[d+1]=h,b[d+2]=h,b[d+3]=255;else if(e)if(f)for(f=d=0;d<a;d+=4,f++)g=4*c[f],b[d]=e[g],b[d+1]=e[g+1], +b[d+2]=e[g+2],b[d+3]=e[g+3];else for(f=d=0;d<a;d+=4,f++)g=4*c[f],b[d]=e[g],b[d+1]=e[g+1],b[d+2]=e[g+2],b[d+3]=255;else if(f)for(d=0;d<a;d+=4)b[d]=c[d],b[d+1]=c[d+1],b[d+2]=c[d+2],b[d+3]=c[d+3];else for(f=d=0;d<a;d+=4,f+=3)b[d]=c[f],b[d+1]=c[f+1],b[d+2]=c[f+2],b[d+3]=255};function Lm(a){this.c=a;this.f=this.b=null;this.a=this.Va;a=n(this.Ya,this);this.c.a=a}var Mm=null,Nm=null,kc=null;k=Lm.prototype;k.Ya=function(){this.b&&this.b.cancel();this.f&&this.f.abort();return!0}; +function Om(a,b){var c=b.g;if(b.a||!kc||!lc(kc,c,n(a.Va,a))){var d=b.h;if(b.f)d=new Kl(d),a.b=new $b,Ll(d,c,n(a.$a,a,b),n(a.ab,a),a.b);else{var e=new Mb;a.f=e;e.o=d;e.g="arraybuffer";kb(e,"readystatechange",function(){if(Yb(e)&&4==Wb(e)){var c=e.Ia();if(b.c)Pm(a,c);else{var d=new ec;d.b=0;d.c=0;if(c&&0<c.byteLength){d.a=c;var h=[c];Qm(c,b,d,h)}d.status=1;a.a(d,!0,h)}}});kb(e,"error",a.bb,!1,a);Pb(e,c)}b.a&&(kc||(kc=new hc),a.a=ic(c,a.b,a.f))}} +k.$a=function(a,b){var c=new ec;c.status=1;c.b=Bl(b,0);c.c=Bl(b,1);var d=m(void 0)?NaN:b.length;d>b.length&&(d=b.length);if(2>=d||2>=b.length)b=null;else{var e=new Uint8Array(d-2);if(zl)for(var f=2;f<d;++f)e[f-2]=wl(b.charCodeAt(f));else for(f=2;f<d;++f)e[f-2]=b.charCodeAt(f)&255;b=e.buffer}if(b&&0<b.byteLength){c.a=b;var g=[b];Qm(b,a,c,g)}this.a(c,!1,g)};k.ab=function(){var a=new ec;a.status=this.b.a;this.a(a,!0)}; +function Pm(a,b){var c=[],d=Nl(b,function(a){c.push(a);2<a.length&&Ol(a,2)}),e=new ec;d?(e.status=1,e.h=c,a.a(e,!0,[b])):(e.status=2,a.a(e,!0))} +function Qm(a,b,c,d){Ol(a);var e=b.b&2;b=b.b&4;if(e||b){var f=new Mh;a=Qc(a);ui(f,a);Rc(a);if(e){if(null!=f.c){null===f.c&&(f.c=new zh);e=f.c;var g;null!=e.Ka&&null==e.Na&&(e.Na=cd(e.Ra,e.Ka,e.Sa));if(g=e.Na)c.i=Rm(g,d)}if(null!=f.b){e=c.f=[];null===f.b&&(f.b=new Jh);a=f.b;for(var h=0;h<(a.a?a.a.length:0);h++)if(g=a.a[h].getImageData())g=Rm(g,d),e[h]=g}}if(b){null===f.g&&(f.g=new mh);b=f.g;if(12>(null==b.Oa?0:b.Oa)){Nm||(Nm=new fm);b=Nm;a=null;e=[];if(h=null!=f.a?!0:!1)h=null!=xi(f).a?!0:!1;if(h)for(h= +xi(f).a,g=0;g<h.length;g++){var r=h[g],v=r.getExtension(177034656);v&&(null==v.a?0:v.a)&&(null==r.c||!r.c)&&null!=r.a&&e.push(Wh(r))}if(e.length)b:{f=dm(f);a=new Uint8Array(65536);for(h=0;h<e.length;h++){r=e[h];v=b.a;g=f;v.reset();em(r,v);r=v.h.subarray(0,v.g);if(0==r.length)r=null;else{v=new Float32Array(2*r.length);for(var F=0;F<r.length;F++){var X=r[F];v[2*F+0]=(X<<16>>16)/g;v[2*F+1]=(X>>16)/g}r=v}if(!r){a=null;break b}v=r.length/6;if(0!=v)for(g=a,v=v?6*v:r.length,F=0;F<v;F+=6)Zl(g,r,F,F+2,F+4)}a= +new cc(a,256,256,4)}a&&d.push(a.data.buffer);d=a}else d=null;c.g=d}}} +function Rm(a,b){var c=2*(a[0]<<23)+(a[1]<<16)+(a[2]<<8)+a[3];switch(c){case 2303741511:var d="image/png";break;case 4292411360:d="image/jpeg";break;case 1195984440:d="image/gif";break;case 1145328416:d="image/x-dds";break;case 1380533830:d="image/unknown";12<a.length&&(c=2*(a[8]<<23)+(a[9]<<16)+(a[10]<<8)+a[11],1464156752==c&&(d="image/webp"));break;default:d="image/unknown"}switch(d){case "image/x-dds":var e=new gm(a.buffer,a.byteOffset+4),f=hm(e,0)+4;b=hm(e,8);c=hm(e,12);d=hm(e,80);hm(e,76)&4&& +(827611204==d||894720068==d)?(a=new Uint8Array(a.buffer,a.byteOffset+f,a.byteLength-f),a=new cc(a,c,b,827611204==d?2:3)):a=null;return a;case "image/png":return Mm||(Mm=new Cm),c=Mm,c.data=a,c.a=8,c.g=[],c.o=null,c.b={},c.h=null,c.w={},c.s=0,c.j=0,c.m=null,c.width=0,c.height=0,c.f=0,c.l=0,c.c=0,c.i=!1,c.u=0,Dm(c),a=new Uint8Array(c.width*c.height*4),Km(c,a,Hm(c)),b&&b.push(a.buffer),new cc(a,a.length/c.height/4,c.height);default:return null}}k.bb=function(){var a=new ec;a.status=2;this.a(a,!0)}; +k.Va=function(a,b,c){var d={};null!=a.status&&(d.status=a.status);null!=a.b&&(d.prIndex=a.b);null!=a.c&&(d.prStatus=a.c);null!=a.a&&(d.prData=a.a);null!=a.h&&(d.prChunks=a.h);a.i&&(d.spritemapImage=fc(a.i));if(a.f)for(var e=d.rasterRenderOpImages=[],f=0;f<a.f.length;f++)e[f]=fc(a.f[f]);a.g&&(d.computedWaterCoverage=fc(a.g));this.c.postMessage(d,b,c)};function Sm(){var a=self;this.b=a;this.a={};a.onmessage=n(this.f,this);this.c=n(this.g,this);Tm(this,"__worker_started__")} +Sm.prototype.f=function(a){var b=a.data,c=ja();if(a=b.abort){if(b=this.a[a])delete this.a[a],b.abort()||Tm(this,"Cannot abort this task.")}else{var d=b.id;a=b.payload;if(m(d))switch(b.command){case 1:a?(b=new la(d,this.b,this.c),b.b=c,this.a[d]=b,c=new Lm(b),b=new dc,m(a.uri)&&(b.g=a.uri),m(a.xdc)&&(b.h=a.xdc),m(a.streaming)&&(b.f=a.streaming),m(a.chunked)&&(b.c=a.chunked),m(a.deferred)&&(b.a=a.deferred),m(a.workerOptions)&&(b.b=a.workerOptions),Om(c,b)):Tm(this,"Payload required for Xhr command."); +break;case 2:b=new la(d,this.b,this.c);b.b=c;this.a[d]=b;a=c=new Lm(b);kc?(c=kc.a,a.c.postMessage({success:c.b,mismatch:c.a},!0)):a.c.postMessage({},!0);break;default:Tm(this,"Unknown message")}}};function Tm(a,b){var c={};c.logs=[b];a.b.postMessage(c)}Sm.prototype.g=function(a){delete this.a[a]};"undefined"!=typeof WorkerGlobalScope&&new Sm;function Um(){var a=Vm;if("undefined"!=typeof window){var b=function(){return this.getAttribute("src")},c=function(b){b=a.call(this,b);this.setAttribute("src",b)},d=this.a=document.createElement;document.createElement=function(a){var e=d.call(this,a);"IMG"==a.toUpperCase()&&Object.defineProperty(e,"src",{enumerable:!0,configurable:!0,get:b,set:c});return e}}}Um.prototype.h=function(){"undefined"!=typeof window&&(document.createElement=this.a)};function Wm(){var a=Vm,b=this.a=XMLHttpRequest.prototype.open;XMLHttpRequest.prototype.open=function(c,d,e,f,g){for(var h=a.call(this,d),r=Array(arguments.length),v=0;v<r.length;v++)r[v]=1==v?h:arguments[v];b.apply(this,r)}}Wm.prototype.h=function(){XMLHttpRequest.prototype.open=this.a};function Xm(){this.h=this.b=this.g=this.a=this.f=this.c=null}function Ym(){this.a=null}Xm.prototype.getExtension=function(){return null};function Zm(a,b){for(a.h=b.b.b;u(b);)switch(b.a){case 1:var c=A(b);a.c=c;break;case 2:null===a.a&&(a.a=b.c);w(b);a.g=b.b.a;break;case 3:c=A(b);a.b=c;break;case 4:y(b);break;default:x(b)}}Xm.prototype.Ia=function(){null!=this.a&&null==this.f&&(this.f=cd(this.h,this.a,this.g));return this.f};Ym.prototype.getExtension=function(){return null};var $m={},an=null,bn=null;function Vm(a){return $m[a]||a};(function(a,b){an&&an.h();an=new Um;bn&&bn.h();bn=new Wm;for(var c in $m)URL.revokeObjectURL($m[c]);$m={};c=new Mb;c.g="arraybuffer";nb(c,"complete",function(){if(Yb(this)){var a=this.Ia(),c=new Ym;for(a=Qc(a);u(a);)switch(a.a){case 1:var f=new Xm;G(a,f,Zm);c.a=c.a||[];c.a.push(f);break;default:x(a)}Rc(a);for(a=0;a<(c.a?c.a.length:0);a++)f=c.a[a],$m[null==f.c?"":f.c]=URL.createObjectURL(new Blob([f.Ia()],{type:null==f.b?"":f.b}));b()}else throw Error("Failed to load dataset.");});Pb(c,a)})("load_dataset", +function(){self.postMessage("dataset_loaded")});}).call(this);
diff --git a/tools/perf/page_sets/media_cases.py b/tools/perf/page_sets/media_cases.py new file mode 100644 index 0000000..5dae8122 --- /dev/null +++ b/tools/perf/page_sets/media_cases.py
@@ -0,0 +1,339 @@ +# Copyright 2014 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. + +# This file defines performance test scenarios related to playing video and +# audio files using HTML5 APIs (as opposed to older tech like Flash and +# Silverlight). These scenarios simply exercise the Chromium code in particular +# ways. The metrics that are produced are calculated in a separate step. + +from telemetry.page import page as page_module +from telemetry.page import traffic_setting as traffic_setting_module +from telemetry import story + +# A complete list of page tags to check. This prevents misspellings and provides +# documentation of scenarios for code readers. These tags can be used to filter +# the list of pages to run using flags like --story-tag-filter=X. +_PAGE_TAGS_LIST = [ + # Audio codecs. + 'pcm', + 'mp3', + 'aac', + 'vorbis', + 'opus', + # Video codecs. + 'h264', + 'vp8', + 'vp9', + # Test types. + 'audio_video', + 'audio_only', + 'video_only', + # Other filter tags. + 'is_50fps', + 'is_4k', + # Play action. + 'seek', + 'beginning_to_end', + 'background', + # Add javascript load. + 'busyjs', + # Constrained network settings. + 'cns', + # VideoStack API. + 'src', + 'mse' +] + +# A list of traffic setting names to append to page names when used. +# Traffic settings is a way to constrain the network to match real-world +# scenarios. +_TRAFFIC_SETTING_NAMES = { + traffic_setting_module.GPRS: 'GPRS', + traffic_setting_module.REGULAR_2G: 'Regular-2G', + traffic_setting_module.GOOD_2G: 'Good-2G', + traffic_setting_module.REGULAR_3G: 'Regular-3G', + traffic_setting_module.GOOD_3G: 'Good-3G', + traffic_setting_module.REGULAR_4G: 'Regular-4G', + traffic_setting_module.DSL: 'DSL', + traffic_setting_module.WIFI: 'WiFi', +} + +_URL_BASE = 'file://media_cases/' + +# +# The following section contains base classes for pages. +# + +class _MediaPage(page_module.Page): + + def __init__(self, url, page_set, tags, extra_browser_args=None, + traffic_setting=traffic_setting_module.NONE): + name = url.split('/')[-1] + if traffic_setting != traffic_setting_module.NONE: + name += '_' + _TRAFFIC_SETTING_NAMES[traffic_setting] + tags.append('cns') + if tags: + for t in tags: + assert t in _PAGE_TAGS_LIST + assert not ('src' in tags and 'mse' in tags) + super(_MediaPage, self).__init__( + url=url, page_set=page_set, tags=tags, name=name, + extra_browser_args=extra_browser_args, + traffic_setting=traffic_setting) + + +class _BeginningToEndPlayPage(_MediaPage): + """A normal play page simply plays the given media until the end.""" + + def __init__(self, url, page_set, tags, extra_browser_args=None, + traffic_setting=traffic_setting_module.NONE): + tags.append('beginning_to_end') + tags.append('src') + super(_BeginningToEndPlayPage, self).__init__( + url, page_set, tags, extra_browser_args, + traffic_setting=traffic_setting) + + def RunPageInteractions(self, action_runner): + # Play the media until it has finished or it times out. + action_runner.PlayMedia(playing_event_timeout_in_seconds=60, + ended_event_timeout_in_seconds=60) + # Generate memory dump for memoryMetric. + if self.page_set.measure_memory: + action_runner.MeasureMemory() + + +class _SeekPage(_MediaPage): + """A seek page seeks twice in the video and measures the seek time.""" + + def __init__(self, url, page_set, tags, extra_browser_args=None, + action_timeout_in_seconds=60, + traffic_setting=traffic_setting_module.NONE): + tags.append('seek') + tags.append('src') + self._action_timeout = action_timeout_in_seconds + super(_SeekPage, self).__init__( + url, page_set, tags, extra_browser_args, + traffic_setting=traffic_setting) + + def RunPageInteractions(self, action_runner): + timeout = self._action_timeout + # Start the media playback. + action_runner.PlayMedia( + playing_event_timeout_in_seconds=timeout) + # Wait for 1 second so that we know the play-head is at ~1s. + action_runner.Wait(1) + # Seek to before the play-head location. + action_runner.SeekMedia(seconds=0.5, timeout_in_seconds=timeout, + label='seek_warm') + # Seek to after the play-head location. + action_runner.SeekMedia(seconds=9, timeout_in_seconds=timeout, + label='seek_cold') + # Generate memory dump for memoryMetric. + if self.page_set.measure_memory: + action_runner.MeasureMemory() + + +class _BackgroundPlaybackPage(_MediaPage): + """A Background playback page plays the given media in a background tab. + + The motivation for this test case is crbug.com/678663. + """ + + def __init__(self, url, page_set, tags, extra_browser_args=None, + background_time=10, + traffic_setting=traffic_setting_module.NONE): + self._background_time = background_time + tags.append('background') + tags.append('src') + # disable-media-suspend is required since for Android background playback + # gets suspended. This flag makes Android work the same way as desktop and + # not turn off video playback in the background. + extra_browser_args = extra_browser_args or [] + extra_browser_args.append('--disable-media-suspend') + super(_BackgroundPlaybackPage, self).__init__( + url, page_set, tags, extra_browser_args) + + def RunPageInteractions(self, action_runner): + # Steps: + # 1. Play a video + # 2. Open new tab overtop to obscure the video + # 3. Close the tab to go back to the tab that is playing the video. + action_runner.PlayMedia( + playing_event_timeout_in_seconds=60) + action_runner.Wait(.5) + new_tab = action_runner.tab.browser.tabs.New() + new_tab.Activate() + action_runner.Wait(self._background_time) + new_tab.Close() + action_runner.Wait(.5) + # Generate memory dump for memoryMetric. + if self.page_set.measure_memory: + action_runner.MeasureMemory() + + +class _MSEPage(_MediaPage): + + def __init__(self, url, page_set, tags, extra_browser_args=None, + number_of_runs=10): + assert number_of_runs >= 1 + self._number_of_runs = number_of_runs + tags.append('mse') + super(_MSEPage, self).__init__( + url, page_set, tags, extra_browser_args) + + def RunPageInteractions(self, action_runner): + # The page automatically runs the test at load time. + self._CheckTestResult(action_runner) + # Now run it a few more times to get more reliable data. + # Note that each run takes ~.5s, so running a bunch of times to get reliable + # data is reasonable. + for _ in range(self._number_of_runs - 1): + url = action_runner.tab.url + action_runner.tab.ClearCache(force=True) + action_runner.tab.Navigate(url) + self._CheckTestResult(action_runner) + + def _CheckTestResult(self, action_runner): + action_runner.WaitForJavaScriptCondition('window.__testDone == true') + test_failed = action_runner.EvaluateJavaScript('window.__testFailed') + if test_failed: + raise RuntimeError(action_runner.EvaluateJavaScript('window.__testError')) + + +class MediaCasesStorySet(story.StorySet): + """ + Description: Video Stack Perf pages that report time_to_play, seek time and + many other media-specific and generic metrics. + """ + def __init__(self, measure_memory=False): + super(MediaCasesStorySet, self).__init__( + cloud_storage_bucket=story.PARTNER_BUCKET) + + self.measure_memory = measure_memory + + pages = [ + _BeginningToEndPlayPage( + url=_URL_BASE + 'video.html?src=crowd.ogg&type=audio', + page_set=self, + tags=['vorbis', 'audio_only']), + _BeginningToEndPlayPage( + url=_URL_BASE + 'video.html?src=crowd1080.webm', + page_set=self, + tags=['is_50fps', 'vp8', 'vorbis', 'audio_video']), + _BeginningToEndPlayPage( + url=_URL_BASE + 'video.html?src=tulip2.ogg&type=audio', + page_set=self, + tags=['vorbis', 'audio_only']), + _BeginningToEndPlayPage( + url=_URL_BASE + 'video.html?src=tulip2.wav&type=audio', + page_set=self, + tags=['pcm', 'audio_only']), + _BeginningToEndPlayPage( + url=_URL_BASE + 'video.html?src=crowd1080.mp4', + page_set=self, + tags=['is_50fps', 'h264', 'aac', 'audio_video']), + _BeginningToEndPlayPage( + url=_URL_BASE + 'video.html?src=tulip2.mp3&type=audio', + page_set=self, + tags=['mp3', 'audio_only']), + _BeginningToEndPlayPage( + url=_URL_BASE + 'video.html?src=tulip2.mp4', + page_set=self, + tags=['h264', 'aac', 'audio_video']), + _BeginningToEndPlayPage( + url=_URL_BASE + 'video.html?src=tulip2.m4a&type=audio', + page_set=self, + tags=['aac', 'audio_only']), + _BeginningToEndPlayPage( + url=_URL_BASE + 'video.html?src=garden2_10s.webm', + page_set=self, + tags=['is_4k', 'vp8', 'vorbis', 'audio_video']), + _BeginningToEndPlayPage( + url=_URL_BASE + 'video.html?src=garden2_10s.mp4', + page_set=self, + tags=['is_4k', 'h264', 'aac', 'audio_video']), + _BeginningToEndPlayPage( + url=_URL_BASE + 'video.html?src=tulip2.vp9.webm', + page_set=self, + tags=['vp9', 'opus', 'audio_video'], + traffic_setting=traffic_setting_module.REGULAR_3G), + _BeginningToEndPlayPage( + url=_URL_BASE + 'video.html?src=tulip2.vp9.webm', + page_set=self, + tags=['vp9', 'opus', 'audio_video']), + _BeginningToEndPlayPage( + url=_URL_BASE + 'video.html?src=crowd1080_vp9.webm', + page_set=self, + tags=['vp9', 'video_only']), + _BeginningToEndPlayPage( + url=_URL_BASE + 'video.html?src=crowd720_vp9.webm', + page_set=self, + tags=['vp9', 'video_only']), + _BeginningToEndPlayPage( + url=_URL_BASE + 'video.html?src=tulip2.mp4&busyjs', + page_set=self, + tags=['h264', 'aac', 'audio_video', 'busyjs']), + _SeekPage( + url=_URL_BASE + 'video.html?src=tulip2.ogg&type=audio&seek', + page_set=self, + tags=['vorbis', 'audio_only']), + _SeekPage( + url=_URL_BASE + 'video.html?src=tulip2.wav&type=audio&seek', + page_set=self, + tags=['pcm', 'audio_only']), + _SeekPage( + url=_URL_BASE + 'video.html?src=tulip2.mp3&type=audio&seek', + page_set=self, + tags=['mp3', 'audio_only']), + _SeekPage( + url=_URL_BASE + 'video.html?src=tulip2.mp4&seek', + page_set=self, + tags=['h264', 'aac', 'audio_video']), + _SeekPage( + url=_URL_BASE + 'video.html?src=garden2_10s.webm&seek', + page_set=self, + tags=['is_4k', 'vp8', 'vorbis', 'audio_video']), + _SeekPage( + url=_URL_BASE + 'video.html?src=garden2_10s.mp4&seek', + page_set=self, + tags=['is_4k', 'h264', 'aac', 'audio_video']), + _SeekPage( + url=_URL_BASE + 'video.html?src=tulip2.vp9.webm&seek', + page_set=self, + tags=['vp9', 'opus', 'audio_video']), + _SeekPage( + url=_URL_BASE + 'video.html?src=crowd1080_vp9.webm&seek', + page_set=self, + tags=['vp9', 'video_only', 'seek']), + _SeekPage( + url=(_URL_BASE + 'video.html?src=' + 'smpte_3840x2160_60fps_vp9.webm&seek'), + page_set=self, + tags=['is_4k', 'vp9', 'video_only'], + action_timeout_in_seconds=120), + _BackgroundPlaybackPage( + url=_URL_BASE + 'video.html?src=tulip2.vp9.webm&background', + page_set=self, + tags=['vp9', 'opus', 'audio_video']), + _MSEPage( + url=_URL_BASE + 'mse.html?media=aac_audio.mp4,h264_video.mp4', + page_set=self, + tags=['h264', 'aac', 'audio_video']), + _MSEPage( + url=(_URL_BASE + 'mse.html?' + 'media=aac_audio.mp4,h264_video.mp4&waitForPageLoaded=true'), + page_set=self, + tags=['h264', 'aac', 'audio_video']), + _MSEPage( + url=_URL_BASE + 'mse.html?media=aac_audio.mp4', + page_set=self, + tags=['aac', 'audio_only']), + _MSEPage( + url=_URL_BASE + 'mse.html?media=h264_video.mp4', + page_set=self, + tags=['h264', 'video_only']), + ] + + for page in pages: + self.AddStory(page)
diff --git a/tools/perf/page_sets/media_cases/OWNERS b/tools/perf/page_sets/media_cases/OWNERS new file mode 100644 index 0000000..06d8911 --- /dev/null +++ b/tools/perf/page_sets/media_cases/OWNERS
@@ -0,0 +1,3 @@ +crouleau@chromium.org +johnchen@chromium.org +dalecurtis@chromium.org
diff --git a/tools/perf/page_sets/mse_cases/audio.mp4.sha1 b/tools/perf/page_sets/media_cases/aac_audio.mp4.sha1 similarity index 100% rename from tools/perf/page_sets/mse_cases/audio.mp4.sha1 rename to tools/perf/page_sets/media_cases/aac_audio.mp4.sha1
diff --git a/tools/perf/page_sets/tough_video_cases/crowd.ogg.sha1 b/tools/perf/page_sets/media_cases/crowd.ogg.sha1 similarity index 100% rename from tools/perf/page_sets/tough_video_cases/crowd.ogg.sha1 rename to tools/perf/page_sets/media_cases/crowd.ogg.sha1
diff --git a/tools/perf/page_sets/tough_video_cases/crowd1080.mp4.sha1 b/tools/perf/page_sets/media_cases/crowd1080.mp4.sha1 similarity index 100% rename from tools/perf/page_sets/tough_video_cases/crowd1080.mp4.sha1 rename to tools/perf/page_sets/media_cases/crowd1080.mp4.sha1
diff --git a/tools/perf/page_sets/tough_video_cases/crowd1080.webm.sha1 b/tools/perf/page_sets/media_cases/crowd1080.webm.sha1 similarity index 100% rename from tools/perf/page_sets/tough_video_cases/crowd1080.webm.sha1 rename to tools/perf/page_sets/media_cases/crowd1080.webm.sha1
diff --git a/tools/perf/page_sets/tough_video_cases/crowd1080_vp9.webm.sha1 b/tools/perf/page_sets/media_cases/crowd1080_vp9.webm.sha1 similarity index 100% rename from tools/perf/page_sets/tough_video_cases/crowd1080_vp9.webm.sha1 rename to tools/perf/page_sets/media_cases/crowd1080_vp9.webm.sha1
diff --git a/tools/perf/page_sets/tough_video_cases/crowd2160.ogv.sha1 b/tools/perf/page_sets/media_cases/crowd2160.ogv.sha1 similarity index 100% rename from tools/perf/page_sets/tough_video_cases/crowd2160.ogv.sha1 rename to tools/perf/page_sets/media_cases/crowd2160.ogv.sha1
diff --git a/tools/perf/page_sets/tough_video_cases/crowd360.mp4.sha1 b/tools/perf/page_sets/media_cases/crowd360.mp4.sha1 similarity index 100% rename from tools/perf/page_sets/tough_video_cases/crowd360.mp4.sha1 rename to tools/perf/page_sets/media_cases/crowd360.mp4.sha1
diff --git a/tools/perf/page_sets/tough_video_cases/crowd360.webm.sha1 b/tools/perf/page_sets/media_cases/crowd360.webm.sha1 similarity index 100% rename from tools/perf/page_sets/tough_video_cases/crowd360.webm.sha1 rename to tools/perf/page_sets/media_cases/crowd360.webm.sha1
diff --git a/tools/perf/page_sets/tough_video_cases/crowd720_vp9.webm.sha1 b/tools/perf/page_sets/media_cases/crowd720_vp9.webm.sha1 similarity index 100% rename from tools/perf/page_sets/tough_video_cases/crowd720_vp9.webm.sha1 rename to tools/perf/page_sets/media_cases/crowd720_vp9.webm.sha1
diff --git a/tools/perf/page_sets/tough_video_cases/garden2_10s.mp4.sha1 b/tools/perf/page_sets/media_cases/garden2_10s.mp4.sha1 similarity index 100% rename from tools/perf/page_sets/tough_video_cases/garden2_10s.mp4.sha1 rename to tools/perf/page_sets/media_cases/garden2_10s.mp4.sha1
diff --git a/tools/perf/page_sets/tough_video_cases/garden2_10s.webm.sha1 b/tools/perf/page_sets/media_cases/garden2_10s.webm.sha1 similarity index 100% rename from tools/perf/page_sets/tough_video_cases/garden2_10s.webm.sha1 rename to tools/perf/page_sets/media_cases/garden2_10s.webm.sha1
diff --git a/tools/perf/page_sets/mse_cases/video.mp4.sha1 b/tools/perf/page_sets/media_cases/h264_video.mp4.sha1 similarity index 100% rename from tools/perf/page_sets/mse_cases/video.mp4.sha1 rename to tools/perf/page_sets/media_cases/h264_video.mp4.sha1
diff --git a/tools/perf/page_sets/media_cases/mse.html b/tools/perf/page_sets/media_cases/mse.html new file mode 100644 index 0000000..55068a8 --- /dev/null +++ b/tools/perf/page_sets/media_cases/mse.html
@@ -0,0 +1,16 @@ +<!doctype html> +<!-- This page is used to test Media Source Extensions implementation. --> +<html> + <head> + <title>Media Source Extensions (MSE) Performance Test</title> + <script src="mse.js"> </script> + </head> + <body> + <div> + <video controls style="width: 640px; height: 360px;" id="video_id"></video> + </div> + <script> + __test(); + </script> + </body> +</html>
diff --git a/tools/perf/page_sets/media_cases/mse.js b/tools/perf/page_sets/media_cases/mse.js new file mode 100644 index 0000000..3d16fba5 --- /dev/null +++ b/tools/perf/page_sets/media_cases/mse.js
@@ -0,0 +1,165 @@ +// 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. + +// The file runs a series of Media Source Entensions (MSE) operations on a +// video tag to set up a media file for playback. The test takes several URL +// parameters described in the loadTestParams() function. + +(() => { + // Map from media content to MIME type. All test content must be added to this + // map. (Feel free to extend it for your test case!) + const MEDIA_MIMES = { + "aac_audio.mp4": "audio/mp4; codecs=\"mp4a.40.2\"", + "h264_video.mp4": "video/mp4; codecs=\"avc1.640028\"", + }; + const testParams = {} + + function test() { + loadTestParams(); + if (testParams.waitForPageLoaded) { + document.body.onload = () => { + runTest(); + } + } else { + runTest(); + } + } + + function loadTestParams() { + var queryParameters = parseQueryParameters(); + // waitForPageLoaded determines whether to wait for body.onload event or + // to start right away. + testParams.waitForPageLoaded = + (queryParameters["waitForPageLoaded"] === "true"); + // startOffset is used to start the media at an offset instead of at the + // beginning of the file. + testParams.startOffset = parseInt(queryParameters["startOffset"] || "0"); + // appendSize determines how large a chuck of the media file to append. + testParams.appendSize = parseInt(queryParameters["appendSize"] || "65536"); + // media argument lists the media files to play. + testParams.media = queryParameters["media"]; + if (!testParams.media) + throw Error("media parameter must be defined to provide test content"); + if (!Array.isArray(testParams.media)) + testParams.media = [testParams.media]; + } + + function parseQueryParameters() { + var params = {}; + var r = /([^&=]+)=([^&]*)/g; + var match; + while (match = r.exec(window.location.search.substring(1))) { + key = decodeURIComponent(match[1]) + value = decodeURIComponent(match[2]); + if (value.includes(',')) { + value = value.split(","); + } + params[key] = value; + } + return params; + } + + function runTest() { + let appenders = []; + let mediaElement = document.getElementById("video_id"); + let mediaSource = new window.MediaSource(); + window.__mediaSource = mediaSource; + + // Pass the test if currentTime of the media increases since that means that + // the file has started playing. + // This code can be modified in the future for full playback tests. + mediaElement.addEventListener("timeupdate", () => { + window.clearTimeout(timeout); + PassTest("Test completed after timeupdate event was received.") + }, {once: true}); + + // Fail the test if we time out. + var timeout = setTimeout(function() { + FailTest("Test timed out waiting for a mediaElement timeupdate event."); + }, 10000); + + mediaSource.addEventListener('sourceopen', (open_event) => { + let mediaSource = open_event.target; + for (let i = 0; i < appenders.length; ++i) { + appenders[i].onSourceOpen(mediaSource); + } + for (let i = 0; i < appenders.length; ++i) { + appenders[i].attemptAppend(mediaSource); + } + mediaElement.play(); + }); + + // Do not attach MediaSource object until all the buffer appenders have + // received the data from the network that they'll append. This removes + // the factor of network overhead from the attachment timing. + let number_of_appenders_with_data = 0; + for (const media_file of testParams.media) { + appender = new BufferAppender(media_file, MEDIA_MIMES[media_file]); + appender.requestMediaBytes(() => { + number_of_appenders_with_data++; + if (number_of_appenders_with_data === testParams.media.length) { + // This attaches the mediaSource object to the mediaElement. Once this + // operation has completed internally, the mediaSource object + // readyState will transition from closed to open, and the sourceopen + // event will fire. + mediaElement.src = URL.createObjectURL(mediaSource); + } + }); + appenders.push(appender); + } + } + + class BufferAppender { + constructor(media_file, mimetype) { + this.media_file = media_file; + this.mimetype = mimetype; + this.xhr = new XMLHttpRequest(); + this.sourceBuffer = null; + } + requestMediaBytes(callback) { + this.xhr.addEventListener('loadend', callback); + this.xhr.open('GET', this.media_file); + this.xhr.setRequestHeader( + 'Range', 'bytes=' + testParams.startOffset + '-' + + (testParams.startOffset + testParams.appendSize - 1)); + this.xhr.responseType = 'arraybuffer'; + this.xhr.send(); + } + onSourceOpen(mediaSource) { + if (this.sourceBuffer) + return; + this.sourceBuffer = mediaSource.addSourceBuffer(this.mimetype); + } + attemptAppend() { + if (!this.xhr.response || !this.sourceBuffer) + return; + this.sourceBuffer.appendBuffer(this.xhr.response); + this.xhr = null; + } + } // End BufferAppender + + function PassTest(message) { + console.log("Test passed: " + message); + window.__testDone = true; + } + + function FailTest(error_message) { + console.error("Test failed: " + error_message); + window.__testFailed = true; + window.__testError = error_message; + window.__testDone = true; + } + + window.onerror = (messageOrEvent, source, lineno, colno, error) => { + // Fail the test if there are any errors. See crbug/777489. + // Note that error.stack already contains error.message. + FailTest(error.stack); + } + + window.__test = test; + // These are outputs to be consumed by media Telemetry test driver code. + window.__testDone = false; + window.__testFailed = false; + window.__testError = ""; +})();
diff --git a/tools/perf/page_sets/tough_video_cases/smpte_3840x2160_60fps_vp9.webm.sha1 b/tools/perf/page_sets/media_cases/smpte_3840x2160_60fps_vp9.webm.sha1 similarity index 100% rename from tools/perf/page_sets/tough_video_cases/smpte_3840x2160_60fps_vp9.webm.sha1 rename to tools/perf/page_sets/media_cases/smpte_3840x2160_60fps_vp9.webm.sha1
diff --git a/tools/perf/page_sets/tough_video_cases/tulip2.m4a.sha1 b/tools/perf/page_sets/media_cases/tulip2.m4a.sha1 similarity index 100% rename from tools/perf/page_sets/tough_video_cases/tulip2.m4a.sha1 rename to tools/perf/page_sets/media_cases/tulip2.m4a.sha1
diff --git a/tools/perf/page_sets/tough_video_cases/tulip2.mp3.sha1 b/tools/perf/page_sets/media_cases/tulip2.mp3.sha1 similarity index 100% rename from tools/perf/page_sets/tough_video_cases/tulip2.mp3.sha1 rename to tools/perf/page_sets/media_cases/tulip2.mp3.sha1
diff --git a/tools/perf/page_sets/tough_video_cases/tulip2.mp4.sha1 b/tools/perf/page_sets/media_cases/tulip2.mp4.sha1 similarity index 100% rename from tools/perf/page_sets/tough_video_cases/tulip2.mp4.sha1 rename to tools/perf/page_sets/media_cases/tulip2.mp4.sha1
diff --git a/tools/perf/page_sets/tough_video_cases/tulip2.ogg.sha1 b/tools/perf/page_sets/media_cases/tulip2.ogg.sha1 similarity index 100% rename from tools/perf/page_sets/tough_video_cases/tulip2.ogg.sha1 rename to tools/perf/page_sets/media_cases/tulip2.ogg.sha1
diff --git a/tools/perf/page_sets/tough_video_cases/tulip2.vp9.webm.sha1 b/tools/perf/page_sets/media_cases/tulip2.vp9.webm.sha1 similarity index 100% rename from tools/perf/page_sets/tough_video_cases/tulip2.vp9.webm.sha1 rename to tools/perf/page_sets/media_cases/tulip2.vp9.webm.sha1
diff --git a/tools/perf/page_sets/tough_video_cases/tulip2.wav.sha1 b/tools/perf/page_sets/media_cases/tulip2.wav.sha1 similarity index 100% rename from tools/perf/page_sets/tough_video_cases/tulip2.wav.sha1 rename to tools/perf/page_sets/media_cases/tulip2.wav.sha1
diff --git a/tools/perf/page_sets/tough_video_cases/video.html b/tools/perf/page_sets/media_cases/video.html similarity index 61% rename from tools/perf/page_sets/tough_video_cases/video.html rename to tools/perf/page_sets/media_cases/video.html index 8a80cc208..d92a2425 100644 --- a/tools/perf/page_sets/tough_video_cases/video.html +++ b/tools/perf/page_sets/media_cases/video.html
@@ -1,4 +1,14 @@ <!DOCTYPE html> +<!-- This page is used to test media src= (video and audio) performance. + + This can be used for src= (but not for MSE or EME) for content of any format + that Chrome supports playing. + + TODO(crouleau): Rename file to contrast with mse.html. "video.html" doesn't + make sense because sometimes we play audio-only content. Note that this will + require a data migration on the chromeperf dashboard since "video.html" is + included in the metrics' page names. +--> <html> <body> </body> @@ -20,30 +30,6 @@ params[d(match[1])] = d(match[2]); return params; } - // Each network config = [DOWNLOAD_BANDWIDTH_Kbit/s, LATENCY_MS] - // Numbers are chosen to be similar to webpagereplay/net_configs.py - var netConfig = {}; - netConfig['cable'] = [5120, 28]; - netConfig['dsl'] = [1536, 50]; - netConfig['wifi'] = [1024, 60]; - netConfig['none'] = null; - // Constrained network server URL. - var CNS_BASE_URL = 'http://cns.chrome:9000/ServeConstrained?'; - - function getNetsimURL(net) { - if (!netConfig[net]) - return CNS_BASE_URL; - return CNS_BASE_URL + 'bandwidth=' + netConfig[net][0] + - '&latency=' + netConfig[net][1] - } - - function getMediaSRC() { - var mediaSRC = qsParams['src'] - if (qsParams['net']) - return getNetsimURL(qsParams['net']) + '&new_port=True' + '&f=' + - mediaSRC; - return mediaSRC; - } // This keeps the renderer thread busy all the time, however, it // stops to let other things run every 20 ms. @@ -57,15 +43,13 @@ qsParams = getQueryStrings(); var type = qsParams['type'] || 'video'; var testElement = document.createElement(type); - var canvasElement; - var canvasContext; testElement.preload = 'none'; testElement.controls = true; if (qsParams['id']) testElement.id = qsParams['id']; if ('busyjs' in qsParams) makeBusy(); - testElement.src = getMediaSRC(); + testElement.src = qsParams['src']; document.body.appendChild(testElement); </script> </html>
diff --git a/tools/perf/page_sets/media_cns_cases.py b/tools/perf/page_sets/media_cns_cases.py deleted file mode 100644 index b09c1e4..0000000 --- a/tools/perf/page_sets/media_cns_cases.py +++ /dev/null
@@ -1,121 +0,0 @@ -# Copyright 2014 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. -from telemetry.page import page as page_module -from telemetry import story - - -class BasicPlayPage(page_module.Page): - - def __init__(self, url, page_set, name=''): - super(BasicPlayPage, self).__init__(url=url, page_set=page_set, name=name) - self.add_browser_metrics = True - - def PlayAction(self, action_runner): - action_runner.PlayMedia(playing_event_timeout_in_seconds=60, - ended_event_timeout_in_seconds=60) - - def RunPageInteractions(self, action_runner): - self.PlayAction(action_runner) - - def SeekBeforeAndAfterPlayhead(self, action_runner): - action_runner.PlayMedia(playing_event_timeout_in_seconds=60) - # Wait for 1 second so that we know the play-head is at ~1s. - action_runner.Wait(1) - # Seek to before the play-head location. - action_runner.SeekMedia(seconds=0.5, timeout_in_seconds=60, - label='seek_warm') - # Seek to after the play-head location. - action_runner.SeekMedia(seconds=15, timeout_in_seconds=60, - label='seek_cold') - -class SeekBeforeAndAfterPlayheadPage(BasicPlayPage): - - def __init__(self, url, page_set, name): - super(SeekBeforeAndAfterPlayheadPage, self).__init__(url=url, - page_set=page_set, - name=name) - self.add_browser_metrics = False - - def RunPageInteractions(self, action_runner): - self.SeekBeforeAndAfterPlayhead(action_runner) - - -class MediaCnsCasesPageSet(story.StorySet): - - """ Media benchmark on network constrained conditions. """ - - def __init__(self): - super(MediaCnsCasesPageSet, self).__init__() - - urls_list = [ - # pylint: disable=line-too-long - 'file://tough_video_cases/video.html?id=no_constraints_webm&src=tulip2.webm&net=none', - # pylint: disable=line-too-long - 'file://tough_video_cases/video.html?id=cable_webm&src=tulip2.webm&net=cable', - # pylint: disable=line-too-long - 'file://tough_video_cases/video.html?id=wifi_webm&src=tulip2.webm&net=wifi', - # pylint: disable=line-too-long - 'file://tough_video_cases/video.html?id=no_constraints_ogv&src=tulip2.ogv&net=none', - # pylint: disable=line-too-long - 'file://tough_video_cases/video.html?id=cable_ogv&src=tulip2.ogv&net=cable', - # pylint: disable=line-too-long - 'file://tough_video_cases/video.html?id=wifi_ogv&src=tulip2.ogv&net=wifi', - # pylint: disable=line-too-long - 'file://tough_video_cases/video.html?id=no_constraints_mp4&src=tulip2.mp4&net=none', - # pylint: disable=line-too-long - 'file://tough_video_cases/video.html?id=cable_mp4&src=tulip2.mp4&net=cable', - # pylint: disable=line-too-long - 'file://tough_video_cases/video.html?id=wifi_mp4&src=tulip2.mp4&net=wifi', - # pylint: disable=line-too-long - 'file://tough_video_cases/video.html?id=no_constraints_wav&src=tulip2.wav&type=audio&net=none', - # pylint: disable=line-too-long - 'file://tough_video_cases/video.html?id=cable_wav&src=tulip2.wav&type=audio&net=cable', - # pylint: disable=line-too-long - 'file://tough_video_cases/video.html?id=wifi_wav&src=tulip2.wav&type=audio&net=wifi', - # pylint: disable=line-too-long - 'file://tough_video_cases/video.html?id=no_constraints_ogg&src=tulip2.ogg&type=audio&net=none', - # pylint: disable=line-too-long - 'file://tough_video_cases/video.html?id=cable_ogg&src=tulip2.ogg&type=audio&net=cable', - # pylint: disable=line-too-long - 'file://tough_video_cases/video.html?id=wifi_ogg&src=tulip2.ogg&type=audio&net=wifi', - # pylint: disable=line-too-long - 'file://tough_video_cases/video.html?id=no_constraints_mp3&src=tulip2.mp3&type=audio&net=none', - # pylint: disable=line-too-long - 'file://tough_video_cases/video.html?id=cable_mp3&src=tulip2.mp3&type=audio&net=cable', - # pylint: disable=line-too-long - 'file://tough_video_cases/video.html?id=wifi_mp3&src=tulip2.mp3&type=audio&net=wifi', - # pylint: disable=line-too-long - 'file://tough_video_cases/video.html?id=no_constraints_m4a&src=tulip2.m4a&type=audio&net=none', - # pylint: disable=line-too-long - 'file://tough_video_cases/video.html?id=cable_m4a&src=tulip2.m4a&type=audio&net=cable', - # pylint: disable=line-too-long - 'file://tough_video_cases/video.html?id=wifi_m4a&src=tulip2.m4a&type=audio&net=wifi' - ] - - for url in urls_list: - self.AddStory(BasicPlayPage(url, self, url.split('/')[-1])) - - urls_list2 = [ - # pylint: disable=line-too-long - 'file://tough_video_cases/video.html?id=wifi_mp3&src=tulip2.mp3&type=audio&net=wifi', - # pylint: disable=line-too-long - 'file://tough_video_cases/video.html?id=wifi_m4a&src=tulip2.m4a&type=audio&net=wifi', - # pylint: disable=line-too-long - 'file://tough_video_cases/video.html?id=wifi_ogg&src=tulip2.ogg&type=audio&net=wifi', - # pylint: disable=line-too-long - 'file://tough_video_cases/video.html?id=wifi_wav&src=tulip2.wav&type=audio&net=wifi', - # pylint: disable=line-too-long - 'file://tough_video_cases/video.html?id=wifi_mp4&src=tulip2.mp4&type=audio&net=wifi', - # pylint: disable=line-too-long - 'file://tough_video_cases/video.html?id=wifi_ogv&src=tulip2.ogv&type=audio&net=wifi', - # pylint: disable=line-too-long - 'file://tough_video_cases/video.html?id=wifi_webm&src=tulip2.webm&type=audio&net=wifi' - ] - - for url in urls_list2: - if url in urls_list: - name = 'seek_' + url - else: - name = url.split('/')[-1] - self.AddStory(SeekBeforeAndAfterPlayheadPage(url, self, name=name))
diff --git a/tools/perf/page_sets/mse_cases.py b/tools/perf/page_sets/mse_cases.py deleted file mode 100644 index 75477b1..0000000 --- a/tools/perf/page_sets/mse_cases.py +++ /dev/null
@@ -1,48 +0,0 @@ -# Copyright 2014 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. -from telemetry.page import page as page_module -from telemetry import story - - -class MseCasesPage(page_module.Page): - - def __init__(self, url, page_set, name): - super(MseCasesPage, self).__init__(url=url, page_set=page_set, name=name) - - def RunNavigateSteps(self, action_runner): - super(MseCasesPage, self).RunNavigateSteps(action_runner) - action_runner.WaitForJavaScriptCondition('window.__testDone == true') - - -class MseCasesPageSet(story.StorySet): - - """ Media source extensions perf benchmark """ - - def __init__(self): - super(MseCasesPageSet, self).__init__( - cloud_storage_bucket=story.PUBLIC_BUCKET) - - urls_list = [ - 'file://mse_cases/startup_test.html?testType=AV', - 'file://mse_cases/startup_test.html?testType=AV&useAppendStream=true', - # pylint: disable=line-too-long - 'file://mse_cases/startup_test.html?testType=AV&doNotWaitForBodyOnLoad=true', - # pylint: disable=line-too-long - 'file://mse_cases/startup_test.html?testType=AV&useAppendStream=true&doNotWaitForBodyOnLoad=true', - 'file://mse_cases/startup_test.html?testType=V', - 'file://mse_cases/startup_test.html?testType=V&useAppendStream=true', - # pylint: disable=line-too-long - 'file://mse_cases/startup_test.html?testType=V&doNotWaitForBodyOnLoad=true', - # pylint: disable=line-too-long - 'file://mse_cases/startup_test.html?testType=V&useAppendStream=true&doNotWaitForBodyOnLoad=true', - 'file://mse_cases/startup_test.html?testType=A', - 'file://mse_cases/startup_test.html?testType=A&useAppendStream=true', - # pylint: disable=line-too-long - 'file://mse_cases/startup_test.html?testType=A&doNotWaitForBodyOnLoad=true', - # pylint: disable=line-too-long - 'file://mse_cases/startup_test.html?testType=A&useAppendStream=true&doNotWaitForBodyOnLoad=true', - ] - - for url in urls_list: - self.AddStory(MseCasesPage(url, self, url.split('/')[-1]))
diff --git a/tools/perf/page_sets/mse_cases/startup_test.html b/tools/perf/page_sets/mse_cases/startup_test.html deleted file mode 100644 index ed28812..0000000 --- a/tools/perf/page_sets/mse_cases/startup_test.html +++ /dev/null
@@ -1,45 +0,0 @@ -<!doctype html> -<html> - <head> - <title>MSE Startup Test</title> - <script src="startup_test.js"> </script> - </head> - <body> - <div> - <video controls style="width: 640px; height: 360px;" id="v"></video> - </div> - <div style="float: left; width: 320px; height: 250px"> - <h4>Test Parameters:</h4> - <form method="GET"> - <table> - <tr> - <td>testType:</td> - <td> - <select id="testType" name="testType"> - <option value="A">audio-only</option> - <option value="V">video-only</option> - <option value="AV" selected >audio/video</option> - </select> - </td> - </tr> - <tr><td>doNotWaitForBodyOnLoad:</td><td ><input id="doNotWaitForBodyOnLoad" name="doNotWaitForBodyOnLoad" type="checkbox" value="true"></td></tr> - <tr><td>useAppendStream:</td><td ><input id="useAppendStream" name="useAppendStream" type="checkbox" value="true"></td></tr> - <tr><td>appendSize:</td><td><input type="text" size="7" id="appendSize" name="appendSize"></td></tr> - <tr><td>graphDuration (ms):</td><td><input type="text" size="7" id="graphDuration" name="graphDuration"></td></tr> - </table> - <input type="submit" value="Run Again"> - </form> - </div> - <div style="float:left; width: 320px; height: 250px"> - <h4>Results:</h4> - <div id="stats"> - </div> - </div> - <div style="clear:both"> - <canvas id="c" width="640" height="200"></canvas> - </div> - <script> - setupTest(); - </script> - </body> -</html>
diff --git a/tools/perf/page_sets/mse_cases/startup_test.js b/tools/perf/page_sets/mse_cases/startup_test.js deleted file mode 100644 index 282bde7..0000000 --- a/tools/perf/page_sets/mse_cases/startup_test.js +++ /dev/null
@@ -1,528 +0,0 @@ -// 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. - - -// The file runs a series of Media Source Entensions (MSE) operations on a -// video tag. The test takes several URL parameters described in -//loadTestParams() function. - -(function() { - function getPerfTimestamp() { - return performance.now(); - } - - var pageStartTime = getPerfTimestamp(); - var bodyLoadTime; - var pageEndTime; - - function parseQueryParameters() { - var params = {}; - var r = /([^&=]+)=?([^&]*)/g; - - function d(s) { return decodeURIComponent(s.replace(/\+/g, ' ')); } - - var match; - while (match = r.exec(window.location.search.substring(1))) - params[d(match[1])] = d(match[2]); - - return params; - } - - var testParams; - function loadTestParams() { - var queryParameters = parseQueryParameters(); - testParams = {}; - testParams.testType = queryParameters["testType"] || "AV"; - testParams.useAppendStream = (queryParameters["useAppendStream"] == "true"); - testParams.doNotWaitForBodyOnLoad = - (queryParameters["doNotWaitForBodyOnLoad"] == "true"); - testParams.startOffset = 0; - testParams.appendSize = parseInt(queryParameters["appendSize"] || "65536"); - testParams.graphDuration = - parseInt(queryParameters["graphDuration"] || "1000"); - } - - function plotTimestamps(timestamps, graphDuration, element) { - if (!timestamps) - return; - var c = document.getElementById('c'); - var ctx = c.getContext('2d'); - - var bars = [ - { label: 'Page Load Total', - start: pageStartTime, - end: pageEndTime, - color: '#404040' }, - { label: 'body.onload Delay', - start: pageStartTime, - end: bodyLoadTime, - color: '#808080' }, - { label: 'Test Total', - start: timestamps.testStartTime, - end: timestamps.testEndTime, - color: '#00FF00' }, - { label: 'MediaSource opening', - start: timestamps.mediaSourceOpenStartTime, - end: timestamps.mediaSourceOpenEndTime, - color: '#008800' } - ]; - - var maxAppendEndTime = 0; - for (var i = 0; i < timestamps.appenders.length; ++i) { - var appender = timestamps.appenders[i]; - bars.push({ label: 'XHR', - start: appender.xhrStartTime, - end: appender.xhrEndTime, - color: '#0088FF' }); - bars.push({ label: 'Append', - start: appender.appendStartTime, - end: appender.appendEndTime, - color: '#00FFFF' }); - if (appender.appendEndTime > maxAppendEndTime) { - maxAppendEndTime = appender.appendEndTime; - } - } - - bars.push({ - label: 'Post Append Delay', - start: maxAppendEndTime, - end: timestamps.testEndTime, - color: '#B0B0B0' }); - - var minTimestamp = Number.MAX_VALUE; - for (var i = 0; i < bars.length; ++i) { - minTimestamp = Math.min(minTimestamp, bars[i].start); - } - - var graphWidth = c.width - 100; - function convertTimestampToX(t) { - return graphWidth * (t - minTimestamp) / graphDuration; - } - var y = 0; - var barThickness = 20; - c.height = bars.length * barThickness; - ctx.font = (0.75 * barThickness) + 'px arial'; - for (var i = 0; i < bars.length; ++i) { - var bar = bars[i]; - var xStart = convertTimestampToX(bar.start); - var xEnd = convertTimestampToX(bar.end); - ctx.fillStyle = bar.color; - ctx.fillRect(xStart, y, xEnd - xStart, barThickness); - - ctx.fillStyle = 'black'; - var text = bar.label + ' (' + (bar.end - bar.start).toFixed(3) + ' ms)'; - ctx.fillText(text, xEnd + 10, y + (0.75 * barThickness)); - y += barThickness; - } - reportTelemetryMediaMetrics(bars, element); - } - - function displayResults(stats) { - var statsDiv = document.getElementById('stats'); - - if (!stats) { - statsDiv.innerHTML = "Test failed"; - return; - } - - var statsMarkup = "Test passed<br><table>"; - for (var i in stats) { - statsMarkup += "<tr><td style=\"text-align:right\">" + i + ":</td><td>" + - stats[i].toFixed(3) + " ms</td>"; - } - statsMarkup += "</table>"; - statsDiv.innerHTML = statsMarkup; - } - - function reportTelemetryMediaMetrics(stats, element) { - var metrics = {}; - for (var i = 0; i < stats.length; ++i) { - var bar = stats[i]; - var label = bar.label.toLowerCase().replace(/\s+|\./g, '_'); - var value = (bar.end - bar.start).toFixed(3); - console.log("appending to telemetry " + label + " : " + value); - _AppendMetric(metrics, label, value); - } - window.__testMetrics = { - "id": element.id, - "metrics": metrics - }; - } - - function _AppendMetric(metrics, metric, value) { - if (!metrics[metric]) - metrics[metric] = []; - metrics[metric].push(value); - } - - function updateControls(testParams) { - var testTypeElement = document.getElementById("testType"); - for (var i in testTypeElement.options) { - var option = testTypeElement.options[i]; - if (option.value == testParams.testType) { - testTypeElement.selectedIndex = option.index; - } - } - - document.getElementById("useAppendStream").checked = - testParams.useAppendStream; - document.getElementById("doNotWaitForBodyOnLoad").checked = - testParams.doNotWaitForBodyOnLoad; - document.getElementById("appendSize").value = testParams.appendSize; - document.getElementById("graphDuration").value = testParams.graphDuration; - } - - function BufferAppender(mimetype, url, id, startOffset, appendSize) { - this.mimetype = mimetype; - this.url = url; - this.id = id; - this.startOffset = startOffset; - this.appendSize = appendSize; - this.xhr = new XMLHttpRequest(); - this.sourceBuffer = null; - } - - BufferAppender.prototype.start = function() { - this.xhr.addEventListener('loadend', this.onLoadEnd.bind(this)); - this.xhr.open('GET', this.url); - this.xhr.setRequestHeader('Range', 'bytes=' + this.startOffset + '-' + - (this.startOffset + this.appendSize - 1)); - this.xhr.responseType = 'arraybuffer'; - this.xhr.send(); - - this.xhrStartTime = getPerfTimestamp(); - }; - - BufferAppender.prototype.onLoadEnd = function() { - this.xhrEndTime = getPerfTimestamp(); - this.attemptAppend(); - }; - - BufferAppender.prototype.onSourceOpen = function(mediaSource) { - if (this.sourceBuffer) - return; - this.sourceBuffer = mediaSource.addSourceBuffer(this.mimetype); - }; - - BufferAppender.prototype.attemptAppend = function() { - if (!this.xhr.response || !this.sourceBuffer) - return; - - this.appendStartTime = getPerfTimestamp(); - - if (this.sourceBuffer.appendBuffer) { - this.sourceBuffer.addEventListener('updateend', - this.onUpdateEnd.bind(this)); - this.sourceBuffer.appendBuffer(this.xhr.response); - } else { - this.sourceBuffer.append(new Uint8Array(this.xhr.response)); - this.appendEndTime = getPerfTimestamp(); - } - - this.xhr = null; - }; - - BufferAppender.prototype.onUpdateEnd = function() { - this.appendEndTime = getPerfTimestamp(); - }; - - BufferAppender.prototype.onPlaybackStarted = function() { - var now = getPerfTimestamp(); - this.playbackStartTime = now; - if (this.sourceBuffer.updating) { - // Still appending but playback has already started so just abort the XHR - // and append. - this.sourceBuffer.abort(); - this.xhr.abort(); - } - }; - - BufferAppender.prototype.getXHRLoadDuration = function() { - return this.xhrEndTime - this.xhrStartTime; - }; - - BufferAppender.prototype.getAppendDuration = function() { - return this.appendEndTime - this.appendStartTime; - }; - - function StreamAppender(mimetype, url, id, startOffset, appendSize) { - this.mimetype = mimetype; - this.url = url; - this.id = id; - this.startOffset = startOffset; - this.appendSize = appendSize; - this.xhr = new XMLHttpRequest(); - this.sourceBuffer = null; - this.appendStarted = false; - } - - StreamAppender.prototype.start = function() { - this.xhr.addEventListener('readystatechange', - this.attemptAppend.bind(this)); - this.xhr.addEventListener('loadend', this.onLoadEnd.bind(this)); - this.xhr.open('GET', this.url); - this.xhr.setRequestHeader('Range', 'bytes=' + this.startOffset + '-' + - (this.startOffset + this.appendSize - 1)); - this.xhr.responseType = 'stream'; - if (this.xhr.responseType != 'stream') { - EndTest("XHR does not support 'stream' responses."); - } - this.xhr.send(); - - this.xhrStartTime = getPerfTimestamp(); - }; - - StreamAppender.prototype.onLoadEnd = function() { - this.xhrEndTime = getPerfTimestamp(); - this.attemptAppend(); - }; - - StreamAppender.prototype.onSourceOpen = function(mediaSource) { - if (this.sourceBuffer) - return; - this.sourceBuffer = mediaSource.addSourceBuffer(this.mimetype); - }; - - StreamAppender.prototype.attemptAppend = function() { - if (this.xhr.readyState < this.xhr.LOADING) { - return; - } - - if (!this.xhr.response || !this.sourceBuffer || this.appendStarted) - return; - - this.appendStartTime = getPerfTimestamp(); - this.appendStarted = true; - this.sourceBuffer.addEventListener('updateend', - this.onUpdateEnd.bind(this)); - this.sourceBuffer.appendStream(this.xhr.response); - }; - - StreamAppender.prototype.onUpdateEnd = function() { - this.appendEndTime = getPerfTimestamp(); - }; - - StreamAppender.prototype.onPlaybackStarted = function() { - var now = getPerfTimestamp(); - this.playbackStartTime = now; - if (this.sourceBuffer.updating) { - // Still appending but playback has already started so just abort the XHR - // and append. - this.sourceBuffer.abort(); - this.xhr.abort(); - if (!this.appendEndTime) - this.appendEndTime = now; - - if (!this.xhrEndTime) - this.xhrEndTime = now; - } - }; - - StreamAppender.prototype.getXHRLoadDuration = function() { - return this.xhrEndTime - this.xhrStartTime; - }; - - StreamAppender.prototype.getAppendDuration = function() { - return this.appendEndTime - this.appendStartTime; - }; - - // runAppendTest() sets testDone to true once all appends finish. - var testDone = false; - function runAppendTest(mediaElement, appenders, doneCallback) { - var testStartTime = getPerfTimestamp(); - var mediaSourceOpenStartTime; - var mediaSourceOpenEndTime; - - for (var i = 0; i < appenders.length; ++i) { - appenders[i].start(); - } - - function onSourceOpen(event) { - var mediaSource = event.target; - - mediaSourceOpenEndTime = getPerfTimestamp(); - - for (var i = 0; i < appenders.length; ++i) { - appenders[i].onSourceOpen(mediaSource); - } - - for (var i = 0; i < appenders.length; ++i) { - appenders[i].attemptAppend(mediaSource); - } - - mediaElement.play(); - } - - var mediaSource; - if (window['MediaSource']) { - mediaSource = new window.MediaSource(); - mediaSource.addEventListener('sourceopen', onSourceOpen); - } else { - mediaSource = new window.WebKitMediaSource(); - mediaSource.addEventListener('webkitsourceopen', onSourceOpen); - } - - var listener; - var timeout; - function checkForCurrentTimeChange() { - if (testDone) - return; - - if (mediaElement.readyState < mediaElement.HAVE_METADATA || - mediaElement.currentTime <= 0) { - listener = window.requestAnimationFrame(checkForCurrentTimeChange); - return; - } - - var testEndTime = getPerfTimestamp(); - for (var i = 0; i < appenders.length; ++i) { - appenders[i].onPlaybackStarted(mediaSource); - } - - testDone = true; - window.clearInterval(listener); - window.clearTimeout(timeout); - - var stats = {}; - stats.total = testEndTime - testStartTime; - stats.sourceOpen = mediaSourceOpenEndTime - mediaSourceOpenStartTime; - stats.maxXHRLoadDuration = appenders[0].getXHRLoadDuration(); - stats.maxAppendDuration = appenders[0].getAppendDuration(); - - var timestamps = {}; - timestamps.testStartTime = testStartTime; - timestamps.testEndTime = testEndTime; - timestamps.mediaSourceOpenStartTime = mediaSourceOpenStartTime; - timestamps.mediaSourceOpenEndTime = mediaSourceOpenEndTime; - timestamps.appenders = []; - - for (var i = 1; i < appenders.length; ++i) { - var appender = appenders[i]; - var xhrLoadDuration = appender.getXHRLoadDuration(); - var appendDuration = appender.getAppendDuration(); - - if (xhrLoadDuration > stats.maxXHRLoadDuration) - stats.maxXHRLoadDuration = xhrLoadDuration; - - if (appendDuration > stats.maxAppendDuration) - stats.maxAppendDuration = appendDuration; - } - - for (var i = 0; i < appenders.length; ++i) { - var appender = appenders[i]; - var appenderTimestamps = {}; - appenderTimestamps.xhrStartTime = appender.xhrStartTime; - appenderTimestamps.xhrEndTime = appender.xhrEndTime; - appenderTimestamps.appendStartTime = appender.appendStartTime; - appenderTimestamps.appendEndTime = appender.appendEndTime; - appenderTimestamps.playbackStartTime = appender.playbackStartTime; - timestamps.appenders.push(appenderTimestamps); - } - - mediaElement.pause(); - - pageEndTime = getPerfTimestamp(); - doneCallback(stats, timestamps); - }; - - listener = window.requestAnimationFrame(checkForCurrentTimeChange); - - timeout = setTimeout(function() { - if (testDone) - return; - - testDone = true; - window.cancelAnimationFrame(listener); - - mediaElement.pause(); - doneCallback(null); - EndTest("Test timed out."); - }, 10000); - - mediaSourceOpenStartTime = getPerfTimestamp(); - mediaElement.src = URL.createObjectURL(mediaSource); - }; - - function onBodyLoad() { - bodyLoadTime = getPerfTimestamp(); - - if (!testParams.doNotWaitForBodyOnLoad) { - startTest(); - } - } - - function startTest() { - updateControls(testParams); - - var appenders = []; - - if (testParams.useAppendStream && !window.MediaSource) - EndTest("Can't use appendStream() because the unprefixed MediaSource " + - "object is not present."); - - var Appender = testParams.useAppendStream ? StreamAppender : BufferAppender; - - if (testParams.testType.indexOf("A") != -1) { - appenders.push( - new Appender("audio/mp4; codecs=\"mp4a.40.2\"", - "audio.mp4", - "a", - testParams.startOffset, - testParams.appendSize)); - } - - if (testParams.testType.indexOf("V") != -1) { - appenders.push( - new Appender("video/mp4; codecs=\"avc1.640028\"", - "video.mp4", - "v", - testParams.startOffset, - testParams.appendSize)); - } - - var video = document.getElementById("v"); - video.addEventListener("error", function(e) { - console.log("video error!"); - EndTest("Video error: " + video.error); - }); - - video.id = getTestID(); - runAppendTest(video, appenders, function(stats, timestamps) { - displayResults(stats); - plotTimestamps(timestamps, testParams.graphDuration, video); - EndTest("Call back call done."); - }); - } - - function EndTest(msg) { - console.log("Ending test: " + msg); - window.__testDone = true; - } - - function getTestID() { - var id = testParams.testType; - if (testParams.useAppendStream) - id += "_stream" - else - id += "_buffer" - if (testParams.doNotWaitForBodyOnLoad) - id += "_pre_load" - else - id += "_post_load" - return id; - } - - function setupTest() { - loadTestParams(); - document.body.onload = onBodyLoad; - - if (testParams.doNotWaitForBodyOnLoad) { - startTest(); - } - } - - window["setupTest"] = setupTest; - window.__testDone = false; - window.__testMetrics = {}; -})();
diff --git a/tools/perf/page_sets/page_cycler_story.py b/tools/perf/page_sets/page_cycler_story.py index 4f631d0..1fffa45 100644 --- a/tools/perf/page_sets/page_cycler_story.py +++ b/tools/perf/page_sets/page_cycler_story.py
@@ -6,6 +6,7 @@ from telemetry.page import page from telemetry.page import cache_temperature as cache_temperature_module +from telemetry.page import traffic_setting as traffic_setting_module from telemetry.page import shared_page_state @@ -15,13 +16,19 @@ class PageCyclerStory(page.Page): def __init__(self, url, page_set, - shared_page_state_class=shared_page_state.SharedDesktopPageState, - cache_temperature=cache_temperature_module.ANY, name='', **kwargs): + shared_page_state_class=shared_page_state.SharedDesktopPageState, + cache_temperature=cache_temperature_module.ANY, name='', + traffic_setting=traffic_setting_module.NONE, **kwargs): super(PageCyclerStory, self).__init__( url=url, page_set=page_set, shared_page_state_class=shared_page_state_class, cache_temperature=cache_temperature, name=name, + traffic_setting=traffic_setting, **kwargs) + if cache_temperature != cache_temperature_module.ANY: + self.grouping_keys['cache_temperature'] = cache_temperature + if traffic_setting != traffic_setting_module.NONE: + self.grouping_keys['traffic_setting'] = traffic_setting def RunNavigateSteps(self, action_runner): url = self.file_path_url_with_scheme if self.is_file else self.url
diff --git a/tools/perf/page_sets/pathological_mobile_sites.py b/tools/perf/page_sets/pathological_mobile_sites.py index 514f3cc4..c6ca7f27 100644 --- a/tools/perf/page_sets/pathological_mobile_sites.py +++ b/tools/perf/page_sets/pathological_mobile_sites.py
@@ -10,7 +10,7 @@ def __init__(self, url, page_set): super(PathologicalMobileSitesPage, self).__init__( - url=url, page_set=page_set, credentials_path='data/credentials.json', + url=url, page_set=page_set, shared_page_state_class=shared_page_state.SharedMobilePageState, name=url)
diff --git a/tools/perf/page_sets/pregenerated_large_profile_shared_state.py b/tools/perf/page_sets/pregenerated_large_profile_shared_state.py deleted file mode 100644 index 3f81b3a..0000000 --- a/tools/perf/page_sets/pregenerated_large_profile_shared_state.py +++ /dev/null
@@ -1,18 +0,0 @@ -# Copyright 2015 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 - -from page_sets import pregenerated_profile_shared_state - - -class PregeneratedLargeProfileSharedState( - pregenerated_profile_shared_state.PregeneratedProfileSharedState): - def __init__(self, test, finder_options, story_set): - super(PregeneratedLargeProfileSharedState, self).__init__( - test, finder_options, story_set) - perf_dir = os.path.normpath( - os.path.join(os.path.dirname(__file__), os.path.pardir)) - self._pregenerated_profile_archive_dir = os.path.join( - perf_dir, 'generated_profiles', self._possible_browser.target_os, - 'large_profile.zip')
diff --git a/tools/perf/page_sets/pregenerated_profile_shared_state.py b/tools/perf/page_sets/pregenerated_profile_shared_state.py deleted file mode 100644 index 4f7cb02..0000000 --- a/tools/perf/page_sets/pregenerated_profile_shared_state.py +++ /dev/null
@@ -1,157 +0,0 @@ -# Copyright 2016 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 os -import shutil -import sys -import tempfile -import zipfile - -from py_utils import cloud_storage - -from telemetry.page import shared_page_state - - -class PregeneratedProfileSharedState(shared_page_state.SharedPageState): - def __init__(self, test, finder_options, story_set): - super(PregeneratedProfileSharedState, self).__init__( - test, finder_options, story_set) - self._unzipped_profile = None - self._migrated_profile = None - self._pregenerated_profile_archive_dir = None - - def WillRunStory(self, page): - if self._ShouldDownloadPregeneratedProfileArchive(): - self._DownloadPregeneratedProfileArchive() - - if self._ShouldMigrateProfile(): - self._MigratePregeneratedProfile() - super(PregeneratedProfileSharedState, self).WillRunStory(page) - - def TearDownState(self): - if self._unzipped_profile: - shutil.rmtree(self._unzipped_profile) - self._unzipped_profile = None - if self._migrated_profile: - shutil.rmtree(self._migrated_profile) - self._migrated_profile = None - super(PregeneratedProfileSharedState, self).TearDownState() - - def _ShouldDownloadPregeneratedProfileArchive(self): - """Whether to download a pre-generated profile archive.""" - if not self._pregenerated_profile_archive_dir: - return False - - if self._finder_options.browser_options.profile_dir: - logging.warning("Profile directory specified on command line: %s, this" - "overrides the benchmark's default profile directory.", - self._finder_options.browser_options.profile_dir) - return False - - if self._possible_browser.IsRemote(): - return False - - return True - - def _DownloadPregeneratedProfileArchive(self): - """Download and extract the profile directory archive if one exists. - - On success, updates self._finder_options.browser_options.profile_dir with - the directory of the extracted profile. - """ - try: - cloud_storage.GetIfChanged(self._pregenerated_profile_archive_dir, - cloud_storage.PUBLIC_BUCKET) - except (cloud_storage.CredentialsError, - cloud_storage.PermissionError) as e: - if os.path.exists(self._pregenerated_profile_archive_dir): - # If the profile directory archive exists, assume the user has their - # own local copy simply warn. - logging.warning('Could not download Profile archive: %s', - self._pregenerated_profile_archive_dir) - else: - # If the archive profile directory doesn't exist, this is fatal. - logging.error('Can not run without required profile archive: %s. ' - 'If you believe you have credentials, follow the ' - 'instructions below.', - self._pregenerated_profile_archive_dir) - logging.error(str(e)) - sys.exit(-1) - - # Check to make sure the zip file exists. - if not os.path.isfile(self._pregenerated_profile_archive_dir): - raise Exception("Profile directory archive not downloaded: ", - self._pregenerated_profile_archive_dir) - - # The location to extract the profile into. - self._unzipped_profile = tempfile.mkdtemp() - profile_archive_path_basename = os.path.basename( - self._pregenerated_profile_archive_dir) - extracted_profile_dir_path = os.path.join( - self._unzipped_profile, - os.path.splitext(profile_archive_path_basename)[0]) - - # Unzip profile directory. - with zipfile.ZipFile(self._pregenerated_profile_archive_dir) as f: - try: - f.extractall(self._unzipped_profile) - except Exception as e: - # Cleanup any leftovers from unzipping. - shutil.rmtree(self._unzipped_profile) - logging.error("Error extracting profile directory zip file: %s", e) - sys.exit(-1) - - if not os.path.exists(extracted_profile_dir_path): - raise Exception("Failed to extract profile: ", - extracted_profile_dir_path) - - # Run with freshly extracted profile directory. - logging.info("Using profile archive directory: %s", - extracted_profile_dir_path) - self._finder_options.browser_options.profile_dir = ( - extracted_profile_dir_path) - - def _ShouldMigrateProfile(self): - return not self._migrated_profile - - def _MigrateProfile(self, finder_options, found_browser, - initial_profile, final_profile): - """Migrates a profile to be compatible with a newer version of Chrome. - - Launching Chrome with the old profile will perform the migration. - """ - # Save the current input and output profiles. - saved_input_profile = finder_options.browser_options.profile_dir - saved_output_profile = finder_options.browser_options.output_profile_path - - # Set the input and output profiles. - finder_options.browser_options.profile_dir = initial_profile - finder_options.browser_options.output_profile_path = final_profile - - # Launch the browser, then close it. - browser = found_browser.Create(finder_options) - browser.Close() - - # Load the saved input and output profiles. - finder_options.browser_options.profile_dir = saved_input_profile - finder_options.browser_options.output_profile_path = saved_output_profile - - def _MigratePregeneratedProfile(self): - """Migrates the pre-generated profile by launching Chrome with it. - - On success, updates self._migrated_profile and - self._finder_options.browser_options.profile_dir with the directory of the - migrated profile. - """ - self._migrated_profile = tempfile.mkdtemp() - logging.info("Starting migration of pre-generated profile to %s", - self._migrated_profile) - pregenerated_profile = self._finder_options.browser_options.profile_dir - - possible_browser = self._FindBrowser(self._finder_options) - self._MigrateProfile(self._finder_options, possible_browser, - pregenerated_profile, self._migrated_profile) - self._finder_options.browser_options.profile_dir = self._migrated_profile - logging.info("Finished migration of pre-generated profile to %s", - self._migrated_profile)
diff --git a/tools/perf/page_sets/service_worker.py b/tools/perf/page_sets/service_worker.py deleted file mode 100644 index 798bfc5..0000000 --- a/tools/perf/page_sets/service_worker.py +++ /dev/null
@@ -1,42 +0,0 @@ -# Copyright 2014 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. - -from telemetry.page import page as page -from telemetry import story - - -archive_data_file_path = 'data/service_worker.json' - - -class ServiceWorkerPageSet(story.StorySet): - """Page set of applications using ServiceWorker""" - - def __init__(self): - super(ServiceWorkerPageSet, self).__init__( - archive_data_file=archive_data_file_path, - cloud_storage_bucket=story.PARTNER_BUCKET) - - # Why: the first application using ServiceWorker - # 1st time: registration - self.AddStory(page.Page( - 'https://jakearchibald.github.io/trained-to-thrill/', self, - name='first_load', make_javascript_deterministic=False)) - # 2nd time: 1st onfetch with caching - self.AddStory(page.Page( - 'https://jakearchibald.github.io/trained-to-thrill/', self, - name='second_load', make_javascript_deterministic=False)) - # 3rd time: 2nd onfetch from cache - self.AddStory(page.Page( - 'https://jakearchibald.github.io/trained-to-thrill/', self, - name='third_load', make_javascript_deterministic=False)) - - # Why: another caching strategy: cache.addAll in oninstall handler - # 1st time: registration and caching - self.AddStory(page.Page( - 'https://jakearchibald.github.io/svgomg/', self, - name='svgomg_first_load', make_javascript_deterministic=False)) - # 2nd time: onfetch from cache - self.AddStory(page.Page( - 'https://jakearchibald.github.io/svgomg/', self, - name='svgomg_second_load', make_javascript_deterministic=False))
diff --git a/tools/perf/page_sets/simple_mobile_sites.py b/tools/perf/page_sets/simple_mobile_sites.py index 587245c0..805541a4 100644 --- a/tools/perf/page_sets/simple_mobile_sites.py +++ b/tools/perf/page_sets/simple_mobile_sites.py
@@ -13,7 +13,6 @@ url=url, page_set=page_set, shared_page_state_class=shared_page_state.Shared10InchTabletPageState, - credentials_path='data/credentials.json', name=url) def RunNavigateSteps(self, action_runner):
diff --git a/tools/perf/page_sets/startup_pages.py b/tools/perf/page_sets/startup_pages.py index f9f9b1a..744db9d 100644 --- a/tools/perf/page_sets/startup_pages.py +++ b/tools/perf/page_sets/startup_pages.py
@@ -41,5 +41,13 @@ self.AddStory(StartedPage('about:blank', self)) # Typical page. self.AddStory(StartedPage('http://bbc.co.uk', self)) - # Horribly complex page - stress test! - self.AddStory(StartedPage('http://kapook.com', self)) + + +class ExperimentalStartupPagesPageSet(story.StorySet): + """Pages for testing starting Chrome with a URL.""" + + def __init__(self): + super(ExperimentalStartupPagesPageSet, self).__init__( + archive_data_file='data/startup_pages.json', + cloud_storage_bucket=story.PARTNER_BUCKET) + self.AddStory(StartedPage('http://bbc.co.uk', self))
diff --git a/tools/perf/page_sets/system_health/accessibility_stories.py b/tools/perf/page_sets/system_health/accessibility_stories.py new file mode 100644 index 0000000..aeb55aa --- /dev/null +++ b/tools/perf/page_sets/system_health/accessibility_stories.py
@@ -0,0 +1,97 @@ +# Copyright 2017 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. + +from page_sets.login_helpers import google_login + +from page_sets.system_health import platforms +from page_sets.system_health import story_tags +from page_sets.system_health import system_health_story + + +LONG_TEXT = """Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla +suscipit enim ut nunc vestibulum, vitae porta dui eleifend. Donec +condimentum ante malesuada mi sodales maximus.""" + + +class _AccessibilityStory(system_health_story.SystemHealthStory): + """Abstract base class for accessibility System Health user stories.""" + ABSTRACT_STORY = True + SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY + + def __init__(self, story_set, take_memory_measurement): + super(_AccessibilityStory, self).__init__( + story_set, take_memory_measurement, + extra_browser_args=['--force-renderer-accessibility']) + + +class AccessibilityScrollingCodeSearchStory(_AccessibilityStory): + """Tests scrolling an element within a page.""" + NAME = 'browse_accessibility:tech:codesearch' + URL = 'https://cs.chromium.org/chromium/src/ui/accessibility/platform/ax_platform_node_mac.mm' + TAGS = [story_tags.ACCESSIBILITY, story_tags.SCROLL] + + def RunNavigateSteps(self, action_runner): + super(AccessibilityScrollingCodeSearchStory, self).RunNavigateSteps( + action_runner) + action_runner.WaitForElement(text='// namespace ui') + action_runner.ScrollElement(selector='#file_scroller', distance=1000) + + +class AccessibilityWikipediaStory(_AccessibilityStory): + """Wikipedia page on Accessibility. Long, but very simple, clean layout.""" + NAME = 'load_accessibility:media:wikipedia' + URL = 'https://en.wikipedia.org/wiki/Accessibility' + TAGS = [story_tags.ACCESSIBILITY] + + +class AccessibilityAmazonStory(_AccessibilityStory): + """Amazon results page. Good example of a site with a data table.""" + NAME = 'load_accessibility:shopping:amazon' + URL = 'https://www.amazon.com/gp/offer-listing/B01IENFJ14' + TAGS = [story_tags.ACCESSIBILITY] + + +class AccessibilityGmailComposeStory(_AccessibilityStory): + """Tests typing a lot of text into a Gmail compose window.""" + NAME = 'browse_accessibility:tools:gmail_compose' + URL = 'https://mail.google.com/mail/#inbox?compose=new' + TAGS = [story_tags.ACCESSIBILITY, story_tags.KEYBOARD_INPUT] + + def RunNavigateSteps(self, action_runner): + google_login.LoginGoogleAccount(action_runner, 'googletest') + + # Navigating to https://mail.google.com immediately leads to an infinite + # redirection loop due to a bug in WPR (see + # https://github.com/chromium/web-page-replay/issues/70). We therefore first + # navigate to a sub-URL to set up the session and hit the resulting + # redirection loop. Afterwards, we can safely navigate to + # https://mail.google.com. + action_runner.tab.WaitForDocumentReadyStateToBeComplete() + action_runner.Navigate( + 'https://mail.google.com/mail/mu/mp/872/trigger_redirection_loop') + action_runner.tab.WaitForDocumentReadyStateToBeComplete() + + super(AccessibilityGmailComposeStory, self).RunNavigateSteps( + action_runner) + + action_runner.WaitForJavaScriptCondition( + 'document.getElementById("loading").style.display === "none"') + + # Tab from the To field to the message body. + action_runner.WaitForElement(selector='#\\:gr') + action_runner.PressKey('Tab') + action_runner.PressKey('Tab') + + # EnterText doesn't handle newlines for some reason. + long_text = LONG_TEXT.replace('\n', ' ') + + # Enter some text + action_runner.EnterText(long_text, character_delay_ms=1) + + # Move up a couple of lines and then enter it again, this causes + # a huge amount of wrapping and re-layout + action_runner.PressKey('Home') + action_runner.PressKey('ArrowUp') + action_runner.PressKey('ArrowUp') + action_runner.EnterText(long_text, character_delay_ms=1)
diff --git a/tools/perf/page_sets/system_health/browsing_stories.py b/tools/perf/page_sets/system_health/browsing_stories.py index 124177a4..52c9377 100644 --- a/tools/perf/page_sets/system_health/browsing_stories.py +++ b/tools/perf/page_sets/system_health/browsing_stories.py
@@ -2,8 +2,6 @@ # Copyright 2016 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 - from page_sets.system_health import platforms from page_sets.system_health import story_tags from page_sets.system_health import system_health_story @@ -477,8 +475,7 @@ SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY def _Login(self, action_runner): - pinterest_login.LoginDesktopAccount(action_runner, 'googletest', - self.credentials_path) + pinterest_login.LoginDesktopAccount(action_runner, 'googletest') def _ViewMediaItem(self, action_runner, index): super(PinterestDesktopStory, self)._ViewMediaItem(action_runner, index) @@ -689,13 +686,7 @@ != null) ''' SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY - TAGS = [story_tags.JAVASCRIPT_HEAVY] - - def CanRunOnBrowser(self, browser_info, _): - if not browser_info.HasWebGLSupport(): - logging.warning('Browser does not support webgl, skipping test') - return False - return True + TAGS = [story_tags.JAVASCRIPT_HEAVY, story_tags.WEBGL] def _DidLoadDocument(self, action_runner): # Click on the search box. @@ -715,7 +706,7 @@ action_runner.ClickElement(selector=self._MAPS_ZOOM_IN_SELECTOR) action_runner.WaitForJavaScriptCondition( self._CHECK_RESTAURANTS_UPDATED, - old_restaurant=prev_restaurant_hash) + old_restaurant=prev_restaurant_hash, timeout=90) # This wait is required to fetch the data for all the tiles in the map. action_runner.Wait(1) @@ -724,7 +715,7 @@ action_runner.ClickElement(selector=self._MAPS_ZOOM_IN_SELECTOR) action_runner.WaitForJavaScriptCondition( self._CHECK_RESTAURANTS_UPDATED, - old_restaurant=prev_restaurant_hash) + old_restaurant=prev_restaurant_hash, timeout=90) # This wait is required to fetch the data for all the tiles in the map. action_runner.Wait(1) @@ -739,7 +730,7 @@ repeat_count=2, speed=500, timeout=120, repeat_delay_ms=2000) action_runner.WaitForJavaScriptCondition( self._CHECK_RESTAURANTS_UPDATED, - old_restaurant=prev_restaurant_hash) + old_restaurant=prev_restaurant_hash, timeout=90) prev_restaurant_hash = action_runner.EvaluateJavaScript( self._GET_RESTAURANT_RESPONSE_HASH) @@ -748,7 +739,7 @@ repeat_count=2, speed=500, timeout=120, repeat_delay_ms=2000) action_runner.WaitForJavaScriptCondition( self._CHECK_RESTAURANTS_UPDATED, - old_restaurant=prev_restaurant_hash) + old_restaurant=prev_restaurant_hash, timeout=90) # To make the recording more realistic. action_runner.Wait(1) @@ -783,13 +774,7 @@ _EARTH_BUTTON_SELECTOR = '[aria-labelledby="widget-minimap-caption"]' _EARTH_ZOOM_IN_SELECTOR = '[aria-label="Zoom in"]' SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY - TAGS = [story_tags.JAVASCRIPT_HEAVY] - - def CanRunOnBrowser(self, browser_info, _): - if not browser_info.HasWebGLSupport(): - logging.warning('Browser does not support webgl, skipping test') - return False - return True + TAGS = [story_tags.JAVASCRIPT_HEAVY, story_tags.WEBGL] def _DidLoadDocument(self, action_runner): # Zommin three times. @@ -906,8 +891,7 @@ SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY def _Login(self, action_runner): - facebook_login.LoginWithMobileSite( - action_runner, 'facebook3', self.credentials_path) + facebook_login.LoginWithMobileSite(action_runner, 'facebook3') class FlickrDesktopStory(_InfiniteScrollStory):
diff --git a/tools/perf/page_sets/system_health/expectations.py b/tools/perf/page_sets/system_health/expectations.py deleted file mode 100644 index 9c12256..0000000 --- a/tools/perf/page_sets/system_health/expectations.py +++ /dev/null
@@ -1,162 +0,0 @@ -# Copyright 2017 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. -from telemetry.story import expectations - - -class SystemHealthDesktopCommonExpectations(expectations.StoryExpectations): - def SetExpectations(self): - self.DisableStory('browse:news:hackernews', - [expectations.ALL_WIN, expectations.ALL_MAC], - 'crbug.com/676336') - self.DisableStory('browse:search:google', - [expectations.ALL_WIN], - 'win:crbug.com/673775, mac:crbug.com/756027') - self.DisableStory('browse:tools:maps', [expectations.ALL], - 'crbug.com/712694') - self.DisableStory('browse:tools:earth', [expectations.ALL], - 'crbug.com/708590') - self.DisableStory('play:media:google_play_music', [expectations.ALL], - 'crbug.com/649392') - self.DisableStory('play:media:soundcloud', [expectations.ALL_WIN], - 'crbug.com/649392') - self.DisableStory('play:media:pandora', [expectations.ALL], - 'crbug.com/64939') - self.DisableStory('browse:media:tumblr', - [expectations.MAC_10_11], 'crbug.com/760966') - self.DisableStory('browse:news:cnn', - [expectations.ALL_MAC], 'crbug.com/728576') - - -class SystemHealthDesktopMemoryExpectations(expectations.StoryExpectations): - def SetExpectations(self): - self.DisableStory('browse:news:hackernews', - [expectations.ALL_WIN, expectations.ALL_MAC], - 'crbug.com/676336') - self.DisableStory('browse:search:google', [expectations.ALL_WIN], - 'crbug.com/673775') - self.DisableStory('browse:tools:maps', [expectations.ALL], - 'crbug.com/712694') - self.DisableStory('browse:tools:earth', [expectations.ALL], - 'crbug.com/708590') - self.DisableStory('load:games:miniclip', [expectations.ALL_MAC], - 'crbug.com/664661') - self.DisableStory('play:media:google_play_music', [expectations.ALL], - 'crbug.com/649392') - self.DisableStory('play:media:soundcloud', [expectations.ALL_WIN], - 'crbug.com/649392') - self.DisableStory('play:media:pandora', [expectations.ALL], - 'crbug.com/64939') - self.DisableStory('browse:media:tumblr', - [expectations.MAC_10_11], 'crbug.com/760966') - self.DisableStory('browse:news:cnn', - [expectations.ALL_MAC], 'crbug.com/728576') - self.DisableStory('browse:social:twitter_infinite_scroll', - [expectations.ALL_WIN], 'crbug.com/728464') - self.DisableStory('multitab:misc:typical24', - [expectations.ALL_MAC], 'crbug.com/742475') - - -class SystemHealthMobileCommonExpectations(expectations.StoryExpectations): - def SetExpectations(self): - self.DisableStory('browse:shopping:flipkart', [expectations.ALL_ANDROID], - 'crbug.com/708300') - self.DisableStory('browse:news:globo', [expectations.ALL_ANDROID], - 'crbug.com/714650') - self.DisableStory('load:tools:gmail', [expectations.ALL_ANDROID], - 'crbug.com/657433') - self.DisableStory('browse:news:toi', [expectations.ALL_ANDROID], - 'crbug.com/728081') - self.DisableStory( - 'load:tools:drive', - [expectations.ANDROID_NEXUS5X, expectations.ANDROID_WEBVIEW], - 'crbug.com/738854') - # TODO(rnephew): This disabling should move to CanRunOnBrowser. - self.DisableStory('browse:chrome:omnibox', - [expectations.ANDROID_WEBVIEW], - 'Webview does not have omnibox') - # TODO(rnephew): This disabling should move to CanRunOnBrowser. - self.DisableStory('browse:chrome:newtab', - [expectations.ANDROID_WEBVIEW], - 'Webview does not have NTP') - # TODO(rnephew): This disabling should move to CanRunOnBrowser. - self.DisableStory('long_running:tools:gmail-background', - [expectations.ANDROID_WEBVIEW], - 'Webview does not have tabs') - self.DisableStory('browse:shopping:avito', - [expectations.ANDROID_NEXUS6], 'crbug.com/736497') - - -class SystemHealthMobileMemoryExpectations(expectations.StoryExpectations): - def SetExpectations(self): - self.DisableStory('long_running:tools:gmail-background', - [expectations.ANDROID_ONE], 'crbug.com/764924') - self.DisableStory('browse:shopping:flipkart', [expectations.ALL_ANDROID], - 'crbug.com/708300') - self.DisableStory('browse:news:globo', [expectations.ALL_ANDROID], - 'crbug.com/714650') - self.DisableStory('load:tools:gmail', [expectations.ALL_ANDROID], - 'crbug.com/657433') - self.DisableStory('browse:news:toi', [expectations.ALL_ANDROID], - 'crbug.com/728081') - self.DisableStory( - 'load:tools:drive', - [expectations.ANDROID_NEXUS5X, expectations.ANDROID_WEBVIEW], - 'crbug.com/738854') - # TODO(rnephew): This disabling should move to CanRunOnBrowser. - self.DisableStory('browse:chrome:omnibox', - [expectations.ANDROID_WEBVIEW], - 'Webview does not have omnibox') - # TODO(rnephew): This disabling should move to CanRunOnBrowser. - self.DisableStory('browse:chrome:newtab', - [expectations.ANDROID_WEBVIEW], - 'Webview does not have NTP') - # TODO(rnephew): This disabling should move to CanRunOnBrowser. - self.DisableStory('long_running:tools:gmail-background', - [expectations.ANDROID_WEBVIEW], - 'Webview does not have tabs') - - -# Should only include browse:*:* stories. -class V8BrowsingDesktopExpecations(expectations.StoryExpectations): - def SetExpectations(self): - self.DisableStory('browse:news:hackernews', - [expectations.ALL_WIN, expectations.ALL_MAC], - 'crbug.com/676336') - self.DisableStory('browse:news:reddit', [expectations.ALL_DESKTOP], - 'crbug.com/759777') - self.DisableStory('browse:news:cnn', [expectations.ALL_DESKTOP], - 'mac:crbug.com/728576, all:crbug.com/759777') - self.DisableStory('browse:tools:earth', [expectations.ALL_DESKTOP], - 'crbug.com/708590') - self.DisableStory('browse:tools:maps', [expectations.ALL_DESKTOP], - 'crbug.com/712694') - - -# Should only include browse:*:* stories. -class V8BrowsingMobileExpecations(expectations.StoryExpectations): - def SetExpectations(self): - self.DisableStory('browse:shopping:flipkart', [expectations.ALL_ANDROID], - 'crbug.com/708300') - self.DisableStory('browse:news:cnn', [expectations.ANDROID_NEXUS5X], - 'crbug.com/714650') - self.DisableStory('browse:news:globo', [expectations.ALL_ANDROID], - 'crbug.com/714650') - self.DisableStory('browse:news:toi', [expectations.ALL_ANDROID], - 'crbug.com/728081') - # TODO(rnephew): This disabling should move to CanRunOnBrowser. - self.DisableStory('browse:chrome:omnibox', - [expectations.ANDROID_WEBVIEW], - 'Webview does not have omnibox') - # TODO(rnephew): This disabling should move to CanRunOnBrowser. - self.DisableStory('browse:chrome:newtab', - [expectations.ANDROID_WEBVIEW], - 'Webview does not have NTP') - self.DisableStory('browse:news:cnn', - [expectations.ANDROID_WEBVIEW], - 'Crash: crbug.com/767595') - - -class SystemHealthWebviewStartupExpectations(expectations.StoryExpectations): - def SetExpectations(self): - pass
diff --git a/tools/perf/page_sets/system_health/loading_stories.py b/tools/perf/page_sets/system_health/loading_stories.py index 1000951..31545fe 100644 --- a/tools/perf/page_sets/system_health/loading_stories.py +++ b/tools/perf/page_sets/system_health/loading_stories.py
@@ -288,8 +288,7 @@ ABSTRACT_STORY = True def _Login(self, action_runner): - google_login.LoginGoogleAccount(action_runner, 'googletest', - self.credentials_path) + google_login.LoginGoogleAccount(action_runner, 'googletest') # Navigating to https://mail.google.com immediately leads to an infinite # redirection loop due to a bug in WPR (see @@ -333,7 +332,7 @@ URL = 'https://www.dropbox.com' def _Login(self, action_runner): - dropbox_login.LoginAccount(action_runner, 'dropbox', self.credentials_path) + dropbox_login.LoginAccount(action_runner, 'dropbox') class LoadWeatherStory(_LoadingStory): @@ -348,8 +347,7 @@ TAGS = [story_tags.JAVASCRIPT_HEAVY] def _Login(self, action_runner): - google_login.LoginGoogleAccount(action_runner, 'googletest', - self.credentials_path) + google_login.LoginGoogleAccount(action_runner, 'googletest') ################################################################################
diff --git a/tools/perf/page_sets/system_health/long_running_stories.py b/tools/perf/page_sets/system_health/long_running_stories.py index 45d11a4c..830545d 100644 --- a/tools/perf/page_sets/system_health/long_running_stories.py +++ b/tools/perf/page_sets/system_health/long_running_stories.py
@@ -49,8 +49,7 @@ ABSTRACT_STORY = True def _Login(self, action_runner): - google_login.LoginGoogleAccount(action_runner, 'googletest', - self.credentials_path) + google_login.LoginGoogleAccount(action_runner, 'googletest') # Navigating to https://mail.google.com immediately leads to an infinite # redirection loop due to a bug in WPR (see @@ -65,11 +64,6 @@ class _LongRunningGmailMobileBase(_LongRunningGmailBase): SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY - @classmethod - def ShouldDisable(cls, possible_browser): - # crbug.com/651198 - return possible_browser.platform.IsSvelte() - def _DidLoadDocument(self, action_runner): # Close the "Get Inbox by Gmail" interstitial. action_runner.WaitForJavaScriptCondition(
diff --git a/tools/perf/page_sets/system_health/media_stories.py b/tools/perf/page_sets/system_health/media_stories.py index 3266046e..2ccc7b8 100644 --- a/tools/perf/page_sets/system_health/media_stories.py +++ b/tools/perf/page_sets/system_health/media_stories.py
@@ -65,8 +65,7 @@ NAVIGATE_SELECTOR = '.description.tooltip.fade-out' def _Login(self, action_runner): - google_login.LoginGoogleAccount(action_runner, 'googletest', - self.credentials_path) + google_login.LoginGoogleAccount(action_runner, 'googletest') def _NavigateToMedia(self, action_runner): # Clicks on Today's top hits. @@ -107,7 +106,7 @@ SEARCH_SELECTOR = '.searchInput' def _Login(self, action_runner): - pandora_login.LoginAccount(action_runner, 'pandora', self.credentials_path) + pandora_login.LoginAccount(action_runner, 'pandora') def _NavigateToMedia(self, action_runner): pass # Audio autoplays on Pandora, no need to search.
diff --git a/tools/perf/page_sets/system_health/story_tags.py b/tools/perf/page_sets/system_health/story_tags.py index e296808cd..6f43e42f 100644 --- a/tools/perf/page_sets/system_health/story_tags.py +++ b/tools/perf/page_sets/system_health/story_tags.py
@@ -11,6 +11,8 @@ # Below are tags that describe various aspect of system health stories. # A story can have multiple tags. All the tags should be noun. +ACCESSIBILITY = Tag( + 'accessibility', 'Story tests performance when accessibility is enabled.') AUDIO_PLAYBACK = Tag( 'audio_playback', 'Story has audio playing.') CANVAS_ANIMATION = Tag( @@ -34,6 +36,8 @@ 'of JavaScript. The story uses 20Mb+ memory for javascript and local ' 'run with "v8" category enabled also shows the trace has js slices across ' 'the whole run.') +KEYBOARD_INPUT = Tag( + 'keyboard_input', 'Story does keyboard input.') SCROLL = Tag( 'scroll', 'Story has scroll gestures & scroll animation.') PINCH_ZOOM = Tag(
diff --git a/tools/perf/page_sets/system_health/system_health_story.py b/tools/perf/page_sets/system_health/system_health_story.py index ffa7b26f..95620b4 100644 --- a/tools/perf/page_sets/system_health/system_health_story.py +++ b/tools/perf/page_sets/system_health/system_health_story.py
@@ -15,6 +15,18 @@ _WAIT_TIME_AFTER_LOAD = 10 +class _SystemHealthSharedState(shared_page_state.SharedPageState): + """Shared state which enables disabling stories on individual platforms. + This should be used only to disable the stories permanently. For + disabling stories temporarily use story expectations in ./expectations.py. + """ + + def CanRunOnBrowser(self, browser_info, story): + if story.TAGS and story_tags.WEBGL in story.TAGS: + return browser_info.HasWebGLSupport() + return True + + class _MetaSystemHealthStory(type): """Metaclass for SystemHealthStory.""" @@ -42,7 +54,8 @@ TAGS = None PLATFORM_SPECIFIC = False - def __init__(self, story_set, take_memory_measurement): + def __init__(self, story_set, take_memory_measurement, + extra_browser_args=None): case, group, _ = self.NAME.split(':') tags = [] if self.TAGS: @@ -50,11 +63,11 @@ assert t in story_tags.ALL_TAGS tags.append(t.name) super(SystemHealthStory, self).__init__( - shared_page_state_class=shared_page_state.SharedPageState, + shared_page_state_class=_SystemHealthSharedState, page_set=story_set, name=self.NAME, url=self.URL, tags=tags, - credentials_path='../data/credentials.json', grouping_keys={'case': case, 'group': group}, - platform_specific=self.PLATFORM_SPECIFIC) + platform_specific=self.PLATFORM_SPECIFIC, + extra_browser_args=extra_browser_args) self._take_memory_measurement = take_memory_measurement @classmethod @@ -72,15 +85,6 @@ """ return None - @classmethod - def ShouldDisable(cls, possible_browser): - """Override this method to disable a story under specific conditions. - - This method is modelled after telemetry.benchmark.Benchmark.ShouldDisable(). - """ - del possible_browser - return False - def _Measure(self, action_runner): if self._take_memory_measurement: action_runner.MeasureMemory(deterministic_mode=True)
diff --git a/tools/perf/page_sets/top_10.py b/tools/perf/page_sets/top_10.py index 2d7b0a4..ab9029b 100644 --- a/tools/perf/page_sets/top_10.py +++ b/tools/perf/page_sets/top_10.py
@@ -7,14 +7,12 @@ class SimplePage(page_module.Page): - def __init__(self, url, page_set, credentials='', name=''): + def __init__(self, url, page_set, name=''): if name == '': name = url super(SimplePage, self).__init__( url, page_set=page_set, name=name, - credentials_path='data/credentials.json', shared_page_state_class=shared_page_state.SharedDesktopPageState) - self.credentials = credentials def RunPageInteractions(self, action_runner): pass @@ -34,8 +32,7 @@ def __init__(self, page_set): super(Gmail, self).__init__( url='https://mail.google.com/mail/', - page_set=page_set, - credentials='google') + page_set=page_set) def RunNavigateSteps(self, action_runner): super(Gmail, self).RunNavigateSteps(action_runner) @@ -48,8 +45,7 @@ def __init__(self, page_set): super(GoogleCalendar, self).__init__( url='https://www.google.com/calendar/', - page_set=page_set, - credentials='google') + page_set=page_set) def RunNavigateSteps(self, action_runner): super(GoogleCalendar, self).RunNavigateSteps(action_runner) @@ -67,8 +63,7 @@ def __init__(self, page_set): super(Youtube, self).__init__( url='http://www.youtube.com', - page_set=page_set, - credentials='google') + page_set=page_set) def RunNavigateSteps(self, action_runner): super(Youtube, self).RunNavigateSteps(action_runner) @@ -80,7 +75,6 @@ super(Facebook, self).__init__( url='https://www.facebook.com/barackobama', page_set=page_set, - credentials='facebook2', name='Facebook') def RunNavigateSteps(self, action_runner):
diff --git a/tools/perf/page_sets/top_25_pages.py b/tools/perf/page_sets/top_25_pages.py index af23583..16e9303 100644 --- a/tools/perf/page_sets/top_25_pages.py +++ b/tools/perf/page_sets/top_25_pages.py
@@ -61,8 +61,3 @@ self.AddStory( page.Page(url, self, shared_page_state_class=shared_desktop_state, name=url)) - -class Top25StoryExpectations(story.expectations.StoryExpectations): - def SetExpectations(self): - self.DisableStory( - 'http://www.cnn.com', [story.expectations.ALL], 'crbug.com/528472')
diff --git a/tools/perf/page_sets/top_25_smooth.py b/tools/perf/page_sets/top_25_smooth.py index 42296c5..6ae9e27 100644 --- a/tools/perf/page_sets/top_25_smooth.py +++ b/tools/perf/page_sets/top_25_smooth.py
@@ -8,130 +8,153 @@ from page_sets import top_pages -def _IssueMarkerAndScroll(action_runner): +def _IssueMarkerAndScroll(action_runner, scroll_forever): with action_runner.CreateGestureInteraction('ScrollAction'): action_runner.ScrollPage() + if scroll_forever: + while True: + action_runner.ScrollPage(direction='up') + action_runner.ScrollPage(direction='down') def _CreatePageClassWithSmoothInteractions(page_cls): + class DerivedSmoothPage(page_cls): # pylint: disable=no-init def RunPageInteractions(self, action_runner): action_runner.Wait(1) - _IssueMarkerAndScroll(action_runner) + _IssueMarkerAndScroll(action_runner, self.story_set.scroll_forever) + return DerivedSmoothPage class TopSmoothPage(page_module.Page): - def __init__(self, url, page_set, name='', credentials=None): + def __init__(self, url, page_set, name='', extra_browser_args=None): if name == '': name = url super(TopSmoothPage, self).__init__( - url=url, page_set=page_set, name=name, + url=url, + page_set=page_set, + name=name, shared_page_state_class=shared_page_state.SharedDesktopPageState, - credentials_path='data/credentials.json') - self.credentials = credentials + extra_browser_args=extra_browser_args) def RunPageInteractions(self, action_runner): action_runner.Wait(1) - _IssueMarkerAndScroll(action_runner) + _IssueMarkerAndScroll(action_runner, self.story_set.scroll_forever) class GmailSmoothPage(top_pages.GmailPage): - """ Why: productivity, top google properties """ - def __init__(self, page_set, - shared_page_state_class=shared_page_state.SharedPageState): - super(GmailSmoothPage, self).__init__( - page_set=page_set, - shared_page_state_class=shared_page_state_class) - def RunPageInteractions(self, action_runner): - action_runner.ExecuteJavaScript(''' + action_runner.ExecuteJavaScript(""" gmonkey.load('2.0', function(api) { window.__scrollableElementForTelemetry = api.getScrollableElement(); - });''') + });""") action_runner.WaitForJavaScriptCondition( 'window.__scrollableElementForTelemetry != null') action_runner.Wait(1) with action_runner.CreateGestureInteraction('ScrollAction'): action_runner.ScrollElement( element_function='window.__scrollableElementForTelemetry') + if self.story_set.scroll_forever: + while True: + action_runner.ScrollElement( + direction='up', + element_function='window.__scrollableElementForTelemetry') + action_runner.ScrollElement( + direction='down', + element_function='window.__scrollableElementForTelemetry') class GoogleCalendarSmoothPage(top_pages.GoogleCalendarPage): - """ Why: productivity, top google properties """ def RunPageInteractions(self, action_runner): action_runner.Wait(1) with action_runner.CreateGestureInteraction('ScrollAction'): action_runner.ScrollElement(selector='#scrolltimedeventswk') + if self.story_set.scroll_forever: + while True: + action_runner.ScrollElement( + direction='up', selector='#scrolltimedeventswk') + action_runner.ScrollElement( + direction='down', selector='#scrolltimedeventswk') class GoogleDocSmoothPage(top_pages.GoogleDocPage): - """ Why: productivity, top google properties; Sample doc in the link """ def RunPageInteractions(self, action_runner): action_runner.Wait(1) with action_runner.CreateGestureInteraction('ScrollAction'): action_runner.ScrollElement(selector='.kix-appview-editor') + if self.story_set.scroll_forever: + while True: + action_runner.ScrollElement( + direction='up', selector='.kix-appview-editor') + action_runner.ScrollElement( + direction='down', selector='.kix-appview-editor') class ESPNSmoothPage(top_pages.ESPNPage): - """ Why: #1 sports """ def RunPageInteractions(self, action_runner): action_runner.Wait(1) with action_runner.CreateGestureInteraction('ScrollAction'): action_runner.ScrollPage(left_start_ratio=0.1) + if self.story_set.scroll_forever: + while True: + action_runner.ScrollPage(direction='up', left_start_ratio=0.1) + action_runner.ScrollPage(direction='down', left_start_ratio=0.1) class Top25SmoothPageSet(story.StorySet): - """ Pages hand-picked for 2012 CrOS scrolling tuning efforts. """ - def __init__(self, techcrunch=True): + def __init__(self, scroll_forever=False): super(Top25SmoothPageSet, self).__init__( archive_data_file='data/top_25_smooth.json', cloud_storage_bucket=story.PARTNER_BUCKET) + self.scroll_forever = scroll_forever + desktop_state_class = shared_page_state.SharedDesktopPageState - self.AddStory(_CreatePageClassWithSmoothInteractions( - top_pages.GoogleWebSearchPage)(self, desktop_state_class)) - self.AddStory(GmailSmoothPage(self, desktop_state_class)) - self.AddStory(GoogleCalendarSmoothPage(self, desktop_state_class)) - self.AddStory(_CreatePageClassWithSmoothInteractions( - top_pages.GoogleImageSearchPage)(self, desktop_state_class)) - self.AddStory(GoogleDocSmoothPage(self, desktop_state_class)) - self.AddStory(_CreatePageClassWithSmoothInteractions( - top_pages.GooglePlusPage)(self, desktop_state_class)) - self.AddStory(_CreatePageClassWithSmoothInteractions( - top_pages.YoutubePage)(self, desktop_state_class)) - self.AddStory(_CreatePageClassWithSmoothInteractions( - top_pages.BlogspotPage)(self, desktop_state_class)) - self.AddStory(_CreatePageClassWithSmoothInteractions( - top_pages.WordpressPage)(self, desktop_state_class)) - self.AddStory(_CreatePageClassWithSmoothInteractions( - top_pages.FacebookPage)(self, desktop_state_class)) - self.AddStory(_CreatePageClassWithSmoothInteractions( - top_pages.LinkedinPage)(self, desktop_state_class)) - self.AddStory(_CreatePageClassWithSmoothInteractions( - top_pages.WikipediaPage)(self, desktop_state_class)) - self.AddStory(_CreatePageClassWithSmoothInteractions( - top_pages.TwitterPage)(self, desktop_state_class)) - self.AddStory(_CreatePageClassWithSmoothInteractions( - top_pages.PinterestPage)(self, desktop_state_class)) - self.AddStory(ESPNSmoothPage(self, desktop_state_class)) - self.AddStory(_CreatePageClassWithSmoothInteractions( - top_pages.WeatherPage)(self, desktop_state_class)) - self.AddStory(_CreatePageClassWithSmoothInteractions( - top_pages.YahooGamesPage)(self, desktop_state_class)) + smooth_page_classes = [ + GmailSmoothPage, + GoogleCalendarSmoothPage, + GoogleDocSmoothPage, + ESPNSmoothPage, + ] + + for smooth_page_class in smooth_page_classes: + self.AddStory( + smooth_page_class(self, shared_page_state_class=desktop_state_class)) + + non_smooth_page_classes = [ + top_pages.GoogleWebSearchPage, + top_pages.GoogleImageSearchPage, + top_pages.GooglePlusPage, + top_pages.YoutubePage, + top_pages.BlogspotPage, + top_pages.WordpressPage, + top_pages.FacebookPage, + top_pages.LinkedinPage, + top_pages.WikipediaPage, + top_pages.TwitterPage, + top_pages.PinterestPage, + top_pages.WeatherPage, + top_pages.YahooGamesPage, + ] + + for non_smooth_page_class in non_smooth_page_classes: + self.AddStory( + _CreatePageClassWithSmoothInteractions(non_smooth_page_class)( + self, shared_page_state_class=desktop_state_class)) other_urls = [ # Why: #1 news worldwide (Alexa global) @@ -149,11 +172,9 @@ 'http://answers.yahoo.com', # Why: #1 Alexa sports 'http://sports.yahoo.com/', + # Why: top tech blog + 'http://techcrunch.com', ] - if techcrunch: - # Why: top tech blog - other_urls.append('http://techcrunch.com') - for url in other_urls: self.AddStory(TopSmoothPage(url, self))
diff --git a/tools/perf/page_sets/top_pages.py b/tools/perf/page_sets/top_pages.py index bf15991..04c296b1 100644 --- a/tools/perf/page_sets/top_pages.py +++ b/tools/perf/page_sets/top_pages.py
@@ -9,27 +9,36 @@ class TopPages(page_module.Page): - def __init__(self, url, page_set, shared_page_state_class, - name='', credentials=None): + def __init__(self, + url, + page_set, + shared_page_state_class, + name='', + extra_browser_args=None): if name == '': name = url super(TopPages, self).__init__( - url=url, page_set=page_set, name=name, - credentials_path='data/credentials.json', - shared_page_state_class=shared_page_state_class) - self.credentials = credentials + url=url, + page_set=page_set, + shared_page_state_class=shared_page_state_class, + name=name, + extra_browser_args=extra_browser_args) class GoogleWebSearchPage(TopPages): - """ Why: top google property; a google tab is often open """ - def __init__(self, page_set, - shared_page_state_class=shared_page_state.SharedPageState): + def __init__(self, + page_set, + shared_page_state_class=shared_page_state.SharedPageState, + name='', + extra_browser_args=None): super(GoogleWebSearchPage, self).__init__( url='https://www.google.com/#hl=en&q=barack+obama', page_set=page_set, - shared_page_state_class=shared_page_state_class) + shared_page_state_class=shared_page_state_class, + name=name, + extra_browser_args=extra_browser_args) def RunNavigateSteps(self, action_runner): super(GoogleWebSearchPage, self).RunNavigateSteps(action_runner) @@ -37,36 +46,42 @@ class GoogleImageSearchPage(TopPages): - """ Why: tough image case; top google properties """ - def __init__(self, page_set, - shared_page_state_class=shared_page_state.SharedPageState): + def __init__(self, + page_set, + shared_page_state_class=shared_page_state.SharedPageState, + name='', + extra_browser_args=None): super(GoogleImageSearchPage, self).__init__( 'https://www.google.com/search?q=cats&tbm=isch', page_set=page_set, - shared_page_state_class=shared_page_state_class) + shared_page_state_class=shared_page_state_class, + name=name, + extra_browser_args=extra_browser_args) def RunNavigateSteps(self, action_runner): - google_login.LoginGoogleAccount(action_runner, 'googletest', - self.credentials_path) + google_login.LoginGoogleAccount(action_runner, 'googletest') super(GoogleImageSearchPage, self).RunNavigateSteps(action_runner) class GmailPage(TopPages): - """ Why: productivity, top google properties """ - def __init__(self, page_set, - shared_page_state_class=shared_page_state.SharedPageState): + def __init__(self, + page_set, + shared_page_state_class=shared_page_state.SharedPageState, + name='', + extra_browser_args=None): super(GmailPage, self).__init__( url='https://mail.google.com/mail/', page_set=page_set, - shared_page_state_class=shared_page_state_class) + shared_page_state_class=shared_page_state_class, + name=name, + extra_browser_args=extra_browser_args) def RunNavigateSteps(self, action_runner): - google_login.LoginGoogleAccount(action_runner, 'googletest', - self.credentials_path) + google_login.LoginGoogleAccount(action_runner, 'googletest') super(GmailPage, self).RunNavigateSteps(action_runner) action_runner.WaitForJavaScriptCondition( 'window.gmonkey !== undefined &&' @@ -74,48 +89,54 @@ class GoogleCalendarPage(TopPages): - """ Why: productivity, top google properties """ - def __init__(self, page_set, - shared_page_state_class=shared_page_state.SharedPageState): + def __init__(self, + page_set, + shared_page_state_class=shared_page_state.SharedPageState, + name='', + extra_browser_args=None): super(GoogleCalendarPage, self).__init__( url='https://www.google.com/calendar/', page_set=page_set, - shared_page_state_class=shared_page_state_class) + shared_page_state_class=shared_page_state_class, + name=name, + extra_browser_args=extra_browser_args) def RunNavigateSteps(self, action_runner): - google_login.LoginGoogleAccount(action_runner, 'googletest', - self.credentials_path) + google_login.LoginGoogleAccount(action_runner, 'googletest') super(GoogleCalendarPage, self).RunNavigateSteps(action_runner) action_runner.Wait(2) action_runner.WaitForElement('div[class~="navForward"]') - action_runner.ExecuteJavaScript(''' + action_runner.ExecuteJavaScript(""" (function() { var elem = document.createElement('meta'); elem.name='viewport'; elem.content='initial-scale=1'; document.body.appendChild(elem); - })();''') + })();""") action_runner.Wait(1) class GoogleDocPage(TopPages): - """ Why: productivity, top google properties; Sample doc in the link """ - def __init__(self, page_set, - shared_page_state_class=shared_page_state.SharedPageState): + def __init__(self, + page_set, + shared_page_state_class=shared_page_state.SharedPageState, + name='Docs_(1_open_document_tab)', + extra_browser_args=None): super(GoogleDocPage, self).__init__( # pylint: disable=line-too-long - url='https://docs.google.com/document/d/1X-IKNjtEnx-WW5JIKRLsyhz5sbsat3mfTpAPUSX3_s4/view', + url= + 'https://docs.google.com/document/d/1X-IKNjtEnx-WW5JIKRLsyhz5sbsat3mfTpAPUSX3_s4/view', page_set=page_set, - name='Docs (1 open document tab)', - shared_page_state_class=shared_page_state_class) + shared_page_state_class=shared_page_state_class, + name=name, + extra_browser_args=extra_browser_args) def RunNavigateSteps(self, action_runner): - google_login.LoginGoogleAccount(action_runner, 'googletest', - self.credentials_path) + google_login.LoginGoogleAccount(action_runner, 'googletest') super(GoogleDocPage, self).RunNavigateSteps(action_runner) action_runner.Wait(2) action_runner.WaitForJavaScriptCondition( @@ -123,53 +144,62 @@ class GooglePlusPage(TopPages): - """ Why: social; top google property; Public profile; infinite scrolls """ - def __init__(self, page_set, - shared_page_state_class=shared_page_state.SharedPageState): + def __init__(self, + page_set, + shared_page_state_class=shared_page_state.SharedPageState, + name='', + extra_browser_args=None): super(GooglePlusPage, self).__init__( url='https://plus.google.com/110031535020051778989/posts', page_set=page_set, - shared_page_state_class=shared_page_state_class) + shared_page_state_class=shared_page_state_class, + name=name, + extra_browser_args=extra_browser_args) def RunNavigateSteps(self, action_runner): - google_login.LoginGoogleAccount(action_runner, 'googletest', - self.credentials_path) + google_login.LoginGoogleAccount(action_runner, 'googletest') super(GooglePlusPage, self).RunNavigateSteps(action_runner) action_runner.WaitForElement(text='Home') class YoutubePage(TopPages): - """ Why: #3 (Alexa global) """ - def __init__(self, page_set, - shared_page_state_class=shared_page_state.SharedPageState): + def __init__(self, + page_set, + shared_page_state_class=shared_page_state.SharedPageState, + name='', + extra_browser_args=None): super(YoutubePage, self).__init__( url='http://www.youtube.com', page_set=page_set, - shared_page_state_class=shared_page_state_class) + shared_page_state_class=shared_page_state_class, + name=name, + extra_browser_args=extra_browser_args) def RunNavigateSteps(self, action_runner): - google_login.LoginGoogleAccount(action_runner, 'googletest', - self.credentials_path) + google_login.LoginGoogleAccount(action_runner, 'googletest') super(YoutubePage, self).RunNavigateSteps(action_runner) action_runner.Wait(2) class BlogspotPage(TopPages): - """ Why: #11 (Alexa global), google property; some blogger layouts have infinite scroll but more interesting """ - def __init__(self, page_set, - shared_page_state_class=shared_page_state.SharedPageState): + def __init__(self, + page_set, + shared_page_state_class=shared_page_state.SharedPageState, + name='Blogger', + extra_browser_args=None): super(BlogspotPage, self).__init__( url='http://googlewebmastercentral.blogspot.com/', page_set=page_set, - name='Blogger', - shared_page_state_class=shared_page_state_class) + shared_page_state_class=shared_page_state_class, + name=name, + extra_browser_args=extra_browser_args) def RunNavigateSteps(self, action_runner): super(BlogspotPage, self).RunNavigateSteps(action_runner) @@ -177,36 +207,44 @@ class WordpressPage(TopPages): - """ Why: #18 (Alexa global), Picked an interesting post """ - def __init__(self, page_set, - shared_page_state_class=shared_page_state.SharedPageState): + def __init__(self, + page_set, + shared_page_state_class=shared_page_state.SharedPageState, + name='Wordpress', + extra_browser_args=None): super(WordpressPage, self).__init__( # pylint: disable=line-too-long - url='http://en.blog.wordpress.com/2012/09/04/freshly-pressed-editors-picks-for-august-2012/', + url= + 'http://en.blog.wordpress.com/2012/09/04/freshly-pressed-editors-picks-for-august-2012/', page_set=page_set, - name='Wordpress', - shared_page_state_class=shared_page_state_class) + shared_page_state_class=shared_page_state_class, + name=name, + extra_browser_args=extra_browser_args) def RunNavigateSteps(self, action_runner): super(WordpressPage, self).RunNavigateSteps(action_runner) action_runner.WaitForElement( # pylint: disable=line-too-long - 'a[href="http://en.blog.wordpress.com/2012/08/30/new-themes-able-and-sight/"]') + 'a[href="http://en.blog.wordpress.com/2012/08/30/new-themes-able-and-sight/"]' + ) class FacebookPage(TopPages): - """ Why: top social,Public profile """ - def __init__(self, page_set, - shared_page_state_class=shared_page_state.SharedPageState): + def __init__(self, + page_set, + shared_page_state_class=shared_page_state.SharedPageState, + name='Facebook', + extra_browser_args=None): super(FacebookPage, self).__init__( url='https://www.facebook.com/barackobama', page_set=page_set, - name='Facebook', - shared_page_state_class=shared_page_state_class) + shared_page_state_class=shared_page_state_class, + name=name, + extra_browser_args=extra_browser_args) def RunNavigateSteps(self, action_runner): super(FacebookPage, self).RunNavigateSteps(action_runner) @@ -214,40 +252,51 @@ class LinkedinPage(TopPages): - """ Why: #12 (Alexa global), Public profile. """ - def __init__(self, page_set, - shared_page_state_class=shared_page_state.SharedPageState): + def __init__(self, + page_set, + shared_page_state_class=shared_page_state.SharedPageState, + name='LinkedIn', + extra_browser_args=None): super(LinkedinPage, self).__init__( - url='http://www.linkedin.com/in/linustorvalds', page_set=page_set, - name='LinkedIn', - shared_page_state_class=shared_page_state_class) + url='http://www.linkedin.com/in/linustorvalds', + page_set=page_set, + shared_page_state_class=shared_page_state_class, + name=name, + extra_browser_args=extra_browser_args) class WikipediaPage(TopPages): - """ Why: #6 (Alexa) most visited worldwide,Picked an interesting page. """ - def __init__(self, page_set, - shared_page_state_class=shared_page_state.SharedPageState): + def __init__(self, + page_set, + shared_page_state_class=shared_page_state.SharedPageState, + name='Wikipedia_(1_tab)', + extra_browser_args=None): super(WikipediaPage, self).__init__( - url='http://en.wikipedia.org/wiki/Wikipedia', page_set=page_set, - name='Wikipedia (1 tab)', - shared_page_state_class=shared_page_state_class) + url='http://en.wikipedia.org/wiki/Wikipedia', + page_set=page_set, + shared_page_state_class=shared_page_state_class, + name=name, + extra_browser_args=extra_browser_args) class TwitterPage(TopPages): - """ Why: #8 (Alexa global),Picked an interesting page """ - def __init__(self, page_set, - shared_page_state_class=shared_page_state.SharedPageState): + def __init__(self, + page_set, + shared_page_state_class=shared_page_state.SharedPageState, + name='Twitter', + extra_browser_args=None): super(TwitterPage, self).__init__( url='https://twitter.com/katyperry', page_set=page_set, - name='Twitter', - shared_page_state_class=shared_page_state_class) + shared_page_state_class=shared_page_state_class, + name=name, + extra_browser_args=extra_browser_args) def RunNavigateSteps(self, action_runner): super(TwitterPage, self).RunNavigateSteps(action_runner) @@ -255,54 +304,67 @@ class PinterestPage(TopPages): - """ Why: #37 (Alexa global) """ - def __init__(self, page_set, - shared_page_state_class=shared_page_state.SharedPageState): + def __init__(self, + page_set, + shared_page_state_class=shared_page_state.SharedPageState, + name='Pinterest', + extra_browser_args=None): super(PinterestPage, self).__init__( url='http://pinterest.com', page_set=page_set, shared_page_state_class=shared_page_state_class, - name='Pinterest') + name=name, + extra_browser_args=extra_browser_args) class ESPNPage(TopPages): - """ Why: #1 sports """ - def __init__(self, page_set, - shared_page_state_class=shared_page_state.SharedPageState): + def __init__(self, + page_set, + shared_page_state_class=shared_page_state.SharedPageState, + name='ESPN', + extra_browser_args=None): super(ESPNPage, self).__init__( url='http://espn.go.com', page_set=page_set, shared_page_state_class=shared_page_state_class, - name='ESPN') + name=name, + extra_browser_args=extra_browser_args) class WeatherPage(TopPages): - """ Why: #7 (Alexa news); #27 total time spent, picked interesting page. """ - def __init__(self, page_set, - shared_page_state_class=shared_page_state.SharedPageState): + def __init__(self, + page_set, + shared_page_state_class=shared_page_state.SharedPageState, + name='Weather.com', + extra_browser_args=None): super(WeatherPage, self).__init__( url='http://www.weather.com/weather/right-now/Mountain+View+CA+94043', page_set=page_set, shared_page_state_class=shared_page_state_class, - name='Weather.com') + name=name, + extra_browser_args=extra_browser_args) class YahooGamesPage(TopPages): - """ Why: #1 games according to Alexa (with actual games in it) """ - def __init__(self, page_set, - shared_page_state_class=shared_page_state.SharedPageState): + def __init__(self, + page_set, + shared_page_state_class=shared_page_state.SharedPageState, + name='', + extra_browser_args=None): super(YahooGamesPage, self).__init__( url='http://games.yahoo.com', page_set=page_set, - shared_page_state_class=shared_page_state_class) + shared_page_state_class=shared_page_state_class, + name=name, + extra_browser_args=extra_browser_args) def RunNavigateSteps(self, action_runner): super(YahooGamesPage, self).RunNavigateSteps(action_runner)
diff --git a/tools/perf/page_sets/tough_compositor_cases.py b/tools/perf/page_sets/tough_compositor_cases.py index 7ae3a6e..1a601cb6 100644 --- a/tools/perf/page_sets/tough_compositor_cases.py +++ b/tools/perf/page_sets/tough_compositor_cases.py
@@ -10,7 +10,7 @@ def __init__(self, url, page_set): super(ToughCompositorPage, self).__init__( - url=url, page_set=page_set, credentials_path = 'data/credentials.json', + url=url, page_set=page_set, shared_page_state_class=shared_page_state.SharedMobilePageState, name=url)
diff --git a/tools/perf/page_sets/tough_filters_cases.py b/tools/perf/page_sets/tough_filters_cases.py index 1056d1a..faaa1aa 100644 --- a/tools/perf/page_sets/tough_filters_cases.py +++ b/tools/perf/page_sets/tough_filters_cases.py
@@ -38,11 +38,11 @@ urls_list = [ ('http://rawgit.com/WebKit/webkit/master/PerformanceTests/Animometer/developer.html?test-interval=20&display=minimal&controller=fixed&frame-rate=50&kalman-process-error=1&kalman-measurement-error=4&time-measurement=performance&suite-name=Animometer&test-name=Focus&complexity=100', # pylint: disable=line-too-long - 'MotionMark Focus'), + 'MotionMark_Focus'), ('http://letmespellitoutforyou.com/samples/svg/filter_terrain.svg', - 'Filter Terrain SVG'), + 'Filter_Terrain_SVG'), ('http://static.bobdo.net/Analog_Clock.svg', - 'Analog Clock SVG'), + 'Analog_Clock_SVG'), ] for url, name in urls_list: @@ -51,5 +51,5 @@ pirate_url = ('http://web.archive.org/web/20150502135732/' 'http://ie.microsoft.com/testdrive/Performance/' 'Pirates/Default.html') - name = 'IE PirateMark' + name = 'IE_PirateMark' self.AddStory(PirateMarkPage(pirate_url, self, name=name))
diff --git a/tools/perf/page_sets/tough_path_rendering_cases.py b/tools/perf/page_sets/tough_path_rendering_cases.py index debbabf..d9c090a 100644 --- a/tools/perf/page_sets/tough_path_rendering_cases.py +++ b/tools/perf/page_sets/tough_path_rendering_cases.py
@@ -31,11 +31,11 @@ cloud_storage_bucket=story.PARTNER_BUCKET) page_list = [ - ('GUIMark Vector Chart Test', + ('GUIMark_Vector_Chart_Test', 'http://www.craftymind.com/factory/guimark2/HTML5ChartingTest.html'), - ('MotionMark Canvas Fill Shapes', + ('MotionMark_Canvas_Fill_Shapes', 'http://rawgit.com/WebKit/webkit/master/PerformanceTests/MotionMark/developer.html?test-name=Fillshapes&test-interval=20&display=minimal&tiles=big&controller=fixed&frame-rate=50&kalman-process-error=1&kalman-measurement-error=4&time-measurement=performance&suite-name=Canvassuite&complexity=1000'), # pylint: disable=line-too-long - ('MotionMark Canvas Stroke Shapes', + ('MotionMark_Canvas_Stroke_Shapes', 'http://rawgit.com/WebKit/webkit/master/PerformanceTests/MotionMark/developer.html?test-name=Strokeshapes&test-interval=20&display=minimal&tiles=big&controller=fixed&frame-rate=50&kalman-process-error=1&kalman-measurement-error=4&time-measurement=performance&suite-name=Canvassuite&complexity=1000'), # pylint: disable=line-too-long ] @@ -47,5 +47,5 @@ # http://ie.microsoft.com/testdrive/Performance/Chalkboard/. chalkboard_url = ('https://testdrive-archive.azurewebsites.net' '/performance/chalkboard/') - name = 'IE Chalkboard' + name = 'IE_Chalkboard' self.AddStory(ChalkboardPage(chalkboard_url, self, name=name))
diff --git a/tools/perf/page_sets/tough_pinch_zoom_cases.py b/tools/perf/page_sets/tough_pinch_zoom_cases.py index 2c3dc50f..2df13b2b 100644 --- a/tools/perf/page_sets/tough_pinch_zoom_cases.py +++ b/tools/perf/page_sets/tough_pinch_zoom_cases.py
@@ -13,8 +13,7 @@ name = url super(ToughPinchZoomCasesPage, self).__init__( url=url, page_set=page_set, name=name, - shared_page_state_class=shared_page_state.SharedDesktopPageState, - credentials_path = 'data/credentials.json') + shared_page_state_class=shared_page_state.SharedDesktopPageState) self.target_scale_factor = page_set.target_scale_factor def RunPinchGesture(self, action_runner, left_anchor_ratio=0.5, @@ -60,8 +59,6 @@ url='https://mail.google.com/mail/', page_set=page_set) - self.credentials = 'google' - def RunNavigateSteps(self, action_runner): super(GmailPage, self).RunNavigateSteps(action_runner) action_runner.WaitForJavaScriptCondition( @@ -78,8 +75,6 @@ url='https://www.google.com/calendar/', page_set=page_set) - self.credentials = 'google' - def RunNavigateSteps(self, action_runner): super(GoogleCalendarPage, self).RunNavigateSteps(action_runner) action_runner.Wait(2) @@ -93,8 +88,6 @@ url='https://www.google.com/search?q=cats&tbm=isch', page_set=page_set) - self.credentials = 'google' - class YoutubePage(ToughPinchZoomCasesPage): @@ -105,8 +98,6 @@ url='http://www.youtube.com', page_set=page_set) - self.credentials = 'google' - def RunNavigateSteps(self, action_runner): super(YoutubePage, self).RunNavigateSteps(action_runner) action_runner.Wait(2) @@ -136,7 +127,6 @@ super(FacebookPage, self).__init__( url='http://www.facebook.com/barackobama', page_set=page_set, name='Facebook') - self.credentials = 'facebook' def RunNavigateSteps(self, action_runner): super(FacebookPage, self).RunNavigateSteps(action_runner)
diff --git a/tools/perf/page_sets/tough_scheduling_cases.py b/tools/perf/page_sets/tough_scheduling_cases.py index 31e725a..d5606514 100644 --- a/tools/perf/page_sets/tough_scheduling_cases.py +++ b/tools/perf/page_sets/tough_scheduling_cases.py
@@ -10,7 +10,7 @@ def __init__(self, url, page_set): super(ToughSchedulingCasesPage, self).__init__( - url=url, page_set=page_set, credentials_path='data/credentials.json', + url=url, page_set=page_set, shared_page_state_class=shared_page_state.SharedMobilePageState, name=url.split('/')[-1])
diff --git a/tools/perf/page_sets/tough_video_cases.py b/tools/perf/page_sets/tough_video_cases.py deleted file mode 100644 index 73c0764..0000000 --- a/tools/perf/page_sets/tough_video_cases.py +++ /dev/null
@@ -1,487 +0,0 @@ -# Copyright 2014 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. -from telemetry.page import page as page_module -from telemetry import story - -_PAGE_TAGS_LIST = [ - # Audio codecs: - 'pcm', - 'mp3', - 'aac', - 'vorbis', - 'opus', - # Video codecs: - 'h264', - 'vp8', - 'vp9', - # Test types: - 'audio_video', - 'audio_only', - 'video_only', - # Other filter tags: - 'is_50fps', - 'is_4k', - # Play action: - 'seek', - 'normal_play', - 'background', - # Add javascript load - 'busyjs' -] - - -# TODO(crouleau): Make a class for each of the page actions: regular, seeking, -# and background. This will simplify page declarations. -class ToughVideoCasesPage(page_module.Page): - - def __init__(self, url, page_set, tags, extra_browser_args=None): - if tags: - for t in tags: - assert t in _PAGE_TAGS_LIST - super(ToughVideoCasesPage, self).__init__( - url=url, page_set=page_set, tags=tags, name=url.split('/')[-1], - extra_browser_args=extra_browser_args) - - def PlayAction(self, action_runner): - # Play the media until it has finished or it times out. - action_runner.PlayMedia(playing_event_timeout_in_seconds=60, - ended_event_timeout_in_seconds=60) - # Generate memory dump for memoryMetric. - if self.page_set.measure_memory: - action_runner.MeasureMemory() - - def SeekBeforeAndAfterPlayhead(self, action_runner, - action_timeout_in_seconds=60): - timeout = action_timeout_in_seconds - # Start the media playback. - action_runner.PlayMedia( - playing_event_timeout_in_seconds=timeout) - # Wait for 1 second so that we know the play-head is at ~1s. - action_runner.Wait(1) - # Seek to before the play-head location. - action_runner.SeekMedia(seconds=0.5, timeout_in_seconds=timeout, - label='seek_warm') - # Seek to after the play-head location. - action_runner.SeekMedia(seconds=9, timeout_in_seconds=timeout, - label='seek_cold') - # Generate memory dump for memoryMetric. - if self.page_set.measure_memory: - action_runner.MeasureMemory() - - def PlayInBackgroundTab(self, action_runner, background_time=10): - # Steps: - # 1. Play a video - # 2. Open new tab overtop to obscure the video - # 3. Close the tab to go back to the tab that is playing the video. - # The motivation for this test case is crbug.com/678663. - action_runner.PlayMedia( - playing_event_timeout_in_seconds=60) - action_runner.Wait(.5) - new_tab = action_runner.tab.browser.tabs.New() - new_tab.Activate() - action_runner.Wait(background_time) - new_tab.Close() - action_runner.Wait(.5) - # Generate memory dump for memoryMetric. - if self.page_set.measure_memory: - action_runner.MeasureMemory() - - -class Page2(ToughVideoCasesPage): - - def __init__(self, page_set): - super(Page2, self).__init__( - url='file://tough_video_cases/video.html?src=crowd.ogg&type=audio', - page_set=page_set, - tags=['vorbis', 'audio_only']) - - self.add_browser_metrics = True - - def RunPageInteractions(self, action_runner): - self.PlayAction(action_runner) - - -class Page4(ToughVideoCasesPage): - - def __init__(self, page_set): - super(Page4, self).__init__( - url='file://tough_video_cases/video.html?src=crowd1080.webm', - page_set=page_set, - tags=['is_50fps', 'vp8', 'vorbis', 'audio_video', 'normal_play']) - - self.add_browser_metrics = True - - def RunPageInteractions(self, action_runner): - self.PlayAction(action_runner) - - -class Page7(ToughVideoCasesPage): - - def __init__(self, page_set): - super(Page7, self).__init__( - url='file://tough_video_cases/video.html?src=tulip2.ogg&type=audio', - page_set=page_set, - tags=['vorbis', 'audio_only', 'normal_play']) - - self.add_browser_metrics = True - - def RunPageInteractions(self, action_runner): - self.PlayAction(action_runner) - - -class Page8(ToughVideoCasesPage): - - def __init__(self, page_set): - super(Page8, self).__init__( - url='file://tough_video_cases/video.html?src=tulip2.wav&type=audio', - page_set=page_set, - tags=['pcm', 'audio_only', 'normal_play']) - - self.add_browser_metrics = True - - def RunPageInteractions(self, action_runner): - self.PlayAction(action_runner) - - -class Page11(ToughVideoCasesPage): - - def __init__(self, page_set): - super(Page11, self).__init__( - url='file://tough_video_cases/video.html?src=crowd1080.mp4', - page_set=page_set, - tags=['is_50fps', 'h264', 'aac', 'audio_video', 'normal_play']) - - self.add_browser_metrics = True - - def RunPageInteractions(self, action_runner): - self.PlayAction(action_runner) - - -class Page12(ToughVideoCasesPage): - - def __init__(self, page_set): - super(Page12, self).__init__( - url='file://tough_video_cases/video.html?src=crowd2160.mp4', - page_set=page_set, - tags=['is_4k', 'is_50fps', 'h264', 'aac', 'audio_video', 'normal_play']) - - self.add_browser_metrics = True - - def RunPageInteractions(self, action_runner): - self.PlayAction(action_runner) - - -class Page13(ToughVideoCasesPage): - - def __init__(self, page_set): - super(Page13, self).__init__( - url='file://tough_video_cases/video.html?src=tulip2.mp3&type=audio', - page_set=page_set, - tags=['mp3', 'audio_only', 'normal_play']) - - self.add_browser_metrics = True - - def RunPageInteractions(self, action_runner): - self.PlayAction(action_runner) - - -class Page14(ToughVideoCasesPage): - - def __init__(self, page_set): - super(Page14, self).__init__( - url='file://tough_video_cases/video.html?src=tulip2.mp4', - page_set=page_set, - tags=['h264', 'aac', 'audio_video', 'normal_play']) - - self.add_browser_metrics = True - - def RunPageInteractions(self, action_runner): - self.PlayAction(action_runner) - - -class Page15(ToughVideoCasesPage): - - def __init__(self, page_set): - super(Page15, self).__init__( - url='file://tough_video_cases/video.html?src=tulip2.m4a&type=audio', - page_set=page_set, - tags=['aac', 'audio_only', 'normal_play']) - - self.add_browser_metrics = True - - def RunPageInteractions(self, action_runner): - self.PlayAction(action_runner) - - -class Page16(ToughVideoCasesPage): - - def __init__(self, page_set): - super(Page16, self).__init__( - url='file://tough_video_cases/video.html?src=garden2_10s.webm', - page_set=page_set, - tags=['is_4k', 'vp8', 'vorbis', 'audio_video', 'normal_play']) - - self.add_browser_metrics = True - - def RunPageInteractions(self, action_runner): - self.PlayAction(action_runner) - - -class Page17(ToughVideoCasesPage): - - def __init__(self, page_set): - super(Page17, self).__init__( - url='file://tough_video_cases/video.html?src=garden2_10s.mp4', - page_set=page_set, - tags=['is_4k', 'h264', 'aac', 'audio_video', 'normal_play']) - - self.add_browser_metrics = True - - def RunPageInteractions(self, action_runner): - self.PlayAction(action_runner) - - -class Page19(ToughVideoCasesPage): - - def __init__(self, page_set): - super(Page19, self).__init__( - url='file://tough_video_cases/video.html?src=tulip2.ogg&type=audio&seek', - page_set=page_set, - tags=['vorbis', 'audio_only', 'seek']) - - self.skip_basic_metrics = True - - def RunPageInteractions(self, action_runner): - self.SeekBeforeAndAfterPlayhead(action_runner) - - -class Page20(ToughVideoCasesPage): - - def __init__(self, page_set): - super(Page20, self).__init__( - url='file://tough_video_cases/video.html?src=tulip2.wav&type=audio&seek', - page_set=page_set, - tags=['pcm', 'audio_only', 'seek']) - - self.skip_basic_metrics = True - - def RunPageInteractions(self, action_runner): - self.SeekBeforeAndAfterPlayhead(action_runner) - - -class Page23(ToughVideoCasesPage): - - def __init__(self, page_set): - super(Page23, self).__init__( - url='file://tough_video_cases/video.html?src=tulip2.mp3&type=audio&seek', - page_set=page_set, - tags=['mp3', 'audio_only', 'seek']) - - self.skip_basic_metrics = True - - def RunPageInteractions(self, action_runner): - self.SeekBeforeAndAfterPlayhead(action_runner) - - -class Page24(ToughVideoCasesPage): - - def __init__(self, page_set): - super(Page24, self).__init__( - url='file://tough_video_cases/video.html?src=tulip2.mp4&seek', - page_set=page_set, - tags=['h264', 'aac', 'audio_video', 'seek']) - - self.skip_basic_metrics = True - - def RunPageInteractions(self, action_runner): - self.SeekBeforeAndAfterPlayhead(action_runner) - - -class Page25(ToughVideoCasesPage): - - def __init__(self, page_set): - super(Page25, self).__init__( - url='file://tough_video_cases/video.html?src=garden2_10s.webm&seek', - page_set=page_set, - tags=['is_4k', 'vp8', 'vorbis', 'audio_video', 'seek']) - - self.skip_basic_metrics = True - - def RunPageInteractions(self, action_runner): - self.SeekBeforeAndAfterPlayhead(action_runner) - - -class Page26(ToughVideoCasesPage): - - def __init__(self, page_set): - super(Page26, self).__init__( - url='file://tough_video_cases/video.html?src=garden2_10s.mp4&seek', - page_set=page_set, - tags=['is_4k', 'h264', 'aac', 'audio_video', 'seek']) - - self.skip_basic_metrics = True - - def RunPageInteractions(self, action_runner): - self.SeekBeforeAndAfterPlayhead(action_runner) - - -class Page30(ToughVideoCasesPage): - - def __init__(self, page_set): - super(Page30, self).__init__( - url='file://tough_video_cases/video.html?src=tulip2.vp9.webm', - page_set=page_set, - tags=['vp9', 'opus', 'audio_video', 'normal_play']) - - self.add_browser_metrics = True - - def RunPageInteractions(self, action_runner): - self.PlayAction(action_runner) - - -class Page31(ToughVideoCasesPage): - - def __init__(self, page_set): - super(Page31, self).__init__( - url='file://tough_video_cases/video.html?src=tulip2.vp9.webm&seek', - page_set=page_set, - tags=['vp9', 'opus', 'audio_video', 'seek']) - - self.skip_basic_metrics = True - - def RunPageInteractions(self, action_runner): - self.SeekBeforeAndAfterPlayhead(action_runner) - - -class Page32(ToughVideoCasesPage): - - def __init__(self, page_set): - super(Page32, self).__init__( - url='file://tough_video_cases/video.html?src=crowd1080_vp9.webm', - page_set=page_set, - tags=['vp9', 'video_only', 'normal_play']) - - self.add_browser_metrics = True - - def RunPageInteractions(self, action_runner): - self.PlayAction(action_runner) - - -class Page33(ToughVideoCasesPage): - - def __init__(self, page_set): - super(Page33, self).__init__( - url='file://tough_video_cases/video.html?src=crowd1080_vp9.webm&seek', - page_set=page_set, - tags=['vp9', 'video_only', 'seek']) - - self.skip_basic_metrics = True - - def RunPageInteractions(self, action_runner): - self.SeekBeforeAndAfterPlayhead(action_runner) - - -class Page34(ToughVideoCasesPage): - - def __init__(self, page_set): - super(Page34, self).__init__( - url='file://tough_video_cases/video.html?src=crowd720_vp9.webm', - page_set=page_set, - tags=['vp9', 'video_only', 'normal_play']) - - self.add_browser_metrics = True - - def RunPageInteractions(self, action_runner): - self.PlayAction(action_runner) - - -class Page36(ToughVideoCasesPage): - - def __init__(self, page_set): - super(Page36, self).__init__( - url=('file://tough_video_cases/video.html?src=' - 'smpte_3840x2160_60fps_vp9.webm&seek'), - page_set=page_set, - tags=['is_4k', 'vp9', 'video_only', 'seek']) - - self.add_browser_metrics = True - - def RunPageInteractions(self, action_runner): - self.SeekBeforeAndAfterPlayhead(action_runner, - action_timeout_in_seconds=120) - -class Page37(ToughVideoCasesPage): - - def __init__(self, page_set): - super(Page37, self).__init__( - url='file://tough_video_cases/video.html?src=tulip2.vp9.webm&background', - page_set=page_set, - tags=['vp9', 'opus', 'audio_video', 'background'], - # disable-media-suspend is required since for Android background playback - # gets suspended. This flag makes Android work the same way as desktop and - # not turn off video playback in the background. - extra_browser_args=['--disable-media-suspend']) - - self.skip_basic_metrics = True - - def RunPageInteractions(self, action_runner): - self.PlayInBackgroundTab(action_runner) - -class Page38(ToughVideoCasesPage): - - def __init__(self, page_set): - super(Page38, self).__init__( - url='file://tough_video_cases/video.html?src=tulip2.mp4&busyjs', - page_set=page_set, - tags=['h264', 'aac', 'audio_video', 'normal_play', 'busyjs']) - - self.add_browser_metrics = True - - def RunPageInteractions(self, action_runner): - self.PlayAction(action_runner) - - -class ToughVideoCasesPageSet(story.StorySet): - """ - Description: Video Stack Perf pages that report time_to_play, seek time and - many other media-specific and generic metrics. - """ - def __init__(self, measure_memory=False): - super(ToughVideoCasesPageSet, self).__init__( - cloud_storage_bucket=story.PARTNER_BUCKET) - - self.measure_memory = measure_memory - - # Normal play tests: - self.AddStory(Page2(self)) - self.AddStory(Page4(self)) - self.AddStory(Page7(self)) - self.AddStory(Page8(self)) - self.AddStory(Page11(self)) - self.AddStory(Page12(self)) - self.AddStory(Page13(self)) - self.AddStory(Page14(self)) - self.AddStory(Page15(self)) - self.AddStory(Page16(self)) - self.AddStory(Page17(self)) - self.AddStory(Page30(self)) - self.AddStory(Page32(self)) - self.AddStory(Page34(self)) - - # Seek tests: - self.AddStory(Page19(self)) - self.AddStory(Page20(self)) - self.AddStory(Page23(self)) - self.AddStory(Page24(self)) - self.AddStory(Page25(self)) - self.AddStory(Page26(self)) - self.AddStory(Page31(self)) - self.AddStory(Page33(self)) - self.AddStory(Page36(self)) - - # Background playback tests: - self.AddStory(Page37(self)) - - # Tests with high JS load - self.AddStory(Page38(self))
diff --git a/tools/perf/page_sets/typical_10_mobile.py b/tools/perf/page_sets/typical_10_mobile.py index 58df35ae..4a5fa32 100644 --- a/tools/perf/page_sets/typical_10_mobile.py +++ b/tools/perf/page_sets/typical_10_mobile.py
@@ -11,7 +11,6 @@ def __init__(self, url, page_set, name=''): super(Typical10MobilePage, self).__init__( url=url, page_set=page_set, name=name, - credentials_path = 'data/credentials.json', shared_page_state_class=shared_page_state.SharedMobilePageState) def RunPageInteractions(self, action_runner):
diff --git a/tools/perf/page_sets/typical_25.py b/tools/perf/page_sets/typical_25.py index fbee296..71bb21d 100644 --- a/tools/perf/page_sets/typical_25.py +++ b/tools/perf/page_sets/typical_25.py
@@ -17,6 +17,8 @@ url=url, page_set=page_set, shared_page_state_class=shared_page_state_class, cache_temperature=cache_temperature, name=url) + if cache_temperature != cache_temperature_module.ANY: + self.grouping_keys['cache_temperature'] = cache_temperature self._run_no_page_interactions = run_no_page_interactions def RunPageInteractions(self, action_runner):
diff --git a/tools/perf/page_sets/v8_top_25.py b/tools/perf/page_sets/v8_top_25.py index 180a8b9..cb3e5760 100644 --- a/tools/perf/page_sets/v8_top_25.py +++ b/tools/perf/page_sets/v8_top_25.py
@@ -1,21 +1,22 @@ # Copyright 2016 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. -from telemetry.page import page as page_module + +from page_sets import page_cycler_story from telemetry import story +from telemetry.page import cache_temperature as cache_temperature_module +cache_temperatures = [ + cache_temperature_module.COLD, + cache_temperature_module.WARM_BROWSER, + cache_temperature_module.HOT_BROWSER, +] -class V8Top25(page_module.Page): - - def __init__(self, url, page_set, name=''): - super(V8Top25, self).__init__( - url=url, page_set=page_set, name=name) - - def RunPageInteractions(self, action_runner): - # We wait for 20 seconds to make sure we capture enough information - # to calculate the interactive time correctly. - action_runner.Wait(20) - +temperature_warmup_run_count = { + cache_temperature_module.COLD: 0, + cache_temperature_module.WARM_BROWSER: 1, + cache_temperature_module.HOT_BROWSER: 2, +} # This URL list is a migration of a non-telemetry existing V8 benchmark. urls_list = [ @@ -57,16 +58,71 @@ 'https://cdn.ampproject.org/c/www.bbc.co.uk/news/amp/37344292#log=3', ] +# URL list to measure performance of Ad scripts. +ads_urls_list = [ + ('https://www.googletagservices.com/tests/gpt/168/impl_manual_tests/tests/adsense_image.html', + 'SyncAdSenseImage', False), + ('https://www.googletagservices.com/tests/gpt/168/impl_manual_tests/tests/click-url-async.html', + 'AsyncAdSenseImage', False), + ('https://www.googletagservices.com/tests/gpt/168/impl_manual_tests/tests/refresh.html', + 'SyncLoadAsyncRenderAdSenseImage', False), + ('https://www.googletagservices.com/tests/gpt/168/impl_manual_tests/tests/gpt-adx-backfill.html', + 'DoubleClickAsyncAds', False), + # pylint: disable=line-too-long + ('https://www.googletagservices.com/tests/gpt/168/impl_manual_tests/tests/release_smoke_tests.html', + 'AdSenseAsyncAds', False), + ('https://www.googletagservices.com/tests/gpt/168/impl_manual_tests/tests/five-level-iu-sra.html', + 'MultipleAdSlots', False), + # pylint: disable=line-too-long + ('https://www.googletagservices.com/tests/gpt/168/impl_manual_tests/tests/target_page_with_ose.html', + 'OnScreenDetection', False), + # pylint: disable=line-too-long + ('https://www.googletagservices.com/tests/gpt/168/impl_manual_tests/tests/view-optimized-rendering-adsense.html', + 'ViewOptimizedRendering', True), + ('https://www.googletagservices.com/tests/gpt/168/impl_manual_tests/tests/amp.html', + 'AMPAds', False) +] + + +class V8Top25Story(page_cycler_story.PageCyclerStory): + + def __init__(self, url, page_set, name='', + cache_temperature=cache_temperature_module.ANY, scroll=False): + super(V8Top25Story, self).__init__( + url=url, page_set=page_set, name=name, + cache_temperature=cache_temperature) + self.remaining_warmups = temperature_warmup_run_count[cache_temperature] + self.should_scroll=scroll + + def RunPageInteractions(self, action_runner): + if self.should_scroll: + action_runner.RepeatableBrowserDrivenScroll( + repeat_count=0, x_scroll_distance_ratio = 0, + y_scroll_distance_ratio = 4, speed=400) + if self.remaining_warmups == 0: + # We wait for 20 seconds to make sure we capture enough information + # to calculate the interactive time correctly. + action_runner.Wait(20) + else: + action_runner.Wait(2) + self.remaining_warmups -= 1 class V8Top25StorySet(story.StorySet): """~25 of top pages, used for v8 testing. They represent popular websites as well as other pages the V8 team wants to track due to their unique characteristics.""" + # When recording this pageset record only for the cold run. def __init__(self): super(V8Top25StorySet, self).__init__( archive_data_file='data/v8_top_25.json', cloud_storage_bucket=story.INTERNAL_BUCKET) for url in urls_list: - self.AddStory(V8Top25(url, self, url)) + for temp in cache_temperatures: + self.AddStory(V8Top25Story(url, self, url, cache_temperature=temp)) + + for (url, name, needs_scroll) in ads_urls_list: + for temp in cache_temperatures: + self.AddStory(V8Top25Story(url, self, 'Ads'+name, + cache_temperature=temp, scroll=needs_scroll))
diff --git a/tools/perf/page_sets/wasm_realworld_pages.py b/tools/perf/page_sets/wasm_realworld_pages.py new file mode 100644 index 0000000..b035834e --- /dev/null +++ b/tools/perf/page_sets/wasm_realworld_pages.py
@@ -0,0 +1,121 @@ +# Copyright 2017 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. +from telemetry.page import page as page_module +from telemetry import story + +from page_sets import webgl_supported_shared_state + + +class Tanks(page_module.Page): + + def __init__(self, page_set): + url = 'http://webassembly.org/demo/Tanks/' + super(Tanks, self).__init__( + url=url, + page_set=page_set, + shared_page_state_class=( + webgl_supported_shared_state.WebGLSupportedSharedState), + name='WasmTanks') + + @property + def skipped_gpus(self): + # Unity WebGL is not supported on mobile + return ['arm', 'qualcomm'] + + def RunPageInteractions(self, action_runner): + action_runner.WaitForJavaScriptCondition( + """document.getElementsByClassName('progress Dark').length != 0""") + action_runner.WaitForJavaScriptCondition( + """document.getElementsByClassName('progress Dark')[0].style['display'] + == 'none'""") + +class SpaceBuggy(page_module.Page): + + def __init__(self, page_set): + url = 'https://playcanv.as/p/3RerJIcy/' + super(SpaceBuggy, self).__init__( + url=url, + page_set=page_set, + shared_page_state_class=( + webgl_supported_shared_state.WebGLSupportedSharedState), + name='WasmSpaceBuggy') + + @property + def skipped_gpus(self): + return [] + + def RunPageInteractions(self, action_runner): + action_runner.WaitForJavaScriptCondition("document.getElementById('frame')") + action_runner.WaitForJavaScriptCondition("""document.getElementById('frame') + .contentDocument.getElementsByClassName('btn btn-primary btn-play') + .length != 0""") + action_runner.ClickElement(element_function="""(function() {return document + .getElementById("frame").contentDocument.getElementsByClassName( + "btn btn-primary btn-play")[0]})()""") + action_runner.WaitForJavaScriptCondition("""document.getElementById('frame') + .contentDocument.getElementsByClassName('panel level-select')[0] + .style.bottom != '-100px'""") + action_runner.ClickElement(element_function="""(function() {return document + .getElementById("frame").contentDocument.getElementsByClassName( + "btn btn-primary btn-play")[1]})()""") + action_runner.WaitForJavaScriptCondition("""document.getElementById('frame') + .contentDocument.getElementsByClassName('panel level-select')[0] + .style.bottom == '-100px'""") + +class EpicPageSet(page_module.Page): + + def __init__(self, page_set, url, name): + super(EpicPageSet, self).__init__( + url=url, + page_set=page_set, + shared_page_state_class=( + webgl_supported_shared_state.WebGLSupportedSharedState), + name=name) + + @property + def skipped_gpus(self): + return ['arm', 'qualcomm'] + + def RunPageInteractions(self, action_runner): + # We wait for the fullscreen button to become visible + action_runner.WaitForJavaScriptCondition("""document + .getElementById('fullscreen_request').style.display === + 'inline-block'""") + +class EpicZenGarden(EpicPageSet): + + def __init__(self, page_set): + url = 'https://s3.amazonaws.com/mozilla-games/ZenGarden/EpicZenGarden.html' + super(EpicZenGarden, self).__init__( + page_set=page_set, url=url, name='WasmZenGarden') + +class EpicSunTemple(EpicPageSet): + + def __init__(self, page_set): + url = ("https://s3.amazonaws.com/mozilla-games/tmp/2017-02-21-SunTemple/" + "SunTemple.html") + super(EpicSunTemple, self).__init__( + page_set=page_set, url=url, name='WasmSunTemple') + +class EpicStylizedRenderer(EpicPageSet): + + def __init__(self, page_set): + url = ("https://s3.amazonaws.com/mozilla-games/tmp/2017-02-21-StylizedRen" + "dering/StylizedRendering.html") + super(EpicStylizedRenderer, self).__init__( + page_set=page_set, url=url, name='WasmStylizedRenderer') + +class WasmRealWorldPagesStorySet(story.StorySet): + """Top apps, used to monitor web assembly apps.""" + + def __init__(self): + super(WasmRealWorldPagesStorySet, self).__init__( + archive_data_file='data/wasm_realworld_pages.json', + cloud_storage_bucket=story.INTERNAL_BUCKET) + + self.AddStory(Tanks(self)) + self.AddStory(SpaceBuggy(self)) + self.AddStory(EpicZenGarden(self)) + self.AddStory(EpicSunTemple(self)) + self.AddStory(EpicStylizedRenderer(self))
diff --git a/tools/perf/page_sets/webrtc_cases.py b/tools/perf/page_sets/webrtc_cases.py index e462cb8..3ff08d1 100644 --- a/tools/perf/page_sets/webrtc_cases.py +++ b/tools/perf/page_sets/webrtc_cases.py
@@ -142,10 +142,6 @@ self.AddStory(DataChannel(self, tags=['datachannel'])) self.AddStory(GetUserMedia(self, tags=['getusermedia'])) self.AddStory(CanvasCapturePeerConnection(self, tags=['smoothness'])) - self.AddStory(AudioCall(self, 'OPUS', tags=['audio'])) - self.AddStory(AudioCall(self, 'G772', tags=['audio'])) - self.AddStory(AudioCall(self, 'PCMU', tags=['audio'])) - self.AddStory(AudioCall(self, 'ISAC/1600', tags=['audio'])) self.AddStory(VideoCodecConstraints(self, 'H264', tags=['videoConstraints'])) self.AddStory(VideoCodecConstraints(self, 'VP8', tags=['videoConstraints'])) self.AddStory(VideoCodecConstraints(self, 'VP9', tags=['videoConstraints']))
diff --git a/tools/perf/perf_device_trigger.py b/tools/perf/perf_device_trigger.py deleted file mode 100755 index 484aa361..0000000 --- a/tools/perf/perf_device_trigger.py +++ /dev/null
@@ -1,124 +0,0 @@ -#!/usr/bin/env python -# Copyright 2017 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. -"""Custom swarming triggering script. - -This script does custom swarming triggering logic, to enable device affinity -for our bots, while lumping all trigger calls under one logical step. - -This script must have roughly the same command line interface as swarming.py -trigger. It modifies it in the following ways: - * Inserts bot id into swarming trigger dimensions, and swarming task arguments. - * Intercepts the dump-json argument, and creates its own by combining the - results from each trigger call. - -This script is normally called from the swarming recipe module in tools/build. -""" - -import argparse -import json -import os -import subprocess -import sys -import tempfile - -from core import path_util - - -def get_swarming_py_path(): - return os.path.join( - path_util.GetChromiumSrcDir(), 'tools', 'swarming_client', 'swarming.py') - - -def modify_args(all_args, bot_id, temp_file): - """Modifies the given argument list. - - Specifically, it does the following: - * Adds a --dump_json argument, to read in the results of the - individual trigger command. - * Adds a bot id dimension. - * Adds the bot id as an argument to the test, so it knows which tests to - run. - - The arguments are structured like this: - <args to swarming.py trigger> -- <args to bot running isolate> - This means we have to add arguments to specific locations in the argument - list, to either affect the trigger command, or what the bot runs. - """ - assert '--' in all_args, ( - 'Malformed trigger command; -- argument expected but not found') - dash_ind = all_args.index('--') - - return all_args[:dash_ind] + [ - '--dump_json', temp_file, '--dimension', 'id', bot_id] + all_args[ - dash_ind:] + ['--id', bot_id] - - -def trigger_tasks(args, remaining): - """Triggers tasks for each bot. - - Args: - args: Parsed arguments which we need to use. - remaining: The remainder of the arguments, which should be passed to - swarming.py calls. - - Returns: - Exit code for the script. - """ - merged_json = {'tasks': {}} - - # TODO: Do these in parallel - for shard_num, bot_id in enumerate(args.bot_id): - # Holds the results of the swarming.py trigger call. - temp_fd, json_temp = tempfile.mkstemp(prefix='perf_device_trigger') - try: - args_to_pass = modify_args(remaining[:], bot_id, json_temp) - - ret = subprocess.call( - sys.executable, [get_swarming_py_path()] + args_to_pass) - if ret: - sys.stderr.write('Failed to trigger a task, aborting\n') - return ret - with open(json_temp) as f: - result_json = json.load(f) - - for k, v in result_json['tasks'].items(): - v['shard_index'] = shard_num - merged_json['tasks'][k + ':%d:%d' % (shard_num, len(args.bot_id))] = v - finally: - os.close(temp_fd) - os.remove(json_temp) - with open(args.dump_json, 'w') as f: - json.dump(merged_json, f) - return 0 - - -def main(): - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument('--bot-id', action='append', required=True, - help='Which bot IDs to trigger tasks on. Number of bot' - ' IDs must match the number of shards. This is because' - ' the recipe code uses the --shard argument to determine' - ' how many shards it expects in the output json.') - parser.add_argument('--dump-json', required=True, - help='(Swarming Trigger Script API) Where to dump the' - ' resulting json which indicates which tasks were' - ' triggered for which shards.') - parser.add_argument('--shards', - help='How many shards to trigger. Duplicated from the' - ' `swarming.py trigger` command. If passed, will be' - ' checked to ensure there are as many shards as bots' - ' specified by the --bot-id argument. If omitted,' - ' --bot-id will be used to determine the number of shards' - ' to create.') - args, remaining = parser.parse_known_args() - - if args.shards and args.shards != len(args.bot_id): - raise parser.error( - 'Number of bots to use must equal number of shards (--shards)') - return trigger_tasks(args, remaining) - - -if __name__ == '__main__': - sys.exit(main())
diff --git a/tools/perf/perf_device_trigger_unittest.py b/tools/perf/perf_device_trigger_unittest.py deleted file mode 100644 index 6043338..0000000 --- a/tools/perf/perf_device_trigger_unittest.py +++ /dev/null
@@ -1,65 +0,0 @@ -# Copyright 2017 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 json -import os -import tempfile -import unittest -import sys - -import mock - -import perf_device_trigger - - -class FakeArgs(object): - def __init__(self, shards, bot_id, dump_json): - self.shards = shards - self.bot_id = bot_id - self.dump_json = dump_json - -class PerfDeviceTriggerUnittest(unittest.TestCase): - def testBasic(self): - with mock.patch('perf_device_trigger.get_swarming_py_path') as py_path_mock: - py_path_mock.return_value = '/path/to/swarming.py' - with mock.patch('perf_device_trigger.subprocess.call') as call_mock: - call_mock.return_value = 0 - m = mock.mock_open(read_data=json.dumps({ - 'tasks': {}, - })) - with mock.patch('perf_device_trigger.open', m, create=True): - temp_fd, json_temp = tempfile.mkstemp( - prefix='perf_device_trigger_unittest') - try: - perf_device_trigger.trigger_tasks( - FakeArgs(1, ['build1'], json_temp), - ['trigger', '--some', '--test', '--', 'args']) - - call_mock.assert_called_once() - - called_args, keyword = call_mock.call_args - self.assertEqual(keyword, {}) - self.assertEqual(called_args[0], sys.executable) - python_args = called_args[1] - json_ind = python_args.index('--dump_json') - # Remove --dump_json and its arg - python_args.pop(json_ind) - temp_json_path = python_args.pop(json_ind) - # We can't assert the exact name, since it's a temp file name. So - # just make sure it has the proper prefix. In order to do this in a - # platform independent way, just make sure that the path provided - # shares a common prefix with the path we made above (that's not - # just '/'). - self.assertTrue( - len(os.path.commonprefix([temp_json_path, json_temp])) > 1) - - self.assertEqual( - python_args, [ - '/path/to/swarming.py', 'trigger', - '--some', '--test', - '--dimension', 'id', 'build1', '--', - 'args', '--id', 'build1']) - finally: - os.close(temp_fd) - os.remove(json_temp)
diff --git a/tools/perf/process_perf_results.py b/tools/perf/process_perf_results.py new file mode 100755 index 0000000..b73e7079 --- /dev/null +++ b/tools/perf/process_perf_results.py
@@ -0,0 +1,117 @@ +#!/usr/bin/env python +# Copyright 2018 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 argparse +import json +import sys + +from core import upload_results_to_perf_dashboard +from core import results_merger +from os import listdir +from os.path import isfile, join + + +RESULTS_URL = 'https://chromeperf.appspot.com' + +def _upload_perf_results(json_to_upload, name, configuration_name, + build_properties): + """Upload the contents of result JSON(s) to the perf dashboard.""" + build_properties = json.loads(build_properties) + args = [ + '--build-dir', '/b/c/b/obbs_fyi/src/out', + '--buildername', build_properties['buildername'], + '--buildnumber', build_properties['buildnumber'], + '--name', name, + '--configuration-name', configuration_name, + '--results-file', json_to_upload, + '--results-url', RESULTS_URL, + '--got-revision-cp', build_properties['got_revision_cp'], + '--got-v8-revision', build_properties['got_v8_revision'], + '--got-webrtc-revision', build_properties['got_webrtc_revision'], + '--chromium-checkout-dir', '/b/c/b/obbs_fyi', + '--send-as-histograms', + ] + upload_results_to_perf_dashboard.main(args) + + +def _merge_json_output(output_json, jsons_to_merge): + """Merges the contents of one or more results JSONs. + + Args: + output_json: A path to a JSON file to which the merged results should be + written. + jsons_to_merge: A list of JSON files that should be merged. + """ + merged_results = results_merger.merge_test_results(jsons_to_merge) + + with open(output_json, 'w') as f: + json.dump(merged_results, f) + + return 0 + + +def _process_perf_results(output_json, configuration_name, + build_properties, task_output_dir): + """Process one or more perf JSON results. + + Consists of merging the json-test-format output and uploading the perf test + output (chartjson and histogram). + + Each directory in the task_output_dir represents one benchmark + that was run. Within this directory, there is a subdirectory with the name + of the benchmark that was run. In that subdirectory, there is a + perftest-output.json file containing the performance results in histogram + or dashboard json format and an output.json file containing the json test + results for the benchmark. + """ + directory_list = [ + f for f in listdir(task_output_dir) + if not isfile(join(task_output_dir, f)) + ] + benchmark_directory_list = [] + for directory in directory_list: + benchmark_directory_list += [ + join(task_output_dir, directory, f) + for f in listdir(join(task_output_dir, directory)) + ] + + test_results_list = [] + for directory in benchmark_directory_list: + with open(join(directory, 'test_results.json')) as json_data: + test_results_list.append(json.load(json_data)) + _merge_json_output(output_json, test_results_list) + + for directory in benchmark_directory_list: + _upload_perf_results(join(directory, 'perf_results.json'), + directory, configuration_name, build_properties) + + return 0 + + +def main(): + """ See collect_task.collect_task for more on the merge script API. """ + parser = argparse.ArgumentParser() + # configuration-name (previously perf-id) is the name of bot the tests run on + # For example, buildbot-test is the name of the obbs_fyi bot + # configuration-name and results-url are set in the json file which is going + # away tools/perf/core/chromium.perf.fyi.extras.json + parser.add_argument('--configuration-name', help=argparse.SUPPRESS) + + parser.add_argument('--build-properties', help=argparse.SUPPRESS) + parser.add_argument('--summary-json', help=argparse.SUPPRESS) + parser.add_argument('--task-output-dir', help=argparse.SUPPRESS) + parser.add_argument('-o', '--output-json', required=True, + help=argparse.SUPPRESS) + parser.add_argument('json_files', nargs='*', help=argparse.SUPPRESS) + + args = parser.parse_args() + + return _process_perf_results( + args.output_json, args.configuration_name, + args.build_properties, args.task_output_dir) + + +if __name__ == '__main__': + sys.exit(main())
diff --git a/tools/perf/profile_creators/__init__.py b/tools/perf/profile_creators/__init__.py deleted file mode 100644 index 29e73ca8..0000000 --- a/tools/perf/profile_creators/__init__.py +++ /dev/null
@@ -1,14 +0,0 @@ -# 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. -"""Generators for Chrome profiles for testing purposes.""" -import os -import sys - -sys.path.insert(1, os.path.abspath(os.path.join( - __file__, '..', '..'))) -from core import path_util - - -path_util.AddTelemetryToPath() -path_util.AddPyUtilsToPath()
diff --git a/tools/perf/profile_creators/cookie_profile_extender.py b/tools/perf/profile_creators/cookie_profile_extender.py deleted file mode 100644 index c75f32c..0000000 --- a/tools/perf/profile_creators/cookie_profile_extender.py +++ /dev/null
@@ -1,92 +0,0 @@ -# Copyright 2015 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 multiprocessing -import os - -try: - import sqlite3 # Not present on ChromeOS DUT. -except ImportError: - pass - -import page_sets - -from profile_creators import fast_navigation_profile_extender - - -class CookieProfileExtender( - fast_navigation_profile_extender.FastNavigationProfileExtender): - """This extender fills in the cookie database. - - By default, Chrome purges the cookie DB down to 3300 cookies. However, it - won't purge cookies accessed in the last month. This means the extender needs - to be careful not to create an artificially high number of cookies. - """ - _COOKIE_DB_EXPECTED_SIZE = 3300 - - def __init__(self, finder_options): - # The rate limiting factors are fetching network resources and executing - # javascript. There's not much to be done about the former, and having one - # tab per logical core appears close to optimum for the latter. - maximum_batch_size = multiprocessing.cpu_count() - - # Web page replay cannot handle too many requests over a duration of 4 - # minutes (maximum segment lifetime), as it may exhaust the socket pool. - # Artificially limit the rate to no more than 5 simultaneous tab loads. - if not finder_options.use_live_sites: - maximum_batch_size = min(5, maximum_batch_size) - - super(CookieProfileExtender, self).__init__( - finder_options, maximum_batch_size) - - # A list of urls that have not yet been navigated to. This list will shrink - # over time. Each navigation will add a diminishing number of new cookies, - # since there's a high probability that the cookie is already present. - self._page_set = page_sets.ProfileSafeUrlsPageSet() - urls = [] - for story in self._page_set.stories: - urls.append(story.url) - self._navigation_urls = urls - - def GetUrlIterator(self): - """Superclass override.""" - return iter(self._navigation_urls) - - def ShouldExitAfterBatchNavigation(self): - """Superclass override.""" - return self._IsCookieDBFull() - - def WebPageReplayArchivePath(self): - return self._page_set.WprFilePathForStory( - self._page_set.stories[0]) - - def FetchWebPageReplayArchives(self): - """Superclass override.""" - self._page_set.wpr_archive_info.DownloadArchivesIfNeeded() - - @staticmethod - def _CookieCountInDB(db_path): - """The number of cookies in the db at |db_path|.""" - connection = sqlite3.connect(db_path) - try: - cursor = connection.cursor() - cursor.execute("select count(*) from cookies") - cookie_count = cursor.fetchone()[0] - except: - raise - finally: - connection.close() - return cookie_count - - def _IsCookieDBFull(self): - """Chrome does not immediately flush cookies to its database. It's possible - that this method will return a false negative.""" - cookie_db_path = os.path.join(self.profile_path, "Default", "Cookies") - try: - cookie_count = CookieProfileExtender._CookieCountInDB(cookie_db_path) - except sqlite3.OperationalError: - # There will occasionally be contention for the SQLite database. This - # shouldn't happen often, so ignore the errors. - return False - - return cookie_count > CookieProfileExtender._COOKIE_DB_EXPECTED_SIZE
diff --git a/tools/perf/profile_creators/cookie_profile_extender_unittest.py b/tools/perf/profile_creators/cookie_profile_extender_unittest.py deleted file mode 100644 index 8760159..0000000 --- a/tools/perf/profile_creators/cookie_profile_extender_unittest.py +++ /dev/null
@@ -1,56 +0,0 @@ -# Copyright 2015 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 tempfile -import unittest - -try: - import sqlite3 # Not present on ChromeOS. -except ImportError: - pass - - -from telemetry import decorators -from profile_creators.cookie_profile_extender import CookieProfileExtender - - -# Testing private method. -# pylint: disable=protected-access -class CookieProfileExtenderTest(unittest.TestCase): - - def _CreateCookieTable(self, path): - connection = sqlite3.connect(path) - cursor = connection.cursor() - cursor.execute("CREATE TABLE cookies (url text)") - connection.commit() - connection.close() - - def _AddCookiesToTable(self, path, count): - connection = sqlite3.connect(path) - cursor = connection.cursor() - for i in range(count): - cursor.execute("INSERT INTO cookies VALUES ('%s')" % i) - connection.commit() - connection.close() - - @decorators.Disabled("chromeos") # crbug.com/483212 - def testCookieCount(self): - # Neither tempfile.TemporaryFile() nor tempfile.NamedTemporaryFile() work - # well here. The former doesn't work at all, since it doesn't guarantee a - # file-system visible path. The latter doesn't work well, since the - # returned file cannot be opened a second time on Windows. The returned - # file would have to be closed, and the method would need to be called with - # Delete=False, which makes its functionality no simpler than - # tempfile.mkstemp(). - handle, path = tempfile.mkstemp() - try: - os.close(handle) - - self._CreateCookieTable(path) - self.assertEquals(CookieProfileExtender._CookieCountInDB(path), 0) - - self._AddCookiesToTable(path, 100) - self.assertEquals(CookieProfileExtender._CookieCountInDB(path), 100) - finally: - os.remove(path)
diff --git a/tools/perf/profile_creators/extension_profile_extender.py b/tools/perf/profile_creators/extension_profile_extender.py deleted file mode 100644 index 52b46152a..0000000 --- a/tools/perf/profile_creators/extension_profile_extender.py +++ /dev/null
@@ -1,175 +0,0 @@ -# Copyright 2015 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 atexit -import json -import logging -import os -import shutil -import sys -import time -import zipfile - -if sys.platform == 'win32': - import _winreg as winreg # pylint: disable=import-error - -from profile_creators import profile_extender -from py_utils import cloud_storage -from telemetry.core import exceptions - - -# Remote target upload directory in cloud storage for extensions. -REMOTE_DIR = 'extension_set' - -# Target zip file. -ZIP_NAME = 'extensions.zip' - - -class InvalidExtensionArchiveError(exceptions.Error): - """Exception thrown when remote archive is invalid or malformed. - - Remote archive should be located at REMOTE_DIR/ZIP_NAME. Upon failure, - prompts user to update remote archive using update_remote_extensions - script. - """ - - def __init__(self, msg=''): - msg += ('\nTry running\n' - '\tpython update_remote_extensions.py -e extension_set.csv\n' - 'in src/tools/perf/profile_creator subdirectory.') - super(InvalidExtensionArchiveError, self).__init__(msg) - - -class ExtensionProfileExtender(profile_extender.ProfileExtender): - """Creates a profile with many extensions.""" - - def __init__(self, finder_options): - super(ExtensionProfileExtender, self).__init__(finder_options) - self._extensions = [] - self.finder_options.browser_options.disable_default_apps = False - self.finder_options.browser_options.AppendExtraBrowserArgs( - '--prompt-for-external-extensions=0') - - def Run(self): - """Superclass override.""" - # Download extensions from cloud and force-install extensions into profile. - local_extensions_dir = os.path.join(self.profile_path, - 'external_extensions_crx') - self._DownloadRemoteExtensions(cloud_storage.PARTNER_BUCKET, - local_extensions_dir) - atexit.register(self._CleanUpExtensions) - self._LoadExtensions(local_extensions_dir, self.profile_path) - try: - self.SetUpBrowser() - self._WaitForExtensionsToLoad() - finally: - self.TearDownBrowser() - - def _DownloadRemoteExtensions(self, remote_bucket, local_extensions_dir): - """Downloads and unzips archive of common extensions to disk. - - Args: - remote_bucket: bucket to download remote archive from. - local_extensions_dir: destination extensions directory. - - Raises: - InvalidExtensionArchiveError if remote archive is not found. - """ - # Force Unix directory separator for remote path. - remote_zip_path = '%s/%s' % (REMOTE_DIR, ZIP_NAME) - local_zip_path = os.path.join(local_extensions_dir, ZIP_NAME) - try: - cloud_storage.Get(remote_bucket, remote_zip_path, local_zip_path) - except cloud_storage.ServerError: - raise InvalidExtensionArchiveError('Can\'t find archive at gs://%s/%s..' - % (remote_bucket, remote_zip_path)) - try: - with zipfile.ZipFile(local_zip_path, 'r') as extensions_zip: - extensions_zip.extractall(local_extensions_dir) - finally: - os.remove(local_zip_path) - - def _GetExtensionInfoFromCrx(self, crx_file): - """Retrieves version + name of extension from CRX archive.""" - with zipfile.ZipFile(crx_file, 'r') as crx_zip: - manifest_contents = crx_zip.read('manifest.json') - decoded_manifest = json.loads(manifest_contents) - crx_version = decoded_manifest['version'] - extension_name = decoded_manifest['name'] - return (crx_version, extension_name) - - def _LoadExtensions(self, local_extensions_dir, profile_dir): - """Loads extensions in _local_extensions_dir into user profile. - - Extensions are loaded according to platform specifications at - https://developer.chrome.com/extensions/external_extensions.html - - Args: - local_extensions_dir: directory containing CRX files. - profile_dir: target profile directory for the extensions. - - Raises: - InvalidExtensionArchiveError if archive contains a non-CRX file. - """ - ext_files = os.listdir(local_extensions_dir) - external_ext_dir = os.path.join(profile_dir, 'External Extensions') - os.makedirs(external_ext_dir) - for ext_file in ext_files: - ext_path = os.path.join(local_extensions_dir, ext_file) - if not ext_file.endswith('.crx'): - raise InvalidExtensionArchiveError('Archive contains non-crx file %s.' - % ext_file) - (version, name) = self._GetExtensionInfoFromCrx(ext_path) - ext_id = os.path.splitext(os.path.basename(ext_path))[0] - extension_info = { - 'extension_id': ext_id, - 'external_crx': ext_path, - 'external_version': version, - '_comment': name - } - # Platform-specific external extension installation - if self.os_name == 'win': # Windows - key_path = 'Software\\Google\\Chrome\\Extensions\\%s' % ext_id - self._WriteRegistryValue(key_path, 'Path', ext_path) - self._WriteRegistryValue(key_path, 'Version', version) - else: - extension_json_path = os.path.join(external_ext_dir, '%s.json' % ext_id) - with open(extension_json_path, 'w') as f: - f.write(json.dumps(extension_info)) - self._extensions.append(ext_id) - - def _WriteRegistryValue(self, key_path, name, value): - """Writes (or overwrites) registry value specified to HKCU\\key_path.""" - with winreg.CreateKey(winreg.HKEY_CURRENT_USER, key_path) as key: - try: # Does registry value already exist? - path_value = winreg.QueryValueEx(key, name) - if path_value != value: - logging.warning( - 'Overwriting registry value %s\\%s:' - '\n%s with %s', key_path, name, path_value, value) - except OSError: - pass - winreg.SetValueEx(key, name, 0, winreg.REG_SZ, value) - - def _CleanUpExtensions(self): - """Cleans up registry keys or JSON files used to install extensions.""" - if self.os_name == 'win': - for ext_id in self._extensions: - winreg.DeleteKey(winreg.HKEY_CURRENT_USER, - 'Software\\Google\\Chrome\\Extensions\\%s' % ext_id) - else: - to_remove = os.path.join(self.profile_path, 'External Extensions') - if os.path.exists(to_remove): - shutil.rmtree(to_remove) - - def _WaitForExtensionsToLoad(self): - """Stall until browser has finished installing/loading all extensions.""" - unloaded_extensions = set(self._extensions) - while unloaded_extensions: - loaded_extensions = set([key.extension_id for key in - self.browser.extensions.keys()]) - unloaded_extensions = unloaded_extensions - loaded_extensions - # There's no event signalling when browser finishes installing - # or loading an extension so re-check every 5 seconds. - time.sleep(5)
diff --git a/tools/perf/profile_creators/extension_profile_extender_unittest.py b/tools/perf/profile_creators/extension_profile_extender_unittest.py deleted file mode 100644 index 6f5992d..0000000 --- a/tools/perf/profile_creators/extension_profile_extender_unittest.py +++ /dev/null
@@ -1,40 +0,0 @@ -# Copyright 2016 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 shutil -import tempfile - -from profile_creators import extension_profile_extender -from telemetry import decorators -from telemetry.testing import options_for_unittests -from telemetry.testing import page_test_test_case - - -class ExtensionProfileExtenderUnitTest(page_test_test_case.PageTestTestCase): - """Smoke test for creating an extension profile. - - Creates an extension profile and verifies that it has non-empty contents. - """ - # Should be enabled on mac, disabled because flaky: https://crbug.com/586362. - @decorators.Disabled('all') # Extension generation only works on Mac for now. - def testExtensionProfileCreation(self): - tmp_dir = tempfile.mkdtemp() - files_in_crx_dir = 0 - try: - options = options_for_unittests.GetCopy() - # TODO(eakuefner): Remove this after crrev.com/1874473006 rolls in. - try: - getattr(options, 'output_profile_path') - options.output_profile_path = tmp_dir - except AttributeError: - options.browser_options.output_profile_path = tmp_dir - extender = extension_profile_extender.ExtensionProfileExtender(options) - extender.Run() - - crx_dir = os.path.join(tmp_dir, 'external_extensions_crx') - files_in_crx_dir = len(os.listdir(crx_dir)) - finally: - shutil.rmtree(tmp_dir) - self.assertGreater(files_in_crx_dir, 0)
diff --git a/tools/perf/profile_creators/extension_set.csv b/tools/perf/profile_creators/extension_set.csv deleted file mode 100644 index f3550987..0000000 --- a/tools/perf/profile_creators/extension_set.csv +++ /dev/null
@@ -1,25 +0,0 @@ -# Fields automatically updated by update_remote_extensions.py. -# Do not manually alter individual fields. -# To manually add extension, append line: -# <extension_name>,<extension_id>,, -# and run update_remote_extensions.py to update hash and version columns. -# To manually remove extension, remove the entire line. -extension_name,id,hash,version -Avast Online Security,gomekmidlodglbbmalcneegieacbdmki,YTIzNDZlYjE4NWI5NzM4ZTExYTI0MDBhN2RkODg2ZGRiZTE5MTdlYg==,10.2.0.190 -Skype Click to Call,lifbcibllhkdhoafpjfnlhfpfgnpldfl,OWY2MTYwNDg0ZDkyNmNjZDlmMGNlMWUyOWFiNjJmMWMxZTY3N2ZlNw==,7.4.0.9058 -AdBlock,gighmmpiobklfepjocnamgkkbiglidom,NDNlMmEwZTNjMjFjNzk2OTQzMWFkMWYzYmZkM2Q2YjViODA0OTRkZQ==,2.36.2 -Bookmark Manager,gmlllbghnfkpflemihljekbapjopfjik,ZGJlNmRkMDE3N2I2ZTZlZmNjYjE5MTBkY2M5NDJkNTRlMDM3NTQ1Yg==,2.2015.611.10417 -Adblock Plus,cfhdojbkjhnklbpkdaibdccddilifddb,YjJhNjljMWFkNjFhNjA3ODk3OTJhNjVjZmY4ZTJmMzFkN2UyYzU0Nw==,1.9.1 -iLivid,nafaimnnclfjfedmmabolbppcngeolgf,MzdiZGE1NmRjODRlOTZjNmIwYTM0ZDVjYjJhYzcxZGJmOGZiYjg0YQ==,1.1 -SiteAdvisor,fheoggkfdfchfphceeifdbepaooicaho,MzE1YjNhYjg2Mjk0NTYwYTllZGJlYTk5MjMyZjYwZGNmOGNlMGQ2Mw==,4.0.0.0 -Avast SafePrice,eofcbnmajmjmplflapaojjnihcjkigck,MWVlYjBlYWYyZGUzNjQxMWE4NWRkNDczMzRlZWY5Nzc1N2M4Y2M0Yg==,10.2.0.190 -Norton Identity Safe,iikflkcanblccfahdhdonehdalibjnif,OTA1NGI5MThiZGFkOWRkNjAzNGQ2N2EzODdhNzUwNTNkZTIyMjAyZA==,1.0.5 -Application Launcher for Drive (by Google),lmjegmlicamnimmfhcmpkclmigmmcbeh,NWY0NjY2ZDNhNGNlOWU3MTY4MjlhMTE5MWFhZTk4Y2FlZTI5NmUwMQ==,3.2 -Norton Security Toolbar,mkfokfffehpeedafpekjeddnmnjhmcmk,NTdlOWVlZjQ0OTU3MDYyMzlhODEzZDc4N2FiYWIyNDhjMTQxYmI1Yw==,2014.7.12.29 -Ask App for iLivid,mppnoffgpafgpgbaigljliadgbnhljfl,ZTg5YzhhMWIyMDk5MGMzN2ZlNTU5ZGU3MjM5NjMwZTAyZTc1Y2E5NA==,1.1 -Avira Browser Safety,flliilndjeohchalpbbcdekjklbdgfkk,ZTk5NGQ4NzRiNWQ2ZGNmZmE1MWFlMTM3YWYxYzcwZTA1NmI3N2RlYw==,1.4.10 -MSN Homepage & Bing Search Engine,fcfenmboojpjinhpgggodefccipikbpd,NjNkNGVkZDFlNTYzNTBkOGY1ZDFiOWZmZGQyOWIxZDkzOWMwODM0Yg==,0.0.0.8 -Adobe Acrobat - Create PDF,efaidnbmnnnibpcajpcglclefindmkaj,MjdkNzdjM2MwYzNhMDJmZDRlYTI1ODc3MjZkZGViMDJmMjkzNTFlMw==,15.0.0.0 -Cisco WebEx Extension,jlhmfgmfgeifomenelglieieghnjghma,NmQ0Y2VhMDI0OGU5YzcxNDAxZjdmYWZmYzBjNGUwZjgzYjI0YWZmYg==,1.0.1 -IDM Helper Module,ngpampappnmepgilojfohadhhmbhlaek,YzIzYzUwYmQ3MGNmOGRmMzFhOWE4OGI0NDg0ZWRhNzU1OTIxZGI5Zg==,6.22.3 -Pin It Button,gpdjojdkbbmdfjfahjcgigfpmkopogic,M2Q2NGU0ZTkwZDBhMmI5M2NkYzFkY2I2ZTFiYTFiZjE3ZDVhZjZhMQ==,1.38.2
diff --git a/tools/perf/profile_creators/fast_navigation_profile_extender.py b/tools/perf/profile_creators/fast_navigation_profile_extender.py deleted file mode 100644 index f2003d4..0000000 --- a/tools/perf/profile_creators/fast_navigation_profile_extender.py +++ /dev/null
@@ -1,245 +0,0 @@ -# Copyright 2015 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 time - -from profile_creators import profile_extender -from telemetry.core import exceptions -from telemetry.core import util - - -class FastNavigationProfileExtender(profile_extender.ProfileExtender): - """Extends a Chrome profile. - - This class creates or extends an existing profile by performing a set of tab - navigations in large batches. This is accomplished by opening a large number - of tabs, simultaneously navigating all the tabs, and then waiting for all the - tabs to load. This provides two benefits: - - Takes advantage of the high number of logical cores on modern CPUs. - - The total time spent waiting for navigations to time out scales linearly - with the number of batches, but does not scale with the size of the - batch. - """ - - def __init__(self, finder_options, maximum_batch_size): - """Initializer. - - Args: - maximum_batch_size: A positive integer indicating the number of tabs to - simultaneously perform navigations. - """ - super(FastNavigationProfileExtender, self).__init__(finder_options) - - # The instance keeps a list of Tabs that can be navigated successfully. - # This means that the Tab is not crashed, and is processing JavaScript in a - # timely fashion. - self._navigation_tabs = [] - - # The number of tabs to use. - self._NUM_TABS = maximum_batch_size - - # The amount of additional time to wait for a batch of pages to finish - # loading for each page in the batch. - self._BATCH_TIMEOUT_PER_PAGE_IN_SECONDS = 20 - - # The amount of time to wait for a page to quiesce. Some pages will never - # quiesce. - self._TIME_TO_WAIT_FOR_PAGE_TO_QUIESCE_IN_SECONDS = 10 - - def Run(self): - """Superclass override.""" - try: - self.SetUpBrowser() - self._PerformNavigations() - finally: - self.TearDownBrowser() - - # When there hasn't been an exception, verify that the profile was - # correctly extended. - # TODO(erikchen): I've intentionally omitted my implementation of - # VerifyProfileWasExtended() in small_profile_extender, since the profile - # is not being correctly extended. http://crbug.com/484833 - # http://crbug.com/484880 - self.VerifyProfileWasExtended() - - def VerifyProfileWasExtended(self): - """Verifies that the profile was correctly extended. - - Can be overridden by subclasses. - """ - pass - - def GetUrlIterator(self): - """Gets URLs for the browser to navigate to. - - Intended for subclass override. - - Returns: - An iterator whose elements are urls to be navigated to. - """ - raise NotImplementedError() - - def ShouldExitAfterBatchNavigation(self): - """Returns a boolean indicating whether profile extension is finished. - - Intended for subclass override. - """ - raise NotImplementedError() - - def CleanUpAfterBatchNavigation(self): - """A hook for subclasses to perform cleanup after each batch of - navigations. - - Can be overridden by subclasses. - """ - pass - - def _RefreshNavigationTabs(self): - """Updates the member self._navigation_tabs to contain self._NUM_TABS - elements, each of which is not crashed. The crashed tabs are intentionally - leaked, since Telemetry doesn't have a good way of killing crashed tabs. - - It is also possible for a tab to be stalled in an infinite JavaScript loop. - These tabs will be in self.browser.tabs, but not in self._navigation_tabs. - There is no way to kill these tabs, so they are also leaked. This method is - careful to only use tabs in self._navigation_tabs, or newly created tabs. - """ - live_tabs = [tab for tab in self._navigation_tabs if tab.IsAlive()] - self._navigation_tabs = live_tabs - - while len(self._navigation_tabs) < self._NUM_TABS: - self._navigation_tabs.append(self._browser.tabs.New()) - - def _RemoveNavigationTab(self, tab): - """Removes a tab which is no longer in a useable state from - self._navigation_tabs. The tab is not removed from self.browser.tabs, - since there is no guarantee that the tab can be safely removed.""" - self._navigation_tabs.remove(tab) - - def _RetrieveTabUrl(self, tab, timeout): - """Retrives the URL of the tab.""" - # TODO(erikchen): Use tab.url instead, which talks to the browser process - # instead of the renderer process. http://crbug.com/486119 - return tab.EvaluateJavaScript('document.URL', timeout=timeout) - - def _WaitForUrlToChange(self, tab, initial_url, end_time): - """Waits for the tab to navigate away from its initial url. - - If time.time() is larger than end_time, the function does nothing. - Otherwise, the function tries to return no later than end_time. - """ - while True: - seconds_to_wait = end_time - time.time() - if seconds_to_wait <= 0: - break - - current_url = self._RetrieveTabUrl(tab, seconds_to_wait) - if current_url != initial_url and current_url != '': - break - - # Retrieving the current url is a non-trivial operation. Add a small - # sleep here to prevent this method from contending with the actual - # navigation. - time.sleep(0.01) - - def _WaitForTabToBeReady(self, tab, end_time): - """Waits for the tab to be ready. - - If time.time() is larger than end_time, the function does nothing. - Otherwise, the function tries to return no later than end_time. - """ - seconds_to_wait = end_time - time.time() - if seconds_to_wait <= 0: - return - tab.WaitForDocumentReadyStateToBeComplete(seconds_to_wait) - - # Wait up to 10 seconds for the page to quiesce. If the page hasn't - # quiesced in 10 seconds, it will probably never quiesce. - seconds_to_wait = end_time - time.time() - seconds_to_wait = max(0, seconds_to_wait) - try: - util.WaitFor(tab.HasReachedQuiescence, seconds_to_wait) - except exceptions.TimeoutException: - pass - - def _BatchNavigateTabs(self, batch): - """Performs a batch of tab navigations with minimal delay. - - Args: - batch: A list of tuples (tab, url). - - Returns: - A list of tuples (tab, initial_url). |initial_url| is the url of the - |tab| prior to a navigation command being sent to it. - """ - # Attempting to pass in a timeout of 0 seconds results in a synchronous - # socket error from the websocket library. Pass in a very small timeout - # instead so that the websocket library raises a Timeout exception. This - # prevents the logic from accidentally catching different socket - # exceptions. - timeout_in_seconds = 0.01 - - queued_tabs = [] - for tab, url in batch: - initial_url = self._RetrieveTabUrl(tab, 20) - try: - tab.Navigate(url, None, timeout_in_seconds) - except exceptions.TimeoutException: - # We expect to receive a timeout exception, since we're not waiting for - # the navigation to complete. - pass - queued_tabs.append((tab, initial_url)) - return queued_tabs - - def _WaitForQueuedTabsToLoad(self, queued_tabs): - """Waits for all the batch navigated tabs to finish loading. - - Args: - queued_tabs: A list of tuples (tab, initial_url). Each tab is guaranteed - to have already been sent a navigation command. - """ - total_batch_timeout = (len(queued_tabs) * - self._BATCH_TIMEOUT_PER_PAGE_IN_SECONDS) - end_time = time.time() + total_batch_timeout - for tab, initial_url in queued_tabs: - # Since we didn't wait any time for the tab url navigation to commit, it's - # possible that the tab hasn't started navigating yet. - self._WaitForUrlToChange(tab, initial_url, end_time) - self._WaitForTabToBeReady(tab, end_time) - - def _GetUrlsToNavigate(self, url_iterator): - """Returns an array of urls to navigate to, given a url_iterator.""" - urls = [] - for _ in xrange(self._NUM_TABS): - try: - urls.append(url_iterator.next()) - except StopIteration: - break - return urls - - def _PerformNavigations(self): - """Repeatedly fetches a batch of urls, and navigates to those urls. This - will run until an empty batch is returned, or - ShouldExitAfterBatchNavigation() returns True. - """ - url_iterator = self.GetUrlIterator() - while True: - self._RefreshNavigationTabs() - urls = self._GetUrlsToNavigate(url_iterator) - - if len(urls) == 0: - break - - batch = [] - for i in range(len(urls)): - url = urls[i] - tab = self._navigation_tabs[i] - batch.append((tab, url)) - - queued_tabs = self._BatchNavigateTabs(batch) - self._WaitForQueuedTabsToLoad(queued_tabs) - - self.CleanUpAfterBatchNavigation() - - if self.ShouldExitAfterBatchNavigation(): - break
diff --git a/tools/perf/profile_creators/fast_navigation_profile_extender_unittest.py b/tools/perf/profile_creators/fast_navigation_profile_extender_unittest.py deleted file mode 100644 index 0a065b0..0000000 --- a/tools/perf/profile_creators/fast_navigation_profile_extender_unittest.py +++ /dev/null
@@ -1,93 +0,0 @@ -# Copyright 2015 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 unittest - -from profile_creators.fast_navigation_profile_extender import ( - FastNavigationProfileExtender) -from telemetry.testing import options_for_unittests - -import mock # pylint: disable=import-error - - -class FakeTab(object): - pass - - -class FakeTabList(object): - - def __init__(self): - self._tabs = [] - - def New(self): - tab = FakeTab() - self._tabs.append(tab) - return tab - - def __len__(self): - return len(self._tabs) - - -class FakeBrowser(object): - - def __init__(self): - self.tabs = FakeTabList() - - -# Testing private method. -# pylint: disable=protected-access -class FastNavigationProfileExtenderTest(unittest.TestCase): - - def testPerformNavigations(self): - maximum_batch_size = 15 - options = options_for_unittests.GetCopy() - extender = FastNavigationProfileExtender(options, maximum_batch_size) - - navigation_urls = [] - for i in range(extender._NUM_TABS): - navigation_urls.append('http://test%s.com' % i) - batch_size = 5 - navigation_urls_batch = navigation_urls[3:3 + batch_size] - - extender.GetUrlIterator = mock.MagicMock( - return_value=iter(navigation_urls_batch)) - extender.ShouldExitAfterBatchNavigation = mock.MagicMock(return_value=True) - extender._WaitForQueuedTabsToLoad = mock.MagicMock() - - extender._browser = FakeBrowser() - extender._BatchNavigateTabs = mock.MagicMock() - - # Set up a callback to record the tabs and urls in each navigation. - callback_tabs_batch = [] - callback_urls_batch = [] - - def SideEffect(*args, **_): - batch = args[0] - for tab, url in batch: - callback_tabs_batch.append(tab) - callback_urls_batch.append(url) - extender._BatchNavigateTabs.side_effect = SideEffect - - # Perform the navigations. - extender._PerformNavigations() - - # Each url in the batch should have been navigated to exactly once. - self.assertEqual(set(callback_urls_batch), set(navigation_urls_batch)) - - # The other urls should not have been navigated to. - navigation_urls_remaining = (set(navigation_urls) - - set(navigation_urls_batch)) - self.assertFalse(navigation_urls_remaining & set(callback_urls_batch)) - - # The first couple of tabs should have been navigated once. The remaining - # tabs should not have been navigated. - for i in range(len(extender._browser.tabs)): - tab = extender._browser.tabs._tabs[i] - - if i < batch_size: - expected_tab_navigation_count = 1 - else: - expected_tab_navigation_count = 0 - - count = callback_tabs_batch.count(tab) - self.assertEqual(count, expected_tab_navigation_count)
diff --git a/tools/perf/profile_creators/large_profile_extender.py b/tools/perf/profile_creators/large_profile_extender.py deleted file mode 100644 index 1afe6e4..0000000 --- a/tools/perf/profile_creators/large_profile_extender.py +++ /dev/null
@@ -1,16 +0,0 @@ -# Copyright 2014 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. - -from profile_creators import cookie_profile_extender -from profile_creators import profile_extender - - -class LargeProfileExtender(profile_extender.ProfileExtender): - """This class creates a large profile by performing a large number of url - navigations.""" - - def Run(self): - extender = cookie_profile_extender.CookieProfileExtender( - self.finder_options) - extender.Run()
diff --git a/tools/perf/profile_creators/profile_extender.py b/tools/perf/profile_creators/profile_extender.py deleted file mode 100644 index f1782af1..0000000 --- a/tools/perf/profile_creators/profile_extender.py +++ /dev/null
@@ -1,162 +0,0 @@ -# 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. - -import copy - -from telemetry.core import platform -from telemetry.util import wpr_modes -from telemetry.internal.browser import browser_finder -from telemetry.internal.browser import browser_finder_exceptions - - -class ProfileExtender(object): - """Abstract base class for an object that constructs a Chrome profile.""" - - def __init__(self, finder_options): - """Initializer. - - |finder_options| is an instance of BrowserFinderOptions. When subclass - implementations of this method inevitably attempt to find and launch a - browser, they should pass |finder_options| to the relevant methods. - - Several properties of |finder_options| might require direct manipulation by - subclasses. These are: - |finder_options.output_profile_path|: The path at which the profile - should be created. - |finder_options.browser_options.profile_dir|: If this property is None, - then a new profile is created. Otherwise, the existing profile is - appended on to. - """ - self._finder_options = copy.deepcopy(finder_options) - # Since profile extenders are not supported on remote platforms, - # this should be the same as target platform. - self._os_name = platform.GetHostPlatform().GetOSName() - - # A reference to the browser that will be performing all of the tab - # navigations. - # This member is initialized during SetUpBrowser(). - self._browser = None - - # We only need to close network controller if we opened it before. - # If it was already open, we should not close it. - self._should_close_network_controller = False - - def Run(self): - """Creates or extends the profile.""" - raise NotImplementedError() - - def WebPageReplayArchivePath(self): - """Returns the path to the WPR archive. - - Can be overridden by subclasses. - """ - return None - - @property - def finder_options(self): - """The options to use to find and run the browser.""" - return self._finder_options - - @property - def profile_path(self): - """The path of the profile that the browser will use while it's running.""" - # TODO(eakuefner): Remove this after crrev.com/1874473006 rolls in. - return getattr(self.finder_options, 'output_profile_path', - self.finder_options.browser_options.output_profile_path) - - @property - def browser(self): - return self._browser - - @property - def os_name(self): - """Name of OS that extender is currently running on.""" - return self._os_name - - def EnabledOSList(self): - """Returns a list of OSes that this extender can run on. - - Can be overridden by subclasses. - - Returns: - List of OS ('win', 'mac', or 'linux') that this extender can run on. - """ - return ['win', 'mac', 'linux'] - - def SetUpBrowser(self): - """Finds and starts the browser. - - Can be overridden by subclasses. The subclass implementation must call the - super class implementation. - - Subclasses do not need to call this method. This method is only necessary - if the subclass needs to start a browser. If a subclass does call this - method, the subclass must also call TearDownBrowser(). - """ - possible_browser = self._GetPossibleBrowser(self.finder_options) - enabled_os_list = self.EnabledOSList() - if self._os_name not in enabled_os_list: - raise NotImplementedError( - 'This profile extender on %s is not yet supported' - % self._os_name) - if possible_browser.IsRemote(): - raise NotImplementedError( - 'Profile extenders are not yet supported on remote platforms.') - assert possible_browser.supports_tab_control - - self._SetUpWebPageReplay(self.finder_options, possible_browser) - self._browser = possible_browser.Create(self.finder_options) - - def TearDownBrowser(self): - """Tears down the browser. - - Can be overridden by subclasses. The subclass implementation must call the - super class implementation. - """ - if self._browser: - if self._should_close_network_controller: - self._browser.platform.network_controller.Close() - self._browser.Close() - self._browser = None - - def FetchWebPageReplayArchives(self): - """Fetches the web page replay archives. - - Can be overridden by subclasses. - """ - pass - - def _SetUpWebPageReplay(self, finder_options, possible_browser): - """Sets up Web Page Replay, if necessary.""" - - wpr_archive_path = self.WebPageReplayArchivePath() - if not wpr_archive_path: - return - - self.FetchWebPageReplayArchives() - - if finder_options.use_live_sites: - wpr_mode = wpr_modes.WPR_OFF - else: - wpr_mode = wpr_modes.WPR_REPLAY - - network_controller = possible_browser.platform.network_controller - if not network_controller.is_open: - self._should_close_network_controller = True - network_controller.Open(wpr_mode, - finder_options.browser_options.extra_wpr_args) - network_controller.StartReplay( - wpr_archive_path, make_javascript_deterministic=True) - - def _GetPossibleBrowser(self, finder_options): - """Return a possible_browser with the given options.""" - possible_browser = browser_finder.FindBrowser(finder_options) - if not possible_browser: - raise browser_finder_exceptions.BrowserFinderException( - 'No browser found.\n\nAvailable browsers:\n%s\n' % - '\n'.join(browser_finder.GetAllAvailableBrowserTypes(finder_options))) - finder_options.browser_options.browser_type = ( - possible_browser.browser_type) - - return possible_browser
diff --git a/tools/perf/profile_creators/profile_generator.py b/tools/perf/profile_creators/profile_generator.py deleted file mode 100644 index 3b880a5..0000000 --- a/tools/perf/profile_creators/profile_generator.py +++ /dev/null
@@ -1,216 +0,0 @@ -# Copyright 2014 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. - -"""Handles generating profiles and transferring them to/from mobile devices.""" - -import logging -import optparse -import os -import shutil -import stat -import sys -import tempfile - -from profile_creators import profile_extender -from telemetry.core import util -from telemetry.internal import story_runner -from telemetry.internal.browser import browser_finder -from telemetry.internal.browser import browser_options -from telemetry.internal.util import binary_manager - -from py_utils import discover - -def _DiscoverProfileExtenderClasses(): - profile_extenders_dir = ( - os.path.abspath( - os.path.join( - util.GetBaseDir(), '..', 'perf', - 'profile_creators'))) - base_dir = os.path.abspath(os.path.join(profile_extenders_dir, '..')) - - profile_extenders_unfiltered = discover.DiscoverClasses( - profile_extenders_dir, base_dir, profile_extender.ProfileExtender) - - # Remove 'extender' suffix from keys. - profile_extenders = {} - for test_name, test_class in profile_extenders_unfiltered.iteritems(): - assert test_name.endswith('_extender') - test_name = test_name[:-len('_extender')] - profile_extenders[test_name] = test_class - return profile_extenders - - -def _IsPseudoFile(directory, paths): - """Filter function for shutil.copytree() to reject socket files and symlinks - since those can't be copied around on bots.""" - def IsSocket(full_path): - """Check if a file at a given path is a socket.""" - try: - if stat.S_ISSOCK(os.stat(full_path).st_mode): - return True - except OSError: - # Thrown if we encounter a broken symlink. - pass - return False - - ignore_list = [] - for path in paths: - full_path = os.path.join(directory, path) - - if os.path.isdir(full_path): - continue - if not IsSocket(full_path) and not os.path.islink(full_path): - continue - - logging.warning('Ignoring pseudo file: %s', full_path) - ignore_list.append(path) - - return ignore_list - - -class ProfileGenerator(object): - """Generate profile. - - On desktop the generated profile is copied to the specified location so later - runs can reuse it. - On CrOS profile resides on cryptohome and there is no easy way to - override it before user login. So for CrOS we just generate the profile - every time when the benchmark starts to run. - """ - - def __init__(self, profile_extender_class, profile_name): - self._profile_extender_class = profile_extender_class - self._profile_name = profile_name - - def Run(self, options): - """Kick off the process. - - Args: - options: Instance of BrowserFinderOptions to search for proper browser. - - Returns: - A 2-tuple (path, new_profile). - - path: The path of the generated profile or existing profile if - --profile-dir is given. Could be None if it's generated on default - location (e.g., cryptohome on CrOS). - - new_profile: Whether a new profile has been generated. If this is True, - the caller is responsible for deleting the profile. - """ - possible_browser = browser_finder.FindBrowser(options) - - if possible_browser.browser_type.startswith('cros'): - self.Create(options, None) - return (None, False) - - # Use the given --profile-dir. - if options.browser_options.profile_dir: - return (options.browser_options.profile_dir, False) - - out_dir = tempfile.mkdtemp(prefix=self._profile_name) - - self.Create(options, out_dir) - return (out_dir, True) - - def Create(self, options, out_dir): - """Generate profile. - - If out_dir is given, copy the generated profile to out_dir. - Otherwise the profile is generated to its default position - (e.g., cryptohome on CrOS). - """ - - # Leave the global options intact. - creator_options = options.Copy() - - if out_dir: - sys.stderr.write('Generating profile to: %s \n' % out_dir) - # The genrated profile is copied to out_dir only if the generation is - # successful. In the generation process a temp directory is used so - # the default profile is not polluted on failure. - tmp_profile_path = tempfile.mkdtemp() - # TODO(eakuefner): Remove this after crrev.com/1874473006 rolls in. - try: - getattr(creator_options, 'output_profile_path') - creator_options.output_profile_path = tmp_profile_path - except AttributeError: - creator_options.browser_options.output_profile_path = tmp_profile_path - - creator = self._profile_extender_class(creator_options) - - try: - creator.Run() - except Exception as e: - logging.exception('Profile creation failed.') - raise e - else: - sys.stderr.write('SUCCESS: Profile generated.\n') - - # Copy generated profile to final destination if out_dir is given. - if out_dir: - if os.path.exists(out_dir): - shutil.rmtree(out_dir) - shutil.copytree(tmp_profile_path, - out_dir, ignore=_IsPseudoFile) - sys.stderr.write( - "SUCCESS: Generated profile copied to: '%s'.\n" % out_dir) - finally: - if out_dir: - shutil.rmtree(tmp_profile_path) - - -def AddCommandLineArgs(parser): - story_runner.AddCommandLineArgs(parser) - - profile_extenders = _DiscoverProfileExtenderClasses().keys() - legal_profile_creators = '|'.join(profile_extenders) - group = optparse.OptionGroup(parser, 'Profile generation options') - group.add_option('--profile-type-to-generate', - dest='profile_type_to_generate', - default=None, - help='Type of profile to generate. ' - 'Supported values: %s' % legal_profile_creators) - parser.add_option_group(group) - - -def ProcessCommandLineArgs(parser, args): - story_runner.ProcessCommandLineArgs(parser, args) - - if not args.profile_type_to_generate: - parser.error('Must specify --profile-type-to-generate option.') - - profile_extenders = _DiscoverProfileExtenderClasses().keys() - if args.profile_type_to_generate not in profile_extenders: - legal_profile_creators = '|'.join(profile_extenders) - parser.error('Invalid profile type, legal values are: %s.' % - legal_profile_creators) - - if not args.browser_type: - parser.error('Must specify --browser option.') - - if not args.output_dir: - parser.error('Must specify --output-dir option.') - - if args.browser_options.dont_override_profile: - parser.error("Can't use existing profile when generating profile.") - - -def Main(): - binary_manager.InitDependencyManager(None) - options = browser_options.BrowserFinderOptions() - parser = options.CreateParser( - '%%prog <--profile-type-to-generate=...> <--browser=...> <--output-dir>') - AddCommandLineArgs(parser) - _, _ = parser.parse_args() - ProcessCommandLineArgs(parser, options) - - # Generate profile. - profile_extenders = _DiscoverProfileExtenderClasses() - profile_extender_class = profile_extenders[options.profile_type_to_generate] - - generator = ProfileGenerator(profile_extender_class, - options.profile_type_to_generate) - generator.Create(options, options.output_dir) - return 0
diff --git a/tools/perf/profile_creators/profile_generator_unittest.py b/tools/perf/profile_creators/profile_generator_unittest.py deleted file mode 100644 index f3cd6302..0000000 --- a/tools/perf/profile_creators/profile_generator_unittest.py +++ /dev/null
@@ -1,69 +0,0 @@ -# Copyright 2014 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 shutil -import socket -import tempfile -import unittest - -from profile_creators import profile_generator - - -class ProfileGeneratorUnitTest(unittest.TestCase): - - def setUp(self): - self.test_directory = tempfile.mkdtemp() - super(ProfileGeneratorUnitTest, self).setUp() - - def _CreateFunkyFilesAndOnePlainFile(self, sandbox_directory): - """Create several special files and one plain file in |sandbox_directory|. - """ - if os.path.exists(sandbox_directory): - shutil.rmtree(sandbox_directory) - - os.mkdir(sandbox_directory) - - # Make a plain file. - plain_filename = os.path.join(sandbox_directory, 'plain_file') - open(plain_filename, 'a').close() - - # Make a directory. - directory_filename = os.path.join(sandbox_directory, 'directory') - os.mkdir(directory_filename) - - if getattr(os, 'symlink', None): # Symlinks not supported on Windows. - # Make a symlink. - symlink_filename = os.path.join(sandbox_directory, 'symlink') - os.symlink(plain_filename, symlink_filename) - - # Make a broken symlink. - nonexistant_filename = os.path.join(sandbox_directory, 'i_dont_exist') - broken_symlink_filename = os.path.join(sandbox_directory, - 'broken_symlink') - os.symlink(nonexistant_filename, broken_symlink_filename) - - # Make a named socket. - if getattr(socket, 'AF_UNIX', None): # Windows doesn't support these. - socket_filename = os.path.join(sandbox_directory, 'named_socket') - the_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - the_socket.bind(socket_filename) - - def testIsPseudoFile(self): - sandbox_dir = os.path.join(self.test_directory, 'sandbox') - self._CreateFunkyFilesAndOnePlainFile(sandbox_dir) - - # If we can copy the directory, we're golden! - sandbox_dir_copy = os.path.join(self.test_directory, 'sandbox_copy') - # pylint: disable=protected-access - shutil.copytree(sandbox_dir, sandbox_dir_copy, - ignore=profile_generator._IsPseudoFile) - - # Check that only the directory and plain file got copied. - dir_contents = os.listdir(sandbox_dir_copy) - dir_contents.sort() - self.assertEqual(['directory', 'plain_file'], dir_contents) - - def tearDown(self): - shutil.rmtree(self.test_directory)
diff --git a/tools/perf/profile_creators/profile_safe_url_generator.py b/tools/perf/profile_creators/profile_safe_url_generator.py deleted file mode 100644 index 0355735..0000000 --- a/tools/perf/profile_creators/profile_safe_url_generator.py +++ /dev/null
@@ -1,97 +0,0 @@ -# Copyright 2015 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 HTMLParser -import json -import logging -import urllib2 -import urlparse - - -class _HRefParser(HTMLParser.HTMLParser): - - def __init__(self): - HTMLParser.HTMLParser.__init__(self) - self.hrefs = [] - - def handle_starttag(self, tag, attrs): - if tag == "a": - for name, value in attrs: - if name == "href": - self.hrefs.append(value) - - -def _AbsoluteUrlHasSaneScheme(absolute_url): - if len(absolute_url) < 4: - return False - return absolute_url[0:4] == "http" - - -def GenerateSafeUrls(): - """Prints a list of safe urls. - - Generates a safe list of urls from a seed list. Each href in the HTML - fetched from the url from the seed list is placed into the safe list. The - safe list contains unsanitized urls. - """ - # A list of websites whose hrefs are unlikely to link to sites that contain - # malware. - seed_urls = [ - "http://www.cnn.com", - "https://www.youtube.com", - "https://www.facebook.com", - "https://www.twitter.com", - "https://www.yahoo.com", - "https://www.amazon.com", - "https://www.wikipedia.com", - "https://www.bing.com", - "https://www.dailymotion.com", - "https://www.stackoverflow.com", - "https://www.google.com/#q=dumpling", - "http://www.baidu.com/s?wd=rice", - "http://www.baidu.com/s?wd=cow", - "https://www.google.com/#q=fox", - "http://www.yahoo.co.jp/", - "http://www.yandex.ru/", - "https://www.imdb.com/", - "http://www.huffingtonpost.com/", - "https://www.deviantart.com/", - "http://www.wsj.com/", - ] - - safe_urls = set() - - for url in seed_urls: - try: - # Fetch and parse the HTML. - response = urllib2.urlopen(url) - encoding = response.headers.getparam("charset") - html = response.read() - if encoding: - html = html.decode(encoding) - - parser = _HRefParser() - parser.feed(html) - except: - logging.exception("Error fetching or parsing url: %s", url) - raise - - # Looks for all hrefs. - for relative_url in parser.hrefs: - if not relative_url: - continue - - absolute_url = urlparse.urljoin(url, relative_url) - if not _AbsoluteUrlHasSaneScheme(absolute_url): - continue - safe_urls.add(absolute_url) - - # Sort the urls, to make them easier to view in bulk. - safe_urls_list = list(safe_urls) - safe_urls_list.sort() - - print json.dumps(safe_urls_list, indent=2, separators=(",", ":")) - -if __name__ == "__main__": - GenerateSafeUrls()
diff --git a/tools/perf/profile_creators/profile_safe_url_list.json b/tools/perf/profile_creators/profile_safe_url_list.json deleted file mode 100644 index fb0849f..0000000 --- a/tools/perf/profile_creators/profile_safe_url_list.json +++ /dev/null
@@ -1,3796 +0,0 @@ -[ - "http://abcnews.go.com/", - "http://abcnews.go.com/Health/texas-hospital-welcomes-girl-quintuplets-born-us/story?id=30314322", - "http://abcnews.go.com/blogs/politics/george-stephanopoulos", - "http://about.deviantart.com/", - "http://about.deviantart.com/advertising/", - "http://about.deviantart.com/advertising/adcast", - "http://about.deviantart.com/contact/", - "http://about.deviantart.com/policy/copyright/", - "http://about.deviantart.com/policy/etiquette/", - "http://about.deviantart.com/policy/privacy/", - "http://about.deviantart.com/policy/service/", - "http://academia.stackexchange.com/questions/43469/how-serious-should-i-regard-the-compliments-in-an-email-denying-my-application", - "http://academia.stackexchange.com/questions/43565/consistent-programming-language-for-computation-mathematica-python-matlab", - "http://ad.doubleclick.net/ddm/clk/285991468;111620318;k", - "http://ad.doubleclick.net/ddm/clk/285992548;112853330;n", - "http://adbravo.deviantart.com/", - "http://adinfo.aol.com/about-our-ads/", - "http://advertising.aol.com/brands/huffington-post", - "http://advertising.dailymotion.com/", - "http://advertising.yandex.ru/?from=main_bottom", - "http://advertising.yandex.ru/welcome/?from=maintest_ru_razmestitrekl", - "http://ajgiel.deviantart.com/", - "http://ajgiel.deviantart.com/art/King-of-the-North-523308495", - "http://alderion-al.deviantart.com/", - "http://alderion-al.deviantart.com/art/Puppet-Zelda-514215697", - "http://alexdeb.deviantart.com/", - "http://amazonlocal.com/", - "http://amukauroy.deviantart.com/art/Pokemon-One-Up-d-178954047", - "http://andikapatrya.deviantart.com/art/Is-this-Love-105384621", - "http://andrew-robinson.deviantart.com/art/King-Pin-280401033", - "http://arvalis.deviantart.com/art/Kyogre-526534240", - "http://auranapse.deviantart.com", - "http://auranapse.deviantart.com?connect", - "http://autos.yahoo.com/news/ford-patent-11-speed-automatic-transmission-wars-escalate-150000430.html", - "http://aws.amazon.com/what-is-cloud-computing/?sc_channel=EL&sc_campaign=amazonfooter", - "http://baseball.fantasysports.yahoo.com/b1", - "http://bconklin.deviantart.com/", - "http://bigcharts.marketwatch.com/", - "http://bikeaddiction.deviantart.com", - "http://bikeaddiction.deviantart.com?connect", - "http://bleacherreport.com", - "http://bleacherreport.com/?utm_source=cnn.com&utm_medium=referral&utm_campaign=editorial", - "http://bleacherreport.com/articles/2421374-the-zidane-clan-can-zinedines-four-sons-make-the-grade-at-real-madrid?utm_source=cnn.com&utm_medium=referral&utm_campaign=cnn-sports-bin", - "http://bleacherreport.com/articles/2429164-matt-miller-and-chris-simms-reveal-their-biggest-2015-nfl-draft-sleepers?utm_source=cnn.com&utm_medium=referral&utm_campaign=cnn-sports-bin", - "http://bleacherreport.com/articles/2429164-matt-miller-and-chris-simms-reveal-their-biggest-2015-nfl-draft-sleepers?utm_source=cnn.com&utm_medium=referral&utm_campaign=editorial", - "http://bleacherreport.com/articles/2429456-watch-65-200-pound-8th-graders-jaw-dropping-megatron-like-highlight-tape?utm_source=cnn.com&utm_medium=referral&utm_campaign=cnn-sports-bin", - "http://bleacherreport.com/articles/2429504-tom-brady-bounces-1st-pitch-at-red-sox-game?utm_source=cnn.com&utm_medium=referral&utm_campaign=editorial", - "http://bleacherreport.com/articles/2429905-how-much-should-jon-lesters-slow-start-to-2015-worry-the-cubs?utm_source=cnn.com&utm_medium=referral&utm_campaign=cnn-sports-bin", - "http://bleacherreport.com/articles/2430134-golfer-in-australia-bitten-by-a-crocodile-while-looking-for-ball-in-the-water?utm_source=cnn.com&utm_medium=referral&utm_campaign=cnn-sports-bin", - "http://bleacherreport.com/articles/2430363-lebron-james-stephen-curry-headline-list-of-2015s-most-popular-nba-jerseys?utm_source=cnn.com&utm_medium=referral&utm_campaign=editorial", - "http://bleacherreport.com/articles/2430547-western-kentucky-swim-team-suspended-5-years-after-hazing-allegations?utm_source=cnn.com&utm_medium=referral&utm_campaign=editorial", - "http://blender.stackexchange.com/questions/28473/how-to-avoid-particle-data-being-stored-in-blend-file-to-make-it-smaller", - "http://blog.dailymotion.com/en", - "http://blog.foreignpolicy.com/", - "http://blog.stackoverflow.com", - "http://blog.stackoverflow.com/2009/06/attribution-required/", - "http://blog.stackoverflow.com?blb=1", - "http://blog.yandex.ru", - "http://bloggingheads.tv/", - "http://blogs.reuters.com/felix-salmon/", - "http://blogs.reuters.com/jackshafer/", - "http://blogs.rollcall.com/white-house/marco-rubios-opening-speech-goof/", - "http://blogs.wsj.com/?mod=WSJ_formfactor", - "http://blogs.wsj.com/briefly/2015/04/14/5-great-quotes-for-tax-day/?mod=WSJ_hpp_sections_yourmoney", - "http://blogs.wsj.com/briefly/2015/04/14/nokia-alcatel-dial-up-potential-40-billion-merger-at-a-glance/", - "http://blogs.wsj.com/cfo/2015/04/13/cost-of-finance-teams-heading-lower-accenture/?mod=WSJ_hpp_sections_cfo", - "http://blogs.wsj.com/cfo/2015/04/14/corporate-pension-funds-pile-into-bonds/?mod=WSJ_hpp_sections_cfo", - "http://blogs.wsj.com/cfo/2015/04/14/proxy-proposals-call-for-social-responsibility-and-lobbying-disclosures/?mod=WSJ_hpp_sections_cfo", - "http://blogs.wsj.com/cio/2015/04/14/nokia-alcatel-lucent-talks-follow-networking-shift-to-software/?mod=WSJ_hpp_sections_cio", - "http://blogs.wsj.com/cio/2015/04/14/nokias-alcatel-lucent-deal-could-reshape-sdn-market/?mod=WSJ_hpp_sections_cio", - "http://blogs.wsj.com/cio/2015/04/14/state-street-draws-on-neuroscience-for-financial-systems-analytics-project/?mod=WSJ_hpp_sections_cio", - "http://blogs.wsj.com/dailyfix/2015/04/14/atletico-madrid-vs-real-madrid-live-blog/?mod=WSJ_hpp_MIDDLENexttoWhatsNewsForth", - "http://blogs.wsj.com/digits/2015/04/14/cannabis-delivery-service-eaze-raises-10-million-to-expand/?mod=WSJ_hpp_sections_tech", - "http://blogs.wsj.com/economics/2015/04/14/imf-euro-depreciation-will-restrain-the-u-s-and-china-for-years/", - "http://blogs.wsj.com/economics/2015/04/14/supply-or-demand-the-imf-breaks-down-the-collapse-of-oil-prices/", - "http://blogs.wsj.com/expat/2015/04/13/for-expats-spice-is-the-spice-of-life/?mod=WSJ_hpp_sections_lifestyle", - "http://blogs.wsj.com/experts/2015/04/14/six-financial-issues-expats-need-to-know-before-accepting-an-assignment/", - "http://blogs.wsj.com/experts/2015/04/14/what-a-paper-route-taught-me-about-business/", - "http://blogs.wsj.com/metropolis/2015/04/14/nypd-collars-coyote-in-manhattan/?mod=WSJ_hpp_sections_newyork", - "http://blogs.wsj.com/moneybeat/?mod=WSJ_hpp_marketdata", - "http://blogs.wsj.com/pharmalot/2015/04/13/former-execs-charged-with-securities-fraud-at-device-maker-bought-by-jj/?mod=WSJ_hpp_sections_health", - "http://blogs.wsj.com/riskandcompliance/2015/04/14/corruption-currents-oregon-bank-drops-marijuana-clients/?mod=WSJ_hpp_sections_riskcompliance", - "http://blogs.wsj.com/riskandcompliance/2015/04/14/crisis-of-the-week-ice-cream-recall-snags-blue-bell/?mod=WSJ_hpp_sections_riskcompliance", - "http://blogs.wsj.com/riskandcompliance/2015/04/14/u-s-official-cites-critical-need-for-criminal-prosecutions/?mod=WSJ_hpp_sections_riskcompliance", - "http://blogs.wsj.com/speakeasy/2015/04/14/rb-pioneer-percy-sledge-dies-at-73/?mod=WSJ_hp_EditorsPicks", - "http://blogs.wsj.com/totalreturn/2015/04/14/if-you-made-a-mistake-on-your-taxes/?mod=WSJ_hpp_sections_yourmoney", - "http://blogs.wsj.com/washwire/2015/04/14/capital-journal-rubio-rejects-leaders-and-ideas-of-the-past-russia-lifts-iran-missile-ban-whats-in-a-logo-how-2016-designs-stack-up/", - "http://boingboing.net/", - "http://bootslof.deviantart.com/art/Kingpin-217309024", - "http://boredwithmodesty.deviantart.com/art/Kiss-40752557", - "http://buzzmachine.com/", - "http://bymyimagination.deviantart.com", - "http://bymyimagination.deviantart.com?connect", - "http://cache.baiducontent.com/c?m=9d78d513d9831afe0ff9d33e53198d205f1697624fcacd432485d55f93130a1d5a26b8ea70&p=84759a46d6c51ef40be2963f5f079c&newp=89769a4786cc42af5ebaca2f584181231610db2151d2d51f&user=baidu&fm=sc&query=rice&qid=b8b471d5000008a5&p1=10", - "http://cache.baiducontent.com/c?m=9d78d513d9831afe0ff9d33e53198d205f1697624fcacd503a918448e43f0a1a1735f4bb50734d5bce85273656b2&p=84759a46d6c31ef40be2963f5f079c&newp=89769a4786cc42af58baca2f584181231610db2151d4d415&user=baidu&fm=sc&query=rice&qid=b8b471d5000008a5&p1=9", - "http://cache.baiducontent.com/c?m=9d78d513d9921cea4caad420024c91205b43811021ca864e2e928448e43d0c18103ab4fd302267558e9a61305db21801af&p=c467c54ad5c447e80ab4d12d02149d&newp=8b2a97379e8711a05bea923f5c4a81231610db2151d0d41f0d9cd7&user=baidu&fm=sc&query=cow&qid=f537508b0000092e&p1=9", - "http://cache.baiducontent.com/c?m=9d78d513d9921cea4caad420024c91205b43811021ca874968d4e40dc83d00031030b8e830226759939061225af612419bad73&p=8e67c64ad48310ff57ee957f150e8e&newp=937cc815d9c040ae12be9b7c464bcf231610db2151d4d51435&user=baidu&fm=sc&query=cow&qid=f537508b0000092e&p1=8", - "http://cache.baiducontent.com/c?m=9d78d513d9921cea4caad420024c91205b43811021ca95503ac3933fc82f080a1471e3cc767f4f19919e202552f45414b0ab6a216b1e22aa9ccc95&p=882a9642d09812a05ab8c535594da5&newp=916fdc5986cc42a85ea5c7710f448a231610db2151d6db1337&user=baidu&fm=sc&query=cow&qid=f537508b0000092e&p1=10", - "http://cache.baiducontent.com/c?m=9d78d513d9921cea4caad420024c91205b43811021ca95503ac3933fcb324c413037bee43a604b589196277a02ae4357fdf04071360526bc8cc8ff109be4cc&p=8d7ac20293904ead46bd9b7d0d178d&newp=97769a4786cc42af59f68c12455ec1231610db2151d3d710&user=baidu&fm=sc&query=cow&qid=f537508b0000092e&p1=4", - "http://cache.baiducontent.com/c?m=9f65cb4a8c8507ed4fece76310408c375f438014668f87492a8ac809c9735b36163bbca6623f415996d1393a41f9460db7b5&p=882a9644d1971af910b6c7710f4cc9&newp=882a9644d18c1bfa4bafc7710f50c9231610db2151d6d112308ec65bd1&user=baidu&fm=sc&query=cow&qid=f537508b0000092e&p1=7", - "http://cache.baiducontent.com/c?m=9f65cb4a8c8507ed4fece76310408c375f4380146d8bcd442291870dce240d4e163ba6&p=8b2a9701828211a05beb94625c7ac4&newp=8b2a9753948b57ff57ee927e135586231610db2151d0db116996db5e&user=baidu&fm=sc&query=cow&qid=f537508b0000092e&p1=6", - "http://cache.baiducontent.com/c?m=9f65cb4a8c8507ed4fece76310418b711923c538658c9242298fc05f93130601127ba6e07e790d6488942b7344f2090ae5b06d2360&p=806fcf1485cc43e610bd9b7d0f129f&newp=926adf16d9c109ff57ee967a1649bb231611d63f6fbad11137&user=baidu&fm=sc&query=rice&qid=b8b471d5000008a5&p1=5", - "http://cache.baiducontent.com/c?m=9f65cb4a8c8507ed4fece763105392230e54f723678687027fa3c41ed4794f041a26b5b467794153&p=806fcf1485cc43e610bd9b7d0c179f&newp=926adf16d9c109ff57ee957f1649bb231610db2151d6d51437&user=baidu&fm=sc&query=rice&qid=b8b471d5000008a5&p1=3", - "http://cache.baiducontent.com/c?m=9f65cb4a8c8507ed4fece763105392230e54f7386d8c804668d4e419ce3b46101a23feaf627f5052dc942122&p=8549d51785cc43f908e2977e070c86&newp=aa3bc54ad5c34bf70fabc7710f478b231610db2151dd884239&user=baidu&fm=sc&query=cow&qid=f537508b0000092e&p1=3", - "http://calvinhollywood.deviantart.com/", - "http://canuckgurl22.deviantart.com/art/The-Kiss-98404598", - "http://celebrity.yahoo.com/blogs/celeb-news/kimora-lee-simmons-gives-birth-boy-203354029.html", - "http://chat.deviantart.com/", - "http://chat.stackoverflow.com", - "http://chemistry.stackexchange.com/questions/28702/how-come-there-arent-any-silicon-analogs-of-alkenes-or-alkynes", - "http://christiannauck.deviantart.com/art/Daredevil-roof-jump-134553438", - "http://christopherpollari.deviantart.com/", - "http://classifieds.wsj.com?mod=WSJ_footer", - "http://classroom.wsj.com/", - "http://clsa.deviantart.com/art/Bullseye-131165042", - "http://cn.wsj.com/gb/index.asp", - "http://cnn.it/go", - "http://cnnnewsource.com", - "http://codereview.stackexchange.com/questions/86895/checking-validity-of-nxn-sudoku", - "http://company.yandex.com/", - "http://company.yandex.ru", - "http://creativecommons.org/licenses/by-sa/3.0/", - "http://criticalrobotboy.deviantart.com/art/Enderdragon-Logo-526806276", - "http://critiques.deviantart.com", - "http://crooksandliars.com/", - "http://dailycaller.com/", - "http://dailykos.com/", - "http://dailylitrecognition.deviantart.com/", - "http://dailylitrecognition.deviantart.com/journal/Daily-Lit-Recognition-for-April-13th-2015-526578496", - "http://dailylitrecognition.deviantart.com/journal/Daily-Lit-Recognition-for-April-14-2015-526808625", - "http://dailynews.yahoo.co.jp/fc/domestic/air_crash/?id=6156593", - "http://dailynews.yahoo.co.jp/fc/domestic/defence_policy/?id=6156606", - "http://dailynews.yahoo.co.jp/fc/domestic/volcanoes/?id=6156604", - "http://dailynews.yahoo.co.jp/fc/economy/bankruptcy/?id=6156598", - "http://dailynews.yahoo.co.jp/fc/entertainment/broad_casting/?id=6156600", - "http://dailynews.yahoo.co.jp/fc/local/hiroshima/?id=6156609", - "http://dailynews.yahoo.co.jp/fc/sports/aoki_norichika/?id=6156607", - "http://dailynews.yahoo.co.jp/fc/sports/vahid_halilhodzic/?id=6156610", - "http://danluvisiart.deviantart.com/art/REDEMPTION-FREEFALL-525627886", - "http://daringfireball.net/", - "http://data.stackexchange.com", - "http://dav-19.deviantart.com/art/Cherep-526720215", - "http://declanshalvey.deviantart.com/art/PUISHER-V-DAREDEVIL-colour-183351045", - "http://deevelliott.deviantart.com/", - "http://deevelliott.deviantart.com/favourites/63948030/Daredevil", - "http://depthradius.deviantart.com/gallery/51277529/Zeitgeist", - "http://depthradius.deviantart.com/gallery/51442382/Collections", - "http://developer.dailymotion.com", - "http://developer.dailymotion.com/documentation#graph-api", - "http://developer.dailymotion.com/documentation#player-api", - "http://deviantart.theresumator.com/apply/", - "http://digbysblog.blogspot.com/", - "http://digital-art-fantasy.deviantart.com/", - "http://digital-art-fantasy.deviantart.com/journal/NEW-CONTEST-526844932", - "http://dish.andrewsullivan.com/", - "http://dj.wsj.com/hub?mod=WSJ_Hat", - "http://dj.wsj.com/rt/pages/dash?mod=ProdX_MktgHub", - "http://djx.wsj.com?mod=ProdX_MktgHub", - "http://dkfktl1004.deviantart.com/", - "http://dkfktl1004.deviantart.com/art/errand-444620756", - "http://drudgereport.com/", - "http://elections.huffingtonpost.com/", - "http://elections.huffingtonpost.com/pollster", - "http://electronics.stackexchange.com/questions/164705/mains-voltage-on-strip-board", - "http://ell.stackexchange.com/questions/54733/what-are-some-polite-ways-to-address-a-group-in-a-forum-post", - "http://english.stackexchange.com/questions/238824/is-there-a-word-that-means-cheating-but-legitimate", - "http://english.stackexchange.com/questions/239208/when-did-more-tea-vicar-start-to-be-used-after-farting-where-did-it-come-fro", - "http://enigma-fotos.deviantart.com/art/Myranda-526722461", - "http://everything.yahoo.com/", - "http://feedback.yahoo.com/forums/206380-us-homepage", - "http://feedback2.yandex.ru/default/", - "http://finance.yahoo.com", - "http://finance.yahoo.com/", - "http://finance.yahoo.com/news/heres-budget-family-feels-theyve-160000283.html", - "http://finance.yahoo.com/q?s=^DJI", - "http://finance.yahoo.com/q?s=^GSPC", - "http://finance.yahoo.com/q?s=^IXIC", - "http://firedoglake.com/", - "http://fivethirtyeight.com/", - "http://fivethirtyeight.com/contributors/nate-silver/", - "http://football.fantasysports.yahoo.com/?ovchn=YAH&ovcpn=Front+Page&ovcrn=Front+page+P+Link+Nav+button&ovrfd=YAH&ovtac=AD", - "http://forum.deviantart.com/", - "http://fotki.yandex.ru/", - "http://foxied3.deviantart.com", - "http://foxied3.deviantart.com?connect", - "http://freebeacon.com/", - "http://fresh.amazon.com", - "http://fucking2princess.deviantart.com/art/I-need-a-kiss-32314312", - "http://games.dailymotion.com", - "http://globalvoicesonline.org/", - "http://gma.yahoo.com/rita-wilson-breast-cancer-underwent-double-mastectomy-130715475--abc-news-celebrities.html", - "http://go.microsoft.com/?linkid=9844325", - "http://go.microsoft.com/fwlink/?LinkID=246338&CLCID=0409", - "http://go.microsoft.com/fwlink/?LinkID=286759&CLCID=409", - "http://go.microsoft.com/fwlink/?LinkId=248686&CLCID=0409", - "http://gothamist.com/", - "http://graphics.wsj.com/2016-candidate-tracker/", - "http://graphics.wsj.com/quarterly-bank-earnings/", - "http://groups.deviantart.com", - "http://guzeetia.deviantart.com/art/art-kiss-102427677", - "http://headlines.yahoo.co.jp/hl?a=20150415-00000009-san-l28.view-000", - "http://help.baidu.com/question", - "http://help.deviantart.com/", - "http://help.wsj.com/customer-service/?mod=WSJ_footer", - "http://help.yahoo.com/kb/index?page=content&y=PROD_FRONT&locale=en_US&id=SLN14553", - "http://help.yandex.ru/", - "http://home.yandex.ru/?from=prov_main", - "http://hotlineblog.nationaljournal.com/", - "http://ie8.smoothfusion.com/WallStreetJournal/view.aspx", - "http://image.baidu.com/i?tn=baiduimage&ct=201326592&lm=-1&cl=2&word=rice&&fr=ala&ori_query=rice&ala=0&alatpl=sp&pos=3", - "http://image.baidu.com/i?tn=baiduimage&ct=201326592&lm=-1&cl=2&word=rice&fr=ala&ori_query=rice&ala=0&alatpl=sp&pos=0", - "http://image.baidu.com/i?tn=baiduimage&ps=1&ct=201326592&lm=-1&cl=2&nc=1&ie=utf-8&word=cow", - "http://image.baidu.com/i?tn=baiduimage&ps=1&ct=201326592&lm=-1&cl=2&nc=1&ie=utf-8&word=rice", - "http://indo.wsj.com/home-page?_wsjregion=asia,indo&_homepage=/home/indo", - "http://info.yahoo.com/", - "http://info.yahoo.com/privacy/us/yahoo/relevantads.html", - "http://inhealth.cnn.com/taking-control-of-low-testosterone/boosting-intimacy-when-you-have-low-t?did=t1_rss5", - "http://ireport.cnn.com", - "http://itunes.apple.com/us/app/the-huffington-post/id306621789?mt=8", - "http://itunes.apple.com/us/app/the-wall-street-journal./id364387007?mt=8", - "http://jane-po.deviantart.com/", - "http://janpirnatphoto.deviantart.com/art/Love-84241487", - "http://jeffieb.deviantart.com/art/Daredevil-Batman-165338550", - "http://jnkboy.deviantart.com/", - "http://jnkboy.deviantart.com/art/Doomguy-526592769", - "http://jobs.dailymotion.com/en/home", - "http://jon-lock.deviantart.com/art/Reflect-526904127", - "http://jp.wsj.com/home-page?_wsjregion=asia,jp&_homepage=/home/jp", - "http://jtart876.deviantart.com", - "http://jtart876.deviantart.com?connect", - "http://judaism.stackexchange.com/questions/57330/the-history-of-the-sephardic-chief-rabbis-outfit", - "http://justabreyerdreamer.deviantart.com", - "http://justabreyerdreamer.deviantart.com?connect", - "http://kawacy.deviantart.com/art/Normal-vs-my-shading-526828438", - "http://kaz-d.deviantart.com/", - "http://kdp.amazon.com/", - "http://koloromuj.deviantart.com/", - "http://kr.wsj.com/home-page?_wsjregion=asia,kr&_homepage=/home/kr", - "http://kr0npr1nz.deviantart.com/art/Apple-526648081", - "http://krugman.blogs.nytimes.com/", - "http://l.deviantart.com/", - "http://lisa-lou-who.deviantart.com/art/Custom-Handmade-Harry-Potter-Letterman-Jackets-526868122", - "http://little-pretty.deviantart.com/art/Oh-It-Is-Love-55313318", - "http://live.huffingtonpost.com/", - "http://live.huffingtonpost.com/r/segment/5506f95602a7606fd600061e", - "http://live.huffingtonpost.com/r/segment/5519718702a7606fd6001335", - "http://live.huffingtonpost.com/r/segment/552c06e502a760e8d900061e", - "http://live.huffingtonpost.com/r/segment/552c226402a760eece00060d", - "http://live.huffingtonpost.com/r/segment/552c22da78c90a6c5f0005a0", - "http://live.wsj.com", - "http://live.wsj.com/?category=markets", - "http://live.wsj.com/?category=news hub am", - "http://live.wsj.com/?category=opinion", - "http://m.huffingtonpost.com", - "http://m.imdb.com?ref_=ft_mdot", - "http://m.twitter.com", - "http://maddog197x.deviantart.com/", - "http://maddog197x.deviantart.com/journal/FNAF-Do-You-Wanna-Make-a-Pizza-Parody-526610047", - "http://map.baidu.com", - "http://map.baidu.com/m?word=cow&fr=ps01000", - "http://map.baidu.com/m?word=rice&fr=ps01000", - "http://maps.yandex.ru", - "http://marioluevanos.deviantart.com/", - "http://market.yandex.ru/?clid=505", - "http://market.yandex.ru/?clid=506", - "http://market.yandex.ru/catalog?hid=7812191&clid=514&utm_source=face&utm_medium=cpc&utm_term=shoes&utm_campaign=world", - "http://markets.wsj.com/us", - "http://markets.wsj.com/us?mod=WSJ_hpp_marketdata", - "http://marthig.deviantart.com/", - "http://marthig.deviantart.com/journal/April-May-2015-Happy-Easter-and-Stuff-526302602", - "http://math.stackexchange.com/questions/1233283/why-did-euler-use-e-to-represent-complex-numbers", - "http://mathematica.stackexchange.com/questions/79866/create-a-list-of-rules-built-from-data-set-fields", - "http://maxromanchak.deviantart.com/art/Kingpin-206522937", - "http://mbreitweiser.deviantart.com/art/Daredevil-Yellow-138971835", - "http://mediamatters.org/", - "http://messenger.yahoo.com", - "http://meta.stackoverflow.com", - "http://metrika.yandex.ru/", - "http://minhtrucdiep.deviantart.com", - "http://minhtrucdiep.deviantart.com?connect", - "http://modyrabi3.deviantart.com/", - "http://modyrabi3.deviantart.com/favourites/11305942/kiss", - "http://money.cnn.com", - "http://money.cnn.com/", - "http://money.cnn.com/2015/04/12/technology/game-of-thrones-leaked-episodes/index.html", - "http://money.cnn.com/2015/04/14/pf/college/corinthian-college-fine/index.html", - "http://money.cnn.com/gallery/pf/taxes/2014/04/08/tax-mistakes/", - "http://money.cnn.com/magazines/fortune/", - "http://moonbeam13.deviantart.com/", - "http://moonbeam13.deviantart.com/journal/Celebrating-Deviousness-April-2015-523811377", - "http://moviefone.com", - "http://music.baidu.com/search?fr=ps&ie=utf-8&key=cow", - "http://music.baidu.com/search?fr=ps&ie=utf-8&key=rice", - "http://my.yahoo.com?mkg=015", - "http://naktarra.deviantart.com/", - "http://naktarra.deviantart.com/journal/April-THE-GROOVIEST-LIT-IN-TOWN-VOLUME-THIRTEEN-526576202", - "http://nanomortis.deviantart.com/art/Followers-526688319", - "http://new.dowjones.com/factiva/?link=djcom_factiva_o_hsad2_5jun14", - "http://news.baidu.com", - "http://news.baidu.com/ns?cl=2&rn=20&tn=news&word=cow", - "http://news.baidu.com/ns?cl=2&rn=20&tn=news&word=rice", - "http://news.google.com/", - "http://news.yahoo.co.jp/fc", - "http://news.yahoo.co.jp/list/?d=20150415&mc=f&mp=f", - "http://news.yahoo.com/", - "http://news.yahoo.com/christie-proposing-overhaul-social-security-benefits-131803972--finance.html", - "http://news.yahoo.com/clinton-starts-iowa-campaign-small-town-meetings-072032295--election.html", - "http://news.yahoo.com/comics/dilbert-slideshow/", - "http://news.yahoo.com/former-atlanta-public-school-educators-sentenced-125312564.html", - "http://news.yahoo.com/lightbox/dilbert-slideshow/20150414-dt150414-gif-photo-050305838.html", - "http://news.yahoo.com/marion-marechal-le-pen-poster-girl-french-far-171254622.html", - "http://news.yahoo.com/n-korea-first-lady-appears-public-first-time-034036151.html", - "http://news.yahoo.com/obama-removes-cuba-state-sponsor-terror-list-190658891--politics.html", - "http://news.yahoo.com/pleas-mulled-former-atlanta-educators-test-cheating-scandal-120733406.html", - "http://news.yahoo.com/senate-committee-challenge-obama-vote-iran-bill-072425948--politics.html", - "http://news.yahoo.com/suspect-arrested-florida-deadly-shooting-north-carolina-college-113059552.html", - "http://news.yahoo.com/video/man-kicked-florida-bar-lights-121529294.html", - "http://news.yahoo.com/video/marco-rubio-152011188.html", - "http://news.yandex.ru/yandsearch?cl4url=lenta.ru/news/2015/04/14/osce/&lang=ru&lr=102567", - "http://news.yandex.ru/yandsearch?cl4url=ria.ru/economy/20150414/1058505479.html&lang=ru&lr=102567", - "http://news.yandex.ru/yandsearch?cl4url=ria.ru/science/20150415/1058595666.html&lang=ru&lr=102567", - "http://news.yandex.ru/yandsearch?cl4url=ria.ru/world/20150414/1058574421.html&lang=ru&lr=102567", - "http://news.yandex.ru/yandsearch?cl4url=rusplt.ru/news/pentagon-zayavil-o-nevozmojnosti-ssha-protivostoyat-kiberugrozam-333759.html&lang=ru&lr=102567", - "http://news.yandex.ru/yandsearch?cl4url=sport.rbc.ru/article/254275/&lang=ru&lr=102567", - "http://news.yandex.ru/yandsearch?cl4url=www.gazeta.ru/comments/2015/04/14_e_6638881.shtml&lang=ru&lr=102567", - "http://news.yandex.ru/yandsearch?cl4url=www.ng.ru/news/500284.html&lang=ru&lr=102567", - "http://news.yandex.ru/yandsearch?cl4url=www.rg.ru/2015/04/14/kuba-site-anons.html&lang=ru&lr=102567", - "http://news.yandex.ru/yandsearch?cl4url=www.vz.ru/news/2015/4/15/740016.html&lang=ru&lr=102567", - "http://nunoplati.deviantart.com/art/Elektra-quickie-262134791", - "http://nymag.com/", - "http://nymag.com/author/jonathan%20chait/", - "http://odetoempyrean.deviantart.com/", - "http://offers.lendingtree.com/splitter/splitter.ashx?id=CNN_Article_Credit2&800num=hide&siteid=credit&hpt=hp_bn17", - "http://offers.lendingtree.com/splitter/splitter.ashx?id=CNN_Article_Personal3&hpt=hp_bn17", - "http://offers.lendingtree.com/splitter/splitter.ashx?id=CNN_Article_Refi1&800num=hide&siteid=seetodays&hpt=hp_bn17", - "http://offers.lendingtree.com/splitter/splitter.ashx?id=RefisavingsJDT1", - "http://offers.lendingtree.com/splitter/splitter.ashx?id=cnn-homepage", - "http://office.com/start/default.aspx?WT.mc_id=O16_BingHP", - "http://official.dailymotion.com", - "http://oilprice.com/", - "http://oneforthetable.com/", - "http://online.barrons.com/?mod=ProdX_MktgHub", - "http://online.barrons.com/home", - "http://online.wsj.com", - "http://online.wsj.com/10point", - "http://online.wsj.com/?mod=WSJDE_footer", - "http://online.wsj.com/article/SB10001424052702303754904577531431270923056.html", - "http://online.wsj.com/article/SB12202959562200624841004580578553193939656.html?mod=WSJ_hpp_PhotosModule_2", - "http://online.wsj.com/article/SB12202959562200624841004580580721622231574.html?mod=WSJ_hpp_PhotosModule_1", - "http://online.wsj.com/conferences?mod=WSJ_footer", - "http://online.wsj.com/home-page", - "http://online.wsj.com/news/column/Corrections?mod=WSJ_footer", - "http://online.wsj.com/news/politics", - "http://online.wsj.com/public/page/classified-search.html", - "http://online.wsj.com/public/page/email-setup.html?sub=capital_journal_daybreak&mod=WSJHomeCapitalJournalDaybreak", - "http://online.wsj.com/public/page/email-setup.html?sub=the_10_point&mod=WSJHome10Point", - "http://online.wsj.com/public/page/news-lifestyle-arts-entertainment.html", - "http://online.wsj.com/public/page/news-opinion-commentary.html", - "http://online.wsj.com/public/page/news-real-estate-homes.html", - "http://online.wsj.com/public/page/peggy-noonan.html", - "http://online.wsj.com/public/page/podcast.html?mod=WSJ_footer", - "http://online.wsj.com/public/page/rss_news_and_feeds.html?mod=WSJ_footer", - "http://online.wsj.com/public/search?article-doc-type=%7BThe+10-Point%7D&HEADER_TEXT=the+10-point", - "http://onlinehelp.microsoft.com/en-US/bing/ff808535.aspx", - "http://open.baidu.com/", - "http://openvod.dailymotion.com", - "http://past1978.deviantart.com/", - "http://peskykid.deviantart.com/art/KINGPIN-379068877", - "http://pevc.dowjones.com/?mod=ProdX_MktgHub", - "http://physics.stackexchange.com/questions/175985/can-we-theoretically-balance-a-perfectly-symmetry-pencil-on-its-one-atom-tip", - "http://picolo-kun.deviantart.com/art/6Teen-526818194", - "http://pix-man.deviantart.com/", - "http://pixiveo.deviantart.com/art/Animated-Girl-Weight-Gain-Expansion-526501668", - "http://poldhannahms.deviantart.com/art/Tender-Kiss-66694744", - "http://politicalwire.com/", - "http://politics.suntimes.com/authors/lsweet", - "http://poll.deviantart.com/439/", - "http://portfolio.deviantart.com", - "http://portfolio.wsj.com?mod=wsj_port_foot", - "http://portfolio.wsj.com?mod=wsj_port_hat", - "http://press.dailymotion.com/us", - "http://privacy.aol.com/", - "http://pro.imdb.com/signup/index.html?rf=cons_ft_hm&ref_=cons_ft_hm", - "http://pro.imdb.com/signup/index.html?rf=cons_nb_hm&ref_=cons_nb_hm", - "http://professor.wsj.com/", - "http://projectporkchop.deviantart.com", - "http://promotion.yahoo.co.jp/event/disney_easter2015/interview/", - "http://psychoheat.deviantart.com/art/Bullseye-6447212", - "http://pubads.g.doubleclick.net/gampad/clk?id=165311666&iu=/2/interactive.wsj.com/default", - "http://pubads.g.doubleclick.net/gampad/clk?id=189483626&iu=/2/interactive.wsj.com/default", - "http://pubads.g.doubleclick.net/gampad/clk?id=196199186&iu=/2", - "http://publisher.dailymotion.com/?l=en", - "http://puzzling.stackexchange.com/questions/12087/poor-dvorak-a-limerick", - "http://qosim.doubleclick.net/cgi-bin/honeypot.pl?client=downjones", - "http://quotes.wsj.com/bond/BX/TMBMKDE-10Y", - "http://quotes.wsj.com/bond/BX/TMBMKES-10Y", - "http://quotes.wsj.com/bond/BX/TMBMKGB-10Y", - "http://quotes.wsj.com/bond/BX/TMBMKIT-10Y", - "http://quotes.wsj.com/bond/BX/TMBMKJP-10Y", - "http://quotes.wsj.com/bond/BX/TMUBMUSD10Y", - "http://quotes.wsj.com/futures/CORN", - "http://quotes.wsj.com/futures/CRUDE OIL - ELECTRONIC", - "http://quotes.wsj.com/futures/DOW JONES INDUSTRIAL FUTURES", - "http://quotes.wsj.com/futures/GOLD", - "http://quotes.wsj.com/futures/S%26P 500 FUTURES", - "http://quotes.wsj.com/futures/SILVER", - "http://quotes.wsj.com/fx/AUDUSD", - "http://quotes.wsj.com/fx/EURUSD", - "http://quotes.wsj.com/fx/GBPUSD", - "http://quotes.wsj.com/fx/USDCHF", - "http://quotes.wsj.com/fx/USDJPY", - "http://quotes.wsj.com/index/CN/SHCOMP", - "http://quotes.wsj.com/index/COMP", - "http://quotes.wsj.com/index/DJI", - "http://quotes.wsj.com/index/DWCF", - "http://quotes.wsj.com/index/DX/DAX", - "http://quotes.wsj.com/index/FR/PX1", - "http://quotes.wsj.com/index/GDOW", - "http://quotes.wsj.com/index/HK/HSI", - "http://quotes.wsj.com/index/IN/1", - "http://quotes.wsj.com/index/JP/NIK", - "http://quotes.wsj.com/index/RUT", - "http://quotes.wsj.com/index/SG/STI", - "http://quotes.wsj.com/index/SPX", - "http://quotes.wsj.com/index/UK/UKX", - "http://quotes.wsj.com/index/XX/ADOW", - "http://quotes.wsj.com/index/XX/BUXX", - "http://quotes.wsj.com/index/XX/FTSEMIB", - "http://quotes.wsj.com/index/XX/IBEX?mod=DNH_S", - "http://quotes.wsj.com/index/XX/SXXP", - "http://rabota.yandex.ru/?from=morda&_openstat=yandex;title;salary;salaryStatall", - "http://rabota.yandex.ru/salary.xml?from=morda&_openstat=yandex;text;salary;salaryStatall", - "http://rashomon707.deviantart.com/art/Kiss-23611807", - "http://rasix-designs.deviantart.com/", - "http://rdsig.yahoo.co.jp/shopping/points/premium/evt=125378/RV=1/RU=aHR0cDovL3RvcGljcy5zaG9wcGluZy55YWhvby5jby5qcC9jYW1wYWlnbi9wb2ludHMvcHJlbWl1bS8_c2NfZT15dHRs", - "http://realty.yandex.ru/?from=morda&_openstat=yandex;title;sell;sell1appAllruru", - "http://realty.yandex.ru/search.xml?type=SELL&category=APARTMENT&roomsTotal=1&from=morda&_openstat=yandex;text;sell;sell1appAllruru", - "http://recommend.yahoo.co.jp/onepiece77/", - "http://redstate.com/", - "http://reiq.deviantart.com/art/Sherry-Patreon-Commish-526710915", - "http://reneaigner.deviantart.com/", - "http://reporting.sunlightfoundation.com/blog/", - "http://rich35211.deviantart.com/", - "http://robertreich.org/", - "http://sakimichan.deviantart.com/art/Harley-Quinn-Caution-nsfw-526774728", - "http://sakuraanxinh.deviantart.com", - "http://sakuraanxinh.deviantart.com?connect", - "http://saphiredesign.deviantart.com/", - "http://scifi.stackexchange.com/questions/86221/was-aragorn-based-on-bard-from-the-hobbit", - "http://scifi.stackexchange.com/questions/86250/what-books-are-shown-on-the-bookshelf-in-interstellar", - "http://scifi.stackexchange.com/questions/86253/looking-for-a-sci-fi-about-life-after-death", - "http://screen.yahoo.com/other-space/episode-1-great-beyond-beyond-070100400.html", - "http://search.yahoo.com/", - "http://search.yahoo.com/local", - "http://seattletimes.nwsource.com/html/home/index.html", - "http://security.stackexchange.com/questions/85963/what-is-the-purpose-of-frequently-rotating-tls-certificates-without-changing-und", - "http://serhatbayram.deviantart.com/art/Kiss-98458361", - "http://services.amazon.com/content/product-ads-on-amazon.htm/ref=footer_pads?ld=AZPADSFooter", - "http://setup1.wsj.com/pznsetup/sub/ksemail/setup.html?mod=WSJ_footer", - "http://setup1.wsj.com/pznsetup/sub/pvemail/setup.html?mod=WSJ_footer", - "http://shine.yahoo.com/horoscope/", - "http://shop.deviantart.com", - "http://shousetsu.deviantart.com/art/A-kiss-67714339", - "http://siriussteve.deviantart.com/art/Hulk-and-Daredevil-458117073", - "http://slovari.yandex.ru/", - "http://spilt-sugar.deviantart.com/art/The-Adorable-Ones-Kiss-104463992", - "http://sports.yahoo.com", - "http://sports.yahoo.com/", - "http://sports.yahoo.com/fantasy", - "http://sports.yahoo.com/mlb/teams/ari", - "http://sports.yahoo.com/mlb/teams/bos", - "http://sports.yahoo.com/mlb/teams/chc", - "http://sports.yahoo.com/mlb/teams/cin", - "http://sports.yahoo.com/mlb/teams/det", - "http://sports.yahoo.com/mlb/teams/laa", - "http://sports.yahoo.com/mlb/teams/lad", - "http://sports.yahoo.com/mlb/teams/pit", - "http://sports.yahoo.com/mlb/teams/sdg", - "http://sports.yahoo.com/mlb/teams/sea", - "http://sports.yahoo.com/mlb/teams/tex", - "http://sports.yahoo.com/mlb/teams/was", - "http://sports.yahoo.com/nba/teams/bos", - "http://sports.yahoo.com/nba/teams/den", - "http://sports.yahoo.com/nba/teams/gsw", - "http://sports.yahoo.com/nba/teams/ind", - "http://sports.yahoo.com/nba/teams/lac", - "http://sports.yahoo.com/nba/teams/mem", - "http://sports.yahoo.com/nba/teams/pho", - "http://sports.yahoo.com/nba/teams/tor", - "http://sports.yahoo.com/nba/teams/was", - "http://sports.yahoo.com/news/clippers-eke-6th-straight-win-110-103-over-053647163--nba.html", - "http://sports.yahoo.com/news/clippers-suns-preview-135440723--nba.html", - "http://sports.yahoo.com/news/dodgers-beat-mariners-6-5-10-innings-053526333--mlb.html", - "http://sports.yahoo.com/news/inciartes-career-high-4-rbis-help-d-backs-051830505--mlb.html", - "http://sports.yahoo.com/news/klay-thompson-scores-42-warriors-down-memphis-111-050505414--nba.html", - "http://sports.yahoo.com/news/nationals-red-sox-preview-012751752--mlb.html", - "http://sports.yahoo.com/news/raptors-celtics-preview-135440146--nba.html", - "http://sports.yahoo.com/news/reds-cubs-preview-135234539--mlb.html", - "http://sports.yahoo.com/news/tigers-pirates-preview-135131838--mlb.html", - "http://sports.yahoo.com/news/wizards-pacers-preview-135440877--nba.html", - "http://sports.yahoo.com/photos/10-most-popular-nba-teams-according-to-merchandise-sales-1429031016-slideshow/", - "http://sta.sh", - "http://sta.sh/0173o5y7gti6", - "http://sta.sh/muro", - "http://sta.sh/muro/", - "http://sta.sh/writer", - "http://stackexchange.com/legal", - "http://stackexchange.com/legal/privacy-policy", - "http://stackexchange.com/mediakit", - "http://stackexchange.com/sites#culturerecreation", - "http://stackexchange.com/sites#lifearts", - "http://stackexchange.com/sites#science", - "http://stackexchange.com/sites#technology", - "http://stackexchange.com/work-here", - "http://status.twitter.com", - "http://subscription.wsj.com/", - "http://superuser.com/questions/901556/does-increasing-upload-or-download-speed-reduce-ping", - "http://support.twitter.com/articles/14226-how-to-find-your-twitter-short-code-or-long-code", - "http://support.twitter.com/forums/26810/entries/78525", - "http://susib.deviantart.com/art/Sunset-Kiss-58122131", - "http://swampland.time.com/", - "http://sweetpeapix.deviantart.com/art/First-Kiss-49646473", - "http://techgnotic.deviantart.com/", - "http://techgnotic.deviantart.com/art/Today-s-Headlines-From-The-News-Desk-4-14-15-526757199", - "http://techgnotic.deviantart.com/art/Today-s-Headlines-From-The-News-Desk-4-14-15-526757199#Destiny-Expansion-Trailer", - "http://techgnotic.deviantart.com/art/Today-s-Headlines-From-The-News-Desk-4-14-15-526757199#Katee-Sackhoff-To-Create-New-Series", - "http://techgnotic.deviantart.com/art/Today-s-Headlines-From-The-News-Desk-4-14-15-526757199#Olivia-Munn-To-Play-Psylocke", - "http://techgnotic.deviantart.com/art/Today-s-Headlines-From-The-News-Desk-4-14-15-526757199#Photography-Debate", - "http://techgnotic.deviantart.com/art/Today-s-Headlines-From-The-News-Desk-4-14-15-526757199#Scream-Trailer", - "http://techgnotic.deviantart.com/art/Today-s-Headlines-From-The-News-Desk-4-14-15-526757199#Wonder-Woman-Loses-Its-Director", - "http://techgnotic.deviantart.com/journal/Chasing-The-Sun-Solar-Power-Is-The-Next-Big-Thing-526784981", - "http://techgnotic.deviantart.com/journal/Collection-Gnomes-Are-of-the-Earth-524480804", - "http://techgnotic.deviantart.com/journal/Collection-Major-League-Baseball-525430006", - "http://techgnotic.deviantart.com/journal/Collection-Mazes-Puzzles-For-The-Truly-Committed-526759351", - "http://techgnotic.deviantart.com/journal/Collection-The-Artist-s-Toolkit-524244375", - "http://techgnotic.deviantart.com/journal/Cosplay-Friday-Mortal-Kombat-525687698", - "http://techgnotic.deviantart.com/journal/Daredevil-Man-Without-Fear-517994215", - "http://techgnotic.deviantart.com/journal/DeviantArt-Road-Trip-Isle-of-Wight-526094317", - "http://techgnotic.deviantart.com/journal/Edward-Gorey-Illustrator-Or-Artist-518419735", - "http://techgnotic.deviantart.com/journal/Fan-Art-Friday-Gargoyles-525639001", - "http://techgnotic.deviantart.com/journal/Food-In-Focus-A-Taste-Of-Japan-524467347", - "http://techgnotic.deviantart.com/journal/Furious-7-Have-Car-Chases-Finally-Jumped-The-Shark-513488584", - "http://techgnotic.deviantart.com/journal/Game-of-Thrones-9-Worst-Destinations-In-Westeros-521429710", - "http://techgnotic.deviantart.com/journal/Lightning-Boy-Studio-Pursuing-A-Dream-524555790", - "http://techgnotic.deviantart.com/journal/Margaret-Atwood-Queen-Of-Devious-Ideas-524309809", - "http://techgnotic.deviantart.com/journal/Project-Porkchop-Vol-364-525892839", - "http://techgnotic.deviantart.com/journal/The-Battle-For-Breakfast-Is-Fought-With-Ads-524255897", - "http://techgnotic.deviantart.com/journal/The-Power-Of-Tomorrow-Tesla-Develops-Future-Tech-524494920", - "http://techgnotic.deviantart.com/journal/The-Procrastinator-A-Day-In-The-Life-526043463", - "http://techgnotic.deviantart.com/journal/The-Written-Revolution-Interviews-On-Writing-510605539", - "http://techgnotic.deviantart.com/journal/Watch-The-Throne-S5-E1-The-Wars-To-Come-526718761", - "http://tex.stackexchange.com/questions/238503/tip-on-how-to-make-a-visually-good-table", - "http://thehill.com/", - "http://themoderatevoice.com/", - "http://theweek.com/speedreads/549552/construction-worker-accidentally-discovers-1000yearold-hideout", - "http://thinkprogress.org/", - "http://thinkprogress.org/justice/2015/04/14/3646567/no-go-zones-nra-convention/", - "http://thrive.huffingtonpost.com/events/", - "http://thrive.huffingtonpost.com/news/", - "http://tieba.baidu.com", - "http://tieba.baidu.com/f?kw=cow&fr=wwwt", - "http://tieba.baidu.com/f?kw=rice&fr=ps0bt&ie=utf-8", - "http://tieba.baidu.com/f?kw=rice&fr=wwwt", - "http://time.yandex.ru", - "http://tintinspartan.deviantart.com/", - "http://tonytorrid.deviantart.com/art/Elektra-Assassin-WIP-179330968", - "http://topics.nytimes.com/top/opinion/editorialsandoped/oped/columnists/davidbrooks/index.html", - "http://topics.nytimes.com/top/opinion/editorialsandoped/oped/columnists/rossdouthat/", - "http://topics.wsj.com/?mod=WSJ_footer", - "http://translate.yandex.ru/", - "http://tune.yandex.ru", - "http://tune.yandex.ru/?retpath=http%3A%2F%2Fwww.yandex.ru%2F%3Fdomredir%3D1", - "http://tune.yandex.ru/region/?retpath=http%3A%2F%2Fwww.yandex.ru%2F%3Fdomredir%3D1", - "http://tv.yahoo.com/news/tom-brokaw-breaks-silence-brian-williams-really-really-180431228.html", - "http://twitter.com/WSJ", - "http://twpictures.deviantart.com/", - "http://uncannyknack.deviantart.com/", - "http://unix.stackexchange.com/questions/196135/problems-when-trying-to-execute-sh-file-from-another-sh-file", - "http://unix.stackexchange.com/questions/196227/using-the-variable-file-obtained-from-for-file-in-and-pass-to-another-scri", - "http://unkopierbar.deviantart.com/", - "http://unkopierbar.deviantart.com/journal/Light-Hunters-Feature-108-526680866", - "http://v.baidu.com", - "http://v.baidu.com/v?ct=301989888&rn=20&pn=0&db=0&s=25&ie=utf-8&word=cow", - "http://v.baidu.com/v?ct=301989888&rn=20&pn=0&db=0&s=25&ie=utf-8&word=rice", - "http://vaxzone.deviantart.com/art/League-of-Legends-Get-Jinxed-526191916", - "http://videos.huffingtonpost.com/world", - "http://voces.huffingtonpost.com/", - "http://wallpaper.deviantart.com/?q=", - "http://web-trunk-qa.youtube.com/test_languages?prepare_for_screenshotting=1", - "http://welcome.deviantart.com", - "http://welcome.deviantart.com/", - "http://wenku.baidu.com/search?word=cow&lm=0&od=0&ie=utf-8", - "http://wenku.baidu.com/search?word=rice&lm=0&od=0&ie=utf-8", - "http://whitneychristine.deviantart.com/art/kiss-52986647", - "http://widgets.yandex.ru?consumer=www", - "http://wolftamer358.deviantart.com", - "http://wolftamer358.deviantart.com?connect", - "http://wonkette.com/", - "http://worldbuilding.stackexchange.com/questions/14254/how-would-a-post-planetary-civilization-measure-time", - "http://worldbuilding.stackexchange.com/questions/14300/how-can-i-explain-a-planet-with-perpetual-rain", - "http://wsj.com/partner/?mod=WSJ_footer", - "http://wsj.com/worldstream", - "http://wsjstudent.com/", - "http://www.6pm.com/", - "http://www.GlobalPost.com", - "http://www.abebooks.com/", - "http://www.accesshollywood.com", - "http://www.actionamerica.com/", - "http://www.acx.com", - "http://www.afterschool.com/", - "http://www.alexa.com/", - "http://www.aljazeera.com/", - "http://www.amazon.ca/", - "http://www.amazon.cn/", - "http://www.amazon.co.jp/", - "http://www.amazon.co.uk/", - "http://www.amazon.com.au", - "http://www.amazon.com.br", - "http://www.amazon.com.mx/", - "http://www.amazon.com/services", - "http://www.amazon.de/", - "http://www.amazon.es/", - "http://www.amazon.fr/", - "http://www.amazon.in/", - "http://www.amazon.it/", - "http://www.amazon.nl/", - "http://www.amazonsupply.com/", - "http://www.americablog.com/", - "http://www.artlebedev.ru", - "http://www.audible.com/", - "http://www.bagnewsnotes.com/", - "http://www.baidu.com/", - "http://www.baidu.com/gaoji/preferences.html", - "http://www.baidu.com/link?url=-M91t8L7rn2kU_un4Mo2wO-p3qp6o5yTofPuHNwv7BRbOttA4-UAH4yAbTAnxkwil3mfSEqFi0EO8-Algv59aq", - "http://www.baidu.com/link?url=0mQV9609slSYX24q8klfO6QNPDS4KRmp7MJ7al3xOZrdcfIwru3UHk0v3x5mu9nEoykWs6q8TCOXwXw5F3VUHbqv6lUkWarNoVv4GulM-T3", - "http://www.baidu.com/link?url=0mQV9609slSYX24q8klfO79QOL1mV2G6YCk5rYUBAz6GIoxmPXR7ny4p4Uhq6V7ceRiP0P1uVXfbgHPgzE4CmtqWmqYq8WSE9mXAzSiSHeW-fYPIbXC7akeB-FaU5qBMHvTGVFWRAaN2Ph4hc7UcIj_Cc2jq7sn5uIeTNNWe-0rgKC81FOSNoj6Iq5n9kJ_r", - "http://www.baidu.com/link?url=0mQV9609slSYX24q8klfO8k5FF1XdSGtfGqb3L12GLb1y4UhOobfEzWxKWkEcxk7BlbxXRWZDowWhEXM5TW3hqrOa1VI9UiMzHXIpwNDwue", - "http://www.baidu.com/link?url=0mQV9609slSYX24q8klfO8k5FF1XdSGtfGqb3L12GLb766FUGGJ2OhZ-8D11ASC9TQ0BK8Q9p6U9KXyrlXEBwkIVMAsAqcZTTLuFmB3u_7qFMGdy5-wJzwJRur09COfMmosC9Z3IqBijpVdcaLR87TgPqm_jMriLMrRCJDcPoAC", - "http://www.baidu.com/link?url=0mQV9609slSYX24q8klfO9xNybEKvMAzqbU-nGEllsXxp1JIL5W3fs_G3LqC40H4plJzvhl6T3e5cLKDl2NJm2fhUckux6aw04dRKrasobDFf_IvWy0Pz3YC8ulaJajFIAq_YBkDFNXCIG0D4GT0cAGIShsMEu11_gcwo3ar3jQcX9TTisjnDVbNEwG3Ra6s-H_STlfLaxbQjPzAFln51_", - "http://www.baidu.com/link?url=0mQV9609slSYX24q8klfOq90QIZJXsV2nOlAbzs0Yp6o6wNTkqIMybfuSet091hc1K86eRWI7DOskzBotzhUDv2T0_MhsKzzLEZHi2teMaa", - "http://www.baidu.com/link?url=0mQV9609slSYX24q8klfOqHEyaLk64jpV8WHABKLhNvkeRCuTEdZV_fdb7VJ_vd43oA9IIvNzkxJ6XOpvvwGqqTfAn8SaUxlSj0aQ2KVUGWG_3Imo847zhsBZ0ATt-36e8k5YiM7r1CmcYtfI2cjpBdguox5ToM2Iqh9D0YbOsbVY-6EifiyiZDySchQcX81", - "http://www.baidu.com/link?url=2PhJ5AqeTnSbSr9XDWFWi_HWyi0bzBf2y5KmcHeVYK105XPDXgrJCmobJITaqdO3", - "http://www.baidu.com/link?url=3hOFcy9XXCTbBiNXtU7Gaf9PSvxUi-Ni25gGeym_GMGppjHQEpHFyEfmgBdDCR1p", - "http://www.baidu.com/link?url=3hOFcy9XXCTbBiNXtU7Gaf9PSvxUi-Ni25gGeym_GMIDgQKIOuJVvz38ek1ORvFwcMokY4LZcyGzdPqhfLy38nc9AcUJiIJG0dsvuAv7U_LNBf13meTPpRNAZTIvpX7kagZ81psl2PW4EKjxzn4D8_", - "http://www.baidu.com/link?url=5uns9UowL1ZepzZm8E26sOL3uJezwjIT3mfcNR7_FPkYt2IbV1UMvsBT_n0hqEjs", - "http://www.baidu.com/link?url=7hk-Iao0WutqX5osf6LjfZ53ONWYZV1lecGvT1HEupLm76juUIY13-Ay61JXIGjcDLd0_YH_ZAGrugaQVTaB0_", - "http://www.baidu.com/link?url=AL-zsBN7Wl1skmBFU4Btrgr_nU66vqigpOhaSI-BDnqO5_eSF4bZxW2wQienf5qC3qm3TleOiLRfYMtRaaPeX-lczbwVge_ILsgx09uo56u", - "http://www.baidu.com/link?url=AL-zsBN7Wl1skmBFU4BtrnNKvYGgVAIGcR5FDxKPWX85tZx7eAYH8XmH9tGks6ZBwX4Eyd2pFlzqaykfluIDGAU1MdZ72W9S7D1pFb23D2VppU6oH5Aoy68wcY6q64R3Pfqlru3eb6QYWLOAULu4DZWxJKymDbEiolqC0RE8c_a", - "http://www.baidu.com/link?url=EVxa_BTrai2lPssN74SEUDpGRvPjETEVq9sOfNk4OLq-UBQP2ZS5oCNtRG-L5HtDpm4oFd39a1JwVno-8c9E5a", - "http://www.baidu.com/link?url=EVxa_BTrai2lPssN74SEUI3M9lF6d30AUrvubL2VO-XL3MUo4WNhUG7AhKAidFq0", - "http://www.baidu.com/link?url=EVxa_BTrai2lPssN74SEUI3M9lF6d30AUrvubL2VO-YWfFzN4oqQccQXSZQIDCI7Tz95VJzKGPeYW-nsCNjuIncJqpMzXZqb4yTj3dPK9I7Icbm_aGzVCYB2uj17-X2bRLuX5DTxsURPqDv_KGvAKq", - "http://www.baidu.com/link?url=E_410vcScg2dOp6vwBY4WLNHpMFVnXDpG6_NgiFwj2FwmGRF3a9I8tKmTHYriXJ4JK4uGv7cjn2kyH_HtwZCNa", - "http://www.baidu.com/link?url=E_410vcScg2dOp6vwBY4WLNHpMFVnXDpG6_NgiFwj2FwmGRF3a9I8tKmTHYriXJ4WHI2qD6oRIrV53OGjxZNc_", - "http://www.baidu.com/link?url=E_410vcScg2dOp6vwBY4WLNHpMFVnXDpG6_NgiFwj2FwmGRF3a9I8tKmTHYriXJ4g7wsaDzyImFypFT5725nuq", - "http://www.baidu.com/link?url=FI5j5ft6lL75AJ3TV3DKS-Fj4QUK_6j-MngMpo3a4pW", - "http://www.baidu.com/link?url=IBoWOqaaEB2q3BbeNvVU5hvYa6S5B8HfbCNMlY9LonGWdIU_9cxkLuz4Z3UFaYaH34MvVrXjipALdHYwr9lUTn0KFCHYCiAyFTcaEtjDYvW", - "http://www.baidu.com/link?url=IyBgTYFahSFX-kHwc44jAhmYGKxY6JdH--kbhyhcWLccG2bm7OoaNzbwX0tct4zOxTMDGamsiosayde438FQeq", - "http://www.baidu.com/link?url=JHCMcSB6vseh77VSTAZ-YqU5KyEOSbCBIZj1WMC4cba", - "http://www.baidu.com/link?url=MiBQS6vM7KZu_dzfdpvtlB4jfCo1J7LNeOPza0gMz6hzxnUxLIgtDHIyL1D1HScDRvTmAOsl0tvrtYMtTGsmHa", - "http://www.baidu.com/link?url=NFE7_4jfpxJ7nvruIvBkmbCk4y6kSJ3aWWvojsASX1efdDQVxfsXoaKlpb9pA2in8GmrHbz2aOXW-ZszEERH6a", - "http://www.baidu.com/link?url=NFE7_4jfpxJ7nvruIvBkmbCk4y6kSJ3aWWvojsASX1go61yAq474lNBuDWlWMcjufjdPq8RwyNoqS2sOJTnwJK", - "http://www.baidu.com/link?url=UCI8DqUdy7_rlCN0vRN8OgO8IXIwwkUX0VOdViCKrurm_sT2o_SeDKhHsOn04OWp", - "http://www.baidu.com/link?url=avDdsoc1OwlkyKfgrInz5KyWHhKEnQ6jWDBH-9mMB9wEhyYrDmlRbGIkUiOJ-ykLq5WviBhmLLOSuyMkxzcuyq", - "http://www.baidu.com/link?url=bx9sWi5WnXjBkUhM5gvOSmz2CbZJ_-OiKdNgZr3udsS", - "http://www.baidu.com/link?url=f8pIyc0EEqRxtjnXi4mBlHJgaWX740RBVpMqsiALfKyXOeeGbMkQTxdMCswYkeh9H5pxo0drsY83Ucp9DkoY5iwf_3OIPPvl852Vdy9l34eEPzSdmL2HOM-hpLtFItO-pFh0YQExVbi_tDiTXcWrMEIxvEwOYgNOf4UoyLemN45k5YsQZOE5MI0keCmdXYcS_Q97aQq-LofBjDGgvJmj8K", - "http://www.baidu.com/link?url=f8pIyc0EEqRxtjnXi4mBlJFtLD-21u4Jd-cb0WmmjNCGe3la0qEQJzGnp3O_75ZNbn_kW5YJU4g0xqrla1n3boVyqmwjDGR-Mg_L1e3X92q", - "http://www.baidu.com/link?url=hMgPFqAn_EueXnigQ4nGVGqkcyhhVJzKjKHP5hl52rroccqSxUtaE7t0u5yl_Ero", - "http://www.baidu.com/link?url=nV4HENY9ckVeSVWwFshKgaY3DvOnJrVd_g_0qMg-UUM9GcmCeqxG96TLk-X5jzWFJfhE82mQTApIiYKXF1VUbk_jTcDmMJkInnaHgl86ZSDhXkkZabhN5wh7BDJc7FEWtWM1Ud1pWKfIQ0mLfbE57zV4vbzuiwdyRHJQ7DWtcti", - "http://www.baidu.com/link?url=nV4HENY9ckVeSVWwFshKgaY3DvOnJrVd_g_0qMg-UUM9GcmCeqxG96TLk-X5jzWFhsp5fJQ91LvyGlZG-76XyedyYEgtdpilkS7ymmWpLVl1gMQ_JWi4BBdIvKo0t2AL3P7O5NOjZD9qPUVSOTvglyNfYK81dItwR5Wdr0nczt2qXnuSEUsigTyqhFtr_6d_", - "http://www.baidu.com/link?url=nV4HENY9ckVeSVWwFshKgaY3DvOnJrVd_g_0qMg-UUM9GcmCeqxG96TLk-X5jzWFo_dukZSLbCUI0tPBqr1qG7pe_TKOnSfE4H5bpvZoe-QA3HFsgJEQJJbsJM4zGUOWuXwyrNp5oYXFzTA3EubYQf8TVFst68NRj_XBQXcKmyK", - "http://www.baidu.com/link?url=suRUK_eZMGFmYicXQcmxdjOadwrLx9aoyZ8JcEqZrvSCQZsEMz8ykdB_vK28_zoI9dEGJ_EAOn7DEA2wOffDkn6mPhg5MN6w3PONfoJ6j897u1f6CbMgnXP4bY3KAqR7mg-IbbgQUi8__eNXve0t2nFea82VD1gUjSg9YkLRP4G", - "http://www.baidu.com/link?url=uVssCQzZkZf1-DfdOQaCTaMJ3SpQllS4sYslfxi6_IlpNUbdcI-_HmKrZzqqU7RpzI9kNRm2dTTaUWzDvTajpCylp5VKUYx1sL86wiKNfNXhzvsIh98Ez0shhxxkCUck3AQ4W61KIilalRK8ckmYIOq5c7dtbFrh1rCcjRYlYUq", - "http://www.baidu.com/link?url=uVssCQzZkZf1-DfdOQaCTihM5xvFvedBLokDBjxVKVAoUKsFuApGSFObcyiy2bda1_chv_qZzXQtNL9QccQ8bq", - "http://www.baidu.com/link?url=uVssCQzZkZf1-DfdOQaCTihM5xvFvedBLokDBjxVKVAoUKsFuApGSFObcyiy2bdafs3dpkTeQXZy4moBKznKJ_", - "http://www.baidu.com/link?url=uVssCQzZkZf1-DfdOQaCTihM5xvFvedBLokDBjxVKVAoUKsFuApGSFObcyiy2bdah0eaRoqUnf-k_W3pu9kA9K", - "http://www.baidu.com/link?url=uVssCQzZkZf1-DfdOQaCTihM5xvFvedBLokDBjxVKVAoUKsFuApGSFObcyiy2bdanqj3TkivteOVWzlHY5eeo_", - "http://www.baidu.com/link?url=uVssCQzZkZf1-DfdOQaCTihM5xvFvedBLokDBjxVKVAoUKsFuApGSFObcyiy2bdaoJt5NgTDOX5So9Cee1kIO_", - "http://www.baidu.com/link?url=uVssCQzZkZf1-DfdOQaCTihM5xvFvedBLokDBjxVKVAoUKsFuApGSFObcyiy2bdawPu6E_vc9wVWxzA4mfpGna", - "http://www.baidu.com/link?url=uVssCQzZkZf1-DfdOQaCTknerArVcL26zMlNQrlYOwi", - "http://www.baidu.com/link?url=xIVPE7l3aIThwsbTHHUhIO_jc890BBOkQnDcd7ivNnZKOihdfpF4ZNHKcHdiVvVA", - "http://www.baidu.com/link?url=zEqHe_131latzXbpoiWEUdRKz89U8vSYQ4Juku48s37gUI2VVATwH9m-ohQUlQEh", - "http://www.baidu.com/more/", - "http://www.baidu.com/s?usm=1&wd=%E4%B8%AD%E5%BC%8F%E8%8B%B1%E8%AF%AD&ie=utf-8&rsv_cq=cow&rsv_dl=0_right_recommends_merge_20826&cq=cow&srcid=20910&rt=\u5176\u4ed6\u4eba\u8fd8\u641c&recid=20826&euri=300085", - "http://www.baidu.com/s?usm=1&wd=%E5%BF%85%E5%BA%94%E8%AF%8D%E5%85%B8&ie=utf-8&rsv_cq=cow&rsv_dl=0_right_recommends_merge_20826&cq=cow&srcid=20910&rt=\u82f1\u8bed\u7ffb\u8bd1&recid=20826&euri=6527206", - "http://www.baidu.com/s?usm=1&wd=%E6%8B%93%E8%AF%8D&ie=utf-8&rsv_cq=cow&rsv_dl=0_right_recommends_merge_20826&cq=cow&srcid=20910&rt=\u82f1\u8bed\u5b66\u4e60\u52a9\u624b&recid=20826&euri=6685701", - "http://www.baidu.com/s?usm=1&wd=%E6%96%B0%E4%B8%9C%E6%96%B9%E5%9C%A8%E7%BA%BF&ie=utf-8&rsv_cq=cow&rsv_dl=0_right_recommends_merge_20826&cq=cow&srcid=20910&rt=\u82f1\u8bed\u5b66\u4e60\u52a9\u624b&recid=20826&euri=2225295", - "http://www.baidu.com/s?usm=1&wd=%E6%9C%80%E9%95%BF%E7%9A%84%E8%8B%B1%E6%96%87%E5%8D%95%E8%AF%8D&ie=utf-8&rsv_cq=cow&rsv_dl=0_right_recommends_merge_20826&cq=cow&srcid=20910&rt=\u5176\u4ed6\u4eba\u8fd8\u641c&recid=20826&euri=657095", - "http://www.baidu.com/s?usm=1&wd=%E6%9C%89%E9%81%93%E8%AF%8D%E5%85%B8&ie=utf-8&rsv_cq=cow&rsv_dl=0_right_recommends_merge_20826&cq=cow&srcid=20910&rt=\u82f1\u8bed\u7ffb\u8bd1&recid=20826&euri=1641307", - "http://www.baidu.com/s?usm=1&wd=%E6%B2%AA%E6%B1%9F%E8%8B%B1%E8%AF%AD&ie=utf-8&rsv_cq=cow&rsv_dl=0_right_recommends_merge_20826&cq=cow&srcid=20910&rt=\u82f1\u8bed\u5b66\u4e60\u52a9\u624b&recid=20826&euri=405084", - "http://www.baidu.com/s?usm=1&wd=%E6%B5%B7%E8%AF%8D%E8%AF%8D%E5%85%B8&ie=utf-8&rsv_cq=cow&rsv_dl=0_right_recommends_merge_20826&cq=cow&srcid=20910&rt=\u82f1\u8bed\u7ffb\u8bd1&recid=20826&euri=7611882", - "http://www.baidu.com/s?usm=1&wd=%E7%81%B5%E6%A0%BC%E6%96%AF&ie=utf-8&rsv_cq=cow&rsv_dl=0_right_recommends_merge_20826&cq=cow&srcid=20910&rt=\u82f1\u8bed\u7ffb\u8bd1&recid=20826&euri=758224", - "http://www.baidu.com/s?usm=1&wd=%E7%99%BE%E5%BA%A6%E7%BF%BB%E8%AF%91&ie=utf-8&rsv_cq=cow&rsv_dl=0_right_recommends_merge_20826&cq=cow&srcid=20910&rt=\u82f1\u8bed\u7ffb\u8bd1&recid=20826&euri=608784", - "http://www.baidu.com/s?usm=1&wd=%E7%99%BE%E8%AF%8D%E6%96%A9&ie=utf-8&rsv_cq=cow&rsv_dl=0_right_recommends_merge_20826&cq=cow&srcid=20910&rt=\u82f1\u8bed\u5b66\u4e60\u52a9\u624b&recid=20826&euri=9089046", - "http://www.baidu.com/s?usm=1&wd=%E7%BB%8F%E5%85%B8%E8%8B%B1%E6%96%87%E6%AD%8C%E6%9B%B2&ie=utf-8&rsv_cq=cow&rsv_dl=0_right_recommends_merge_20826&cq=cow&srcid=20910&rt=\u5176\u4ed6\u4eba\u8fd8\u641c&recid=20826&euri=1216241", - "http://www.baidu.com/s?usm=1&wd=%E8%8B%B1%E8%AF%AD%E8%B0%9A%E8%AF%AD&ie=utf-8&rsv_cq=cow&rsv_dl=0_right_recommends_merge_20826&cq=cow&srcid=20910&rt=\u5176\u4ed6\u4eba\u8fd8\u641c&recid=20826&euri=17075", - "http://www.baidu.com/s?usm=1&wd=%E8%AE%B0%E5%BF%86%E6%B3%95&ie=utf-8&rsv_cq=cow&rsv_dl=0_right_recommends_merge_20826&cq=cow&srcid=20910&rt=\u5176\u4ed6\u4eba\u8fd8\u641c&recid=20826&euri=1520914", - "http://www.baidu.com/s?usm=1&wd=%E9%87%91%E5%B1%B1%E8%AF%8D%E9%9C%B8&ie=utf-8&rsv_cq=cow&rsv_dl=0_right_recommends_merge_20826&cq=cow&srcid=20910&rt=\u82f1\u8bed\u7ffb\u8bd1&recid=20826&euri=6599", - "http://www.baidu.com/s?usm=1&wd=91%E5%A4%96%E6%95%99%E7%BD%91&ie=utf-8&rsv_cq=cow&rsv_dl=0_right_recommends_merge_20826&cq=cow&srcid=20910&rt=\u82f1\u8bed\u5b66\u4e60\u52a9\u624b&recid=20826&euri=10142484", - "http://www.baidu.com/s?usm=1&wd=a+cattle&ie=utf-8&rsv_crq=7&bs=cow", - "http://www.baidu.com/s?usm=1&wd=basketball%E7%9A%84%E9%9F%B3%E6%A0%87&ie=utf-8&rsv_crq=7&bs=cow", - "http://www.baidu.com/s?usm=1&wd=cattle&ie=utf-8&rsv_crq=7&bs=cow", - "http://www.baidu.com/s?usm=1&wd=cow%E5%8F%AF%E6%95%B0%E5%90%97&ie=utf-8&rsv_cq=cow&rsv_dl=0_left_dict3_85_18695", - "http://www.baidu.com/s?usm=1&wd=cow%E6%80%8E%E4%B9%88%E8%AF%BB&ie=utf-8&rsv_cq=cow&rsv_dl=0_left_dict3_85_18695", - "http://www.baidu.com/s?usm=1&wd=cow%E6%80%8E%E4%B9%88%E8%AF%BB&ie=utf-8&rsv_crq=7&bs=cow", - "http://www.baidu.com/s?usm=1&wd=cow%E6%98%AF%E4%BB%80%E4%B9%88%E6%84%8F%E6%80%9D&ie=utf-8&rsv_crq=7&bs=cow", - "http://www.baidu.com/s?usm=1&wd=cow%E6%98%AF%E4%BB%80%E4%B9%88%E6%84%8F%E6%80%9D&ie=utf-8&rsv_rq=2&rsv_cq=cow", - "http://www.baidu.com/s?usm=1&wd=cow%E6%B4%97%E9%9D%A2%E5%A5%B6&ie=utf-8&rsv_cq=cow&rsv_dl=0_left_bk_polysemy_91_19781", - "http://www.baidu.com/s?usm=1&wd=cow%E6%B4%97%E9%9D%A2%E5%A5%B6&ie=utf-8&rsv_cq=cow&rsv_dl=0_left_dict3_85_18695", - "http://www.baidu.com/s?usm=1&wd=cow%E6%B4%97%E9%9D%A2%E5%A5%B6&ie=utf-8&rsv_rq=2&rsv_cq=cow", - "http://www.baidu.com/s?usm=1&wd=cow%E7%89%9B%E4%B9%B3%E7%9F%B3%E7%A2%B1&ie=utf-8&rsv_cq=cow&rsv_dl=0_left_bk_polysemy_91_19781", - "http://www.baidu.com/s?usm=1&wd=cow%E7%89%9B%E4%B9%B3%E7%9F%B3%E7%A2%B1&ie=utf-8&rsv_rq=2&rsv_cq=cow", - "http://www.baidu.com/s?usm=1&wd=cow%E8%8B%B1%E8%AF%AD%E6%80%8E%E4%B9%88%E8%AF%BB&ie=utf-8&rsv_crq=7&bs=cow", - "http://www.baidu.com/s?usm=1&wd=cow%E9%B8%A1%E5%B0%BE%E9%85%92&ie=utf-8&rsv_cq=cow&rsv_dl=0_left_bk_polysemy_91_19781", - "http://www.baidu.com/s?usm=1&wd=cow+%E4%BB%A3%E7%90%86&ie=utf-8&rsv_cq=cow&rsv_dl=0_left_bk_polysemy_91_19781", - "http://www.baidu.com/s?usm=1&wd=cow+%E5%86%99%E6%97%B6%E5%A4%8D%E5%88%B6&ie=utf-8&rsv_cq=cow&rsv_dl=0_left_bk_polysemy_91_19781", - "http://www.baidu.com/s?usm=1&wd=cow+&ie=utf-8&gate=&rsv_rq=2&rsv_cq=cow", - "http://www.baidu.com/s?usm=1&wd=cow+gate%E5%AE%98%E7%BD%91&ie=utf-8&rsv_crq=7&bs=cow", - "http://www.baidu.com/s?usm=1&wd=cow+gate&ie=utf-8&rsv_rq=2&rsv_cq=cow", - "http://www.baidu.com/s?usm=1&wd=cow+gate+nutrilon&ie=utf-8&rsv_crq=7&bs=cow", - "http://www.baidu.com/s?usm=1&wd=cow+girl&ie=utf-8&rsv_cq=cow&rsv_dl=0_left_dict3_85_18695", - "http://www.baidu.com/s?usm=1&wd=cow+milk&ie=utf-8&rsv_crq=7&bs=cow", - "http://www.baidu.com/s?usm=1&wd=dairy+cattle&ie=utf-8&rsv_crq=7&bs=cow", - "http://www.baidu.com/s?usm=1&wd=holy+cow&ie=utf-8&rsv_cq=cow&rsv_dl=0_left_dict3_85_18695", - "http://www.baidu.com/s?usm=1&wd=the+biggest+cow%E6%98%AF%E4%BB%80%E4%B9%88%E6%84%8F%E6%80%9D&ie=utf-8&rsv_crq=7&bs=cow", - "http://www.baidu.com/s?usm=5&wd=%E4%B8%AD%E5%BC%8F%E8%8B%B1%E8%AF%AD&ie=utf-8&rsv_cq=rice&rsv_dl=0_right_recommends_merge_20826&cq=rice&srcid=20910&rt=\u5176\u4ed6\u4eba\u8fd8\u641c&recid=20826&euri=300085", - "http://www.baidu.com/s?usm=5&wd=%E4%BF%A1%E6%89%98%E5%9F%BA%E9%87%91+rice&ie=utf-8&rsv_cq=rice&rsv_dl=0_left_shares_simple_16311_18695", - "http://www.baidu.com/s?usm=5&wd=%E5%BF%85%E5%BA%94%E8%AF%8D%E5%85%B8&ie=utf-8&rsv_cq=rice&rsv_dl=0_right_recommends_merge_20826&cq=rice&srcid=20910&rt=\u82f1\u8bed\u7ffb\u8bd1&recid=20826&euri=6527206", - "http://www.baidu.com/s?usm=5&wd=%E6%8B%93%E8%AF%8D&ie=utf-8&rsv_cq=rice&rsv_dl=0_right_recommends_merge_20826&cq=rice&srcid=20910&rt=\u82f1\u8bed\u5b66\u4e60\u52a9\u624b&recid=20826&euri=6685701", - "http://www.baidu.com/s?usm=5&wd=%E6%96%B0%E4%B8%9C%E6%96%B9%E5%9C%A8%E7%BA%BF&ie=utf-8&rsv_cq=rice&rsv_dl=0_right_recommends_merge_20826&cq=rice&srcid=20910&rt=\u82f1\u8bed\u5b66\u4e60\u52a9\u624b&recid=20826&euri=2225295", - "http://www.baidu.com/s?usm=5&wd=%E6%9C%80%E9%95%BF%E7%9A%84%E8%8B%B1%E6%96%87%E5%8D%95%E8%AF%8D&ie=utf-8&rsv_cq=rice&rsv_dl=0_right_recommends_merge_20826&cq=rice&srcid=20910&rt=\u5176\u4ed6\u4eba\u8fd8\u641c&recid=20826&euri=657095", - "http://www.baidu.com/s?usm=5&wd=%E6%9C%89%E9%81%93%E8%AF%8D%E5%85%B8&ie=utf-8&rsv_cq=rice&rsv_dl=0_right_recommends_merge_20826&cq=rice&srcid=20910&rt=\u82f1\u8bed\u7ffb\u8bd1&recid=20826&euri=1641307", - "http://www.baidu.com/s?usm=5&wd=%E6%B2%AA%E6%B1%9F%E8%8B%B1%E8%AF%AD&ie=utf-8&rsv_cq=rice&rsv_dl=0_right_recommends_merge_20826&cq=rice&srcid=20910&rt=\u82f1\u8bed\u5b66\u4e60\u52a9\u624b&recid=20826&euri=405084", - "http://www.baidu.com/s?usm=5&wd=%E6%B5%B7%E8%AF%8D%E8%AF%8D%E5%85%B8&ie=utf-8&rsv_cq=rice&rsv_dl=0_right_recommends_merge_20826&cq=rice&srcid=20910&rt=\u82f1\u8bed\u7ffb\u8bd1&recid=20826&euri=7611882", - "http://www.baidu.com/s?usm=5&wd=%E7%81%B5%E6%A0%BC%E6%96%AF&ie=utf-8&rsv_cq=rice&rsv_dl=0_right_recommends_merge_20826&cq=rice&srcid=20910&rt=\u82f1\u8bed\u7ffb\u8bd1&recid=20826&euri=758224", - "http://www.baidu.com/s?usm=5&wd=%E7%99%BE%E5%BA%A6%E7%BF%BB%E8%AF%91&ie=utf-8&rsv_cq=rice&rsv_dl=0_right_recommends_merge_20826&cq=rice&srcid=20910&rt=\u82f1\u8bed\u7ffb\u8bd1&recid=20826&euri=608784", - "http://www.baidu.com/s?usm=5&wd=%E7%99%BE%E8%AF%8D%E6%96%A9&ie=utf-8&rsv_cq=rice&rsv_dl=0_right_recommends_merge_20826&cq=rice&srcid=20910&rt=\u82f1\u8bed\u5b66\u4e60\u52a9\u624b&recid=20826&euri=9089046", - "http://www.baidu.com/s?usm=5&wd=%E7%BB%8F%E5%85%B8%E8%8B%B1%E6%96%87%E6%AD%8C%E6%9B%B2&ie=utf-8&rsv_cq=rice&rsv_dl=0_right_recommends_merge_20826&cq=rice&srcid=20910&rt=\u5176\u4ed6\u4eba\u8fd8\u641c&recid=20826&euri=1216241", - "http://www.baidu.com/s?usm=5&wd=%E8%8B%B1%E8%AF%AD%E8%B0%9A%E8%AF%AD&ie=utf-8&rsv_cq=rice&rsv_dl=0_right_recommends_merge_20826&cq=rice&srcid=20910&rt=\u5176\u4ed6\u4eba\u8fd8\u641c&recid=20826&euri=17075", - "http://www.baidu.com/s?usm=5&wd=%E8%AE%B0%E5%BF%86%E6%B3%95&ie=utf-8&rsv_cq=rice&rsv_dl=0_right_recommends_merge_20826&cq=rice&srcid=20910&rt=\u5176\u4ed6\u4eba\u8fd8\u641c&recid=20826&euri=1520914", - "http://www.baidu.com/s?usm=5&wd=%E9%87%91%E5%B1%B1%E8%AF%8D%E9%9C%B8&ie=utf-8&rsv_cq=rice&rsv_dl=0_right_recommends_merge_20826&cq=rice&srcid=20910&rt=\u82f1\u8bed\u7ffb\u8bd1&recid=20826&euri=6599", - "http://www.baidu.com/s?usm=5&wd=%E9%9F%A9%E5%9B%BD%E5%8C%96%E5%A6%86%E5%93%81rice%E5%85%AC%E5%8F%B8&ie=utf-8&rsv_cq=rice&rsv_dl=0_left_shares_simple_16311_18695", - "http://www.baidu.com/s?usm=5&wd=91%E5%A4%96%E6%95%99%E7%BD%91&ie=utf-8&rsv_cq=rice&rsv_dl=0_right_recommends_merge_20826&cq=rice&srcid=20910&rt=\u82f1\u8bed\u5b66\u4e60\u52a9\u624b&recid=20826&euri=10142484", - "http://www.baidu.com/s?usm=5&wd=damien+rice&ie=utf-8&rsv_cq=rice&rsv_dl=0_left_bk_polysemy_91_19781", - "http://www.baidu.com/s?usm=5&wd=damien+rice&ie=utf-8&rsv_cq=rice&rsv_dl=0_left_sp_img_4_18696", - "http://www.baidu.com/s?usm=5&wd=damien+rice&ie=utf-8&rsv_cq=rice&rsv_dl=0_left_vd_mininewest_1_18695", - "http://www.baidu.com/s?usm=5&wd=damien+rice&ie=utf-8&rsv_rq=2&rsv_cq=rice", - "http://www.baidu.com/s?usm=5&wd=damien+rice+cold+ater&ie=utf-8&rsv_cq=rice&rsv_dl=0_left_vd_mininewest_1_18695", - "http://www.baidu.com/s?usm=5&wd=damien+rice+long+long+way&ie=utf-8&rsv_cq=rice&rsv_dl=0_left_vd_mininewest_1_18695", - "http://www.baidu.com/s?usm=5&wd=deoproce&ie=utf-8&rsv_cq=rice&rsv_dl=0_left_shares_simple_16311_18695", - "http://www.baidu.com/s?usm=5&wd=northwestern+university&ie=utf-8&rsv_crq=7&bs=rice", - "http://www.baidu.com/s?usm=5&wd=rice%E5%8C%96%E5%A6%86%E5%93%81&ie=utf-8&rsv_rq=2&rsv_cq=rice", - "http://www.baidu.com/s?usm=5&wd=rice%E5%8F%AF%E6%95%B0%E5%90%97&ie=utf-8&rsv_cq=rice&rsv_dl=0_left_dict3_85_18695", - "http://www.baidu.com/s?usm=5&wd=rice%E5%8F%AF%E6%95%B0%E5%90%97&ie=utf-8&rsv_rq=2&rsv_cq=rice", - "http://www.baidu.com/s?usm=5&wd=rice%E5%A4%A7%E5%AD%A6&ie=utf-8&rsv_rq=2&rsv_cq=rice", - "http://www.baidu.com/s?usm=5&wd=rice%E6%80%8E%E4%B9%88%E8%AF%BB&ie=utf-8&rsv_cq=rice&rsv_dl=0_left_dict3_85_18695", - "http://www.baidu.com/s?usm=5&wd=rice%E6%98%AF%E5%8F%AF%E6%95%B0%E5%90%8D%E8%AF%8D%E5%90%97&ie=utf-8&rsv_cq=rice&rsv_dl=0_left_dict3_85_18695", - "http://www.baidu.com/s?usm=5&wd=rice%E7%9A%84%E6%B5%B7%E6%8A%A5&ie=utf-8&rsv_cq=rice&rsv_dl=0_left_sp_img_4_18696", - "http://www.baidu.com/s?usm=5&wd=rice+%26+shine&ie=utf-8&rsv_cq=rice&rsv_dl=0_left_bk_polysemy_91_19781", - "http://www.baidu.com/s?usm=5&wd=rice+%E7%BB%9F%E8%AE%A1&ie=utf-8&rsv_cq=rice&rsv_dl=0_left_bk_polysemy_91_19781", - "http://www.baidu.com/s?usm=5&wd=rice+&ie=utf-8&shine=&rsv_rq=2&rsv_cq=rice", - "http://www.baidu.com/s?usm=5&wd=rice+cooker&ie=utf-8&rsv_cq=rice&rsv_dl=0_left_sp_img_4_18696", - "http://www.baidu.com/s?usm=5&wd=rice+dumpling&ie=utf-8&rsv_rq=2&rsv_cq=rice", - "http://www.baidu.com/s?usm=5&wd=rice+energy&ie=utf-8&rsv_cq=rice&rsv_dl=0_left_shares_simple_16311_18695", - "http://www.baidu.com/s?usm=5&wd=rice+pudding&ie=utf-8&rsv_cq=rice&rsv_dl=0_left_sp_img_4_18696", - "http://www.baidu.com/s?usm=5&wd=rice+queen&ie=utf-8&rsv_cq=rice&rsv_dl=0_left_dict3_85_18695", - "http://www.baidu.com/s?usm=5&wd=rice+university%E6%8E%92%E5%90%8D&ie=utf-8&rsv_cq=rice&rsv_dl=0_left_bk_polysemy_91_19781", - "http://www.baidu.com/s?usm=5&wd=rice+university&ie=utf-8&rsv_rq=2&rsv_cq=rice", - "http://www.baidu.com/s?usm=5&wd=talk+does+not+cook+rice&ie=utf-8&rsv_crq=7&bs=rice", - "http://www.baidu.com/s?usm=5&wd=turn+o62n+the+cooker+%E7%9A%84%E8%8B%B1%E8%AF%AD%E6%84%8F%E6%80%9D&ie=utf-8&rsv_crq=7&bs=rice", - "http://www.baidu.com/s?usm=5&wd=white+rice+organic+texmati&ie=utf-8&rsv_crq=7&bs=rice", - "http://www.baidu.com/s?wd=%E5%A4%8F%E8%88%AA%E7%87%95&rsp=7&f=1&oq=cow&ie=utf-8&usm=1&rsv_pq=f537508b0000092e&rsv_t=3ba1NEgMEGYo0PYSwo6tX5sslRvA81yOlYQgEie8eSwiLaHYIF5Lq9ZSeFE&rsv_ers=xdt0&rs_src=0&rsv_pq=f537508b0000092e&rsv_t=3ba1NEgMEGYo0PYSwo6tX5sslRvA81yOlYQgEie8eSwiLaHYIF5Lq9ZSeFE", - "http://www.baidu.com/s?wd=%E6%9E%97%E7%A7%8B%E7%A6%BB&rsp=6&f=1&oq=rice&ie=utf-8&usm=5&rsv_pq=b8b471d5000008a5&rsv_t=3453uWIvu2sbVpZ6oCuwvXflyrudK42UZQILLesFKD54VodI4hsL52diKkc&rsv_ers=xdt0&rs_src=0&rsv_pq=b8b471d5000008a5&rsv_t=3453uWIvu2sbVpZ6oCuwvXflyrudK42UZQILLesFKD54VodI4hsL52diKkc", - "http://www.baidu.com/s?wd=%E6%B0%B4%E7%86%8A&rsp=6&f=1&oq=cow&ie=utf-8&usm=1&rsv_pq=f537508b0000092e&rsv_t=3ba1NEgMEGYo0PYSwo6tX5sslRvA81yOlYQgEie8eSwiLaHYIF5Lq9ZSeFE&rsv_ers=xdt0&rs_src=0&rsv_pq=f537508b0000092e&rsv_t=3ba1NEgMEGYo0PYSwo6tX5sslRvA81yOlYQgEie8eSwiLaHYIF5Lq9ZSeFE", - "http://www.baidu.com/s?wd=%E9%99%88%E5%A5%95%E8%BF%85&rsp=7&f=1&oq=rice&ie=utf-8&usm=5&rsv_pq=b8b471d5000008a5&rsv_t=3453uWIvu2sbVpZ6oCuwvXflyrudK42UZQILLesFKD54VodI4hsL52diKkc&rsv_ers=xdt0&rs_src=0&rsv_pq=b8b471d5000008a5&rsv_t=3453uWIvu2sbVpZ6oCuwvXflyrudK42UZQILLesFKD54VodI4hsL52diKkc", - "http://www.baidu.com/s?wd=cow%20gate%E5%AE%98%E7%BD%91&rsp=3&f=1&oq=cow&ie=utf-8&usm=1&rsv_pq=f537508b0000092e&rsv_t=3ba1NEgMEGYo0PYSwo6tX5sslRvA81yOlYQgEie8eSwiLaHYIF5Lq9ZSeFE&rsv_ers=xdt0&rs_src=0&rsv_pq=f537508b0000092e&rsv_t=3ba1NEgMEGYo0PYSwo6tX5sslRvA81yOlYQgEie8eSwiLaHYIF5Lq9ZSeFE", - "http://www.baidu.com/s?wd=cow%20gate&rsp=2&f=1&oq=cow&ie=utf-8&usm=1&rsv_pq=f537508b0000092e&rsv_t=3ba1NEgMEGYo0PYSwo6tX5sslRvA81yOlYQgEie8eSwiLaHYIF5Lq9ZSeFE&rsv_ers=xdt0&rs_src=0&rsv_pq=f537508b0000092e&rsv_t=3ba1NEgMEGYo0PYSwo6tX5sslRvA81yOlYQgEie8eSwiLaHYIF5Lq9ZSeFE", - "http://www.baidu.com/s?wd=cow%E6%98%AF%E4%BB%80%E4%B9%88%E6%84%8F%E6%80%9D&rsp=1&f=1&oq=cow&ie=utf-8&usm=1&rsv_pq=f537508b0000092e&rsv_t=3ba1NEgMEGYo0PYSwo6tX5sslRvA81yOlYQgEie8eSwiLaHYIF5Lq9ZSeFE&rsv_ers=xdt0&rs_src=0&rsv_pq=f537508b0000092e&rsv_t=3ba1NEgMEGYo0PYSwo6tX5sslRvA81yOlYQgEie8eSwiLaHYIF5Lq9ZSeFE", - "http://www.baidu.com/s?wd=cow%E6%B4%97%E9%9D%A2%E5%A5%B6&rsp=0&f=1&oq=cow&ie=utf-8&usm=1&rsv_pq=f537508b0000092e&rsv_t=3ba1NEgMEGYo0PYSwo6tX5sslRvA81yOlYQgEie8eSwiLaHYIF5Lq9ZSeFE&rsv_ers=xdt0&rs_src=0&rsv_pq=f537508b0000092e&rsv_t=3ba1NEgMEGYo0PYSwo6tX5sslRvA81yOlYQgEie8eSwiLaHYIF5Lq9ZSeFE", - "http://www.baidu.com/s?wd=cow%E7%89%9B%E4%B9%B3%E7%9F%B3%E7%A2%B1&rsp=4&f=1&oq=cow&ie=utf-8&usm=1&rsv_pq=f537508b0000092e&rsv_t=3ba1NEgMEGYo0PYSwo6tX5sslRvA81yOlYQgEie8eSwiLaHYIF5Lq9ZSeFE&rsv_ers=xdt0&rs_src=0&rsv_pq=f537508b0000092e&rsv_t=3ba1NEgMEGYo0PYSwo6tX5sslRvA81yOlYQgEie8eSwiLaHYIF5Lq9ZSeFE", - "http://www.baidu.com/s?wd=cow&pn=10&oq=cow&ie=utf-8&usm=1&rsv_pq=f537508b0000092e&rsv_t=3ba1NEgMEGYo0PYSwo6tX5sslRvA81yOlYQgEie8eSwiLaHYIF5Lq9ZSeFE", - "http://www.baidu.com/s?wd=cow&pn=10&oq=cow&ie=utf-8&usm=1&rsv_pq=f537508b0000092e&rsv_t=3ba1NEgMEGYo0PYSwo6tX5sslRvA81yOlYQgEie8eSwiLaHYIF5Lq9ZSeFE&rsv_page=1", - "http://www.baidu.com/s?wd=cow&pn=20&oq=cow&ie=utf-8&usm=1&rsv_pq=f537508b0000092e&rsv_t=3ba1NEgMEGYo0PYSwo6tX5sslRvA81yOlYQgEie8eSwiLaHYIF5Lq9ZSeFE", - "http://www.baidu.com/s?wd=cow&pn=30&oq=cow&ie=utf-8&usm=1&rsv_pq=f537508b0000092e&rsv_t=3ba1NEgMEGYo0PYSwo6tX5sslRvA81yOlYQgEie8eSwiLaHYIF5Lq9ZSeFE", - "http://www.baidu.com/s?wd=cow&pn=40&oq=cow&ie=utf-8&usm=1&rsv_pq=f537508b0000092e&rsv_t=3ba1NEgMEGYo0PYSwo6tX5sslRvA81yOlYQgEie8eSwiLaHYIF5Lq9ZSeFE", - "http://www.baidu.com/s?wd=cow&pn=50&oq=cow&ie=utf-8&usm=1&rsv_pq=f537508b0000092e&rsv_t=3ba1NEgMEGYo0PYSwo6tX5sslRvA81yOlYQgEie8eSwiLaHYIF5Lq9ZSeFE", - "http://www.baidu.com/s?wd=cow&pn=60&oq=cow&ie=utf-8&usm=1&rsv_pq=f537508b0000092e&rsv_t=3ba1NEgMEGYo0PYSwo6tX5sslRvA81yOlYQgEie8eSwiLaHYIF5Lq9ZSeFE", - "http://www.baidu.com/s?wd=cow&pn=70&oq=cow&ie=utf-8&usm=1&rsv_pq=f537508b0000092e&rsv_t=3ba1NEgMEGYo0PYSwo6tX5sslRvA81yOlYQgEie8eSwiLaHYIF5Lq9ZSeFE", - "http://www.baidu.com/s?wd=cow&pn=80&oq=cow&ie=utf-8&usm=1&rsv_pq=f537508b0000092e&rsv_t=3ba1NEgMEGYo0PYSwo6tX5sslRvA81yOlYQgEie8eSwiLaHYIF5Lq9ZSeFE", - "http://www.baidu.com/s?wd=cow&pn=90&oq=cow&ie=utf-8&usm=1&rsv_pq=f537508b0000092e&rsv_t=3ba1NEgMEGYo0PYSwo6tX5sslRvA81yOlYQgEie8eSwiLaHYIF5Lq9ZSeFE", - "http://www.baidu.com/s?wd=cowboy&rsp=5&f=1&oq=cow&ie=utf-8&usm=1&rsv_pq=f537508b0000092e&rsv_t=3ba1NEgMEGYo0PYSwo6tX5sslRvA81yOlYQgEie8eSwiLaHYIF5Lq9ZSeFE&rsv_ers=xdt0&rs_src=0&rsv_pq=f537508b0000092e&rsv_t=3ba1NEgMEGYo0PYSwo6tX5sslRvA81yOlYQgEie8eSwiLaHYIF5Lq9ZSeFE", - "http://www.baidu.com/s?wd=damien%20rice&rsp=5&f=1&oq=rice&ie=utf-8&usm=5&rsv_pq=b8b471d5000008a5&rsv_t=3453uWIvu2sbVpZ6oCuwvXflyrudK42UZQILLesFKD54VodI4hsL52diKkc&rsv_ers=xdt0&rs_src=0&rsv_pq=b8b471d5000008a5&rsv_t=3453uWIvu2sbVpZ6oCuwvXflyrudK42UZQILLesFKD54VodI4hsL52diKkc", - "http://www.baidu.com/s?wd=dict.cn@v&vmp_ec=2d76f41b6c01eb92d92p3aYaXbX75e3f45=Qu3faR5474Y2d67s4Ja08451532b4&vmp_ectm=1427987238&from=vs", - "http://www.baidu.com/s?wd=dict.hjenglish.com@v&vmp_ec=3c1949e0a03c5746997971744766e3a1f=Yeu3bXeRf77b7d2=8eXQ3fLovNpmpQNladasbmbGaJ42X6ded2cs2e5c91ed05&vmp_ectm=1427893909&from=vs", - "http://www.baidu.com/s?wd=dict.kekenet.com@v&vmp_ec=a97033531653664ebeb5a67657e7add5Z073W5radf74d751b7b=s2jC5lY8uVap2aQ23XR32370J35X74ef92ed&vmp_ectm=1419410638&from=vs", - "http://www.baidu.com/s?wd=openrice&rsp=8&f=1&oq=rice&ie=utf-8&usm=5&rsv_pq=b8b471d5000008a5&rsv_t=3453uWIvu2sbVpZ6oCuwvXflyrudK42UZQILLesFKD54VodI4hsL52diKkc&rsv_ers=xdt0&rs_src=0&rsv_pq=b8b471d5000008a5&rsv_t=3453uWIvu2sbVpZ6oCuwvXflyrudK42UZQILLesFKD54VodI4hsL52diKkc", - "http://www.baidu.com/s?wd=rice", - "http://www.baidu.com/s?wd=rice%20shine&rsp=3&f=1&oq=rice&ie=utf-8&usm=5&rsv_pq=b8b471d5000008a5&rsv_t=3453uWIvu2sbVpZ6oCuwvXflyrudK42UZQILLesFKD54VodI4hsL52diKkc&rsv_ers=xdt0&rs_src=0&rsv_pq=b8b471d5000008a5&rsv_t=3453uWIvu2sbVpZ6oCuwvXflyrudK42UZQILLesFKD54VodI4hsL52diKkc", - "http://www.baidu.com/s?wd=rice%20university&rsp=2&f=1&oq=rice&ie=utf-8&usm=5&rsv_pq=b8b471d5000008a5&rsv_t=3453uWIvu2sbVpZ6oCuwvXflyrudK42UZQILLesFKD54VodI4hsL52diKkc&rsv_ers=xdt0&rs_src=0&rsv_pq=b8b471d5000008a5&rsv_t=3453uWIvu2sbVpZ6oCuwvXflyrudK42UZQILLesFKD54VodI4hsL52diKkc", - "http://www.baidu.com/s?wd=rice%E5%8F%AF%E6%95%B0%E5%90%97&rsp=4&f=1&oq=rice&ie=utf-8&usm=5&rsv_pq=b8b471d5000008a5&rsv_t=3453uWIvu2sbVpZ6oCuwvXflyrudK42UZQILLesFKD54VodI4hsL52diKkc&rsv_ers=xdt0&rs_src=0&rsv_pq=b8b471d5000008a5&rsv_t=3453uWIvu2sbVpZ6oCuwvXflyrudK42UZQILLesFKD54VodI4hsL52diKkc", - "http://www.baidu.com/s?wd=rice&pn=10&oq=rice&ie=utf-8&usm=5&rsv_pq=b8b471d5000008a5&rsv_t=3453uWIvu2sbVpZ6oCuwvXflyrudK42UZQILLesFKD54VodI4hsL52diKkc", - "http://www.baidu.com/s?wd=rice&pn=10&oq=rice&ie=utf-8&usm=5&rsv_pq=b8b471d5000008a5&rsv_t=3453uWIvu2sbVpZ6oCuwvXflyrudK42UZQILLesFKD54VodI4hsL52diKkc&rsv_page=1", - "http://www.baidu.com/s?wd=rice&pn=20&oq=rice&ie=utf-8&usm=5&rsv_pq=b8b471d5000008a5&rsv_t=3453uWIvu2sbVpZ6oCuwvXflyrudK42UZQILLesFKD54VodI4hsL52diKkc", - "http://www.baidu.com/s?wd=rice&pn=30&oq=rice&ie=utf-8&usm=5&rsv_pq=b8b471d5000008a5&rsv_t=3453uWIvu2sbVpZ6oCuwvXflyrudK42UZQILLesFKD54VodI4hsL52diKkc", - "http://www.baidu.com/s?wd=rice&pn=40&oq=rice&ie=utf-8&usm=5&rsv_pq=b8b471d5000008a5&rsv_t=3453uWIvu2sbVpZ6oCuwvXflyrudK42UZQILLesFKD54VodI4hsL52diKkc", - "http://www.baidu.com/s?wd=rice&pn=50&oq=rice&ie=utf-8&usm=5&rsv_pq=b8b471d5000008a5&rsv_t=3453uWIvu2sbVpZ6oCuwvXflyrudK42UZQILLesFKD54VodI4hsL52diKkc", - "http://www.baidu.com/s?wd=rice&pn=60&oq=rice&ie=utf-8&usm=5&rsv_pq=b8b471d5000008a5&rsv_t=3453uWIvu2sbVpZ6oCuwvXflyrudK42UZQILLesFKD54VodI4hsL52diKkc", - "http://www.baidu.com/s?wd=rice&pn=70&oq=rice&ie=utf-8&usm=5&rsv_pq=b8b471d5000008a5&rsv_t=3453uWIvu2sbVpZ6oCuwvXflyrudK42UZQILLesFKD54VodI4hsL52diKkc", - "http://www.baidu.com/s?wd=rice&pn=80&oq=rice&ie=utf-8&usm=5&rsv_pq=b8b471d5000008a5&rsv_t=3453uWIvu2sbVpZ6oCuwvXflyrudK42UZQILLesFKD54VodI4hsL52diKkc", - "http://www.baidu.com/s?wd=rice&pn=90&oq=rice&ie=utf-8&usm=5&rsv_pq=b8b471d5000008a5&rsv_t=3453uWIvu2sbVpZ6oCuwvXflyrudK42UZQILLesFKD54VodI4hsL52diKkc", - "http://www.baidu.com/s?wd=rise&rsp=1&f=1&oq=rice&ie=utf-8&usm=5&rsv_pq=b8b471d5000008a5&rsv_t=3453uWIvu2sbVpZ6oCuwvXflyrudK42UZQILLesFKD54VodI4hsL52diKkc&rsv_ers=xdt0&rs_src=0&rsv_pq=b8b471d5000008a5&rsv_t=3453uWIvu2sbVpZ6oCuwvXflyrudK42UZQILLesFKD54VodI4hsL52diKkc", - "http://www.baidu.com/s?wd=shine&rsp=0&f=1&oq=rice&ie=utf-8&usm=5&rsv_pq=b8b471d5000008a5&rsv_t=3453uWIvu2sbVpZ6oCuwvXflyrudK42UZQILLesFKD54VodI4hsL52diKkc&rsv_ers=xdt0&rs_src=0&rsv_pq=b8b471d5000008a5&rsv_t=3453uWIvu2sbVpZ6oCuwvXflyrudK42UZQILLesFKD54VodI4hsL52diKkc", - "http://www.baidu.com/s?wd=slamacow&rsp=8&f=1&oq=cow&ie=utf-8&usm=1&rsv_pq=f537508b0000092e&rsv_t=3ba1NEgMEGYo0PYSwo6tX5sslRvA81yOlYQgEie8eSwiLaHYIF5Lq9ZSeFE&rsv_ers=xdt0&rs_src=0&rsv_pq=f537508b0000092e&rsv_t=3ba1NEgMEGYo0PYSwo6tX5sslRvA81yOlYQgEie8eSwiLaHYIF5Lq9ZSeFE", - "http://www.baidu.com/s?wd=www.iciba.com@v&vmp_ec=44bb91c76017fd30076a0bea8=j25s0d2J1Y2235fd3b2Yi9ayl55Sef3cbp0dc34Xd5Xe36593ddce0&vmp_ectm=1427712608&from=vs", - "http://www.baidu.com/s?wd=www.iyaya.com@v&vmp_ec=a0344a20ec76845c7d8333e703d5S0yabdc7599ef5772bj=739WF5YXdpce59JXs83919d7570801d3&vmp_ectm=1429054691&from=vs", - "http://www.baidu.com/s?wd=www.jd.com@v&vmp_ec=5421364aa037f76d2d2fbd3d2j=35Z12089fe8c0aby955c5sC9qXdJ83fX5d58454f9be3c&vmp_ectm=1429021679&from=vs", - "http://www.baidu.com/search/jubao.html", - "http://www.baidu.com/tools?url=http%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3D-M91t8L7rn2kU_un4Mo2wO-p3qp6o5yTofPuHNwv7BRbOttA4-UAH4yAbTAnxkwil3mfSEqFi0EO8-Algv59aq&jump=http%3A%2F%2Fkoubei.baidu.com%2Fwomc%2Fp%2Fsentry%3Ftitle%3D%02cow%03%E5%92%8C%01cattle%01%E6%9C%89%01%E4%BB%80%E4%B9%88%01%E5%8C%BA%E5%88%AB%01%3F%01_%01%E7%99%BE%E5%BA%A6%01%E7%9F%A5%E9%81%93%01%26q%3Dcow&key=surl", - "http://www.baidu.com/tools?url=http%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3D5uns9UowL1ZepzZm8E26sOL3uJezwjIT3mfcNR7_FPkYt2IbV1UMvsBT_n0hqEjs&jump=http%3A%2F%2Fkoubei.baidu.com%2Fwomc%2Fp%2Fsentry%3Ftitle%3D%02cow%03%E6%98%AF%01%E4%BB%80%E4%B9%88%01%E6%84%8F%E6%80%9D%01_%01%E8%8B%B1%E8%AF%AD%01%E5%9C%A8%E7%BA%BF%01%E7%BF%BB%E8%AF%91%01_%02cow%03%E7%9A%84%01%E7%BF%BB%E8%AF%91%01%E3%80%81%01%E5%90%AB%E4%B9%89%01%E3%80%81%01%E8%AF%BB%E9%9F%B3%01%E3%80%81%01%E7%94%A8%E6%B3%95%01%E3%80%81%01%E5%8F%82%E8%80%83%01...%26q%3Dcow&key=surl", - "http://www.baidu.com/tools?url=http%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3DFI5j5ft6lL75AJ3TV3DKS-Fj4QUK_6j-MngMpo3a4pW&jump=http%3A%2F%2Fkoubei.baidu.com%2Fwomc%2Fp%2Fsentry%3Ftitle%3D%02rice%03%E6%98%AF%01%E4%BB%80%E4%B9%88%01%E6%84%8F%E6%80%9D%01_%02rice%03%E5%9C%A8%E7%BA%BF%01%E7%BF%BB%E8%AF%91%01_%01%E8%8B%B1%E8%AF%AD%01_%01%E8%AF%BB%E9%9F%B3%01_%01%E7%94%A8%E6%B3%95%01_%01%E4%BE%8B%E5%8F%A5%01_%01%E6%B5%B7%01%E8%AF%8D%01%E8%AF%8D%E5%85%B8%01%26q%3Drice&key=surl", - "http://www.baidu.com/tools?url=http%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3DJHCMcSB6vseh77VSTAZ-YqU5KyEOSbCBIZj1WMC4cba&jump=http%3A%2F%2Fkoubei.baidu.com%2Fwomc%2Fp%2Fsentry%3Ftitle%3D%01Home%01%20%01-%01%20%02Rice%03%20%01University%01%26q%3Drice&key=surl", - "http://www.baidu.com/tools?url=http%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3DUCI8DqUdy7_rlCN0vRN8OgO8IXIwwkUX0VOdViCKrurm_sT2o_SeDKhHsOn04OWp&jump=http%3A%2F%2Fkoubei.baidu.com%2Fwomc%2Fp%2Fsentry%3Ftitle%3D%02cow%03%E6%98%AF%01%E4%BB%80%E4%B9%88%01%E6%84%8F%E6%80%9D%01_%02cow%03%E7%9A%84%01%E7%BF%BB%E8%AF%91%01_%01%E9%9F%B3%E6%A0%87%01_%01%E8%AF%BB%E9%9F%B3%01_%01%E7%94%A8%E6%B3%95%01_%01%E4%BE%8B%E5%8F%A5%01_%01%E7%88%B1%01%E8%AF%8D%E9%9C%B8%01%E5%9C%A8%E7%BA%BF%01%E8%AF%8D%E5%85%B8%01%26q%3Dcow&key=surl", - "http://www.baidu.com/tools?url=http%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3Dbx9sWi5WnXjBkUhM5gvOSmz2CbZJ_-OiKdNgZr3udsS&jump=http%3A%2F%2Fkoubei.baidu.com%2Fwomc%2Fp%2Fsentry%3Ftitle%3D%02cow%03%E6%98%AF%01%E4%BB%80%E4%B9%88%01%E6%84%8F%E6%80%9D%01_%02cow%03%E5%9C%A8%E7%BA%BF%01%E7%BF%BB%E8%AF%91%01_%01%E8%8B%B1%E8%AF%AD%01_%01%E8%AF%BB%E9%9F%B3%01_%01%E7%94%A8%E6%B3%95%01_%01%E4%BE%8B%E5%8F%A5%01_%01%E6%B5%B7%01%E8%AF%8D%01%E8%AF%8D%E5%85%B8%01%26q%3Dcow&key=surl", - "http://www.baidu.com/tools?url=http%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3DhMgPFqAn_EueXnigQ4nGVGqkcyhhVJzKjKHP5hl52rroccqSxUtaE7t0u5yl_Ero&jump=http%3A%2F%2Fkoubei.baidu.com%2Fwomc%2Fp%2Fsentry%3Ftitle%3D%02rice%03%E6%98%AF%01%E4%BB%80%E4%B9%88%01%E6%84%8F%E6%80%9D%01_%02rice%03%E7%9A%84%01%E7%BF%BB%E8%AF%91%01_%01%E9%9F%B3%E6%A0%87%01_%01%E8%AF%BB%E9%9F%B3%01_%01%E7%94%A8%E6%B3%95%01_%01%E4%BE%8B%E5%8F%A5%01_%01%E7%88%B1%01%E8%AF%8D%E9%9C%B8%01%E5%9C%A8%E7%BA%BF%01%E8%AF%8D%E5%85%B8%01%26q%3Drice&key=surl", - "http://www.baidu.com/tools?url=http%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3DxIVPE7l3aIThwsbTHHUhIO_jc890BBOkQnDcd7ivNnZKOihdfpF4ZNHKcHdiVvVA&jump=http%3A%2F%2Fkoubei.baidu.com%2Fwomc%2Fp%2Fsentry%3Ftitle%3D%01%22%02cow%03%22%01%E6%98%AF%01%E4%BB%80%E4%B9%88%01%E6%84%8F%E6%80%9D%01-%01%22%02cow%03%22%01%E7%BF%BB%E8%AF%91%01_%02cow%03%E7%9A%84%01%E5%8F%91%E9%9F%B3%01%E3%80%81%01%E7%BF%BB%E8%AF%91%01%E3%80%81%01%E5%8F%82%E8%80%83%01%E4%BE%8B%E5%8F%A5%01-%01%E5%8F%AF%E5%8F%AF%01%E6%9F%A5%01%E8%AF%8D%01%26q%3Dcow&key=surl", - "http://www.bbc.co.uk/news/world/us_and_canada/", - "http://www.beautybar.com/", - "http://www.bloomberg.com/", - "http://www.bookdepository.com/", - "http://www.bostonglobe.com/", - "http://www.bravenewfilms.org/", - "http://www.businessinsider.com/", - "http://www.businessinsider.com/iron-man-suit-has-one-key-problem-2015-4", - "http://www.businessinsider.com/profile-of-corinthian-student-michael-adorno-2015-4", - "http://www.businessweek.com/blogs/joshua-green-on-politics", - "http://www.buzzfeed.com/", - "http://www.c-span.org", - "http://www.casa.com/", - "http://www.cbsnews.com/", - "http://www.cbsnews.com/news/video-mob-of-high-school-students-attacks-man-at-gas-station/?ftag=YHF4eb9d17", - "http://www.chicagotribune.com/", - "http://www.cnn.com", - "http://www.cnn.com/", - "http://www.cnn.com/2013/02/13/showbiz/gallery/pregnant-celebrities-2013/index.html", - "http://www.cnn.com/2013/07/13/world/oil-spills-fast-facts/index.html", - "http://www.cnn.com/2014/12/26/opinion/reddy-valentine-fighting-oil-spills/index.html", - "http://www.cnn.com/2015/01/05/showbiz/gallery/celebs-turning-50-in-2015/index.html", - "http://www.cnn.com/2015/01/09/world/gallery/people-we-lost-2015/index.html", - "http://www.cnn.com/2015/03/06/politics/obamacare-enrollments-florida-repubican/index.html", - "http://www.cnn.com/2015/03/09/world/gallery/sites-damaged-by-isis/index.html", - "http://www.cnn.com/2015/03/27/us/gallery/military-photography-of-the-year/index.html", - "http://www.cnn.com/2015/04/02/world/cnnphotos-cuba-solares/index.html", - "http://www.cnn.com/2015/04/03/travel/gallery/lincoln-assassination-anniversary/index.html", - "http://www.cnn.com/2015/04/05/living/cnnphotos-swedish-dads-parental-leave/index.html", - "http://www.cnn.com/2015/04/07/politics/how-russians-hacked-the-wh/index.html", - "http://www.cnn.com/2015/04/10/travel/feat-abraham-lincoln-assassination-150-anniversary/index.html", - "http://www.cnn.com/2015/04/10/us/oil-rig-victim-families-five-years-later/index.html", - "http://www.cnn.com/2015/04/12/sport/andy-murray-wedding/index.html", - "http://www.cnn.com/2015/04/12/us/rowing-flying-carp-feat-irpt/index.html", - "http://www.cnn.com/2015/04/13/entertainment/feat-madonna-kiss-drake/index.html", - "http://www.cnn.com/2015/04/13/entertainment/olivia-munn-xmen-psylocke-feat-thr/index.html", - "http://www.cnn.com/2015/04/13/entertainment/wonder-woman-director-michelle-maclaren-feat/index.html", - "http://www.cnn.com/2015/04/13/europe/italy-oldest-neanderthal-dna-sample-altamura/index.html", - "http://www.cnn.com/2015/04/13/football/paddy-power-liverpool-newcastle-football-tweet/index.html", - "http://www.cnn.com/2015/04/13/health/superfoods-stress-relief/index.html", - "http://www.cnn.com/2015/04/13/living/feat-maryland-free-range-parenting-family-under-investigation-again/index.html", - "http://www.cnn.com/2015/04/13/opinions/reyes-marco-rubio-candidacy/index.html", - "http://www.cnn.com/2015/04/13/opinions/urry-alien-life/index.html", - "http://www.cnn.com/2015/04/13/politics/ben-carson-may-4-presidential-announcement/index.html", - "http://www.cnn.com/2015/04/13/politics/nra-convention-2015-2016-elections/index.html", - "http://www.cnn.com/2015/04/13/travel/cuba-travel-us-sanctions/index.html", - "http://www.cnn.com/2015/04/13/travel/gallery/game-of-thrones-locations-gallery/index.html", - "http://www.cnn.com/2015/04/13/us/cleveland-zoo-cheetah-fall/index.html", - "http://www.cnn.com/2015/04/13/us/tulsa-shooting-robert-bates-volunteer-deputy/index.html", - "http://www.cnn.com/2015/04/14/asia/gallery/kim-jong-un-wife-ri-jol-su/index.html", - "http://www.cnn.com/2015/04/14/entertainment/feat-pink-weight-response-hln/index.html", - "http://www.cnn.com/2015/04/14/entertainment/feat-rita-wilson-cancer/index.html", - "http://www.cnn.com/2015/04/14/entertainment/feat-stephen-hawking-sings-galaxy-song/index.html", - "http://www.cnn.com/2015/04/14/entertainment/percy-sledge-dies-feat/index.html", - "http://www.cnn.com/2015/04/14/europe/hilary-clinton-18-rating-russia/index.html", - "http://www.cnn.com/2015/04/14/health/annual-physical-ritual-costly/index.html", - "http://www.cnn.com/2015/04/14/health/breast-milk-online-dangers/index.html", - "http://www.cnn.com/2015/04/14/living/feat-foster-child-davion-only-gets-forever-home/index.html", - "http://www.cnn.com/2015/04/14/living/most-challenged-books-2014-feat/index.html", - "http://www.cnn.com/2015/04/14/opinions/al-qaeda-fading-peter-bergen/index.html", - "http://www.cnn.com/2015/04/14/opinions/drexler-dont-call-her-hillary/index.html", - "http://www.cnn.com/2015/04/14/opinions/zelizer-iran-deal-congress-involved/index.html", - "http://www.cnn.com/2015/04/14/politics/chris-christie-new-hampshire-2016-elections/index.html", - "http://www.cnn.com/2015/04/14/politics/corker-iran-bill-deal-reached/index.html", - "http://www.cnn.com/2015/04/14/politics/dea-head-oversight-committee-hearing/index.html", - "http://www.cnn.com/2015/04/14/politics/gao-newer-aircraft-vulnerable-to-hacking/index.html", - "http://www.cnn.com/2015/04/14/politics/george-pataki-new-hampshire-ad/index.html", - "http://www.cnn.com/2015/04/14/politics/hillary-clinton-2016-elections-iowa-trip/index.html", - "http://www.cnn.com/2015/04/14/politics/iraqi-prime-ministers-visit-to-white-house/index.html", - "http://www.cnn.com/2015/04/14/politics/kelley-paul-book-2016-elections/index.html", - "http://www.cnn.com/2015/04/14/politics/rand-paul-wife-kelley-election-2016-turtlenecks/index.html", - "http://www.cnn.com/2015/04/14/sport/gallery/what-a-shot-sports-0414/index.html", - "http://www.cnn.com/2015/04/14/travel/bourdain-top-10-episodes/index.html", - "http://www.cnn.com/2015/04/14/travel/chernobyl-tourism/index.html", - "http://www.cnn.com/2015/04/14/us/arizona-police-run-over-suspect/index.html", - "http://www.cnn.com/2015/04/14/us/florida-panama-city-gang-rape-case/index.html", - "http://www.cnn.com/2015/04/14/us/georgia-atlanta-public-schools-cheating-scandal-verdicts/index.html", - "http://www.cnn.com/2015/04/14/us/gulf-oil-spill-unknowns/index.html", - "http://www.cnn.com/2015/04/14/us/mom-bee-attack-twins-drown/index.html", - "http://www.cnn.com/2015/04/14/us/north-carolina-college-shooting/index.html", - "http://www.cnn.com/2015/04/14/us/philadelphia-quadriplegic-man-abandoned-mom-extradition/index.html", - "http://www.cnn.com/2015/04/14/us/spacex-rocket-launch/index.html", - "http://www.cnn.com/2015/04/14/us/washington-overpass-accident-concrete-barrier/index.html", - "http://www.cnn.com/2015/04/14/world/cnnphotos-boragaon-landfill-india/index.html", - "http://www.cnn.com/2015/04/14/world/uk-russia-aircraft-intercepted/index.html", - "http://www.cnn.com/about", - "http://www.cnn.com/collection", - "http://www.cnn.com/entertainment", - "http://www.cnn.com/go/?stream=CNN", - "http://www.cnn.com/health", - "http://www.cnn.com/help", - "http://www.cnn.com/interactive/2014/05/specials/city-of-tomorrow/index.html", - "http://www.cnn.com/interactive/2014/12/us/cnn-guns-project/index.html", - "http://www.cnn.com/living", - "http://www.cnn.com/login.html", - "http://www.cnn.com/more", - "http://www.cnn.com/mycnn", - "http://www.cnn.com/opinions", - "http://www.cnn.com/politics", - "http://www.cnn.com/privacy", - "http://www.cnn.com/services/advertise/main.html", - "http://www.cnn.com/shows/cnn-films", - "http://www.cnn.com/shows/high-profits", - "http://www.cnn.com/shows/mike-rowe", - "http://www.cnn.com/shows/wonder-list", - "http://www.cnn.com/specials/cnn-heroes", - "http://www.cnn.com/specials/cnn-investigations", - "http://www.cnn.com/specials/cnn-longform", - "http://www.cnn.com/specials/digital-studios", - "http://www.cnn.com/specials/impact-your-world", - "http://www.cnn.com/specials/last-50-stories", - "http://www.cnn.com/specials/latest-news-videos", - "http://www.cnn.com/specials/more/cnn-leadership", - "http://www.cnn.com/specials/opinion/change-the-list", - "http://www.cnn.com/specials/opinion/opinion-politics", - "http://www.cnn.com/specials/opinion/opinion-social-issues", - "http://www.cnn.com/specials/photos", - "http://www.cnn.com/specials/profiles/", - "http://www.cnn.com/specials/tv/all-shows", - "http://www.cnn.com/specials/tv/anchors-and-reporters", - "http://www.cnn.com/specials/video-landing/gotta-watch-video-collection", - "http://www.cnn.com/specials/videos/digital-shorts", - "http://www.cnn.com/tech", - "http://www.cnn.com/terms", - "http://www.cnn.com/transcripts", - "http://www.cnn.com/travel", - "http://www.cnn.com/tv", - "http://www.cnn.com/tv/schedule/cnn", - "http://www.cnn.com/us", - "http://www.cnn.com/videos", - "http://www.cnn.com/videos/business/2014/04/08/orig-pkg-what-is-a-ponzi-scheme-zain-asher.cnn", - "http://www.cnn.com/videos/business/2014/04/15/orig-pkg-what-is-high-frequency-trading-zain-asher.cnn", - "http://www.cnn.com/videos/business/2014/04/29/what-is-your-credit-score-fico-christine-romans-cnnmoney.cnn", - "http://www.cnn.com/videos/business/2014/10/10/cnn-orig-what-is-bankruptcy-cristina-alesci.cnn", - "http://www.cnn.com/videos/business/2014/10/24/cnn-orig-what-is-inversion-cristina-alesci.cnn", - "http://www.cnn.com/videos/business/2015/04/14/qmb-pickpocket-james-freedman-intv.cnn", - "http://www.cnn.com/videos/entertainment/2015/04/13/late-night-television-hosts-lisas-desk-orig-mg.cnn", - "http://www.cnn.com/videos/health/2014/03/10/orig-brain-on-weed-sanjay-jr-jt.cnn", - "http://www.cnn.com/videos/living/2015/04/13/erin-pkg-moos-chimp-takes-down-drone.cnn", - "http://www.cnn.com/videos/politics/2015/04/13/marco-rubio-explained-under-90-seconds-origwx-al.cnn", - "http://www.cnn.com/videos/politics/2015/04/14/nr-hillary-clinton-unrecognized-at-chipotle.cnn", - "http://www.cnn.com/videos/tech/2015/04/13/apps-aim-catch-police-camera-orig.cnn", - "http://www.cnn.com/videos/tv/2015/04/13/nr-seg-armenia-kanye-west-jumps-in-lake.cnn", - "http://www.cnn.com/videos/tv/2015/04/13/pkg-griffin-bp-gulf-oil-spill-dive.cnn", - "http://www.cnn.com/videos/tv/2015/04/14/lead-live-marsh-planes-hacked.cnn", - "http://www.cnn.com/videos/us/2015/04/11/bts-soccer-player-attacked-on-plane.cnn", - "http://www.cnn.com/videos/us/2015/04/11/pkg-mom-reunited-with-daughter-50-years-later.ktvi-kplr", - "http://www.cnn.com/videos/us/2015/04/14/dnt-mountain-lion-p-22-sneaks-into-home.ktla", - "http://www.cnn.com/videos/us/2015/04/14/pkg-milwaukee-crash-shooting-death.wtmj", - "http://www.cnn.com/videos/world/2015/04/13/orig-u-s-ships-pass-through-suez-canal.cnn", - "http://www.cnn.com/world", - "http://www.createspace.com/", - "http://www.csmonitor.com/", - "http://www.dailymail.co.uk/ushome/index.html", - "http://www.dailymotion.com/video/x2j5um5_the-50-most-bizarre-couple-photos-compilation_fun", - "http://www.dailymotion.com/video/x2jy5zi_omg-chain-snatching-on-the-road-from-a-woman_news", - "http://www.dailymotion.com/video/x2lslaq_%EC%9E%A5%EB%AF%B8%EB%B9%9B-%EC%97%B0%EC%9D%B8%EB%93%A4-e50-150405-h1_creation", - "http://www.dailymotion.com/video/x2lvdqc_%EB%B9%9B%EB%82%98%EA%B1%B0%EB%82%98-%EB%AF%B8%EC%B9%98%EA%B1%B0%EB%82%98-e23-150406-1_creation", - "http://www.dailymotion.com/video/x2lvpai_%EB%B9%84%EC%A0%95%EC%83%81%ED%9A%8C%EB%8B%B4-e40-150406-l1_creation", - "http://www.dailymotion.com/video/x2m5eo2_new-latest-punjabi-song-2015-jeevan-leather-life-sad-top-hit-2014-indian-pakistani-rock-movies-bolly_music", - "http://www.dailymotion.com/video/x2m7x9n_little-boy-heartbreakingly-says-goodbye-to-his-best-friend_fun", - "http://www.dailymotion.com/video/x2m9zq7_german-shepherd-lovingly-cares-for-adopted-new-puppy_animals", - "http://www.dailymotion.com/video/x2ma90d_sadqay-tumhare-last-episode-27-in-high-quality-10th-april-2015_shortfilms", - "http://www.dailymotion.com/video/x2mfnhb_tyler-the-creator-live-coachella-2015_music", - "http://www.dailymotion.com/video/x2mjvre_rowers-challenged-as-several-flying-asian-carp-join-in-training_fun", - "http://www.dailymotion.com/video/x2mkwgg_top-5-benefits-of-apple-carplay-and-google-android_tech", - "http://www.dailymotion.com/video/x2ml6qg_ice-waves-n-ice-to-meet-you_travel", - "http://www.dailymotion.com/video/x2ml8ox_awesome-jetsprint-boat-pov-holy-sprint_auto", - "http://www.dailymotion.com/video/x2mlb4j_i-am-bread-review-commentary_videogames", - "http://www.dailymotion.com/video/x2mldhx_5-star-s-brandon-jones-nacogdoches-tx_sport", - "http://www.dailymotion.com/video/x2mlh4k_things-that-go-wrong-when-trying-to-watch-netflix_lifestyle", - "http://www.dailymotion.com/video/x2mlh4r_how-to-get-the-best-chips-in-the-bowl_lifestyle", - "http://www.dailymotion.com/video/x2mm5mh_mission-impossible-rogue-nation-fate-2015-tom-cruise_shortfilms", - "http://www.dailymotion.com/video/x2mnl05_terrified-skiers-appear-to-encounter-giant-mountain-lion-on-slopes_fun", - "http://www.dailymotion.com/video/x2mo9bq_gentlemen-lobsters-what-really-happens-at-coachella_lifestyle", - "http://www.dailymotion.com/video/x2mo9ds_astronauts-take-a-gopro-on-their-spacewalk_tech", - "http://www.dailymotion.com/video/x2mogov_flawed-perceptions-of-chris-paul_sport", - "http://www.dailymotion.com/video/x2mon13_dennis-quaid-freaks-out-on-set-and-it-s-caught-on-camera_people", - "http://www.dailymotion.com/video/x2mow8y_rihanna-wants-you-to-know-she-s-not-using-cocaine-in-this-video_news", - "http://www.democracyarsenal.org/", - "http://www.democracynow.org/", - "http://www.deviantart.com/", - "http://www.deviantart.com/?day=2015-04-13", - "http://www.deviantart.com/browse/all/", - "http://www.deviantart.com/browse/undiscovered/", - "http://www.deviantart.com/browse/whatshot ", - "http://www.deviantart.com/browse/whatshot/", - "http://www.deviantart.com/dailydeviations", - "http://www.deviantart.com/dailydeviations/", - "http://www.deviantart.com/developers", - "http://www.deviantart.com/journals/", - "http://www.deviantart.com/mobile", - "http://www.deviantart.com/random/deviant", - "http://www.deviantart.com/random/deviation", - "http://www.deviantart.com/random/group", - "http://www.deviantart.com/submit/deviation", - "http://www.deviantart.com/tag/animation", - "http://www.deviantart.com/tag/animationstudio", - "http://www.deviantart.com/tag/art", - "http://www.deviantart.com/tag/artist", - "http://www.deviantart.com/tag/arttools", - "http://www.deviantart.com/tag/baseball", - "http://www.deviantart.com/tag/breakfast", - "http://www.deviantart.com/tag/burgerking", - "http://www.deviantart.com/tag/collection", - "http://www.deviantart.com/tag/comics", - "http://www.deviantart.com/tag/cosplay", - "http://www.deviantart.com/tag/cosplayfriday", - "http://www.deviantart.com/tag/daredevil", - "http://www.deviantart.com/tag/dart", - "http://www.deviantart.com/tag/depthradius", - "http://www.deviantart.com/tag/destiny", - "http://www.deviantart.com/tag/discover", - "http://www.deviantart.com/tag/disney", - "http://www.deviantart.com/tag/dragons", - "http://www.deviantart.com/tag/earthday", - "http://www.deviantart.com/tag/edwardgorey", - "http://www.deviantart.com/tag/electriccar", - "http://www.deviantart.com/tag/elonmusk", - "http://www.deviantart.com/tag/energy", - "http://www.deviantart.com/tag/fanartfriday", - "http://www.deviantart.com/tag/fastandfurious", - "http://www.deviantart.com/tag/fastfood", - "http://www.deviantart.com/tag/food", - "http://www.deviantart.com/tag/foodinfocus", - "http://www.deviantart.com/tag/foodphotography", - "http://www.deviantart.com/tag/furious7", - "http://www.deviantart.com/tag/gameofthrones", - "http://www.deviantart.com/tag/gardengnomes", - "http://www.deviantart.com/tag/gargoyles", - "http://www.deviantart.com/tag/gnomes", - "http://www.deviantart.com/tag/got", - "http://www.deviantart.com/tag/highfantasy", - "http://www.deviantart.com/tag/illustrator", - "http://www.deviantart.com/tag/india", - "http://www.deviantart.com/tag/isleofwight", - "http://www.deviantart.com/tag/japan", - "http://www.deviantart.com/tag/japanesecuisine", - "http://www.deviantart.com/tag/kingslanding", - "http://www.deviantart.com/tag/kiss", - "http://www.deviantart.com/tag/lazy", - "http://www.deviantart.com/tag/literature", - "http://www.deviantart.com/tag/majorleaguebaseball", - "http://www.deviantart.com/tag/margaretatwood", - "http://www.deviantart.com/tag/marvelcomics", - "http://www.deviantart.com/tag/mazes", - "http://www.deviantart.com/tag/mcdonalds", - "http://www.deviantart.com/tag/mlb", - "http://www.deviantart.com/tag/mortalkombat", - "http://www.deviantart.com/tag/newsdesk", - "http://www.deviantart.com/tag/novel", - "http://www.deviantart.com/tag/paulwalker", - "http://www.deviantart.com/tag/photography", - "http://www.deviantart.com/tag/photogtraphy", - "http://www.deviantart.com/tag/poll", - "http://www.deviantart.com/tag/procrastination", - "http://www.deviantart.com/tag/projectporkchop", - "http://www.deviantart.com/tag/puzzles", - "http://www.deviantart.com/tag/recap", - "http://www.deviantart.com/tag/shortfilm", - "http://www.deviantart.com/tag/solarenergy", - "http://www.deviantart.com/tag/solarpanels", - "http://www.deviantart.com/tag/solarpower", - "http://www.deviantart.com/tag/spoilersahead", - "http://www.deviantart.com/tag/stars", - "http://www.deviantart.com/tag/tacobell", - "http://www.deviantart.com/tag/teslamotors", - "http://www.deviantart.com/tag/thehandmaidstale", - "http://www.deviantart.com/tag/theironislands", - "http://www.deviantart.com/tag/thewrittenrevolution", - "http://www.deviantart.com/tag/toolsoftrade", - "http://www.deviantart.com/tag/vindiesel", - "http://www.deviantart.com/tag/westeros", - "http://www.deviantart.com/tag/winterfell", - "http://www.deviantart.com/tag/witches", - "http://www.deviantart.com/tag/writer", - "http://www.deviantart.com/today", - "http://www.deviantart.com/today/", - "http://www.deviantart.com?q=special:critiquable", - "http://www.diapers.com/", - "http://www.digg.com/", - "http://www.djreprints.com/?mod=WSJ_footer", - "http://www.dowjones.com/careers.asp?mod=WSJ_footer", - "http://www.dpreview.com/", - "http://www.eastdane.com/welcome", - "http://www.efinancialnews.com/", - "http://www.engadget.com", - "http://www.eonline.com/", - "http://www.ew.com/ew/", - "http://www.fabric.com/", - "http://www.facebook.com/dailymotion", - "http://www.facebook.com/wsj", - "http://www.flickr.com/photos/flickr/galleries/72157649608126894", - "http://www.flickr.com/photos/flickr/galleries/72157649608126894/with/14523607768/lightbox/?yc=https://www.yahoo.com", - "http://www.flickr.com/photos/flickr/galleries/72157649608126894/with/15533024319/lightbox/?yc=https://www.yahoo.com", - "http://www.flickr.com/photos/flickr/galleries/72157649608126894/with/15615019488/lightbox/?yc=https://www.yahoo.com", - "http://www.flickr.com/photos/flickr/galleries/72157649608126894/with/15814864721/lightbox/?yc=https://www.yahoo.com", - "http://www.flickr.com/photos/flickr/galleries/72157649608126894/with/16055716103/lightbox/?yc=https://www.yahoo.com", - "http://www.flickr.com/photos/flickr/galleries/72157649608126894/with/16069733286/lightbox/?yc=https://www.yahoo.com", - "http://www.flickr.com/photos/flickr/galleries/72157649608126894/with/16301542813/lightbox/?yc=https://www.yahoo.com", - "http://www.flickr.com/photos/flickr/galleries/72157649608126894/with/16371429136/lightbox/?yc=https://www.yahoo.com", - "http://www.flickr.com/photos/flickr/galleries/72157649608126894/with/16470173515/lightbox/?yc=https://www.yahoo.com", - "http://www.flickr.com/photos/flickr/galleries/72157649608126894/with/5631862261/lightbox/?yc=https://www.yahoo.com", - "http://www.food.com/slideshow/15-easy-coffee-drinks-229?c1=CNN_Brand-Priorities&c2=CNN", - "http://www.food.com/slideshow/easter-treats-for-kids-174?c1=CNN_Brand-Priorities&c2=CNN", - "http://www.food.com/slideshow/eggs-50-ways-225/baked-eggs-in-bread-7?c1=CNN_Brand-Priorities&c2=CNN", - "http://www.food.com/slideshow/quick-easy-make-breakfast-for-dinner-78?c1=CNN_Brand-Priorities&c2=CNN", - "http://www.forbes.com/", - "http://www.foreignaffairs.com/", - "http://www.foreignpolicy.com/", - "http://www.foxnews.com/", - "http://www.ft.com/home/us", - "http://www.funnyordie.com/", - "http://www.goodreads.com/", - "http://www.google.com/history/optout?hl=en", - "http://www.google.com/intl/en/options/", - "http://www.guardiannews.com/", - "http://www.haaretz.com/", - "http://www.hao123.com", - "http://www.healthgrades.com/procedures/top-10-womens-health-concerns?cid=t1_rss1d&sr=C53310a10", - "http://www.healthgrades.com/provider-search-directory/search?q=Rheumatology&prof.type=provider&search.type=PracticingSpecialty&loc=locIsSolrCity%3Dfalse%3Fcid%3Dt1_rss1d&sr=C53310a10", - "http://www.healthgrades.com/right-care/birth-control/birth-control-choices-for-women-35-and-older?cid=t1_rss1d&sr=C53310a10", - "http://www.healthgrades.com/right-care/diabetes/12-things-your-diabetes-doctor-wants-you-to-know?cid=t1_rss1d&sr=C53310a10", - "http://www.healthgrades.com/right-care/diabetes/7-celebrities-living-with-diabetes?cid=t1_rss1d&sr=C53310a10", - "http://www.hlntv.com/video/2015/04/13/bobby-brown-bobbi-kristina-coma-status", - "http://www.huffingtonpost.com/", - "http://www.huffingtonpost.com/#blog_links", - "http://www.huffingtonpost.com/2015/04/08/anti-inflammatory-foods_n_7028052.html?ir=Healthy+Living", - "http://www.huffingtonpost.com/2015/04/09/finding-a-partner_n_7030736.html", - "http://www.huffingtonpost.com/2015/04/09/finding-a-partner_n_7030736.html#comments", - "http://www.huffingtonpost.com/2015/04/09/hillary-clinton-funny-tweets_n_7035396.html?ir=Comedy", - "http://www.huffingtonpost.com/2015/04/12/moti-device_n_7028556.html?ir=Technology", - "http://www.huffingtonpost.com/2015/04/13/apple-watch-sales_n_7054492.html?ir=Technology", - "http://www.huffingtonpost.com/2015/04/13/best-jobs-2015_n_7056118.html?ir=Business", - "http://www.huffingtonpost.com/2015/04/13/bill-oreilly-open-season_n_7059058.html?ir=Media", - "http://www.huffingtonpost.com/2015/04/13/blackwater-guard-sentenced_n_7057452.html?ir=Politics", - "http://www.huffingtonpost.com/2015/04/13/corker-iran-bill-markup_n_7058600.html?ir=Politics", - "http://www.huffingtonpost.com/2015/04/13/corker-iran-bill-veto_n_7058600.html", - "http://www.huffingtonpost.com/2015/04/13/dixon-white-redneck_n_7059414.html?ir=Media", - "http://www.huffingtonpost.com/2015/04/13/drake-madonna-kiss-coachella_n_7053822.html?ir=Entertainment", - "http://www.huffingtonpost.com/2015/04/13/epidiolex_n_7055784.html?ir=Healthy+Living", - "http://www.huffingtonpost.com/2015/04/13/funny-tombstones_n_7051048.html?ir=Comedy", - "http://www.huffingtonpost.com/2015/04/13/hillary-clinton-404-page_n_7056172.html?ir=Technology", - "http://www.huffingtonpost.com/2015/04/13/hillary-clinton-video-announcement-2016_n_7054350.html?ir=Media", - "http://www.huffingtonpost.com/2015/04/13/holiness-the-17th-karmapa_n_7057622.html", - "http://www.huffingtonpost.com/2015/04/13/holiness-the-17th-karmapa_n_7057622.html#comments", - "http://www.huffingtonpost.com/2015/04/13/honest-inspirational-quotes_n_7055172.html?ir=Comedy", - "http://www.huffingtonpost.com/2015/04/13/house-vote-on-iran_n_7056150.html", - "http://www.huffingtonpost.com/2015/04/13/improve-internet-privacy_n_6902622.html?ir=Technology", - "http://www.huffingtonpost.com/2015/04/13/indiana-pr-firm_n_7056268.html?ir=Politics", - "http://www.huffingtonpost.com/2015/04/13/iraq-isis-counter-attack-anbar_n_7057974.html?ir=WorldPost", - "http://www.huffingtonpost.com/2015/04/13/jennifer-lopez-mtv-movie-awards_n_7054560.html?ir=Entertainment", - "http://www.huffingtonpost.com/2015/04/13/lena-dunham-mental-health_n_7053556.html?ir=Entertainment", - "http://www.huffingtonpost.com/2015/04/13/low-wages-cost-taxpayers-153-billion_n_7055202.html?ir=Business", - "http://www.huffingtonpost.com/2015/04/13/madison-small-bacterial-meningitis_n_7057822.html?ir=Healthy+Living", - "http://www.huffingtonpost.com/2015/04/13/manny-pacquiao-music-video-mayweather-_n_7054776.html", - "http://www.huffingtonpost.com/2015/04/13/manny-pacquiao-music-video-mayweather-_n_7054776.html#comments", - "http://www.huffingtonpost.com/2015/04/13/mother-65-quadruplets-german_n_7054068.html?ir=WorldPost", - "http://www.huffingtonpost.com/2015/04/13/nate-silver-vox-chart_n_7056154.html?ir=Media", - "http://www.huffingtonpost.com/2015/04/13/norovirus-cruise-ship_n_7058434.html?ir=Healthy+Living", - "http://www.huffingtonpost.com/2015/04/13/pink-weight-critics_n_7054238.html?ir=Entertainment", - "http://www.huffingtonpost.com/2015/04/13/redneck-dixon-white_n_7059414.html", - "http://www.huffingtonpost.com/2015/04/13/redneck-dixon-white_n_7059414.html#comments", - "http://www.huffingtonpost.com/2015/04/13/rich-people-live-longer-are-healthier_n_7054548.html?ir=Business", - "http://www.huffingtonpost.com/2015/04/13/rnc-gave-reporters-gag-fl_n_7055564.html?ir=Media", - "http://www.huffingtonpost.com/2015/04/13/russia-iran-missiles_n_7053940.html?ir=WorldPost", - "http://www.huffingtonpost.com/2015/04/13/toddler-sleep-problems-_n_7056016.html", - "http://www.huffingtonpost.com/2015/04/13/toddler-sleep-problems-_n_7056016.html#comments", - "http://www.huffingtonpost.com/2015/04/13/watch-spacex-launch-rocket-landing_n_7055812.html", - "http://www.huffingtonpost.com/2015/04/13/watch-spacex-launch-rocket-landing_n_7055812.html#comments", - "http://www.huffingtonpost.com/2015/04/13/whole-grain-health-benefits_n_6968990.html?ir=Healthy+Living", - "http://www.huffingtonpost.com/2015/04/14/abraham-lincoln-assassination-150th-anniversary_n_7065854.html", - "http://www.huffingtonpost.com/2015/04/14/abraham-lincoln-assassination-150th-anniversary_n_7065854.html#comments", - "http://www.huffingtonpost.com/2015/04/14/abraham-lincoln-dog-animal-lover_n_7055640.html", - "http://www.huffingtonpost.com/2015/04/14/abraham-lincoln-dog-animal-lover_n_7055640.html#comments", - "http://www.huffingtonpost.com/2015/04/14/amandla-stenberg-cultural_n_7064420.html?utm_hp_ref=mostpopular", - "http://www.huffingtonpost.com/2015/04/14/andrew-wiggins-omer-asik-dunk_n_7061260.html", - "http://www.huffingtonpost.com/2015/04/14/andrew-wiggins-omer-asik-dunk_n_7061260.html#comments", - "http://www.huffingtonpost.com/2015/04/14/anti-inflammatory-foods_n_7028052.html", - "http://www.huffingtonpost.com/2015/04/14/anti-inflammatory-foods_n_7028052.html#comments", - "http://www.huffingtonpost.com/2015/04/14/asiana-airlines-skids-runway_n_7061700.html", - "http://www.huffingtonpost.com/2015/04/14/asiana-airlines-skids-runway_n_7061700.html#comments", - "http://www.huffingtonpost.com/2015/04/14/brad-gooch-smash-cut_n_7058084.html", - "http://www.huffingtonpost.com/2015/04/14/brad-gooch-smash-cut_n_7058084.html#comments", - "http://www.huffingtonpost.com/2015/04/14/bringbackourgirls-one-year-anniversary_n_7056592.html", - "http://www.huffingtonpost.com/2015/04/14/bringbackourgirls-one-year-anniversary_n_7056592.html#comments", - "http://www.huffingtonpost.com/2015/04/14/bringbackourgirls-one-year-anniversary_n_7056592.html?ir=WorldPost", - "http://www.huffingtonpost.com/2015/04/14/c-section-rate-recommendation_n_7058954.html", - "http://www.huffingtonpost.com/2015/04/14/c-section-rate-recommendation_n_7058954.html#comments", - "http://www.huffingtonpost.com/2015/04/14/california-campus-rape-punishments_n_7056554.html", - "http://www.huffingtonpost.com/2015/04/14/california-campus-rape-punishments_n_7056554.html#comments", - "http://www.huffingtonpost.com/2015/04/14/chris-christie-2016_n_7061276.html", - "http://www.huffingtonpost.com/2015/04/14/chris-christie-blames-bri_n_7066226.html#comments", - "http://www.huffingtonpost.com/2015/04/14/cigarette-packaging_n_7064268.html", - "http://www.huffingtonpost.com/2015/04/14/cigarette-packaging_n_7064268.html#comments", - "http://www.huffingtonpost.com/2015/04/14/coffee-shop-bans-anti-gay_n_7061982.html", - "http://www.huffingtonpost.com/2015/04/14/coffee-shop-bans-anti-gay_n_7061982.html#comments", - "http://www.huffingtonpost.com/2015/04/14/congress-iran-bill_n_7062704.html?ir=Politics", - "http://www.huffingtonpost.com/2015/04/14/couple-killed-by-falling-construction-debris_n_7065862.html", - "http://www.huffingtonpost.com/2015/04/14/couple-killed-by-falling-construction-debris_n_7065862.html#comments", - "http://www.huffingtonpost.com/2015/04/14/cuba-terror-list_n_7064762.html", - "http://www.huffingtonpost.com/2015/04/14/cuba-terror-list_n_7064762.html#comments", - "http://www.huffingtonpost.com/2015/04/14/cuba-terror-list_n_7064762.html?utm_hp_ref=mostpopular", - "http://www.huffingtonpost.com/2015/04/14/dea-sex-parties_n_7063474.html", - "http://www.huffingtonpost.com/2015/04/14/dea-sex-parties_n_7063474.html#comments", - "http://www.huffingtonpost.com/2015/04/14/detention-center-hunger-strike_n_7064532.html", - "http://www.huffingtonpost.com/2015/04/14/detention-center-hunger-strike_n_7064532.html#comments", - "http://www.huffingtonpost.com/2015/04/14/drake-madonna-kiss-response_n_7061150.html?ir=Entertainment", - "http://www.huffingtonpost.com/2015/04/14/edward-snowden-bust-nypd_n_7065936.html", - "http://www.huffingtonpost.com/2015/04/14/edward-snowden-bust-nypd_n_7065936.html#comments", - "http://www.huffingtonpost.com/2015/04/14/epa-carbon-rule_n_7064302.html", - "http://www.huffingtonpost.com/2015/04/14/epa-carbon-rule_n_7064302.html#comments", - "http://www.huffingtonpost.com/2015/04/14/eu-google-antitrust-annou_n_7066634.html", - "http://www.huffingtonpost.com/2015/04/14/eu-google-antitrust-annou_n_7066634.html#comments", - "http://www.huffingtonpost.com/2015/04/14/family-feud-avengers_n_7061860.html?ir=Comedy", - "http://www.huffingtonpost.com/2015/04/14/fiduciary-standard-retirement-fees_n_7065110.html", - "http://www.huffingtonpost.com/2015/04/14/fiduciary-standard-retirement-fees_n_7065110.html#comments", - "http://www.huffingtonpost.com/2015/04/14/france-anorexia-bill_n_7066084.html", - "http://www.huffingtonpost.com/2015/04/14/france-anorexia-bill_n_7066084.html#comments", - "http://www.huffingtonpost.com/2015/04/14/free-cone-day-ben-and-jerrys-where_n_7033084.html", - "http://www.huffingtonpost.com/2015/04/14/free-cone-day-ben-and-jerrys-where_n_7033084.html#comments", - "http://www.huffingtonpost.com/2015/04/14/gravity-payments-raise_n_7061676.html?ir=Business", - "http://www.huffingtonpost.com/2015/04/14/hillary-clinton-chipotle_n_7063558.html", - "http://www.huffingtonpost.com/2015/04/14/hillary-clinton-chipotle_n_7063558.html#comments", - "http://www.huffingtonpost.com/2015/04/14/hillary-clinton-iowa-video_n_7064176.html", - "http://www.huffingtonpost.com/2015/04/14/hillary-clinton-iowa-video_n_7064176.html#comments", - "http://www.huffingtonpost.com/2015/04/14/ibrahim-al-rubaish-killed-yemen_n_7062758.html", - "http://www.huffingtonpost.com/2015/04/14/ibrahim-al-rubaish-killed-yemen_n_7062758.html#comments", - "http://www.huffingtonpost.com/2015/04/14/international-circus-anno_n_7062520.html#comments", - "http://www.huffingtonpost.com/2015/04/14/iran-bill-vote_n_7066070.html", - "http://www.huffingtonpost.com/2015/04/14/iran-bill-vote_n_7066070.html#comments", - "http://www.huffingtonpost.com/2015/04/14/iran-deal-senate_n_7063266.html", - "http://www.huffingtonpost.com/2015/04/14/jeb-bushs-administration-_n_7062336.html#comments", - "http://www.huffingtonpost.com/2015/04/14/jesse-williams-support-police-shootings_n_7063512.html", - "http://www.huffingtonpost.com/2015/04/14/jesse-williams-support-police-shootings_n_7063512.html#comments", - "http://www.huffingtonpost.com/2015/04/14/jon-stewart-hillary-clinton-announcement_n_7060206.html", - "http://www.huffingtonpost.com/2015/04/14/jon-stewart-hillary-clinton-announcement_n_7060206.html#comments", - "http://www.huffingtonpost.com/2015/04/14/jon-stewart-hillary-clinton-announcement_n_7060206.html?ir=Comedy", - "http://www.huffingtonpost.com/2015/04/14/ka-holt-house-arrest-poems_n_7058066.html", - "http://www.huffingtonpost.com/2015/04/14/ka-holt-house-arrest-poems_n_7058066.html#comments", - "http://www.huffingtonpost.com/2015/04/14/kenneth-morgan-stancil-iii-shooting_n_7061256.html", - "http://www.huffingtonpost.com/2015/04/14/kenneth-morgan-stancil-iii-shooting_n_7061256.html#comments", - "http://www.huffingtonpost.com/2015/04/14/kylie-jenner-lips_n_7064364.html?utm_hp_ref=mostpopular", - "http://www.huffingtonpost.com/2015/04/14/lawyer-tulsa-reserve-depu_n_7065652.html", - "http://www.huffingtonpost.com/2015/04/14/lawyer-tulsa-reserve-depu_n_7065652.html#comments", - "http://www.huffingtonpost.com/2015/04/14/lostandhungry-sorted-team_n_7062696.html#comments", - "http://www.huffingtonpost.com/2015/04/14/manufactured-housing-republicans_n_7065810.html", - "http://www.huffingtonpost.com/2015/04/14/manufactured-housing-republicans_n_7065810.html#comments", - "http://www.huffingtonpost.com/2015/04/14/marco-rubio-nicki-minaj_n_7062232.html", - "http://www.huffingtonpost.com/2015/04/14/marco-rubio-nicki-minaj_n_7062232.html#comments", - "http://www.huffingtonpost.com/2015/04/14/marco-rubios-announcement_n_7061846.html#comments", - "http://www.huffingtonpost.com/2015/04/14/missouri-state-auditor_n_7065144.html", - "http://www.huffingtonpost.com/2015/04/14/missouri-state-auditor_n_7065144.html#comments", - "http://www.huffingtonpost.com/2015/04/14/nancy-pelosi-iran-bill_n_7063826.html", - "http://www.huffingtonpost.com/2015/04/14/nancy-pelosi-iran-bill_n_7063826.html#comments", - "http://www.huffingtonpost.com/2015/04/14/oitnb-star-diane-guerrero_n_7063912.html", - "http://www.huffingtonpost.com/2015/04/14/oitnb-star-diane-guerrero_n_7063912.html#comments", - "http://www.huffingtonpost.com/2015/04/14/party-primary-poll_n_7064270.html", - "http://www.huffingtonpost.com/2015/04/14/party-primary-poll_n_7064270.html#comments", - "http://www.huffingtonpost.com/2015/04/14/percy-sledge-dead_n_7062944.html", - "http://www.huffingtonpost.com/2015/04/14/percy-sledge-dead_n_7062944.html#comments", - "http://www.huffingtonpost.com/2015/04/14/police-body-cameras-dc-mayor_n_7064060.html", - "http://www.huffingtonpost.com/2015/04/14/police-body-cameras-dc-mayor_n_7064060.html#comments", - "http://www.huffingtonpost.com/2015/04/14/republicans-equal-pay_n_7062128.html", - "http://www.huffingtonpost.com/2015/04/14/republicans-equal-pay_n_7062128.html#comments", - "http://www.huffingtonpost.com/2015/04/14/republicans-push-269-bill_n_7061458.html", - "http://www.huffingtonpost.com/2015/04/14/republicans-push-269-bill_n_7061458.html#comments", - "http://www.huffingtonpost.com/2015/04/14/republicans-push-269-bill_n_7061458.html?ir=Politics", - "http://www.huffingtonpost.com/2015/04/14/rikers-island-de-blasio-justice-reboot_n_7065438.html", - "http://www.huffingtonpost.com/2015/04/14/rikers-island-de-blasio-justice-reboot_n_7065438.html#comments", - "http://www.huffingtonpost.com/2015/04/14/romantic-comedies-failing-women_n_7026302.html", - "http://www.huffingtonpost.com/2015/04/14/romantic-comedies-failing-women_n_7026302.html#comments", - "http://www.huffingtonpost.com/2015/04/14/ron-johnson-obamacare-lawsuit_n_7064688.html?utm_hp_ref=mostpopular", - "http://www.huffingtonpost.com/2015/04/14/salomon-melgen-medicare-fraud_n_7066336.html", - "http://www.huffingtonpost.com/2015/04/14/salomon-melgen-medicare-fraud_n_7066336.html#comments", - "http://www.huffingtonpost.com/2015/04/14/sentence-teacher-scandal_n_7063296.html", - "http://www.huffingtonpost.com/2015/04/14/sentence-teacher-scandal_n_7063296.html#comments", - "http://www.huffingtonpost.com/2015/04/14/sexual-violence-report-boko-haram-isis_n_7059652.html?ir=WorldPost", - "http://www.huffingtonpost.com/2015/04/14/socially-responsible-companies-ranked_n_7063106.html", - "http://www.huffingtonpost.com/2015/04/14/socially-responsible-companies-ranked_n_7063106.html#comments", - "http://www.huffingtonpost.com/2015/04/14/summer-movie-preview-2015_n_7058302.html", - "http://www.huffingtonpost.com/2015/04/14/summer-movie-preview-2015_n_7058302.html#comments", - "http://www.huffingtonpost.com/2015/04/14/tech-visas_n_7061010.html?ir=Technology", - "http://www.huffingtonpost.com/2015/04/14/thabo-sefolosha-police-nypd_n_7064750.html", - "http://www.huffingtonpost.com/2015/04/14/thabo-sefolosha-police-nypd_n_7064750.html#comments", - "http://www.huffingtonpost.com/2015/04/14/thabo-sefolosha-police-nypd_n_7064750.html?utm_hp_ref=mostpopular", - "http://www.huffingtonpost.com/2015/04/14/the-future-project_n_7043956.html", - "http://www.huffingtonpost.com/2015/04/14/the-future-project_n_7043956.html#comments", - "http://www.huffingtonpost.com/2015/04/14/times-square-cookie-monster-gropes-teen_n_7062860.html", - "http://www.huffingtonpost.com/2015/04/14/times-square-cookie-monster-gropes-teen_n_7062860.html#comments", - "http://www.huffingtonpost.com/2015/04/14/tk-signs-of-oral-cancer_0_n_7055712.html", - "http://www.huffingtonpost.com/2015/04/14/tk-signs-of-oral-cancer_0_n_7055712.html#comments", - "http://www.huffingtonpost.com/2015/04/14/tom-brady-first-pitch_n_7062180.html", - "http://www.huffingtonpost.com/2015/04/14/tom-brady-first-pitch_n_7062180.html#comments", - "http://www.huffingtonpost.com/2015/04/14/tylenol-emotion-reduce-pleasure_n_7055518.html", - "http://www.huffingtonpost.com/2015/04/14/tylenol-emotion-reduce-pleasure_n_7055518.html#comments", - "http://www.huffingtonpost.com/2015/04/14/us-war-on-wildlife_n_7065294.html#comments", - "http://www.huffingtonpost.com/2015/04/14/what-chefs-eat-after-work_n_7019412.html", - "http://www.huffingtonpost.com/2015/04/14/what-chefs-eat-after-work_n_7019412.html#comments", - "http://www.huffingtonpost.com/50/", - "http://www.huffingtonpost.com/?country=BR", - "http://www.huffingtonpost.com/?country=CA", - "http://www.huffingtonpost.com/?country=DE", - "http://www.huffingtonpost.com/?country=ES", - "http://www.huffingtonpost.com/?country=FR", - "http://www.huffingtonpost.com/?country=GR", - "http://www.huffingtonpost.com/?country=IN", - "http://www.huffingtonpost.com/?country=IT", - "http://www.huffingtonpost.com/?country=JP", - "http://www.huffingtonpost.com/?country=KR", - "http://www.huffingtonpost.com/?country=MG", - "http://www.huffingtonpost.com/?country=UK", - "http://www.huffingtonpost.com/?country=US", - "http://www.huffingtonpost.com/?m=true", - "http://www.huffingtonpost.com/abraham-h-foxman", - "http://www.huffingtonpost.com/abraham-h-foxman/", - "http://www.huffingtonpost.com/abraham-h-foxman/how-to-deal-with-iranian-expansionism_b_7064596.html", - "http://www.huffingtonpost.com/amy-morin", - "http://www.huffingtonpost.com/amy-morin/", - "http://www.huffingtonpost.com/amy-morin/friends-health-science_b_7042042.html", - "http://www.huffingtonpost.com/arts/", - "http://www.huffingtonpost.com/arturo-lopez-levy", - "http://www.huffingtonpost.com/arturo-lopez-levy/", - "http://www.huffingtonpost.com/arturo-lopez-levy/marco-rubio-cuba-family-story_b_7058486.html", - "http://www.huffingtonpost.com/barry-levinson/", - "http://www.huffingtonpost.com/barry-levinson/the-age-of-insanity-part-5_b_7057854.html?utm_hp_ref=homepage", - "http://www.huffingtonpost.com/beth-markley", - "http://www.huffingtonpost.com/beth-markley/", - "http://www.huffingtonpost.com/beth-markley/whats-the-real-takeaway-from-gwyneths-29-effort_b_7059194.html", - "http://www.huffingtonpost.com/big-news/", - "http://www.huffingtonpost.com/big-news/#homepage", - "http://www.huffingtonpost.com/black-voices/", - "http://www.huffingtonpost.com/books/", - "http://www.huffingtonpost.com/bruce-ackerman/", - "http://www.huffingtonpost.com/bruce-ackerman/hillary-clintons-bad-beginning_b_7053662.html?utm_hp_ref=homepage", - "http://www.huffingtonpost.com/bruce-ackerman/hillary-clintons-bad-beginning_b_7053662.html?utm_hp_ref=yahoo&ir=Yahoo", - "http://www.huffingtonpost.com/bruce-wilson", - "http://www.huffingtonpost.com/bruce-wilson/", - "http://www.huffingtonpost.com/bruce-wilson/marco-rubios-miami-church_b_7063336.html", - "http://www.huffingtonpost.com/business/", - "http://www.huffingtonpost.com/celebrity/", - "http://www.huffingtonpost.com/charles-t-rubin", - "http://www.huffingtonpost.com/charles-t-rubin/", - "http://www.huffingtonpost.com/charles-t-rubin/ethical-artificial-intelligence_b_7034070.html", - "http://www.huffingtonpost.com/chicago/", - "http://www.huffingtonpost.com/code/", - "http://www.huffingtonpost.com/college/", - "http://www.huffingtonpost.com/comedy/", - "http://www.huffingtonpost.com/comment/policy/", - "http://www.huffingtonpost.com/contact/", - "http://www.huffingtonpost.com/crime/", - "http://www.huffingtonpost.com/dana-beyer", - "http://www.huffingtonpost.com/dana-beyer/", - "http://www.huffingtonpost.com/dana-beyer/as-the-wedge-turns----is_b_7065002.html", - "http://www.huffingtonpost.com/david-bromwich", - "http://www.huffingtonpost.com/david-bromwich/", - "http://www.huffingtonpost.com/david-bromwich/what-makes-abraham-lincoln_b_7063234.html", - "http://www.huffingtonpost.com/david-bromwich/what-makes-abraham-lincoln_b_7063234.html?utm_hp_ref=homepage", - "http://www.huffingtonpost.com/david-bromwich/what-makes-abraham-lincoln_b_7063234.html?utm_hp_ref=yahoo&ir=Yahoo", - "http://www.huffingtonpost.com/davidhalperin/video-in-iowa-clinton-str_b_7065662.html", - "http://www.huffingtonpost.com/davidhalperin/video-in-iowa-clinton-str_b_7065662.html#comments", - "http://www.huffingtonpost.com/dc/", - "http://www.huffingtonpost.com/dean-baker", - "http://www.huffingtonpost.com/dean-baker/", - "http://www.huffingtonpost.com/dean-baker/bonanza-for-the-super-rich_b_7058952.html", - "http://www.huffingtonpost.com/dennis-d-parker", - "http://www.huffingtonpost.com/dennis-d-parker/", - "http://www.huffingtonpost.com/dennis-d-parker/recent-slayings-of-unarme_b_7066128.html", - "http://www.huffingtonpost.com/denver/", - "http://www.huffingtonpost.com/detroit/", - "http://www.huffingtonpost.com/divorce/", - "http://www.huffingtonpost.com/dl-cade", - "http://www.huffingtonpost.com/dl-cade/", - "http://www.huffingtonpost.com/dl-cade/35-beautiful-photos-of-ch_b_7054670.html", - "http://www.huffingtonpost.com/drphil/", - "http://www.huffingtonpost.com/education/", - "http://www.huffingtonpost.com/elizabeth-barnett", - "http://www.huffingtonpost.com/elizabeth-barnett/", - "http://www.huffingtonpost.com/elizabeth-barnett/mental-health-stigma-_b_7054722.html", - "http://www.huffingtonpost.com/entertainment/", - "http://www.huffingtonpost.com/faq/", - "http://www.huffingtonpost.com/feeds/index.xml", - "http://www.huffingtonpost.com/fernando-espuelas", - "http://www.huffingtonpost.com/fernando-espuelas/", - "http://www.huffingtonpost.com/fernando-espuelas/enraged-congressman-confr_b_7063456.html", - "http://www.huffingtonpost.com/fifty/", - "http://www.huffingtonpost.com/food/", - "http://www.huffingtonpost.com/gary-a-olson", - "http://www.huffingtonpost.com/gary-a-olson/", - "http://www.huffingtonpost.com/gary-a-olson/how-to-understand-the-high-cost-of-college_b_7064796.html", - "http://www.huffingtonpost.com/gay-voices/", - "http://www.huffingtonpost.com/good-news/", - "http://www.huffingtonpost.com/gps-for-the-soul/", - "http://www.huffingtonpost.com/green/", - "http://www.huffingtonpost.com/grover-norquist/in-land-of-gridlock_b_7042874.html", - "http://www.huffingtonpost.com/grover-norquist/in-land-of-gridlock_b_7042874.html#comments", - "http://www.huffingtonpost.com/hawaii/", - "http://www.huffingtonpost.com/health-fitness/", - "http://www.huffingtonpost.com/health-news/", - "http://www.huffingtonpost.com/healthy-living/", - "http://www.huffingtonpost.com/home/", - "http://www.huffingtonpost.com/horoscopes/", - "http://www.huffingtonpost.com/huff-wires/", - "http://www.huffingtonpost.com/impact/", - "http://www.huffingtonpost.com/jack-stahlmann", - "http://www.huffingtonpost.com/jack-stahlmann/", - "http://www.huffingtonpost.com/jack-stahlmann/learning-from-the-masters_b_7061948.html", - "http://www.huffingtonpost.com/jobs/", - "http://www.huffingtonpost.com/joe-wilson", - "http://www.huffingtonpost.com/joe-wilson/", - "http://www.huffingtonpost.com/joe-wilson/were-for-hillary-and-here_b_7062940.html", - "http://www.huffingtonpost.com/joshua-l-schank-phd", - "http://www.huffingtonpost.com/joshua-l-schank-phd/", - "http://www.huffingtonpost.com/joshua-l-schank-phd/infrastructure-2-congress-and-the-terrible-horrible-no-good-very-bad-roads_b_7064222.html", - "http://www.huffingtonpost.com/kristin-rowefinkbeiner", - "http://www.huffingtonpost.com/kristin-rowefinkbeiner/", - "http://www.huffingtonpost.com/kristin-rowefinkbeiner/equalpayday-women-are-worth-more-than-spare-change_b_7064474.html", - "http://www.huffingtonpost.com/kristin-rowefinkbeiner/equalpayday-women-are-worth-more-than-spare-change_b_7064474.html?utm_hp_ref=mostpopular", - "http://www.huffingtonpost.com/latino-voices/", - "http://www.huffingtonpost.com/lori-pollan", - "http://www.huffingtonpost.com/lori-pollan/", - "http://www.huffingtonpost.com/lori-pollan/5-healthy-eating-strategies-that-will-outlast-any-trend_b_7054008.html", - "http://www.huffingtonpost.com/los-angeles/", - "http://www.huffingtonpost.com/makehome/", - "http://www.huffingtonpost.com/marc-lamont-hill", - "http://www.huffingtonpost.com/marc-lamont-hill/", - "http://www.huffingtonpost.com/margee-ensign", - "http://www.huffingtonpost.com/margee-ensign/", - "http://www.huffingtonpost.com/margee-ensign/we-the-survivors-of-boko-haram-kidnapping-have-not-been-broken_b_7062340.html", - "http://www.huffingtonpost.com/marlothomas/", - "http://www.huffingtonpost.com/mary-bottari", - "http://www.huffingtonpost.com/mary-bottari/", - "http://www.huffingtonpost.com/mary-bottari/hotel-industry-spins-wage_b_7058634.html", - "http://www.huffingtonpost.com/matt_green", - "http://www.huffingtonpost.com/matt_green/", - "http://www.huffingtonpost.com/matt_green/building-better-men_b_7064994.html", - "http://www.huffingtonpost.com/media/", - "http://www.huffingtonpost.com/miami/", - "http://www.huffingtonpost.com/money/", - "http://www.huffingtonpost.com/nancy-roman/things-i-learned-at-a-nude-resort_b_7029124.html", - "http://www.huffingtonpost.com/nancy-roman/things-i-learned-at-a-nude-resort_b_7029124.html#comments", - "http://www.huffingtonpost.com/new-york/", - "http://www.huffingtonpost.com/news/@sleep123/", - "http://www.huffingtonpost.com/news/afghanistan-war-blog/", - "http://www.huffingtonpost.com/news/ap/", - "http://www.huffingtonpost.com/news/becoming-fearless/", - "http://www.huffingtonpost.com/news/bob-menendez", - "http://www.huffingtonpost.com/news/bob-menendez/", - "http://www.huffingtonpost.com/news/brain/", - "http://www.huffingtonpost.com/news/buddhism", - "http://www.huffingtonpost.com/news/climate-change/", - "http://www.huffingtonpost.com/news/comedy-club/", - "http://www.huffingtonpost.com/news/comedy-original-video/", - "http://www.huffingtonpost.com/news/crossing-the-line/", - "http://www.huffingtonpost.com/news/dating/", - "http://www.huffingtonpost.com/news/diet/", - "http://www.huffingtonpost.com/news/drug-war", - "http://www.huffingtonpost.com/news/eat-the-press/", - "http://www.huffingtonpost.com/news/entertainment-originals/", - "http://www.huffingtonpost.com/news/floyd-mayweather/", - "http://www.huffingtonpost.com/news/for-profit-colleges/", - "http://www.huffingtonpost.com/news/foreign-affairs/", - "http://www.huffingtonpost.com/news/france", - "http://www.huffingtonpost.com/news/funny-videos/", - "http://www.huffingtonpost.com/news/gay-rights/", - "http://www.huffingtonpost.com/news/google", - "http://www.huffingtonpost.com/news/hpl", - "http://www.huffingtonpost.com/news/hpl/", - "http://www.huffingtonpost.com/news/hplifestyle/", - "http://www.huffingtonpost.com/news/huffpolitics-blog/", - "http://www.huffingtonpost.com/news/icon-next/", - "http://www.huffingtonpost.com/news/immigration/", - "http://www.huffingtonpost.com/news/income-inequality/", - "http://www.huffingtonpost.com/news/iran", - "http://www.huffingtonpost.com/news/iran/", - "http://www.huffingtonpost.com/news/japan/", - "http://www.huffingtonpost.com/news/jon-stewart/", - "http://www.huffingtonpost.com/news/kristen-bell", - "http://www.huffingtonpost.com/news/less-stress-more-living/", - "http://www.huffingtonpost.com/news/lgbt-history/", - "http://www.huffingtonpost.com/news/love-and-relationships", - "http://www.huffingtonpost.com/news/michelle-obama", - "http://www.huffingtonpost.com/news/nasa/", - "http://www.huffingtonpost.com/news/nature/", - "http://www.huffingtonpost.com/news/new-england-patriots/", - "http://www.huffingtonpost.com/news/nude/", - "http://www.huffingtonpost.com/news/nypd/", - "http://www.huffingtonpost.com/news/own-eating/", - "http://www.huffingtonpost.com/news/pet/", - "http://www.huffingtonpost.com/news/planning-for-retirement/", - "http://www.huffingtonpost.com/news/political-humor/", - "http://www.huffingtonpost.com/news/positive-change/", - "http://www.huffingtonpost.com/news/refugees", - "http://www.huffingtonpost.com/news/retirement", - "http://www.huffingtonpost.com/news/sleep/", - "http://www.huffingtonpost.com/news/smarter-ideas/", - "http://www.huffingtonpost.com/news/social-media/", - "http://www.huffingtonpost.com/news/spain", - "http://www.huffingtonpost.com/news/syria/", - "http://www.huffingtonpost.com/news/the-backstory/", - "http://www.huffingtonpost.com/news/third-metric/", - "http://www.huffingtonpost.com/news/trail-to-the-chief/", - "http://www.huffingtonpost.com/news/tulsa-shooting/", - "http://www.huffingtonpost.com/news/urban_progress/", - "http://www.huffingtonpost.com/news/video/", - "http://www.huffingtonpost.com/news/viral/", - "http://www.huffingtonpost.com/news/walter-scott/", - "http://www.huffingtonpost.com/news/warren-buffett", - "http://www.huffingtonpost.com/news/warren-buffett/", - "http://www.huffingtonpost.com/news/washington-post/", - "http://www.huffingtonpost.com/news/whats-working/", - "http://www.huffingtonpost.com/news/white-house/", - "http://www.huffingtonpost.com/news/yemen/", - "http://www.huffingtonpost.com/own/", - "http://www.huffingtonpost.com/p/arianna-in-print.html", - "http://www.huffingtonpost.com/p/ariannas-radio-and-podcas.html", - "http://www.huffingtonpost.com/p/ariannas-tv-appearances.html", - "http://www.huffingtonpost.com/p/huffington-post.html", - "http://www.huffingtonpost.com/parents/", - "http://www.huffingtonpost.com/patrick-r-krill", - "http://www.huffingtonpost.com/patrick-r-krill/", - "http://www.huffingtonpost.com/patrick-r-krill/price-of-alcohol_b_7054270.html", - "http://www.huffingtonpost.com/politics/", - "http://www.huffingtonpost.com/religion/", - "http://www.huffingtonpost.com/rep-jan-schakowsky", - "http://www.huffingtonpost.com/rep-jan-schakowsky/", - "http://www.huffingtonpost.com/rep-jan-schakowsky/on-equal-pay-day-lets-sta_b_7062680.html", - "http://www.huffingtonpost.com/rev-al-sharpton", - "http://www.huffingtonpost.com/rev-al-sharpton/", - "http://www.huffingtonpost.com/rev-al-sharpton/-will-the-south-teach-the_b_7055866.html", - "http://www.huffingtonpost.com/rev-al-sharpton/-will-the-south-teach-the_b_7055866.html?utm_hp_ref=homepage", - "http://www.huffingtonpost.com/rev-al-sharpton/-will-the-south-teach-the_b_7055866.html?utm_hp_ref=yahoo&ir=Yahoo", - "http://www.huffingtonpost.com/robert-l-borosage", - "http://www.huffingtonpost.com/robert-l-borosage/", - "http://www.huffingtonpost.com/robert-l-borosage/hillary-is-in-the-challen_b_7054712.html", - "http://www.huffingtonpost.com/roy-sekoff", - "http://www.huffingtonpost.com/roy-sekoff/", - "http://www.huffingtonpost.com/roy-sekoff/from-mississippi-1963-to-south-carolina-2015_b_7057048.html", - "http://www.huffingtonpost.com/san-francisco/", - "http://www.huffingtonpost.com/science/", - "http://www.huffingtonpost.com/sen-sheldon-whitehouse/", - "http://www.huffingtonpost.com/sen-sheldon-whitehouse/right-wing-groups-get-ove_b_7054956.html?utm_hp_ref=homepage", - "http://www.huffingtonpost.com/seungyoon-lee/noam-chomsky-twitter-interview_b_7064462.html", - "http://www.huffingtonpost.com/seungyoon-lee/noam-chomsky-twitter-interview_b_7064462.html#comments", - "http://www.huffingtonpost.com/shelley-emling", - "http://www.huffingtonpost.com/shelley-emling/", - "http://www.huffingtonpost.com/shelley-emling/17-things-i-want-my-son-to-know-on-his-17th-birthday_b_7034756.html", - "http://www.huffingtonpost.com/simple-thrifty-living/4-things-to-do-when-your-_b_7059046.html?ir=Business", - "http://www.huffingtonpost.com/small-business/", - "http://www.huffingtonpost.com/social/", - "http://www.huffingtonpost.com/sports/", - "http://www.huffingtonpost.com/style/", - "http://www.huffingtonpost.com/susan-brink", - "http://www.huffingtonpost.com/susan-brink/", - "http://www.huffingtonpost.com/susan-brink/the-permanent-loss-of-an-ex_b_7043310.html", - "http://www.huffingtonpost.com/syndication", - "http://www.huffingtonpost.com/syndication/", - "http://www.huffingtonpost.com/taste/", - "http://www.huffingtonpost.com/tavis-smiley", - "http://www.huffingtonpost.com/tavis-smiley/", - "http://www.huffingtonpost.com/tavis-smiley/my-conversation-with-isaiah-washington-on-black-identity_b_7059306.html", - "http://www.huffingtonpost.com/tech/", - "http://www.huffingtonpost.com/technology/", - "http://www.huffingtonpost.com/tedweekends/", - "http://www.huffingtonpost.com/teen/", - "http://www.huffingtonpost.com/terms.html", - "http://www.huffingtonpost.com/theworldpost/", - "http://www.huffingtonpost.com/travel/", - "http://www.huffingtonpost.com/tv/", - "http://www.huffingtonpost.com/users/logout/?referer=%2F", - "http://www.huffingtonpost.com/users/preferences/", - "http://www.huffingtonpost.com/valerie-plame-wilson", - "http://www.huffingtonpost.com/valerie-plame-wilson/", - "http://www.huffingtonpost.com/webslices/?v=home", - "http://www.huffingtonpost.com/weddings/", - "http://www.huffingtonpost.com/weird-news/", - "http://www.huffingtonpost.com/william-hartung", - "http://www.huffingtonpost.com/william-hartung/", - "http://www.huffingtonpost.com/william-hartung/on-pentagon-spending-will_b_7061698.html", - "http://www.huffingtonpost.com/women/", - "http://www.huffingtonpost.com/world/", - "http://www.ibtimes.com/jeb-bushs-administration-steered-florida-pension-money-george-w-bushs-fundraisers-1880592", - "http://www.imdb.com/", - "http://www.imdb.com/board/bd0000088/thread/242355070?ref_=hm_poll_lk1", - "http://www.imdb.com/imdbpicks/imdbtv-weekly-picks?ref_=hm_hm_tvpks_hd", - "http://www.imdb.com/imdbpicks/imdbtv-weekly-picks?ref_=hm_hm_tvpks_sm", - "http://www.imdb.com/list/ls002595589/?ref_=hm_aiv_hd", - "http://www.imdb.com/list/ls002595589/?ref_=hm_aiv_sm", - "http://www.imdb.com/poll/?ref_=hm_poll_mp", - "http://www.imdb.com/seen/ls076901727/?ref_=hm_poll_lk2", - "http://www.imdb.com/title/tt4120544/synopsis?ref_=hm_tvr_lk2", - "http://www.imdb.com/title/tt4260872/synopsis?ref_=hm_tvr_lk3", - "http://www.imdb.com/title/tt4294382/?ref_=hm_tvr_lk1", - "http://www.imdb.com/title/tt4294382/synopsis?ref_=hm_tvr_i_1", - "http://www.independent.co.uk/news/", - "http://www.instagram.com/dailymotion", - "http://www.instapundit.com/", - "http://www.juancole.com/", - "http://www.junglee.com/", - "http://www.kcrw.com/news/programs/lr", - "http://www.kottke.org/", - "http://www.latimes.com/", - "http://www.linkedin.com/today/online.wsj.com", - "http://www.linktv.org/mosaic/", - "http://www.look.com/", - "http://www.marginalrevolution.com/", - "http://www.marketwatch.com/Game/", - "http://www.mcclatchydc.com/", - "http://www.mediaite.com/", - "http://www.motherjones.com/", - "http://www.moviefone.com/", - "http://www.msn.com/", - "http://www.msnbc.com/maddowblog", - "http://www.myhabit.com/", - "http://www.nationaljournal.com/", - "http://www.nationaljournal.com/columns/political-connections", - "http://www.nationalreview.com/corner", - "http://www.nbcnews.com/", - "http://www.ndnblog.com", - "http://www.newrepublic.com/", - "http://www.newsmax.com/", - "http://www.newsweek.com", - "http://www.newsy.com/", - "http://www.newyorker.com/", - "http://www.npr.org/", - "http://www.nydailynews.com/", - "http://www.nydailynews.com/topics/Stanley+Crouch", - "http://www.nytimes.com/", - "http://www.nytimes.com/politics/first-draft/2015/04/14/christie-blames-trusting-nature-for-bridge-scandal/", - "http://www.observer.com/", - "http://www.offthebus.org", - "http://www.opednews.com/", - "http://www.pandagon.net/", - "http://www.pbs.org/newshour/", - "http://www.people.com/people", - "http://www.people.com/people/gallery/0,,20911186,00.html?xid=CNNApril16", - "http://www.people.com/people/gallery/0,,20911200,00.html?xid=CNNApril2", - "http://www.people.com/people/gallery/0,,20911278,00.html?xid=CNNApril7", - "http://www.peoplestylewatch.com/people/stylewatch/gallery/0,,20772704,00.html?xid=CNNApril9", - "http://www.politico.com/", - "http://www.propublica.org/", - "http://www.publicintegrity.org/", - "http://www.rawstory.com", - "http://www.realtor.com", - "http://www.reuters.com/", - "http://www.rollcall.com/", - "http://www.rollingstone.com/", - "http://www.salon.com/", - "http://www.sbnation.com/nfl-mock-draft/2015/4/14/8408341/2015-nfl-draft-trades-rams-broncos-marcus-mariota", - "http://www.seeingtheforest.com/", - "http://www.sfgate.com/", - "http://www.shopbop.com/welcome", - "http://www.slate.com/", - "http://www.slate.com/blogs/weigel.html", - "http://www.soap.com/", - "http://www.subscribe.wsj.com/getweekendnow?mod=WSJ_footer", - "http://www.suntimes.com/", - "http://www.talkingpointsmemo.com/", - "http://www.talkleft.com/", - "http://www.taylormarsh.com/", - "http://www.techcrunch.com", - "http://www.ted.com/", - "http://www.telegraph.co.uk/", - "http://www.tenmarks.com/", - "http://www.thatminoritything.com/", - "http://www.theatlantic.com/", - "http://www.theatlantic.com/james-fallows/", - "http://www.theglobeandmail.com/", - "http://www.thenation.com/", - "http://www.thenation.com/authors/eric-alterman", - "http://www.thenation.com/blogs/thebeat/", - "http://www.theroot.com", - "http://www.theyoungturks.com/", - "http://www.thismodernworld.com/", - "http://www.time.com/time/?xid=huffpo-direct", - "http://www.tmz.com", - "http://www.today.com/food/lostandhungry-sorted-teams-today-find-best-food-america-t14671?cid=par-huffingtonpost", - "http://www.tomdispatch.com/", - "http://www.tripadvisor.com/hotelhighlight?geo=45963&m=21194", - "http://www.tripadvisor.com/smartdeals?geo=186338&m=21194", - "http://www.tripadvisor.com/smartdeals?geo=34438&m=21194", - "http://www.tripadvisor.com/smartdeals?geo=60763&m=21194", - "http://www.tripadvisor.com/smartdeals?geo=60982&m=21194", - "http://www.trulia.com/?ecampaign=partner_cnn_home_search", - "http://www.trulia.com/?ecampaign=partner_cnn_home_title", - "http://www.trulia.com/for_rent?ecampaign=partner_cnn_rent", - "http://www.trulia.com/rent_vs_buy?ecampaign=partner_cnn_rentvbuy", - "http://www.trulia.com/sell?ts=CNN&tscamp=home_page_sell&ecampaign=partner_cnn_sell", - "http://www.trulia.com?ecampaign=partner_cnn_home_moving", - "http://www.truthdig.com/", - "http://www.turner.com", - "http://www.turner.com/careers", - "http://www.twitter.com/DailymotionUSA", - "http://www.usatoday.com/", - "http://www.usnews.com/news/blogs/washington-whispers", - "http://www.vanityfair.com/", - "http://www.vanityfair.com/online/wolcott", - "http://www.vinemarket.com/", - "http://www.vox.com/", - "http://www.vox.com/2015/4/14/8389515/iran-war", - "http://www.vox.com/2015/4/14/8410679/gender-wage-gap-retirement", - "http://www.wag.com/", - "http://www.washingtonmonthly.com/", - "http://www.washingtonpost.com/", - "http://www.washingtonpost.com/blogs/wonkblog/", - "http://www.washingtonpost.com/ej-dionne-jr/2011/02/24/ABhJNkM_page.html", - "http://www.washingtonpost.com/wp-dyn/content/linkset/2005/03/24/LI2005032402294.html", - "http://www.washingtontimes.com/", - "http://www.wired.com/dangerroom/", - "http://www.wired.com/threatlevel/", - "http://www.wsj.com/", - "http://www.wsj.com/ http://markets.wsj.com/us", - "http://www.wsj.com/#next", - "http://www.wsj.com/#prev", - "http://www.wsj.com/#top", - "http://www.wsj.com/10point", - "http://www.wsj.com/?_wsjregion=na,us&_homepage=/home/us", - "http://www.wsj.com/?mod=WSJ_hpp_videohome_1", - "http://www.wsj.com/?mod=WSJ_hpp_videohome_2", - "http://www.wsj.com/?mod=WSJ_hpp_videohome_3", - "http://www.wsj.com/?mod=WSJ_hpp_videohome_top", - "http://www.wsj.com/americas", - "http://www.wsj.com/articles/a-changing-nicaragua-attracts-resort-investor-1429027235?mod=WSJ_hpp_MIDDLE_Video_second", - "http://www.wsj.com/articles/a-churchs-light-inspires-a-jewelry-designer-from-afar-1429036012?mod=WSJ_hp_EditorsPicks", - "http://www.wsj.com/articles/a-consumer-drone-pioneer-were-learning-as-we-go-1428511868?mod=WSJ_hpp_sections_smallbusiness", - "http://www.wsj.com/articles/a-look-at-the-tax-year-2015-1428895367?mod=WSJ_hpp_sections_yourmoney", - "http://www.wsj.com/articles/a-new-jersey-home-that-doubles-as-a-resort-1429023305?mod=WSJ_hpp_sections_realestate", - "http://www.wsj.com/articles/a-to-be-renovated-westchester-house-is-listing-for-29-5-million-1428605768?mod=WSJ_hpp_sections_realestate", - "http://www.wsj.com/articles/after-two-years-new-york-baccarat-condo-sells-for-19-75-million-1428607165?mod=WSJ_hpp_sections_realestate", - "http://www.wsj.com/articles/alibaba-tencent-alumni-fuel-chinas-startup-success-1429028237?mod=WSJ_hp_EditorsPicks", - "http://www.wsj.com/articles/alibaba-tencent-alumni-fuel-chinas-startup-success-1429028237?mod=WSJ_hpp_sections_business", - "http://www.wsj.com/articles/annoying-things-donors-do-that-nonprofits-wish-they-would-stop-1428894145", - "http://www.wsj.com/articles/apple-buys-israeli-camera-technology-company-linx-1429037790#articleTabs%3Dcomments", - "http://www.wsj.com/articles/apple-buys-israeli-camera-technology-company-linx-1429037790?mod=WSJ_hpp_sections_tech", - "http://www.wsj.com/articles/apple-buys-israeli-camera-technology-company-linx-1429037790?mod=trending_now_10", - "http://www.wsj.com/articles/at-t-sues-to-overturn-fccs-net-neutrality-rules-1429052166?mod=WSJ_hp_LEFTWhatsNewsCollection", - "http://www.wsj.com/articles/atlantas-groundbreaking-discovery-we-have-an-nba-team-1428940903?mod=WSJ_hpp_sections_sports", - "http://www.wsj.com/articles/avon-explores-strategic-alternatives-1429030371?mod=WSJ_hp_LEFTWhatsNewsCollection", - "http://www.wsj.com/articles/california-water-supplier-cuts-summer-deliveries-1429044013?mod=WSJ_hpp_MIDDLENexttoWhatsNewsFifth", - "http://www.wsj.com/articles/californias-water-woes-are-priceless-1429051903", - "http://www.wsj.com/articles/castleton-emerges-as-leading-bidder-for-morgan-stanley-oil-business-1429046478?mod=WSJ_hpp_sections_markets", - "http://www.wsj.com/articles/china-expands-islands-in-disputed-waters-photos-show-1429011466?mod=WSJ_hpp_sections_world", - "http://www.wsj.com/articles/chinese-drone-maker-dji-in-talks-to-raise-funding-at-valuation-of-10-billion-1429050685?mod=WSJ_hpp_MIDDLENexttoWhatsNewsThird", - "http://www.wsj.com/articles/christie-to-call-for-raising-age-for-social-security-cutting-benefit-for-some-seniors-1429018212#articleTabs%3Dcomments", - "http://www.wsj.com/articles/christie-to-call-for-raising-age-for-social-security-cutting-benefit-for-some-seniors-1429018212?mod=WSJ_hpp_sections_newyork", - "http://www.wsj.com/articles/christie-to-call-for-raising-age-for-social-security-cutting-benefit-for-some-seniors-1429018212?mod=trending_now_2", - "http://www.wsj.com/articles/citigroups-asia-pacific-head-stephen-bird-to-run-consumer-bank-1428941075?mod=WSJ_hpp_sections_management", - "http://www.wsj.com/articles/digital-music-sales-overtake-cds-for-first-time-1429034467?mod=WSJ_hp_EditorsPicks", - "http://www.wsj.com/articles/digital-music-sales-overtake-cds-for-first-time-1429034467?mod=WSJ_hpp_sections_business", - "http://www.wsj.com/articles/does-your-whole-home-need-antivirus-now-1429036789?mod=WSJ_hpp_MIDDLENexttoWhatsNewsThird", - "http://www.wsj.com/articles/dont-overlook-netflixs-bigger-picture-ahead-of-the-tape-1429036988?mod=WSJ_hpp_sections_markets", - "http://www.wsj.com/articles/energy-future-files-42-billion-chapter-11-reorganization-plan-1429018731?mod=WSJ_hp_LEFTWhatsNewsCollection", - "http://www.wsj.com/articles/eu-to-file-antitrust-charges-against-google-1429039881#articleTabs%3Dcomments", - "http://www.wsj.com/articles/eu-to-file-antitrust-charges-against-google-1429039881?mod=WSJ_hp_LEFTTopStories", - "http://www.wsj.com/articles/eu-to-file-antitrust-charges-against-google-1429039881?mod=trending_now_9", - "http://www.wsj.com/articles/ex-educator-accepts-deal-in-atlanta-cheating-case-1429025212?mod=WSJ_hpp_MIDDLENexttoWhatsNewsFifth", - "http://www.wsj.com/articles/extreme-closet-makeover-1429028352?mod=WSJ_hpp_MIDDLE_Video_second", - "http://www.wsj.com/articles/fare-increase-of-9-proposed-for-nj-transit-1429025661?mod=WSJ_hpp_sections_newyork", - "http://www.wsj.com/articles/for-duponts-ceo-high-stakes-vote-looms-1428951201?mod=WSJ_hpp_sections_management", - "http://www.wsj.com/articles/french-government-weighs-in-on-nokia-alcatel-lucent-deal-1429007493", - "http://www.wsj.com/articles/from-kale-to-chia-plot-the-arc-of-a-food-fad-1429034489#articleTabs%3Dcomments", - "http://www.wsj.com/articles/from-kale-to-chia-plot-the-arc-of-a-food-fad-1429034489?mod=WSJ_hp_EditorsPicks", - "http://www.wsj.com/articles/from-kale-to-chia-plot-the-arc-of-a-food-fad-1429034489?mod=WSJ_hpp_sections_lifestyle", - "http://www.wsj.com/articles/from-kale-to-chia-plot-the-arc-of-a-food-fad-1429034489?mod=trending_now_7", - "http://www.wsj.com/articles/germanys-rising-wages-bode-well-for-global-economy-1428861139?mod=WSJ_hpp_sections_careerjournal", - "http://www.wsj.com/articles/gm-seeks-longer-term-supplier-contracts-in-bid-to-cut-costs-1429046498?mod=WSJ_hp_LEFTWhatsNewsCollection", - "http://www.wsj.com/articles/good-mental-health-away-from-home-starts-before-college-1428944477#articleTabs%3Dcomments", - "http://www.wsj.com/articles/good-mental-health-away-from-home-starts-before-college-1428944477?mod=trending_now_3", - "http://www.wsj.com/articles/google-may-offer-new-way-to-target-ads-1429044389?mod=WSJ_hpp_MIDDLENexttoWhatsNewsThird", - "http://www.wsj.com/articles/hillary-and-the-liberal-way-of-lying-1428968021#articleTabs%3Dcomments", - "http://www.wsj.com/articles/hillary-and-the-liberal-way-of-lying-1428968021?mod=trending_now_1", - "http://www.wsj.com/articles/hillary-clinton-vows-campaign-finance-fix-1429051307?mod=WSJ_hppMIDDLENexttoWhatsNewsSecond", - "http://www.wsj.com/articles/how-to-catch-a-rocket-with-a-helicopter-1429055300?mod=WSJ_hp_RightTopStories", - "http://www.wsj.com/articles/ibm-positions-itself-as-large-broker-of-health-data-1428961227?mod=WSJ_hpp_sections_health", - "http://www.wsj.com/articles/imf-slowing-emerging-market-growth-is-sapping-global-economic-prospects-1429016407?mod=WSJ_hp_LEFTWhatsNewsCollection", - "http://www.wsj.com/articles/intel-reports-3-rise-in-earnings-1429042439?mod=WSJ_hpp_sections_tech", - "http://www.wsj.com/articles/investors-hunt-bargains-in-european-corporate-bonds-1429033188?mod=WSJ_hpp_sections_markets", - "http://www.wsj.com/articles/iran-foreign-minister-javad-zarif-puts-forward-peace-plan-for-yemen-1429006525?mod=WSJ_hpp_sections_world", - "http://www.wsj.com/articles/j-p-morgan-chases-wells-fargos-profitability-heard-on-the-street-1429040256", - "http://www.wsj.com/articles/japan-skirts-immigration-debate-by-offering-internships-to-foreigners-1429049533?mod=WSJ_hpp_sections_world", - "http://www.wsj.com/articles/jet-blue-wants-to-get-into-hotel-business-at-jfks-former-twa-terminal-1429035857?mod=WSJ_hpp_MIDDLE_Video_second", - "http://www.wsj.com/articles/justice-department-charges-former-export-import-bank-official-with-bribery-1429050539?mod=WSJ_hpp_sections_news", - "http://www.wsj.com/articles/kenyan-money-transfer-ban-puts-strain-on-somalis-1429053973?mod=WSJ_hpp_MIDDLE_Video_Top", - "http://www.wsj.com/articles/los-angeles-dodgers-turn-to-technology-in-hopes-of-engaging-fans-1429040649?mod=WSJ_hpp_MIDDLENexttoWhatsNewsThird", - "http://www.wsj.com/articles/lynda-com-a-60-year-old-earns-internet-glory-1428625176?mod=WSJ_hpp_sections_careerjournal", - "http://www.wsj.com/articles/lynda-com-a-60-year-old-earns-internet-glory-1428625176?mod=WSJ_hpp_sections_smallbusiness", - "http://www.wsj.com/articles/machinists-may-cancel-vote-on-unionizing-boeing-plant-in-south-carolina-1429043870?mod=WSJ_hp_LEFTWhatsNewsCollection", - "http://www.wsj.com/articles/matomy-media-to-acquire-70-of-avenlo-1429052401?mod=WSJ_hp_LEFTWhatsNewsCollection", - "http://www.wsj.com/articles/mogadishu-ukraine-hillary-china-wsj-photos-of-the-day-1429045997", - "http://www.wsj.com/articles/nba-playoff-chase-it-all-comes-down-to-this-1429042343?mod=WSJ_hpp_sections_sports", - "http://www.wsj.com/articles/new-jersey-gov-christie-calls-for-social-security-cuts-1429054912?mod=WSJ_hppMIDDLENexttoWhatsNewsSecond", - "http://www.wsj.com/articles/nokia-in-talks-to-buy-alcatel-lucent-1428996832?mod=WSJ_hp_LEFTWhatsNewsCollection", - "http://www.wsj.com/articles/nokia-looks-to-reinvent-itself-yet-again-1429023574", - "http://www.wsj.com/articles/obama-to-remove-cuba-from-terror-list-1429040182?mod=WSJ_hp_LEFTTopStories", - "http://www.wsj.com/articles/obamas-one-man-nuclear-deal-1429054186", - "http://www.wsj.com/articles/obamas-one-man-nuclear-deal-1429054186?mod=WSJ_hpp_sections_opinion", - "http://www.wsj.com/articles/oil-layoffs-hit-100-000-and-counting-1429055740?mod=WSJ_hp_LEFTTopStories", - "http://www.wsj.com/articles/one-way-to-get-unstuck-and-move-up-all-you-have-to-do-is-ask-1429037179?mod=WSJ_hpp_MIDDLE_Video_Third", - "http://www.wsj.com/articles/p-g-ceo-lafley-lays-groundwork-for-exit-1428972027?mod=WSJ_hpp_sections_management", - "http://www.wsj.com/articles/photos-drawings-by-child-victims-of-boko-haram-attacks-1428958782", - "http://www.wsj.com/articles/police-arrest-suspect-in-north-carolina-campus-shooting-1429010542?mod=WSJ_hpp_sections_news", - "http://www.wsj.com/articles/regulators-call-for-short-term-loan-changes-to-handle-too-big-to-fail-1429051454?mod=WSJ_hp_LEFTWhatsNewsCollection", - "http://www.wsj.com/articles/reserve-deputy-in-oklahoma-police-shooting-booked-for-manslaughter-1429037783?mod=WSJ_hpp_sections_news", - "http://www.wsj.com/articles/sec-reaches-settlement-with-former-freddie-mac-executives-1429044796?mod=WSJ_hp_LEFTWhatsNewsCollection", - "http://www.wsj.com/articles/senate-panel-nears-compromise-on-iran-nuclear-deal-1429026751#articleTabs%3Dcomments", - "http://www.wsj.com/articles/senate-panel-nears-compromise-on-iran-nuclear-deal-1429026751?mod=WSJ_hp_LEFTTopStories", - "http://www.wsj.com/articles/senate-panel-nears-compromise-on-iran-nuclear-deal-1429026751?mod=trending_now_5", - "http://www.wsj.com/articles/spacex-rocket-fails-to-survive-landing-1429045616#articleTabs%3Dcomments", - "http://www.wsj.com/articles/spacex-rocket-fails-to-survive-landing-1429045616?mod=trending_now_4", - "http://www.wsj.com/articles/teen-years-are-a-window-of-opportunity-to-learn-empathy-1429051107?mod=WSJ_hpp_MIDDLE_Video_Third", - "http://www.wsj.com/articles/the-benefit-of-good-financial-habits-learned-early-1428894139", - "http://www.wsj.com/articles/the-best-or-worst-moment-to-make-a-big-change-1429044087?mod=WSJ_hp_RightTopStories", - "http://www.wsj.com/articles/the-cia-needs-an-iran-team-b-1429052586", - "http://www.wsj.com/articles/the-cia-needs-an-iran-team-b-1429052586?mod=WSJ_hpp_sections_opinion", - "http://www.wsj.com/articles/the-hillary-pay-ratio-1429054250", - "http://www.wsj.com/articles/the-hillary-pay-ratio-1429054250?mod=WSJ_hpp_sections_opinion", - "http://www.wsj.com/articles/these-tax-collectors-say-few-understand-their-passion-1429030555?mod=WSJ_hp_EditorsPicks", - "http://www.wsj.com/articles/u-s-could-eliminate-net-energy-imports-by-2030-1429037457?mod=WSJ_hpp_MIDDLENexttoWhatsNewsFifth", - "http://www.wsj.com/articles/u-s-stock-futures-trade-little-changed-1429013691?mod=WSJ_hp_LEFTWhatsNewsCollection", - "http://www.wsj.com/articles/u-s-tech-giants-double-down-in-europe-1429046792?mod=WSJ_hpp_sections_business", - "http://www.wsj.com/articles/wall-street-rebounds-for-banks-in-first-quarter-1429038112?mod=WSJ_hp_LEFTWhatsNewsCollection", - "http://www.wsj.com/articles/webs-most-maniacal-bargain-hunters-1428619524?mod=WSJ_hpp_sections_smallbusiness", - "http://www.wsj.com/articles/what-parents-can-do-to-help-preemies-1428940972#articleTabs%3Dcomments", - "http://www.wsj.com/articles/what-parents-can-do-to-help-preemies-1428940972?mod=WSJ_hpp_sections_lifestyle", - "http://www.wsj.com/articles/what-parents-can-do-to-help-preemies-1428940972?mod=trending_now_8", - "http://www.wsj.com/articles/where-luxury-homes-sell-the-fastest-1429028433?mod=WSJ_hpp_MIDDLE_Video_second", - "http://www.wsj.com/articles/who-will-rule-the-nhl-now-1429030826?mod=WSJ_hpp_MIDDLENexttoWhatsNewsForth", - "http://www.wsj.com/articles/why-masters-champion-jordan-spieth-hired-a-former-schoolteacher-as-his-caddie-1428881077#articleTabs%3Dcomments", - "http://www.wsj.com/articles/why-masters-champion-jordan-spieth-hired-a-former-schoolteacher-as-his-caddie-1428881077?mod=trending_now_6", - "http://www.wsj.com/articles/wreck-of-migrant-vessel-headed-to-italy-leaves-up-to-400-dead-1429046306?mod=WSJ_hpp_MIDDLE_Video_Top", - "http://www.wsj.com/articles/youre-not-getting-a-pay-raise-youre-getting-a-money-management-class-1428423285?mod=WSJ_hpp_sections_careerjournal", - "http://www.wsj.com/articles/zimmer-extends-termination-date-for-biomet-deal-1428961625?mod=WSJ_hpp_sections_health", - "http://www.wsj.com/asia?_wsjregion=asia&_homepage=/home/asia", - "http://www.wsj.com/europe?_wsjregion=europe&_homepage=/home/europe", - "http://www.wsj.com/india?_wsjregion=asia,india&_homepage=/home/india", - "http://www.wsj.com/itp?mod=WSJ_formfactor", - "http://www.wsj.com/maketime", - "http://www.wsj.com/mdc/public/npage/2_3023_creditdervs.html?mod=topnav_2_3000", - "http://www.wsj.com/mdc/public/page/marketsdata.html", - "http://www.wsj.com/mdc/public/page/mdc_bonds.html", - "http://www.wsj.com/mdc/public/page/mdc_commodities.html", - "http://www.wsj.com/mdc/public/page/mdc_currencies.html", - "http://www.wsj.com/mdc/public/page/mdc_international.html", - "http://www.wsj.com/mdc/public/page/mdc_us_stocks.html", - "http://www.wsj.com/news/politics", - "http://www.wsj.com/news/technology", - "http://www.wsj.com/news/technology?mod=WSJ_hpp_sections_tech", - "http://www.wsj.com/news/technology?mod=WSJ_topnav_tech_main", - "http://www.wsj.com/page/columnists.html?mod=WSJ_footer", - "http://www.wsj.com/portuguese", - "http://www.wsj.com/public/page/archive.html", - "http://www.wsj.com/public/page/cfo-journal.html?mod=WSJ_hpp_sections_cfo", - "http://www.wsj.com/public/page/cio-journal.html?mod=WSJ_hpp_sections_cio", - "http://www.wsj.com/public/page/cookie-policy.html?mod=WSJ_footer", - "http://www.wsj.com/public/page/cookie-policy.html?mod=WSJ_footer#cookies_advertising", - "http://www.wsj.com/public/page/copyright_policy.html?mod=WSJ_footer", - "http://www.wsj.com/public/page/data-policy.html?mod=WSJ_footer", - "http://www.wsj.com/public/page/designtech-wsjModuleHome.html?mod=WSJ_footer", - "http://www.wsj.com/public/page/email-setup.html", - "http://www.wsj.com/public/page/email-setup.html?mod=WSJ_footer", - "http://www.wsj.com/public/page/guides.html?mod=WSJ_footer", - "http://www.wsj.com/public/page/journal-report-wealth.html", - "http://www.wsj.com/public/page/management.html", - "http://www.wsj.com/public/page/management.html?mod=WSJ_hpp_sections_management", - "http://www.wsj.com/public/page/management.html?mod=WSJ_topnav_management_main", - "http://www.wsj.com/public/page/new-york-main.html", - "http://www.wsj.com/public/page/new-york-main.html?mod=WSJ_hpp_sections_newyork", - "http://www.wsj.com/public/page/new-york-main.html?mod=WSJ_topnav_ny_main", - "http://www.wsj.com/public/page/news-business-us.html", - "http://www.wsj.com/public/page/news-business-us.html?mod=WSJ_hpp_sections_business", - "http://www.wsj.com/public/page/news-business-us.html?mod=WSJ_topnav_business_main", - "http://www.wsj.com/public/page/news-career-jobs.html?mod=WSJ_hpp_sections_careerjournal", - "http://www.wsj.com/public/page/news-financial-markets-stock.html", - "http://www.wsj.com/public/page/news-financial-markets-stock.html?mod=WSJ_hpp_sections_markets", - "http://www.wsj.com/public/page/news-financial-markets-stock.html?mod=WSJ_topnav_markets_main", - "http://www.wsj.com/public/page/news-global-world.html", - "http://www.wsj.com/public/page/news-global-world.html?mod=WSJ_hpp_sections_world", - "http://www.wsj.com/public/page/news-global-world.html?mod=WSJ_topnav_world_main", - "http://www.wsj.com/public/page/news-health-industry.html?mod=WSJ_hpp_sections_health", - "http://www.wsj.com/public/page/news-interactive-features-trends.html?mod=WSJ_footer", - "http://www.wsj.com/public/page/news-lifestyle-arts-entertainment.html", - "http://www.wsj.com/public/page/news-lifestyle-arts-entertainment.html?mod=WSJ_hpp_sections_lifestyle", - "http://www.wsj.com/public/page/news-lifestyle-arts-entertainment.html?mod=WSJ_topnav_lifeculture_main", - "http://www.wsj.com/public/page/news-opinion-commentary.html", - "http://www.wsj.com/public/page/news-opinion-commentary.html?mod=WSJ_hpp_sections_opinion", - "http://www.wsj.com/public/page/news-opinion-commentary.html?mod=WSJ_topnav_opinion_main", - "http://www.wsj.com/public/page/news-personal-finance.html", - "http://www.wsj.com/public/page/news-personal-finance.html?mod=WSJ_hpp_sections_yourmoney", - "http://www.wsj.com/public/page/news-personal-finance.html?mod=WSJ_topnav_yourmoney_main", - "http://www.wsj.com/public/page/news-real-estate-homes.html", - "http://www.wsj.com/public/page/news-real-estate-homes.html?mod=WSJ_hpp_sections_realestate", - "http://www.wsj.com/public/page/news-real-estate-homes.html?mod=WSJ_topnav_realestate_main", - "http://www.wsj.com/public/page/news-small-business-marketing.html?mod=WSJ_hpp_sections_smallbusiness", - "http://www.wsj.com/public/page/news-sports-scores.html", - "http://www.wsj.com/public/page/news-sports-scores.html?mod=WSJ_hpp_sections_sports", - "http://www.wsj.com/public/page/news-wall-street-heard.html?mod=WSJ_formfactor", - "http://www.wsj.com/public/page/news-world-business.html", - "http://www.wsj.com/public/page/news-world-business.html?mod=WSJ_hpp_sections_news", - "http://www.wsj.com/public/page/news-world-business.html?mod=WSJ_topnav_us_main", - "http://www.wsj.com/public/page/privacy-policy.html?mod=WSJ_footer", - "http://www.wsj.com/public/page/risk-compliance-journal.html?mod=WSJ_hpp_sections_riskcompliance", - "http://www.wsj.com/public/page/subscriber_agreement.html?mod=WSJ_footer", - "http://www.wsj.com/video-center", - "http://www.wsj.com/video/christie-proposes-social-security-cuts/766B079B-59A6-4192-83BE-F9B0376688CC.html?mod=WSJ_hpp_videohome_3", - "http://www.wsj.com/video/do-you-need-antivirus-protection-for-your-whole-home/098D6AB5-74AD-4875-B8D0-439D878B728A.html?mod=WSJ_hpp_videohome_2", - "http://www.wsj.com/video/jerry-seib-clintons-nontraditional-campaign-strategy/397E64AA-3E01-4FC3-B03B-64B1D867CBC2.html", - "http://www.wsj.com/video/volunteer-cops-90-carry-guns-says-new-study/014526ED-61B3-40D6-A1CB-CBFD12BEA0A9.html?mod=WSJ_hpp_videohome_1", - "http://www.wsj.com/video/volunteer-cops-90-carry-guns-says-new-study/014526ED-61B3-40D6-A1CB-CBFD12BEA0A9.html?mod=WSJ_hpp_videohome_top", - "http://www.wsj.com/wsjdlive", - "http://www.wsjdigital.com?mod=WSJ_footer", - "http://www.wsjlocal.com?mod=WSJ_footer", - "http://www.wsjplus.com", - "http://www.wsjwine.com/", - "http://www.wsjwine.com/5941002", - "http://www.yahoo.co.jp/r/c1", - "http://www.yahoo.co.jp/r/c12", - "http://www.yahoo.co.jp/r/c13", - "http://www.yahoo.co.jp/r/c14", - "http://www.yahoo.co.jp/r/c15", - "http://www.yahoo.co.jp/r/c2", - "http://www.yahoo.co.jp/r/c25", - "http://www.yahoo.co.jp/r/c26", - "http://www.yahoo.co.jp/r/c32", - "http://www.yahoo.co.jp/r/c33", - "http://www.yahoo.co.jp/r/c34", - "http://www.yahoo.co.jp/r/c37", - "http://www.yahoo.co.jp/r/c41", - "http://www.yahoo.co.jp/r/c44", - "http://www.yahoo.co.jp/r/c46", - "http://www.yahoo.co.jp/r/c48", - "http://www.yahoo.co.jp/r/c5", - "http://www.yahoo.co.jp/r/c53", - "http://www.yahoo.co.jp/r/c57", - "http://www.yahoo.co.jp/r/c73", - "http://www.yahoo.co.jp/r/c97", - "http://www.yahoo.co.jp/r/cf17", - "http://www.yahoo.co.jp/r/cf20", - "http://www.yahoo.co.jp/r/cf21", - "http://www.yahoo.co.jp/r/cp3", - "http://www.yahoo.co.jp/r/fad", - "http://www.yahoo.co.jp/r/fcgi", - "http://www.yahoo.co.jp/r/fcsr", - "http://www.yahoo.co.jp/r/fdi", - "http://www.yahoo.co.jp/r/fhr", - "http://www.yahoo.co.jp/r/fin", - "http://www.yahoo.co.jp/r/fiv", - "http://www.yahoo.co.jp/r/fpv", - "http://www.yahoo.co.jp/r/fsec", - "http://www.yahoo.co.jp/r/ftm", - "http://www.yahoo.co.jp/r/lst", - "http://www.yahoo.co.jp/r/mht", - "http://www.yahoo.co.jp/r/pbk", - "http://www.yahoo.co.jp/r/pbx", - "http://www.yahoo.co.jp/r/pcl", - "http://www.yahoo.co.jp/r/pclplo", - "http://www.yahoo.co.jp/r/pet", - "http://www.yahoo.co.jp/r/pl1", - "http://www.yahoo.co.jp/r/plh1", - "http://www.yahoo.co.jp/r/plpb", - "http://www.yahoo.co.jp/r/pmllo", - "http://www.yahoo.co.jp/r/pnr", - "http://www.yahoo.co.jp/r/ppml", - "http://www.yandex.ru/?edit=1", - "http://www.yandex.ru/all", - "http://www.yandex.ru/themes", - "http://www.youthradio.org/", - "http://www.youtube.com/user/WSJDigitalNetwork", - "http://www.yoyo.com/", - "http://www.zappos.com/c/top-searches", - "http://wyv1.deviantart.com/art/Bullseye-2-0-353106293", - "http://wyv1.deviantart.com/art/Bullseye-351810171", - "http://xsu.deviantart.com/art/Kiss-17315599", - "http://yabs.yandex.ru/count/6TYBwTAPH4u40WW0gQA0022EiwtQKWLHbGAR1cbQYBW6yGe7feK9YgI4Bskg0QMM66IHlD19P0QJcYW7GgC1hlNeBE7T4xWJ1R41mV__________3yMF3tm9", - "http://yahoo.match.com?trackingid=526100&bannerid=673168", - "http://yahoonews.tumblr.com/MayweatherVsPacquiao", - "http://yandex.ru/images/", - "http://yandex.ru/video", - "http://zen-emma.deviantart.com/", - "http://zhidao.baidu.com/q?ct=17&pn=0&tn=ikaslist&rn=10&word=cow&fr=wwwt", - "http://zhidao.baidu.com/q?ct=17&pn=0&tn=ikaslist&rn=10&word=rice&fr=wwwt", - "http://zwyer.deviantart.com/art/kingpin-rodeo-100244386", - "https://ab.wikipedia.org/", - "https://about.twitter.com/careers", - "https://about.twitter.com/press/brand-assets", - "https://academia.stackexchange.com", - "https://accounts.google.com/ServiceLogin?continue=https%3A%2F%2Fwww.youtube.com%2Fsignin%3Fapp%3Ddesktop%26action_handle_signin%3Dtrue%26next%3D%252F%26hl%3Den%26feature%3Dplaylist&passive=true&uilel=3&hl=en&service=youtube", - "https://accounts.google.com/ServiceLogin?continue=https%3A%2F%2Fwww.youtube.com%2Fsignin%3Fapp%3Ddesktop%26action_handle_signin%3Dtrue%26next%3D%252F%26hl%3Den%26feature%3Dsign_in_promo&passive=true&uilel=3&hl=en&service=youtube", - "https://accounts.google.com/ServiceLogin?hl=en&continue=https://www.google.com/", - "https://ace.wikipedia.org/", - "https://ads.twitter.com/start?ref=gl-tw-tw-twitter-advertise", - "https://advertising.yahoo.com/", - "https://af.wikipedia.org/", - "https://ak.wikipedia.org/", - "https://als.wikipedia.org/", - "https://am.wikipedia.org/", - "https://an.wikipedia.org/", - "https://android.stackexchange.com", - "https://ang.wikipedia.org/", - "https://answers.yahoo.com/", - "https://apple.stackexchange.com", - "https://appworld.blackberry.com/webstore/content/19143/", - "https://ar-ar.facebook.com/", - "https://ar.wikipedia.org/", - "https://arc.wikipedia.org/", - "https://area51.stackexchange.com", - "https://arz.wikipedia.org/", - "https://as.wikipedia.org/", - "https://askubuntu.com", - "https://ast.wikipedia.org/", - "https://auto.yandex.ru/?from=morda&_openstat=yandex_c_b;title;vned5y;earalr5y_c_b_2", - "https://auto.yandex.ru/search?body_type=ALLROAD&year_from=2008&from=morda&_openstat=yandex_c_b;text;vned5y;earalr5y_c_b_2", - "https://av.wikipedia.org/", - "https://ay.wikipedia.org/", - "https://az.wikipedia.org/", - "https://ba.wikipedia.org/", - "https://bar.wikipedia.org/", - "https://bat-smg.wikipedia.org/", - "https://bcl.wikipedia.org/", - "https://be-x-old.wikipedia.org/", - "https://be.wikipedia.org/", - "https://beap.gemini.yahoo.com/mbclk?bv=1.0.0&es=MonthW8GIS_drcBjX3XSzP2AuLEQ.sSvZF9kctnyweQe9NyeVccbhN8pWRmKIZxJaT06ULgYjeTBs7zzm3_0y_.qtPm2iFzDTDviSCVZF4sZm69DOwi3hhY5lDLyoyGa4wvx9NEs8QWVk0wF_4DfSg7tdW0mXyp.myb_H4YB72sTaK6klW4asP1SxrqvEv_ODoZyyjJZ.ckSJPvLebOWWEWm85I4LAauCoojUEx03nCjOz0HrQDAcv_OJuP04DVMm4xqUpm2ckvlQ1eLGMTFz6hL7JY3dr7_prhOBd69Mi.xbtvnhA_FCIn40WMVG50Om1n9Berixti1a8YQnqA.tni5jYfg.ax6LRhNCOafZRqB8kvdQaRgZq8daVjpi0gs2S1L8K0ABR9G0BIRKzCzHklaEzMWQyUHlNSAvnotlsEbIP2wlGZp6J6mc8n0vrNrrOvv9ZMx.TOFAhg30wXGgaSLgggNe4mez8UPVSuvG7ZGhq1zdRe1svV2ldXMGNZC8Bg02C52iGP5d585o68GbXLKbmFp7XzC3P99W5mRBIJySjw-%26lp=", - "https://beap.gemini.yahoo.com/mbclk?bv=1.0.0&es=WCnObs0GIS9nbXiRw_DPZJUTacoX68H6gv8HYk2MB4OUDh2XXkpRVi.V7pMkN_SlTOL1yqFNwIXv8SF_JBVfICXXSZHhJ1FsupqpK93YeDgGinXDeGyUK4Kh5aEhcFFHuW962hi82VoXsX4AMBhCsQrPpWaU5D2htV6r0cEUiwJNBAlyVZk4_LkyZ3NSnqkWcDAZl1fnLSEAMWr1nXtAVBaFfHsU_dT4_l6fyjal2fA.FBQNW0n7SJEspxGEXCpznD.dhurDXm7UmW2d76S2Jb_0Ox80IG4dlbEdiwRNSYqwR83NksS4rqTsXzAbpgAtHelmgsSnFKPnwoLNcHj2UbOvLQHjEYLyShd6_aMSk3NWXnWWhPwINL0Hjc7q1KYayU6DzpoKrvM5aOI8ZHWN6Yd5Q.VpBI4zR8vHzrDfBWbdcT_WeDw3VNgkh44n8_6oflciAt3wsXbjgCgeeu8bxBuBKGVwWKgE8NG54jSX%26lp=", - "https://beap.gemini.yahoo.com/mbclk?bv=1.0.0&es=YBp6pYUGIS9MBDTQtcnaLw549xd7ZhIKYkrlIhITDGMuFu2LikIvMAUjGh.9tMXi7MBkuGnsI2mj6Z3V8yGpNjNCWxFockU3GknFP0GTw74KePGo8o9.DekcnwVzWIi51z34DSBnPVFtlpwOUSI1FcxuOlisu4zSd2IlVtUwma7C3ZqlPBRK7k9DxCBVjK5tuZ.peL_phzOIfgZYVdwuOTmTVjSRrv_Ym9MQ56Ipw9UNvfoaYm4vMzj3R85cAPLlOdxMEkBkwKNg1dpOerqgZLfv9WyNxWwS2EaiMSvDjNzPu6Vn9rolCJjBGqpm_t66Vq41AWkdTMB1IICzevCf6V07pOgsx2pXRBxygcpbLjD5m.9IOQDsD3wyV0sF98ejic9gSZulPPElSiKIRq9zI2kd_LWRcif2hHdKnunzILK3g8j0gpvqCDHlgwTJtTiBngUXjqB6Kg61IfsRfYHnXdAaOgogvT3H1RuH_pX6c9J3FBfutmeHis424_BMcrVH7INMHsPxclxzyLD4tSdmxcML9jhtD.H78AzGOjwFuhxqLpHb2QyxkkGJorpDFGRSgR.SLahbq4NjgZm7OFoWKWpCHQ--%26lp=", - "https://beap.gemini.yahoo.com/mbclk?bv=1.0.0&es=p.a5KLcGIS.8klbqtcJonC1UUNfBl7noU_MGU2obXL3c2yz5.17LQzpbHWp7aoIh9tHMCsszj847uckzoAdBrcagtNpMtKCoB9DUIfRsMoDsAZs2HEeQ_06_MOXtRTlrPrg6b5FK6zpelNd.nIdryR_hraRTlA0OqUnQBqFI68CEjyQDL8yKiisSs.BEnq3GAhdE1V.DqkextmN7bI0Lv0tlf5KNa_LsxdjKs6z7qHXwh3XCznXhzK5MOTK5oiUsuFLoCZpZSC1p2EyxLISV_rQWMLNzzhslM54Agf.q_SNGuG6c7mOKK6TAxnrKFb1ooBpMMOMyu7euCFTsacQ_NHgK3WO5DHS6FgAIFDgWQ8Tn09nHsjuJvM5DoB.g5IymYZjmU27B9pTWT7zUuozlY_N76wFyZy8YFlt48Leut1EM.7OlXZp3OoeW_XE7WtoDxFMKSqozlrEfFGjzF0718zbAkxxu4Uk7WCqbU27jgmud2o.PGvE60piEJRLBj_MNFx2a3ek3hqiwrPewOlvMVDWGpN0kZq1X1TokofHxVjYUHshTBp6ZDkknB4ZkLg--%26lp=", - "https://beap.gemini.yahoo.com/mbclk?bv=1.0.0&es=wb9qsqYGIS_MawyqahMhDJi2q7Dx74gUpsCCOe9C.nUjDzmuxgmAPf_TSHKSBhjIBOF479lJbaIl.yNrx3d8AVK0zhpl5gjgRhgkGQJnycE7vBqQl0pXeoUZKi9dMiEqRpxgLm8nASLlYuWMyf7mJ5bDkEWeoEpveix9HCfX07YNsr55sR7vEGolRP7aujSeLfLqiHrq2ss.YM0.hG_KogbiiqdUKVafoOUHke4qIpLtcVhmd233xeQC1jXvMLOBzRq562RaFYPKNb4.fNK9_DVXBdO_hnjLRucfz9pUeZh4Ak9pTuJJinGqPLwhCvMtpKYK6ogwGHyAjjwXKkTOuUfEMdSEc6MxUppzk095OXBY17ZLzbcPJplWWYayy8n1hCRCo_KqlXwVrsNvoyOeEszFkJbm3JTa9jau2dqQ1RvS9EffDr6XDKItCDXS65241.oXwhGiyAqxAF6kKbfQaXh8tP0yPNt0q5SU4XZTbmYWV1ELKV8mRiZCUbI4DDNyAWOrIm9v1zm6j1wUVmqGMr8J.FUeI76A49Og2MyOtr2crJdGbg25JQxqRu7apm8lcc3eAA0L%26lp=", - "https://bg.wikipedia.org/", - "https://bh.wikipedia.org/", - "https://bi.wikipedia.org/", - "https://bicycles.stackexchange.com", - "https://bjn.wikipedia.org/", - "https://blog.twitter.com", - "https://bm.wikipedia.org/", - "https://bn.wikipedia.org/", - "https://bo.wikipedia.org/", - "https://bpy.wikipedia.org/", - "https://br.wikipedia.org/", - "https://bs.wikipedia.org/", - "https://bug.wikipedia.org/", - "https://business.twitter.com", - "https://bxr.wikipedia.org/", - "https://ca.wikipedia.org/", - "https://calendar.live.com/?WT.mc_id=O16_BingHP", - "https://careers.stackoverflow.com", - "https://careers.stackoverflow.com?utm_source=stackoverflow.com&utm_medium=site-ui&utm_campaign=anon-topbar", - "https://careers.stackoverflow.com?utm_source=stackoverflow.com&utm_medium=site-ui&utm_campaign=multicollider", - "https://careers.yahoo.com", - "https://careers.yahoo.com/", - "https://cbk-zam.wikipedia.org/", - "https://cdo.wikipedia.org/", - "https://ce.wikipedia.org/", - "https://ceb.wikipedia.org/", - "https://celebrity.yahoo.com/", - "https://celebrity.yahoo.com/horoscope/aries/overview-daily-20150414.html", - "https://ch.wikipedia.org/", - "https://chr.wikipedia.org/", - "https://christianity.stackexchange.com", - "https://chy.wikipedia.org/", - "https://ckb.wikipedia.org/", - "https://classifieds.wsj.com/ad/Business-For-Sale-Ads?mod=WSJ_footer", - "https://classifieds.wsj.com/ad/Commercial-Real-Estate-Ads?mod=WSJ_footer", - "https://classifieds.wsj.com/ad/Franchise-For-Sale-Ads?mod=WSJ_footer", - "https://classifieds.wsj.com/ad/Job-Ads?mod=WSJ_footer", - "https://classifieds.wsj.com/ad/Residential-Real-Estate-Ads?mod=WSJ_footer", - "https://co.wikipedia.org/", - "https://commons.wikimedia.org/", - "https://cooking.stackexchange.com", - "https://crh.wikipedia.org/", - "https://cs.wikipedia.org/", - "https://csb.wikipedia.org/", - "https://cstheory.stackexchange.com", - "https://cu.wikipedia.org/", - "https://customercenter.wsj.com/view/contactus.html?mod=WSJ_footer", - "https://customercenter.wsj.com/view/ctdir/contactdirectory.html?mod=WSJ_footer", - "https://cv.wikipedia.org/", - "https://cy.wikipedia.org/", - "https://da.wikipedia.org/", - "https://dba.stackexchange.com", - "https://de-de.facebook.com/", - "https://de.wikipedia.org/", - "https://de.wikipedia.org/wiki/Wikipedia:Sprachen", - "https://dev.twitter.com", - "https://dev.twitter.com/docs/embedded-tweets", - "https://developers.facebook.com/?ref=pf", - "https://diq.wikipedia.org/", - "https://direct.yandex.ru/?from=maintest_ru_razmestitrekl", - "https://disk.yandex.ru/?auth&source=main-nonlogin", - "https://diy.stackexchange.com", - "https://djrc.dowjones.com/?mod=ProdX_MktgHub", - "https://drive.google.com/?tab=wo", - "https://drupal.stackexchange.com", - "https://dsb.wikipedia.org/", - "https://dv.wikipedia.org/", - "https://dz.wikipedia.org/", - "https://edit.yahoo.com/registration?.src=fpctx&.intl=us&.done=https%3A%2F%2Fwww.yahoo.com%2F", - "https://ee.wikipedia.org/", - "https://el.wikipedia.org/", - "https://electronics.stackexchange.com", - "https://eml.wikipedia.org/", - "https://en.wikipedia.org/", - "https://english.stackexchange.com", - "https://eo.wikipedia.org/", - "https://eo.wikipedia.org/wiki/Vikipedio:Internacia_Vikipedio", - "https://es-la.facebook.com/", - "https://es.wikipedia.org/", - "https://espanol.yahoo.com/", - "https://et.wikipedia.org/", - "https://eu.wikipedia.org/", - "https://everything.yahoo.com", - "https://ext.wikipedia.org/", - "https://fa.wikipedia.org/", - "https://faq.dailymotion.com/hc/en-us", - "https://faq.dailymotion.com/hc/en-us/requests/new", - "https://ff.wikipedia.org/", - "https://fi.wikipedia.org/", - "https://firstlook.org/theintercept/", - "https://fiu-vro.wikipedia.org/", - "https://fj.wikipedia.org/", - "https://flickr.com", - "https://fo.wikipedia.org/", - "https://foursquare.com/wsj", - "https://fr-fr.facebook.com/", - "https://fr.wikipedia.org/", - "https://frp.wikipedia.org/", - "https://frr.wikipedia.org/", - "https://fur.wikipedia.org/", - "https://fy.wikipedia.org/", - "https://ga.wikipedia.org/", - "https://gag.wikipedia.org/", - "https://gamedev.stackexchange.com", - "https://games.yahoo.com/", - "https://games.yahoo.com/game/gamepoint-bingo.html?_s_icmp=yahoofrontpage&adid=yahoofrontpageapprecommended&adcamp=yahoofrontpageapp&adop=org&adprop=yahoofrontpage", - "https://games.yahoo.com/game/royal-story.html?_s_icmp=yahoofrontpage&adid=yahoofrontpageapprecommended&adcamp=yahoofrontpageapp&adop=org&adprop=yahoofrontpage", - "https://games.yahoo.com/game/superhero-slots.html?_s_icmp=yahoofrontpage&adid=yahoofrontpageapprecommended&adcamp=yahoofrontpageapp&adop=org&adprop=yahoofrontpage", - "https://games.yahoo.com?_s_icmp=yahoofrontpage&adid=yahoofrontpageappmoregames&adcamp=yahoofrontpageapp&adop=org&adprop=yahoofrontpage", - "https://gaming.stackexchange.com", - "https://gan.wikipedia.org/", - "https://gd.wikipedia.org/", - "https://gis.stackexchange.com", - "https://gl.wikipedia.org/", - "https://glk.wikipedia.org/", - "https://global.factiva.com/du/global.aspx?mod=ProdX_MktgHub", - "https://gn.wikipedia.org/", - "https://got.wikipedia.org/", - "https://graphicdesign.stackexchange.com", - "https://groups.yahoo.com/", - "https://gu.wikipedia.org/", - "https://gv.wikipedia.org/", - "https://ha.wikipedia.org/", - "https://hak.wikipedia.org/", - "https://haw.wikipedia.org/", - "https://he.wikipedia.org/", - "https://help.yahoo.com/l/us/yahoo/helpcentral/", - "https://hi-in.facebook.com/", - "https://hi.wikipedia.org/", - "https://hif.wikipedia.org/", - "https://homes.yahoo.com/", - "https://hr.wikipedia.org/", - "https://hsb.wikipedia.org/", - "https://ht.wikipedia.org/", - "https://hu.wikipedia.org/", - "https://hy.wikipedia.org/", - "https://ia.wikipedia.org/", - "https://id.wikipedia.org/", - "https://id.wsj.com/access/509b1a086458232f6e000002/latest/register_standalone.html", - "https://id.wsj.com/auth/log-in", - "https://ie.wikipedia.org/", - "https://ig.wikipedia.org/", - "https://ik.wikipedia.org/", - "https://ilo.wikipedia.org/", - "https://info.yahoo.com", - "https://info.yahoo.com/legal/us/yahoo/utos/terms/", - "https://info.yahoo.com/privacy/us/yahoo/", - "https://info.yahoo.com/privacy/us/yahoo/relevantads.html", - "https://io.wikipedia.org/", - "https://is.wikipedia.org/", - "https://it-it.facebook.com/", - "https://it.wikipedia.org/", - "https://itunes.apple.com/us/app/huffpost-live/id572584499?ls=1&mt=8", - "https://itunes.apple.com/us/app/the-huffington-post/id306621789?mt=8", - "https://iu.wikipedia.org/", - "https://ja.wikipedia.org/", - "https://ja.wikipedia.org/wiki/Wikipedia:%E5%A4%9A%E8%A8%80%E8%AA%9E%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%A8%E3%81%97%E3%81%A6%E3%81%AE%E3%82%A6%E3%82%A3%E3%82%AD%E3%83%9A%E3%83%87%E3%82%A3%E3%82%A2", - "https://jbo.wikipedia.org/", - "https://judaism.stackexchange.com", - "https://jv.wikipedia.org/", - "https://ka.wikipedia.org/", - "https://kaa.wikipedia.org/", - "https://kab.wikipedia.org/", - "https://kbd.wikipedia.org/", - "https://kg.wikipedia.org/", - "https://ki.wikipedia.org/", - "https://kk.wikipedia.org/", - "https://kl.wikipedia.org/", - "https://km.wikipedia.org/", - "https://kn.wikipedia.org/", - "https://ko-kr.facebook.com/", - "https://ko.wikipedia.org/", - "https://koi.wikipedia.org/", - "https://krc.wikipedia.org/", - "https://ks.wikipedia.org/", - "https://ksh.wikipedia.org/", - "https://ku.wikipedia.org/", - "https://kv.wikipedia.org/", - "https://kw.wikipedia.org/", - "https://ky.wikipedia.org/", - "https://la.wikipedia.org/", - "https://lad.wikipedia.org/", - "https://lb.wikipedia.org/", - "https://lbe.wikipedia.org/", - "https://lez.wikipedia.org/", - "https://lg.wikipedia.org/", - "https://li.wikipedia.org/", - "https://lij.wikipedia.org/", - "https://lmo.wikipedia.org/", - "https://ln.wikipedia.org/", - "https://lo.wikipedia.org/", - "https://login.yahoo.com/config/login?.src=fpctx&.intl=us&.done=https%3A%2F%2Fwww.yahoo.com%2F", - "https://lt.wikipedia.org/", - "https://ltg.wikipedia.org/", - "https://lv.wikipedia.org/", - "https://mai.wikipedia.org/", - "https://mail.google.com/mail/?tab=wm", - "https://mail.yahoo.com?.src=ym&.intl=us", - "https://mail.yandex.ru", - "https://map-bms.wikipedia.org/", - "https://maps.google.com/maps?hl=en&tab=wl", - "https://maps.yahoo.com/", - "https://maps.yandex.ru/", - "https://maps.yandex.ru/?index&ll=43.506343%2C55.219296&spn=22.434082%2C7.001578&z=6&l=map%2Cstv%2Csta&hint=zaglpano", - "https://math.stackexchange.com", - "https://mathematica.stackexchange.com", - "https://mathoverflow.net", - "https://mdf.wikipedia.org/", - "https://media.twitter.com", - "https://messenger.com/", - "https://meta.stackexchange.com", - "https://meta.stackoverflow.com", - "https://meta.wikimedia.org/", - "https://meta.wikimedia.org/wiki/%EC%9C%84%ED%82%A4%EB%B0%B1%EA%B3%BC%EC%9D%98_%EB%AA%A9%EB%A1%9D", - "https://meta.wikimedia.org/wiki/List_of_Wikipedias", - "https://meta.wikimedia.org/wiki/Lista_de_Wikipedias", - "https://meta.wikimedia.org/wiki/Liste_des_Wikip%C3%A9dias", - "https://mg.wikipedia.org/", - "https://mhr.wikipedia.org/", - "https://mi.wikipedia.org/", - "https://min.wikipedia.org/", - "https://mk.wikipedia.org/", - "https://ml.wikipedia.org/", - "https://mn.wikipedia.org/", - "https://mo.wikipedia.org/", - "https://mobile.yahoo.com", - "https://mobile.yahoo.com/yahoo/?src=gta", - "https://money.stackexchange.com", - "https://money.yandex.ru/", - "https://mr.wikipedia.org/", - "https://mrj.wikipedia.org/", - "https://ms.wikipedia.org/", - "https://mt.wikipedia.org/", - "https://music.yahoo.com", - "https://mwl.wikipedia.org/", - "https://my.wikipedia.org/", - "https://my.yahoo.com/?fr=yfp-t-403", - "https://myv.wikipedia.org/", - "https://mzn.wikipedia.org/", - "https://na.wikipedia.org/", - "https://nah.wikipedia.org/", - "https://nap.wikipedia.org/", - "https://nds-nl.wikipedia.org/", - "https://nds.wikipedia.org/", - "https://ne.wikipedia.org/", - "https://new.wikipedia.org/", - "https://news.google.com/nwshp?hl=en&tab=wn", - "https://news.yandex.ru/", - "https://news.yandex.ru/?lang=ru", - "https://news.yandex.ru/USA", - "https://news.yandex.ru/quotes/1.html", - "https://news.yandex.ru/quotes/1006.html", - "https://news.yandex.ru/quotes/2000.html", - "https://news.yandex.ru/quotes/2002.html", - "https://news.yandex.ru/quotes/23.html", - "https://nl.wikipedia.org/", - "https://nn.wikipedia.org/", - "https://no.wikipedia.org/", - "https://nov.wikipedia.org/", - "https://nrm.wikipedia.org/", - "https://nso.wikipedia.org/", - "https://nv.wikipedia.org/", - "https://ny.wikipedia.org/", - "https://oc.wikipedia.org/", - "https://offers.lendingtree.com/splitter/splitter.ashx?id=cnn-bizloan", - "https://office.live.com/start/Excel.aspx?WT.mc_id=O16_BingHP", - "https://office.live.com/start/PowerPoint.aspx?WT.mc_id=O16_BingHP", - "https://office.live.com/start/Word.aspx?WT.mc_id=O16_BingHP", - "https://om.wikipedia.org/", - "https://or.wikipedia.org/", - "https://os.wikipedia.org/", - "https://outlook.com/?WT.mc_id=O16_BingHP?mkt=en-US", - "https://pa.wikipedia.org/", - "https://pag.wikipedia.org/", - "https://pam.wikipedia.org/", - "https://pap.wikipedia.org/", - "https://passport.baidu.com/v2/?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2F", - "https://passport.yandex.ru/passport?mode=restore", - "https://passport.yandex.ru/registration/mail?mode=register&retpath=https://mail.yandex.ru%2F%3Forigin%3Dhome_ru_old&origin=home_ru_old", - "https://pcd.wikipedia.org/", - "https://pdc.wikipedia.org/", - "https://people.live.com/?WT.mc_id=O16_BingHP", - "https://pfl.wikipedia.org/", - "https://photo.stackexchange.com", - "https://physics.stackexchange.com", - "https://pi.wikipedia.org/", - "https://pih.wikipedia.org/", - "https://pl.wikipedia.org/", - "https://pl.wikipedia.org/wiki/Wikipedia:Lista_wersji_j%C4%99zykowych", - "https://play.google.com/?hl=en&tab=w8", - "https://play.google.com/store/apps/details?id=com.huffingtonpost.android", - "https://play.google.com/store/apps/details?id=com.huffingtonpost.android&hl=en", - "https://play.google.com/store/apps/details?id=com.huffingtonpost.android&hl=en_US", - "https://plus.google.com/+youtube", - "https://plus.google.com/116899029375914044550", - "https://plus.google.com/117720626238470886461/posts", - "https://pms.wikipedia.org/", - "https://pnb.wikipedia.org/", - "https://pnt.wikipedia.org/", - "https://pogoda.yandex.ru/mountain-view/", - "https://portfolio.wsj.com/portfolio?mod=wsj_port_mdc", - "https://programmers.stackexchange.com", - "https://ps.wikipedia.org/", - "https://pt-br.facebook.com/", - "https://pt.wikipedia.org/", - "https://qu.wikipedia.org/", - "https://rm.wikipedia.org/", - "https://rmy.wikipedia.org/", - "https://rn.wikipedia.org/", - "https://ro.wikipedia.org/", - "https://roa-rup.wikipedia.org/", - "https://roa-tara.wikipedia.org/", - "https://rpg.stackexchange.com", - "https://ru.wikipedia.org/", - "https://ru.wikipedia.org/wiki/%D0%92%D0%B8%D0%BA%D0%B8%D0%BF%D0%B5%D0%B4%D0%B8%D1%8F:%D0%A1%D0%92", - "https://rue.wikipedia.org/", - "https://rw.wikipedia.org/", - "https://sa.wikipedia.org/", - "https://sah.wikipedia.org/", - "https://salesforce.stackexchange.com", - "https://sc.wikipedia.org/", - "https://scifi.stackexchange.com", - "https://scn.wikipedia.org/", - "https://sco.wikipedia.org/", - "https://screen.yahoo.com", - "https://screen.yahoo.com/", - "https://screen.yahoo.com/live/", - "https://screen.yahoo.com/live/event/bad-religion", - "https://screen.yahoo.com/meghan-trainor-music-videos/bass-live-house-blues-chicago-020038973.html", - "https://screen.yahoo.com/sin-city-saints/episode-7-urine-gods-hands-070100636.html", - "https://sd.wikipedia.org/", - "https://se.wikipedia.org/", - "https://search.yahoo.com/search?cs=bz&p=Tax+deadline&fr=fp-tts-901&fr2=ps&woeid=12587712&fp=1", - "https://search.yahoo.com/search?cs=bz&p=Tax+deadline&fr=fp-tts-901&woeid=12587712&fp=1&fr2=p:fp,m:tn,ct:all,pg:1,stl:crsl", - "https://search.yahoo.com/search?p=Alexis+Roderick&fr=fp-tts-901&fr2=ps&woeid=12587712&fp=1", - "https://search.yahoo.com/search?p=Alexis+Roderick&fr=fp-tts-901&woeid=12587712&fp=1&fr2=p:fp,m:tn,ct:all,pg:1,stl:crsl", - "https://search.yahoo.com/search?p=Anna+Kendrick&fr=fp-tts-901&fr2=ps&woeid=12587712&fp=1", - "https://search.yahoo.com/search?p=Anna+Kendrick&fr=fp-tts-901&woeid=12587712&fp=1&fr2=p:fp,m:tn,ct:all,pg:1,stl:crsl", - "https://search.yahoo.com/search?p=Carly+Rae+Jepsen&fr=fp-tts-901&fr2=ps&woeid=12587712&fp=1", - "https://search.yahoo.com/search?p=Carly+Rae+Jepsen&fr=fp-tts-901&woeid=12587712&fp=1&fr2=p:fp,m:tn,ct:all,pg:1,stl:crsl", - "https://search.yahoo.com/search?p=Chrissy+Teigen&fr=fp-tts-901&fr2=ps&woeid=12587712&fp=1", - "https://search.yahoo.com/search?p=Chrissy+Teigen&fr=fp-tts-901&woeid=12587712&fp=1&fr2=p:fp,m:tn,ct:all,pg:1,stl:crsl", - "https://search.yahoo.com/search?p=Christy+Mack&fr=fp-tts-901&fr2=ps&woeid=12587712&fp=1", - "https://search.yahoo.com/search?p=Christy+Mack&fr=fp-tts-901&woeid=12587712&fp=1&fr2=p:fp,m:tn,ct:all,pg:1,stl:crsl", - "https://search.yahoo.com/search?p=Nina+Dobrev&fr=fp-tts-901&fr2=ps&woeid=12587712&fp=1", - "https://search.yahoo.com/search?p=Nina+Dobrev&fr=fp-tts-901&woeid=12587712&fp=1&fr2=p:fp,m:tn,ct:all,pg:1,stl:crsl", - "https://search.yahoo.com/search?p=Olivia+Munn&fr=fp-tts-901&fr2=ps&woeid=12587712&fp=1", - "https://search.yahoo.com/search?p=Olivia+Munn&fr=fp-tts-901&woeid=12587712&fp=1&fr2=p:fp,m:tn,ct:all,pg:1,stl:crsl", - "https://search.yahoo.com/search?p=Wonder+Woman&fr=fp-tts-901&fr2=ps&woeid=12587712&fp=1", - "https://search.yahoo.com/search?p=Wonder+Woman&fr=fp-tts-901&woeid=12587712&fp=1&fr2=p:fp,m:tn,ct:all,pg:1,stl:crsl", - "https://search.yahoo.com/search?p=Wu-Tang+Clan&fr=fp-tts-901&fr2=ps&woeid=12587712&fp=1", - "https://search.yahoo.com/search?p=Wu-Tang+Clan&fr=fp-tts-901&woeid=12587712&fp=1&fr2=p:fp,m:tn,ct:all,pg:1,stl:crsl", - "https://secure.imdb.com/register-imdb/form-v2?ref_=ft_reg", - "https://secure.imdb.com/register-imdb/form-v2?ref_=nv_usr_reg_2", - "https://security.stackexchange.com", - "https://serverfault.com", - "https://sg.wikipedia.org/", - "https://sh.wikipedia.org/", - "https://sharepoint.stackexchange.com", - "https://shopping.yahoo.com/", - "https://si.wikipedia.org/", - "https://simple.wikipedia.org/", - "https://sk.wikipedia.org/", - "https://skeptics.stackexchange.com", - "https://skydrive.live.com/?gologin=1&WT.mc_id=O16_BingHP", - "https://sl.wikipedia.org/", - "https://sm.wikipedia.org/", - "https://smallbusiness.yahoo.com/?s_fptrough=ysb_acq_fp", - "https://sn.wikipedia.org/", - "https://so.wikipedia.org/", - "https://species.wikimedia.org/", - "https://sprav.yandex.ru/", - "https://sq.wikipedia.org/", - "https://sr.wikipedia.org/", - "https://srn.wikipedia.org/", - "https://ss.wikipedia.org/", - "https://st.wikipedia.org/", - "https://stackapps.com", - "https://stackexchange.com", - "https://stackexchange.com/questions?tab=hot", - "https://stackexchange.com/sites", - "https://stackoverflow.com", - "https://stackoverflow.com/users/login?returnurl=http%3a%2f%2fstackoverflow.com%2f", - "https://stackoverflow.com/users/signup?returnurl=http%3a%2f%2fstackoverflow.com%2f", - "https://stats.stackexchange.com", - "https://stq.wikipedia.org/", - "https://su.wikipedia.org/", - "https://subscribe.wsj.com/hphousead", - "https://superuser.com", - "https://support.google.com/youtube/?hl=en", - "https://support.twitter.com", - "https://support.twitter.com/articles/20170451", - "https://support.twitter.com/articles/20170514", - "https://sv.wikipedia.org/", - "https://sw.wikipedia.org/", - "https://szl.wikipedia.org/", - "https://ta.wikipedia.org/", - "https://te.wikipedia.org/", - "https://tet.wikipedia.org/", - "https://tex.stackexchange.com", - "https://tg.wikipedia.org/", - "https://th.wikipedia.org/", - "https://ti.wikipedia.org/", - "https://tk.wikipedia.org/", - "https://tl.wikipedia.org/", - "https://tn.wikipedia.org/", - "https://to.wikipedia.org/", - "https://tpi.wikipedia.org/", - "https://tr.wikipedia.org/", - "https://travel.stackexchange.com", - "https://ts.wikipedia.org/", - "https://tt.wikipedia.org/", - "https://tum.wikipedia.org/", - "https://tw.wikipedia.org/", - "https://twitter.com/HuffingtonPost", - "https://twitter.com/IMDb", - "https://twitter.com/dpsahoo/status/588051373901512704", - "https://twitter.com/intent/follow?screen_name=dpsahoo", - "https://twitter.com/intent/user?screen_name=NationalDefense", - "https://twitter.com/intent/user?screen_name=StewMagnusonNDM", - "https://twitter.com/intent/user?screen_name=dpsahoo", - "https://twitter.com/signup?context=login", - "https://ty.wikipedia.org/", - "https://tyv.wikipedia.org/", - "https://udm.wikipedia.org/", - "https://ug.wikipedia.org/", - "https://uk.wikipedia.org/", - "https://unix.stackexchange.com", - "https://ur.wikipedia.org/", - "https://ux.stackexchange.com", - "https://uz.wikipedia.org/", - "https://ve.wikipedia.org/", - "https://vec.wikipedia.org/", - "https://vep.wikipedia.org/", - "https://vi.wikipedia.org/", - "https://vi.wikipedia.org/wiki/Wikipedia:Phi%C3%AAn_b%E1%BA%A3n_ng%C3%B4n_ng%E1%BB%AF", - "https://vls.wikipedia.org/", - "https://vo.wikipedia.org/", - "https://wa.wikipedia.org/", - "https://war.wikipedia.org/", - "https://weather.yahoo.com", - "https://weather.yahoo.com/united-states/California/SantaClaraCounty-12587712/", - "https://webapps.stackexchange.com", - "https://webmasters.stackexchange.com", - "https://wikimediafoundation.org/", - "https://wikimediafoundation.org/wiki/Privacy_policy", - "https://wikimediafoundation.org/wiki/Terms_of_Use", - "https://wo.wikipedia.org/", - "https://wordpress.stackexchange.com", - "https://wuu.wikipedia.org/", - "https://www.amazon.com", - "https://www.amazon.com#gw-ftGr-desktop-hero-1", - "https://www.amazon.com#gw-ftGr-desktop-hero-2", - "https://www.amazon.com#gw-ftGr-desktop-hero-3", - "https://www.amazon.com#gw-ftGr-desktop-hero-4", - "https://www.amazon.com#gw-ftGr-desktop-hero-5", - "https://www.amazon.com/", - "https://www.amazon.com/101-Dalmatians-Diamond-Edition-Blu-ray/dp/B00OZLF4AG", - "https://www.amazon.com/AGPtEK%C2%AE-Playback-Lossless-Player-Supports/dp/B00SD18E60", - "https://www.amazon.com/AR-AR383-Electric-Pressure-Washer/dp/B002Z8E52Y", - "https://www.amazon.com/ARRIS-Motorola-SurfBoard-SB6121-DOCSIS/dp/B004XC6GJ0", - "https://www.amazon.com/Amazon-1_US_Email-Gift-Card-Email/dp/B004LLIKVU", - "https://www.amazon.com/Amazon-Kindle-Paperwhite-Special-Offers/dp/B00JG8GOWU", - "https://www.amazon.com/Amazon-W87CUN-Fire-TV-Stick/dp/B00GDQ0RMG", - "https://www.amazon.com/AmazonBasics-Apple-Certified-Lightning-Cable/dp/B00NH12YN0", - "https://www.amazon.com/Annie-HD-Albert-Finney/dp/B009V5KI98", - "https://www.amazon.com/Apple-MC544L-Generation-Discontinued-Manufacturer/dp/B001FA1O18", - "https://www.amazon.com/Apple-ME179LL-Generation-Discontinued-Manufacturer/dp/B0097BEFEU", - "https://www.amazon.com/Apple-classic-160GB-Generation-Player/dp/B001F7AHOG", - "https://www.amazon.com/Apple-iPod-Nano-Generation-MD477LL/dp/B0097BEDTC", - "https://www.amazon.com/Apple-iPod-Touch-16GB-Player/dp/B00LG71NZ2", - "https://www.amazon.com/Apple-shuffle-Space-Generation-NEWEST/dp/B0097BEEW8", - "https://www.amazon.com/Apple-touch-Generation-Discontinued-Manufacturer/dp/B001FA1O0O", - "https://www.amazon.com/BE365-CAM-609-Camelot-Deadbolt/dp/B001COBTBC", - "https://www.amazon.com/Barefoot-HD-Evan-Rachel-Wood/dp/B00JUIZMMY", - "https://www.amazon.com/Batman-Arkham-Knight-PlayStation-4/dp/B00IQCRKT8", - "https://www.amazon.com/Batman-HD-Michael-Keaton/dp/B00A3Z384M", - "https://www.amazon.com/Best-Sellers-Home-Improvement-Hand-Tools/zgbs/hi/551238", - "https://www.amazon.com/Big-Hero-Blu-ray-DVD-Digital/dp/B00O4ZC57I", - "https://www.amazon.com/Black-mini-Clip-Mp3-player/dp/B004S464WM", - "https://www.amazon.com/Brilliant-Flashlight-Waterproof-Shock-Resistant-MAGNETIZED/dp/B00TA2X4MU", - "https://www.amazon.com/Canon-EOS-Rebel-T5-Professional/dp/B00J34YO92", - "https://www.amazon.com/Canon-EOS-T5-Professional-lightweight/dp/B00L3NY180", - "https://www.amazon.com/Canon-LP-E8-Battery-Digital-Cameras/dp/B00393THEK", - "https://www.amazon.com/Canon-PowerShot-Digital-Camera-Black/dp/B00HLDFNKQ", - "https://www.amazon.com/Canon-PowerShot-SX520-16Digital-Stabilized/dp/B00M0QVTOS", - "https://www.amazon.com/Canon-Rebel-EF-S-18-55mm-Digital/dp/B00IB1BTWI", - "https://www.amazon.com/Captain-America-Winter-Soldier-Blu-ray/dp/B0090SI3GQ", - "https://www.amazon.com/Chicka-Boom-Book/dp/1442450703", - "https://www.amazon.com/Cinderella-2-Disc-Blu-ray-DVD-Digital/dp/B00UI5CTE2", - "https://www.amazon.com/Cinderella-Ilene-Woods/dp/B003ZHVJGO", - "https://www.amazon.com/Cowboy-Bebop-Complete-Series-Blu-ray/dp/B00NP06DJE", - "https://www.amazon.com/Currency-Converter/b?ie=UTF8&node=388305011", - "https://www.amazon.com/Dark-Souls-II-Scholar-First-PlayStation/dp/B00Q03M3HY", - "https://www.amazon.com/Fantasy-Remaster-Limited-Edition-playstation-4/dp/B00QU47SJG", - "https://www.amazon.com/Fast-Furious-6-Movie-Collection-Diesel/dp/B00IMYVCA8", - "https://www.amazon.com/Fiio-X1-FiiO-Silver/dp/B00NS3MRKC", - "https://www.amazon.com/Fire-HD-Display-Wi-Fi-GB/dp/B00KC6I06S", - "https://www.amazon.com/Fire-TV-streaming-media-player/dp/B00CX5P8FC", - "https://www.amazon.com/Flashlight-Modes-Torch-Adjustable-Focus/dp/B006E0QAFY", - "https://www.amazon.com/Force-Assisted-Opening-Folding-4-5-Inch/dp/B00FOR2DTU", - "https://www.amazon.com/G-G-Martinsen-Player-Media-Music-accessories-Blue/dp/B00NPTLAFW", - "https://www.amazon.com/G-I-Joe-Retaliation-Bruce-Willis/dp/B00DFFHUUA", - "https://www.amazon.com/Gods-Not-Dead-Kevin-Sorbo/dp/B00LPRKH5U", - "https://www.amazon.com/Godzilla-HD-Matthew-Broderick/dp/B008Y79HE6", - "https://www.amazon.com/Guardians-Galaxy-Blu-ray-3D-Digital/dp/B00N1JQ2UO", - "https://www.amazon.com/Hakko-CHP-170-Stand-off-Construction-21-Degree/dp/B00FZPDG1K", - "https://www.amazon.com/Halo-Master-Chief-Collection-Xbox-One/dp/B00KSQHX1K", - "https://www.amazon.com/Headlamp-Brightness-Headlamps-Batteries-Included/dp/B005FEGYJC", - "https://www.amazon.com/Iain-Sinclair-Design-Cardsharp2-Folding/dp/B006O9V2OY", - "https://www.amazon.com/Ill-Follow-You-Down-HD/dp/B00KMGZWVO", - "https://www.amazon.com/Indiana-Jones-Complete-Adventures-Raiders/dp/B000NQRE9Q", - "https://www.amazon.com/Interstellar-Blu-ray-Matthew-McConaughey/dp/B00SI7GCJK", - "https://www.amazon.com/Into-Woods-1-Disc-Blu-ray-Digital/dp/B00Q7WBFTA", - "https://www.amazon.com/Jack-Reacher-HD-Tom-Cruise/dp/B00BUCXVPI", - "https://www.amazon.com/Jack-Ryan-Shadow-Recruit-HD/dp/B00HZ3C4N6", - "https://www.amazon.com/Jupiter-Ascending-Blu-ray-UltraViolet-Combo/dp/B00K2CHYTQ", - "https://www.amazon.com/Kindle-Glare-Free-Touchscreen-Display-Wi-Fi/dp/B00I15SB16", - "https://www.amazon.com/Kubik-Player-Radio-Expandable-MicroSD/dp/B0041MMMWW", - "https://www.amazon.com/Lonve-Player-Music-Screen-Audio/dp/B00SASFBJE", - "https://www.amazon.com/Lonve-Player-Music-Screen-Audio/dp/B00SASFGF8", - "https://www.amazon.com/Lytro-Light-Field-Camera-16GB/dp/B0099QUUBU", - "https://www.amazon.com/Mario-Kart-8-Nintendo-Wii-U/dp/B00DC7G2W8", - "https://www.amazon.com/Mario-Party-10-Wii-U/dp/B00KWG4HG0", - "https://www.amazon.com/Metal-Gear-Solid-Phantom-Pain-PlayStation/dp/B00JKM06HG", - "https://www.amazon.com/Mortal-Kombat-X-PlayStation-4/dp/B00KOOUVNI", - "https://www.amazon.com/My-Old-Lady-Kevin-Kline/dp/B00S65W70M", - "https://www.amazon.com/Nikon-COOLPIX-Digital-Certified-Refurbished/dp/B00P18BDKC", - "https://www.amazon.com/Nikon-COOLPIX-Digital-Discontinued-Manufacturer/dp/B00HQ4W3OE", - "https://www.amazon.com/Nikon-COOLPIX-Waterproof-Discontinued-Manufacturer/dp/B00IA9LQK6", - "https://www.amazon.com/Nikon-Coolpix-Digital-Camera-Optical/dp/B00LMIKR6Q", - "https://www.amazon.com/Nikon-Coolpix-L330-Digital-Camera/dp/B00HQDBLDO", - "https://www.amazon.com/Nikon-Digital-NIKKOR-18-55mm-3-5-5-6G/dp/B00HQ4W1QE", - "https://www.amazon.com/Nintendo-Wii-Deluxe-Set-Bundle-U/dp/B00MVUKM0A", - "https://www.amazon.com/Outlander-Season-One-Volume/dp/B00RGQ4674", - "https://www.amazon.com/Panasonic-DMC-FZ70-Digital-Optical-Stabilized/dp/B00DY2Y28M", - "https://www.amazon.com/Panasonic-DMC-ZS50K-Travel-Camera-Viewfinder/dp/B00RBG687A", - "https://www.amazon.com/PlayStation-3-500-GB-System/dp/B009DL2TBA", - "https://www.amazon.com/PlayStation-4-Console/dp/B00BGA9WK2", - "https://www.amazon.com/Pok%C3%A9mon-Omega-Ruby-Nintendo-3DS/dp/B00KI2OZ9M", - "https://www.amazon.com/Robocop-HD-Joel-Kinnaman/dp/B00IK590UI", - "https://www.amazon.com/SE-MZ101B-Helping-Hands-Magnifying/dp/B000RB38X8", - "https://www.amazon.com/Samsung-2-5-Inch-Internal-MZ-75E250B-AM/dp/B00OAJ412U", - "https://www.amazon.com/Samsung-GC200-Galaxy-Camera-Touchscreen/dp/B00R3DGKWY", - "https://www.amazon.com/Samsung-Galaxy-S6-Black-Sapphire/dp/B00V5LZUWQ", - "https://www.amazon.com/Samsung-Galaxy-S6-Black-Sapphire/dp/B00V5LZXCS", - "https://www.amazon.com/Samsung-Galaxy-S6-Edge-Platinum/dp/B00V5M0QTC", - "https://www.amazon.com/Samsung-Galaxy-S6-Edge-Platinum/dp/B00V5M0TJ4", - "https://www.amazon.com/Samsung-Galaxy-S6-Edge-Platinum/dp/B00V5M0VV0", - "https://www.amazon.com/Samsung-Galaxy-S6-Edge-Sapphire/dp/B00V5M0J3U", - "https://www.amazon.com/Samsung-Galaxy-S6-Edge-Sapphire/dp/B00V5M0LQ0", - "https://www.amazon.com/Samsung-Galaxy-S6-Edge-Sapphire/dp/B00V7FWZVY", - "https://www.amazon.com/Samsung-Galaxy-S6-Edge-Sapphire/dp/B00V7FX36U", - "https://www.amazon.com/Samsung-Galaxy-S6-Edge-Sapphire/dp/B00V7FY076", - "https://www.amazon.com/Samsung-Galaxy-S6-Edge-Sprint/dp/B00V7FWSY8", - "https://www.amazon.com/Samsung-Galaxy-S6-Edge-Sprint/dp/B00V7FWWA8", - "https://www.amazon.com/Samsung-Galaxy-S6-Edge-White/dp/B00V5M09EY", - "https://www.amazon.com/Samsung-Galaxy-S6-Edge-White/dp/B00V5M0DU4", - "https://www.amazon.com/Samsung-Galaxy-S6-Edge-Wireless/dp/B00V7FY44A", - "https://www.amazon.com/Samsung-Galaxy-S6-Edge-Wireless/dp/B00V7FYD32", - "https://www.amazon.com/Samsung-Galaxy-S6-Gold-Platinum/dp/B00V5M028W", - "https://www.amazon.com/Samsung-Galaxy-S6-Gold-Platinum/dp/B00V5M04OE", - "https://www.amazon.com/Samsung-Galaxy-S6-Platinum-128GB/dp/B00V5M072I", - "https://www.amazon.com/Samsung-Galaxy-S6-Sapphire-Sprint/dp/B00V7FWBZY", - "https://www.amazon.com/Samsung-Galaxy-S6-Sapphire-Sprint/dp/B00V7FWEX8", - "https://www.amazon.com/Samsung-Galaxy-S6-Sapphire-Wireless/dp/B00V7FXCZ2", - "https://www.amazon.com/Samsung-Galaxy-S6-Sapphire-Wireless/dp/B00V7FXLNA", - "https://www.amazon.com/Samsung-Galaxy-S6-Verizon-Wireless/dp/B00V7FXHC0", - "https://www.amazon.com/Samsung-Galaxy-S6-Verizon-Wireless/dp/B00V7FXP5E", - "https://www.amazon.com/Samsung-Galaxy-S6-White-Pearl/dp/B00V5LZNFK", - "https://www.amazon.com/Samsung-Galaxy-S6-White-Pearl/dp/B00V5LZPAI", - "https://www.amazon.com/Samsung-Galaxy-S6-White-Sprint/dp/B00V7FVZ74", - "https://www.amazon.com/Samsung-Galaxy-S6-White-Sprint/dp/B00V7FW4MY", - "https://www.amazon.com/Samsung-WB350F-16-3MP-Digital-Optical/dp/B00HV6KK0G", - "https://www.amazon.com/SanDisk-Player-Screen-MicroSDHC-SDMX24-004G-G46R/dp/B00HCMZ19Y", - "https://www.amazon.com/SanDisk-Sansa-Clip-Player-Black/dp/B002MAPS6W", - "https://www.amazon.com/Schlage-B60N716-Deadbolt-Keyed-Bronze/dp/B0030ZM6JK", - "https://www.amazon.com/Schlage-BE365-PLY-619-Plymouth/dp/B0026SZNW4", - "https://www.amazon.com/Schlage-F10VACC619-Accent-Passage-Nickel/dp/B0007PNP2I", - "https://www.amazon.com/Schlage-F170-LAT-619-Latitude/dp/B0046ZRI5A", - "https://www.amazon.com/Schlage-F170ACC619RH-Accent-Right-Nickel/dp/B000HE7U98", - "https://www.amazon.com/Schlage-F170GEO619-Georgian-Dummy-Nickel/dp/B000HE314Q", - "https://www.amazon.com/Schlage-F170PLY619-Plymouth-Dummy-Nickel/dp/B000KKVDRY", - "https://www.amazon.com/Schlage-F60-CEN-619-LAT/dp/B0081Q6L4Y", - "https://www.amazon.com/Schlage-FE285-CAM-619-ACC/dp/B001NEK976", - "https://www.amazon.com/Schlage-FE595-16-234-10-027-Lock/dp/B0097GTAMC", - "https://www.amazon.com/Schlage-FE595-PLY-505-FLA/dp/B002057UWO", - "https://www.amazon.com/Schlage-FE595-PLY-505-Flex-Lock/dp/B001COEZT0", - "https://www.amazon.com/Schlage-Touchscreen-Deadbolt-Built-In-BE469NXCAM716/dp/B00AGK9KUU", - "https://www.amazon.com/Secret-Garden-Inky-Treasure-Coloring/dp/1780671067", - "https://www.amazon.com/Skyfall-HD-Daniel-Craig/dp/B00B5HQLMI", - "https://www.amazon.com/Smiths-PP1-Pocket-Multifunction-Sharpener/dp/B000O8OTNC", - "https://www.amazon.com/Sony-NEX-5TL-Compact-Interchangeable-Digital/dp/B00ENZRP38", - "https://www.amazon.com/Sony-NWZE385-Walkman-Video-Player/dp/B00ECQUY2M", - "https://www.amazon.com/Sony-W800-Digital-Camera-Black/dp/B00I8BIBCW", - "https://www.amazon.com/Sony-Walkman-NWZW273S-Waterproof-Swimming/dp/B00I05EFO4", - "https://www.amazon.com/Spirited-Away-2-Disc-Blu-ray-Combo/dp/B00V3QQF6I", - "https://www.amazon.com/Stanley-66-344-4-in-1-Pocket-Screwdriver/dp/B0014KMDZ0", - "https://www.amazon.com/Star-Trek-Into-Darkness-HD/dp/B00E5Q1HJS", - "https://www.amazon.com/Star-Wars-Digital-Movie-Collection/dp/B00VJ04TH0", - "https://www.amazon.com/Super-Smash-Bros-Nintendo-3DS/dp/B00DD0B1R0", - "https://www.amazon.com/The-Book-Pictures-B-J-Novak/dp/0803741715", - "https://www.amazon.com/The-Brothers-Grimm-Matt-Damon/dp/B008Y6U5AM", - "https://www.amazon.com/The-Hobbit-Blu-ray-Digital-UltraViolet/dp/B00R3DO58K", - "https://www.amazon.com/The-Hohng-Company-Catistry/dp/B00JBN7TUQ", - "https://www.amazon.com/The-Hunger-Games-Catching-Fire/dp/B00I2TV3NO", - "https://www.amazon.com/The-Hunger-Games-Mockingjay-Blu-ray/dp/B00PYLT4YI", - "https://www.amazon.com/The-Imitation-Game-Blu-ray-Ultraviolet/dp/B00RY86HSU", - "https://www.amazon.com/The-Last-Legion-HD-weinstein/dp/B009TGWVRG", - "https://www.amazon.com/The-Legend-Zelda-Majoras-Mask-3DS/dp/B00PB9LZQI", - "https://www.amazon.com/The-Lord-Rings-Fellowship-Extended/dp/B007ZQAKHU", - "https://www.amazon.com/The-Order-1886-PlayStation-4/dp/B00DBLBMBQ", - "https://www.amazon.com/Tyler-Perrys-Single-Moms-Club/dp/B00LFE43QC", - "https://www.amazon.com/Ultraviolet-flashlight-Blacklight-Scorpions-Guarantee/dp/B007SIR08C", - "https://www.amazon.com/Universal-Capacity-Exclusive-ChargeWise-Technology/dp/B00P060KB8", - "https://www.amazon.com/World-War-HD-Brad-Pitt/dp/B00EL8I8IS", - "https://www.amazon.com/Xbox-360-Wireless-Controller-Glossy-Black/dp/B003ZSP0WW", - "https://www.amazon.com/Xbox-One-Halo-Master-Collection-Bundle/dp/B00TY9KYKE", - "https://www.amazon.com/Xbox-One/dp/B00KAI3KW2", - "https://www.amazon.com/Xenoblade-Chronicles-3D-New-Nintendo-3DS/dp/B00T9Z8CHU", - "https://www.amazon.com/access", - "https://www.amazon.com/ap/signin?_encoding=UTF8&openid.assoc_handle=usflex&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.ns.pape=http%3A%2F%2Fspecs.openid.net%2Fextensions%2Fpape%2F1.0&openid.pape.max_auth_age=0&openid.return_to=https%3A%2F%2Fwww.amazon.com%2Fgp%2Fyourstore%2Fhome%3Fie%3DUTF8%26ref_%3Dnav_ya_signin", - "https://www.amazon.com/b/?_encoding=UTF8&node=11275476011", - "https://www.amazon.com/b?_encoding=UTF8&node=10048700011", - "https://www.amazon.com/b?_encoding=UTF8&node=8546790011", - "https://www.amazon.com/b?ie=UTF8&node=10158976011", - "https://www.amazon.com/b?ie=UTF8&node=10394030011", - "https://www.amazon.com/b?ie=UTF8&node=10659983011", - "https://www.amazon.com/b?ie=UTF8&node=10772747011", - "https://www.amazon.com/b?ie=UTF8&node=13786321", - "https://www.amazon.com/b?ie=UTF8&node=13786411", - "https://www.amazon.com/compare-credit-card-offers/b?ie=UTF8&node=3561432011", - "https://www.amazon.com/earn-spend-rewards-points/b?ie=UTF8&node=2634438011", - "https://www.amazon.com/gift-cards/b?ie=UTF8&node=2238192011", - "https://www.amazon.com/gp/bestsellers/electronics/1264866011", - "https://www.amazon.com/gp/bestsellers/electronics/281052", - "https://www.amazon.com/gp/cart/view.html", - "https://www.amazon.com/gp/cobrandcard/marketing.html?ie=UTF-8&place=camp&plattr=CCLFOOT&pr=ibprox", - "https://www.amazon.com/gp/css/homepage.html", - "https://www.amazon.com/gp/css/returns/homepage.html", - "https://www.amazon.com/gp/digital/fiona/manage", - "https://www.amazon.com/gp/feature.html?ie=UTF8&docId=1002989221", - "https://www.amazon.com/gp/goldbox", - "https://www.amazon.com/gp/help/customer/display.html?ie=UTF8&nodeId=468496", - "https://www.amazon.com/gp/help/customer/display.html?ie=UTF8&nodeId=468520", - "https://www.amazon.com/gp/help/customer/display.html?ie=UTF8&nodeId=508088", - "https://www.amazon.com/gp/help/customer/display.html?ie=UTF8&nodeId=508510", - "https://www.amazon.com/gp/most-wished-for/movies-tv", - "https://www.amazon.com/gp/most-wished-for/videogames", - "https://www.amazon.com/gp/prime", - "https://www.amazon.com/gp/product/B00DBYBNEE", - "https://www.amazon.com/gp/redirect.html?_encoding=UTF8&location=http%3A%2F%2Fphx.corporate-ir.net%2Fphoenix.zhtml%3Fc%3D176060%26p%3Dirol-mediaHome&source=standards&token=F9CAD8A11D4336B5E0B3C3B089FA066D0A467C1C", - "https://www.amazon.com/gp/redirect.html?_encoding=UTF8&location=http%3A%2F%2Fphx.corporate-ir.net%2Fphoenix.zhtml%3Fc%3D97664%26p%3Dirol-irhome&source=standards&token=F9CAD8A11D4336B5E0B3C3B089FA066D0A467C1C", - "https://www.amazon.com/gp/redirect.html?_encoding=UTF8&location=http%3A%2F%2Fservices.amazon.com%2Fselling-services%2Fbenefits.htm%3Fld%3DAZUSVAS-globalfooter&source=standards&token=2EF4DF105FC57E2F8FA2BB129755A3E03E343571", - "https://www.amazon.com/gp/redirect.html?_encoding=UTF8&location=http%3A%2F%2Fwww.amazon.com%2Fb%3Fnode%3D10048108011&source=standards&token=3A0F170E7CEFE27BDC730D3D7344512BC1296B83", - "https://www.amazon.com/gp/redirect.html?_encoding=UTF8&location=http%3A%2F%2Fwww.amazonservices.com%2Fcontent%2Fsell-on-amazon.htm%2Fref%3Dfooter_soa%3Fld%3DAZFSSOA&source=standards&token=1E60AB4AC0ECCA00151B45353E21782E539DC601", - "https://www.amazon.com/gp/redirect.html?ie=UTF8&location=http%3A%2F%2Fwww.amazon.jobs%2Fgp%2Fredirect.html%3Flocation%3D%252F&source=standards&token=25117E9F01C8F0AB1D649F37EDDD2DEBE047C3A6", - "https://www.amazon.com/gp/redirect.html?location=http://affiliate-program.amazon.com/&token=020E83530EE2B7F2EDA65ADA51F882D31A4AC155&source=standards", - "https://www.amazon.com/gp/registry/wishlist", - "https://www.amazon.com/gp/seller-account/mm-landing.html?ie=UTF8&ld=AZSOAviewallMakeM", - "https://www.amazon.com/gp/seller-account/mm-product-page.html?ie=UTF8&ld=AZSOAUSCSNav", - "https://www.amazon.com/gp/seller-account/mm-summary-page.html?ie=UTF8&ld=AZFooterSelfPublish&topic=200260520", - "https://www.amazon.com/gp/site-directory", - "https://www.amazon.com/gp/wedding/homepage", - "https://www.amazon.com/gp/yourstore/home", - "https://www.amazon.com/interestbasedads", - "https://www.amazon.com/iss/credit/rewardscardmember?_encoding=UTF8&plattr=CBFOOT", - "https://www.amazon.com/iss/credit/storecardmember?_encoding=UTF8&plattr=PLCCFOOT", - "https://www.amazon.com/mortal-kombat-x/dp/B00US76GJY", - "https://www.amazon.com/s?_encoding=UTF8&bbn=172648&rh=i%3Aoffice-electronics%2Cn%3A1064954%2Cn%3A!1084128%2Cn%3A172574%2Cn%3A9424016011%2Cn%3A172635%2Cn%3A172648%2Cp_89%3ACanon%2Cp_36%3A0-9900", - "https://www.amazon.com/s?_encoding=UTF8&bbn=5856181011&rh=i%3Abeauty%2Cp_6%2Cn%3A5856181011%2Cn%3A3760911%2Cn%3A!11055981%2Cn%3A11057241", - "https://www.amazon.com/s?_encoding=UTF8&node=2858778011%2C7613704011&search-alias=prime-instant-video", - "https://www.amazon.com/s?_encoding=UTF8&rh=i%3Aoffice-products%2Cn%3A2563256011", - "https://www.amazon.com/s?_encoding=UTF8&rh=n%3A13889001%2Ci%3Abeauty", - "https://www.amazon.com:443/gp/redirect.html?_encoding=UTF8&location=https%3A%2F%2Fdeveloper.amazon.com%2Fappsandservices%3Fsc_channel%3Dba%26sc_place%3Damazonhome&source=standards&token=DF0CFA9EECFD0DEDEAE6094981480E48DBC1E112", - "https://www.bing.com", - "https://www.bing.com/account/general?ru=https%3a%2f%2fwww.bing.com%3a443%2f&FORM=SEFD", - "https://www.bing.com/explore?FORM=HPSFLT", - "https://www.bing.com/explore?FORM=Z9LH4", - "https://www.bing.com/images/search?q=Mount+Yoshino+Japan&FORM=hphot1", - "https://www.bing.com/images?FORM=Z9LH", - "https://www.bing.com/maps/?FORM=Z9LH2", - "https://www.bing.com/news?FORM=Z9LH3", - "https://www.bing.com/profile/history?FORM=Z9LH5", - "https://www.bing.com/rewards/dashboard", - "https://www.bing.com/search?q=Mount+Yoshino+&form=hpcapt&filters=HpDate%3a%2220150414_0700%22", - "https://www.bing.com/set/homepage?PUBL=BINGCOM", - "https://www.bing.com/translator?FORM=HPSFLT", - "https://www.bing.com/travel?FORM=HPSFLT", - "https://www.bing.com/videos/search?q=Mount+Yoshino&form=hphot2#view=detail&mid=662667328FC2B5E200A0662667328FC2B5E200A0", - "https://www.bing.com/videos/search?q=cherry+blossom+bonsai+dessert&FORM=hphot3#view=detail&mid=2E5DB183A7392542575F2E5DB183A7392542575F", - "https://www.bing.com/videos?FORM=Z9LH1", - "https://www.bing.com/weather/search?q=weather&FORM=HPSFLT", - "https://www.bing.com?FORM=HYLH", - "https://www.bing.com?FORM=HYLH1", - "https://www.comixology.com/", - "https://www.dailymotion.com", - "https://www.dailymotion.com/AgrigentoTV", - "https://www.dailymotion.com/CNET", - "https://www.dailymotion.com/Complex", - "https://www.dailymotion.com/HollyscoopTV", - "https://www.dailymotion.com/JukinVideo", - "https://www.dailymotion.com/LincolnLaunchDecember2012", - "https://www.dailymotion.com/LocalNews-GrabNetworks", - "https://www.dailymotion.com/MaxPreps", - "https://www.dailymotion.com/MojoSupreme", - "https://www.dailymotion.com/NowThis", - "https://www.dailymotion.com/Showtime", - "https://www.dailymotion.com/archived/index.html", - "https://www.dailymotion.com/buzzfeedvideo", - "https://www.dailymotion.com/carefreecooking", - "https://www.dailymotion.com/cbssports", - "https://www.dailymotion.com/dramashq", - "https://www.dailymotion.com/gq", - "https://www.dailymotion.com/ign", - "https://www.dailymotion.com/legal/childprotection", - "https://www.dailymotion.com/legal/copyright", - "https://www.dailymotion.com/legal/privacy", - "https://www.dailymotion.com/legal/prohibited", - "https://www.dailymotion.com/legal/terms", - "https://www.dailymotion.com/ndrive", - "https://www.dailymotion.com/oddsquadtumblr--", - "https://www.dailymotion.com/prime-pollution", - "https://www.dailymotion.com/rss/us", - "https://www.dailymotion.com/s-driver", - "https://www.dailymotion.com/splashnews", - "https://www.dailymotion.com/storyfulviral", - "https://www.dailymotion.com/stream", - "https://www.dailymotion.com/t-drive", - "https://www.dailymotion.com/teasertrailer", - "https://www.dailymotion.com/upload", - "https://www.dailymotion.com/us", - "https://www.dailymotion.com/us/about", - "https://www.dailymotion.com/us/browse", - "https://www.dailymotion.com/us/channel/animals", - "https://www.dailymotion.com/us/channel/auto", - "https://www.dailymotion.com/us/channel/fun", - "https://www.dailymotion.com/us/channel/lifestyle", - "https://www.dailymotion.com/us/channel/news", - "https://www.dailymotion.com/us/channel/people", - "https://www.dailymotion.com/us/channel/shortfilms", - "https://www.dailymotion.com/us/channel/sport", - "https://www.dailymotion.com/us/channel/tech", - "https://www.dailymotion.com/us/channel/travel", - "https://www.dailymotion.com/us/channel/videogames", - "https://www.dailymotion.com/us/everywhere", - "https://www.dailymotion.com/us/extras/jukebox", - "https://www.dailymotion.com/us/extras/mass_uploader", - "https://www.dailymotion.com/us/trending/1", - "https://www.dailymotion.com/us/users/no-explicit/list/recommended/1", - "https://www.dailymotion.com/us/users/no-explicit/list/recommended/1:10", - "https://www.dailymotion.com/video/x2j5um5_the-50-most-bizarre-couple-photos-compilation_fun", - "https://www.dailymotion.com/video/x2jy5zi_omg-chain-snatching-on-the-road-from-a-woman_news", - "https://www.dailymotion.com/video/x2lslaq_%EC%9E%A5%EB%AF%B8%EB%B9%9B-%EC%97%B0%EC%9D%B8%EB%93%A4-e50-150405-h1_creation", - "https://www.dailymotion.com/video/x2lvdqc_%EB%B9%9B%EB%82%98%EA%B1%B0%EB%82%98-%EB%AF%B8%EC%B9%98%EA%B1%B0%EB%82%98-e23-150406-1_creation", - "https://www.dailymotion.com/video/x2lvpai_%EB%B9%84%EC%A0%95%EC%83%81%ED%9A%8C%EB%8B%B4-e40-150406-l1_creation", - "https://www.dailymotion.com/video/x2lz0en_%EC%9A%A9%EA%B0%90%ED%95%9C-%EA%B8%B0%EC%9E%90%EB%93%A4-e106-150408_tv", - "https://www.dailymotion.com/video/x2lz46d_%EA%BD%83%EB%B3%B4%EB%8B%A4-%ED%95%A0%EB%B0%B0-in-%EA%B7%B8%EB%A6%AC%EC%8A%A4-e03-150410-480-1_tv", - "https://www.dailymotion.com/video/x2m5eo2_new-latest-punjabi-song-2015-jeevan-leather-life-sad-top-hit-2014-indian-pakistani-rock-movies-bolly_music", - "https://www.dailymotion.com/video/x2m7x9n_little-boy-heartbreakingly-says-goodbye-to-his-best-friend_fun", - "https://www.dailymotion.com/video/x2m9zq7_german-shepherd-lovingly-cares-for-adopted-new-puppy_animals", - "https://www.dailymotion.com/video/x2ma90d_sadqay-tumhare-last-episode-27-in-high-quality-10th-april-2015_shortfilms", - "https://www.dailymotion.com/video/x2me84t_kekkai-sensen-02-hd_tv", - "https://www.dailymotion.com/video/x2meh8f_women-s-makeup-throughout-history_news", - "https://www.dailymotion.com/video/x2mfnhb_tyler-the-creator-live-coachella-2015_music", - "https://www.dailymotion.com/video/x2miwgx_jeep-cherokee-2015-marrakesh-challenge-driving_auto", - "https://www.dailymotion.com/video/x2mjvre_rowers-challenged-as-several-flying-asian-carp-join-in-training_fun", - "https://www.dailymotion.com/video/x2mkwgg_top-5-benefits-of-apple-carplay-and-google-android_tech", - "https://www.dailymotion.com/video/x2ml6qg_ice-waves-n-ice-to-meet-you_travel", - "https://www.dailymotion.com/video/x2ml8ox_awesome-jetsprint-boat-pov-holy-sprint_auto", - "https://www.dailymotion.com/video/x2mlb4j_i-am-bread-review-commentary_videogames", - "https://www.dailymotion.com/video/x2mldhx_5-star-s-brandon-jones-nacogdoches-tx_sport", - "https://www.dailymotion.com/video/x2mlh4k_things-that-go-wrong-when-trying-to-watch-netflix_lifestyle", - "https://www.dailymotion.com/video/x2mlh4r_how-to-get-the-best-chips-in-the-bowl_lifestyle", - "https://www.dailymotion.com/video/x2mm5mh_mission-impossible-rogue-nation-fate-2015-tom-cruise_shortfilms", - "https://www.dailymotion.com/video/x2mnl05_terrified-skiers-appear-to-encounter-giant-mountain-lion-on-slopes_fun", - "https://www.dailymotion.com/video/x2mo9bq_gentlemen-lobsters-what-really-happens-at-coachella_lifestyle", - "https://www.dailymotion.com/video/x2mo9ds_astronauts-take-a-gopro-on-their-spacewalk_tech", - "https://www.dailymotion.com/video/x2mogov_flawed-perceptions-of-chris-paul_sport", - "https://www.dailymotion.com/video/x2mon13_dennis-quaid-freaks-out-on-set-and-it-s-caught-on-camera_people", - "https://www.dailymotion.com/video/x2mow8y_rihanna-wants-you-to-know-she-s-not-using-cocaine-in-this-video_news", - "https://www.dailymotion.com/videobash", - "https://www.dailymotion.com/worldtalk", - "https://www.dailymotion.com/worldwideinterweb", - "https://www.deviantart.com/", - "https://www.deviantart.com/#skins", - "https://www.deviantart.com/checkout/?mx=premium&subpref=22870_0&point=footer", - "https://www.deviantart.com/checkout/?mx=premium&subpref=22870_0&point=loginbar", - "https://www.deviantart.com/join", - "https://www.deviantart.com/join/?joinpoint=header", - "https://www.deviantart.com/join?joinpoint=standard", - "https://www.deviantart.com/users/forgot", - "https://www.facebook.com", - "https://www.facebook.com/", - "https://www.facebook.com/about/privacy", - "https://www.facebook.com/badges/?ref=pf", - "https://www.facebook.com/campaign/landing.php?placement=pflo&campaign_id=402047449186&extra_1=auto", - "https://www.facebook.com/careers/?ref=pf", - "https://www.facebook.com/directory/pages/", - "https://www.facebook.com/directory/people/", - "https://www.facebook.com/directory/places/", - "https://www.facebook.com/facebook", - "https://www.facebook.com/find-friends?ref=pf", - "https://www.facebook.com/games/", - "https://www.facebook.com/help/?ref=pf", - "https://www.facebook.com/help/cookies", - "https://www.facebook.com/help/cookies/?ref=sitefooter", - "https://www.facebook.com/legal/terms", - "https://www.facebook.com/login/", - "https://www.facebook.com/mobile/?ref=pf", - "https://www.facebook.com/pages/create/?ref_type=registration_form", - "https://www.facebook.com/pages/create/?ref_type=sitefooter", - "https://www.facebook.com/places/", - "https://www.facebook.com/policies/?ref=pf", - "https://www.facebook.com/privacy/explanation", - "https://www.facebook.com/r.php", - "https://www.facebook.com/recover/initiate", - "https://www.flickr.com/", - "https://www.flickr.com/photos/19716902@N00/2289844848", - "https://www.flickr.com/photos/35807342@N00/8622380863", - "https://www.flickr.com/photos/50668516@N00/8757590849", - "https://www.flickr.com/photos/8452611@N05/7942369750", - "https://www.flickr.com/photos/86665756@N00/7980261511", - "https://www.google.com/advanced_search?hl=en&authuser=0", - "https://www.google.com/chrome/index.html?hl=en&brand=CHNG&utm_source=en-hpp&utm_medium=hpp&utm_campaign=en", - "https://www.google.com/imghp?hl=en&tab=wi", - "https://www.google.com/intl/en/about.html", - "https://www.google.com/intl/en/ads/", - "https://www.google.com/intl/en/policies/privacy/", - "https://www.google.com/intl/en/policies/terms/", - "https://www.google.com/language_tools?hl=en&authuser=0", - "https://www.google.com/preferences?hl=en", - "https://www.google.com/search?site=&ie=UTF-8&q=when+was+the+first+mail+delivered+via+the+pony+express&oi=ddle&ct=155th-anniversary-of-the-pony-express-5959391580782592&hl=en&sa=X&ei=0qotVdGjDoK0yASvrIHAAg&ved=0CAMQNg", - "https://www.google.com/search?site=&ie=UTF-8&q=when+was+the+first+mail+delivered+via+the+pony+express&oi=ddle&ct=155th-anniversary-of-the-pony-express-5959391580782592&hl=en&sa=X&ei=z6otVcj0FZKzyATP6YCgAg&ved=0CAMQNg", - "https://www.google.com/services/", - "https://www.imdb.com/?ref_=ft_hm", - "https://www.imdb.com/?ref_=nv_home", - "https://www.imdb.com/a2z?ref_=ft_si", - "https://www.imdb.com/academymuseum/?ref_=nv_sf_am_1", - "https://www.imdb.com/apps/?ref_=ft_apps", - "https://www.imdb.com/apps/?ref_=nb_app", - "https://www.imdb.com/awards-central/?ref_=nv_ev_all_10", - "https://www.imdb.com/awards-central/?ref_=nv_ev_awrd_1", - "https://www.imdb.com/awards-central/?ref_=nv_tp_awrd_2", - "https://www.imdb.com/best-of/?ref_=nv_sf_bo_3", - "https://www.imdb.com/boards/?ref_=ft_mb", - "https://www.imdb.com/boards/?ref_=nv_cm_bd_1", - "https://www.imdb.com/boards/?ref_=nv_tp_bd_2", - "https://www.imdb.com/calendar/?ref_=nv_mv_cal_5", - "https://www.imdb.com/cannes/?ref_=nv_ev_can_5", - "https://www.imdb.com/chart/?ref_=ft_cht", - "https://www.imdb.com/chart/?ref_=hm_cht_sm", - "https://www.imdb.com/chart/?ref_=nv_ch_cht_2", - "https://www.imdb.com/chart/top?ref_=ft_250", - "https://www.imdb.com/chart/top?ref_=nv_ch_250_4", - "https://www.imdb.com/comic-con/?ref_=nv_ev_comic_6", - "https://www.imdb.com/czone/?ref_=nv_cm_cz_2", - "https://www.imdb.com/emmys/?ref_=nv_ev_rte_7", - "https://www.imdb.com/gallery/rg49781504?ref_=hm_ultron_ph_hd", - "https://www.imdb.com/gallery/rg49781504?ref_=hm_ultron_ph_sm", - "https://www.imdb.com/games/guess?ref_=nv_cm_qz_3", - "https://www.imdb.com/genre/?ref_=nv_ch_gr_5", - "https://www.imdb.com/help/", - "https://www.imdb.com/help/?ref_=nb_hlp", - "https://www.imdb.com/help/show_article?conditions", - "https://www.imdb.com/help/show_article?conditions&ref_=ft_cou", - "https://www.imdb.com/helpdesk/contact?ref_=ft_con", - "https://www.imdb.com/imdbpicks/?ref_=nv_sf_pks_2", - "https://www.imdb.com/imdbpicks/imdbtv-summer-premieres?ref_=hm_eds_cap_pri_1", - "https://www.imdb.com/imdbpicks/imdbtv-summer-premieres?ref_=hm_eds_i_1", - "https://www.imdb.com/imdbpicks/imdbtv-weekly-picks?ref_=hm_eds_cap_pri_2", - "https://www.imdb.com/imdbpicks/imdbtv-weekly-picks?ref_=hm_eds_i_2", - "https://www.imdb.com/imdbpicks/imdbtv-weekly-picks?ref_=hm_hm_tvpks_i_1", - "https://www.imdb.com/imdbpicks/imdbtv-weekly-picks?ref_=hm_hm_tvpks_i_2", - "https://www.imdb.com/imdbpicks/imdbtv-weekly-picks?ref_=hm_hm_tvpks_i_3", - "https://www.imdb.com/imdbpicks/month/april/indie-releases/?ref_=hm_eds_cap_pri_3", - "https://www.imdb.com/imdbpicks/month/april/indie-releases/?ref_=hm_eds_i_3", - "https://www.imdb.com/imdbpicks/month/april/tv-premieres/?ref_=hm_eds_cap_pri_4", - "https://www.imdb.com/imdbpicks/month/april/tv-premieres/?ref_=hm_eds_i_4", - "https://www.imdb.com/jobs?ref_=ft_jb", - "https://www.imdb.com/list/watchlist?ref_=nv_wl_all_0", - "https://www.imdb.com/media/index/rg1176148480?ref_=nv_ph_ls_1", - "https://www.imdb.com/media/index/rg1176148480?ref_=nv_tp_ph_3", - "https://www.imdb.com/media/index/rg1528338944?ref_=nv_ph_lp_2", - "https://www.imdb.com/media/index/rg2465176320?ref_=nv_ph_lv_3", - "https://www.imdb.com/media/rm1204876800/rg49781504?ref_=hm_ultron_ph_i_2", - "https://www.imdb.com/media/rm1708193280/rg49781504?ref_=hm_ultron_ph_i_1", - "https://www.imdb.com/media/rm2848978432/rg1056414464?ref_=hm_snp_cap_pri_2", - "https://www.imdb.com/media/rm2848978432/rg1056414464?ref_=hm_snp_i_2", - "https://www.imdb.com/media/rm3722442240/rg49781504?ref_=hm_ultron_ph_i_3", - "https://www.imdb.com/media/rm3804624384/rg955751168?ref_=hm_snp_cap_pri_3", - "https://www.imdb.com/media/rm3804624384/rg955751168?ref_=hm_snp_i_3", - "https://www.imdb.com/media/rm670234112/rg720870144?ref_=hm_snp_cap_pri_1", - "https://www.imdb.com/media/rm670234112/rg720870144?ref_=hm_snp_i_1", - "https://www.imdb.com/movies-coming-soon/?ref_=ft_cs", - "https://www.imdb.com/movies-coming-soon/?ref_=hm_cs_sm", - "https://www.imdb.com/movies-coming-soon/?ref_=nv_mv_cs_4", - "https://www.imdb.com/movies-in-theaters/?ref_=ft_inth", - "https://www.imdb.com/movies-in-theaters/?ref_=hm_otw_sm", - "https://www.imdb.com/movies-in-theaters/?ref_=nv_mv_inth_1", - "https://www.imdb.com/movies-in-theaters/?ref_=nv_tp_inth_1", - "https://www.imdb.com/name/nm0000234?ref_=hm_nw_cel1_lk1", - "https://www.imdb.com/name/nm0000576?ref_=hm_nw_cel1_lk2", - "https://www.imdb.com/name/nm0000598?ref_=hm_nw_tp1_lk1", - "https://www.imdb.com/name/nm0000598?ref_=hm_nw_tp1_lk2", - "https://www.imdb.com/name/nm0001015?ref_=hm_brn_cap_pri_lk1_4", - "https://www.imdb.com/name/nm0001015?ref_=hm_brn_i_4", - "https://www.imdb.com/name/nm0001264?ref_=hm_brn_cap_pri_lk1_2", - "https://www.imdb.com/name/nm0001264?ref_=hm_brn_i_2", - "https://www.imdb.com/name/nm0001309?ref_=hm_brn_cap_pri_lk1_5", - "https://www.imdb.com/name/nm0001309?ref_=hm_brn_i_5", - "https://www.imdb.com/name/nm0001570?ref_=hm_nw_mv1_lk1", - "https://www.imdb.com/name/nm0004778?ref_=hm_brn_cap_pri_lk1_3", - "https://www.imdb.com/name/nm0004778?ref_=hm_brn_i_3", - "https://www.imdb.com/name/nm0749263?ref_=hm_nw_mv1_lk2", - "https://www.imdb.com/name/nm0805476?ref_=hm_nw_tp1_lk4", - "https://www.imdb.com/name/nm1113550?ref_=hm_brn_cap_pri_lk1_1", - "https://www.imdb.com/name/nm1113550?ref_=hm_brn_i_1", - "https://www.imdb.com/news/?ref_=ft_nw", - "https://www.imdb.com/news/celebrity?ref_=hm_nw_cel_tb", - "https://www.imdb.com/news/celebrity?ref_=hm_nw_sm", - "https://www.imdb.com/news/celebrity?ref_=nv_cel_nw_2", - "https://www.imdb.com/news/celebrity?ref_=nv_nw_cel_4", - "https://www.imdb.com/news/indie?ref_=nv_nw_ind_5", - "https://www.imdb.com/news/movie?ref_=hm_nw_mv_tb", - "https://www.imdb.com/news/movie?ref_=hm_nw_sm", - "https://www.imdb.com/news/movie?ref_=nv_nw_mv_2", - "https://www.imdb.com/news/ni58503006?ref_=hm_nw_mv2", - "https://www.imdb.com/news/ni58504217?ref_=hm_nw_mv3", - "https://www.imdb.com/news/ni58504376/?ref_=nv_nw_tn_2", - "https://www.imdb.com/news/ni58504376?ref_=hm_nw_tp2", - "https://www.imdb.com/news/ni58504454?ref_=hm_nw_cel3", - "https://www.imdb.com/news/ni58504489?ref_=hm_nw_mv4", - "https://www.imdb.com/news/ni58504514/?ref_=nv_nw_tn_3", - "https://www.imdb.com/news/ni58504514?ref_=hm_nw_tp3", - "https://www.imdb.com/news/ni58504595?ref_=hm_nw_cel2", - "https://www.imdb.com/news/ni58504683?ref_=hm_nw_cel1", - "https://www.imdb.com/news/ni58504683?ref_=hm_nw_cel1_i", - "https://www.imdb.com/news/ni58504683?ref_=hm_nw_cel1_sm", - "https://www.imdb.com/news/ni58504790?ref_=hm_nw_tp5", - "https://www.imdb.com/news/ni58504791?ref_=hm_nw_mv1", - "https://www.imdb.com/news/ni58504791?ref_=hm_nw_mv1_i", - "https://www.imdb.com/news/ni58504791?ref_=hm_nw_mv1_sm", - "https://www.imdb.com/news/ni58504848?ref_=hm_nw_mv5", - "https://www.imdb.com/news/ni58504852?ref_=hm_nw_tv1", - "https://www.imdb.com/news/ni58504852?ref_=hm_nw_tv1_i", - "https://www.imdb.com/news/ni58504852?ref_=hm_nw_tv1_sm", - "https://www.imdb.com/news/ni58504981?ref_=hm_nw_tp4", - "https://www.imdb.com/news/ni58505067/?ref_=nv_nw_tn_1", - "https://www.imdb.com/news/ni58505067?ref_=hm_nw_tp1", - "https://www.imdb.com/news/ni58505067?ref_=hm_nw_tp1_i", - "https://www.imdb.com/news/ni58505067?ref_=hm_nw_tp1_sm", - "https://www.imdb.com/news/ni58505271?ref_=hm_nw_tv3", - "https://www.imdb.com/news/ni58505642?ref_=hm_nw_tv2", - "https://www.imdb.com/news/ni58506924?ref_=hm_nw_tv4", - "https://www.imdb.com/news/ni58506925?ref_=hm_nw_tv5", - "https://www.imdb.com/news/ni58507004?ref_=hm_nw_cel4", - "https://www.imdb.com/news/ni58507021?ref_=hm_nw_cel5", - "https://www.imdb.com/news/ns0000001?ref_=hm_nw_tp1_src", - "https://www.imdb.com/news/ns0000001?ref_=hm_nw_tp2_src", - "https://www.imdb.com/news/ns0000001?ref_=hm_nw_tv1_src", - "https://www.imdb.com/news/ns0000088?ref_=hm_nw_cel5_src", - "https://www.imdb.com/news/ns0000098?ref_=hm_nw_mv1_src", - "https://www.imdb.com/news/ns0000139?ref_=hm_nw_mv5_src", - "https://www.imdb.com/news/ns0000141?ref_=hm_nw_cel1_src", - "https://www.imdb.com/news/ns0000141?ref_=hm_nw_cel2_src", - "https://www.imdb.com/news/ns0000151?ref_=hm_nw_mv3_src", - "https://www.imdb.com/news/ns0000151?ref_=hm_nw_mv4_src", - "https://www.imdb.com/news/ns0000151?ref_=hm_nw_tp4_src", - "https://www.imdb.com/news/ns0000151?ref_=hm_nw_tp5_src", - "https://www.imdb.com/news/ns0000173?ref_=hm_nw_tv2_src", - "https://www.imdb.com/news/ns0000236?ref_=hm_nw_cel3_src", - "https://www.imdb.com/news/ns0000358?ref_=hm_nw_cel4_src", - "https://www.imdb.com/news/ns0004912?ref_=hm_nw_mv2_src", - "https://www.imdb.com/news/ns0013977?ref_=hm_nw_tv3_src", - "https://www.imdb.com/news/ns0052791?ref_=hm_nw_tp3_src", - "https://www.imdb.com/news/ns0052792?ref_=hm_nw_tv4_src", - "https://www.imdb.com/news/ns0052792?ref_=hm_nw_tv5_src", - "https://www.imdb.com/news/top?ref_=hm_nw_sm", - "https://www.imdb.com/news/top?ref_=hm_nw_tp_tb", - "https://www.imdb.com/news/top?ref_=nv_nw_tp_1", - "https://www.imdb.com/news/top?ref_=nv_tp_nw_1", - "https://www.imdb.com/news/tv?ref_=hm_nw_sm", - "https://www.imdb.com/news/tv?ref_=hm_nw_tv_tb", - "https://www.imdb.com/news/tv?ref_=nv_nw_tv_3", - "https://www.imdb.com/offsite/?page-action=ft-aiv&token=BCYnS4pbDbSJ_Z3uM-U4enQKsyVpEdAF0brwgB0pn8a7o_ru9zV92gIaPfWQhKzkurQ1dajYyA6p%0D%0A2uaqx8CYri8gn68-dOpOSytBo9ZWpuJTFQCw25YB32EzwiT6g4skhifvPSOllxzmnxHvoleFyOpd%0D%0AIpFLWFChtvt3Fiaw6tynNyA6wYbiu3Py3Rnu0xzfd1pBc2kGHsIv7pMdiOzWaAII-88UgyHFfo04%0D%0AbhwvsVW2ZE0%0D%0A", - "https://www.imdb.com/offsite/?page-action=ft-amzn-aud&token=BCYslYPVtgdBjNCAXnFH31o4XJ-U1p2Tm3QbdVdbsV-3eI0E3kTM1p8RUOPAT1CvKZgA1qdlbf6Q%0D%0AAmJLsgt0NfMb6VxcLJHkW5zgMj7Uww0ZP_-5vlA0DLzPjKx2klilqhyOoUfhWQ44pnz1bUDEc9j0%0D%0AkHAVo0YZrFGxZ6HN4y5HnUYHSP-VbE3wM_1QdPAzyG2f%0D%0A", - "https://www.imdb.com/offsite/?page-action=ft-amzn-de&token=BCYnvtJRxiJ-WjA0r0keBo8q9a9BGGN3xCEi7magPzgJ0b1sUXOoTcI4Ph5SWjRaTrXAOz03Rwmz%0D%0Avj_ILFubJJAiFE3ampmW7zFlCTWXF_BbvcyAhDMt1T8K03bMfw02jO5uPIx1YYEQMtYBj8y4SkAc%0D%0AC9dL3pMYoDYcz49wSceXILvGcX8WKcNIb5fzbowp741bl9VjYjUAypM88tM5iE7UzSFAM_yJqhxV%0D%0Aevvdgxz_k_U%0D%0A", - "https://www.imdb.com/offsite/?page-action=ft-amzn-dpr&token=BCYl6nwtyOMPyNnfeK71cDJgbjB4w77n3WxtaCboXjhpmHDRhgR-kuolQPAElqkOe0oYcGrE0ijm%0D%0ANGOq46qBkGWqhE5u0SsOgZkJTNAI6T2Z1jjl_XzCAMGPlHRwtEiiiwLjHuTMVJ7Jw5U0RV0HMXdC%0D%0AWo75bc1FBUH9RommUqrO5OYA9rd-qWDbqLZQ929BmcUD%0D%0A", - "https://www.imdb.com/offsite/?page-action=ft-amzn-fr&token=BCYlh9XCR5KIpnSe1ExgbvvaF_91vXecwZ9XZf6HoNGmZum2qugPaGgJGWm5Mu7P_fLFEIautVSK%0D%0ArMd3qe50UYqpOTTY8Efwic4g31sEIFMWa_A0mPc5EOW9hFN5bmq3wK1XmxPf8q71Sp_llP_918mo%0D%0AWkEB_4UlIZ1Qtx6Uilg_iz1JTM755pZa0F3OP7cYZTrc4AIFl3SKKKuCvtAaI54G6X_8xYQ0C1x_%0D%0Ar_zq3P2YC1M%0D%0A", - "https://www.imdb.com/offsite/?page-action=ft-amzn-in&token=BCYu_ApKeCqzDQagRzBRDV9VIa0aWqHwgltHX9yzp4iuso5FmMuUWRRKFZAQynsko8eUcEhdFuUy%0D%0AUFSB3QIV91LLKDFsVKaSYQ6Eltqnz75JthrcxQHVV07kFb_iQOxl2fg9RxMUstgXEmnKkHc0JWXA%0D%0A50sqcKt_UvCz_sr0xGMFaVeEEbxle0OaklLcLSmbnlc0DgsYzFn2Q59Hm9Rwj6iyUCnsoG9c3AfB%0D%0AXsZQiwNcsgc1v7vdhtgKhEq0-U2MoeXh%0D%0A", - "https://www.imdb.com/offsite/?page-action=ft-amzn-it&token=BCYsOfV7DyzBMAgSWcIxpm2XDPDd_dvF0oh3S18UVaPo3DV2xozRTrmLRviFNoN6pTJ2l2tRyvKa%0D%0AkYbx2Iie21FMHJTHBgdwbMhuUBUaerqGKwZPqkNCjTDWvLdiw5OOeVVWP7o_S3eUEHrwukUjHqD2%0D%0AyV_OtTsN5AUfqhVRHSYWHKt6JdQEj2YogFbFSBnWiIE4C1moNuaujXaGYnQwj8nlfXtaPkVRYlk7%0D%0AYcMbpXsghGU%0D%0A", - "https://www.imdb.com/offsite/?page-action=ft-fb&token=BCYgb2kuzPH8coLcEkz_x2XQz0fcMGN2KkTgbo7SgOgTi1RbKGg8HdH9P0VBIfphm2yUmWylrT3j%0D%0AhCcRvJPjvj_yLh7dDST3ErQgXSm7RzudClLBhH9T4uAHe4gRAMVH6ogTXloNmiBVSnvEnyZLTU6X%0D%0A_3iFfDUQO3XGMaR5clNKDFwauCxG1bLXyF1j5g0HbBfK%0D%0A", - "https://www.imdb.com/offsite/?page-action=ft-iba&token=BCYsTA_15a8K1N2bBz7F1dk4gzQb1uBT733WUnh3-b3el7JJchRGuN1hrLpQGxrPVre5YLoqzcB8%0D%0Amp47gBTf1stfZ17abfDHX2NKO0zKrYuiv0bTA6yZbPBNF3y2eYY9XY-UAOKX4F2gDsECCYPn6N0-%0D%0ANKLEBF6UilKr3VxnBtl16ZYDar6vHkh8jIdRLA8j8hnl%0D%0A", - "https://www.imdb.com/offsite/?page-action=ft-mojo&token=BCYp3Egvw7PXYeiN8Hv_YGLkY_xiYFYaikvqYdvvfFaA9nnRdzWDgz5Fc-Oy-wg15puIiE2xlJ_l%0D%0AZjMnyG97F2gaBEQ2YnZ5wr73qL_5XukJqWSgBCnihT5E2HMacTvt06Ul58rmFTJgyOhuzy-Hxotk%0D%0A3rHisWOoVEiIc0pPs7I7D4uch1Iljwjbali1RndBjs5w%0D%0A", - "https://www.imdb.com/offsite/?page-action=ft-piv&token=BCYux-hLrLj7UzVf4eEGkZzlx1VkmmmiCC8nRg0EMLKasHnLXk-rAoUlFazw4NW10eesUTBjVNYi%0D%0AV4zzmJkFRslFKm0XrUJWYJx6DcbknNuJElX8PutPRhOWTvgmcIP9pXBNm3pCVIBFeqHTMX0lNWI2%0D%0A-l7Od-sso2xdX8TLolrjP_ahUrbQcaaxm25t4IJSX0Du_NccbrqrrmaOEml2Ape1WN2pRR8dQeQI%0D%0Ai8p1KE5e22o%0D%0A", - "https://www.imdb.com/offsite/?page-action=ft-twt&token=BCYrqpPSe0gj2RDl6NbeQmf8SX2apiS6bB2bhxusZGt_TYs3q1m0sGu0E5PMDLiQjPePGC3ApM7o%0D%0AtAObl04Bxhn6_0LbdiGh3B0CHyTtBmkDfvsucBDUQRSIdfhHWoFZ7ybwcDIEfkJPY9rtegfS4CzH%0D%0AOANqxwd-EDQVY8dFn_xIjg0%0D%0A", - "https://www.imdb.com/offsite/?page-action=ft-wab&token=BCYqPAFnJLQWMA58a5RS3U44O0zVhjBkVUIzrMkBefnvaiaO4oJkq4jT59Jqgpy7lcQcd8hqj-xj%0D%0Aa_aH5wNI2ChH3qWnfojo2XiGjTDJf-FSKPy1RQkT8ALfPlf3ZmVekdiCdFZtwUZyoB8G-3qBZEnN%0D%0Ag-nZEiEWmCnK5kZvnWvPsjJzKnS4ieboY9wGus_7sdkx%0D%0A", - "https://www.imdb.com/offsite/?page-action=ft_ad&token=BCYmWEiQlooMv8N_zbAY3FWobPb54arUcug0QGhGFtYV91b9Nm2TKuvLS7vFr9QezSAY0DJ3x1ow%0D%0AJGsEN5ZZ3wliIT20ZJ5pQGq_VJE0XWEyMiXO1SPG_c04bpEqpUtFo_Lt3DQoJ8r9v_2L62Khqc-4%0D%0Aw2WKCvLnC1JXxVxe3G70_CykmDEhHBl9LY9DS7MIDgtQkZinVDEzSSz7a2OgFq0FwaqaY09ptpYW%0D%0A-b6SFAgVK2Aq3yPVqbMzdFUdjR6yBHn9%0D%0A", - "https://www.imdb.com/offsite/?page-action=offsite-amazon&token=BCYouCi7ir9DKNdmwjpk3jL2B9kCnuatXGbFsBfgUAx7rE95D4tG0Y6_ww5tNvjWC9NeDKSXKUvY%0D%0AmfLVrhmWPJ3pGyOH2Bqe8rpt1_Q7vXP-tOP2s0u5DAS811ggUW3MI9cRl3av1PbP0ZQokShaGl22%0D%0Anw1vS7uzmzBTZNZxTG3xI7f6yHIvNx2WT-6zdTtBt-6tXKeraWZQxNchpHQBDSCQCvNVBhXylKWQ%0D%0AFZcoGqvh0KporJOWVeRqLHCXuxf61vmLT-yTiOuzDnCPyWGK5k9vNg%0D%0A&ref_=hm_aiv_i_2", - "https://www.imdb.com/offsite/?page-action=offsite-amazon&token=BCYsqURNXyyiZQ3VQ3Xh5qQ4zEsp0i66qhm6p4szalkw0rZLi6ODuqnsPUYvhTXuM_zrQ75-nQDx%0D%0A-j7a0bXtY_Hbx7hDF-Mq_z8DEdJGRnGOdBe46G5vzGC7HMczyl3eRsElQj0JrE1t5S3YWUqXIPGK%0D%0ARyNpQ4eVJxd59kvTx0CH3b6qcBtYBN8WyA_bJ8OLBH9eQQK8aTAjrHSyFMgyPBSt6hAekyO-j7Yz%0D%0ATrevobv3JhX24RCN209hPYyUlQvuYilg2W91MHNPaettGzUbYbUstw%0D%0A&ref_=hm_aiv_i_3", - "https://www.imdb.com/offsite/?page-action=offsite-amazon&token=BCYvDo9qpkcamcnzHqUKZ42sSfpllJFeuuUzSkmFa9m5ggMk-jxdSDLks0qRCRJuq90zeTHnAtcX%0D%0AYPKGdTuXCHqJqLy5RScbWm4zcuLlou-gVGClYn0Q0ZpaY7LVY_zLTLpXakTyLgrE50Ju7d3FU3fp%0D%0AAlMNZYmqOWN2Kp5I0er5r-24YgNGXviMS9bCaBHR-_C914-y9DYo2bmmLo2o8VMzyHDqOXMWPezU%0D%0A-BFqqmhf825U08mkKDNwLlMIz8MBo2pls8hdRNRveH61QV0o7_dukA%0D%0A&ref_=hm_aiv_i_1", - "https://www.imdb.com/offsite/?page-action=watch-aiv&token=BCYhWzeSjyrDVhwNX7Uxe81g5ku054A5_8FizYe-RhD5Sl2rt9vz3i-Duku52pRwR4wgdkVs3Hqu%0D%0ApARap21ysYAZhl7QvqdQ3dz91dfGTtLFsjR-tcdOeefPApbvJIMdaCS9lQUoDgMwpz4G3IVYS5XZ%0D%0AaGebvCeOcMlmxIamRurAMhdIPElM6r_qHmEgkM6BGDbZwNgaf9Rjn7TwTdH97IEg1-nm-ZWvR0VE%0D%0A_l0xiOnWqW37DaxGQwBHaojf_7SKOZwB%0D%0A&ref_=hm_cs_aiv_1", - "https://www.imdb.com/poll/?ref_=nv_cm_pl_4", - "https://www.imdb.com/poll/mXFsH63S28Y/?ref_=hm_poll_hd", - "https://www.imdb.com/poll/mXFsH63S28Y/?ref_=hm_poll_i_1", - "https://www.imdb.com/poll/mXFsH63S28Y/?ref_=hm_poll_i_2", - "https://www.imdb.com/poll/mXFsH63S28Y/?ref_=hm_poll_sm", - "https://www.imdb.com/pressroom/?ref_=ft_pr", - "https://www.imdb.com/privacy?ref_=ft_pvc", - "https://www.imdb.com/register/login?ref_=nv_usr_lgin_1", - "https://www.imdb.com/register/login?ref_=nv_usr_lgin_3", - "https://www.imdb.com/search/", - "https://www.imdb.com/search/name?birth_monthday=04-15&refine=birth_monthday&ref_=nv_cel_brn_1", - "https://www.imdb.com/search/name?gender=male,female&ref_=nv_cel_m_3", - "https://www.imdb.com/search/name?gender=male,female&ref_=nv_tp_cel_1", - "https://www.imdb.com/search/name?refine=birth_monthday&birth_monthday=4-14&ref_=hm_brn_hd", - "https://www.imdb.com/search/name?refine=birth_monthday&birth_monthday=4-14&ref_=hm_brn_sm", - "https://www.imdb.com/search/title?count=100&groups=oscar_best_picture_winners&sort=year,desc&ref_=nv_ch_osc_3", - "https://www.imdb.com/search/title?count=100&title_type=feature,tv_series,tv_movie&explore=title_type,genres,year,countries&ref_=nv_ch_mm_1", - "https://www.imdb.com/search?ref_=ft_sr", - "https://www.imdb.com/sections/dvd/?ref_=nv_tvv_dvd_4", - "https://www.imdb.com/sections/tv/?ref_=ft_tv", - "https://www.imdb.com/showtimes/?ref_=nv_mv_sh_2", - "https://www.imdb.com/showtimes/?ref_=nv_tp_sh_3", - "https://www.imdb.com/showtimes/title/tt1014763/2015-04-16?ref_=hm_otw_gt", - "https://www.imdb.com/showtimes/title/tt1655441?ref_=hm_cs_gt", - "https://www.imdb.com/showtimes/title/tt1661199?ref_=hm_cht_gt", - "https://www.imdb.com/showtimes/title/tt1810683/2015-04-23?ref_=hm_cs_gt", - "https://www.imdb.com/showtimes/title/tt2224026?ref_=hm_cht_gt", - "https://www.imdb.com/showtimes/title/tt2273657/2015-04-16?ref_=hm_otw_gt", - "https://www.imdb.com/showtimes/title/tt2561572?ref_=hm_cht_gt", - "https://www.imdb.com/showtimes/title/tt2726560?ref_=hm_cht_gt", - "https://www.imdb.com/showtimes/title/tt2820852?ref_=hm_cht_gt", - "https://www.imdb.com/showtimes/title/tt3450650/2015-04-16?ref_=hm_otw_gt", - "https://www.imdb.com/showtimes/title/tt3660770/2015-04-16?ref_=hm_otw_gt", - "https://www.imdb.com/showtimes/title/tt3713166/2015-04-16?ref_=hm_otw_gt", - "https://www.imdb.com/showtimes?ref_=hm_sh_lk1", - "https://www.imdb.com/sundance/?ref_=nv_ev_sun_2", - "https://www.imdb.com/sxsw/?ref_=nv_ev_sxsw_3", - "https://www.imdb.com/title/tt0478970?ref_=hm_hp_cap_pri_2", - "https://www.imdb.com/title/tt0478970?ref_=hm_hp_i_2", - "https://www.imdb.com/title/tt0804503?ref_=hm_nw_tp1_lk3", - "https://www.imdb.com/title/tt0944947?ref_=hm_nw_tv1_lk1", - "https://www.imdb.com/title/tt1014763?ref_=hm_otw_t2", - "https://www.imdb.com/title/tt1340138?ref_=hm_hp_cap_pri_3", - "https://www.imdb.com/title/tt1340138?ref_=hm_hp_i_3", - "https://www.imdb.com/title/tt1489428?ref_=hm_ontv_t3", - "https://www.imdb.com/title/tt1655441?ref_=hm_cs_t0", - "https://www.imdb.com/title/tt1661199?ref_=hm_cht_t4", - "https://www.imdb.com/title/tt1810683?ref_=hm_cs_t1", - "https://www.imdb.com/title/tt1839578?ref_=hm_ontv_t4", - "https://www.imdb.com/title/tt1935302?ref_=hm_otw_t8", - "https://www.imdb.com/title/tt2224026?ref_=hm_cht_t1", - "https://www.imdb.com/title/tt2273657?ref_=hm_otw_t4", - "https://www.imdb.com/title/tt2364582?ref_=hm_ontv_t1", - "https://www.imdb.com/title/tt2395427/trivia?item=tr2442275&ref_=hm_trv_hd", - "https://www.imdb.com/title/tt2395427/trivia?item=tr2442275&ref_=hm_trv_sm", - "https://www.imdb.com/title/tt2395427?ref_=hm_trv_i_1", - "https://www.imdb.com/title/tt2395427?ref_=hm_trv_lk1", - "https://www.imdb.com/title/tt2561572?ref_=hm_cht_t3", - "https://www.imdb.com/title/tt2726560?ref_=hm_cht_t2", - "https://www.imdb.com/title/tt2820852?ref_=hm_cht_t0", - "https://www.imdb.com/title/tt2911668?ref_=hm_otw_t6", - "https://www.imdb.com/title/tt2977090?ref_=hm_otw_t5", - "https://www.imdb.com/title/tt3007512?ref_=hm_cs_t3", - "https://www.imdb.com/title/tt3107288?ref_=hm_ontv_t0", - "https://www.imdb.com/title/tt3107288?ref_=hm_ontv_t0_cap", - "https://www.imdb.com/title/tt3107288?ref_=hm_ontv_t0_i", - "https://www.imdb.com/title/tt3132632?ref_=hm_cs_t2", - "https://www.imdb.com/title/tt3318750?ref_=hm_cs_t4", - "https://www.imdb.com/title/tt3399916?ref_=hm_otw_t9", - "https://www.imdb.com/title/tt3450650?ref_=hm_otw_t0", - "https://www.imdb.com/title/tt3501584?ref_=hm_ontv_t2", - "https://www.imdb.com/title/tt3660770?ref_=hm_otw_t3", - "https://www.imdb.com/title/tt3685218?ref_=hm_otw_t7", - "https://www.imdb.com/title/tt3713166?ref_=hm_otw_t1", - "https://www.imdb.com/title/tt4120544/synopsis?ref_=hm_tvr_cap_pri_2", - "https://www.imdb.com/title/tt4120544/synopsis?ref_=hm_tvr_i_2", - "https://www.imdb.com/title/tt4120730/?ref_=hm_hm_tvpks_cap_pri_2", - "https://www.imdb.com/title/tt4138352/?ref_=hm_hm_tvpks_cap_pri_1", - "https://www.imdb.com/title/tt4217814/?ref_=hm_hm_tvpks_cap_pri_3", - "https://www.imdb.com/title/tt4260872/synopsis?ref_=hm_tvr_cap_pri_3", - "https://www.imdb.com/title/tt4260872/synopsis?ref_=hm_tvr_i_3", - "https://www.imdb.com/title/tt4294382/synopsis?ref_=hm_tvr_cap_pri_1", - "https://www.imdb.com/toronto/?ref_=nv_ev_tff_9", - "https://www.imdb.com/trailers/?ref_=nv_mv_tr_3", - "https://www.imdb.com/trailers?ref_=hm_hp_sm", - "https://www.imdb.com/tribeca/?ref_=nv_ev_tri_4", - "https://www.imdb.com/tv/?ref_=nv_tp_tvhm_2", - "https://www.imdb.com/tv/?ref_=nv_tvv_hm_1", - "https://www.imdb.com/tv/blog?ref_=nv_tvv_blog_5", - "https://www.imdb.com/tvgrid/?ref_=hm_ontv_sm", - "https://www.imdb.com/tvgrid/?ref_=nv_tvv_ls_2", - "https://www.imdb.com/venice/?ref_=nv_ev_venice_8", - "https://www.imdb.com/watchnow/?ref_=nv_tvv_wn_3", - "https://www.imdb.com/whattowatch/?ref_=hm_hp_i_1", - "https://www.imdb.com/whattowatch/?ref_=nv_sf_wtw_5", - "https://www.imdb.com/x-ray/?ref_=nv_sf_xray_4", - "https://www.mediawiki.org/", - "https://www.mozilla.org/firefox/new/?utm_source=yahoo&utm_medium=referral&utm_content=uh&utm_campaign=y-upgrade-new-firefox", - "https://www.onenote.com/notebooks?WT.mc_id=O16_BingHP", - "https://www.stackoverflow.com", - "https://www.stackoverflow.com/", - "https://www.stackoverflow.com/contact", - "https://www.stackoverflow.com/feeds", - "https://www.stackoverflow.com/help", - "https://www.stackoverflow.com/help/badges", - "https://www.stackoverflow.com/questions", - "https://www.stackoverflow.com/questions/1160516/javascript-code-to-capture-networks-served-ad", - "https://www.stackoverflow.com/questions/1160516/javascript-code-to-capture-networks-served-ad/?lastactivity", - "https://www.stackoverflow.com/questions/11835894/tidy-css-for-notepad", - "https://www.stackoverflow.com/questions/11835894/tidy-css-for-notepad/?lastactivity", - "https://www.stackoverflow.com/questions/15386861/user-permissions-in-microsoft-access-2010", - "https://www.stackoverflow.com/questions/15386861/user-permissions-in-microsoft-access-2010/?lastactivity", - "https://www.stackoverflow.com/questions/29104784/how-to-import-dropbox-chooser-sdk-in-android-studio", - "https://www.stackoverflow.com/questions/29104784/how-to-import-dropbox-chooser-sdk-in-android-studio/?lastactivity", - "https://www.stackoverflow.com/questions/29548687/how-do-i-automatically-add-threads-to-a-pool-based-on-the-computational-needs-of", - "https://www.stackoverflow.com/questions/29548687/how-do-i-automatically-add-threads-to-a-pool-based-on-the-computational-needs-of/?lastactivity", - "https://www.stackoverflow.com/questions/29611139/steps-to-get-signalr-working-in-android-studio", - "https://www.stackoverflow.com/questions/29611139/steps-to-get-signalr-working-in-android-studio/?lastactivity", - "https://www.stackoverflow.com/questions/29633263/rails-4-devise-with-after-sign-in-path-forresource-always-redirect-to-show-ac", - "https://www.stackoverflow.com/questions/29636099/php-iconv-special-character-conversion", - "https://www.stackoverflow.com/questions/29637382/maxdoubleslicesum-algorithm", - "https://www.stackoverflow.com/questions/29637516/projecting-domain-model-child-count-onto-view-model-without-extra-queries", - "https://www.stackoverflow.com/questions/29637516/projecting-domain-model-child-count-onto-view-model-without-extra-queries/?lastactivity", - "https://www.stackoverflow.com/questions/29637985/how-to-rename-a-bucket-in-couchbase", - "https://www.stackoverflow.com/questions/29637985/how-to-rename-a-bucket-in-couchbase/?lastactivity", - "https://www.stackoverflow.com/questions/29638020/transposing-items-with-prices-to-separate-section", - "https://www.stackoverflow.com/questions/29638020/transposing-items-with-prices-to-separate-section/?lastactivity", - "https://www.stackoverflow.com/questions/29638035/java-try-block-code-does-not-execute", - "https://www.stackoverflow.com/questions/29638035/java-try-block-code-does-not-execute/?lastactivity", - "https://www.stackoverflow.com/questions/29638148/prevent-scrolling-when-mouse-enters-wpf-combobox-dropdown", - "https://www.stackoverflow.com/questions/29638177/tyconpackage-changed-from-ghc-7-8-to-ghc-7-10", - "https://www.stackoverflow.com/questions/29638263/avoiding-excels-scientific-notation-rounding-when-parsing-with-pandas", - "https://www.stackoverflow.com/questions/29638454/c-sharp-linq-to-sql-query-not-returning-results-but-generated-sql-works-fine", - "https://www.stackoverflow.com/questions/29638454/c-sharp-linq-to-sql-query-not-returning-results-but-generated-sql-works-fine/?lastactivity", - "https://www.stackoverflow.com/questions/29638503/what-is-wrong-with-this-laravel-5-response", - "https://www.stackoverflow.com/questions/29638547/slow-animation-pushpage", - "https://www.stackoverflow.com/questions/29638838/how-do-we-store-a-pfx-file-in-certstore-which-is-protected-using-password-retri", - "https://www.stackoverflow.com/questions/29638924/one-of-files-in-my-project-is-not-treated-as-python-code-file-by-pycharm", - "https://www.stackoverflow.com/questions/29638997/send-email-with-material-from-tableview-or-nsmutabledictionary", - "https://www.stackoverflow.com/questions/29639015/scipy-periodogram-for-finite-length-signal", - "https://www.stackoverflow.com/questions/29639038/deploy-to-ec2-with-rubber", - "https://www.stackoverflow.com/questions/29639078/maven-no-longer-adding-dependencies-in-eclipse", - "https://www.stackoverflow.com/questions/29639093/why-does-r-store-the-loop-variable-index-dummy-in-memory", - "https://www.stackoverflow.com/questions/29639098/nstextattachment-cut-off-when-appended-to-nsmutableattributedstring", - "https://www.stackoverflow.com/questions/29639100/implementing-dynamic-radiobuttons-in-java-gui", - "https://www.stackoverflow.com/questions/29639102/uninitialized-constant-anioturnoscontroller-routing-error", - "https://www.stackoverflow.com/questions/29639117/why-arent-my-values-being-input-into-my-database-php-mysql-html", - "https://www.stackoverflow.com/questions/29639117/why-arent-my-values-being-input-into-my-database-php-mysql-html/?lastactivity", - "https://www.stackoverflow.com/questions/29639119/nsmenuitem-key-equivalent-set-to-enter-key-from-number-pad", - "https://www.stackoverflow.com/questions/29639150/complex-0-1-backpack-with-multiple-compartments", - "https://www.stackoverflow.com/questions/29639152/how-to-find-out-if-winjs-promise-was-cancelled-by-timeout-or-cancel-call", - "https://www.stackoverflow.com/questions/29639158/programmatically-determine-number-of-cores-and-amount-of-memory-available-to-spa", - "https://www.stackoverflow.com/questions/29639166/netbeans-struts-config-xml-action-configuration", - "https://www.stackoverflow.com/questions/29639169/xml-schema-element-is-not-declared", - "https://www.stackoverflow.com/questions/29639173/urlrewritefilter-behaving-differently-with-the-order-of-rule-with-http-post", - "https://www.stackoverflow.com/questions/29639190/window-title-is-overwritten-when-using-caliburns-conductorobject-in-view-mode", - "https://www.stackoverflow.com/questions/29639198/django-imagekit-not-uploading-images", - "https://www.stackoverflow.com/questions/29639202/matlab-save-a-class-property", - "https://www.stackoverflow.com/questions/29639204/generating-at-runtime-autogenerate-spring-mvc-controllers-services-etc", - "https://www.stackoverflow.com/questions/29639205/unable-to-execute-pig-scripts-using-azure-powershell", - "https://www.stackoverflow.com/questions/29639208/hive-tables-not-visible-when-connecting-via-odbc", - "https://www.stackoverflow.com/questions/29639210/custom-size-for-modal-view-controller-swift", - "https://www.stackoverflow.com/questions/29639223/custom-file-owner-of-a-nib-file-leaks-in-os-x-swift", - "https://www.stackoverflow.com/questions/29639230/google-dataflow-failure", - "https://www.stackoverflow.com/questions/29639236/vsc-create-a-class-and-run-functions-from-dll-without-the-h", - "https://www.stackoverflow.com/questions/29639240/regex-for-searching-or-gripping-complex-passwords-in-code-repos", - "https://www.stackoverflow.com/questions/29639253/how-do-i-make-a-proper-post-to-symfony-requestmethod", - "https://www.stackoverflow.com/questions/29639272/running-android-emulator-on-travis-ci-without-no-window-option", - "https://www.stackoverflow.com/questions/29639276/pydev-tab-alignment-in-inline-comments", - "https://www.stackoverflow.com/questions/29639277/reading-smallint-and-timestamp-field-using-serde2", - "https://www.stackoverflow.com/questions/29639280/multiple-page-native-flow-using-wl-nativepage-show", - "https://www.stackoverflow.com/questions/29639283/how-to-fork-actions-in-oozie", - "https://www.stackoverflow.com/questions/29639284/expected-before-token-c", - "https://www.stackoverflow.com/questions/29639284/expected-before-token-c/?lastactivity", - "https://www.stackoverflow.com/questions/29639285/merging-with-pdftk-output-path", - "https://www.stackoverflow.com/questions/29639286/google-map-geocoding-with-form-submit", - "https://www.stackoverflow.com/questions/29639295/how-to-combine-header-and-footer-in-collection-view-in-swift", - "https://www.stackoverflow.com/questions/29639297/docker-container-time-timezone-will-not-reflect-changes", - "https://www.stackoverflow.com/questions/29639301/vba-dom-variable-attribute-in-xpath", - "https://www.stackoverflow.com/questions/29639305/opengl-why-is-my-framebuffer-not-work-if-my-fragment-code-is-in-a-function", - "https://www.stackoverflow.com/questions/29639306/cloud-code-vs-express", - "https://www.stackoverflow.com/questions/29639316/display-variable-content-not-varialbe-namein-ruby-on-rails", - "https://www.stackoverflow.com/questions/29639318/how-to-add-more-than-one-panel-in-a-single-panel", - "https://www.stackoverflow.com/questions/29639331/how-to-use-graphics2d-g-scale-on-only-some-things-but-not-others", - "https://www.stackoverflow.com/questions/29639340/can-you-run-javascript-as-a-dynamic-language-in-visual-studio-2013", - "https://www.stackoverflow.com/questions/29639345/angular-ui-grid-add-value-of-selected-cell-to-model", - "https://www.stackoverflow.com/questions/29639350/aurelia-one-way-binding-to-a-checkbox", - "https://www.stackoverflow.com/questions/29639352/fading-between-svg-sprite-background-position-using-background-check-js", - "https://www.stackoverflow.com/questions/29639360/using-autofac-and-moqs-with-delegate-factories", - "https://www.stackoverflow.com/questions/29639362/aweber-integration-with-rails-error-oauthunauthorized", - "https://www.stackoverflow.com/questions/29639373/mips-32-floating-point-addition-computation", - "https://www.stackoverflow.com/questions/29639375/how-can-i-remove-an-object-from-an-array", - "https://www.stackoverflow.com/questions/29639377/vb-net-datagridview-update-insert-sql-views", - "https://www.stackoverflow.com/questions/29639378/know-if-device-is-connected-to-a-network", - "https://www.stackoverflow.com/questions/29639380/ntlm-authentication-with-jersey-rest-service-keeps-logging-warning-how-stop", - "https://www.stackoverflow.com/questions/29639381/php-timestamps-timezone-configuration", - "https://www.stackoverflow.com/questions/29639384/c-weird-folder-locking-for-child-process", - "https://www.stackoverflow.com/questions/29639393/returning-html-from-asp-net-mvc-extension-function", - "https://www.stackoverflow.com/questions/29639394/how-to-create-a-new-customer-via-code", - "https://www.stackoverflow.com/questions/29639396/sequence-contains-no-matching-element-error-using-boolean", - "https://www.stackoverflow.com/questions/29639401/lisp-compiler-design-for-embedded-systems", - "https://www.stackoverflow.com/questions/29639404/a-405-error-when-using-spring-data-rest-restcontroller-at-the-same-time", - "https://www.stackoverflow.com/questions/29639405/continuous-integration-with-gerrit-and-xcode-server", - "https://www.stackoverflow.com/questions/29639410/how-to-use-pygments-in-pelican-with-markdown", - "https://www.stackoverflow.com/questions/29639413/sign-xml-using-pure-javascript-in-the-browser", - "https://www.stackoverflow.com/questions/29639416/make-tabs-stick-to-top-of-div", - "https://www.stackoverflow.com/questions/29639420/database-not-being-filled-quick-enough-to-be-used-with-cursorloader-on-app-launc", - "https://www.stackoverflow.com/questions/29639423/pinning-results-of-ivy-resolution", - "https://www.stackoverflow.com/questions/29639424/propagation-requires-new-seems-to-not-work", - "https://www.stackoverflow.com/questions/29639426/using-your-nsurlresponsewebviewhack", - "https://www.stackoverflow.com/questions/29639427/openam-unable-to-get-application-sso-token", - "https://www.stackoverflow.com/questions/29639430/monitoring-docker-container-performance-using-cadvisor-cgroup-best-approach", - "https://www.stackoverflow.com/questions/29639431/rest-spring-http-post-request-no-working", - "https://www.stackoverflow.com/questions/7385228/serial-port-rs232-communication-with-visual-c-2010", - "https://www.stackoverflow.com/questions/7385228/serial-port-rs232-communication-with-visual-c-2010/?lastactivity", - "https://www.stackoverflow.com/questions/822841/android-recent-apps-seem-to-have-google-provided-ads-is-there-some-new-api-for", - "https://www.stackoverflow.com/questions/822841/android-recent-apps-seem-to-have-google-provided-ads-is-there-some-new-api-for/?lastactivity", - "https://www.stackoverflow.com/questions/ask", - "https://www.stackoverflow.com/questions/tagged/acumatica", - "https://www.stackoverflow.com/questions/tagged/algorithm", - "https://www.stackoverflow.com/questions/tagged/amazon-ec2", - "https://www.stackoverflow.com/questions/tagged/android", - "https://www.stackoverflow.com/questions/tagged/android-studio", - "https://www.stackoverflow.com/questions/tagged/angular-ui-grid", - "https://www.stackoverflow.com/questions/tagged/angularjs", - "https://www.stackoverflow.com/questions/tagged/apache-pig", - "https://www.stackoverflow.com/questions/tagged/apache-spark", - "https://www.stackoverflow.com/questions/tagged/api", - "https://www.stackoverflow.com/questions/tagged/applet", - "https://www.stackoverflow.com/questions/tagged/asp.net-mvc", - "https://www.stackoverflow.com/questions/tagged/assembly", - "https://www.stackoverflow.com/questions/tagged/aurelia", - "https://www.stackoverflow.com/questions/tagged/autofac", - "https://www.stackoverflow.com/questions/tagged/aweber", - "https://www.stackoverflow.com/questions/tagged/azure", - "https://www.stackoverflow.com/questions/tagged/c", - "https://www.stackoverflow.com/questions/tagged/c%23", - "https://www.stackoverflow.com/questions/tagged/c%23-4.0", - "https://www.stackoverflow.com/questions/tagged/c%2b%2b", - "https://www.stackoverflow.com/questions/tagged/caching", - "https://www.stackoverflow.com/questions/tagged/caliburn", - "https://www.stackoverflow.com/questions/tagged/certificate", - "https://www.stackoverflow.com/questions/tagged/cgroups", - "https://www.stackoverflow.com/questions/tagged/cloud-code", - "https://www.stackoverflow.com/questions/tagged/collectd", - "https://www.stackoverflow.com/questions/tagged/combobox", - "https://www.stackoverflow.com/questions/tagged/compiler-construction", - "https://www.stackoverflow.com/questions/tagged/containers", - "https://www.stackoverflow.com/questions/tagged/cordova", - "https://www.stackoverflow.com/questions/tagged/couchbase", - "https://www.stackoverflow.com/questions/tagged/css", - "https://www.stackoverflow.com/questions/tagged/csstidy", - "https://www.stackoverflow.com/questions/tagged/data-binding", - "https://www.stackoverflow.com/questions/tagged/data-transfer", - "https://www.stackoverflow.com/questions/tagged/datagridview", - "https://www.stackoverflow.com/questions/tagged/date", - "https://www.stackoverflow.com/questions/tagged/datetime", - "https://www.stackoverflow.com/questions/tagged/delegate-factories", - "https://www.stackoverflow.com/questions/tagged/dependency-management", - "https://www.stackoverflow.com/questions/tagged/devise", - "https://www.stackoverflow.com/questions/tagged/digital-signature", - "https://www.stackoverflow.com/questions/tagged/django", - "https://www.stackoverflow.com/questions/tagged/django-imagekit", - "https://www.stackoverflow.com/questions/tagged/django-models", - "https://www.stackoverflow.com/questions/tagged/dll", - "https://www.stackoverflow.com/questions/tagged/docker", - "https://www.stackoverflow.com/questions/tagged/dom", - "https://www.stackoverflow.com/questions/tagged/dropbox", - "https://www.stackoverflow.com/questions/tagged/dropbox-api", - "https://www.stackoverflow.com/questions/tagged/dynamic", - "https://www.stackoverflow.com/questions/tagged/eclipse", - "https://www.stackoverflow.com/questions/tagged/embedded", - "https://www.stackoverflow.com/questions/tagged/emulator", - "https://www.stackoverflow.com/questions/tagged/entity-framework", - "https://www.stackoverflow.com/questions/tagged/exception-handling", - "https://www.stackoverflow.com/questions/tagged/express", - "https://www.stackoverflow.com/questions/tagged/firefox", - "https://www.stackoverflow.com/questions/tagged/floating-point", - "https://www.stackoverflow.com/questions/tagged/for-loop", - "https://www.stackoverflow.com/questions/tagged/form-submit", - "https://www.stackoverflow.com/questions/tagged/forms", - "https://www.stackoverflow.com/questions/tagged/fragment-shader", - "https://www.stackoverflow.com/questions/tagged/geocode", - "https://www.stackoverflow.com/questions/tagged/gerrit", - "https://www.stackoverflow.com/questions/tagged/ghc", - "https://www.stackoverflow.com/questions/tagged/google-cloud-dataflow", - "https://www.stackoverflow.com/questions/tagged/google-maps", - "https://www.stackoverflow.com/questions/tagged/google-spreadsheet", - "https://www.stackoverflow.com/questions/tagged/grafana", - "https://www.stackoverflow.com/questions/tagged/graphics2d", - "https://www.stackoverflow.com/questions/tagged/graphite", - "https://www.stackoverflow.com/questions/tagged/grep", - "https://www.stackoverflow.com/questions/tagged/hadoop", - "https://www.stackoverflow.com/questions/tagged/haskell", - "https://www.stackoverflow.com/questions/tagged/hdinsight", - "https://www.stackoverflow.com/questions/tagged/hibernate", - "https://www.stackoverflow.com/questions/tagged/hive", - "https://www.stackoverflow.com/questions/tagged/hiveql", - "https://www.stackoverflow.com/questions/tagged/html", - "https://www.stackoverflow.com/questions/tagged/htmltidy", - "https://www.stackoverflow.com/questions/tagged/import-from-excel", - "https://www.stackoverflow.com/questions/tagged/interface-builder", - "https://www.stackoverflow.com/questions/tagged/ios", - "https://www.stackoverflow.com/questions/tagged/ios7", - "https://www.stackoverflow.com/questions/tagged/ivy", - "https://www.stackoverflow.com/questions/tagged/java", - "https://www.stackoverflow.com/questions/tagged/java-ee", - "https://www.stackoverflow.com/questions/tagged/javascript", - "https://www.stackoverflow.com/questions/tagged/jax-rs", - "https://www.stackoverflow.com/questions/tagged/jersey-client", - "https://www.stackoverflow.com/questions/tagged/jpa", - "https://www.stackoverflow.com/questions/tagged/jquery", - "https://www.stackoverflow.com/questions/tagged/jradiobutton", - "https://www.stackoverflow.com/questions/tagged/keyboard-shortcuts", - "https://www.stackoverflow.com/questions/tagged/laravel-5", - "https://www.stackoverflow.com/questions/tagged/linq-to-sql", - "https://www.stackoverflow.com/questions/tagged/linux", - "https://www.stackoverflow.com/questions/tagged/lisp", - "https://www.stackoverflow.com/questions/tagged/locking", - "https://www.stackoverflow.com/questions/tagged/loops", - "https://www.stackoverflow.com/questions/tagged/machine-learning", - "https://www.stackoverflow.com/questions/tagged/mapreduce", - "https://www.stackoverflow.com/questions/tagged/markdown", - "https://www.stackoverflow.com/questions/tagged/mathematical-optimization", - "https://www.stackoverflow.com/questions/tagged/matlab", - "https://www.stackoverflow.com/questions/tagged/maven", - "https://www.stackoverflow.com/questions/tagged/mips32", - "https://www.stackoverflow.com/questions/tagged/mobilefirst", - "https://www.stackoverflow.com/questions/tagged/mongodb", - "https://www.stackoverflow.com/questions/tagged/mongoose", - "https://www.stackoverflow.com/questions/tagged/moq", - "https://www.stackoverflow.com/questions/tagged/ms-access", - "https://www.stackoverflow.com/questions/tagged/multithreading", - "https://www.stackoverflow.com/questions/tagged/mvvm", - "https://www.stackoverflow.com/questions/tagged/mysql", - "https://www.stackoverflow.com/questions/tagged/n1ql", - "https://www.stackoverflow.com/questions/tagged/netbeans", - "https://www.stackoverflow.com/questions/tagged/networking", - "https://www.stackoverflow.com/questions/tagged/notepad%2b%2b", - "https://www.stackoverflow.com/questions/tagged/nsattributedstring", - "https://www.stackoverflow.com/questions/tagged/nsmenuitem", - "https://www.stackoverflow.com/questions/tagged/nsmutableattributedstring", - "https://www.stackoverflow.com/questions/tagged/nstextattachment", - "https://www.stackoverflow.com/questions/tagged/onsen-ui", - "https://www.stackoverflow.com/questions/tagged/oop", - "https://www.stackoverflow.com/questions/tagged/oozie", - "https://www.stackoverflow.com/questions/tagged/oozie-coordinator", - "https://www.stackoverflow.com/questions/tagged/openam", - "https://www.stackoverflow.com/questions/tagged/opengl", - "https://www.stackoverflow.com/questions/tagged/osx", - "https://www.stackoverflow.com/questions/tagged/pandas", - "https://www.stackoverflow.com/questions/tagged/panels", - "https://www.stackoverflow.com/questions/tagged/parse.com", - "https://www.stackoverflow.com/questions/tagged/parsing", - "https://www.stackoverflow.com/questions/tagged/pdftk", - "https://www.stackoverflow.com/questions/tagged/pelican", - "https://www.stackoverflow.com/questions/tagged/performance", - "https://www.stackoverflow.com/questions/tagged/php", - "https://www.stackoverflow.com/questions/tagged/phpunit", - "https://www.stackoverflow.com/questions/tagged/post", - "https://www.stackoverflow.com/questions/tagged/powershell", - "https://www.stackoverflow.com/questions/tagged/process", - "https://www.stackoverflow.com/questions/tagged/promise", - "https://www.stackoverflow.com/questions/tagged/pycharm", - "https://www.stackoverflow.com/questions/tagged/pydev", - "https://www.stackoverflow.com/questions/tagged/pygments", - "https://www.stackoverflow.com/questions/tagged/python", - "https://www.stackoverflow.com/questions/tagged/python-2.7", - "https://www.stackoverflow.com/questions/tagged/r", - "https://www.stackoverflow.com/questions/tagged/radio-button", - "https://www.stackoverflow.com/questions/tagged/regex", - "https://www.stackoverflow.com/questions/tagged/rest", - "https://www.stackoverflow.com/questions/tagged/routes", - "https://www.stackoverflow.com/questions/tagged/rubber", - "https://www.stackoverflow.com/questions/tagged/ruby", - "https://www.stackoverflow.com/questions/tagged/ruby-on-rails", - "https://www.stackoverflow.com/questions/tagged/schema", - "https://www.stackoverflow.com/questions/tagged/serial-port", - "https://www.stackoverflow.com/questions/tagged/server", - "https://www.stackoverflow.com/questions/tagged/session", - "https://www.stackoverflow.com/questions/tagged/shader", - "https://www.stackoverflow.com/questions/tagged/signalr", - "https://www.stackoverflow.com/questions/tagged/signals", - "https://www.stackoverflow.com/questions/tagged/single-sign-on", - "https://www.stackoverflow.com/questions/tagged/spectrum", - "https://www.stackoverflow.com/questions/tagged/spreadsheet", - "https://www.stackoverflow.com/questions/tagged/spring", - "https://www.stackoverflow.com/questions/tagged/spring-data-rest", - "https://www.stackoverflow.com/questions/tagged/spring-mvc", - "https://www.stackoverflow.com/questions/tagged/sql", - "https://www.stackoverflow.com/questions/tagged/sql-server", - "https://www.stackoverflow.com/questions/tagged/string-interpolation", - "https://www.stackoverflow.com/questions/tagged/svg", - "https://www.stackoverflow.com/questions/tagged/swift", - "https://www.stackoverflow.com/questions/tagged/swing", - "https://www.stackoverflow.com/questions/tagged/symfony2", - "https://www.stackoverflow.com/questions/tagged/systems-programming", - "https://www.stackoverflow.com/questions/tagged/threadpool", - "https://www.stackoverflow.com/questions/tagged/timezone", - "https://www.stackoverflow.com/questions/tagged/travis-ci", - "https://www.stackoverflow.com/questions/tagged/try-catch", - "https://www.stackoverflow.com/questions/tagged/tuckey-urlrewrite-filter", - "https://www.stackoverflow.com/questions/tagged/uicollectionview", - "https://www.stackoverflow.com/questions/tagged/uicollectionviewcell", - "https://www.stackoverflow.com/questions/tagged/uiwebview", - "https://www.stackoverflow.com/questions/tagged/unit-testing", - "https://www.stackoverflow.com/questions/tagged/user-interface", - "https://www.stackoverflow.com/questions/tagged/variables", - "https://www.stackoverflow.com/questions/tagged/vb.net", - "https://www.stackoverflow.com/questions/tagged/vba", - "https://www.stackoverflow.com/questions/tagged/viewmodel", - "https://www.stackoverflow.com/questions/tagged/visual-c%2b%2b", - "https://www.stackoverflow.com/questions/tagged/visual-studio-2013", - "https://www.stackoverflow.com/questions/tagged/wifi", - "https://www.stackoverflow.com/questions/tagged/windows", - "https://www.stackoverflow.com/questions/tagged/windows-7", - "https://www.stackoverflow.com/questions/tagged/winjs", - "https://www.stackoverflow.com/questions/tagged/worklight", - "https://www.stackoverflow.com/questions/tagged/wpf", - "https://www.stackoverflow.com/questions/tagged/xcode", - "https://www.stackoverflow.com/questions/tagged/xml", - "https://www.stackoverflow.com/questions/tagged/xml-parsing", - "https://www.stackoverflow.com/questions/tagged/xpath", - "https://www.stackoverflow.com/tags", - "https://www.stackoverflow.com/tour", - "https://www.stackoverflow.com/unanswered", - "https://www.stackoverflow.com/users", - "https://www.stackoverflow.com/users/-1/community", - "https://www.stackoverflow.com/users/1045881/toddmo", - "https://www.stackoverflow.com/users/1091853/brian-thomas", - "https://www.stackoverflow.com/users/1146822/user1146822", - "https://www.stackoverflow.com/users/1151334/soleil", - "https://www.stackoverflow.com/users/1261774/user1261774", - "https://www.stackoverflow.com/users/1295877/svonborries", - "https://www.stackoverflow.com/users/1296178/maxhud", - "https://www.stackoverflow.com/users/1336797/dan-g", - "https://www.stackoverflow.com/users/1366938/yogiraj", - "https://www.stackoverflow.com/users/1371968/grayfoxnz", - "https://www.stackoverflow.com/users/1373663/adaml", - "https://www.stackoverflow.com/users/138105/joegaggler", - "https://www.stackoverflow.com/users/1409907/milos", - "https://www.stackoverflow.com/users/1440762/fabiocosta", - "https://www.stackoverflow.com/users/1503554/thisisnozaku", - "https://www.stackoverflow.com/users/1505120/pnuts", - "https://www.stackoverflow.com/users/1571407/niton", - "https://www.stackoverflow.com/users/1649952/james-shaw", - "https://www.stackoverflow.com/users/165198/davidk01", - "https://www.stackoverflow.com/users/16861/simon-fox", - "https://www.stackoverflow.com/users/1778038/sunsin1985", - "https://www.stackoverflow.com/users/1795874/bmuk", - "https://www.stackoverflow.com/users/1858225/kyle-strand", - "https://www.stackoverflow.com/users/1894630/mohab-hassan", - "https://www.stackoverflow.com/users/1899010/h-z", - "https://www.stackoverflow.com/users/1908292/tim-hauser", - "https://www.stackoverflow.com/users/19224/ricardo-acras", - "https://www.stackoverflow.com/users/219166/erikvold", - "https://www.stackoverflow.com/users/2251200/cdell", - "https://www.stackoverflow.com/users/2258616/samirman", - "https://www.stackoverflow.com/users/234401/dva", - "https://www.stackoverflow.com/users/2362671/come-raczy", - "https://www.stackoverflow.com/users/2392106/medbo", - "https://www.stackoverflow.com/users/2581928/rainingchain", - "https://www.stackoverflow.com/users/2669425/david-hall", - "https://www.stackoverflow.com/users/2695387/victor-sigler", - "https://www.stackoverflow.com/users/2752334/paddy", - "https://www.stackoverflow.com/users/2775185/user2775185", - "https://www.stackoverflow.com/users/2868481/d8d0d65b3f7cf42", - "https://www.stackoverflow.com/users/2913800/andrew-sumner", - "https://www.stackoverflow.com/users/2917993/chockomonkey", - "https://www.stackoverflow.com/users/2988919/benjour", - "https://www.stackoverflow.com/users/299209/philk", - "https://www.stackoverflow.com/users/3034030/dsal1951", - "https://www.stackoverflow.com/users/3075435/emmanuel-orozco", - "https://www.stackoverflow.com/users/3195200/ioskmt", - "https://www.stackoverflow.com/users/3200823/casekey", - "https://www.stackoverflow.com/users/3267086/user3267086", - "https://www.stackoverflow.com/users/3324220/mongothegeek", - "https://www.stackoverflow.com/users/337134/knows-not-much", - "https://www.stackoverflow.com/users/3576984/michaelchirico", - "https://www.stackoverflow.com/users/3759159/user3759159", - "https://www.stackoverflow.com/users/3813605/misunderstood", - "https://www.stackoverflow.com/users/3866309/jaredramirez", - "https://www.stackoverflow.com/users/3909196/rashadb", - "https://www.stackoverflow.com/users/3920526/user3920526", - "https://www.stackoverflow.com/users/3924273/user3924273", - "https://www.stackoverflow.com/users/3930335/tom", - "https://www.stackoverflow.com/users/4040102/velkerr", - "https://www.stackoverflow.com/users/4111363/novice-programmer", - "https://www.stackoverflow.com/users/416631/kenny-wyland", - "https://www.stackoverflow.com/users/4199865/zombie", - "https://www.stackoverflow.com/users/4208583/grender", - "https://www.stackoverflow.com/users/4276217/pwnies", - "https://www.stackoverflow.com/users/4312650/whyyounowork", - "https://www.stackoverflow.com/users/4328443/chen-chen", - "https://www.stackoverflow.com/users/4344581/basma", - "https://www.stackoverflow.com/users/4441082/user4441082", - "https://www.stackoverflow.com/users/4443576/chris-paterson", - "https://www.stackoverflow.com/users/4481308/david-park", - "https://www.stackoverflow.com/users/4537802/joey-hanlon", - "https://www.stackoverflow.com/users/4552955/miles", - "https://www.stackoverflow.com/users/4643092/nrh", - "https://www.stackoverflow.com/users/4647993/alexandra-feldman", - "https://www.stackoverflow.com/users/4680156/teaspoon", - "https://www.stackoverflow.com/users/4703156/zach-templeton", - "https://www.stackoverflow.com/users/4714646/sanchay-subhedar", - "https://www.stackoverflow.com/users/472495/halfer", - "https://www.stackoverflow.com/users/4727821/dungey-140", - "https://www.stackoverflow.com/users/4783618/marrioa", - "https://www.stackoverflow.com/users/4788577/robert", - "https://www.stackoverflow.com/users/4789423/srikat", - "https://www.stackoverflow.com/users/4789565/ji-chen", - "https://www.stackoverflow.com/users/4789579/eddy-p", - "https://www.stackoverflow.com/users/4789605/a-negrete", - "https://www.stackoverflow.com/users/4789643/chizbe-joe", - "https://www.stackoverflow.com/users/494343/schultz9999", - "https://www.stackoverflow.com/users/53771/spence", - "https://www.stackoverflow.com/users/736937/jedwards", - "https://www.stackoverflow.com/users/774575/mins", - "https://www.stackoverflow.com/users/877069/nick-chammas", - "https://www.stackoverflow.com/users/912772/vic", - "https://www.stackoverflow.com/users/957648/tyler-exposure", - "https://www.stackoverflow.com/users/972044/mikeb", - "https://www.stackoverflow.com?tab=featured", - "https://www.stackoverflow.com?tab=hot", - "https://www.stackoverflow.com?tab=interesting", - "https://www.stackoverflow.com?tab=month", - "https://www.stackoverflow.com?tab=week", - "https://www.subscribe.wsj.com/hpfooterlink", - "https://www.subscribe.wsj.com/hpheaderlink", - "https://www.thedodo.com/circus-elephants-carden-1089266986.html?utm_source=HuffPo", - "https://www.thedodo.com/millions-animals-killed-by-us-government-1090872400.html?utm_source=HuffPo", - "https://www.tumblr.com/", - "https://www.twitter.com", - "https://www.twitter.com#supported_languages", - "https://www.twitter.com/", - "https://www.twitter.com/JaredLeto/status/549847390342361088", - "https://www.twitter.com/NBA/status/560319834135998464", - "https://www.twitter.com/RaviVora/status/515695592656224256", - "https://www.twitter.com/Thursday_Neal/status/500060476571926528", - "https://www.twitter.com/about", - "https://www.twitter.com/account/begin_password_reset", - "https://www.twitter.com/account/complete", - "https://www.twitter.com/astro_reid/status/531567705368059904", - "https://www.twitter.com/i/cricket", - "https://www.twitter.com/i/directory/profiles", - "https://www.twitter.com/login", - "https://www.twitter.com/privacy", - "https://www.twitter.com/sanarao/status/531643781163261952", - "https://www.twitter.com/tos", - "https://www.twitter.com?lang=ar", - "https://www.twitter.com?lang=bn", - "https://www.twitter.com?lang=cs", - "https://www.twitter.com?lang=da", - "https://www.twitter.com?lang=de", - "https://www.twitter.com?lang=en-gb", - "https://www.twitter.com?lang=es", - "https://www.twitter.com?lang=fa", - "https://www.twitter.com?lang=fi", - "https://www.twitter.com?lang=fil", - "https://www.twitter.com?lang=fr", - "https://www.twitter.com?lang=he", - "https://www.twitter.com?lang=hi", - "https://www.twitter.com?lang=hu", - "https://www.twitter.com?lang=id", - "https://www.twitter.com?lang=it", - "https://www.twitter.com?lang=ja", - "https://www.twitter.com?lang=ko", - "https://www.twitter.com?lang=msa", - "https://www.twitter.com?lang=nl", - "https://www.twitter.com?lang=no", - "https://www.twitter.com?lang=pl", - "https://www.twitter.com?lang=pt", - "https://www.twitter.com?lang=ro", - "https://www.twitter.com?lang=ru", - "https://www.twitter.com?lang=sv", - "https://www.twitter.com?lang=th", - "https://www.twitter.com?lang=tr", - "https://www.twitter.com?lang=uk", - "https://www.twitter.com?lang=vi", - "https://www.twitter.com?lang=zh-cn", - "https://www.twitter.com?lang=zh-tw", - "https://www.wikibooks.org/", - "https://www.wikidata.org/", - "https://www.wikinews.org/", - "https://www.wikiquote.org/", - "https://www.wikisource.org/", - "https://www.wikiversity.org/", - "https://www.wikivoyage.org/", - "https://www.wiktionary.org/", - "https://www.yahoo.com", - "https://www.yahoo.com#suggestions", - "https://www.yahoo.com/", - "https://www.yahoo.com/autos", - "https://www.yahoo.com/autos/see-an-astronauts-daughter-use-cars-to-compose-a-116398297787.html", - "https://www.yahoo.com/beauty", - "https://www.yahoo.com/beauty/lorraine-bracco-takes-on-aging-one-food-at-a-time-116256087243.html", - "https://www.yahoo.com/food", - "https://www.yahoo.com/health", - "https://www.yahoo.com/health/moms-open-letter-to-handicap-parking-shamer-116388141197.html", - "https://www.yahoo.com/makers", - "https://www.yahoo.com/movies", - "https://www.yahoo.com/parenting", - "https://www.yahoo.com/politics", - "https://www.yahoo.com/politics/chris-christie-bets-on-bold-chris-christie-116349714161.html", - "https://www.yahoo.com/style", - "https://www.yahoo.com/tech", - "https://www.yahoo.com/tech/s/apple-just-made-big-move-could-next-gen-202430965.html", - "https://www.yahoo.com/travel", - "https://www.yahoo.com/tv", - "https://www.yahoo.com/tv/community-cheat-sheet-secrets-of-the-lunch-ladys-116386982085.html", - "https://www.youtube.com/", - "https://www.youtube.com/?tab=w1", - "https://www.youtube.com/channel/SBAaOjE-GIlRI", - "https://www.youtube.com/channel/UC-9-kyTW8ZkZNDHQJ6FgpwQ", - "https://www.youtube.com/channel/UC3yA8nDwraeOfnYfBWun83g", - "https://www.youtube.com/channel/UC4uUNnBRq0CYscEMgdB6EJw", - "https://www.youtube.com/channel/UCBR8-60-B28hp2BmDPdntcQ", - "https://www.youtube.com/channel/UCDIfQhadlTH-AdaB8yDOMcA", - "https://www.youtube.com/channel/UCEgdi0XIXXZ-qJOFPf4JSKw", - "https://www.youtube.com/channel/UCF0pVplsI8R5kcAqgtoRqoA", - "https://www.youtube.com/channel/UCF16SjpLvjwG8O6_LZvj8Xw", - "https://www.youtube.com/channel/UCLRYsOHrkk5qcIhtq033bLQ", - "https://www.youtube.com/channel/UCOpNcN46UbXVtpKMrmU4Abg", - "https://www.youtube.com/channel/UCPSlVo6uTRt4whnlqsn9UIw", - "https://www.youtube.com/channel/UCYfdidRxbB8Qhf0Nx7ioOYw", - "https://www.youtube.com/channel/UCczhp4wznQWonO7Pb8HQ2MQ", - "https://www.youtube.com/channel/UCh4sCWxEhYe0rlmBjxEunQw", - "https://www.youtube.com/channel/UCl8dMTqDrJQ0c8y23UBu4kQ", - "https://www.youtube.com/channels", - "https://www.youtube.com/feed/history", - "https://www.youtube.com/feed/music", - "https://www.youtube.com/playlist?list=PLrEnWoR732-BHrPp_Pm8_VleD68f9s14-", - "https://www.youtube.com/t/terms", - "https://www.youtube.com/testtube", - "https://www.youtube.com/upload", - "https://www.youtube.com/user/ArianaGrandeVevo", - "https://www.youtube.com/user/CiaraVEVO", - "https://www.youtube.com/user/EllieGouldingVEVO", - "https://www.youtube.com/user/FoxSports", - "https://www.youtube.com/user/JimmyKimmelLive", - "https://www.youtube.com/user/LastWeekTonight", - "https://www.youtube.com/user/MARVEL", - "https://www.youtube.com/user/MTV", - "https://www.youtube.com/user/MarkRonsonVEVO", - "https://www.youtube.com/user/Maroon5VEVO", - "https://www.youtube.com/user/MeghanTrainorVEVO", - "https://www.youtube.com/user/RihannaVEVO", - "https://www.youtube.com/user/SiaVEVO", - "https://www.youtube.com/user/TaylorSwiftVEVO", - "https://www.youtube.com/user/TerminatorGenisys", - "https://www.youtube.com/user/VanossGaming", - "https://www.youtube.com/user/WatchMojo", - "https://www.youtube.com/user/YelawolfVEVO", - "https://www.youtube.com/user/destinygame", - "https://www.youtube.com/user/jonmillsswns", - "https://www.youtube.com/user/movieclipsTRAILERS", - "https://www.youtube.com/user/omarionmmg", - "https://www.youtube.com/watch?v=-CmadmM5cOk", - "https://www.youtube.com/watch?v=09R8_2nJtjg", - "https://www.youtube.com/watch?v=0ABiaTEd3Rw", - "https://www.youtube.com/watch?v=0OkB6p_FZAw", - "https://www.youtube.com/watch?v=0o81YZrNiqs", - "https://www.youtube.com/watch?v=0uY7gLZDmn4", - "https://www.youtube.com/watch?v=3ck68PrV668", - "https://www.youtube.com/watch?v=47lYbqjB97g", - "https://www.youtube.com/watch?v=6AHI_BUK_1E", - "https://www.youtube.com/watch?v=7Akvt9ZSOcg", - "https://www.youtube.com/watch?v=7LfFW8aA8vw", - "https://www.youtube.com/watch?v=7PCkvCPvDXk", - "https://www.youtube.com/watch?v=8xg3vE8Ie_E", - "https://www.youtube.com/watch?v=AJtDXIazrMo", - "https://www.youtube.com/watch?v=AgFeZr5ptV8", - "https://www.youtube.com/watch?v=ArrWgQS51Yc", - "https://www.youtube.com/watch?v=BPgEgaPk62M", - "https://www.youtube.com/watch?v=CQERFnGvi_A", - "https://www.youtube.com/watch?v=CieuGZ7TthE", - "https://www.youtube.com/watch?v=FLzfXQSPBOg", - "https://www.youtube.com/watch?v=GZgQjN0aNHM", - "https://www.youtube.com/watch?v=IbJwRcRSRyE", - "https://www.youtube.com/watch?v=IfbxK0EQrkQ", - "https://www.youtube.com/watch?v=IxUqZU4XW0E", - "https://www.youtube.com/watch?v=KWZGAExj-es", - "https://www.youtube.com/watch?v=MD5bFCDfySc", - "https://www.youtube.com/watch?v=Nn_Zln_4pA8", - "https://www.youtube.com/watch?v=OPf0YbXqDm0", - "https://www.youtube.com/watch?v=Shg53iv4B9o", - "https://www.youtube.com/watch?v=ShlW5plD_40", - "https://www.youtube.com/watch?v=UDbBXS-XlUI", - "https://www.youtube.com/watch?v=VSYjs5RnlRo", - "https://www.youtube.com/watch?v=VuNIsY6JdUw", - "https://www.youtube.com/watch?v=WA4iX5D9Z64", - "https://www.youtube.com/watch?v=X4do3Kus2nQ", - "https://www.youtube.com/watch?v=_6e5nE2SXYU", - "https://www.youtube.com/watch?v=aOjUSjghGI8", - "https://www.youtube.com/watch?v=aPxVSCfoYnU", - "https://www.youtube.com/watch?v=alQlJDRnQkE", - "https://www.youtube.com/watch?v=bV4jT0v1H_M", - "https://www.youtube.com/watch?v=cqmG5JWLRag", - "https://www.youtube.com/watch?v=dMMfSVfNkoA", - "https://www.youtube.com/watch?v=e-ORhEE9VVg", - "https://www.youtube.com/watch?v=fPg3jWn6Nn0", - "https://www.youtube.com/watch?v=j1p0_R8ZLB0", - "https://www.youtube.com/watch?v=ksrHwD9cZjQ", - "https://www.youtube.com/watch?v=kt0g4dWxEBo", - "https://www.youtube.com/watch?v=lWZ7O-RrATY", - "https://www.youtube.com/watch?v=meQEM3nVmi8", - "https://www.youtube.com/watch?v=nfWlot6h_JM", - "https://www.youtube.com/watch?v=ofxGAXSope8", - "https://www.youtube.com/watch?v=oiJWrNWDXvM", - "https://www.youtube.com/watch?v=okGcksYM0N8", - "https://www.youtube.com/watch?v=pWdKf3MneyI", - "https://www.youtube.com/watch?v=pXwaKB7YOjw", - "https://www.youtube.com/watch?v=qDc_5zpBj7s", - "https://www.youtube.com/watch?v=rGSxss7gWak", - "https://www.youtube.com/watch?v=u1XdfL42_ZA", - "https://www.youtube.com/watch?v=u9mcE-txqoQ", - "https://www.youtube.com/watch?v=vWa9iYYPYF4", - "https://www.youtube.com/watch?v=w1oM3kQpXRo", - "https://www.youtube.com/watch?v=xqc-akOWPe8", - "https://www.youtube.com/watch?v=yOkSedn_cfc", - "https://www.youtube.com/yt/about/", - "https://www.youtube.com/yt/advertise/", - "https://www.youtube.com/yt/copyright/", - "https://www.youtube.com/yt/creators/", - "https://www.youtube.com/yt/dev/", - "https://www.youtube.com/yt/policyandsafety/", - "https://www.youtube.com/yt/press/", - "https://xal.wikipedia.org/", - "https://xh.wikipedia.org/", - "https://xmf.wikipedia.org/", - "https://yandex.ru/jobs", - "https://yi.wikipedia.org/", - "https://yo.wikipedia.org/", - "https://za.wikipedia.org/", - "https://zea.wikipedia.org/", - "https://zh-classical.wikipedia.org/", - "https://zh-cn.facebook.com/", - "https://zh-min-nan.wikipedia.org/", - "https://zh-yue.wikipedia.org/", - "https://zh.wikipedia.org/", - "https://zh.wikipedia.org/wiki/Wikipedia:%E7%BB%B4%E5%9F%BA%E7%99%BE%E7%A7%91%E8%AF%AD%E8%A8%80%E5%88%97%E8%A1%A8", - "https://zu.wikipedia.org/" -]
diff --git a/tools/perf/profile_creators/profile_safe_url_list.py b/tools/perf/profile_creators/profile_safe_url_list.py deleted file mode 100644 index e7cda25..0000000 --- a/tools/perf/profile_creators/profile_safe_url_list.py +++ /dev/null
@@ -1,26 +0,0 @@ -# Copyright 2015 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 json -import os -import random - - -def GetShuffledSafeUrls(): - """Returns a deterministic shuffling of safe urls. - - The profile generators access the urls in order, and the urls are grouped by - domain. The shuffling reduces the load on external servers. - """ - random.seed(0) - url_list_copy = list(GetSafeUrls()) - random.shuffle(url_list_copy) - return url_list_copy - - -def GetSafeUrls(): - """Returns a list of safe urls by loading them from a pre-generated file.""" - safe_url_dir = os.path.dirname(os.path.realpath(__file__)) - safe_url_path = os.path.join(safe_url_dir, "profile_safe_url_list.json") - with open(safe_url_path, "r") as safe_url_file: - return json.load(safe_url_file)
diff --git a/tools/perf/profile_creators/small_profile_extender.py b/tools/perf/profile_creators/small_profile_extender.py deleted file mode 100644 index 22664f5..0000000 --- a/tools/perf/profile_creators/small_profile_extender.py +++ /dev/null
@@ -1,43 +0,0 @@ -# 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. - -import page_sets - -from profile_creators import fast_navigation_profile_extender - - -class SmallProfileExtender( - fast_navigation_profile_extender.FastNavigationProfileExtender): - """Creates a small profile by performing 25 navigations.""" - - def __init__(self, finder_options): - # Use exactly 5 tabs to generate the profile. This is because consumers of - # this profile will perform a session restore, and expect 5 restored tabs. - maximum_batch_size = 5 - super(SmallProfileExtender, self).__init__( - finder_options, maximum_batch_size) - - # Get the list of urls from the typical 25 page set. - self._page_set = page_sets.Typical25PageSet() - urls = [] - for story in self._page_set.stories: - urls.append(story.url) - self._navigation_urls = urls - - def GetUrlIterator(self): - """Superclass override.""" - return iter(self._navigation_urls) - - def ShouldExitAfterBatchNavigation(self): - """Superclass override.""" - return False - - def WebPageReplayArchivePath(self): - """Superclass override.""" - return self._page_set.WprFilePathForStory( - self._page_set.stories[0]) - - def FetchWebPageReplayArchives(self): - """Superclass override.""" - self._page_set.wpr_archive_info.DownloadArchivesIfNeeded()
diff --git a/tools/perf/profile_creators/update_remote_extensions.py b/tools/perf/profile_creators/update_remote_extensions.py deleted file mode 100644 index bf28d4a..0000000 --- a/tools/perf/profile_creators/update_remote_extensions.py +++ /dev/null
@@ -1,217 +0,0 @@ -# Copyright 2015 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 base64 -import csv -import json -import optparse -import os -import shutil -import sys -import tempfile -import urllib2 -import zipfile - -sys.path.insert(1, os.path.abspath(os.path.join( - __file__, '..', '..'))) -from core import path_util - - -path_util.AddPyUtilsToPath() -from py_utils import cloud_storage - -path_util.AddTelemetryToPath() -from telemetry.core import exceptions - - -# Remote target upload directory in cloud storage for extensions. -REMOTE_DIR = 'extension_set' - -# Target zip file. -ZIP_NAME = 'extensions.zip' - - -def _DownloadCrxFromCws(ext_id, dst): - """Downloads CRX specified from Chrome Web Store. - - Retrieves CRX (Chrome extension file) specified by ext_id from Chrome Web - Store, into directory specified by dst. - - Args: - ext_id: id of extension to retrieve. - dst: directory to download CRX into - - Returns: - Returns local path to downloaded CRX. - If download fails, return None. - """ - dst_path = os.path.join(dst, '%s.crx' % ext_id) - cws_url = ('https://clients2.google.com/service/update2/crx?response=' - 'redirect&prodversion=38.0&x=id%%3D%s%%26installsource%%3D' - 'ondemand%%26uc' % ext_id) - response = urllib2.urlopen(cws_url) - if response.getcode() is not 200: - return None - with open(dst_path, 'w') as f: - f.write(response.read()) - return dst_path - - -def _UpdateExtensionsInCloud(local_extensions_dir, extensions_csv, remote_dir): - """Updates set of extensions in Cloud Storage from a CSV of extension ids. - - From well-formatted CSV file containing some set of extensions - (extensions_csv), download them, compress into archive, and update - the remote extension archive under REMOTE_DIR in CHROME-PARTNER-TELEMETRY - bucket. This script expects 2nd column of CSV file to contain extension ids. - - Args: - local_extensions_dir: directory to download CRX files into. - extension_csv: CSV to pull extension_ids from. - remote_dir: remote directory to put extension archive in cloud storage. - - Raises: - Exception if a CRX download fails. - """ - - # Download CRX to temp files and compress into archive - zip_path = os.path.join(local_extensions_dir, ZIP_NAME) - extension_zip = zipfile.ZipFile(zip_path, 'w') - update_csv = False - extensions_info = [] - with open(extensions_csv, 'rb') as csv_file: - reader = csv.reader(csv_file) - # Stores comments (in case CSV needs to be updated/rewritten) - # and skips header line. - comments = [] - line = ','.join(reader.next()) - while line.startswith('#'): - comments.append(line) - line = ','.join(reader.next()) - # Extract info from CSV. - for row in reader: - extension_info = { - 'extension_name': row[0], - 'id': row[1], - 'hash': row[2], - 'version': row[3] - } - - print 'Fetching extension %s...' % extension_info['id'] - crx_path = _DownloadCrxFromCws(extension_info['id'], local_extensions_dir) - if crx_path is None: - raise exceptions.Error('\tCould not fetch %s.\n\n' - 'If this extension dl consistently fails, ' - 'remove this entry from %s.' - % (extension_info['id'], extensions_csv)) - (new_hash, new_version) = _CrxHashIfChanged(crx_path, extension_info) - if new_hash is not None: - update_csv = True - extension_info['hash'] = new_hash - extension_info['version'] = new_version - extensions_info.append(extension_info) - extension_zip.write(crx_path, arcname='%s.crx' % extension_info['id']) - extension_zip.close() - - if update_csv: - print 'Updating CSV...' - _UpdateCsv(comments, extensions_csv, extensions_info) - - print 'Uploading extensions to cloud...' - remote_zip_path = os.path.join(remote_dir, ZIP_NAME) - cloud_storage.Insert(cloud_storage.PARTNER_BUCKET, remote_zip_path, zip_path) - - -def _CrxHashIfChanged(crx_path, extension_info): - """Checks whether downloaded Crx has been altered. - - Compares stored hash with hash of downloaded Crx. If different, alerts user - that CRX version has changed and will be updated in CSV file. - - Args: - crx_path: Path to downloaded CRX. - extension_info: Info from CSV (including id and previous hash) about CRX. - - Returns: - New hash and version if extension differed. Otherwise, returns (None, None) - """ - downloaded_hash = _Base64Hash(crx_path) - new_version = _GetVersionFromCrx(crx_path) - if downloaded_hash != extension_info['hash']: - if new_version != extension_info['version']: - ans = raw_input('\tWarning: Extension %s version from Web Store differs ' - 'from CSV version.\n\tIf continued, script will write ' - 'new hash and version to CSV.\n\tContinue? (y/n) ' - % extension_info['id']).lower() - else: - raise exceptions.Error('Extension %s hash from Web Store differs from ' - '\nhash stored in CSV, but versions are the same.') - if not ans.startswith('y'): - sys.exit('Web Store extension %s hash differs from hash in CSV.' - % extension_info['id']) - return (downloaded_hash, new_version) - return (None, None) - - -def _UpdateCsv(comments, extensions_csv, extensions_info): - """Updates CSV with information in extensions_info. - - Original CSV is overwritten with updated information about each extension. - Header comments from original CSV are preserved. - - Args: - comments: List containing lines of comments found in header of original CSV. - extensions_csv: Path to CSV file. - extensions_info: List of extension info to write to CSV. Each entry is - a dict containing fields extension_name, id, hash, and version. - """ - # Maintain pre-existing comments. - with open(extensions_csv, 'w') as csv_file: - csv_file.write('\n'.join(comments)) - csv_file.write('\n') - with open(extensions_csv, 'a') as csv_file: - writer = csv.DictWriter( - csv_file, fieldnames=['extension_name', 'id', 'hash', 'version']) - writer.writeheader() - writer.writerows(extensions_info) - - -def _GetCsvFromArgs(): - """Parse options to retrieve name of CSV file.""" - parser = optparse.OptionParser() - parser.add_option('-e', '--extension-csv', dest='extension_csv', - help='CSV of extensions to load.') - (options, _) = parser.parse_args() - if not options.extension_csv: - parser.error('Must specify --extension-csv option.') - return options.extension_csv - - -def _GetVersionFromCrx(crx_path): - """Retrieves extension version from CRX archive. - - Args: - crx_path: path to CRX archive to extract version from. - """ - with zipfile.ZipFile(crx_path, 'r') as crx_zip: - manifest_contents = crx_zip.read('manifest.json') - version = json.loads(manifest_contents)['version'] - return version - - -def _Base64Hash(file_path): - return base64.b64encode(cloud_storage.CalculateHash(file_path)) - - -def main(): - extension_csv = _GetCsvFromArgs() - local_extensions_dir = tempfile.mkdtemp() - try: - _UpdateExtensionsInCloud(local_extensions_dir, - extension_csv, REMOTE_DIR) - finally: - shutil.rmtree(local_extensions_dir) - -if __name__ == '__main__': - main()
diff --git a/tools/perf/record_android_profile.py b/tools/perf/record_android_profile.py deleted file mode 100755 index da7d3e4..0000000 --- a/tools/perf/record_android_profile.py +++ /dev/null
@@ -1,39 +0,0 @@ -#!/usr/bin/env python -# 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. - -import os -import sys -import tempfile - -from core import path_util -path_util.AddTelemetryToPath() - -from telemetry.internal.browser import browser_finder -from telemetry.internal.browser import browser_options - - -def _RunPrebuilt(options): - browser_to_create = browser_finder.FindBrowser(options) - with browser_to_create.Create(options) as browser: - output_file = os.path.join(tempfile.mkdtemp(), options.profiler) - raw_input('Press enter to start profiling...') - print '>> Starting profiler', options.profiler - browser.profiling_controller.Start(options.profiler, output_file) - try: - raw_input('Press enter or CTRL+C to stop') - except KeyboardInterrupt: - pass - finally: - print '<< Stopping ...', - sys.stdout.flush() - browser.profiling_controller.Stop() - print 'Stopped profiler ', options.profiler - - -if __name__ == '__main__': - browser_finder_options = browser_options.BrowserFinderOptions() - parser = browser_finder_options.CreateParser('') - profiler_options, _ = parser.parse_args() - sys.exit(_RunPrebuilt(profiler_options))
diff --git a/tools/perf/record_wpr b/tools/perf/record_wpr index 178e1af..465163e9 100755 --- a/tools/perf/record_wpr +++ b/tools/perf/record_wpr
@@ -17,23 +17,7 @@ import third_party # pylint: disable=unused-import -_WARNING_PATTERN = '\033[93m%s\033[0m' # Use yellow color for warning. - - -def _WarnPythonVersion(): - print (_WARNING_PATTERN % - ("Your system python's version is less than 2.7.9. " - 'For best recording results, please run record_wpr with Python ' - 'version 2.7.9 or after (See ' - 'https://github.com/chromium/web-page-replay/issues/73 ' - 'for more information).\n' - 'For instructions on how to upgrade Python on Ubuntu 14.04, see:\n' - 'http://mbless.de/blog/2016/01/09/upgrade-to-python-2711-on-ubuntu-1404-lts.html')) - - if __name__ == '__main__': - if sys.version_info < (2, 7, 9): - _WarnPythonVersion() config = chromium_config.ChromiumConfig( benchmark_dirs=[path_util.GetPerfBenchmarksDir()], top_level_dir=path_util.GetPerfDir())
diff --git a/tools/perf/run_and_compare_benchmarks b/tools/perf/run_and_compare_benchmarks deleted file mode 100755 index 511dfb9..0000000 --- a/tools/perf/run_and_compare_benchmarks +++ /dev/null
@@ -1,139 +0,0 @@ -#!/usr/bin/env python -# Copyright 2016 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. - -"""Runs given benchmark on two executables and determines if the results are -significantly different. - -Run one of the benchmarks available in 'run_benchmark' on two different browser -executables and compare the results using a statistical hypothesis test to -determine whether or not differences in benchmark results are statistically -significant (i.e. whether or not there is an actual difference in performance). -""" - -from __future__ import print_function -import os -import sys -import time - -import argparse -import subprocess - -from core import path_util -sys.path.insert(1, os.path.join(path_util.GetChromiumSrcDir(), 'third_party', - 'catapult', 'experimental')) -from statistical_analysis import compare_benchmark_results - - -def CreateOutputDir(output_dir_name): - """Check if specified output directory exists and create if necessary.""" - if not os.path.isdir(output_dir_name): - os.makedirs(output_dir_name) - - -def RunBenchmark(benchmark_name, executable_path, output_dir, num_runs, - reset_results): - """Runs a benchmark (using the run_benchmark command).""" - run_benchmark_path = os.path.join(os.path.dirname(__file__), 'run_benchmark') - - command = ['{}'.format(run_benchmark_path), - 'run', - '{}'.format(benchmark_name), - '--browser-executable={}'.format(os.path.join(executable_path)), - '--pageset-repeat={}'.format(num_runs), - '--output-dir={}'.format(output_dir), - '--output-format=chartjson', - '--output-format=html'] - if reset_results: - command = command + ['--reset-results'] - - subprocess.check_call(command, shell=False) - - -def RenameBenchmarkResultsJson(output_dir_name, new_json_file_name): - """Renames the JSON produced by the run_benchmark script. - - Renaming the JSON makes sure that it is not overwritten by the following - benchmark result JSON. - """ - current_name = os.path.join(output_dir_name, 'results-chart.json') - new_name = os.path.join(output_dir_name, new_json_file_name) - os.rename(current_name, new_name) - - -def CreateJsonPathArgs(output_dir_name, json_file_names): - """Returns a list of the JSON path command line arguments for the - compare_benchmark_results script. - - These two command line arguments are implicit and are not specified by the - command line arguments of this script since the JSON files are created and - processed by this script and are at no point handled by the user. - """ - return [os.path.join(output_dir_name, json_file_name) for json_file_name in - json_file_names] - - -def main(): - parser = argparse.ArgumentParser(description= - 'Runs the given benchmark on two different given executables and then ' - 'compares the results to determine if they are significantly different ' - 'from each other. Also takes any argument taken by ' - 'compare_benchmark_results.py in ' - 'catapult/experimental/statistical_analysis.') - - def CheckNumRuns(val): - ret_val = int(val) - if ret_val < 3: - raise argparse.ArgumentTypeError('--num-runs has to be an int >= 3. ' - 'Entered value: {}.'.format(val)) - - return ret_val - - parser.add_argument(dest='benchmark_name', help='Name of the benchmark as ' - 'required by run_benchmark script. Run ./run_benchmark ' - 'list for a list of available benchmarks.') - - parser.add_argument(dest='executable_path', nargs=2, - help='Browser executable location.') - - parser.add_argument('--num-runs', dest='num_runs', default=30, - type=CheckNumRuns, metavar='NUM', help='Number of times ' - 'the benchmark is run for each executable. Has to be >= ' - '2.') - - parser.add_argument('--output-dir', dest='output_dir', help='Output ' - 'directory where the resulting Chart JSONs (one for ' - 'each benchmark, raw data) and the output results.html ' - 'file (summarizing and visualizing results) will be ' - 'saved.') - - # forward_args will be passed to the compare_benchmark_results script. - known_args, forward_args = parser.parse_known_args() - - if known_args.output_dir is None: - output_dir_name = 'statistical_analysis_' + known_args.benchmark_name - else: - output_dir_name = known_args.output_dir - - CreateOutputDir(output_dir_name) - new_json_file_names = ('results-1-chart.json', 'results-2-chart.json') - reset_results_for_benchmark = (True, False) - - print('Run Benchmarks:\n') - start_time = time.time() - for executable_path, json_file_name, reset_results in zip( - known_args.executable_path, new_json_file_names, - reset_results_for_benchmark): - RunBenchmark(known_args.benchmark_name, executable_path, output_dir_name, - known_args.num_runs, reset_results=reset_results) - RenameBenchmarkResultsJson(output_dir_name, json_file_name) - print('Running benchmarks took {} seconds.'.format(time.time() - start_time)) - - forward_args = (CreateJsonPathArgs(output_dir_name, new_json_file_names) + - forward_args) - compare_benchmark_results.main(forward_args) - - -if __name__ == '__main__': - sys.exit(main())
diff --git a/tools/perf/run_benchmark b/tools/perf/run_benchmark index 9329184..0a6e183c 100755 --- a/tools/perf/run_benchmark +++ b/tools/perf/run_benchmark
@@ -18,7 +18,8 @@ config = chromium_config.ChromiumConfig( benchmark_dirs=[path_util.GetPerfBenchmarksDir(), path_util.GetPerfContribDir()], - top_level_dir=path_util.GetPerfDir()) + top_level_dir=path_util.GetPerfDir(), + expectations_file=path_util.GetExpectationsPath()) return benchmark_runner.main(config, [trybot_command.Trybot])
diff --git a/tools/perf/scripts_smoke_unittest.py b/tools/perf/scripts_smoke_unittest.py index da2e82a..6005df60 100644 --- a/tools/perf/scripts_smoke_unittest.py +++ b/tools/perf/scripts_smoke_unittest.py
@@ -16,8 +16,12 @@ perf_dir = os.path.dirname(__file__) - def RunPerfScript(self, command): - args = [sys.executable] + command.split(' ') + def RunPerfScript(self, command, venv=False): + main_command = [sys.executable] + # TODO(crbug.com/805552): Remove if/else block + if venv: + main_command = ['vpython'] + args = main_command + command.split(' ') proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=self.perf_dir) stdout = proc.communicate()[0] @@ -39,19 +43,14 @@ self.assertIn('No benchmark named "foo"', stdout) self.assertNotEquals(return_code, 0) - def testRunTrybotWithTypo(self): - return_code, stdout = self.RunPerfScript('run_benchmark try linux octaenz') - self.assertIn('No benchmark named "octaenz"', stdout) - self.assertIn('octane', stdout) - self.assertNotEqual(return_code, 0) - def testRunRecordWprHelp(self): return_code, stdout = self.RunPerfScript('record_wpr') self.assertEquals(return_code, 0, stdout) self.assertIn('optional arguments:', stdout) def testRunRecordWprList(self): - return_code, stdout = self.RunPerfScript('record_wpr --list-benchmarks') + return_code, stdout = self.RunPerfScript('record_wpr --list-benchmarks', + venv=True) # TODO(nednguyen): Remove this once we figure out why importing # small_profile_extender fails on Android dbg. # crbug.com/561668
diff --git a/tools/perf/system_health_stories.csv b/tools/perf/system_health_stories.csv index 2d5947e..5791bd0 100644 --- a/tools/perf/system_health_stories.csv +++ b/tools/perf/system_health_stories.csv
@@ -1,53 +1,47 @@ -Story name,Platform,Description -background:media:imgur,mobile,"Load http://imgur.com/gallery/hUita, then put the Chrome browser into the background." -background:news:nytimes,mobile,"Load http://www.nytimes.com/2016/10/04/us/politics/vice-presidential-debate.html?_r=0, then put the Chrome browser into the background." -background:search:google,mobile,"Load https://www.google.co.uk/#q=tom+cruise+movies, then put the Chrome browser into the background." -background:social:facebook,mobile,"Load https://www.facebook.com/rihanna, then put the Chrome browser into the background." -background:tools:gmail,mobile,Load https://mail.google.com/mail/ -blank:about:blank,all,Story that loads the about:blank page. +Story name,Platform,Description,Disabled Platforms +background:media:imgur,mobile,"Load http://imgur.com/gallery/hUita, then put the browser into the background.", +background:news:nytimes,mobile,"Load http://www.nytimes.com/2016/10/04/us/politics/vice-presidential-debate.html?_r=0, then put the browser into the background.", +background:search:google,mobile,"Load https://www.google.co.uk/#q=tom+cruise+movies, then put the browser into the background.", +background:social:facebook,mobile,"Load https://www.facebook.com/rihanna, then put the browser into the background.", +background:tools:gmail,mobile,Load https://mail.google.com/mail/,Nexus_5 browse:chrome:newtab,mobile,"Story that loads new tab page and performs searches. - For each of the search queries in in the list below, this story does: + Given a list of typical search queries, this story does for each of them: - enter the search query on the new tab page search box - read results - navigates back to new tab page - - List of search queries: - 'does google know everything', - 'most famous paintings', - 'current weather', - 'best movies 2016', - 'how to tie a tie' - " + ",Android_Webview browse:chrome:omnibox,mobile,"Story that peforms search by using omnibox search provider Loads a website and enters a search query on omnibox and navigates to default search provider (google). - " + ",Android_Webview browse:media:facebook_photos,mobile,"Load a photo page from Rihanna's facebook page then navigate a few next photos. - " -browse:media:imgur,desktop,Load http://imgur.com/gallery/5UlBN and navigate to some items/articles. -browse:media:imgur,mobile,Load http://imgur.com/gallery/5UlBN and navigate to some items/articles. -browse:media:pinterest,desktop,Load https://pinterest.com and navigate to some items/articles. -browse:media:tumblr,desktop,Load https://tumblr.com/search/gifs and navigate to some items/articles. + ", +browse:media:flickr_infinite_scroll,desktop,Load https://www.flickr.com/explore then make a very long scroll., +browse:media:flickr_infinite_scroll,mobile,Load https://www.flickr.com/explore then make a very long scroll., +browse:media:imgur,desktop,Load http://imgur.com/gallery/5UlBN and navigate to some items/articles., +browse:media:imgur,mobile,Load http://imgur.com/gallery/5UlBN and navigate to some items/articles., +browse:media:pinterest,desktop,Load https://pinterest.com and navigate to some items/articles., +browse:media:tumblr,desktop,Load https://tumblr.com/search/gifs and navigate to some items/articles.,Win browse:media:youtube,desktop,"Load a typical YouTube video then navigate to a next few videos. Stop and watch each video for a few seconds. - " + ", browse:media:youtube,mobile,"Load a typical YouTube video then navigate to a next few videos. Stop and watch each video for few seconds. - " -browse:news:cnn,all,The second top website in http://www.alexa.com/topsites/category/News -browse:news:cricbuzz,mobile,Load http://m.cricbuzz.com and navigate to some items/articles. -browse:news:flipboard,desktop,Load https://flipboard.com/explore and navigate to some items/articles. -browse:news:globo,mobile,Load http://www.globo.com and navigate to some items/articles. -browse:news:hackernews,desktop,Load https://news.ycombinator.com and navigate to some items/articles. -browse:news:nytimes,desktop,The third top website in http://www.alexa.com/topsites/category/News -browse:news:qq,mobile,Load http://news.qq.com and navigate to some items/articles. -browse:news:reddit,desktop,The top website in http://www.alexa.com/topsites/category/News -browse:news:reddit,mobile,The top website in http://www.alexa.com/topsites/category/News -browse:news:toi,mobile,Load http://m.timesofindia.com and navigate to some items/articles. -browse:news:washingtonpost,mobile,Progressive website + ", +browse:news:cnn,all,The second top website in http://www.alexa.com/topsites/category/News,Mac +browse:news:cricbuzz,mobile,Load http://m.cricbuzz.com and navigate to some items/articles., +browse:news:flipboard,desktop,Load https://flipboard.com/explore and navigate to some items/articles., +browse:news:globo,mobile,Load http://www.globo.com and navigate to some items/articles.,Android +browse:news:hackernews,desktop,Load https://news.ycombinator.com and navigate to some items/articles.,"Win, Mac" +browse:news:nytimes,desktop,The third top website in http://www.alexa.com/topsites/category/News, +browse:news:qq,mobile,Load http://news.qq.com and navigate to some items/articles., +browse:news:reddit,desktop,The top website in http://www.alexa.com/topsites/category/News, +browse:news:reddit,mobile,The top website in http://www.alexa.com/topsites/category/News, +browse:news:toi,mobile,Load http://m.timesofindia.com and navigate to some items/articles.,Android +browse:news:washingtonpost,mobile,Progressive website, browse:search:google,desktop," A typical google search story: _ Start at https://www.google.com/search?q=flower @@ -60,7 +54,7 @@ _ Click the next page result of 'flower delivery'. _ Scroll the search page. - " + ",Win browse:search:google_india,desktop," A typical google search story in India: 1. Start at https://www.google.co.in/search?q=%E0%A4%AB%E0%A5%82%E0%A4%B2` @@ -71,22 +65,29 @@ 5. Click the next page result 6. Scroll the search result page. - " -browse:shopping:amazon,mobile,Load https://www.amazon.co.in/s/?field-keywords=Mobile and navigate to some items/articles. -browse:shopping:avito,mobile,Load https://www.avito.ru/rossiya and navigate to some items/articles. -browse:shopping:flipkart,mobile,Load https://flipkart.com/search?q=Sunglasses and navigate to some items/articles. -browse:shopping:lazada,mobile,Load https://www.lazada.co.id/catalog/?q=Wrist+watch and navigate to some items/articles. -browse:social:facebook,mobile,Load https://www.facebook.com/rihanna and navigate to some items/articles. -browse:social:instagram,mobile,Load https://www.instagram.com/badgalriri/ and navigate to some items/articles. -browse:social:twitter,desktop,Load https://www.twitter.com/nasa and navigate to some items/articles. -browse:social:twitter,mobile,Load https://www.twitter.com/nasa and navigate to some items/articles. + ", +browse:shopping:amazon,mobile,Load https://www.amazon.co.in/s/?field-keywords=Mobile and navigate to some items/articles., +browse:shopping:avito,mobile,Load https://www.avito.ru/rossiya and navigate to some items/articles.,Nexus_6 +browse:shopping:flipkart,mobile,Load https://flipkart.com/search?q=Sunglasses and navigate to some items/articles.,Android +browse:shopping:lazada,mobile,Load https://www.lazada.co.id/catalog/?q=Wrist+watch and navigate to some items/articles., +browse:social:facebook,mobile,Load https://www.facebook.com/rihanna and navigate to some items/articles.,Nexus_5 +browse:social:facebook_infinite_scroll,desktop,Load https://www.facebook.com/shakira then make a very long scroll., +browse:social:facebook_infinite_scroll,mobile,Load https://m.facebook.com/shakira then make a very long scroll., +browse:social:instagram,mobile,Load https://www.instagram.com/badgalriri/ and navigate to some items/articles., +browse:social:pinterest_infinite_scroll,mobile,Load https://www.pinterest.com/all then make a very long scroll., +browse:social:tumblr_infinite_scroll,all,Load http://techcrunch.tumblr.com/ then make a very long scroll., +browse:social:twitter,desktop,Load https://www.twitter.com/nasa and navigate to some items/articles., +browse:social:twitter,mobile,Load https://www.twitter.com/nasa and navigate to some items/articles., +browse:social:twitter_infinite_scroll,desktop,Load https://twitter.com/taylorswift13 then make a very long scroll.,Win +browse:tech:discourse_infinite_scroll,desktop,Load https://meta.discourse.org/t/the-official-discourse-tags-plugin-discourse-tagging/26482 then make a very long scroll., +browse:tech:discourse_infinite_scroll,mobile,Load https://meta.discourse.org/t/the-official-discourse-tags-plugin-discourse-tagging/26482 then make a very long scroll., browse:tools:earth,desktop," Google Earth story: _ Start at https://www.maps.google.com/maps _ Click on the Earth link _ Click ZoomIn three times, waiting for 3 sec in between. - " + ", browse:tools:maps,desktop," Google maps story: _ Start at https://www.maps.google.com/maps @@ -94,70 +95,65 @@ _ Click ZoomIn two times, waiting for 3 sec in between. _ Scroll the map horizontally and vertically. _ Pick a restaurant and ask for directions. - " + ",Mac browse:tools:maps,mobile,"Story that browses google maps mobile page This story searches for nearby restaurants on google maps website and finds directions to a chosen restaurant from search results. - " -load:games:alphabetty,desktop,Load https://king.com/play/alphabetty -load:games:bubbles,all,"Load ""smarty bubbles"" game on famobi.com" -load:games:lazors,all,Load http://www8.games.mobi/games/html5/lazors/lazors.html -load:games:miniclip,desktop,Load http://www.miniclip.com/games/en/ -load:games:spychase,all,Load http://playstar.mobi/games/spychase/index.php -load:media:9gag,desktop,Load https://www.9gag.com/ -load:media:dailymotion,all,Load https://www.dailymotion.com/video/x489k7d_street-performer-shows-off-slinky-skills_fun?autoplay=false -load:media:facebook_photos,mobile,Load a page of rihanna's facebook with a photo. -load:media:flickr,desktop,Load https://www.flickr.com/photos/tags/farm -load:media:google_images,all,Load https://www.google.co.uk/search?tbm=isch&q=love -load:media:imgur,all,Load http://imgur.com/gallery/5UlBN -load:media:soundcloud,all,Load https://soundcloud.com/lifeofdesiigner/desiigner-panda -load:media:youtube,all,Load https://www.youtube.com/watch?v=QGfhS1hfTWw&autoplay=false -load:news:bbc,desktop,Load https://www.bbc.co.uk/news/world-asia-china-36189636 -load:news:cnn,all,Load http://edition.cnn.com -load:news:flipboard,desktop,Load https://flipboard.com/explore -load:news:hackernews,desktop,Load https://news.ycombinator.com -load:news:irctc,mobile,Load https://www.irctc.co.in -load:news:nytimes,desktop,Load http://www.nytimes.com -load:news:nytimes,mobile,Load http://mobile.nytimes.com -load:news:qq,all,Load http://news.qq.com -load:news:reddit,desktop,Load https://www.reddit.com/r/news/top/?sort=top&t=week -load:news:reddit,mobile,Load https://www.reddit.com/r/news/top/?sort=top&t=week -load:news:washingtonpost,mobile,Load https://www.washingtonpost.com/pwa -load:news:wikipedia,all,Load https://en.wikipedia.org/wiki/Science -load:search:amazon,desktop,Load https://www.amazon.com/s/?field-keywords=nexus -load:search:baidu,all,Load https://www.baidu.com/s?word=google -load:search:ebay,all,Load https://www.ebay.com/sch/i.html?_nkw=headphones -load:search:google,all,Load https://www.google.co.uk/ -load:search:taobao,desktop,Load https://world.taobao.com/ -load:search:taobao,mobile,Load http://m.intl.taobao.com/?ali_trackid -load:search:yahoo,all,Load https://search.yahoo.com/search;_ylt=?p=google -load:search:yandex,all,Load https://yandex.ru/touchsearch?text=science -load:social:facebook,all,Load https://www.facebook.com/rihanna -load:social:instagram,desktop,Load https://www.instagram.com/selenagomez/ -load:social:pinterest,all,Load https://uk.pinterest.com/categories/popular/ -load:social:tumblr,all,Load https://50thousand.tumblr.com/ -load:social:twitter,all,Load https://www.twitter.com/nasa -load:social:vk,desktop,Load https://vk.com/sbeatles -load:tools:docs,all,Load a typical google doc page. -load:tools:drive,all,Load https://drive.google.com/drive/my-drive -load:tools:dropbox,all,Load https://www.dropbox.com -load:tools:gmail,desktop,Load https://mail.google.com/mail/ -load:tools:gmail,mobile,Load https://mail.google.com/mail/ -load:tools:stackoverflow,all,Load a typical question & answer page of stackoverflow.com -load:tools:weather,all,Load https://weather.com/en-GB/weather/today/l/USCA0286:1:US -long_running:tools:gmail-background,desktop,Load https://mail.google.com/mail/ then open a new blank tab and let the loaded page stay in background for 100 seconds. -long_running:tools:gmail-background,mobile,Load https://mail.google.com/mail/ then open a new blank tab and let the loaded page stay in background for 100 seconds. -long_running:tools:gmail-foreground,desktop,Load https://mail.google.com/mail/ then let it stay in foreground for 100 seconds. -long_running:tools:gmail-foreground,mobile,Load https://mail.google.com/mail/ then let it stay in foreground for 100 seconds. -multitab:misc:typical24,desktop,"Load 24 different web sites in 24 tabs, then cycle through each tab." -play:media:google_play_music,desktop,"Browse the songs list in music.google.com, then play a song." -play:media:pandora,desktop,"Load pandora.com, then play a song." -play:media:soundcloud,desktop,"Load soundcloud.com, search for ""Smooth Jazz"", then play a song." -search:portal:google,all," A typical Google search user story. - Issue the search query ""what is science"" in the search box and press Enter. - Wait for the search result page to be loaded, then scroll to the Wikipedia - result. - Navigate to wikipedia page by clicking on the result and wait for it to be - fully loaded. - " + ",Mac +browse_accessibility:tech:codesearch,desktop,Tests scrolling an element within a page., +browse_accessibility:tools:gmail_compose,desktop,Tests typing a lot of text into a Gmail compose window.,All +load:chrome:blank,all,Story that loads the about:blank page., +load:games:alphabetty,desktop,Load https://king.com/play/alphabetty, +load:games:bubbles,all,"Load ""smarty bubbles"" game on famobi.com", +load:games:lazors,all,Load http://www8.games.mobi/games/html5/lazors/lazors.html, +load:games:miniclip,desktop,Load http://www.miniclip.com/games/en/,Mac +load:games:spychase,all,Load http://playstar.mobi/games/spychase/index.php, +load:media:9gag,desktop,Load https://www.9gag.com/, +load:media:dailymotion,all,Load https://www.dailymotion.com/video/x489k7d_street-performer-shows-off-slinky-skills_fun?autoplay=false, +load:media:facebook_photos,mobile,Load a page of rihanna's facebook with a photo., +load:media:google_images,all,Load https://www.google.co.uk/search?tbm=isch&q=love, +load:media:imgur,all,Load http://imgur.com/gallery/5UlBN, +load:media:soundcloud,all,Load https://soundcloud.com/lifeofdesiigner/desiigner-panda,Android_Webview +load:media:youtube,all,Load https://www.youtube.com/watch?v=QGfhS1hfTWw&autoplay=false, +load:news:bbc,desktop,Load https://www.bbc.co.uk/news/world-asia-china-36189636, +load:news:cnn,all,Load http://edition.cnn.com, +load:news:flipboard,desktop,Load https://flipboard.com/explore, +load:news:hackernews,desktop,Load https://news.ycombinator.com, +load:news:irctc,mobile,Load https://www.irctc.co.in, +load:news:nytimes,desktop,Load http://www.nytimes.com, +load:news:nytimes,mobile,Load http://mobile.nytimes.com, +load:news:qq,all,Load http://news.qq.com, +load:news:reddit,desktop,Load https://www.reddit.com/r/news/top/?sort=top&t=week, +load:news:reddit,mobile,Load https://www.reddit.com/r/news/top/?sort=top&t=week, +load:news:washingtonpost,mobile,Load https://www.washingtonpost.com/pwa, +load:news:wikipedia,all,Load https://en.wikipedia.org/wiki/Science, +load:search:amazon,desktop,Load https://www.amazon.com/s/?field-keywords=nexus, +load:search:baidu,all,Load https://www.baidu.com/s?word=google, +load:search:ebay,all,Load https://www.ebay.com/sch/i.html?_nkw=headphones, +load:search:google,all,Load https://www.google.co.uk/, +load:search:taobao,desktop,Load https://world.taobao.com/, +load:search:taobao,mobile,Load http://m.intl.taobao.com/?ali_trackid, +load:search:yahoo,all,Load https://search.yahoo.com/search;_ylt=?p=google, +load:search:yandex,all,Load https://yandex.ru/touchsearch?text=science, +load:social:instagram,desktop,Load https://www.instagram.com/selenagomez/, +load:social:pinterest,desktop,Load https://uk.pinterest.com/categories/popular/, +load:social:twitter,mobile,Load https://www.twitter.com/nasa, +load:social:vk,desktop,Load https://vk.com/sbeatles, +load:tools:docs,all,Load a typical google doc page., +load:tools:drive,all,Load https://drive.google.com/drive/my-drive,"Nexus_5X, Android_Webview" +load:tools:dropbox,all,Load https://www.dropbox.com, +load:tools:gmail,desktop,Load https://mail.google.com/mail/,Android +load:tools:gmail,mobile,Load https://mail.google.com/mail/,Android +load:tools:stackoverflow,all,Load a typical question & answer page of stackoverflow.com, +load:tools:weather,all,Load https://weather.com/en-GB/weather/today/l/USCA0286:1:US, +load_accessibility:media:wikipedia,desktop,"Wikipedia page on Accessibility. Long, but very simple, clean layout.", +load_accessibility:shopping:amazon,desktop,Amazon results page. Good example of a site with a data table., +long_running:tools:gmail-background,desktop,Load https://mail.google.com/mail/ then open a new blank tab and let the loaded page stay in background for 100 seconds.,"Android_Webview, Android_Svelte" +long_running:tools:gmail-background,mobile,Load https://mail.google.com/mail/ then open a new blank tab and let the loaded page stay in background for 100 seconds.,"Android_Webview, Android_Svelte" +long_running:tools:gmail-foreground,desktop,Load https://mail.google.com/mail/ then let it stay in foreground for 100 seconds., +long_running:tools:gmail-foreground,mobile,Load https://mail.google.com/mail/ then let it stay in foreground for 100 seconds., +multitab:misc:typical24,desktop,"Load 24 different web sites in 24 tabs, then cycle through each tab.",Mac +play:media:google_play_music,desktop,"Browse the songs list in music.google.com, then play a song.",All +play:media:pandora,desktop,"Load pandora.com, then play a song.",All +play:media:soundcloud,desktop,"Load soundcloud.com, search for ""Smooth Jazz"", then play a song.",Win
diff --git a/tools/perf/validate_wpr_archives b/tools/perf/validate_wpr_archives index f5a7e28ed..8281827 100755 --- a/tools/perf/validate_wpr_archives +++ b/tools/perf/validate_wpr_archives
@@ -21,13 +21,15 @@ benchmarks_to_skip = [ 'skpicture_printer_ct', 'screenshot_ct', + 'smoothness_ct', 'repaint_ct', 'rasterize_and_record_micro_ct', 'multipage_skpicture_printer_ct', 'loading.cluster_telemetry', 'skpicture_printer', 'cros_tab_switching.typical_24', - 'multipage_skpicture_printer'] + 'multipage_skpicture_printer', + 'leak_detection.cluster_telemetry'] for benchmark in benchmark_finders.GetAllBenchmarks(): if benchmark.Name() in benchmarks_to_skip:
diff --git a/tools/perry.py b/tools/perry.py new file mode 100755 index 0000000..0ea8ce5 --- /dev/null +++ b/tools/perry.py
@@ -0,0 +1,107 @@ +#!/usr/bin/env python +# Copyright 2017 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. + +"""Runs all permutations of pairs of tests in a gtest binary to attempt to +detect state leakage between tests. + +Example invocation: + +gn gen out/asan --args='is_asan=true enable_nacl=false is_debug=false' +ninja -C out/asan base_unittests +tools/perry.py out/asan/base_unittests > perry.log & +tail -f perry.log + +You might want to run it in `screen` as it'll take a while. +""" + +import argparse +import os +import multiprocessing +import subprocess +import sys + + +def _GetTestList(path_to_binary): + """Returns a set of full test names. + + Each test will be of the form "Case.Test". There will be a separate line + for each combination of Case/Test (there are often multiple tests in each + case). + """ + raw_output = subprocess.check_output([path_to_binary, "--gtest_list_tests"]) + input_lines = raw_output.splitlines() + + # The format of the gtest_list_tests output is: + # "Case1." + # " Test1 # <Optional extra stuff>" + # " Test2" + # "Case2." + # " Test1" + case_name = '' # Includes trailing dot. + test_set = set() + for line in input_lines: + if len(line) > 1: + if '#' in line: + line = line[:line.find('#')] + if line[0] == ' ': + # Indented means a test in previous case. + test_set.add(case_name + line.strip()) + else: + # New test case. + case_name = line.strip() + + return test_set + + +def _CheckForFailure(data): + test_binary, pair0, pair1 = data + p = subprocess.Popen( + [test_binary, '--gtest_repeat=5', '--gtest_shuffle', + '--gtest_filter=' + pair0 + ':' + pair1], + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + out, _ = p.communicate() + if p.returncode != 0: + return (pair0, pair1, out) + return None + + +def _PrintStatus(i, total, failed): + status = '%d of %d tested (%d failures)' % (i+1, total, failed) + print '\r%s%s' % (status, '\x1B[K'), + sys.stdout.flush() + + +def main(): + parser = argparse.ArgumentParser(description="Find failing pairs of tests.") + parser.add_argument('binary', help='Path to gtest binary or wrapper script.') + args = parser.parse_args() + print 'Getting test list...' + all_tests = _GetTestList(args.binary) + permuted = [(args.binary, x, y) for x in all_tests for y in all_tests] + + failed = [] + pool = multiprocessing.Pool() + total_count = len(permuted) + for i, result in enumerate(pool.imap_unordered( + _CheckForFailure, permuted, 1)): + if result: + print '\n--gtest_filter=%s:%s failed\n\n%s\n\n' % ( + result[0], result[1], result[2]) + failed.append(result) + _PrintStatus(i, total_count, len(failed)) + + pool.terminate() + pool.join() + + if failed: + print 'Failed pairs:' + for f in failed: + print f[0], f[1] + + return 0 + + +if __name__ == '__main__': + sys.exit(main())
diff --git a/tools/polymer/OWNERS b/tools/polymer/OWNERS index 0fe465ae..d1f55b1 100644 --- a/tools/polymer/OWNERS +++ b/tools/polymer/OWNERS
@@ -1,4 +1,3 @@ dpapad@chromium.org jklein@chromium.org michaelpg@chromium.org -tsergeant@chromium.org
diff --git a/tools/polymer/generate_gn.py b/tools/polymer/generate_gn.py new file mode 100755 index 0000000..6219723 --- /dev/null +++ b/tools/polymer/generate_gn.py
@@ -0,0 +1,92 @@ +#!/usr/bin/env python +# Copyright 2017 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. + +from bs4 import BeautifulSoup +from datetime import date +import os.path as path +import sys + +_COMPILE_JS = '//third_party/closure_compiler/compile_js.gni' +_POLYMERS = ['polymer.html', 'polymer-mini.html', 'polymer-micro.html'] +_WEB_ANIMATIONS_BASE = 'web-animations.html' +_WEB_ANIMATIONS_EXTERNS = \ + '//third_party/closure_compiler/externs/web_animations.js' +_COMPILED_RESOURCES_TEMPLATE = ''' +# Copyright %d 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. +# +# NOTE: Created with %s, please do not edit. + +import("%s") + +%s +'''.strip() + + +def main(created_by, html_files): + targets = '' + + def _html_to_extracted(html_file): + assert html_file.endswith('.html') + return html_file[:-len('.html')] + '-extracted' + + def _target_name(target_file): + return _html_to_extracted(path.basename(target_file)) + + def _has_extracted_js(html_file): + return path.isfile(_html_to_extracted(html_file) + '.js') + + html_files = filter(_has_extracted_js, html_files) + + for html_file in sorted(html_files, key=_target_name): + html_base = path.basename(html_file) + if html_base in _POLYMERS: + continue + + parsed = BeautifulSoup(open(html_file), 'html.parser') + imports = set( + i.get('href') for i in parsed.find_all('link', rel='import')) + + html_dir = path.dirname(html_file) + dependencies = [] + externs = '' + + for html_import in sorted(imports): + import_dir, import_base = path.split(html_import.encode('ascii')) + if import_base in _POLYMERS: + continue + + if import_base == _WEB_ANIMATIONS_BASE: + externs += '\n externs_list = [ "%s" ]' % \ + _WEB_ANIMATIONS_EXTERNS + continue + + # Only exclude these after appending web animations externs. + if not _has_extracted_js(path.join(html_dir, html_import)): + continue + + target = ':' + _target_name(import_base) + + dependencies.append(import_dir + target) + + targets += '\njs_library("%s-extracted") {' % html_base[:-5] + if dependencies: + targets += '\n deps = [' + targets += '\n "%s",' % '",\n "'.join(dependencies) + targets += '\n ]' + targets += externs + targets += '\n}\n' + + targets = targets.strip() + + if targets: + current_year = date.today().year + print _COMPILED_RESOURCES_TEMPLATE % (current_year, created_by, + _COMPILE_JS, targets) + + +if __name__ == '__main__': + main(path.basename(sys.argv[0]), sys.argv[1:])
diff --git a/tools/polymer/txt_to_polymer_grdp.py b/tools/polymer/txt_to_polymer_grdp.py index 41e0b20..ed483ba 100755 --- a/tools/polymer/txt_to_polymer_grdp.py +++ b/tools/polymer/txt_to_polymer_grdp.py
@@ -35,7 +35,8 @@ %(v_1_0)s <structure name="IDR_POLYMER_1_0_WEB_ANIMATIONS_JS_WEB_ANIMATIONS_NEXT_LITE_MIN_JS" file="../../../third_party/web-animations-js/sources/web-animations-next-lite.min.js" - type="chrome_html" /> + type="chrome_html" + compress="gzip" /> </grit-part> """ @@ -43,7 +44,8 @@ DEFINITION_TEMPLATE_1_0 = \ """ <structure name="%s" file="../../../third_party/polymer/v1_0/components-chromium/%s" - type="chrome_html" />""" + type="chrome_html" + compress="gzip" />""" def PathToGritId(path):
diff --git a/tools/prepare-bisect-perf-regression.py b/tools/prepare-bisect-perf-regression.py deleted file mode 100755 index 0029a793..0000000 --- a/tools/prepare-bisect-perf-regression.py +++ /dev/null
@@ -1,70 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 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. - -"""Prepare Performance Test Bisect Tool - -This script is used by a try bot to create a working directory and sync an -initial copy of the depot for use in bisecting performance regressions. - -An example usage: - -./tools/prepare-bisect-perf-regressions.py --working_directory "~/builds" - --output_buildbot_annotations - -Would result in creating ~/builds/bisect and then populating it with a copy of -the depot. -""" - -import optparse -import sys - -from auto_bisect import bisect_utils - - -def main(): - """Does an initial checkout of Chromium then exits.""" - - usage = ('%prog [options] [-- chromium-options]\n' - 'Prepares a temporary depot for use on a try bot.') - - parser = optparse.OptionParser(usage=usage) - - parser.add_option('-w', '--working_directory', - type='str', - help='Path to the working directory where the script will ' - 'do an initial checkout of the chromium depot. The ' - 'files will be placed in a subdirectory "bisect" under ' - 'working_directory and that will be used to perform the ' - 'bisection.') - parser.add_option('--output_buildbot_annotations', - action='store_true', - help='Add extra annotation output for buildbot.') - parser.add_option('--target_platform', - type='choice', - choices=['chromium', 'cros', 'android'], - default='chromium', - help='The target platform. Choices are "chromium" (current ' - 'platform), "cros", or "android". If you specify something ' - 'other than "chromium", you must be properly set up to ' - 'build that platform.') - opts, _ = parser.parse_args() - - if not opts.working_directory: - print 'Error: missing required parameter: --working_directory' - print - parser.print_help() - return 1 - - if not bisect_utils.CheckIfBisectDepotExists(opts): - try: - bisect_utils.CreateBisectDirectoryAndSetupDepot( - opts, bisect_utils.DEFAULT_GCLIENT_CUSTOM_DEPS) - except RuntimeError: - return 1 - return 0 - - -if __name__ == '__main__': - sys.exit(main())
diff --git a/tools/python/llvm_symbolizer.py b/tools/python/llvm_symbolizer.py new file mode 100644 index 0000000..fd0df11 --- /dev/null +++ b/tools/python/llvm_symbolizer.py
@@ -0,0 +1,110 @@ +# Copyright 2017 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 os +import re +import subprocess +import threading + +_CHROME_SRC = os.path.join(os.path.dirname(__file__), os.pardir, os.pardir) +_LLVM_SYMBOLIZER_PATH = os.path.join( + _CHROME_SRC, 'third_party', 'llvm-build', 'Release+Asserts', 'bin', + 'llvm-symbolizer') + +_BINARY = re.compile(r'0b[0,1]+') +_HEX = re.compile(r'0x[0-9,a-e]+') +_OCTAL = re.compile(r'0[0-7]+') + +_UNKNOWN = '<UNKNOWN>' + + +def _CheckValidAddr(addr): + """ + Check whether the addr is valid input to llvm symbolizer. + Valid addr has to be octal, binary, or hex number. + + Args: + addr: addr to be entered to llvm symbolizer. + + Returns: + whether the addr is valid input to llvm symbolizer. + """ + return _HEX.match(addr) or _OCTAL.match(addr) or _BINARY.match(addr) + + +class LLVMSymbolizer(object): + def __init__(self): + """Create a LLVMSymbolizer instance that interacts with the llvm symbolizer. + + The purpose of the LLVMSymbolizer is to get function names and line + numbers of an address from the symbols library. + """ + self._llvm_symbolizer_subprocess = None + # Allow only one thread to call GetSymbolInformation at a time. + self._lock = threading.Lock() + + def Start(self): + """Start the llvm symbolizer subprocess. + + Create a subprocess of the llvm symbolizer executable, which will be used + to retrieve function names etc. + """ + if os.path.isfile(_LLVM_SYMBOLIZER_PATH): + self._llvm_symbolizer_subprocess = subprocess.Popen( + [_LLVM_SYMBOLIZER_PATH], stdout=subprocess.PIPE, stdin=subprocess.PIPE) + else: + logging.error('Cannot find llvm_symbolizer here: %s.' % + _LLVM_SYMBOLIZER_PATH) + self._llvm_symbolizer_subprocess = None + + def Close(self): + """Close the llvm symbolizer subprocess. + + Close the subprocess by closing stdin, stdout and killing the subprocess. + """ + with self._lock: + if self._llvm_symbolizer_subprocess: + self._llvm_symbolizer_subprocess.kill() + self._llvm_symbolizer_subprocess = None + + def __enter__(self): + """Start the llvm symbolizer subprocess.""" + self.Start() + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + """Close the llvm symbolizer subprocess.""" + self.Close() + + def GetSymbolInformation(self, lib, addr): + """Return the corresponding function names and line numbers. + + Args: + lib: library to search for info. + addr: address to look for info. + + Returns: + A list of (function name, line numbers) tuple. + """ + if (self._llvm_symbolizer_subprocess is None or not lib + or not _CheckValidAddr(addr) or not os.path.isfile(lib)): + return [(_UNKNOWN, lib)] + + with self._lock: + self._llvm_symbolizer_subprocess.stdin.write('%s %s\n' % (lib, addr)) + self._llvm_symbolizer_subprocess.stdin.flush() + + result = [] + # Read till see new line, which is a symbol of end of output. + # One line of function name is always followed by one line of line number. + while True: + line = self._llvm_symbolizer_subprocess.stdout.readline() + if line != '\n': + line_numbers = self._llvm_symbolizer_subprocess.stdout.readline() + result.append( + (line[:-1], + line_numbers[:-1])) + else: + return result
diff --git a/tools/resources/OWNERS b/tools/resources/OWNERS index b6a4905e..ea259a7 100644 --- a/tools/resources/OWNERS +++ b/tools/resources/OWNERS
@@ -1,3 +1,3 @@ agrieve@chromium.org +per-file filter_resource_whitelist.*=estevenson@chromium.org per-file generate_resource_whitelist.*=estevenson@chromium.org -per-file filter_resource_whitelist.*=zpeng@chromium.org
diff --git a/tools/resources/optimize-png-files.sh b/tools/resources/optimize-png-files.sh index b74f4d8..9c223929 100755 --- a/tools/resources/optimize-png-files.sh +++ b/tools/resources/optimize-png-files.sh
@@ -22,17 +22,14 @@ chrome/app/theme chrome/browser/resources chrome/renderer/resources -component/resources content/public/android/java/res content/app/resources -content/renderer/resources content/shell/resources remoting/resources ui/android/java/res ui/resources ui/chromeos/resources ui/webui/resources/images -win8/resources " # Files larger than this file size (in bytes) will
diff --git a/tools/roll_angle.py b/tools/roll_angle.py index aa48c39..8928d08 100755 --- a/tools/roll_angle.py +++ b/tools/roll_angle.py
@@ -44,7 +44,7 @@ CHROMIUM_GIT_URL = 'https://chromium.googlesource.com/chromium/src.git' CL_ISSUE_RE = re.compile('^Issue number: ([0-9]+) \((.*)\)$') -RIETVELD_URL_RE = re.compile('^https?://(.*)/(.*)') +REVIEW_URL_RE = re.compile('^https?://(.*)/(.*)') ROLL_BRANCH_NAME = 'special_angle_roll_branch' TRYJOB_STATUS_SLEEP_SECONDS = 30 @@ -54,7 +54,7 @@ CommitInfo = collections.namedtuple('CommitInfo', ['git_commit', 'git_repo_url']) -CLInfo = collections.namedtuple('CLInfo', ['issue', 'url', 'rietveld_server']) +CLInfo = collections.namedtuple('CLInfo', ['issue', 'url', 'review_server']) def _VarLookup(local_scope): return lambda var_name: local_scope['vars'][var_name] @@ -190,13 +190,13 @@ issue_number = int(m.group(1)) url = m.group(2) - # Parse the Rietveld host from the URL. - m = RIETVELD_URL_RE.match(url) + # Parse the codereview host from the URL. + m = REVIEW_URL_RE.match(url) if not m: - logging.error('Cannot parse Rietveld host from URL: %s', url) + logging.error('Cannot parse codereview host from URL: %s', url) sys.exit(-1) - rietveld_server = m.group(1) - return CLInfo(issue_number, url, rietveld_server) + review_server = m.group(1) + return CLInfo(issue_number, url, review_server) def _GetCurrentBranchName(self): return self._RunCommand(
diff --git a/tools/roll_swiftshader.py b/tools/roll_swiftshader.py index 5a928ec..5b4dd0e 100755 --- a/tools/roll_swiftshader.py +++ b/tools/roll_swiftshader.py
@@ -31,12 +31,6 @@ "buildernames": ["android_optional_gpu_tests_rel"] } ] -extra_fyi_trybots = [ - { - "mastername": "master.tryserver.chromium.win", - "buildernames": ["win_clang_dbg"] - } -] SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__)) SRC_DIR = os.path.abspath(os.path.join(SCRIPT_DIR, os.pardir)) @@ -51,7 +45,7 @@ CHROMIUM_GIT_URL = 'https://chromium.googlesource.com/chromium/src.git' CL_ISSUE_RE = re.compile('^Issue number: ([0-9]+) \((.*)\)$') -RIETVELD_URL_RE = re.compile('^https?://(.*)/(.*)') +REVIEW_URL_RE = re.compile('^https?://(.*)/(.*)') ROLL_BRANCH_NAME = 'special_swiftshader_roll_branch' TRYJOB_STATUS_SLEEP_SECONDS = 30 @@ -61,7 +55,7 @@ CommitInfo = collections.namedtuple('CommitInfo', ['git_commit', 'git_repo_url']) -CLInfo = collections.namedtuple('CLInfo', ['issue', 'url', 'rietveld_server']) +CLInfo = collections.namedtuple('CLInfo', ['issue', 'url', 'review_server']) def _VarLookup(local_scope): return lambda var_name: local_scope['vars'][var_name] @@ -198,13 +192,13 @@ issue_number = int(m.group(1)) url = m.group(2) - # Parse the Rietveld host from the URL. - m = RIETVELD_URL_RE.match(url) + # Parse the codereview host from the URL. + m = REVIEW_URL_RE.match(url) if not m: - logging.error('Cannot parse Rietveld host from URL: %s', url) + logging.error('Cannot parse codereview host from URL: %s', url) sys.exit(-1) - rietveld_server = m.group(1) - return CLInfo(issue_number, url, rietveld_server) + review_server = m.group(1) + return CLInfo(issue_number, url, review_server) def _GetCurrentBranchName(self): return self._RunCommand( @@ -316,16 +310,6 @@ base_try_cmd = ['git', 'cl', 'try'] self._RunCommand(base_try_cmd) - if extra_cq_trybots: - # Run additional tryjobs. - # TODO(kbr): this should not be necessary -- the - # CQ_INCLUDE_TRYBOTS directive above should handle it. - # http://crbug.com/585237 - self._TriggerExtraTrybots(extra_cq_trybots) - - if extra_fyi_trybots: - self._TriggerExtraTrybots(extra_fyi_trybots) - # Mark the CL to be committed if requested if should_commit: self._RunCommand(['git', 'cl', 'set-commit'])
diff --git a/tools/roll_webgl_conformance.py b/tools/roll_webgl_conformance.py index 326f2c4..f0fad65 100755 --- a/tools/roll_webgl_conformance.py +++ b/tools/roll_webgl_conformance.py
@@ -29,6 +29,16 @@ "mastername": "master.tryserver.chromium.android", "buildernames": ["android_optional_gpu_tests_rel"] }, + # Include the ANGLE tryservers which run the WebGL conformance tests + # in some non-default configurations. + { + "mastername": "master.tryserver.chromium.angle", + "buildernames": ["linux_angle_rel_ng"] + }, + { + "mastername": "master.tryserver.chromium.angle", + "buildernames": ["win_angle_rel_ng"] + }, ] SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__)) @@ -44,7 +54,7 @@ CHROMIUM_GIT_URL = 'https://chromium.googlesource.com/chromium/src.git' CL_ISSUE_RE = re.compile('^Issue number: ([0-9]+) \((.*)\)$') -RIETVELD_URL_RE = re.compile('^https?://(.*)/(.*)') +REVIEW_URL_RE = re.compile('^https?://(.*)/(.*)') ROLL_BRANCH_NAME = 'special_webgl_roll_branch' TRYJOB_STATUS_SLEEP_SECONDS = 30 @@ -56,7 +66,7 @@ CommitInfo = collections.namedtuple('CommitInfo', ['git_commit', 'git_repo_url']) -CLInfo = collections.namedtuple('CLInfo', ['issue', 'url', 'rietveld_server']) +CLInfo = collections.namedtuple('CLInfo', ['issue', 'url', 'review_server']) def _VarLookup(local_scope): @@ -101,7 +111,7 @@ return '%s/+log/%s' % (git_repo_url, change_string) def GetBugString(bugs): - bug_str = 'BUG=' + bug_str = 'Bug: ' for bug in bugs: bug_str += str(bug) + ',' return bug_str.rstrip(',') @@ -121,17 +131,14 @@ s += t['mastername'] + ':' + ','.join(t['buildernames']) return s - extra_trybot_args = [] - if extra_trybots: - extra_trybot_string = GetExtraTrybotString() - extra_trybot_args = ['-m', 'CQ_INCLUDE_TRYBOTS=' + extra_trybot_string] - - return [ - '-m', 'Roll WebGL ' + change_str, - '-m', '%s' % changelog_url, - '-m', GetBugString(bugs), - '-m', 'TEST=bots', - ] + extra_trybot_args + return ('Roll WebGL %s\n\n' + '%s\n\n' + '%s\n' + 'Cq-Include-Trybots: %s\n') % ( + change_str, + changelog_url, + GetBugString(bugs), + GetExtraTrybotString()) class AutoRoller(object): @@ -189,13 +196,13 @@ issue_number = int(m.group(1)) url = m.group(2) - # Parse the Rietveld host from the URL. - m = RIETVELD_URL_RE.match(url) + # Parse the codereview host from the URL. + m = REVIEW_URL_RE.match(url) if not m: - logging.error('Cannot parse Rietveld host from URL: %s', url) + logging.error('Cannot parse codereview host from URL: %s', url) sys.exit(-1) - rietveld_server = m.group(1) - return CLInfo(issue_number, url, rietveld_server) + review_server = m.group(1) + return CLInfo(issue_number, url, review_server) def _GetCurrentBranchName(self): return self._RunCommand( @@ -289,7 +296,7 @@ webgl_current, webgl_latest, bugs) logging.debug('Committing changes locally.') self._RunCommand(['git', 'add', '--update', '.']) - self._RunCommand(['git', 'commit'] + description) + self._RunCommand(['git', 'commit', '-m', description]) logging.debug('Uploading changes...') self._RunCommand(['git', 'cl', 'upload'], extra_env={'EDITOR': 'true'}) @@ -298,16 +305,6 @@ # Kick off tryjobs. base_try_cmd = ['git', 'cl', 'try'] self._RunCommand(base_try_cmd) - if extra_trybots: - # Run additional tryjobs. - # TODO(kbr): this should not be necessary -- the - # CQ_INCLUDE_TRYBOTS directive above should handle it. - # http://crbug.com/585237 - for trybot in extra_trybots: - for builder in trybot['buildernames']: - self._RunCommand(base_try_cmd + [ - '-m', trybot['mastername'], - '-b', builder]) cl_info = self._GetCLInfo() print 'Issue: %d URL: %s' % (cl_info.issue, cl_info.url)
diff --git a/tools/roll_webrtc.py b/tools/roll_webrtc.py index 0599ffe7..23eb39f1 100755 --- a/tools/roll_webrtc.py +++ b/tools/roll_webrtc.py
@@ -18,7 +18,6 @@ sys.path.insert(0, os.path.join(SRC_DIR, 'build')) import find_depot_tools find_depot_tools.add_depot_tools_to_path() -import rietveld import roll_dep_svn from third_party import upload @@ -28,7 +27,7 @@ CHROMIUM_GIT_URL = 'https://chromium.googlesource.com/chromium/src.git' COMMIT_POSITION_RE = re.compile('^Cr-Commit-Position: .*#([0-9]+).*$') CL_ISSUE_RE = re.compile('^Issue number: ([0-9]+) \((.*)\)$') -RIETVELD_URL_RE = re.compile('^https?://(.*)/(.*)') +REVIEW_URL_RE = re.compile('^https?://(.*)/(.*)') ROLL_BRANCH_NAME = 'special_webrtc_roll_branch' TRYJOB_STATUS_SLEEP_SECONDS = 30 @@ -58,7 +57,7 @@ CommitInfo = collections.namedtuple('CommitInfo', ['commit_position', 'git_commit', 'git_repo_url']) -CLInfo = collections.namedtuple('CLInfo', ['issue', 'url', 'rietveld_server']) +CLInfo = collections.namedtuple('CLInfo', ['issue', 'url', 'review_server']) def _VarLookup(local_scope): @@ -105,44 +104,6 @@ return local_scope -def _WaitForTrybots(issue, rietveld_server): - """Wait until all trybots have passed or at least one have failed. - - Returns: - An exit code of 0 if all trybots passed or non-zero otherwise. - """ - assert type(issue) is int - print 'Trybot status for https://%s/%d:' % (rietveld_server, issue) - remote = rietveld.Rietveld('https://' + rietveld_server, None, None) - - attempt = 0 - max_tries = 60*60/TRYJOB_STATUS_SLEEP_SECONDS # Max one hour - while attempt < max_tries: - # Get patches for the issue so we can use the latest one. - data = remote.get_issue_properties(issue, messages=False) - patchsets = data['patchsets'] - - # Get trybot status for the latest patch set. - data = remote.get_patchset_properties(issue, patchsets[-1]) - - tryjob_results = data['try_job_results'] - if len(tryjob_results) == 0: - logging.debug('No trybots have yet been triggered for https://%s/%d' , - rietveld_server, issue) - else: - _PrintTrybotsStatus(tryjob_results) - if any(r['result'] in FAILURE_STATUS for r in tryjob_results): - logging.error('Found failing tryjobs (see above)') - return 1 - if all(r['result'] in SUCCESS_STATUS for r in tryjob_results): - return 0 - - logging.debug('Waiting for %d seconds before next check...', - TRYJOB_STATUS_SLEEP_SECONDS) - time.sleep(TRYJOB_STATUS_SLEEP_SECONDS) - attempt += 1 - - def _PrintTrybotsStatus(tryjob_results): status_to_name = {} for trybot_result in tryjob_results: @@ -154,6 +115,7 @@ for status,name_list in status_to_name.iteritems(): print '%s: %s' % (status, ','.join(sorted(name_list))) + class AutoRoller(object): def __init__(self, chromium_src): self._chromium_src = chromium_src @@ -245,13 +207,13 @@ issue_number = int(m.group(1)) url = m.group(2) - # Parse the Rietveld host from the URL. - m = RIETVELD_URL_RE.match(url) + # Parse the codereview host from the URL. + m = REVIEW_URL_RE.match(url) if not m: - logging.error('Cannot parse Rietveld host from URL: %s', url) + logging.error('Cannot parse codereview host from URL: %s', url) sys.exit(-1) - rietveld_server = m.group(1) - return CLInfo(issue_number, url, rietveld_server) + review_server = m.group(1) + return CLInfo(issue_number, url, review_server) def _GetCurrentBranchName(self): return self._RunCommand( @@ -386,13 +348,6 @@ self._RunCommand(['git', 'branch', '-D', ROLL_BRANCH_NAME]) return 0 - def WaitForTrybots(self): - active_branch, _ = self._GetBranches() - if active_branch != ROLL_BRANCH_NAME: - self._RunCommand(['git', 'checkout', ROLL_BRANCH_NAME]) - cl_info = self._GetCLInfo() - return _WaitForTrybots(cl_info.issue, cl_info.rietveld_server) - def main(): parser = argparse.ArgumentParser( @@ -405,12 +360,6 @@ help=('Don\'t send the CL to the CQ. This is useful if additional changes ' 'are needed to the CL (like for API changes).'), action='store_true') - parser.add_argument('--wait-for-trybots', - help=('Waits until all trybots from a previously created roll are either ' - 'successful or at least one has failed. This is useful to be able to ' - 'continuously run this script but not initiating new rolls until a ' - 'previous one is known to have passed or failed.'), - action='store_true') parser.add_argument('--close-previous-roll', action='store_true', help='Abort a previous roll if one exists.') parser.add_argument('--dry-run', action='store_true', default=False, @@ -434,8 +383,6 @@ autoroller = AutoRoller(SRC_DIR) if args.abort: return autoroller.Abort() - elif args.wait_for_trybots: - return autoroller.WaitForTrybots() else: return autoroller.PrepareRoll(args.dry_run, args.ignore_checks, args.no_commit, args.close_previous_roll,
diff --git a/tools/run-bisect-manual-test.py b/tools/run-bisect-manual-test.py deleted file mode 100755 index e1e6aeb..0000000 --- a/tools/run-bisect-manual-test.py +++ /dev/null
@@ -1,173 +0,0 @@ -#!/usr/bin/env python -# 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. - -"""Run Manual Test Bisect Tool - -An example usage: -tools/run-bisect-manual-test.py -g 201281 -b 201290 - -On Linux platform, follow the instructions in this document -https://chromium.googlesource.com/chromium/src/+/master/docs/linux_suid_sandbox_development.md -to setup the sandbox manually before running the script. Otherwise the script -fails to launch Chrome and exits with an error. - -This script serves a similar function to bisect-builds.py, except it uses -the bisect_perf_regression.py. This means that that it can obtain builds of -Chromium for revisions where builds aren't available in cloud storage. -""" - -import os -import subprocess -import sys - -CROS_BOARD_ENV = 'BISECT_CROS_BOARD' -CROS_IP_ENV = 'BISECT_CROS_IP' -_TOOLS_DIR = os.path.abspath(os.path.dirname(__file__)) -_BISECT_SCRIPT_PATH = os.path.join( - _TOOLS_DIR, 'auto_bisect', 'bisect_perf_regression.py') - -sys.path.append(os.path.join(_TOOLS_DIR, 'perf')) -from chrome_telemetry_build import chromium_config -sys.path.append(chromium_config.GetTelemetryDir()) -from telemetry.internal.browser import browser_options - - -def _RunBisectionScript(options): - """Attempts to execute the bisect script (bisect_perf_regression.py). - - Args: - options: The configuration options to pass to the bisect script. - - Returns: - An exit code; 0 for success, 1 for failure. - """ - script_path = os.path.join(options.working_directory, - 'bisect', 'src', 'tools','bisect-manual-test.py') - abs_script_path = os.path.abspath(script_path) - - test_command = ('python %s --browser=%s --chrome-root=.' % - (abs_script_path, options.browser_type)) - - cmd = ['python', _BISECT_SCRIPT_PATH, - '-c', test_command, - '-g', options.good_revision, - '-b', options.bad_revision, - '-m', 'manual_test/manual_test', - '-r', '1', - '--working_directory', options.working_directory, - '--build_preference', 'ninja', - '--no_custom_deps', - '--builder_type', options.builder_type] - - if options.extra_src: - cmd.extend(['--extra_src', options.extra_src]) - - if 'cros' in options.browser_type: - cmd.extend(['--target_platform', 'cros']) - - if os.environ[CROS_BOARD_ENV] and os.environ[CROS_IP_ENV]: - cmd.extend(['--cros_board', os.environ[CROS_BOARD_ENV]]) - cmd.extend(['--cros_remote_ip', os.environ[CROS_IP_ENV]]) - else: - print ('Error: Cros build selected, but BISECT_CROS_IP or' - 'BISECT_CROS_BOARD undefined.\n') - return 1 - elif 'android-chrome' == options.browser_type: - if not options.extra_src: - print 'Error: Missing --extra_src to run bisect for android-chrome.' - sys.exit(-1) - cmd.extend(['--target_platform', 'android-chrome']) - elif 'android' in options.browser_type: - cmd.extend(['--target_platform', 'android']) - elif not options.target_build_type: - cmd.extend(['--target_build_type', options.browser_type.title()]) - - if options.target_build_type: - cmd.extend(['--target_build_type', options.target_build_type]) - - if options.goma_threads: - cmd.extend(['--use_goma', '--goma_threads', options.goma_threads]) - - cmd = [str(c) for c in cmd] - - return_code = subprocess.call(cmd) - - if return_code: - print 'Error: bisect_perf_regression.py had exit code %d.' % return_code - print - - return return_code - - -def main(): - """Does a bisect based on the command-line arguments passed in. - - The user will be prompted to classify each revision as good or bad. - """ - usage = ('%prog [options]\n' - 'Used to run the bisection script with a manual test.') - - options = browser_options.BrowserFinderOptions('release') - parser = options.CreateParser(usage) - - parser.add_option('-b', '--bad_revision', - type='str', - help='A bad revision to start bisection. ' + - 'Must be later than good revision. May be either a git' + - ' or svn revision.') - parser.add_option('-g', '--good_revision', - type='str', - help='A revision to start bisection where performance' + - ' test is known to pass. Must be earlier than the ' + - 'bad revision. May be either a git or svn revision.') - parser.add_option('-w', '--working_directory', - type='str', - default='..', - help='A working directory to supply to the bisection ' - 'script, which will use it as the location to checkout ' - 'a copy of the chromium depot.') - parser.add_option('--extra_src', - type='str', - help='Path to extra source file. If this is supplied, ' - 'bisect script will use this to override default behavior.') - parser.add_option('--target_build_type', - type='choice', - choices=['Release', 'Debug'], - help='The target build type. Choices are "Release" ' - 'or "Debug".') - parser.add_option('--goma_threads', default=64, - type='int', - help='Number of goma threads to use. 0 will disable goma.') - parser.add_option('--builder_type', default='', - choices=['perf', - 'full', - 'android-chrome-perf', ''], - help='Type of builder to get build from. This allows ' - 'script to use cached builds. By default (empty), binaries ' - 'are built locally.') - options, _ = parser.parse_args() - error_msg = '' - if not options.good_revision: - error_msg += 'Error: missing required parameter: --good_revision\n' - if not options.bad_revision: - error_msg += 'Error: missing required parameter: --bad_revision\n' - - if error_msg: - print error_msg - parser.print_help() - return 1 - - if 'android' not in options.browser_type and sys.platform.startswith('linux'): - if not os.environ.get('CHROME_DEVEL_SANDBOX'): - print 'SUID sandbox has not been setup.'\ - ' See https://chromium.googlesource.com/chromium/src/'\ - '+/master/docs/linux_suid_sandbox_development.md.' - return 1 - - return _RunBisectionScript(options) - - -if __name__ == '__main__': - sys.exit(main())
diff --git a/tools/run-bisect-perf-regression.py b/tools/run-bisect-perf-regression.py deleted file mode 100755 index 52019db..0000000 --- a/tools/run-bisect-perf-regression.py +++ /dev/null
@@ -1,886 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 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. - -"""Run Performance Test Bisect Tool - -This script is used by a try bot to run the bisect script with the parameters -specified in the bisect config file. It checks out a copy of the depot in -a subdirectory 'bisect' of the working directory provided, annd runs the -bisect scrip there. -""" - -import json -import optparse -import os -import platform -import re -import shlex -import subprocess -import sys -import traceback - -from auto_bisect import bisect_perf_regression -from auto_bisect import bisect_utils -from auto_bisect import math_utils -from auto_bisect import source_control - -CROS_BOARD_ENV = 'BISECT_CROS_BOARD' -CROS_IP_ENV = 'BISECT_CROS_IP' -SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__)) -SRC_DIR = os.path.join(SCRIPT_DIR, os.path.pardir) -BISECT_CONFIG_PATH = os.path.join(SCRIPT_DIR, 'auto_bisect', 'bisect.cfg') -RUN_TEST_CONFIG_PATH = os.path.join(SCRIPT_DIR, 'run-perf-test.cfg') -WEBKIT_RUN_TEST_CONFIG_PATH = os.path.join( - SRC_DIR, 'third_party', 'WebKit', 'Tools', 'run-perf-test.cfg') -BISECT_SCRIPT_DIR = os.path.join(SCRIPT_DIR, 'auto_bisect') - -PERF_BENCHMARKS_PATH = 'tools/perf/benchmarks' -PERF_MEASUREMENTS_PATH = 'tools/perf/measurements' -BUILDBOT_BUILDERNAME = 'BUILDBOT_BUILDERNAME' -BENCHMARKS_JSON_FILE = 'benchmarks.json' - -# This is used to identify tryjobs triggered by the commit queue. -_COMMIT_QUEUE_USERS = [ - '5071639625-1lppvbtck1morgivc6sq4dul7klu27sd@developer.gserviceaccount.com', - 'commit-bot@chromium.org'] - -class Goma(object): - - def __init__(self, path_to_goma): - self._abs_path_to_goma = None - self._abs_path_to_goma_file = None - if not path_to_goma: - return - self._abs_path_to_goma = os.path.abspath(path_to_goma) - filename = 'goma_ctl.bat' if os.name == 'nt' else 'goma_ctl.sh' - self._abs_path_to_goma_file = os.path.join(self._abs_path_to_goma, filename) - - def __enter__(self): - if self._HasGomaPath(): - self._SetupAndStart() - return self - - def __exit__(self, *_): - if self._HasGomaPath(): - self._Stop() - - def _HasGomaPath(self): - return bool(self._abs_path_to_goma) - - def _SetupEnvVars(self): - if os.name == 'nt': - os.environ['CC'] = (os.path.join(self._abs_path_to_goma, 'gomacc.exe') + - ' cl.exe') - os.environ['CXX'] = (os.path.join(self._abs_path_to_goma, 'gomacc.exe') + - ' cl.exe') - else: - os.environ['PATH'] = os.pathsep.join([self._abs_path_to_goma, - os.environ['PATH']]) - - def _SetupAndStart(self): - """Sets up goma and launches it. - - Args: - path_to_goma: Path to goma directory. - - Returns: - True if successful.""" - self._SetupEnvVars() - - # Sometimes goma is lingering around if something went bad on a previous - # run. Stop it before starting a new process. Can ignore the return code - # since it will return an error if it wasn't running. - self._Stop() - - if subprocess.call([self._abs_path_to_goma_file, 'start']): - raise RuntimeError('Goma failed to start.') - - def _Stop(self): - subprocess.call([self._abs_path_to_goma_file, 'stop']) - - -def _LoadConfigFile(config_file_path): - """Attempts to load the specified config file as a module - and grab the global config dict. - - Args: - config_file_path: Path to the config file. - - Returns: - If successful, returns the config dict loaded from the file. If no - such dictionary could be loaded, returns the empty dictionary. - """ - try: - local_vars = {} - execfile(config_file_path, local_vars) - return local_vars['config'] - except Exception: - print - traceback.print_exc() - print - return {} - - -def _ValidateConfigFile(config_contents, required_parameters): - """Validates the config file contents, checking whether all values are - non-empty. - - Args: - config_contents: A config dictionary. - required_parameters: A list of parameters to check for. - - Returns: - True if valid. - """ - for parameter in required_parameters: - if parameter not in config_contents: - return False - value = config_contents[parameter] - if not value or type(value) is not str: - return False - return True - - -def _ValidatePerfConfigFile(config_contents): - """Validates the perf config file contents. - - This is used when we're doing a perf try job, rather than a bisect. - The config file is called run-perf-test.cfg by default. - - The parameters checked are the required parameters; any additional optional - parameters won't be checked and validation will still pass. - - Args: - config_contents: A config dictionary. - - Returns: - True if valid. - """ - return _ValidateConfigFile(config_contents, required_parameters=['command']) - - -def _ValidateBisectConfigFile(config_contents): - """Validates the bisect config file contents. - - The parameters checked are the required parameters; any additional optional - parameters won't be checked and validation will still pass. - - Args: - config_contents: A config dictionary. - - Returns: - True if valid. - """ - return _ValidateConfigFile( - config_contents, - required_parameters=['command', 'good_revision', 'bad_revision']) - - -def _OutputFailedResults(text_to_print): - bisect_utils.OutputAnnotationStepStart('Results - Failed') - print - print text_to_print - print - bisect_utils.OutputAnnotationStepClosed() - - -def _CreateBisectOptionsFromConfig(config): - print config['command'] - opts_dict = {} - opts_dict['command'] = config['command'] - opts_dict['metric'] = config.get('metric') - - if config['repeat_count']: - opts_dict['repeat_test_count'] = int(config['repeat_count']) - - if config['truncate_percent']: - opts_dict['truncate_percent'] = int(config['truncate_percent']) - - if config['max_time_minutes']: - opts_dict['max_time_minutes'] = _Clamp( - int(config['max_time_minutes']), low=1, high=60) - - if config.has_key('use_goma'): - opts_dict['use_goma'] = config['use_goma'] - if config.has_key('goma_dir'): - opts_dict['goma_dir'] = config['goma_dir'] - - if config.has_key('improvement_direction'): - opts_dict['improvement_direction'] = int(config['improvement_direction']) - - if config.has_key('required_initial_confidence'): - opts_dict['required_initial_confidence'] = float( - config['required_initial_confidence']) - - if config.has_key('target_arch'): - opts_dict['target_arch'] = config['target_arch'] - - if config.has_key('bug_id') and str(config['bug_id']).isdigit(): - opts_dict['bug_id'] = config['bug_id'] - - if config.has_key('try_job_id'): - opts_dict['try_job_id'] = config['try_job_id'] - - opts_dict['build_preference'] = 'ninja' - opts_dict['output_buildbot_annotations'] = True - - if '--browser=cros' in config['command']: - opts_dict['target_platform'] = 'cros' - - if os.environ[CROS_BOARD_ENV] and os.environ[CROS_IP_ENV]: - opts_dict['cros_board'] = os.environ[CROS_BOARD_ENV] - opts_dict['cros_remote_ip'] = os.environ[CROS_IP_ENV] - else: - raise RuntimeError('CrOS build selected, but BISECT_CROS_IP or' - 'BISECT_CROS_BOARD undefined.') - elif 'android' in config['command']: - if 'android-chromium' in config['command']: - opts_dict['target_platform'] = 'android' - elif 'android-chrome' in config['command']: - opts_dict['target_platform'] = 'android-chrome' - else: - opts_dict['target_platform'] = 'android' - - return bisect_perf_regression.BisectOptions.FromDict(opts_dict) - - -def _Clamp(n, low, high): - """Clamps a value to a range.""" - return min(high, max(low, n)) - - -def _ParseCloudLinksFromOutput(output): - html_results_pattern = re.compile( - r'\s(?P<VALUES>http://storage.googleapis.com/' + - 'chromium-telemetry/html-results/results-[a-z0-9-_]+)\s', - re.MULTILINE) - profiler_pattern = re.compile( - r'\s(?P<VALUES>https://console.developers.google.com/' + - 'm/cloudstorage/b/[a-z-]+/o/profiler-[a-z0-9-_.]+)\s', - re.MULTILINE) - - results = { - 'html-results': html_results_pattern.findall(output), - 'profiler': profiler_pattern.findall(output), - } - - return results - - -def _ParseAndOutputCloudLinks( - results_without_patch, results_with_patch, annotations_dict): - cloud_links_without_patch = _ParseCloudLinksFromOutput( - results_without_patch[2]) - cloud_links_with_patch = _ParseCloudLinksFromOutput( - results_with_patch[2]) - - cloud_file_link = (cloud_links_without_patch['html-results'][0] - if cloud_links_without_patch['html-results'] else '') - - profiler_file_links_with_patch = cloud_links_with_patch['profiler'] - profiler_file_links_without_patch = cloud_links_without_patch['profiler'] - - # Calculate the % difference in the means of the 2 runs. - percent_diff_in_means = None - std_err = None - if (results_with_patch[0].has_key('mean') and - results_with_patch[0].has_key('values')): - percent_diff_in_means = (results_with_patch[0]['mean'] / - max(0.0001, results_without_patch[0]['mean'])) * 100.0 - 100.0 - std_err = math_utils.PooledStandardError( - [results_with_patch[0]['values'], results_without_patch[0]['values']]) - - if percent_diff_in_means is not None and std_err is not None: - bisect_utils.OutputAnnotationStepStart('Results - %.02f +- %0.02f delta' % - (percent_diff_in_means, std_err)) - print ' %s %s %s' % (''.center(10, ' '), 'Mean'.center(20, ' '), - 'Std. Error'.center(20, ' ')) - print ' %s %s %s' % ('Patch'.center(10, ' '), - ('%.02f' % results_with_patch[0]['mean']).center(20, ' '), - ('%.02f' % results_with_patch[0]['std_err']).center(20, ' ')) - print ' %s %s %s' % ('No Patch'.center(10, ' '), - ('%.02f' % results_without_patch[0]['mean']).center(20, ' '), - ('%.02f' % results_without_patch[0]['std_err']).center(20, ' ')) - if cloud_file_link: - bisect_utils.OutputAnnotationStepLink('HTML Results', cloud_file_link) - bisect_utils.OutputAnnotationStepClosed() - elif cloud_file_link: - bisect_utils.OutputAnnotationStepLink('HTML Results', cloud_file_link) - - if profiler_file_links_with_patch and profiler_file_links_without_patch: - for i in xrange(len(profiler_file_links_with_patch)): - bisect_utils.OutputAnnotationStepLink( - '%s[%d]' % (annotations_dict.get('profiler_link1'), i), - profiler_file_links_with_patch[i]) - for i in xrange(len(profiler_file_links_without_patch)): - bisect_utils.OutputAnnotationStepLink( - '%s[%d]' % (annotations_dict.get('profiler_link2'), i), - profiler_file_links_without_patch[i]) - - -def _ResolveRevisionsFromConfig(config): - if not 'good_revision' in config and not 'bad_revision' in config: - return (None, None) - - bad_revision = source_control.ResolveToRevision( - config['bad_revision'], 'chromium', bisect_utils.DEPOT_DEPS_NAME, 100) - if not bad_revision: - raise RuntimeError('Failed to resolve [%s] to git hash.', - config['bad_revision']) - good_revision = source_control.ResolveToRevision( - config['good_revision'], 'chromium', bisect_utils.DEPOT_DEPS_NAME, -100) - if not good_revision: - raise RuntimeError('Failed to resolve [%s] to git hash.', - config['good_revision']) - - return (good_revision, bad_revision) - - -def _GetStepAnnotationStringsDict(config): - if 'good_revision' in config and 'bad_revision' in config: - return { - 'build1': 'Building [%s]' % config['good_revision'], - 'build2': 'Building [%s]' % config['bad_revision'], - 'run1': 'Running [%s]' % config['good_revision'], - 'run2': 'Running [%s]' % config['bad_revision'], - 'sync1': 'Syncing [%s]' % config['good_revision'], - 'sync2': 'Syncing [%s]' % config['bad_revision'], - 'results_label1': config['good_revision'], - 'results_label2': config['bad_revision'], - 'profiler_link1': 'Profiler Data - %s' % config['good_revision'], - 'profiler_link2': 'Profiler Data - %s' % config['bad_revision'], - } - else: - return { - 'build1': 'Building With Patch', - 'build2': 'Building Without Patch', - 'run1': 'Running With Patch', - 'run2': 'Running Without Patch', - 'results_label1': 'Patch', - 'results_label2': 'ToT', - 'profiler_link1': 'With Patch - Profiler Data', - 'profiler_link2': 'Without Patch - Profiler Data', - } - - -def _RunBuildStepForPerformanceTest(bisect_instance, - build_string, - sync_string, - revision): - if revision: - bisect_utils.OutputAnnotationStepStart(sync_string) - if not source_control.SyncToRevision(revision, 'gclient'): - raise RuntimeError('Failed [%s].' % sync_string) - bisect_utils.OutputAnnotationStepClosed() - - bisect_utils.OutputAnnotationStepStart(build_string) - - if bisect_utils.RunGClient(['runhooks']): - raise RuntimeError('Failed to run gclient runhooks') - - if not bisect_instance.ObtainBuild('chromium'): - raise RuntimeError('Patched version failed to build.') - - bisect_utils.OutputAnnotationStepClosed() - - -def _RunCommandStepForPerformanceTest(bisect_instance, - opts, - reset_on_first_run, - upload_on_last_run, - results_label, - run_string): - bisect_utils.OutputAnnotationStepStart(run_string) - - results = bisect_instance.RunPerformanceTestAndParseResults( - opts.command, - opts.metric, - reset_on_first_run=reset_on_first_run, - upload_on_last_run=upload_on_last_run, - results_label=results_label, - allow_flakes=False) - - if results[1]: - raise RuntimeError('Patched version failed to run performance test.') - - bisect_utils.OutputAnnotationStepClosed() - - return results - - -def _RunPerformanceTest(config): - """Runs a performance test with and without the current patch. - - Args: - config: Contents of the config file, a dictionary. - - Attempts to build and run the current revision with and without the - current patch, with the parameters passed in. - """ - # Bisect script expects to be run from the src directory - os.chdir(SRC_DIR) - - opts = _CreateBisectOptionsFromConfig(config) - revisions = _ResolveRevisionsFromConfig(config) - annotations_dict = _GetStepAnnotationStringsDict(config) - b = bisect_perf_regression.BisectPerformanceMetrics(opts, os.getcwd()) - - _RunBuildStepForPerformanceTest(b, - annotations_dict.get('build1'), - annotations_dict.get('sync1'), - revisions[0]) - - results_with_patch = _RunCommandStepForPerformanceTest( - b, opts, True, True, annotations_dict['results_label1'], - annotations_dict['run1']) - - bisect_utils.OutputAnnotationStepStart('Reverting Patch') - # TODO: When this is re-written to recipes, this should use bot_update's - # revert mechanism to fully revert the client. But for now, since we know that - # the perf try bot currently only supports src/ and src/third_party/WebKit, we - # simply reset those two directories. - bisect_utils.CheckRunGit(['reset', '--hard']) - bisect_utils.CheckRunGit(['reset', '--hard'], - os.path.join('third_party', 'WebKit')) - bisect_utils.OutputAnnotationStepClosed() - - _RunBuildStepForPerformanceTest(b, - annotations_dict.get('build2'), - annotations_dict.get('sync2'), - revisions[1]) - - results_without_patch = _RunCommandStepForPerformanceTest( - b, opts, False, True, annotations_dict['results_label2'], - annotations_dict['run2']) - - # Find the link to the cloud stored results file. - _ParseAndOutputCloudLinks( - results_without_patch, results_with_patch, annotations_dict) - - -def _SetupAndRunPerformanceTest(config, path_to_goma, is_cq_tryjob=False): - """Attempts to build and run the current revision with and without the - current patch, with the parameters passed in. - - Args: - config: The config read from run-perf-test.cfg. - path_to_goma: Path to goma directory. - is_cq_tryjob: Whether or not the try job was initiated by commit queue. - - Returns: - An exit code: 0 on success, otherwise 1. - """ - if platform.release() == 'XP': - print 'Windows XP is not supported for perf try jobs because it lacks ' - print 'goma support. Please refer to crbug.com/330900.' - return 1 - try: - with Goma(path_to_goma) as _: - config['use_goma'] = bool(path_to_goma) - if config['use_goma']: - config['goma_dir'] = os.path.abspath(path_to_goma) - if not is_cq_tryjob: - _RunPerformanceTest(config) - else: - return _RunBenchmarksForCommitQueue(config) - return 0 - except RuntimeError, e: - bisect_utils.OutputAnnotationStepFailure() - bisect_utils.OutputAnnotationStepClosed() - _OutputFailedResults('Error: %s' % e.message) - return 1 - - -def _RunBisectionScript( - config, working_directory, path_to_goma, path_to_extra_src, dry_run): - """Attempts to execute the bisect script with the given parameters. - - Args: - config: A dict containing the parameters to pass to the script. - working_directory: A working directory to provide to the bisect script, - where it will store it's own copy of the depot. - path_to_goma: Path to goma directory. - path_to_extra_src: Path to extra source file. - dry_run: Do a dry run, skipping sync, build, and performance testing steps. - - Returns: - An exit status code: 0 on success, otherwise 1. - """ - _PrintConfigStep(config) - - # Construct the basic command with all necessary arguments. - cmd = [ - 'python', - os.path.join(BISECT_SCRIPT_DIR, 'bisect_perf_regression.py'), - '--command', config['command'], - '--good_revision', config['good_revision'], - '--bad_revision', config['bad_revision'], - '--working_directory', working_directory, - '--output_buildbot_annotations' - ] - - # Add flags for any optional config parameters if given in the config. - options = [ - ('metric', '--metric'), - ('repeat_count', '--repeat_test_count'), - ('truncate_percent', '--truncate_percent'), - ('max_time_minutes', '--max_time_minutes'), - ('bisect_mode', '--bisect_mode'), - ('improvement_direction', '--improvement_direction'), - ('bug_id', '--bug_id'), - ('try_job_id', '--try_job_id'), - ('builder_type', '--builder_type'), - ('target_arch', '--target_arch'), - ('required_initial_confidence', '--required_initial_confidence'), - ] - for config_key, flag in options: - if config.has_key(config_key): - cmd.extend([flag, config[config_key]]) - - cmd.extend(['--build_preference', 'ninja']) - - # Possibly set the target platform name based on the browser name in a - # Telemetry command. - if 'android-chromium' in config['command']: - cmd.extend(['--target_platform', 'android']) - elif 'android-chrome' in config['command']: - cmd.extend(['--target_platform', 'android-chrome']) - elif 'android' in config['command']: - cmd.extend(['--target_platform', 'android']) - - if path_to_goma: - # For Windows XP platforms, goma service is not supported. - # Moreover we don't compile chrome when gs_bucket flag is set instead - # use builds archives, therefore ignore goma service for Windows XP. - # See http://crbug.com/330900. - if platform.release() == 'XP': - print ('Goma doesn\'t have a win32 binary, therefore it is not supported ' - 'on Windows XP platform. Please refer to crbug.com/330900.') - path_to_goma = None - cmd.append('--use_goma') - cmd.append('--goma_dir') - cmd.append(os.path.abspath(path_to_goma)) - - if path_to_extra_src: - cmd.extend(['--extra_src', path_to_extra_src]) - - if dry_run: - cmd.extend([ - '--debug_ignore_build', - '--debug_ignore_sync', - '--debug_ignore_perf_test' - ]) - - cmd = [str(c) for c in cmd] - - with Goma(path_to_goma) as _: - return_code = subprocess.call(cmd) - - if return_code: - print ('Error: bisect_perf_regression.py returned with error %d\n' - % return_code) - - return return_code - - -def _PrintConfigStep(config): - """Prints out the given config, along with Buildbot annotations.""" - bisect_utils.OutputAnnotationStepStart('Config') - print - for k, v in config.iteritems(): - print ' %s : %s' % (k, v) - print - bisect_utils.OutputAnnotationStepClosed() - - -def _GetBrowserType(bot_platform): - """Gets the browser type to be used in the run benchmark command.""" - if bot_platform == 'android': - return 'android-chromium' - elif 'x64' in bot_platform: - return 'release_x64' - - return 'release' - - - -def _GuessTelemetryTestCommand(bot_platform, test_name=None): - """Creates a Telemetry benchmark command based on bot and test name.""" - command = [] - # On Windows, Python scripts should be prefixed with the python command. - if bot_platform == 'win': - command.append('python') - command.append('tools/perf/run_benchmark') - command.append('-v') - command.append('--browser=%s' % _GetBrowserType(bot_platform)) - if test_name: - command.append(test_name) - - return ' '.join(command) - - -def _GetConfigBasedOnPlatform(config, bot_name, test_name): - """Generates required options to create BisectPerformanceMetrics instance.""" - opts_dict = { - 'command': _GuessTelemetryTestCommand(bot_name, test_name), - 'target_arch': 'x64' if 'x64' in bot_name else 'ia32', - 'build_preference': 'ninja', - 'output_buildbot_annotations': True, - 'repeat_test_count': 1, - 'bisect_mode': bisect_utils.BISECT_MODE_RETURN_CODE, - } - - if 'use_goma' in config: - opts_dict['use_goma'] = config['use_goma'] - if 'goma_dir' in config: - opts_dict['goma_dir'] = config['goma_dir'] - if 'android-chromium' in opts_dict['command']: - opts_dict['target_platform'] = 'android' - - return bisect_perf_regression.BisectOptions.FromDict(opts_dict) - - -def _GetModifiedFilesFromPatch(cwd=None): - """Gets list of files modified in the current patch.""" - log_output = bisect_utils.CheckRunGit( - ['diff', '--no-ext-diff', '--name-only', 'HEAD~1'], cwd=cwd) - modified_files = log_output.split() - return modified_files - - -def _GetAffectedBenchmarkModuleNames(): - """Gets list of modified benchmark files under tools/perf/benchmarks.""" - all_affected_files = _GetModifiedFilesFromPatch() - modified_benchmarks = [] - for affected_file in all_affected_files: - if (affected_file.startswith(PERF_BENCHMARKS_PATH) or - affected_file.startswith(PERF_MEASUREMENTS_PATH)): - benchmark = os.path.basename(os.path.splitext(affected_file)[0]) - modified_benchmarks.append(benchmark) - return modified_benchmarks - - -def _ListAvailableBenchmarks(bot_platform): - """Gets all available benchmarks names as a list.""" - browser_type = _GetBrowserType(bot_platform) - if os.path.exists(BENCHMARKS_JSON_FILE): - os.remove(BENCHMARKS_JSON_FILE) - command = [] - if 'win' in bot_platform: - command.append('python') - command.append('tools/perf/run_benchmark') - command.extend([ - 'list', - '--browser', - browser_type, - '--json-output', - BENCHMARKS_JSON_FILE]) - try: - output, return_code = bisect_utils.RunProcessAndRetrieveOutput( - command=command, cwd=SRC_DIR) - if return_code: - raise RuntimeError('Something went wrong while listing benchmarks. ' - 'Please review the command line: %s.\nERROR: [%s]' % - (' '.join(command), output)) - with open(BENCHMARKS_JSON_FILE) as tests_json: - tests_data = json.load(tests_json) - if tests_data.get('steps'): - return tests_data.get('steps').keys() - finally: - try: - if os.path.exists(BENCHMARKS_JSON_FILE): - os.remove(BENCHMARKS_JSON_FILE) - except OSError as e: - if e.errno != errno.ENOENT: - raise - return None - - -def _OutputOverallResults(results): - """Creates results step and prints results on buildbot job.""" - test_status = all(current_value == True for current_value in results.values()) - bisect_utils.OutputAnnotationStepStart( - 'Results - %s' % ('Passed' if test_status else 'Failed')) - print - print 'Results of benchmarks:' - print - for benchmark, result in results.iteritems(): - print '%s: %s' % (benchmark, 'Passed' if result else 'Failed') - if not test_status: - bisect_utils.OutputAnnotationStepFailure() - bisect_utils.OutputAnnotationStepClosed() - # Returns 0 for success and 1 for failure. - return 0 if test_status else 1 - - -def _RunBenchmark(bisect_instance, opts, bot_name, benchmark_name): - """Runs a Telemetry benchmark.""" - bisect_utils.OutputAnnotationStepStart(benchmark_name) - command_to_run = _GuessTelemetryTestCommand(bot_name, benchmark_name) - args = shlex.split(command_to_run, posix=not bisect_utils.IsWindowsHost()) - output, return_code = bisect_utils.RunProcessAndRetrieveOutput(args, SRC_DIR) - # A value other than 0 indicates that the test couldn't be run, and results - # should also include an error message. - if return_code: - print ('Error: Something went wrong running the benchmark: %s.' - 'Please review the command line:%s\n\n%s' % - (benchmark_name, command_to_run, output)) - bisect_utils.OutputAnnotationStepFailure() - print output - bisect_utils.OutputAnnotationStepClosed() - # results[1] contains the return code from subprocess that executes test - # command, On successful test run it contains 0 otherwise any non-zero value. - return return_code == 0 - - -def _RunBenchmarksForCommitQueue(config): - """Runs Telemetry benchmark for the commit queue.""" - os.chdir(SRC_DIR) - # To determine the bot platform by reading buildbot name from environment - # variable. - bot_name = os.environ.get(BUILDBOT_BUILDERNAME) - if not bot_name: - bot_name = sys.platform - bot_name = bot_name.split('_')[0] - - affected_benchmarks = _GetAffectedBenchmarkModuleNames() - # Abort if there are no changes to benchmark any existing benchmark files. - if not affected_benchmarks: - bisect_utils.OutputAnnotationStepStart('Results') - print - print ('There are no modification to Telemetry benchmarks,' - ' aborting the try job.') - bisect_utils.OutputAnnotationStepClosed() - return 0 - - # Bisect script expects to be run from the src directory - # Gets required options inorder to create BisectPerformanceMetrics instance. - # Since command is a required arg in BisectPerformanceMetrics, we just create - # a dummy command for now. - opts = _GetConfigBasedOnPlatform(config, bot_name, test_name='') - annotations_dict = _GetStepAnnotationStringsDict(config) - b = bisect_perf_regression.BisectPerformanceMetrics(opts, os.getcwd()) - _RunBuildStepForPerformanceTest(b, - annotations_dict.get('build1'), - annotations_dict.get('sync1'), - None) - available_benchmarks = _ListAvailableBenchmarks(bot_name) - overall_results = {} - for affected_benchmark in affected_benchmarks: - for benchmark in available_benchmarks: - if (benchmark.startswith(affected_benchmark) and - not benchmark.endswith('reference')): - overall_results[benchmark] = _RunBenchmark(b, opts, bot_name, benchmark) - - return _OutputOverallResults(overall_results) - - -def _OptionParser(): - """Returns the options parser for run-bisect-perf-regression.py.""" - - def ConvertJson(option, _, value, parser): - """Provides an OptionParser callback to unmarshal a JSON string.""" - setattr(parser.values, option.dest, json.loads(value)) - - usage = ('%prog [options] [-- chromium-options]\n' - 'Used by a try bot to run the bisection script using the parameters' - ' provided in the auto_bisect/bisect.cfg file.') - parser = optparse.OptionParser(usage=usage) - parser.add_option('-w', '--working_directory', - type='str', - help='A working directory to supply to the bisection ' - 'script, which will use it as the location to checkout ' - 'a copy of the chromium depot.') - parser.add_option('-p', '--path_to_goma', - type='str', - help='Path to goma directory. If this is supplied, goma ' - 'builds will be enabled.') - parser.add_option('--path_to_config', - type='str', - help='Path to the config file to use. If this is supplied, ' - 'the bisect script will use this to override the default ' - 'config file path. The script will attempt to load it ' - 'as a bisect config first, then a perf config.') - parser.add_option('--extra_src', - type='str', - help='Path to extra source file. If this is supplied, ' - 'bisect script will use this to override default behavior.') - parser.add_option('--dry_run', - action="store_true", - help='The script will perform the full bisect, but ' - 'without syncing, building, or running the performance ' - 'tests.') - # This argument is passed by buildbot to supply build properties to the bisect - # script. Note: Don't change "--build-properties" property name. - parser.add_option('--build-properties', action='callback', - dest='build_properties', - callback=ConvertJson, type='string', - nargs=1, default={}, - help='build properties in JSON format') - - return parser - - -def main(): - """Entry point for run-bisect-perf-regression.py. - - Reads the config file, and then tries to either bisect a regression or - just run a performance test, depending on the particular config parameters - specified in the config file. - """ - parser = _OptionParser() - opts, _ = parser.parse_args() - - # Use the default config file path unless one was specified. - config_path = BISECT_CONFIG_PATH - if opts.path_to_config: - config_path = opts.path_to_config - config = _LoadConfigFile(config_path) - - # Check if the config is valid for running bisect job. - config_is_valid = _ValidateBisectConfigFile(config) - - if config and config_is_valid: - if not opts.working_directory: - print 'Error: missing required parameter: --working_directory\n' - parser.print_help() - return 1 - - return _RunBisectionScript( - config, opts.working_directory, opts.path_to_goma, opts.extra_src, - opts.dry_run) - - # If it wasn't valid for running a bisect, then maybe the user wanted - # to run a perf test instead of a bisect job. Try reading any possible - # perf test config files. - perf_cfg_files = [RUN_TEST_CONFIG_PATH, WEBKIT_RUN_TEST_CONFIG_PATH] - for current_perf_cfg_file in perf_cfg_files: - if opts.path_to_config: - path_to_perf_cfg = opts.path_to_config - else: - path_to_perf_cfg = os.path.join( - os.path.abspath(os.path.dirname(sys.argv[0])), - current_perf_cfg_file) - - config = _LoadConfigFile(path_to_perf_cfg) - config_is_valid = _ValidatePerfConfigFile(config) - - if config and config_is_valid: - return _SetupAndRunPerformanceTest(config, opts.path_to_goma) - - # If there are no changes to config file, then check if the request is - # from the commit queue, if so then run the modified Telemetry benchmarks for - # the patch. - if opts.build_properties.get('requester') in _COMMIT_QUEUE_USERS: - return _SetupAndRunPerformanceTest( - config={}, path_to_goma=opts.path_to_goma, is_cq_tryjob=True) - - print ('Error: Could not load config file. Double check your changes to ' - 'auto_bisect/bisect.cfg or run-perf-test.cfg for syntax errors.\n') - return 1 - - -if __name__ == '__main__': - sys.exit(main())
diff --git a/tools/run-perf-test.cfg b/tools/run-perf-test.cfg deleted file mode 100644 index 2529fca9..0000000 --- a/tools/run-perf-test.cfg +++ /dev/null
@@ -1,77 +0,0 @@ -# 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. - -"""Config file for Run Performance Test Bot - -This script is intended for use by anyone that wants to run a remote performance -test. Modify the config below and add the command to run the performance test, -the metric you're interested in, and repeat/discard parameters. You can then -run a git try <bot>. - -Changes to this file should never be submitted. - -Args: - 'command': This is the full command line to pass to the - bisect-perf-regression.py script in order to execute the test. - 'metric': The name of the metric to parse out from the results of the - performance test. You can retrieve the metric by looking at the stdio of - the performance test. Look for lines of the format: - - RESULT <graph>: <trace>= <value> <units> - - The metric name is "<graph>/<trace>". - 'repeat_count': The number of times to repeat the performance test. - 'max_time_minutes': The script will attempt to run the performance test - "repeat_count" times, unless it exceeds "max_time_minutes". - 'truncate_percent': Discard the highest/lowest % values from performance test. - -Sample config: - -config = { - 'command': './tools/perf/run_benchmark --browser=release smoothness.key_mobile_sites', - 'metric': 'mean_frame_time/mean_frame_time', - 'repeat_count': '20', - 'max_time_minutes': '20', - 'truncate_percent': '25', -} - -On Windows: - - If you're calling a python script you will need to add "python" to -the command: - -config = { - 'command': 'python tools/perf/run_benchmark -v --browser=release smoothness.key_mobile_sites', - 'metric': 'mean_frame_time/mean_frame_time', - 'repeat_count': '20', - 'max_time_minutes': '20', - 'truncate_percent': '25', -} - - -On ChromeOS: - - Script accepts either ChromeOS versions, or unix timestamps as revisions. - - You don't need to specify --identity and --remote, they will be added to - the command using the bot's BISECT_CROS_IP and BISECT_CROS_BOARD values. - -config = { - 'command': './tools/perf/run_benchmark -v '\ - '--browser=cros-chrome-guest '\ - 'smoothness.key_mobile_sites', - 'metric': 'mean_frame_time/mean_frame_time', - 'repeat_count': '20', - 'max_time_minutes': '20', - 'truncate_percent': '25', -} - -""" - -config = { - 'command': '', - 'metric': '', - 'repeat_count': '', - 'max_time_minutes': '', - 'truncate_percent': '', -} - -# Workaround git try issue, see crbug.com/257689
diff --git a/tools/safely-roll-deps.py b/tools/safely-roll-deps.py index 73941238..15e3ab6 100755 --- a/tools/safely-roll-deps.py +++ b/tools/safely-roll-deps.py
@@ -4,7 +4,7 @@ # found in the LICENSE file. """Generate a CL to roll a DEPS entry to the specified revision number and post -it to Rietveld so that the CL will land automatically if it passes the +it for review so that the CL will land automatically if it passes the commit-queue's checks. """ @@ -122,7 +122,6 @@ if not options.dry_run: prnt_subprocess.check_call(['git', 'fetch', 'origin']) - prnt_subprocess.call(['git', 'svn', 'fetch']) branch_cmd = ['git', 'checkout', '-b', new_branch, options.upstream] if options.force: branch_cmd.append('-f')
diff --git a/tools/tests/OWNERS b/tools/tests/OWNERS index 704ad91..35d7f81 100644 --- a/tools/tests/OWNERS +++ b/tools/tests/OWNERS
@@ -1,3 +1 @@ -per-file licenses_test.py=phajdan.jr@chromium.org -per-file licenses_test.py=sgurun@chromium.org -per-file licenses_test.py=torne@chromium.org +per-file licenses_test.py=ichikawa@chromium.org
diff --git a/tools/traffic_annotation/.gitignore b/tools/traffic_annotation/.gitignore new file mode 100644 index 0000000..cced2bf72 --- /dev/null +++ b/tools/traffic_annotation/.gitignore
@@ -0,0 +1,4 @@ +bin/linux64/traffic_annotation_auditor +bin/linux64/traffic_annotation_extractor +bin/win32/traffic_annotation_auditor.exe +bin/win32/traffic_annotation_extractor.exe
diff --git a/tools/traffic_annotation/OWNERS b/tools/traffic_annotation/OWNERS index 3e10541..01d4a759 100644 --- a/tools/traffic_annotation/OWNERS +++ b/tools/traffic_annotation/OWNERS
@@ -1,2 +1,3 @@ battre@chromium.org -msramek@chromium.org \ No newline at end of file +msramek@chromium.org +rhalavati@chromium.org
diff --git a/tools/traffic_annotation/README.md b/tools/traffic_annotation/README.md new file mode 100644 index 0000000..3e6e851 --- /dev/null +++ b/tools/traffic_annotation/README.md
@@ -0,0 +1,102 @@ +# Running the traffic annotation checkers + +The traffic annotation checkers ensure that every operation in the +code base that talks to the network is properly annotated in the +source code, so that we can produce reports of what Chromium talks to +over the network and why. +Please see `docs/network_traffic_annotations.md` for an introduction to network +traffic annotations. + +To run the checkers, you need a populated build directory, and then +you do: + +``` +$ python tools/annotation_checker/presubmit_checks.py --build-path out/Default +``` + +## Building the annotation checker. + +The annotation checkers are built as Clang tools. We do not want every +developer to have to build clang, and so we store pre-built binaries +in a Google Cloud Storage bucket and retrieve them via gclient hooks. + +To roll new versions of the binaries, assuming you have write access +to the chromium-tools-traffic_annotation bucket, run: + +# On Linux: +```bash +git new-branch roll_traffic_annotation_tools +python tools/clang/scripts/update.py --bootstrap --force-local-build \ + --without-android --extra-tools traffic_annotation_extractor +cp third_party/llvm-build/Release+Asserts/bin/traffic_annotation_extractor \ + tools/traffic_annotation/bin/linux64/ + +# These GN flags produce an optimized, stripped binary that has no dependency +# on glib. +gn gen --args='is_official_build=true use_ozone=true' out/Default + +ninja -C out/Default traffic_annotation_auditor +cp -p out/Default/traffic_annotation_auditor \ + tools/traffic_annotation/bin/linux64 + +strip tools/traffic_annotation/bin/linux64/traffic_annotation_{auditor,extractor} + +third_party/depot_tools/upload_to_google_storage.py \ + -b chromium-tools-traffic_annotation \ + tools/traffic_annotation/bin/linux64/traffic_annotation_{auditor,extractor} +sed -i '/^CLANG_REVISION =/d' tools/traffic_annotation/README.md +sed -i '/^LASTCHANGE=/d' tools/traffic_annotation/README.md +grep '^CLANG_REVISION =' tools/clang/scripts/update.py >> tools/traffic_annotation/README.md +cat build/util/LASTCHANGE >> tools/traffic_annotation/README.md +git commit -a -m 'Roll traffic_annotation checkers' +git cl upload + +``` + +# On Windows: +```bash +git new-branch roll_traffic_annotation_tools +python tools/clang/scripts/update.py --bootstrap --force-local-build ^ + --without-android --extra-tools traffic_annotation_extractor +cp third_party/llvm-build/Release+Asserts/bin/traffic_annotation_extractor.exe ^ + tools/traffic_annotation/bin/win32/ + +# These GN flags produce an optimized, stripped binary that has no dependency +# on glib. +gn gen --args="is_official_build=true" out/Default + +ninja -C out/Default traffic_annotation_auditor +cp -p out/Default/traffic_annotation_auditor.exe ^ + tools/traffic_annotation/bin/win32 + +python third_party/depot_tools/upload_to_google_storage.py ^ + -b chromium-tools-traffic_annotation ^ + tools/traffic_annotation/bin/win32/traffic_annotation_auditor.exe +python third_party/depot_tools/upload_to_google_storage.py ^ + -b chromium-tools-traffic_annotation ^ + tools/traffic_annotation/bin/win32/traffic_annotation_extractor.exe +sed -i "/^CLANG_REVISION =/d" tools/traffic_annotation/README.md +sed -i "/^LASTCHANGE=/d" tools/traffic_annotation/README.md +grep "^CLANG_REVISION =" tools/clang/scripts/update.py >> ^ + tools/traffic_annotation/README.md +cat build/util/LASTCHANGE >> tools/traffic_annotation/README.md +dos2unix tools/traffic_annotation/README.md +git commit -a -m 'Roll traffic_annotation checkers' +git cl upload + +``` + +and land the resulting CL. + +The following two lines will be updated by the above script, and the modified +README should be committed along with the updated .sha1 checksums. + +In the event that clang changes something that requires this tool to be +rebuilt (or for some other reason the tests don't work correctly), please +disable this test by setting the `TEST_IS_ENABLED` flag to False in +//tools/traffic_annotation/scripts_check_annotation.py, and file a bug +and cc the people listed in OWNERS; they'll be on the hook to rebuild and +re-enable the test. + +CLANG_REVISION = '324578' +LASTCHANGE=cd6e9ca2e9c5cda30fac77c70d35d2eb699e5f88-refs/heads/master@{#536659}
diff --git a/tools/traffic_annotation/auditor/BUILD.gn b/tools/traffic_annotation/auditor/BUILD.gn index e9e563a2..f4b33ba 100644 --- a/tools/traffic_annotation/auditor/BUILD.gn +++ b/tools/traffic_annotation/auditor/BUILD.gn
@@ -56,9 +56,11 @@ "traffic_annotation_exporter.h", "traffic_annotation_file_filter.cc", "traffic_annotation_file_filter.h", + "traffic_annotation_id_checker.cc", + "traffic_annotation_id_checker.h", ] data = [ - "white_list.txt", + "safe_list.txt", ] public_deps = [ @@ -84,6 +86,14 @@ "traffic_annotation_auditor_unittest.cc", ] data = [ + "tests/annotations_diff12.txt", + "tests/annotations_diff13.txt", + "tests/annotations_diff23.txt", + "tests/annotations_sample1.xml", + "tests/annotations_sample2.xml", + "tests/annotations_sample3.xml", + "tests/extractor_outputs/bad_assignment1.txt", + "tests/extractor_outputs/bad_assignment2.txt", "tests/extractor_outputs/bad_call.txt", "tests/extractor_outputs/bad_syntax_annotation1.txt", "tests/extractor_outputs/bad_syntax_annotation2.txt", @@ -92,6 +102,7 @@ "tests/extractor_outputs/fatal_annotation1.txt", "tests/extractor_outputs/fatal_annotation2.txt", "tests/extractor_outputs/fatal_annotation3.txt", + "tests/extractor_outputs/good_assignment.txt", "tests/extractor_outputs/good_branched_completing_annotation.txt", "tests/extractor_outputs/good_call.txt", "tests/extractor_outputs/good_complete_annotation.txt",
diff --git a/tools/traffic_annotation/auditor/README.md b/tools/traffic_annotation/auditor/README.md index a6a8326..2110005 100644 --- a/tools/traffic_annotation/auditor/README.md +++ b/tools/traffic_annotation/auditor/README.md
@@ -1,6 +1,8 @@ # Network Traffic Annotation Auditor This executable runs the clang tool for extraction of Network Traffic Annotations from chromium source code and collects and summarizes its outputs. +Please see `docs/network_traffic_annotations.md` for an introduction to network +traffic annotations. ## Usage `traffic_annotation_auditor [OPTION]... [path_filter]...` @@ -10,15 +12,11 @@ Run `traffic_annotation_auditor --help` for options. Example: - `traffic_annotation_auditor --build-dir=out/Debug --summary-file= - report.txt` + `traffic_annotation_auditor --build-dir=out/Debug` -## Running on Linux -Before running the script as above, you should build the COMPLETE chromium. +The binaries of this file and the clang tool are checked out into +`tools/traffic_annotation/bin/[platform]`. This is only done for Linux platform +now and will be extended to other platforms later. -## Running on Windows -Before running the script as above, you should build the COMPLETE chromium with -clang with keeprsp switch as follows: -1. `gn args [build_dir, e.g. out\Debug]` -2. add `is_clang=true` to the opened text file and save and close it. -3. `ninja -C [build_dir] -d keeprsp` +## Running +Before running, you need to build the COMPLETE chromium.
diff --git a/tools/traffic_annotation/auditor/auditor_result.cc b/tools/traffic_annotation/auditor/auditor_result.cc index 99f8805..85bbded9 100644 --- a/tools/traffic_annotation/auditor/auditor_result.cc +++ b/tools/traffic_annotation/auditor/auditor_result.cc
@@ -19,14 +19,15 @@ type == AuditorResult::Type::RESULT_OK || type == AuditorResult::Type::RESULT_IGNORE || type == AuditorResult::Type::ERROR_FATAL || - type == AuditorResult::Type::ERROR_DUPLICATE_UNIQUE_ID_HASH_CODE || - type == AuditorResult::Type::ERROR_MERGE_FAILED); + type == AuditorResult::Type::ERROR_HASH_CODE_COLLISION || + type == AuditorResult::Type::ERROR_REPEATED_ID || + type == AuditorResult::Type::ERROR_MERGE_FAILED || + type == AuditorResult::Type::ERROR_ANNOTATIONS_XML_UPDATE); DCHECK(!message.empty() || type == AuditorResult::Type::RESULT_OK || type == AuditorResult::Type::RESULT_IGNORE || type == AuditorResult::Type::ERROR_MISSING_TAG_USED || type == AuditorResult::Type::ERROR_NO_ANNOTATION || - type == AuditorResult::Type::ERROR_MISSING_EXTRA_ID || - type == AuditorResult::Type::ERROR_INCOMPLETED_ANNOTATION || + type == AuditorResult::Type::ERROR_MISSING_SECOND_ID || type == AuditorResult::Type::ERROR_DIRECT_ASSIGNMENT); if (!message.empty()) details_.push_back(message); @@ -44,13 +45,10 @@ std::string(), kNoCodeLineSpecified) {} -AuditorResult::AuditorResult(const AuditorResult& other) - : type_(other.type_), - details_(other.details_), - file_path_(other.file_path_), - line_(other.line_){}; +AuditorResult::AuditorResult(const AuditorResult& other) = default; +; -AuditorResult::~AuditorResult() {} +AuditorResult::~AuditorResult() = default; void AuditorResult::AddDetail(const std::string& message) { details_.push_back(message); @@ -59,7 +57,7 @@ std::string AuditorResult::ToText() const { switch (type_) { case AuditorResult::Type::ERROR_FATAL: - DCHECK(details_.size()); + DCHECK(!details_.empty()); return details_[0]; case AuditorResult::Type::ERROR_MISSING_TAG_USED: @@ -72,59 +70,66 @@ file_path_.c_str(), line_); case AuditorResult::Type::ERROR_SYNTAX: { - DCHECK(details_.size()); + DCHECK(!details_.empty()); std::string flat_message(details_[0]); std::replace(flat_message.begin(), flat_message.end(), '\n', ' '); return base::StringPrintf("Syntax error in '%s': %s", file_path_.c_str(), flat_message.c_str()); } - case AuditorResult::Type::ERROR_RESERVED_UNIQUE_ID_HASH_CODE: - DCHECK(details_.size()); + case AuditorResult::Type::ERROR_RESERVED_ID_HASH_CODE: + DCHECK(!details_.empty()); return base::StringPrintf( - "Unique id '%s' in '%s:%i' has a hash code similar to a reserved " - "word and should be changed.", + "Id '%s' in '%s:%i' has a hash code equal to a reserved word and " + "should be changed.", details_[0].c_str(), file_path_.c_str(), line_); - case AuditorResult::Type::ERROR_DEPRECATED_UNIQUE_ID_HASH_CODE: - DCHECK(details_.size()); + case AuditorResult::Type::ERROR_DEPRECATED_ID_HASH_CODE: + DCHECK(!details_.empty()); return base::StringPrintf( - "Unique id '%s' in '%s:%i' has a hash code similar to a deprecated " - "unique id and should be changed.", + "Id '%s' in '%s:%i' has a hash code equal to a deprecated id and " + "should be changed.", details_[0].c_str(), file_path_.c_str(), line_); - case AuditorResult::Type::ERROR_DUPLICATE_UNIQUE_ID_HASH_CODE: + case AuditorResult::Type::ERROR_HASH_CODE_COLLISION: DCHECK_EQ(details_.size(), 2u); return base::StringPrintf( - "The following annotations have similar unique id " - "hash codes and should be updated: %s, %s.", + "The following annotations have colliding hash codes and should be " + "updated: %s, %s.", details_[0].c_str(), details_[1].c_str()); - case AuditorResult::Type::ERROR_UNIQUE_ID_INVALID_CHARACTER: - DCHECK(details_.size()); + case AuditorResult::Type::ERROR_REPEATED_ID: + DCHECK_EQ(details_.size(), 2u); return base::StringPrintf( - "Unique id '%s' in '%s:%i' contains an invalid character.", + "The following annotations have equal ids and should be updated: " + "%s, %s.", + details_[0].c_str(), details_[1].c_str()); + + case AuditorResult::Type::ERROR_ID_INVALID_CHARACTER: + DCHECK(!details_.empty()); + return base::StringPrintf( + "Id '%s' in '%s:%i' contains an invalid character.", details_[0].c_str(), file_path_.c_str(), line_); case AuditorResult::Type::ERROR_MISSING_ANNOTATION: - DCHECK(details_.size()); + DCHECK(!details_.empty()); return base::StringPrintf("Function '%s' in '%s:%i' requires annotation.", details_[0].c_str(), file_path_.c_str(), line_); case AuditorResult::Type::ERROR_INCOMPLETE_ANNOTATION: - DCHECK(details_.size()); + DCHECK(!details_.empty()); return base::StringPrintf( "Annotation at '%s:%i' has the following missing fields: %s", file_path_.c_str(), line_, details_[0].c_str()); - case AuditorResult::Type::ERROR_MISSING_EXTRA_ID: + case AuditorResult::Type::ERROR_MISSING_SECOND_ID: return base::StringPrintf( "Second id of annotation at '%s:%i' should be updated as it has the " "same hash code as the first one.", file_path_.c_str(), line_); case AuditorResult::Type::ERROR_INCONSISTENT_ANNOTATION: - DCHECK(details_.size()); + DCHECK(!details_.empty()); return base::StringPrintf( "Annotation at '%s:%i' has the following inconsistencies: %s", file_path_.c_str(), line_, details_[0].c_str()); @@ -137,8 +142,9 @@ details_[1].c_str(), details_[2].c_str(), details_[0].c_str()); case AuditorResult::Type::ERROR_INCOMPLETED_ANNOTATION: - return base::StringPrintf("Annotation at '%s:%i' is never completed.", - file_path_.c_str(), line_); + DCHECK(!details_.empty()); + return base::StringPrintf("Annotation '%s' is never completed.", + details_[0].c_str()); case AuditorResult::Type::ERROR_DIRECT_ASSIGNMENT: return base::StringPrintf( @@ -146,6 +152,17 @@ "functions.", file_path_.c_str(), line_); + case AuditorResult::Type::ERROR_ANNOTATIONS_XML_UPDATE: + DCHECK(!details_.empty()); + return base::StringPrintf( + "'tools/traffic_annotation/summary/annotations.xml' requires update. " + "It is recommended to run traffic_annotation_auditor locally to do " + "the updates automatically (please refer to tools/traffic_annotation/" + "auditor/README.md), but you can also apply the following edit(s) to " + "do it manually:%s\n\n If you are using build flags that modify " + "files (like jumbo), rerun the auditor using --all-files switch.", + details_[0].c_str()); + default: return std::string(); } @@ -154,12 +171,12 @@ std::string AuditorResult::ToShortText() const { switch (type_) { case AuditorResult::Type::ERROR_INCOMPLETE_ANNOTATION: - DCHECK(details_.size()); + DCHECK(!details_.empty()); return base::StringPrintf("the following fields are missing: %s", details_[0].c_str()); case AuditorResult::Type::ERROR_INCONSISTENT_ANNOTATION: - DCHECK(details_.size()); + DCHECK(!details_.empty()); return base::StringPrintf("the following inconsistencies: %s", details_[0].c_str());
diff --git a/tools/traffic_annotation/auditor/auditor_result.h b/tools/traffic_annotation/auditor/auditor_result.h index fd95977..996921c 100644 --- a/tools/traffic_annotation/auditor/auditor_result.h +++ b/tools/traffic_annotation/auditor/auditor_result.h
@@ -18,18 +18,21 @@ // MISSING_TRAFFIC_ANNOTATION tag. ERROR_NO_ANNOTATION, // A function is called with NO_ANNOTATION tag. ERROR_SYNTAX, // Annotation syntax is not right. - ERROR_RESERVED_UNIQUE_ID_HASH_CODE, // A unique id has a hash code similar - // to a reserved word. - ERROR_DEPRECATED_UNIQUE_ID_HASH_CODE, // A unique id has a hash code - // equal to a deprecated one. - ERROR_DUPLICATE_UNIQUE_ID_HASH_CODE, // Two unique ids have equal hash - // codes. - ERROR_UNIQUE_ID_INVALID_CHARACTER, // A unique id contanins a characer - // which is not alphanumeric or - // underline. + ERROR_RESERVED_ID_HASH_CODE, // An id has a hash code equal to a reserved + // word. + ERROR_DEPRECATED_ID_HASH_CODE, // An id has a hash code equal to a + // deprecated one. + ERROR_HASH_CODE_COLLISION, // Two ids have equal hash codes. + ERROR_REPEATED_ID, // An id is used in two places without proper + // matching conditions. Proper conditions + // include cases that two annotations are + // completing each other or are different + // branches of one completing annotation. + ERROR_ID_INVALID_CHARACTER, // An id contanins a characer which is not + // alphanumeric or underline. ERROR_MISSING_ANNOTATION, // A function that requires annotation is not // annotated. - ERROR_MISSING_EXTRA_ID, // Annotation does not have a valid extra id. + ERROR_MISSING_SECOND_ID, // Annotation does not have a valid second id. ERROR_INCOMPLETE_ANNOTATION, // Annotation has some missing fields. ERROR_INCONSISTENT_ANNOTATION, // Annotation has some inconsistent fields. ERROR_MERGE_FAILED, // Two annotations that are supposed to merge @@ -37,9 +40,10 @@ ERROR_INCOMPLETED_ANNOTATION, // A partial or [branched_] completing // annotation is not paired with any other // annotation to be completed. - ERROR_DIRECT_ASSIGNMENT // A value is directly assigned to a mutable + ERROR_DIRECT_ASSIGNMENT, // A value is directly assigned to a mutable // annotation or annotation instialized with // list expresssion. + ERROR_ANNOTATIONS_XML_UPDATE // Annotations XML requires update. }; static const int kNoCodeLineSpecified;
diff --git a/tools/traffic_annotation/auditor/instance.cc b/tools/traffic_annotation/auditor/instance.cc index de06a26..a930834 100644 --- a/tools/traffic_annotation/auditor/instance.cc +++ b/tools/traffic_annotation/auditor/instance.cc
@@ -4,6 +4,7 @@ #include "tools/traffic_annotation/auditor/instance.h" +#include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "net/traffic_annotation/network_traffic_annotation.h" @@ -22,7 +23,7 @@ : google::protobuf::io::ErrorCollector(), line_offset_(proto_starting_line) {} - ~SimpleErrorCollector() override {} + ~SimpleErrorCollector() override = default; void AddError(int line, google::protobuf::io::ColumnNumber column, @@ -63,16 +64,67 @@ } \ } +std::map<int, std::string> kSemanticsFields = { + {traffic_annotation::NetworkTrafficAnnotation_TrafficSemantics:: + kSenderFieldNumber, + "semantics::sender"}, + {traffic_annotation::NetworkTrafficAnnotation_TrafficSemantics:: + kDescriptionFieldNumber, + "semantics::description"}, + {traffic_annotation::NetworkTrafficAnnotation_TrafficSemantics:: + kTriggerFieldNumber, + "semantics::trigger"}, + {traffic_annotation::NetworkTrafficAnnotation_TrafficSemantics:: + kDataFieldNumber, + "semantics::data"}, + {traffic_annotation::NetworkTrafficAnnotation_TrafficSemantics:: + kDestinationFieldNumber, + "semantics::destination"}, +}; + +std::map<int, std::string> kPolicyFields = { + {traffic_annotation::NetworkTrafficAnnotation_TrafficPolicy:: + kCookiesAllowedFieldNumber, + "policy::cookies_allowed"}, + {traffic_annotation::NetworkTrafficAnnotation_TrafficPolicy:: + kCookiesStoreFieldNumber, + "policy::cookies_store"}, + {traffic_annotation::NetworkTrafficAnnotation_TrafficPolicy:: + kSettingFieldNumber, + "policy::setting"}, + {traffic_annotation::NetworkTrafficAnnotation_TrafficPolicy:: + kChromePolicyFieldNumber, + "policy::chrome_policy"}, + {traffic_annotation::NetworkTrafficAnnotation_TrafficPolicy:: + kPolicyExceptionJustificationFieldNumber, + "policy::policy_exception_justification"}, +}; + +std::vector<int> kChromePolicyFields = { + traffic_annotation::NetworkTrafficAnnotation_TrafficPolicy:: + kChromePolicyFieldNumber, + traffic_annotation::NetworkTrafficAnnotation_TrafficPolicy:: + kPolicyExceptionJustificationFieldNumber}; + } // namespace -AnnotationInstance::AnnotationInstance() : type(Type::ANNOTATION_COMPLETE) {} +AnnotationInstance::AnnotationInstance() + : type(Type::ANNOTATION_COMPLETE), + unique_id_hash_code(0), + second_id_hash_code(0), + archive_content_hash_code(0), + is_loaded_from_archive(false), + is_merged(false) {} AnnotationInstance::AnnotationInstance(const AnnotationInstance& other) : proto(other.proto), type(other.type), - extra_id(other.extra_id), + second_id(other.second_id), unique_id_hash_code(other.unique_id_hash_code), - extra_id_hash_code(other.extra_id_hash_code){}; + second_id_hash_code(other.second_id_hash_code), + archive_content_hash_code(other.archive_content_hash_code), + is_loaded_from_archive(other.is_loaded_from_archive), + is_merged(other.is_merged){}; AuditorResult AnnotationInstance::Deserialize( const std::vector<std::string>& serialized_lines, @@ -90,7 +142,7 @@ base::StringToInt(serialized_lines[start_line++], &line_number); std::string function_type = serialized_lines[start_line++]; const std::string& unique_id = serialized_lines[start_line++]; - extra_id = serialized_lines[start_line++]; + second_id = serialized_lines[start_line++]; // Decode function type. if (function_type == "Definition") { @@ -128,6 +180,13 @@ return AuditorResult(AuditorResult::Type::ERROR_MISSING_TAG_USED, "", file_path, line_number); + // TODO(crbug.com/656607): Remove this test. + // Process temporary tag. + if (unique_id_hash_code == + NO_TRAFFIC_ANNOTATION_BUG_656607.unique_id_hash_code) { + return AuditorResult(AuditorResult::Type::RESULT_IGNORE); + } + // Decode serialized proto. std::string annotation_text = ""; while (start_line < end_line) { @@ -151,53 +210,115 @@ src->set_function(function_context); src->set_line(line_number); proto.set_unique_id(unique_id); - extra_id_hash_code = TrafficAnnotationAuditor::ComputeHashValue(extra_id); + second_id_hash_code = TrafficAnnotationAuditor::ComputeHashValue(second_id); return AuditorResult(AuditorResult::Type::RESULT_OK); } +// Returns the proto field numbers of TrafficSemantics. +void AnnotationInstance::GetSemanticsFieldNumbers( + std::set<int>* field_numbers) const { + field_numbers->clear(); + + const traffic_annotation::NetworkTrafficAnnotation_TrafficSemantics + semantics = proto.semantics(); + + if (!semantics.sender().empty()) + field_numbers->insert(semantics.kSenderFieldNumber); + + if (!semantics.description().empty()) + field_numbers->insert(semantics.kDescriptionFieldNumber); + + if (!semantics.trigger().empty()) + field_numbers->insert(semantics.kTriggerFieldNumber); + + if (!semantics.data().empty()) + field_numbers->insert(semantics.kDataFieldNumber); + + if (semantics.destination() != + traffic_annotation:: + NetworkTrafficAnnotation_TrafficSemantics_Destination_UNSPECIFIED) { + field_numbers->insert(semantics.kDestinationFieldNumber); + } +} + +// Returns the proto field numbers of TrafficPolicy. +void AnnotationInstance::GetPolicyFieldNumbers( + std::set<int>* field_numbers) const { + field_numbers->clear(); + + const traffic_annotation::NetworkTrafficAnnotation_TrafficPolicy policy = + proto.policy(); + + // If cookies are not allowed, the negated value of the + // kCookiesAllowedFieldNumber is returned. As field numbers are positive, this + // will not collide with any other value. + if (policy.cookies_allowed() == + traffic_annotation:: + NetworkTrafficAnnotation_TrafficPolicy_CookiesAllowed_YES) { + field_numbers->insert(policy.kCookiesAllowedFieldNumber); + } else if (policy.cookies_allowed() == + traffic_annotation:: + NetworkTrafficAnnotation_TrafficPolicy_CookiesAllowed_NO) { + field_numbers->insert(-policy.kCookiesAllowedFieldNumber); + } + + if (!policy.cookies_store().empty()) + field_numbers->insert(policy.kCookiesStoreFieldNumber); + + if (!policy.setting().empty()) + field_numbers->insert(policy.kSettingFieldNumber); + + if (policy.chrome_policy_size()) + field_numbers->insert(policy.kChromePolicyFieldNumber); + + if (!policy.policy_exception_justification().empty()) + field_numbers->insert(policy.kPolicyExceptionJustificationFieldNumber); +} + // Checks if an annotation has all required fields. AuditorResult AnnotationInstance::IsComplete() const { std::vector<std::string> unspecifieds; std::string extra_texts; - const traffic_annotation::NetworkTrafficAnnotation_TrafficSemantics - semantics = proto.semantics(); - if (semantics.sender().empty()) - unspecifieds.push_back("semantics::sender"); - if (semantics.description().empty()) - unspecifieds.push_back("semantics::description"); - if (semantics.trigger().empty()) - unspecifieds.push_back("semantics::trigger"); - if (semantics.data().empty()) - unspecifieds.push_back("semantics::data"); - if (semantics.destination() == - traffic_annotation:: - NetworkTrafficAnnotation_TrafficSemantics_Destination_UNSPECIFIED) - unspecifieds.push_back("semantics::destination"); - - const traffic_annotation::NetworkTrafficAnnotation_TrafficPolicy policy = - proto.policy(); - if (policy.cookies_allowed() == - traffic_annotation:: - NetworkTrafficAnnotation_TrafficPolicy_CookiesAllowed_UNSPECIFIED) { - unspecifieds.push_back("policy::cookies_allowed"); - } else if ( - policy.cookies_allowed() == - traffic_annotation:: - NetworkTrafficAnnotation_TrafficPolicy_CookiesAllowed_YES && - policy.cookies_store().empty()) { - unspecifieds.push_back("policy::cookies_store"); + std::set<int> fields; + GetSemanticsFieldNumbers(&fields); + for (const auto& item : kSemanticsFields) { + if (!base::ContainsKey(fields, item.first)) + unspecifieds.push_back(item.second); } - if (policy.setting().empty()) - unspecifieds.push_back("policy::setting"); + GetPolicyFieldNumbers(&fields); + for (const auto& item : kPolicyFields) { + if (!base::ContainsKey(fields, item.first)) { + // If 'cookies_allowed = NO' is provided, ignore not having + // 'cookies_allowed = YES'. + if (item.first == + traffic_annotation::NetworkTrafficAnnotation_TrafficPolicy:: + kCookiesAllowedFieldNumber && + base::ContainsKey(fields, -item.first)) + continue; - if (!policy.chrome_policy_size() && - policy.policy_exception_justification().empty()) { - unspecifieds.push_back( - "neither policy::chrome_policy nor " - "policy::policy_exception_justification"); + // If |cookies_store| is not provided, ignore if 'cookies_allowed = NO' is + // in the list. + if (item.first == + traffic_annotation::NetworkTrafficAnnotation_TrafficPolicy:: + kCookiesStoreFieldNumber && + base::ContainsKey( + fields, + -traffic_annotation::NetworkTrafficAnnotation_TrafficPolicy:: + kCookiesAllowedFieldNumber)) + continue; + + // If either of |chrome_policy| or |policy_exception_justification| are + // avaliable, ignore not having the other one. + if (base::ContainsValue(kChromePolicyFields, item.first) && + (base::ContainsKey(fields, kChromePolicyFields[0]) || + base::ContainsKey(fields, kChromePolicyFields[1]))) { + continue; + } + unspecifieds.push_back(item.second); + } } if (!unspecifieds.size()) @@ -240,13 +361,13 @@ bool AnnotationInstance::IsCompletableWith( const AnnotationInstance& other) const { - if (type != AnnotationInstance::Type::ANNOTATION_PARTIAL || extra_id.empty()) + if (type != AnnotationInstance::Type::ANNOTATION_PARTIAL || second_id.empty()) return false; if (other.type == AnnotationInstance::Type::ANNOTATION_COMPLETING) { - return extra_id_hash_code == other.unique_id_hash_code; + return second_id_hash_code == other.unique_id_hash_code; } else if (other.type == AnnotationInstance::Type::ANNOTATION_BRANCHED_COMPLETING) { - return extra_id_hash_code == other.extra_id_hash_code; + return second_id_hash_code == other.second_id_hash_code; } else { return false; } @@ -271,16 +392,28 @@ other = this; } + combination->is_merged = true; combination->type = AnnotationInstance::Type::ANNOTATION_COMPLETE; - combination->extra_id.clear(); - combination->extra_id_hash_code = 0; - combination->comments = base::StringPrintf( + combination->second_id.clear(); + combination->second_id_hash_code = 0; + + // Update comment. + std::string new_comments = combination->proto.comments(); + if (!other->proto.comments().empty()) { + if (!new_comments.empty()) + new_comments += "\n"; + new_comments += other->proto.comments(); + } + if (!new_comments.empty()) + new_comments += "\n"; + new_comments += base::StringPrintf( "This annotation is a merge of the following two annotations:\n" "'%s' in '%s:%i' and '%s' in '%s:%i'.", proto.unique_id().c_str(), proto.source().file().c_str(), proto.source().line(), completing_annotation.proto.unique_id().c_str(), completing_annotation.proto.source().file().c_str(), completing_annotation.proto.source().line()); + combination->proto.set_comments(new_comments); // Copy TrafficSemantics. const traffic_annotation::NetworkTrafficAnnotation_TrafficSemantics @@ -288,7 +421,6 @@ traffic_annotation::NetworkTrafficAnnotation_TrafficSemantics* dst_semantics = combination->proto.mutable_semantics(); - MERGE_STRING_FIELDS(src_semantics, dst_semantics, empty_policy_justification); MERGE_STRING_FIELDS(src_semantics, dst_semantics, sender); MERGE_STRING_FIELDS(src_semantics, dst_semantics, description); MERGE_STRING_FIELDS(src_semantics, dst_semantics, trigger); @@ -352,6 +484,173 @@ return AuditorResult::Type::RESULT_OK; } +int AnnotationInstance::GetContentHashCode() const { + if (is_loaded_from_archive) + return archive_content_hash_code; + + traffic_annotation::NetworkTrafficAnnotation source_free_proto = proto; + source_free_proto.clear_source(); + std::string content; + google::protobuf::TextFormat::PrintToString(source_free_proto, &content); + return TrafficAnnotationAuditor::ComputeHashValue(content); +} + +// static +AnnotationInstance AnnotationInstance::LoadFromArchive( + AnnotationInstance::Type type, + const std::string& unique_id, + int unique_id_hash_code, + int second_id_hash_code, + int content_hash_code, + const std::set<int>& semantics_fields, + const std::set<int>& policy_fields, + const std::string& file_path) { + AnnotationInstance annotation; + + annotation.is_loaded_from_archive = true; + annotation.type = type; + annotation.proto.set_unique_id(unique_id); + annotation.proto.mutable_source()->set_file(file_path); + annotation.unique_id_hash_code = unique_id_hash_code; + + if (annotation.NeedsTwoIDs()) { + annotation.second_id_hash_code = second_id_hash_code; + // As we don't have the actual second id, a generated value is written to + // ensure that the field is not empty. Current set of auditor tests and + // unittests just check if this field is not empty when a second id is + // required. Tests that are based on matching the ids (like + // partial/completing annotations) are based on the hash codes. + annotation.second_id = + base::StringPrintf("ARCHIVED_ID_%i", annotation.second_id_hash_code); + } + + annotation.archive_content_hash_code = content_hash_code; + + // The values of the semantics and policy are set so that the tests would know + // which fields were available before archive. + if (base::ContainsKey( + semantics_fields, + traffic_annotation::NetworkTrafficAnnotation_TrafficSemantics:: + kSenderFieldNumber)) { + annotation.proto.mutable_semantics()->set_sender("[Archived]"); + } + + if (base::ContainsKey( + semantics_fields, + traffic_annotation::NetworkTrafficAnnotation_TrafficSemantics:: + kDescriptionFieldNumber)) { + annotation.proto.mutable_semantics()->set_description("[Archived]"); + } + + if (base::ContainsKey( + semantics_fields, + traffic_annotation::NetworkTrafficAnnotation_TrafficSemantics:: + kTriggerFieldNumber)) { + annotation.proto.mutable_semantics()->set_trigger("[Archived]"); + } + + if (base::ContainsKey( + semantics_fields, + traffic_annotation::NetworkTrafficAnnotation_TrafficSemantics:: + kDataFieldNumber)) { + annotation.proto.mutable_semantics()->set_data("[Archived]"); + } + + if (base::ContainsKey( + semantics_fields, + traffic_annotation::NetworkTrafficAnnotation_TrafficSemantics:: + kDestinationFieldNumber)) { + annotation.proto.mutable_semantics()->set_destination( + traffic_annotation:: + NetworkTrafficAnnotation_TrafficSemantics_Destination_WEBSITE); + } + + if (base::ContainsKey( + policy_fields, + traffic_annotation::NetworkTrafficAnnotation_TrafficPolicy:: + kCookiesAllowedFieldNumber)) { + annotation.proto.mutable_policy()->set_cookies_allowed( + traffic_annotation:: + NetworkTrafficAnnotation_TrafficPolicy_CookiesAllowed_YES); + } + + if (base::ContainsKey( + policy_fields, + -traffic_annotation::NetworkTrafficAnnotation_TrafficPolicy:: + kCookiesAllowedFieldNumber)) { + annotation.proto.mutable_policy()->set_cookies_allowed( + traffic_annotation:: + NetworkTrafficAnnotation_TrafficPolicy_CookiesAllowed_NO); + } + + if (base::ContainsKey( + policy_fields, + traffic_annotation::NetworkTrafficAnnotation_TrafficPolicy:: + kCookiesStoreFieldNumber)) { + annotation.proto.mutable_policy()->set_cookies_store("[Archived]"); + } + + if (base::ContainsKey( + policy_fields, + traffic_annotation::NetworkTrafficAnnotation_TrafficPolicy:: + kSettingFieldNumber)) { + annotation.proto.mutable_policy()->set_setting("[Archived]"); + } + + if (base::ContainsKey( + policy_fields, + traffic_annotation::NetworkTrafficAnnotation_TrafficPolicy:: + kChromePolicyFieldNumber)) { + annotation.proto.mutable_policy()->add_chrome_policy(); + } + + if (base::ContainsKey( + policy_fields, + traffic_annotation::NetworkTrafficAnnotation_TrafficPolicy:: + kPolicyExceptionJustificationFieldNumber)) { + annotation.proto.mutable_policy()->set_policy_exception_justification( + "[Archived]"); + } + + return annotation; +} + +std::string AnnotationInstance::Serialize() const { + std::string text; + std::set<int> fields; + + text = base::StringPrintf( + "{\tType: %i\n" + "\tID: %s\n" + "\tHashcode 1: %i\n" + "\tHashcode 2: %i\n" + "\tFrom Archive: %i\n" + "\tSource File: %s\n", + static_cast<int>(type), proto.unique_id().c_str(), unique_id_hash_code, + second_id_hash_code, is_loaded_from_archive, + proto.source().file().c_str()); + + GetSemanticsFieldNumbers(&fields); + text += "\tSemantics: "; + for (int i : fields) + text += base::StringPrintf("%s,", kSemanticsFields[i].c_str()); + + GetPolicyFieldNumbers(&fields); + text += "\n\tPolicies: "; + for (int i : fields) { + text += base::StringPrintf("%s%s,", i < 0 ? "-" : "", + kPolicyFields[abs(i)].c_str()); + } + text += "\n}"; + + return text; +} + +std::ostream& operator<<(std::ostream& out, + const AnnotationInstance& instance) { + return out << instance.Serialize(); +} + CallInstance::CallInstance() : line_number(0), is_annotated(false) {} CallInstance::CallInstance(const CallInstance& other)
diff --git a/tools/traffic_annotation/auditor/instance.h b/tools/traffic_annotation/auditor/instance.h index 8a04494..420672c 100644 --- a/tools/traffic_annotation/auditor/instance.h +++ b/tools/traffic_annotation/auditor/instance.h
@@ -51,6 +51,28 @@ int start_line, int end_line) override; + // Returns the proto field numbers of TrafficSemantics fields that are + // included in this annotation. + void GetSemanticsFieldNumbers(std::set<int>* field_numbers) const; + + // Returns the proto field numbers of TrafficPolicy fields that are included + // in this annotation. + // For the cookies_allowed field, if the value is YES, + // kCookiesAllowedFieldNumber is added to the set and if it is NO, + // -kCookiesAllowedFieldNumber is added. + void GetPolicyFieldNumbers(std::set<int>* field_numbers) const; + + // Loads annotation based on the data from archive in annotations.xml. + static AnnotationInstance LoadFromArchive( + AnnotationInstance::Type type, + const std::string& unique_id, + int unique_id_hash_code, + int second_id_hash_code, + int content_hash_code, + const std::set<int>& semantics_fields, + const std::set<int>& policy_fields, + const std::string& file_path); + // Checks if an annotation has all required fields. AuditorResult IsComplete() const; @@ -63,28 +85,55 @@ // type. bool IsCompletableWith(const AnnotationInstance& other) const; + // Tells if annotation requires two ids. All annotations have the unique id, + // but partial annotations also require the completing id, and branched + // completing annotations require the group id. + bool NeedsTwoIDs() const { + return type == Type::ANNOTATION_PARTIAL || + type == Type::ANNOTATION_BRANCHED_COMPLETING; + } + + // If annotation is loaded from archive, returns |archive_content_hash_code|. + // Otherwise computes a hashcode for the annotation content. Source field is + // not used in this computation as we don't need sensitivity to changes in + // source location, i.e. filepath, line number and function. + int GetContentHashCode() const; + // Combines |*this| partial annotation with a completing/branched_completing // annotation and returns the combined complete annotation. AuditorResult CreateCompleteAnnotation( AnnotationInstance& completing_annotation, AnnotationInstance* combination) const; + // Serializes to text for debugging and visualization. + std::string Serialize() const; + // Protobuf of the annotation. traffic_annotation::NetworkTrafficAnnotation proto; // Type of the annotation. Type type; - // Extra id of the annotation (if available). - std::string extra_id; + // Extra id of the annotation (if available). This can be the completing id + // for partial annotations, or group id for branched completing annotations. + std::string second_id; // Hash codes of unique id and extra id (if available). int unique_id_hash_code; - int extra_id_hash_code; + int second_id_hash_code; - std::string comments; + // The hash code of annotation content for archived annotations. + int archive_content_hash_code; + + // Flag stating if annotation is loaded from annotations.xml. + bool is_loaded_from_archive; + + // This annotation is generated from merging two other incomplete annotations. + bool is_merged; }; +std::ostream& operator<<(std::ostream& out, const AnnotationInstance& instance); + // Holds an instance of calling a function that might have a network traffic // annotation argument. class CallInstance : public InstanceBase {
diff --git a/tools/traffic_annotation/auditor/safe_list.txt b/tools/traffic_annotation/auditor/safe_list.txt index 65aa3356..93bf3ff 100644 --- a/tools/traffic_annotation/auditor/safe_list.txt +++ b/tools/traffic_annotation/auditor/safe_list.txt
@@ -5,4 +5,4 @@ all,tools missing,net/url_request/url_fetcher.cc missing,net/url_request/url_request_context.cc -direct_assignment,download::ProtoConversions::EntryFromProto@components/download/internal/proto_conversions.cc \ No newline at end of file +direct_assignment,download::ProtoConversions::EntryFromProto@components/download/internal/background_service/proto_conversions.cc \ No newline at end of file
diff --git a/tools/traffic_annotation/auditor/tests/annotations_diff12.txt b/tools/traffic_annotation/auditor/tests/annotations_diff12.txt new file mode 100644 index 0000000..2239195 --- /dev/null +++ b/tools/traffic_annotation/auditor/tests/annotations_diff12.txt
@@ -0,0 +1,5 @@ + + Add line: ' <item id="A" hash_code="1" content_hash_code="10" os_list="linux,windows"/>' + Add line: ' <item id="E" hash_code="5" content_hash_code="50" os_list="linux,windows"/>' + Add line: ' <item id="Z" hash_code="9" content_hash_code="90" os_list="linux,windows"/>' + Update line: ' <item id="M" hash_code="6" content_hash_code="60" os_list="linux,windows"/>' --> ' <item id="M" hash_code="7" content_hash_code="70" os_list="linux,windows"/>' \ No newline at end of file
diff --git a/tools/traffic_annotation/auditor/tests/annotations_diff13.txt b/tools/traffic_annotation/auditor/tests/annotations_diff13.txt new file mode 100644 index 0000000..7a4b7c8 --- /dev/null +++ b/tools/traffic_annotation/auditor/tests/annotations_diff13.txt
@@ -0,0 +1,5 @@ + + Add line: ' <item id="G" hash_code="4" content_hash_code="40" os_list="linux,windows"/>' + Remove line: ' <item id="C" hash_code="3" content_hash_code="30" os_list="linux,windows"/>' + Remove line: ' <item id="M" hash_code="6" content_hash_code="60" os_list="linux,windows"/>' + Remove line: ' <item id="X" hash_code="8" content_hash_code="80" os_list="linux,windows"/>' \ No newline at end of file
diff --git a/tools/traffic_annotation/auditor/tests/annotations_diff23.txt b/tools/traffic_annotation/auditor/tests/annotations_diff23.txt new file mode 100644 index 0000000..978b221 --- /dev/null +++ b/tools/traffic_annotation/auditor/tests/annotations_diff23.txt
@@ -0,0 +1,8 @@ + + Add line: ' <item id="G" hash_code="4" content_hash_code="40" os_list="linux,windows"/>' + Remove line: ' <item id="A" hash_code="1" content_hash_code="10" os_list="linux,windows"/>' + Remove line: ' <item id="C" hash_code="3" content_hash_code="30" os_list="linux,windows"/>' + Remove line: ' <item id="E" hash_code="5" content_hash_code="50" os_list="linux,windows"/>' + Remove line: ' <item id="M" hash_code="7" content_hash_code="70" os_list="linux,windows"/>' + Remove line: ' <item id="X" hash_code="8" content_hash_code="80" os_list="linux,windows"/>' + Remove line: ' <item id="Z" hash_code="9" content_hash_code="90" os_list="linux,windows"/>' \ No newline at end of file
diff --git a/tools/traffic_annotation/auditor/tests/annotations_sample1.xml b/tools/traffic_annotation/auditor/tests/annotations_sample1.xml new file mode 100644 index 0000000..57bdef0 --- /dev/null +++ b/tools/traffic_annotation/auditor/tests/annotations_sample1.xml
@@ -0,0 +1,14 @@ +<?xml version="1.0"?> +<!-- +Copyright 2017 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. + +Refer to README.md for content description and update process. +--> + +<annotations> + <item id="C" hash_code="3" content_hash_code="30" os_list="linux,windows"/> + <item id="M" hash_code="6" content_hash_code="60" os_list="linux,windows"/> + <item id="X" hash_code="8" content_hash_code="80" os_list="linux,windows"/> +</annotations>
diff --git a/tools/traffic_annotation/auditor/tests/annotations_sample2.xml b/tools/traffic_annotation/auditor/tests/annotations_sample2.xml new file mode 100644 index 0000000..7e0ed0e --- /dev/null +++ b/tools/traffic_annotation/auditor/tests/annotations_sample2.xml
@@ -0,0 +1,17 @@ +<?xml version="1.0"?> +<!-- +Copyright 2017 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. + +Refer to README.md for content description and update process. +--> + +<annotations> + <item id="A" hash_code="1" content_hash_code="10" os_list="linux,windows"/> + <item id="C" hash_code="3" content_hash_code="30" os_list="linux,windows"/> + <item id="E" hash_code="5" content_hash_code="50" os_list="linux,windows"/> + <item id="M" hash_code="7" content_hash_code="70" os_list="linux,windows"/> + <item id="X" hash_code="8" content_hash_code="80" os_list="linux,windows"/> + <item id="Z" hash_code="9" content_hash_code="90" os_list="linux,windows"/> +</annotations>
diff --git a/tools/traffic_annotation/auditor/tests/annotations_sample3.xml b/tools/traffic_annotation/auditor/tests/annotations_sample3.xml new file mode 100644 index 0000000..eff397b --- /dev/null +++ b/tools/traffic_annotation/auditor/tests/annotations_sample3.xml
@@ -0,0 +1,12 @@ +<?xml version="1.0"?> +<!-- +Copyright 2017 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. + +Refer to README.md for content description and update process. +--> + +<annotations> + <item id="G" hash_code="4" content_hash_code="40" os_list="linux,windows"/> +</annotations>
diff --git a/tools/traffic_annotation/auditor/tests/extractor_outputs/good_assignment.txt b/tools/traffic_annotation/auditor/tests/extractor_outputs/good_assignment.txt index cb6237d..67a84a98 100644 --- a/tools/traffic_annotation/auditor/tests/extractor_outputs/good_assignment.txt +++ b/tools/traffic_annotation/auditor/tests/extractor_outputs/good_assignment.txt
@@ -1,3 +1,3 @@ -components/download/internal/proto_conversions.cc +components/download/internal/background_service/proto_conversions.cc download::ProtoConversions::EntryFromProto 267 \ No newline at end of file
diff --git a/tools/traffic_annotation/auditor/traffic_annotation_auditor.cc b/tools/traffic_annotation/auditor/traffic_annotation_auditor.cc index fcfa6db..7552d8b 100644 --- a/tools/traffic_annotation/auditor/traffic_annotation_auditor.cc +++ b/tools/traffic_annotation/auditor/traffic_annotation_auditor.cc
@@ -6,7 +6,7 @@ #include <stdio.h> -#include "base/files/dir_reader_posix.h" +#include "base/files/file_enumerator.h" #include "base/files/file_util.h" #include "base/logging.h" #include "base/process/launch.h" @@ -18,8 +18,8 @@ #include "build/build_config.h" #include "net/traffic_annotation/network_traffic_annotation.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" -#include "tools/traffic_annotation/auditor/traffic_annotation_exporter.h" #include "tools/traffic_annotation/auditor/traffic_annotation_file_filter.h" +#include "tools/traffic_annotation/auditor/traffic_annotation_id_checker.h" namespace { @@ -37,7 +37,7 @@ {PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS.unique_id_hash_code, "test_partial"}, {NO_TRAFFIC_ANNOTATION_YET.unique_id_hash_code, "undefined"}, {MISSING_TRAFFIC_ANNOTATION.unique_id_hash_code, "missing"}, -}; + {NO_TRAFFIC_ANNOTATION_BUG_656607.unique_id_hash_code, "undefined-656607"}}; struct AnnotationID { // Two ids can be the same in the following cases: @@ -53,28 +53,46 @@ AnnotationInstance* instance; }; -// Removes all occurances of a charcter from a string and returns the modified -// string. -std::string RemoveChar(const std::string& source, char removee) { - std::string output; - output.reserve(source.length()); - for (const char* current = source.data(); *current; current++) { - if (*current != removee) - output += *current; - } - return output; -} - const std::string kBlockTypes[] = {"ASSIGNMENT", "ANNOTATION", "CALL"}; -const base::FilePath kSafeListPath( - FILE_PATH_LITERAL("tools/traffic_annotation/auditor/safe_list.txt")); +const base::FilePath kSafeListPath = + base::FilePath(FILE_PATH_LITERAL("tools")) + .Append(FILE_PATH_LITERAL("traffic_annotation")) + .Append(FILE_PATH_LITERAL("auditor")) + .Append(FILE_PATH_LITERAL("safe_list.txt")); // The folder that includes the latest Clang built-in library. Inside this // folder, there should be another folder with version number, like // '.../lib/clang/6.0.0', which would be passed to the clang tool. -const base::FilePath kClangLibraryPath( - FILE_PATH_LITERAL("third_party/llvm-build/Release+Asserts/lib/clang")); +const base::FilePath kClangLibraryPath = + base::FilePath(FILE_PATH_LITERAL("third_party")) + .Append(FILE_PATH_LITERAL("llvm-build")) + .Append(FILE_PATH_LITERAL("Release+Asserts")) + .Append(FILE_PATH_LITERAL("lib")) + .Append(FILE_PATH_LITERAL("clang")); + +const base::FilePath kRunToolScript = + base::FilePath(FILE_PATH_LITERAL("tools")) + .Append(FILE_PATH_LITERAL("clang")) + .Append(FILE_PATH_LITERAL("scripts")) + .Append(FILE_PATH_LITERAL("run_tool.py")); + +// Checks if the list of |path_filters| include the given |file_path|, or there +// are path filters which are a folder (don't have a '.' in their name), and +// match the file name. +// TODO(https://crbug.com/690323): Update to a more general policy. +bool PathFiltersMatch(const std::vector<std::string>& path_filters, + const std::string file_path) { + if (base::ContainsValue(path_filters, file_path)) + return true; + for (const std::string& path_filter : path_filters) { + if (path_filter.find(".") == std::string::npos && + file_path.substr(0, path_filter.length()) == path_filter) { + return true; + } + } + return false; +} } // namespace @@ -85,13 +103,14 @@ : source_path_(source_path), build_path_(build_path), clang_tool_path_(clang_tool_path), + exporter_(source_path), safe_list_loaded_(false) { DCHECK(!source_path.empty()); DCHECK(!build_path.empty()); DCHECK(!clang_tool_path.empty()); } -TrafficAnnotationAuditor::~TrafficAnnotationAuditor() {} +TrafficAnnotationAuditor::~TrafficAnnotationAuditor() = default; // static int TrafficAnnotationAuditor::ComputeHashValue(const std::string& unique_id) { @@ -101,35 +120,26 @@ } base::FilePath TrafficAnnotationAuditor::GetClangLibraryPath() { - base::FilePath base_path = source_path_.Append(kClangLibraryPath); - std::string library_folder; - base::DirReaderPosix dir_reader(base_path.MaybeAsASCII().c_str()); - - while (dir_reader.Next()) { - if (strcmp(dir_reader.name(), ".") && strcmp(dir_reader.name(), "..")) { - library_folder = dir_reader.name(); - break; - } - } - - if (library_folder.empty()) { - return base::FilePath(); - } else { -#if defined(OS_WIN) - return base_path.Append(base::ASCIIToUTF16(library_folder)); -#else - return base_path.Append(library_folder); -#endif - } + return base::FileEnumerator(source_path_.Append(kClangLibraryPath), false, + base::FileEnumerator::DIRECTORIES) + .Next(); } bool TrafficAnnotationAuditor::RunClangTool( const std::vector<std::string>& path_filters, - const bool full_run) { + bool filter_files_based_on_heuristics, + bool use_compile_commands) { if (!safe_list_loaded_ && !LoadSafeList()) return false; - // Create a file to pass options to clang scripts. + // Get list of files/folders to process. + std::vector<std::string> file_paths; + GenerateFilesListForClangTool(path_filters, filter_files_based_on_heuristics, + use_compile_commands, &file_paths); + if (file_paths.empty()) + return true; + + // Create a file to pass options to the clang tool running script. base::FilePath options_filepath; if (!base::CreateTemporaryFile(&options_filepath)) { LOG(ERROR) << "Could not create temporary options file."; @@ -137,7 +147,7 @@ } FILE* options_file = base::OpenFile(options_filepath, "wt"); if (!options_file) { - LOG(ERROR) << "Could not create temporary options file."; + LOG(ERROR) << "Could not open temporary options file."; return false; } @@ -147,47 +157,22 @@ fprintf( options_file, "--generate-compdb --tool=traffic_annotation_extractor -p=%s " - "--tool-path=%s --tool-args=--extra-arg=-resource-dir=%s ", + "--tool-path=%s --tool-arg=--extra-arg=-resource-dir=%s " + "--tool-arg=--extra-arg=-Wno-comment ", build_path_.MaybeAsASCII().c_str(), base::MakeAbsoluteFilePath(clang_tool_path_).MaybeAsASCII().c_str(), base::MakeAbsoluteFilePath(GetClangLibraryPath()).MaybeAsASCII().c_str()); - // |safe_list_[ALL]| is not passed when |full_run| is happening as there is - // no way to pass it to run_tools.py except enumerating all alternatives. - // The paths in |safe_list_[ALL]| are removed later from the results. - if (full_run) { - for (const std::string& file_path : path_filters) - fprintf(options_file, "%s ", file_path.c_str()); - } else { - TrafficAnnotationFileFilter filter; - std::vector<std::string> file_paths; + if (use_compile_commands) + fprintf(options_file, "--all "); - if (path_filters.size()) { - for (const auto& path_filter : path_filters) { - filter.GetRelevantFiles( - source_path_, - safe_list_[static_cast<int>(AuditorException::ExceptionType::ALL)], - path_filter, &file_paths); - } - } else { - filter.GetRelevantFiles( - source_path_, - safe_list_[static_cast<int>(AuditorException::ExceptionType::ALL)], - "", &file_paths); - } + for (const std::string& file_path : file_paths) + fprintf(options_file, "%s ", file_path.c_str()); - if (!file_paths.size()) { - base::CloseFile(options_file); - base::DeleteFile(options_filepath, false); - return false; - } - for (const auto& file_path : file_paths) - fprintf(options_file, "%s ", file_path.c_str()); - } base::CloseFile(options_file); - base::CommandLine cmdline(source_path_.Append( - FILE_PATH_LITERAL("tools/clang/scripts/run_tool.py"))); + base::CommandLine cmdline( + base::MakeAbsoluteFilePath(source_path_.Append(kRunToolScript))); #if defined(OS_WIN) cmdline.PrependWrapper(L"python"); @@ -196,14 +181,116 @@ cmdline.AppendArg(base::StringPrintf( "--options-file=%s", options_filepath.MaybeAsASCII().c_str())); - // Run, and clean after. + // Change current folder to source before running run_tool.py as it expects to + // be run from there. + base::FilePath original_path; + base::GetCurrentDirectory(&original_path); + base::SetCurrentDirectory(source_path_); bool result = base::GetAppOutput(cmdline, &clang_tool_raw_output_); + // If running clang tool had no output, it means that the script running it + // could not perform the task. + if (clang_tool_raw_output_.empty()) + result = false; + + if (!result) { + if (use_compile_commands && !clang_tool_raw_output_.empty()) { + printf( + "\nWARNING: Ignoring clang tool error as it is called using " + "compile_commands.json which will result in processing some " + "library files that clang cannot process.\n"); + result = true; + } else { + std::string tool_errors; + std::string options_file_text; + + base::GetAppOutputAndError(cmdline, &tool_errors); + if (!base::ReadFileToString(options_filepath, &options_file_text)) + options_file_text = "Could not read options file."; + + LOG(ERROR) << base::StringPrintf( + "Calling clang tool from %s returned false.\nCommand line: %s\n\n" + "Returned error text: %s\n\nPartial options file: %s\n", + source_path_.MaybeAsASCII().c_str(), +#if defined(OS_WIN) + base::UTF16ToASCII(cmdline.GetCommandLineString()).c_str(), +#else + cmdline.GetCommandLineString().c_str(), +#endif + tool_errors.c_str(), options_file_text.substr(0, 1024).c_str()); + } + } + + base::SetCurrentDirectory(original_path); base::DeleteFile(options_filepath, false); return result; } +void TrafficAnnotationAuditor::GenerateFilesListForClangTool( + const std::vector<std::string>& path_filters, + bool filter_files_based_on_heuristics, + bool use_compile_commands, + std::vector<std::string>* file_paths) { + // If |use_compile_commands| is requested or + // |filter_files_based_on_heuristics| is false, we pass all given file paths + // to the running script and the files in the safe list will be later removed + // from the results. + if (!filter_files_based_on_heuristics || use_compile_commands) { + *file_paths = path_filters; + return; + } + + TrafficAnnotationFileFilter filter; + + // If no path filter is provided, get all relevant files, except the safe + // listed ones. + if (path_filters.empty()) { + filter.GetRelevantFiles( + source_path_, + safe_list_[static_cast<int>(AuditorException::ExceptionType::ALL)], "", + file_paths); + return; + } + + base::FilePath original_path; + base::GetCurrentDirectory(&original_path); + base::SetCurrentDirectory(source_path_); + + bool possibly_deleted_files = false; + for (const auto& path_filter : path_filters) { +#if defined(OS_WIN) + base::FilePath path = base::FilePath( + base::FilePath::StringPieceType((base::UTF8ToWide(path_filter)))); +#else + base::FilePath path = base::FilePath(path_filter); +#endif + + // If path filter is a directory, add its relevent, not safe-listed + // contents. + if (base::DirectoryExists(path)) { + filter.GetRelevantFiles( + source_path_, + safe_list_[static_cast<int>(AuditorException::ExceptionType::ALL)], + path_filter, file_paths); + } else { + // Add the file if it exists and is a relevant file which is not + // safe-listed. + if (base::PathExists(path)) { + if (!TrafficAnnotationAuditor::IsSafeListed( + path_filter, AuditorException::ExceptionType::ALL) && + filter.IsFileRelevant(path_filter)) { + file_paths->push_back(path_filter); + } + } else { + possibly_deleted_files = true; + } + } + } + + base::SetCurrentDirectory(original_path); +} + bool TrafficAnnotationAuditor::IsSafeListed( const std::string& file_path, AuditorException::ExceptionType exception_type) { @@ -228,11 +315,10 @@ if (!safe_list_loaded_ && !LoadSafeList()) return false; // Remove possible carriage return characters before splitting lines. - // Not using base::RemoveChars as the input is ~47M and the implementation is - // too slow for it. - std::vector<std::string> lines = - base::SplitString(RemoveChar(clang_tool_raw_output_, '\r'), "\n", - base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); + std::string temp_string; + base::RemoveChars(clang_tool_raw_output_, "\r", &temp_string); + std::vector<std::string> lines = base::SplitString( + temp_string, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); for (unsigned int current = 0; current < lines.size(); current++) { // All blocks reported by clang tool start with '====', so we can ignore // all lines that do not start with a '='. @@ -359,164 +445,16 @@ // static const std::map<int, std::string>& -TrafficAnnotationAuditor::GetReservedUniqueIDs() { +TrafficAnnotationAuditor::GetReservedIDsMap() { return kReservedAnnotations; } -void TrafficAnnotationAuditor::PurgeAnnotations( - const std::set<int>& hash_codes) { - extracted_annotations_.erase( - std::remove_if(extracted_annotations_.begin(), - extracted_annotations_.end(), - [&hash_codes](AnnotationInstance& annotation) { - return base::ContainsKey(hash_codes, - annotation.unique_id_hash_code); - }), - extracted_annotations_.end()); -} - -bool TrafficAnnotationAuditor::CheckDuplicateHashes() { - const std::map<int, std::string> reserved_ids = GetReservedUniqueIDs(); - - std::map<int, std::vector<AnnotationID>> collisions; - std::set<int> to_be_purged; - std::set<int> deprecated_ids; - - // Load deprecated Hashcodes. - if (!TrafficAnnotationExporter(source_path_) - .GetDeprecatedHashCodes(&deprecated_ids)) { - return false; - } - - for (AnnotationInstance& instance : extracted_annotations_) { - // Check if partial and branched completing annotation have an extra id - // which is different from their unique id. - if ((instance.type == AnnotationInstance::Type::ANNOTATION_PARTIAL || - instance.type == - AnnotationInstance::Type::ANNOTATION_BRANCHED_COMPLETING) && - (instance.unique_id_hash_code == instance.extra_id_hash_code)) { - errors_.push_back(AuditorResult( - AuditorResult::Type::ERROR_MISSING_EXTRA_ID, std::string(), - instance.proto.source().file(), instance.proto.source().line())); - continue; - } - - AnnotationID current; - current.instance = &instance; - // Iterate over unique id and extra id. - for (int id = 0; id < 2; id++) { - if (id) { - // If it's an empty extra id, no further check is required. - if (instance.extra_id.empty()) { - continue; - } else { - current.text = instance.extra_id; - current.hash = instance.extra_id_hash_code; - if (instance.type == AnnotationInstance::Type::ANNOTATION_PARTIAL) { - current.type = AnnotationID::Type::kPatrialExtra; - } else if (instance.type == - AnnotationInstance::Type::ANNOTATION_BRANCHED_COMPLETING) { - current.type = AnnotationID::Type::kBranchedExtra; - } else { - current.type = AnnotationID::Type::kOther; - } - } - } else { - current.text = instance.proto.unique_id(); - current.hash = instance.unique_id_hash_code; - current.type = - instance.type == AnnotationInstance::Type::ANNOTATION_COMPLETING - ? AnnotationID::Type::kCompletingMain - : AnnotationID::Type::kOther; - } - - // If the id's hash code is the same as a reserved id, add an error. - if (base::ContainsKey(reserved_ids, current.hash)) { - errors_.push_back(AuditorResult( - AuditorResult::Type::ERROR_RESERVED_UNIQUE_ID_HASH_CODE, - current.text, instance.proto.source().file(), - instance.proto.source().line())); - continue; - } - - // If the id's hash code was formerly used by a deprecated annotation, - // add an error. - if (base::ContainsKey(deprecated_ids, current.hash)) { - errors_.push_back(AuditorResult( - AuditorResult::Type::ERROR_DEPRECATED_UNIQUE_ID_HASH_CODE, - current.text, instance.proto.source().file(), - instance.proto.source().line())); - continue; - } - - // Check for collisions. - if (!base::ContainsKey(collisions, current.hash)) { - collisions[current.hash] = std::vector<AnnotationID>(); - } else { - // Add error for ids with the same hash codes. If the texts are really - // different, there is a hash collision and should be corrected in any - // case. Otherwise, it's an error if it doesn't match the criteria that - // are previously spcified in definition of AnnotationID struct. - for (const auto& other : collisions[current.hash]) { - if (current.text == other.text && - ((current.type == AnnotationID::Type::kPatrialExtra && - (other.type == AnnotationID::Type::kPatrialExtra || - other.type == AnnotationID::Type::kCompletingMain || - other.type == AnnotationID::Type::kBranchedExtra)) || - (other.type == AnnotationID::Type::kPatrialExtra && - (current.type == AnnotationID::Type::kCompletingMain || - current.type == AnnotationID::Type::kBranchedExtra)) || - (current.type == AnnotationID::Type::kBranchedExtra && - other.type == AnnotationID::Type::kBranchedExtra))) { - continue; - } - - AuditorResult error( - AuditorResult::Type::ERROR_DUPLICATE_UNIQUE_ID_HASH_CODE, - base::StringPrintf( - "%s in '%s:%i'", current.text.c_str(), - current.instance->proto.source().file().c_str(), - current.instance->proto.source().line())); - error.AddDetail( - base::StringPrintf("%s in '%s:%i'", other.text.c_str(), - other.instance->proto.source().file().c_str(), - other.instance->proto.source().line())); - - errors_.push_back(error); - to_be_purged.insert(current.hash); - to_be_purged.insert(other.hash); - } - } - collisions[current.hash].push_back(current); - } - } - - PurgeAnnotations(to_be_purged); - return true; -} - -void TrafficAnnotationAuditor::CheckUniqueIDsFormat() { - std::set<int> to_be_purged; - for (const AnnotationInstance& instance : extracted_annotations_) { - if (!base::ContainsOnlyChars(base::ToLowerASCII(instance.proto.unique_id()), - "0123456789_abcdefghijklmnopqrstuvwxyz")) { - errors_.push_back(AuditorResult( - AuditorResult::Type::ERROR_UNIQUE_ID_INVALID_CHARACTER, - instance.proto.unique_id(), instance.proto.source().file(), - instance.proto.source().line())); - to_be_purged.insert(instance.unique_id_hash_code); - } - if (!instance.extra_id.empty() && - !base::ContainsOnlyChars(base::ToLowerASCII(instance.extra_id), - "0123456789_abcdefghijklmnopqrstuvwxyz")) { - errors_.push_back( - AuditorResult(AuditorResult::Type::ERROR_UNIQUE_ID_INVALID_CHARACTER, - instance.extra_id, instance.proto.source().file(), - instance.proto.source().line())); - to_be_purged.insert(instance.unique_id_hash_code); - } - } - PurgeAnnotations(to_be_purged); +// static +std::set<int> TrafficAnnotationAuditor::GetReservedIDsSet() { + std::set<int> reserved_ids; + for (const auto& item : kReservedAnnotations) + reserved_ids.insert(item.first); + return reserved_ids; } void TrafficAnnotationAuditor::CheckAllRequiredFunctionsAreAnnotated() { @@ -558,8 +496,13 @@ // Check if the file including this function is part of Chrome build. const base::CommandLine::CharType* args[] = { #if defined(OS_WIN) - FILE_PATH_LITERAL("gn.bat"), + FILE_PATH_LITERAL("buildtools/win/gn.exe"), +#elif defined(OS_MACOSX) + FILE_PATH_LITERAL("buildtools/mac/gn"), +#elif defined(OS_LINUX) + FILE_PATH_LITERAL("buildtools/linux64/gn"), #else + // Fallback to using PATH to find gn. FILE_PATH_LITERAL("gn"), #endif FILE_PATH_LITERAL("refs"), @@ -597,19 +540,18 @@ std::vector<AnnotationInstance*> partial_annotations; std::vector<AnnotationInstance*> completing_annotations; std::vector<AnnotationInstance> new_annotations; - std::set<int> to_be_purged; // Process complete annotations and separate the others. for (AnnotationInstance& instance : extracted_annotations_) { - bool keep_annotation = false; switch (instance.type) { case AnnotationInstance::Type::ANNOTATION_COMPLETE: { + // Instances loaded from archive are already checked before archiving. + if (instance.is_loaded_from_archive) + continue; AuditorResult result = instance.IsComplete(); if (result.IsOK()) result = instance.IsConsistent(); - if (result.IsOK()) - keep_annotation = true; - else + if (!result.IsOK()) errors_.push_back(result); break; } @@ -619,8 +561,6 @@ default: completing_annotations.push_back(&instance); } - if (!keep_annotation) - to_be_purged.insert(instance.unique_id_hash_code); } std::set<AnnotationInstance*> used_completing_annotations; @@ -632,6 +572,12 @@ found_a_pair = true; used_completing_annotations.insert(completing); + // Instances loaded from archive are already checked before archiving. + if (partial->is_loaded_from_archive && + completing->is_loaded_from_archive) { + break; + } + AnnotationInstance completed; AuditorResult result = partial->CreateCompleteAnnotation(*completing, &completed); @@ -655,33 +601,78 @@ } if (!found_a_pair) { - errors_.push_back(AuditorResult( - AuditorResult::Type::ERROR_INCOMPLETED_ANNOTATION, std::string(), - partial->proto.source().file(), partial->proto.source().line())); + errors_.push_back( + AuditorResult(AuditorResult::Type::ERROR_INCOMPLETED_ANNOTATION, + partial->proto.unique_id())); } } for (AnnotationInstance* instance : completing_annotations) { if (!base::ContainsKey(used_completing_annotations, instance)) { - errors_.push_back(AuditorResult( - AuditorResult::Type::ERROR_INCOMPLETED_ANNOTATION, std::string(), - instance->proto.source().file(), instance->proto.source().line())); + errors_.push_back( + AuditorResult(AuditorResult::Type::ERROR_INCOMPLETED_ANNOTATION, + instance->proto.unique_id())); } } - PurgeAnnotations(to_be_purged); if (new_annotations.size()) extracted_annotations_.insert(extracted_annotations_.end(), new_annotations.begin(), new_annotations.end()); } -bool TrafficAnnotationAuditor::RunAllChecks() { - if (!CheckDuplicateHashes()) +void TrafficAnnotationAuditor::AddMissingAnnotations( + const std::vector<std::string>& path_filters) { + for (const auto& item : exporter_.GetArchivedAnnotations()) { + if (item.second.deprecation_date.empty() && + exporter_.MatchesCurrentPlatform(item.second) && + !item.second.file_path.empty() && + !PathFiltersMatch(path_filters, item.second.file_path)) { + extracted_annotations_.push_back(AnnotationInstance::LoadFromArchive( + item.second.type, item.first, item.second.unique_id_hash_code, + item.second.second_id_hash_code, item.second.content_hash_code, + item.second.semantics_fields, item.second.policy_fields, + item.second.file_path)); + } + } +} + +bool TrafficAnnotationAuditor::RunAllChecks( + const std::vector<std::string>& path_filters, + bool report_xml_updates) { + std::set<int> deprecated_ids; + + if (!exporter_.GetDeprecatedHashCodes(&deprecated_ids)) { return false; - CheckUniqueIDsFormat(); - CheckAnnotationsContents(); + } + + if (path_filters.size()) + AddMissingAnnotations(path_filters); + + TrafficAnnotationIDChecker id_checker(GetReservedIDsSet(), deprecated_ids); + id_checker.Load(extracted_annotations_); + id_checker.CheckIDs(&errors_); + + // Only check annotation contents if IDs are all OK, because if there are + // id errors, there might be some mismatching annotations and irrelevant + // content errors. + if (errors_.empty()) + CheckAnnotationsContents(); CheckAllRequiredFunctionsAreAnnotated(); + + if (errors_.empty()) { + if (!exporter_.UpdateAnnotations(extracted_annotations_, + GetReservedIDsMap())) { + return false; + } + } + + if (report_xml_updates && exporter_.modified()) { + errors_.push_back( + AuditorResult(AuditorResult::Type::ERROR_ANNOTATIONS_XML_UPDATE, + exporter_.GetRequiredUpdates())); + } + return true; -} \ No newline at end of file +}
diff --git a/tools/traffic_annotation/auditor/traffic_annotation_auditor.h b/tools/traffic_annotation/auditor/traffic_annotation_auditor.h index 5d32bc6..0c39d7c2 100644 --- a/tools/traffic_annotation/auditor/traffic_annotation_auditor.h +++ b/tools/traffic_annotation/auditor/traffic_annotation_auditor.h
@@ -11,6 +11,7 @@ #include "base/files/file_path.h" #include "tools/traffic_annotation/auditor/auditor_result.h" #include "tools/traffic_annotation/auditor/instance.h" +#include "tools/traffic_annotation/auditor/traffic_annotation_exporter.h" #include "tools/traffic_annotation/traffic_annotation.pb.h" // Holds an item of safe list rules for auditor. @@ -50,9 +51,14 @@ ~TrafficAnnotationAuditor(); // Runs traffic_annotation_extractor clang tool and puts its output in - // |clang_tool_raw_output_|. + // |clang_tool_raw_output_|. If |filter_files_based_on_heuristics| flag is + // set, the list of files will be received from repository and heuristically + // filtered to only process the relevant files. If |use_compile_commands| flag + // is set, the list of files is extracted from compile_commands.json instead + // of git and will not be filtered. bool RunClangTool(const std::vector<std::string>& path_filters, - bool full_run); + bool filter_files_based_on_heuristics, + bool use_compile_commands); // Parses the output of clang tool (|clang_tool_raw_output_|) and populates // |extracted_annotations_|, |extracted_calls_|, and |errors_|. @@ -70,17 +76,6 @@ bool IsSafeListed(const std::string& file_path, AuditorException::ExceptionType exception_type); - // Checks to see if any unique id or extra id or their hash code are - // duplicated, either in currently existing annotations, or in deprecated - // ones. Adds errors to |errors_| and purges annotations with duplicate ids. - // Returns false if any errors happen while checking. - bool CheckDuplicateHashes(); - - // Checks to see if unique ids only include alphanumeric characters and - // underline. Adds errors to |errors_| and purges annotations with - // incorrect ids. - void CheckUniqueIDsFormat(); - // Checks to see if annotation contents are valid. Complete annotations should // have all required fields and be consistent, and incomplete annotations // should be completed with each other. Merges all matching incomplete @@ -94,17 +89,24 @@ // Checks if a call instance can stay not annotated. bool CheckIfCallCanBeUnannotated(const CallInstance& call); - // Performs all checks on extracted annotations and calls. - bool RunAllChecks(); + // Performs all checks on extracted annotations and calls. The input path + // filters are passed so that the data for files that were not tested would be + // read from annotations.xml. If |report_xml_updates| is set and + // annotations.xml requires updates, the updates are added to |errors_|. + bool RunAllChecks(const std::vector<std::string>& path_filters, + bool report_xml_updates); // Returns a mapping of reserved unique ids' hash codes to the unique ids' // texts. This list includes all unique ids that are defined in // net/traffic_annotation/network_traffic_annotation.h and // net/traffic_annotation/network_traffic_annotation_test_helper.h - static const std::map<int, std::string>& GetReservedUniqueIDs(); + static const std::map<int, std::string>& GetReservedIDsMap(); - // Removes annotations whose unique id hash code are given. - void PurgeAnnotations(const std::set<int>& hash_codes); + // Returns a set of reserved unique ids' hash codes. This set includes all + // unique ids that are defined in + // net/traffic_annotation/network_traffic_annotation.h and + // net/traffic_annotation/network_traffic_annotation_test_helper.h + static std::set<int> GetReservedIDsSet(); std::string clang_tool_raw_output() const { return clang_tool_raw_output_; }; @@ -131,6 +133,8 @@ const std::vector<AuditorResult>& errors() const { return errors_; } + const TrafficAnnotationExporter& exporter() const { return exporter_; } + void ClearErrorsForTesting() { errors_.clear(); } void ClearCheckedDependenciesForTesting() { checked_dependencies_.clear(); } @@ -149,6 +153,8 @@ const base::FilePath build_path_; const base::FilePath clang_tool_path_; + TrafficAnnotationExporter exporter_; + std::string clang_tool_raw_output_; std::vector<AnnotationInstance> extracted_annotations_; std::vector<CallInstance> extracted_calls_; @@ -160,6 +166,22 @@ AuditorException::ExceptionType::EXCEPTION_TYPE_LAST) + 1]; + // Adds all archived annotations (from annotations.xml) that match the + // following features, to |extracted_annotations_|: + // 1- Not deprecated. + // 2- OS list includes current platform. + // 2- Has a path (is not a reserved word). + // 3- Path matches an item in |path_filters|. + void AddMissingAnnotations(const std::vector<std::string>& path_filters); + + // Generates files list to Run clang tool on. Please refer to RunClangTool + // function's comment. + void GenerateFilesListForClangTool( + const std::vector<std::string>& path_filters, + bool filter_files_based_on_heuristics, + bool use_compile_commands, + std::vector<std::string>* file_paths); + base::FilePath gn_file_for_test_; std::map<std::string, bool> checked_dependencies_; };
diff --git a/tools/traffic_annotation/auditor/traffic_annotation_auditor_ui.cc b/tools/traffic_annotation/auditor/traffic_annotation_auditor_ui.cc index 218b65d..a8a0009e 100644 --- a/tools/traffic_annotation/auditor/traffic_annotation_auditor_ui.cc +++ b/tools/traffic_annotation/auditor/traffic_annotation_auditor_ui.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "base/files/file_util.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" @@ -24,7 +25,7 @@ Usage: traffic_annotation_auditor [OPTION]... [path_filters] Extracts network traffic annotations from source files. If path filter(s) are -specified, only those directories of the source will be analyzed. +specified, only those directories of the source will be analyzed. Options: -h, --help Shows help. @@ -37,12 +38,17 @@ auditor's executable. --extractor-output Optional path to the temporary file that extracted annotations will be stored into. - --extracted-input Optional path to the file that temporary extracted + --extractor-input Optional path to the file that temporary extracted annotations are already stored in. If this is provided, clang tool is not run and this is used as input. - --full-run Optional flag asking the tool to run on the whole + --no-filtering Optional flag asking the tool to run on the whole repository without text filtering files. Using this flag may increase processing time x40. + --all-files Optional flag asking to use compile_commands.json instead + of git to get the list of files that will be checked. + This flag is useful when using build flags that change + files, like jumbo. This flag slows down the execution as + it checks every compiled file. --test-only Optional flag to request just running tests and not updating any file. If not specified, 'tools/traffic_annotation/summary/annotations.xml' might @@ -51,14 +57,27 @@ be called to update downstream files. --summary-file Optional path to the output file with all annotations. --annotations-file Optional path to a TSV output file with all annotations. - path_filters Optional paths to filter what files the tool is run on. + --limit Limit for the maximum number of returned errors. + Use 0 for unlimited. + --error-resilient Optional flag, stating not to return error in exit code if + auditor fails to perform the tests. This flag can be used + for trybots to avoid spamming when tests cannot run. + path_filters Optional paths to filter which files the tool is run on. + It can also include deleted files names when auditor is + run on a partial repository. Example: - traffic_annotation_auditor --build-dir=out/Debug summary-file=report.txt + traffic_annotation_auditor --build-path=out/Release )"; -const base::FilePath kDownstreamUpdater(FILE_PATH_LITERAL( - "tools/traffic_annotation/scripts/annotations_xml_downstream_caller.py")); +const base::FilePath kDownstreamUpdater = + base::FilePath(FILE_PATH_LITERAL("tools")) + .Append(FILE_PATH_LITERAL("traffic_annotation")) + .Append(FILE_PATH_LITERAL("scripts")) + .Append(FILE_PATH_LITERAL("annotations_xml_downstream_caller.py")); + +const std::string kCodeSearchLink("https://cs.chromium.org/chromium/src/"); + } // namespace // Calls |kDownstreamUpdater| script to update files that depend on @@ -173,24 +192,25 @@ // Writes a TSV file of all annotations and their content. bool WriteAnnotationsFile(const base::FilePath& filepath, - const std::vector<AnnotationInstance>& annotations) { + const std::vector<AnnotationInstance>& annotations, + const std::vector<std::string>& missing_ids) { std::vector<std::string> lines; std::string title = - "Unique ID\tReview by pconunsel\tEmpty Policy Justification\t" - "Sender\tDescription\tTrigger\tData\tDestination\tCookies Allowed\t" - "Cookies Store\tSetting\tChrome Policy\tComments\tSource File\tHash Code"; + "Unique ID\tLast Update\tSender\tDescription\tTrigger\tData\t" + "Destination\tCookies Allowed\tCookies Store\tSetting\tChrome Policy\t" + "Comments\tSource File\tID Hash Code\tContent Hash Code"; for (auto& instance : annotations) { + if (instance.type != AnnotationInstance::Type::ANNOTATION_COMPLETE) + continue; // Unique ID std::string line = instance.proto.unique_id(); - // Place holder for Review by pcounsel. + // Place holder for Last Update Date, will be updated in the scripts. line += "\t"; // Semantics. const auto semantics = instance.proto.semantics(); - line += base::StringPrintf("\t%s", - semantics.empty_policy_justification().c_str()); line += base::StringPrintf("\t%s", semantics.sender().c_str()); line += base::StringPrintf( "\t%s", UpdateTextForTSV(semantics.description()).c_str()); @@ -213,11 +233,13 @@ break; case traffic_annotation:: NetworkTrafficAnnotation_TrafficSemantics_Destination_OTHER: - if (!semantics.destination_other().empty()) + if (!semantics.destination_other().empty()) { + line += "\t"; line += UpdateTextForTSV(base::StringPrintf( - "\tOther: %s", semantics.destination_other().c_str())); - else + "Other: %s", semantics.destination_other().c_str())); + } else { line += "\tOther"; + } break; default: @@ -252,23 +274,36 @@ line += base::StringPrintf("\t%s", UpdateTextForTSV(policies_text).c_str()); // Comments. - line += "\t" + instance.proto.comments(); + line += "\t" + UpdateTextForTSV(instance.proto.comments()); // Source. const auto source = instance.proto.source(); - line += base::StringPrintf("\t%s:%i", source.file().c_str(), source.line()); + line += base::StringPrintf("\t%s%s?l=%i", kCodeSearchLink.c_str(), + source.file().c_str(), source.line()); - // Hash code. + // ID Hash code. line += base::StringPrintf("\t%i", instance.unique_id_hash_code); + // Content Hash code. + line += base::StringPrintf("\t%i", instance.GetContentHashCode()); + lines.push_back(line); } + // Add missing annotations. + int columns = std::count(title.begin(), title.end(), '\t'); + std::string tabs(columns, '\t'); + + for (const std::string& id : missing_ids) { + lines.push_back(id + tabs); + } + std::sort(lines.begin(), lines.end()); lines.insert(lines.begin(), title); std::string report; - for (const std::string& line : lines) + for (const std::string& line : lines) { report += line + "\n"; + } return base::WriteFile(filepath, report.c_str(), report.length()) != -1; } @@ -278,9 +313,12 @@ #else int main(int argc, char* argv[]) { #endif + printf("Starting traffic annotation auditor. This may take a few minutes.\n"); + // Parse switches. base::CommandLine command_line = base::CommandLine(argc, argv); - if (command_line.HasSwitch("help") || command_line.HasSwitch("h")) { + if (command_line.HasSwitch("help") || command_line.HasSwitch("h") || + argc == 1) { printf("%s", HELP_TEXT); return 1; } @@ -292,16 +330,36 @@ command_line.GetSwitchValuePath("extractor-output"); base::FilePath extractor_input = command_line.GetSwitchValuePath("extractor-input"); - bool full_run = command_line.HasSwitch("full-run"); + bool filter_files = !command_line.HasSwitch("no-filtering"); + bool all_files = command_line.HasSwitch("all-files"); bool test_only = command_line.HasSwitch("test-only"); base::FilePath summary_file = command_line.GetSwitchValuePath("summary-file"); base::FilePath annotations_file = command_line.GetSwitchValuePath("annotations-file"); std::vector<std::string> path_filters; + int outputs_limit = 0; + if (command_line.HasSwitch("limit")) { + if (!base::StringToInt(command_line.GetSwitchValueNative("limit"), + &outputs_limit) || + outputs_limit < 0) { + LOG(ERROR) + << "The value for 'limit' switch should be a positive integer."; + + // This error is always enforced, as it is a commandline switch. + return 1; + } + } + + // If 'error-resilient' switch is provided, 0 will be returned in case of + // operational errors, otherwise 1. + int error_value = command_line.HasSwitch("error-resilient") ? 0 : 1; #if defined(OS_WIN) - for (const auto& path : command_line.GetArgs()) - path_filters.push_back(base::UTF16ToASCII(path)); + for (const auto& path : command_line.GetArgs()) { + std::string repaired_path(base::UTF16ToASCII(path)); + base::ReplaceChars(repaired_path, "\\", "/", &repaired_path); + path_filters.push_back(repaired_path); + } #else path_filters = command_line.GetArgs(); #endif @@ -321,21 +379,22 @@ .Append(base::FilePath::kParentDirectory); } + // Get build directory, if it is empty issue an error. + if (build_path.empty()) { + LOG(ERROR) + << "You must specify a compiled build directory to run the auditor.\n"; + + // This error is always enforced, as it is a commandline switch. + return 1; + } + TrafficAnnotationAuditor auditor(source_path, build_path, tool_path); // Extract annotations. if (extractor_input.empty()) { - // Get build directory, if it is empty issue an error. - if (build_path.empty()) { - LOG(ERROR) - << "You must either specify the build directory to run the clang " - "tool and extract annotations, or specify the input file where " - "extracted annotations already exist.\n"; - return 1; - } - if (!auditor.RunClangTool(path_filters, full_run)) { + if (!auditor.RunClangTool(path_filters, filter_files, all_files)) { LOG(ERROR) << "Failed to run clang tool."; - return 1; + return error_value; } // Write extractor output if requested. @@ -349,7 +408,7 @@ if (!base::ReadFileToString(extractor_input, &raw_output)) { LOG(ERROR) << "Could not read input file: " << extractor_input.value().c_str(); - return 1; + return error_value; } else { auditor.set_clang_tool_raw_output(raw_output); } @@ -357,12 +416,12 @@ // Process extractor output. if (!auditor.ParseClangToolRawOutput()) - return 1; + return error_value; // Perform checks. - if (!auditor.RunAllChecks()) { + if (!auditor.RunAllChecks(path_filters, test_only)) { LOG(ERROR) << "Running checks failed."; - return 1; + return error_value; } // Write the summary file. @@ -370,42 +429,43 @@ !WriteSummaryFile(summary_file, auditor.extracted_annotations(), auditor.extracted_calls(), auditor.errors())) { LOG(ERROR) << "Could not write summary file."; - return 1; + return error_value; } // Write annotations TSV file. - if (!annotations_file.empty() && - !WriteAnnotationsFile(annotations_file, - auditor.extracted_annotations())) { - LOG(ERROR) << "Could not write TSV file."; - return 1; - } - - // Test/Update annotations.xml. - TrafficAnnotationExporter exporter(source_path); - if (!exporter.UpdateAnnotations( - auditor.extracted_annotations(), - TrafficAnnotationAuditor::GetReservedUniqueIDs())) { - return 1; - } - if (exporter.modified()) { - if (test_only) { - printf("Error: annotation.xml needs update.\n"); - } else if (!exporter.SaveAnnotationsXML() || - !RunAnnotationDownstreamUpdater(source_path)) { - LOG(ERROR) << "Could not update annotations XML or downstream files."; - return 1; + if (!annotations_file.empty()) { + std::vector<std::string> missing_ids; + if (!auditor.exporter().GetOtherPlatformsAnnotationIDs(&missing_ids) || + !WriteAnnotationsFile(annotations_file, auditor.extracted_annotations(), + missing_ids)) { + LOG(ERROR) << "Could not write TSV file."; + return error_value; } } - // Dump Errors and Warnings to stdout. const std::vector<AuditorResult>& errors = auditor.errors(); - for (const auto& error : errors) { - printf( - "%s: %s\n", - error.type() == AuditorResult::Type::ERROR_SYNTAX ? "Error" : "Warning", - error.ToText().c_str()); + + // Update annotations.xml if everything else is OK and the auditor is not + // run in test-only mode. + if (errors.empty() && !test_only && auditor.exporter().modified()) { + if (!auditor.exporter().SaveAnnotationsXML() || + !RunAnnotationDownstreamUpdater(source_path)) { + LOG(ERROR) << "Could not update annotations XML or downstream files."; + return error_value; + } } - return 0; + // Dump Errors to stdout. + if (errors.size()) { + printf("[Errors]\n"); + for (int i = 0; i < static_cast<int>(errors.size()); i++) { + printf(" (%i)\t%s\n", i + 1, errors[i].ToText().c_str()); + if (i + 1 == outputs_limit) + break; + } + } else { + printf("Traffic annotations are all OK.\n"); + } + + return static_cast<int>(errors.size()); } \ No newline at end of file
diff --git a/tools/traffic_annotation/auditor/traffic_annotation_auditor_unittest.cc b/tools/traffic_annotation/auditor/traffic_annotation_auditor_unittest.cc index 0a4be56b..0dab1425 100644 --- a/tools/traffic_annotation/auditor/traffic_annotation_auditor_unittest.cc +++ b/tools/traffic_annotation/auditor/traffic_annotation_auditor_unittest.cc
@@ -19,6 +19,7 @@ #include "testing/gtest/include/gtest/gtest.h" #include "tools/traffic_annotation/auditor/traffic_annotation_exporter.h" #include "tools/traffic_annotation/auditor/traffic_annotation_file_filter.h" +#include "tools/traffic_annotation/auditor/traffic_annotation_id_checker.h" namespace { @@ -36,16 +37,23 @@ "tools/traffic_annotation/auditor/tests/relevant_file_name_and_content.cc", "tools/traffic_annotation/auditor/tests/relevant_file_name_and_content.mm"}; -const base::FilePath kTestsFolder( - FILE_PATH_LITERAL("tools/traffic_annotation/auditor/tests")); +const base::FilePath kTestsFolder = + base::FilePath(FILE_PATH_LITERAL("tools")) + .Append(FILE_PATH_LITERAL("traffic_annotation")) + .Append(FILE_PATH_LITERAL("auditor")) + .Append(FILE_PATH_LITERAL("tests")); -const base::FilePath kClangToolPath( - FILE_PATH_LITERAL("tools/traffic_annotation/bin")); +const base::FilePath kClangToolPath = + base::FilePath(FILE_PATH_LITERAL("tools")) + .Append(FILE_PATH_LITERAL("traffic_annotation/bin")); -const base::FilePath kDownstreamUnittests( - FILE_PATH_LITERAL("tools/traffic_annotation/scripts/" - "annotations_xml_downstream_caller.py")); +const base::FilePath kDownstreamUnittests = + base::FilePath(FILE_PATH_LITERAL("tools")) + .Append(FILE_PATH_LITERAL("traffic_annotation")) + .Append(FILE_PATH_LITERAL("scripts")) + .Append(FILE_PATH_LITERAL("annotations_xml_downstream_caller.py")); +const std::set<int> kDummyDeprecatedIDs = {100, 101, 102}; } // namespace using namespace testing; @@ -76,13 +84,20 @@ // As build path is not available and not used in tests, the default (empty) // build path is passed to auditor. auditor_ = std::make_unique<TrafficAnnotationAuditor>( - source_path_, source_path_.Append(FILE_PATH_LITERAL("out/Default")), + source_path_, + source_path_.Append(FILE_PATH_LITERAL("out")) + .Append(FILE_PATH_LITERAL("Default")), clang_tool_path); + + id_checker_ = std::make_unique<TrafficAnnotationIDChecker>( + TrafficAnnotationAuditor::GetReservedIDsSet(), kDummyDeprecatedIDs); } const base::FilePath source_path() const { return source_path_; } const base::FilePath tests_folder() const { return tests_folder_; }; TrafficAnnotationAuditor& auditor() { return *auditor_; } + TrafficAnnotationIDChecker& id_checker() { return *id_checker_; } + std::vector<AuditorResult>* errors() { return &errors_; } protected: // Deserializes an annotation or a call instance from a sample file similar to @@ -92,6 +107,13 @@ // Creates a complete annotation instance using sample files. AnnotationInstance CreateAnnotationInstanceSample(); + AnnotationInstance CreateAnnotationInstanceSample( + AnnotationInstance::Type type, + int unique_id); + AnnotationInstance CreateAnnotationInstanceSample( + AnnotationInstance::Type type, + int unique_id, + int second_id); void SetAnnotationForTesting(const AnnotationInstance& instance) { std::vector<AnnotationInstance> annotations; @@ -100,10 +122,20 @@ auditor_->ClearErrorsForTesting(); } + void RunIDChecker(const AnnotationInstance& instance) { + std::vector<AnnotationInstance> annotations; + annotations.push_back(instance); + errors_.clear(); + id_checker_->Load(annotations); + id_checker_->CheckIDs(&errors_); + } + private: base::FilePath source_path_; base::FilePath tests_folder_; std::unique_ptr<TrafficAnnotationAuditor> auditor_; + std::unique_ptr<TrafficAnnotationIDChecker> id_checker_; + std::vector<AuditorResult> errors_; }; AuditorResult::Type TrafficAnnotationAuditorTest::Deserialize( @@ -113,7 +145,8 @@ EXPECT_TRUE(base::ReadFileToString( tests_folder_.Append(FILE_PATH_LITERAL("extractor_outputs")) .AppendASCII(file_name), - &file_content)); + &file_content)) + << file_name; base::RemoveChars(file_content, "\r", &file_content); std::vector<std::string> lines = base::SplitString( file_content, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); @@ -129,6 +162,30 @@ return instance; } +AnnotationInstance TrafficAnnotationAuditorTest::CreateAnnotationInstanceSample( + AnnotationInstance::Type type, + int unique_id) { + return CreateAnnotationInstanceSample(type, unique_id, 0); +} + +AnnotationInstance TrafficAnnotationAuditorTest::CreateAnnotationInstanceSample( + AnnotationInstance::Type type, + int unique_id, + int second_id) { + AnnotationInstance instance = CreateAnnotationInstanceSample(); + instance.type = type; + instance.unique_id_hash_code = unique_id; + instance.proto.set_unique_id(base::StringPrintf("S%i", unique_id)); + if (second_id) { + instance.second_id = base::StringPrintf("S%i", second_id); + instance.second_id_hash_code = second_id; + } else { + instance.second_id.clear(); + instance.second_id_hash_code = 0; + } + return instance; +} + // Tests if the two hash computation functions have the same result. TEST_F(TrafficAnnotationAuditorTest, HashFunctionCheck) { TEST_HASH_CODE("test"); @@ -333,18 +390,19 @@ } } -// Tests if TrafficAnnotationAuditor::GetReservedUniqueIDs has all known ids and +// Tests if TrafficAnnotationAuditor::GetReservedIDsMap has all known ids and // they have correct text. -TEST_F(TrafficAnnotationAuditorTest, GetReservedUniqueIDs) { +TEST_F(TrafficAnnotationAuditorTest, GetReservedIDsCoverage) { int expected_ids[] = { TRAFFIC_ANNOTATION_FOR_TESTS.unique_id_hash_code, PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS.unique_id_hash_code, NO_TRAFFIC_ANNOTATION_YET.unique_id_hash_code, NO_PARTIAL_TRAFFIC_ANNOTATION_YET.unique_id_hash_code, - MISSING_TRAFFIC_ANNOTATION.unique_id_hash_code}; + MISSING_TRAFFIC_ANNOTATION.unique_id_hash_code, + NO_TRAFFIC_ANNOTATION_BUG_656607.unique_id_hash_code}; std::map<int, std::string> reserved_words = - TrafficAnnotationAuditor::GetReservedUniqueIDs(); + TrafficAnnotationAuditor::GetReservedIDsMap(); for (int id : expected_ids) { EXPECT_TRUE(base::ContainsKey(reserved_words, id)); @@ -353,157 +411,171 @@ } } -// Tests if TrafficAnnotationAuditor::CheckDuplicateHashes works as expected. -TEST_F(TrafficAnnotationAuditorTest, CheckDuplicateHashes) { - // Load a valid annotation. - AnnotationInstance instance = CreateAnnotationInstanceSample(); +// Tests if use of reserved ids are detected. +TEST_F(TrafficAnnotationAuditorTest, CheckReservedIDsUsageDetection) { + for (const auto& reserved_id : auditor().GetReservedIDsSet()) { + RunIDChecker(CreateAnnotationInstanceSample( + AnnotationInstance::Type::ANNOTATION_COMPLETE, reserved_id)); + EXPECT_EQ(1u, errors()->size()); + EXPECT_EQ(AuditorResult::Type::ERROR_RESERVED_ID_HASH_CODE, + (*errors())[0].type()); - const std::map<int, std::string>& reserved_words = - TrafficAnnotationAuditor::GetReservedUniqueIDs(); + RunIDChecker(CreateAnnotationInstanceSample( + AnnotationInstance::Type::ANNOTATION_PARTIAL, 1, reserved_id)); + EXPECT_EQ(1u, errors()->size()); + EXPECT_EQ(AuditorResult::Type::ERROR_RESERVED_ID_HASH_CODE, + (*errors())[0].type()); + } +} +// Tests if use of deprecated ids are detected. +TEST_F(TrafficAnnotationAuditorTest, CheckDeprecatedIDsUsageDetection) { + for (const auto& deprecated_id : kDummyDeprecatedIDs) { + RunIDChecker(CreateAnnotationInstanceSample( + AnnotationInstance::Type::ANNOTATION_COMPLETE, deprecated_id)); + EXPECT_EQ(1u, errors()->size()); + EXPECT_EQ(AuditorResult::Type::ERROR_DEPRECATED_ID_HASH_CODE, + (*errors())[0].type()); + + RunIDChecker(CreateAnnotationInstanceSample( + AnnotationInstance::Type::ANNOTATION_PARTIAL, 1, deprecated_id)); + EXPECT_EQ(1u, errors()->size()); + EXPECT_EQ(AuditorResult::Type::ERROR_DEPRECATED_ID_HASH_CODE, + (*errors())[0].type()); + } +} + +// Tests if use of repeated ids are detected. +TEST_F(TrafficAnnotationAuditorTest, CheckRepeatedIDsDetection) { std::vector<AnnotationInstance> annotations; - // Check for reserved words hash code duplication errors. - int next_id = 0; - for (const auto& reserved_word : reserved_words) { - EXPECT_FALSE(base::ContainsKey(reserved_words, next_id)); - instance.unique_id_hash_code = next_id; - instance.extra_id_hash_code = reserved_word.first; - instance.extra_id = "SomeID"; - annotations.push_back(instance); - next_id++; - - EXPECT_FALSE(base::ContainsKey(reserved_words, next_id)); - instance.unique_id_hash_code = reserved_word.first; - instance.extra_id_hash_code = next_id; - instance.extra_id.clear(); - annotations.push_back(instance); - next_id++; - } - - auditor().SetExtractedAnnotationsForTesting(annotations); - auditor().ClearErrorsForTesting(); - auditor().CheckDuplicateHashes(); - EXPECT_EQ(auditor().errors().size(), annotations.size()); - for (const auto& error : auditor().errors()) { - EXPECT_EQ(error.type(), - AuditorResult::Type::ERROR_RESERVED_UNIQUE_ID_HASH_CODE); - } - // Check if several different hash codes result in no error. - annotations.clear(); - instance.extra_id_hash_code = 0; - instance.extra_id.clear(); for (int i = 0; i < 10; i++) { - // Ensure that the test id is not a reserved hash code. - EXPECT_FALSE(base::ContainsKey(reserved_words, i)); - instance.unique_id_hash_code = i; - annotations.push_back(instance); + annotations.push_back(CreateAnnotationInstanceSample( + AnnotationInstance::Type::ANNOTATION_COMPLETE, i)); } - auditor().SetExtractedAnnotationsForTesting(annotations); - auditor().ClearErrorsForTesting(); - auditor().CheckDuplicateHashes(); - EXPECT_EQ(auditor().errors().size(), 0u); + id_checker().Load(annotations); + errors()->clear(); + id_checker().CheckIDs(errors()); + EXPECT_EQ(0u, errors()->size()); // Check if repeating the same hash codes results in errors. annotations.clear(); for (int i = 0; i < 10; i++) { - instance.unique_id_hash_code = i; - annotations.push_back(instance); - annotations.push_back(instance); + annotations.push_back(CreateAnnotationInstanceSample( + AnnotationInstance::Type::ANNOTATION_COMPLETE, i)); + annotations.push_back(annotations.back()); } - auditor().SetExtractedAnnotationsForTesting(annotations); - auditor().ClearErrorsForTesting(); - auditor().CheckDuplicateHashes(); - EXPECT_EQ(auditor().errors().size(), 10u); - for (const auto& error : auditor().errors()) { - EXPECT_EQ(error.type(), - AuditorResult::Type::ERROR_DUPLICATE_UNIQUE_ID_HASH_CODE); + id_checker().Load(annotations); + errors()->clear(); + id_checker().CheckIDs(errors()); + EXPECT_EQ(10u, errors()->size()); + for (const auto& error : *errors()) { + EXPECT_EQ(error.type(), AuditorResult::Type::ERROR_REPEATED_ID); } +} - // Check if the same value for unique id and extra id only results in error in - // types with valid extra id. - instance.unique_id_hash_code = 1; - instance.extra_id_hash_code = 1; +// Tests if having the same unique id and second id is detected. +TEST_F(TrafficAnnotationAuditorTest, CheckSimilarUniqueAndSecondIDsDetection) { const int last_type = static_cast<int>(AnnotationInstance::Type::ANNOTATION_INSTANCE_TYPE_LAST); for (int type = 0; type <= last_type; type++) { - instance.type = static_cast<AnnotationInstance::Type>(type); - SetAnnotationForTesting(instance); - auditor().CheckDuplicateHashes(); - SCOPED_TRACE(type); - if (instance.type == AnnotationInstance::Type::ANNOTATION_COMPLETE || - instance.type == AnnotationInstance::Type::ANNOTATION_COMPLETING) { - // Extra id of these two types is not used. - EXPECT_EQ(auditor().errors().size(), 0u); - } else { - EXPECT_EQ(auditor().errors().size(), 1u); - } + AnnotationInstance instance = CreateAnnotationInstanceSample( + static_cast<AnnotationInstance::Type>(type), 1, 1); + RunIDChecker(instance); + EXPECT_EQ(instance.NeedsTwoIDs() ? 1u : 0u, errors()->size()) << type; } +} - // Check for unique id / extra id collision cases. - AnnotationInstance other = instance; +// Tests Unique id and Second id collision cases. +TEST_F(TrafficAnnotationAuditorTest, CheckDuplicateIDsDetection) { + const int last_type = + static_cast<int>(AnnotationInstance::Type::ANNOTATION_INSTANCE_TYPE_LAST); + for (int type1 = 0; type1 < last_type; type1++) { for (int type2 = type1; type2 <= last_type; type2++) { - // Iterate different possiblities of common id. - for (int common1 = 0; common1 < 2; common1++) { - for (int common2 = 0; common2 < 2; common2++) { - instance.type = static_cast<AnnotationInstance::Type>(type1); - other.type = static_cast<AnnotationInstance::Type>(type2); - instance.unique_id_hash_code = common1 ? 1 : 2; - instance.extra_id_hash_code = common1 ? 2 : 1; - other.unique_id_hash_code = common2 ? 2 : 3; - other.extra_id_hash_code = common2 ? 3 : 2; + for (int id1 = 1; id1 < 5; id1++) { + for (int id2 = 1; id2 < 5; id2++) { + for (int id3 = 1; id3 < 5; id3++) { + for (int id4 = 1; id4 < 5; id4++) { + SCOPED_TRACE( + base::StringPrintf("Testing (%i, %i, %i, %i, %i, %i).", type1, + type2, id1, id2, id3, id4)); - annotations.clear(); - annotations.push_back(instance); - annotations.push_back(other); - auditor().SetExtractedAnnotationsForTesting(annotations); - auditor().ClearErrorsForTesting(); - auditor().CheckDuplicateHashes(); + AnnotationInstance instance1 = CreateAnnotationInstanceSample( + static_cast<AnnotationInstance::Type>(type1), id1, id2); + AnnotationInstance instance2 = CreateAnnotationInstanceSample( + static_cast<AnnotationInstance::Type>(type2), id3, id4); + std::vector<AnnotationInstance> annotations; + annotations.push_back(instance1); + annotations.push_back(instance2); + id_checker().Load(annotations); + errors()->clear(); + id_checker().CheckIDs(errors()); - bool acceptable = false; - switch (instance.type) { - case AnnotationInstance::Type::ANNOTATION_COMPLETE: - // The unique id of a complete annotation must not be reused. - acceptable = - (instance.unique_id_hash_code != other.unique_id_hash_code && - instance.unique_id_hash_code != other.extra_id_hash_code); - break; + std::set<int> unique_ids; + bool first_needs_two = instance1.NeedsTwoIDs(); + bool second_needs_two = instance2.NeedsTwoIDs(); + unique_ids.insert(id1); + if (first_needs_two) + unique_ids.insert(id2); + unique_ids.insert(id3); + if (second_needs_two) + unique_ids.insert(id4); - case AnnotationInstance::Type::ANNOTATION_PARTIAL: - // The unique id of a partial annotation should be unique. - // It's extra id can be used as unique id of a completing - // annotation or extra id of a branched completing one. - if (instance.unique_id_hash_code != other.unique_id_hash_code && - instance.unique_id_hash_code != other.extra_id_hash_code) { - if (instance.extra_id_hash_code == other.unique_id_hash_code) { - acceptable = - (other.type == - AnnotationInstance::Type::ANNOTATION_COMPLETING); - } else if (instance.extra_id_hash_code == - other.extra_id_hash_code) { - acceptable = - (other.type == AnnotationInstance::Type:: - ANNOTATION_BRANCHED_COMPLETING); + if (first_needs_two && second_needs_two) { + // If both need two ids, either the 4 ids should be different, + // or the second ids should be equal and both annotations should + // be of types partial or branched completing. + if (unique_ids.size() == 4) { + EXPECT_TRUE(errors()->empty()); + } else if (unique_ids.size() == 3) { + bool acceptable = + (id2 == id4) && + (type1 == + static_cast<int>( + AnnotationInstance::Type::ANNOTATION_PARTIAL) || + type1 == static_cast<int>( + AnnotationInstance::Type:: + ANNOTATION_BRANCHED_COMPLETING)) && + (type2 == + static_cast<int>( + AnnotationInstance::Type::ANNOTATION_PARTIAL) || + type2 == static_cast<int>( + AnnotationInstance::Type:: + ANNOTATION_BRANCHED_COMPLETING)); + + EXPECT_EQ(acceptable, errors()->empty()); } else { - acceptable = true; + EXPECT_FALSE(errors()->empty()); + } + } else if (first_needs_two && !second_needs_two) { + // If just the first one needs two ids, then either the 3 ids + // should be different or the first annotation would be partial + // and the second completing, with one common id. + if (unique_ids.size() == 3) { + EXPECT_TRUE(errors()->empty()); + } else if (unique_ids.size() == 2) { + bool acceptable = + (id2 == id3) && + (type1 == + static_cast<int>( + AnnotationInstance::Type::ANNOTATION_PARTIAL) && + type2 == static_cast<int>(AnnotationInstance::Type:: + ANNOTATION_COMPLETING)); + EXPECT_EQ(errors()->empty(), acceptable); + } else { + EXPECT_FALSE(errors()->empty()); + } + } else if (!first_needs_two && second_needs_two) { + // Can only be valid if all 3 are different. + EXPECT_EQ(unique_ids.size() == 3, errors()->empty()); + } else { + // If none requires two ids, it can only be valid if ids are + // different. + EXPECT_EQ(unique_ids.size() == 2, errors()->empty()); } } - break; - - case AnnotationInstance::Type::ANNOTATION_COMPLETING: - case AnnotationInstance::Type::ANNOTATION_INSTANCE_TYPE_LAST: - // Considering the other annotation has a higher type number, - // unique id of a completing or branched completing annotation - // should not be used as unique or extra id of another one. - acceptable = - (instance.unique_id_hash_code != other.unique_id_hash_code && - instance.unique_id_hash_code != other.extra_id_hash_code); - break; - - default: - NOTREACHED(); } } } @@ -511,46 +583,49 @@ } } -// Tests if TrafficAnnotationAuditor::CheckUniqueIDsFormat results are as -// expected. -TEST_F(TrafficAnnotationAuditorTest, CheckUniqueIDsFormat) { +// Tests if IDs format is correctly checked. +TEST_F(TrafficAnnotationAuditorTest, CheckIDsFormat) { std::map<std::string, bool> test_cases = { {"ID1", true}, {"id2", true}, {"Id_3", true}, {"ID?4", false}, {"ID:5", false}, {"ID>>6", false}, }; - std::vector<AnnotationInstance> annotations; AnnotationInstance instance = CreateAnnotationInstanceSample(); - unsigned int false_samples_count = 0; - - // Test cases one by one. for (const auto& test_case : test_cases) { + // Set type to complete to require just unique id. instance.type = AnnotationInstance::Type::ANNOTATION_COMPLETE; instance.proto.set_unique_id(test_case.first); - instance.extra_id.clear(); - SetAnnotationForTesting(instance); - annotations.push_back(instance); - auditor().CheckUniqueIDsFormat(); - EXPECT_EQ(auditor().errors().size(), test_case.second ? 0u : 1u); - if (!test_case.second) - false_samples_count++; + instance.unique_id_hash_code = 1; + RunIDChecker(instance); + EXPECT_EQ(test_case.second ? 0u : 1u, errors()->size()) << test_case.first; - instance.type = AnnotationInstance::Type::ANNOTATION_COMPLETING; + // Set type to partial to require both ids. + instance.type = AnnotationInstance::Type::ANNOTATION_PARTIAL; instance.proto.set_unique_id("Something_Good"); - instance.extra_id = test_case.first; - SetAnnotationForTesting(instance); - annotations.push_back(instance); - auditor().CheckUniqueIDsFormat(); - EXPECT_EQ(auditor().errors().size(), test_case.second ? 0u : 1u); - if (!test_case.second) - false_samples_count++; + instance.second_id = test_case.first; + instance.unique_id_hash_code = 1; + instance.second_id_hash_code = 2; + RunIDChecker(instance); + EXPECT_EQ(test_case.second ? 0u : 1u, errors()->size()) << test_case.first; } // Test all cases together. - auditor().SetExtractedAnnotationsForTesting(annotations); - auditor().ClearErrorsForTesting(); - auditor().CheckUniqueIDsFormat(); - EXPECT_EQ(auditor().errors().size(), false_samples_count); + std::vector<AnnotationInstance> annotations; + instance.type = AnnotationInstance::Type::ANNOTATION_COMPLETE; + instance.unique_id_hash_code = 1; + + unsigned int false_samples_count = 0; + for (const auto& test_case : test_cases) { + instance.proto.set_unique_id(test_case.first); + instance.unique_id_hash_code++; + annotations.push_back(instance); + if (!test_case.second) + false_samples_count++; + } + id_checker().Load(annotations); + errors()->clear(); + id_checker().CheckIDs(errors()); + EXPECT_EQ(false_samples_count, errors()->size()); } // Tests if TrafficAnnotationAuditor::CheckAllRequiredFunctionsAreAnnotated @@ -748,52 +823,43 @@ } // Check All. - unsigned int tests_count = annotations.size(); auditor().SetExtractedAnnotationsForTesting(annotations); auditor().ClearErrorsForTesting(); auditor().CheckAnnotationsContents(); EXPECT_EQ(auditor().errors().size(), expected_errors_count); - // All annotations with errors should be purged. - EXPECT_EQ(auditor().extracted_annotations().size(), - tests_count - expected_errors_count); } // Tests if AnnotationInstance::IsCompletableWith works as expected. TEST_F(TrafficAnnotationAuditorTest, IsCompletableWith) { - AnnotationInstance instance = CreateAnnotationInstanceSample(); - AnnotationInstance other = instance; - const int last_type = static_cast<int>(AnnotationInstance::Type::ANNOTATION_INSTANCE_TYPE_LAST); for (int type1 = 0; type1 < last_type; type1++) { for (int type2 = 0; type2 <= last_type; type2++) { // Iterate all combination of common/specified ids. for (int ids = 0; ids < 256; ids++) { - instance.type = static_cast<AnnotationInstance::Type>(type1); - other.type = static_cast<AnnotationInstance::Type>(type2); - instance.unique_id_hash_code = ids % 4; - instance.extra_id_hash_code = (ids >> 2) % 4; - other.unique_id_hash_code = (ids >> 4) % 4; - other.extra_id_hash_code = (ids >> 6); - instance.extra_id = - instance.extra_id_hash_code ? "SomeID" : std::string(); - other.extra_id = other.extra_id_hash_code ? "SomeID" : std::string(); + AnnotationInstance instance1 = CreateAnnotationInstanceSample( + static_cast<AnnotationInstance::Type>(type1), ids % 4, + (ids >> 2) % 4); + AnnotationInstance instance2 = CreateAnnotationInstanceSample( + static_cast<AnnotationInstance::Type>(type2), (ids >> 4) % 4, + (ids >> 6)); bool expectation = false; - // It's compatible only if the first one is partial and has extra_id, + // It's compatible only if the first one is partial and has second_id, // and the second one is either completing with matching unique id, or - // branched completing with matching extra id. - if (instance.type == AnnotationInstance::Type::ANNOTATION_PARTIAL && - !instance.extra_id.empty()) { + // branched completing with matching second id. + if (instance1.type == AnnotationInstance::Type::ANNOTATION_PARTIAL && + !instance1.second_id.empty()) { expectation |= - (other.type == AnnotationInstance::Type::ANNOTATION_COMPLETING && - instance.extra_id_hash_code == other.unique_id_hash_code); + (instance2.type == + AnnotationInstance::Type::ANNOTATION_COMPLETING && + instance1.second_id_hash_code == instance2.unique_id_hash_code); expectation |= - (other.type == + (instance2.type == AnnotationInstance::Type::ANNOTATION_BRANCHED_COMPLETING && - instance.extra_id_hash_code == other.extra_id_hash_code); + instance1.second_id_hash_code == instance2.second_id_hash_code); } - EXPECT_EQ(instance.IsCompletableWith(other), expectation); + EXPECT_EQ(instance1.IsCompletableWith(instance2), expectation); } } } @@ -813,8 +879,8 @@ // Partial and Completing. instance.type = AnnotationInstance::Type::ANNOTATION_PARTIAL; other.type = AnnotationInstance::Type::ANNOTATION_COMPLETING; - instance.extra_id_hash_code = 1; - instance.extra_id = "SomeID"; + instance.second_id_hash_code = 1; + instance.second_id = "SomeID"; other.unique_id_hash_code = 1; EXPECT_EQ(instance.CreateCompleteAnnotation(other, &combination).type(), AuditorResult::Type::RESULT_OK); @@ -822,9 +888,9 @@ // Partial and Branched Completing. other.type = AnnotationInstance::Type::ANNOTATION_BRANCHED_COMPLETING; - instance.extra_id_hash_code = 1; - other.extra_id_hash_code = 1; - other.extra_id = "SomeID"; + instance.second_id_hash_code = 1; + other.second_id_hash_code = 1; + other.second_id = "SomeID"; EXPECT_EQ(instance.CreateCompleteAnnotation(other, &combination).type(), AuditorResult::Type::RESULT_OK); EXPECT_EQ(combination.unique_id_hash_code, other.unique_id_hash_code); @@ -832,9 +898,9 @@ // Inconsistent field. other = instance; other.type = AnnotationInstance::Type::ANNOTATION_BRANCHED_COMPLETING; - instance.extra_id_hash_code = 1; - other.extra_id_hash_code = 1; - other.extra_id = "SomeID"; + instance.second_id_hash_code = 1; + other.second_id_hash_code = 1; + other.second_id = "SomeID"; instance.proto.mutable_semantics()->set_destination( traffic_annotation:: NetworkTrafficAnnotation_TrafficSemantics_Destination_WEBSITE); @@ -850,7 +916,7 @@ TrafficAnnotationExporter exporter(source_path()); EXPECT_TRUE(exporter.LoadAnnotationsXML()); - EXPECT_TRUE(exporter.CheckReportItems()); + EXPECT_TRUE(exporter.CheckArchivedAnnotations()); } // Tests if downstream files depending on of Annotations.xml are updated. @@ -873,4 +939,57 @@ TEST_F(TrafficAnnotationAuditorTest, GetClangLibraryPath) { base::FilePath clang_library = auditor().GetClangLibraryPath(); EXPECT_FALSE(clang_library.empty()); -} \ No newline at end of file +} + +// Tests if 'annotations.xml' is read and has at least one item. +TEST_F(TrafficAnnotationAuditorTest, AnnotationsXMLLines) { + TrafficAnnotationExporter exporter(source_path()); + EXPECT_LE(1u, exporter.GetXMLItemsCountForTesting()); +} + +// Tests if 'annotations.xml' changes are correctly reported. +TEST_F(TrafficAnnotationAuditorTest, AnnotationsXMLDifferences) { + TrafficAnnotationExporter exporter(source_path()); + + std::string xml1; + std::string xml2; + std::string xml3; + + EXPECT_TRUE(base::ReadFileToString( + base::MakeAbsoluteFilePath( + tests_folder().Append(FILE_PATH_LITERAL("annotations_sample1.xml"))), + &xml1)); + EXPECT_TRUE(base::ReadFileToString( + base::MakeAbsoluteFilePath( + tests_folder().Append(FILE_PATH_LITERAL("annotations_sample2.xml"))), + &xml2)); + EXPECT_TRUE(base::ReadFileToString( + base::MakeAbsoluteFilePath( + tests_folder().Append(FILE_PATH_LITERAL("annotations_sample3.xml"))), + &xml3)); + + std::string diff12 = exporter.GetXMLDifferencesForTesting(xml1, xml2); + std::string diff13 = exporter.GetXMLDifferencesForTesting(xml1, xml3); + std::string diff23 = exporter.GetXMLDifferencesForTesting(xml2, xml3); + + std::string expected_diff12; + std::string expected_diff13; + std::string expected_diff23; + + EXPECT_TRUE(base::ReadFileToString( + base::MakeAbsoluteFilePath( + tests_folder().Append(FILE_PATH_LITERAL("annotations_diff12.txt"))), + &expected_diff12)); + EXPECT_TRUE(base::ReadFileToString( + base::MakeAbsoluteFilePath( + tests_folder().Append(FILE_PATH_LITERAL("annotations_diff13.txt"))), + &expected_diff13)); + EXPECT_TRUE(base::ReadFileToString( + base::MakeAbsoluteFilePath( + tests_folder().Append(FILE_PATH_LITERAL("annotations_diff23.txt"))), + &expected_diff23)); + + EXPECT_EQ(diff12, expected_diff12); + EXPECT_EQ(diff13, expected_diff13); + EXPECT_EQ(diff23, expected_diff23); +}
diff --git a/tools/traffic_annotation/auditor/traffic_annotation_exporter.cc b/tools/traffic_annotation/auditor/traffic_annotation_exporter.cc index ddb13fa..d47a101 100644 --- a/tools/traffic_annotation/auditor/traffic_annotation_exporter.cc +++ b/tools/traffic_annotation/auditor/traffic_annotation_exporter.cc
@@ -7,7 +7,6 @@ #include <ctime> #include "base/files/file_util.h" -#include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" #include "base/strings/stringprintf.h" @@ -27,31 +26,72 @@ "\nRefer to README.md for content description and update process.\n" "-->\n\n"; -const base::FilePath kAnnotationsXmlPath( - FILE_PATH_LITERAL("tools/traffic_annotation/summary/annotations.xml")); +const base::FilePath kAnnotationsXmlPath = + base::FilePath(FILE_PATH_LITERAL("tools")) + .Append(FILE_PATH_LITERAL("traffic_annotation")) + .Append(FILE_PATH_LITERAL("summary")) + .Append(FILE_PATH_LITERAL("annotations.xml")); + +// Extracts annotation id from a line of XML. Expects to have the line in the +// following format: <... id="..." .../> +// TODO(rhalavati): Use real XML parsing. +std::string GetAnnotationID(const std::string& xml_line) { + std::string::size_type start = xml_line.find("id=\""); + if (start == std::string::npos) + return ""; + + start += 4; + std::string::size_type end = xml_line.find("\"", start); + if (end == std::string::npos) + return ""; + + return xml_line.substr(start, end - start); +} + +// Extracts a map of XML items, keyed by their 'id' tags, from a serialized XML. +void ExtractXMLItems(const std::string& serialized_xml, + std::map<std::string, std::string>* items) { + std::vector<std::string> lines = base::SplitString( + serialized_xml, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); + for (const std::string& line : lines) { + std::string id = GetAnnotationID(line); + if (!id.empty()) + items->insert(std::make_pair(id, line)); + } +} } // namespace -TrafficAnnotationExporter::ReportItem::ReportItem() - : unique_id_hash_code(-1), content_hash_code(-1) {} +TrafficAnnotationExporter::ArchivedAnnotation::ArchivedAnnotation() + : type(AnnotationInstance::Type::ANNOTATION_COMPLETE), + unique_id_hash_code(-1), + second_id_hash_code(-1), + content_hash_code(-1) {} -TrafficAnnotationExporter::ReportItem::ReportItem( - const TrafficAnnotationExporter::ReportItem& other) - : unique_id_hash_code(other.unique_id_hash_code), - deprecation_date(other.deprecation_date), - content_hash_code(other.content_hash_code), - os_list(other.os_list) {} +TrafficAnnotationExporter::ArchivedAnnotation::ArchivedAnnotation( + const TrafficAnnotationExporter::ArchivedAnnotation& other) = default; -TrafficAnnotationExporter::ReportItem::~ReportItem() {} +TrafficAnnotationExporter::ArchivedAnnotation::~ArchivedAnnotation() = default; TrafficAnnotationExporter::TrafficAnnotationExporter( const base::FilePath& source_path) - : source_path_(source_path), modified_(false) {} + : source_path_(source_path), modified_(false) { + all_supported_platforms_.push_back("linux"); + all_supported_platforms_.push_back("windows"); +#if defined(OS_LINUX) + current_platform_ = "linux"; +#elif defined(OS_WIN) + current_platform_ = "windows"; +#else + NOTREACHED() << "Other platforms are not supported yet."; + current_platform_ = "undefined"; +#endif +} -TrafficAnnotationExporter::~TrafficAnnotationExporter() {} +TrafficAnnotationExporter::~TrafficAnnotationExporter() = default; bool TrafficAnnotationExporter::LoadAnnotationsXML() { - report_items_.clear(); + archive_.clear(); XmlReader reader; if (!reader.LoadFile( source_path_.Append(kAnnotationsXmlPath).MaybeAsASCII())) { @@ -67,31 +107,59 @@ if (reader.NodeName() != "item") continue; - ReportItem item; - std::string temp; + ArchivedAnnotation item; + std::string temp_str; + int temp_int = 0; std::string unique_id; all_ok &= reader.NodeAttribute("id", &unique_id); - all_ok &= reader.NodeAttribute("hash_code", &temp) && - base::StringToInt(temp, &item.unique_id_hash_code); - if (all_ok && reader.NodeAttribute("content_hash_code", &temp)) - all_ok &= base::StringToInt(temp, &item.content_hash_code); + all_ok &= reader.NodeAttribute("hash_code", &temp_str) && + base::StringToInt(temp_str, &item.unique_id_hash_code); + all_ok &= reader.NodeAttribute("type", &temp_str) && + base::StringToInt(temp_str, &temp_int); + item.type = static_cast<AnnotationInstance::Type>(temp_int); + + if (reader.NodeAttribute("second_id", &temp_str)) + all_ok &= base::StringToInt(temp_str, &item.second_id_hash_code); + + if (all_ok && reader.NodeAttribute("content_hash_code", &temp_str)) + all_ok &= base::StringToInt(temp_str, &item.content_hash_code); else item.content_hash_code = -1; reader.NodeAttribute("deprecated", &item.deprecation_date); - if (reader.NodeAttribute("os_list", &temp)) { - item.os_list = base::SplitString(temp, ",", base::TRIM_WHITESPACE, + if (reader.NodeAttribute("os_list", &temp_str)) { + item.os_list = base::SplitString(temp_str, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); } + if (reader.NodeAttribute("semantics_fields", &temp_str)) { + std::vector<std::string> temp_list = base::SplitString( + temp_str, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); + for (std::string field : temp_list) { + base::StringToInt(field, &temp_int); + item.semantics_fields.insert(temp_int); + } + } + + if (reader.NodeAttribute("policy_fields", &temp_str)) { + std::vector<std::string> temp_list = base::SplitString( + temp_str, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); + for (std::string field : temp_list) { + base::StringToInt(field, &temp_int); + item.policy_fields.insert(temp_int); + } + } + + all_ok &= reader.NodeAttribute("file_path", &item.file_path); + if (!all_ok) { LOG(ERROR) << "Unexpected format in annotations.xml."; break; } - report_items_.insert(std::make_pair(unique_id, item)); + archive_.insert(std::make_pair(unique_id, item)); } modified_ = false; @@ -101,95 +169,166 @@ bool TrafficAnnotationExporter::UpdateAnnotations( const std::vector<AnnotationInstance>& annotations, const std::map<int, std::string>& reserved_ids) { - std::string platform; -#if defined(OS_LINUX) - platform = "linux"; -#elif defined(OS_WIN) - platform = "windows"; -#else - NOTREACHED() << "Other platforms are not supported yet."; -#endif - - if (report_items_.empty() && !LoadAnnotationsXML()) + if (archive_.empty() && !LoadAnnotationsXML()) return false; - // Iterate current annotations and add/update. - for (AnnotationInstance annotation : annotations) { - // Source tag is not used in computing the hashcode, as we don't need - // sensitivity to changes in source location (filepath, line number, - // and function). - std::string content; - annotation.proto.clear_source(); - google::protobuf::TextFormat::PrintToString(annotation.proto, &content); - int content_hash_code = TrafficAnnotationAuditor::ComputeHashValue(content); + std::set<int> current_platform_hashcodes; - if (base::ContainsKey(report_items_, annotation.proto.unique_id())) { - ReportItem* current = &report_items_[annotation.proto.unique_id()]; - if (!base::ContainsValue(current->os_list, platform)) { - current->os_list.push_back(platform); + // Iterate annotations extracted from the code, and add/update them in the + // reported list, if required. + for (AnnotationInstance annotation : annotations) { + // Annotations.XML only stores raw annotations. + if (annotation.is_merged) + continue; + + int content_hash_code = annotation.GetContentHashCode(); + // If annotation unique id is already in the imported annotations list, + // check if other fields have changed. + if (base::ContainsKey(archive_, annotation.proto.unique_id())) { + ArchivedAnnotation* current = &archive_[annotation.proto.unique_id()]; + + // Check second id. + if (current->second_id_hash_code != + archive_[annotation.proto.unique_id()].second_id_hash_code) { + archive_[annotation.proto.unique_id()].second_id_hash_code = + current->second_id_hash_code; + modified_ = true; + } + + // Check platform. + if (!base::ContainsValue(current->os_list, current_platform_)) { + current->os_list.push_back(current_platform_); + modified_ = true; + } + + // Check content (including policy and semnantic fields). + if (current->content_hash_code != content_hash_code) { + current->content_hash_code = content_hash_code; + modified_ = true; + } + + // Check file path. + if (current->file_path != annotation.proto.source().file()) { + current->file_path = annotation.proto.source().file(); modified_ = true; } } else { - ReportItem new_item; + // If annotation is new, add it and assume it is on all platforms. Tests + // running on other platforms will request updating this if required. + ArchivedAnnotation new_item; + new_item.type = annotation.type; new_item.unique_id_hash_code = annotation.unique_id_hash_code; + if (annotation.NeedsTwoIDs()) + new_item.second_id_hash_code = annotation.second_id_hash_code; new_item.content_hash_code = content_hash_code; - new_item.os_list.push_back(platform); - report_items_[annotation.proto.unique_id()] = new_item; + new_item.os_list = all_supported_platforms_; + if (annotation.type != AnnotationInstance::Type::ANNOTATION_COMPLETE) { + annotation.GetSemanticsFieldNumbers(&new_item.semantics_fields); + annotation.GetPolicyFieldNumbers(&new_item.policy_fields); + } + new_item.file_path = annotation.proto.source().file(); + archive_[annotation.proto.unique_id()] = new_item; + modified_ = true; + } + current_platform_hashcodes.insert(annotation.unique_id_hash_code); + } + + // If a none-reserved annotation is removed from current platform, update it. + for (auto& item : archive_) { + if (base::ContainsValue(item.second.os_list, current_platform_) && + item.second.content_hash_code != -1 && + !base::ContainsKey(current_platform_hashcodes, + item.second.unique_id_hash_code)) { + base::Erase(item.second.os_list, current_platform_); modified_ = true; } } // If there is a new reserved id, add it. for (const auto& item : reserved_ids) { - if (!base::ContainsKey(report_items_, item.second)) { - ReportItem new_item; + if (!base::ContainsKey(archive_, item.second)) { + ArchivedAnnotation new_item; new_item.unique_id_hash_code = item.first; - new_item.os_list.push_back("all"); - report_items_[item.second] = new_item; + new_item.os_list = all_supported_platforms_; + archive_[item.second] = new_item; modified_ = true; } } // If there are annotations that are not used in any OS, set the deprecation // flag. - for (auto& item : report_items_) { + for (auto& item : archive_) { if (item.second.os_list.empty() && item.second.deprecation_date.empty()) { base::Time::Exploded now; base::Time::Now().UTCExplode(&now); item.second.deprecation_date = base::StringPrintf( "%i-%02i-%02i", now.year, now.month, now.day_of_month); + item.second.file_path = ""; + item.second.semantics_fields.clear(); + item.second.policy_fields.clear(); modified_ = true; } } - return CheckReportItems(); + return CheckArchivedAnnotations(); } -bool TrafficAnnotationExporter::SaveAnnotationsXML() { +std::string TrafficAnnotationExporter::GenerateSerializedXML() const { XmlWriter writer; writer.StartWriting(); writer.StartElement("annotations"); - for (const auto& item : report_items_) { + for (const auto& item : archive_) { writer.StartElement("item"); writer.AddAttribute("id", item.first); writer.AddAttribute( "hash_code", base::StringPrintf("%i", item.second.unique_id_hash_code)); + writer.AddAttribute("type", base::StringPrintf("%i", item.second.type)); + + if (item.second.second_id_hash_code != -1) + writer.AddAttribute( + "second_id", + base::StringPrintf("%i", item.second.second_id_hash_code)); + if (!item.second.deprecation_date.empty()) writer.AddAttribute("deprecated", item.second.deprecation_date); + if (item.second.content_hash_code == -1) writer.AddAttribute("reserved", "1"); else writer.AddAttribute( "content_hash_code", base::StringPrintf("%i", item.second.content_hash_code)); - std::string os_list; - for (const std::string& platform : item.second.os_list) - os_list += platform + ","; - if (!os_list.empty()) { - os_list.pop_back(); - writer.AddAttribute("os_list", os_list); + + // Write OS list. + if (!item.second.os_list.empty()) { + std::string text; + for (const std::string& platform : item.second.os_list) + text += platform + ","; + text.pop_back(); + writer.AddAttribute("os_list", text); } + + // Write semantics list (for incomplete annotations). + if (!item.second.semantics_fields.empty()) { + std::string text; + for (int field : item.second.semantics_fields) + text += base::StringPrintf("%i,", field); + text.pop_back(); + writer.AddAttribute("semantics_fields", text); + } + + // Write policy list (for incomplete annotations). + if (!item.second.policy_fields.empty()) { + std::string text; + for (int field : item.second.policy_fields) + text += base::StringPrintf("%i,", field); + text.pop_back(); + writer.AddAttribute("policy_fields", text); + } + + writer.AddAttribute("file_path", item.second.file_path); + writer.EndElement(); } writer.EndElement(); @@ -199,27 +338,33 @@ // Add comment before annotation tag (and after xml version). xml_content.insert(xml_content.find("<annotations>"), kXmlComment); + return xml_content; +} + +bool TrafficAnnotationExporter::SaveAnnotationsXML() const { + std::string xml_content = GenerateSerializedXML(); + return base::WriteFile(source_path_.Append(kAnnotationsXmlPath), xml_content.c_str(), xml_content.length()) != -1; } bool TrafficAnnotationExporter::GetDeprecatedHashCodes( std::set<int>* hash_codes) { - if (report_items_.empty() && !LoadAnnotationsXML()) + if (archive_.empty() && !LoadAnnotationsXML()) return false; hash_codes->clear(); - for (const auto& item : report_items_) { + for (const auto& item : archive_) { if (!item.second.deprecation_date.empty()) hash_codes->insert(item.second.unique_id_hash_code); } return true; } -bool TrafficAnnotationExporter::CheckReportItems() { +bool TrafficAnnotationExporter::CheckArchivedAnnotations() { // Check for annotation hash code duplications. std::set<int> used_codes; - for (auto& item : report_items_) { + for (auto& item : archive_) { if (base::ContainsKey(used_codes, item.second.unique_id_hash_code)) { LOG(ERROR) << "Unique id hash code " << item.second.unique_id_hash_code << " is used more than once."; @@ -230,7 +375,7 @@ } // Check for coexistence of OS(es) and deprecation date. - for (auto& item : report_items_) { + for (auto& item : archive_) { if (!item.second.deprecation_date.empty() && !item.second.os_list.empty()) { LOG(ERROR) << "Annotation " << item.first << " has a deprecation date and at least one active OS."; @@ -238,4 +383,92 @@ } } return true; +} + +unsigned TrafficAnnotationExporter::GetXMLItemsCountForTesting() { + std::string xml_content; + if (!base::ReadFileToString( + base::MakeAbsoluteFilePath(source_path_.Append(kAnnotationsXmlPath)), + &xml_content)) { + LOG(ERROR) << "Could not read 'annotations.xml'."; + return 0; + } + + std::map<std::string, std::string> lines; + ExtractXMLItems(xml_content, &lines); + return lines.size(); +} + +std::string TrafficAnnotationExporter::GetRequiredUpdates() { + std::string old_xml; + if (!base::ReadFileToString( + base::MakeAbsoluteFilePath(source_path_.Append(kAnnotationsXmlPath)), + &old_xml)) { + return "Could not generate required changes."; + } + + return GetXMLDifferences(old_xml, GenerateSerializedXML()); +} + +std::string TrafficAnnotationExporter::GetXMLDifferences( + const std::string& old_xml, + const std::string& new_xml) { + std::map<std::string, std::string> old_items; + ExtractXMLItems(old_xml, &old_items); + std::set<std::string> old_keys; + std::transform(old_items.begin(), old_items.end(), + std::inserter(old_keys, old_keys.end()), + [](auto pair) { return pair.first; }); + + std::map<std::string, std::string> new_items; + ExtractXMLItems(new_xml, &new_items); + std::set<std::string> new_keys; + std::transform(new_items.begin(), new_items.end(), + std::inserter(new_keys, new_keys.end()), + [](auto pair) { return pair.first; }); + + std::set<std::string> added_items; + std::set<std::string> removed_items; + + std::set_difference(new_keys.begin(), new_keys.end(), old_keys.begin(), + old_keys.end(), + std::inserter(added_items, added_items.begin())); + std::set_difference(old_keys.begin(), old_keys.end(), new_keys.begin(), + new_keys.end(), + std::inserter(removed_items, removed_items.begin())); + + std::string message; + + for (const std::string& id : added_items) { + message += base::StringPrintf("\n\tAdd line: '%s'", new_items[id].c_str()); + } + + for (const std::string& id : removed_items) { + message += + base::StringPrintf("\n\tRemove line: '%s'", old_items[id].c_str()); + } + + for (const std::string& id : old_keys) { + if (base::ContainsKey(new_items, id) && old_items[id] != new_items[id]) { + message += + base::StringPrintf("\n\tUpdate line: '%s' --> '%s'", + old_items[id].c_str(), new_items[id].c_str()); + } + } + + return message; +} + +bool TrafficAnnotationExporter::GetOtherPlatformsAnnotationIDs( + std::vector<std::string>* ids) const { + if (archive_.empty()) + return false; + + ids->clear(); + for (const std::pair<std::string, ArchivedAnnotation>& item : archive_) { + if (item.second.deprecation_date.empty() && + !MatchesCurrentPlatform(item.second)) + ids->push_back(item.first); + } + return true; } \ No newline at end of file
diff --git a/tools/traffic_annotation/auditor/traffic_annotation_exporter.h b/tools/traffic_annotation/auditor/traffic_annotation_exporter.h index 6717cf9..1ba6f29e 100644 --- a/tools/traffic_annotation/auditor/traffic_annotation_exporter.h +++ b/tools/traffic_annotation/auditor/traffic_annotation_exporter.h
@@ -10,49 +10,92 @@ #include <vector> #include "base/files/file_path.h" +#include "base/stl_util.h" #include "tools/traffic_annotation/auditor/instance.h" class TrafficAnnotationExporter { public: + struct ArchivedAnnotation { + ArchivedAnnotation(); + ArchivedAnnotation(const ArchivedAnnotation& other); + ~ArchivedAnnotation(); + + AnnotationInstance::Type type; + + int unique_id_hash_code; + int second_id_hash_code; + int content_hash_code; + + std::string deprecation_date; + std::vector<std::string> os_list; + + std::set<int> semantics_fields; + std::set<int> policy_fields; + std::string file_path; + }; + TrafficAnnotationExporter(const base::FilePath& source_path); ~TrafficAnnotationExporter(); TrafficAnnotationExporter(const TrafficAnnotationExporter&) = delete; TrafficAnnotationExporter(TrafficAnnotationExporter&&) = delete; - // Loads annotations from annotations.xml file into |report_items_|. + // Loads annotations from annotations.xml file into |archive_|. bool LoadAnnotationsXML(); - // Updates |report_items_| with current set of extracted annotations and + // Updates |archive_| with current set of extracted annotations and // reserved ids. Sets the |modified_| flag if any item is updated. bool UpdateAnnotations(const std::vector<AnnotationInstance>& annotations, const std::map<int, std::string>& reserved_ids); - // Saves |report_items_| into annotations.xml. - bool SaveAnnotationsXML(); + // Saves |archive_| into annotations.xml. + bool SaveAnnotationsXML() const; + + // Returns the required updates for annotations.xml. + std::string GetRequiredUpdates(); // Produces the list of deprecated hash codes. Returns false if - // annotations.xml is not and cannot be loaded. + // annotations.xml is not loaded and cannot be loaded. bool GetDeprecatedHashCodes(std::set<int>* hash_codes); - bool modified() { return modified_; } + bool modified() const { return modified_; } - // Runs tests on content of |report_items_|. - bool CheckReportItems(); + // Runs tests on content of |archive_|. + bool CheckArchivedAnnotations(); + + const std::map<std::string, ArchivedAnnotation>& GetArchivedAnnotations() + const { + return archive_; + } + + // Checks if the current platform is in the os list of archived annotation. + bool MatchesCurrentPlatform(const ArchivedAnnotation& annotation) const { + return base::ContainsValue(annotation.os_list, current_platform_); + } + + // Produces the list of annotations that are not defined in this platform. + // Returns false if annotations.xml is not loaded. + bool GetOtherPlatformsAnnotationIDs(std::vector<std::string>* ids) const; + + // Returns the number of items in annotations.xml for testing. + unsigned GetXMLItemsCountForTesting(); + + std::string GetXMLDifferencesForTesting(const std::string& old_xml, + const std::string& new_xml) { + return GetXMLDifferences(old_xml, new_xml); + } private: - struct ReportItem { - ReportItem(); - ReportItem(const ReportItem& other); - ~ReportItem(); + // Generates a text serialized XML for current report items. + std::string GenerateSerializedXML() const; - int unique_id_hash_code; - std::string deprecation_date; - int content_hash_code; - std::vector<std::string> os_list; - }; + // Returns the required updates to convert one serialized XML to another. + std::string GetXMLDifferences(const std::string& old_xml, + const std::string& new_xml); - std::map<std::string, ReportItem> report_items_; + std::vector<std::string> all_supported_platforms_; + std::map<std::string, ArchivedAnnotation> archive_; const base::FilePath source_path_; + std::string current_platform_; bool modified_; };
diff --git a/tools/traffic_annotation/auditor/traffic_annotation_file_filter.cc b/tools/traffic_annotation/auditor/traffic_annotation_file_filter.cc index 216d8ea..20460ca 100644 --- a/tools/traffic_annotation/auditor/traffic_annotation_file_filter.cc +++ b/tools/traffic_annotation/auditor/traffic_annotation_file_filter.cc
@@ -36,22 +36,16 @@ "MISSING_TRAFFIC_ANNOTATION", "TRAFFIC_ANNOTATION_FOR_TESTS", "PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS", - "SSLClientSocket", // SSLClientSocket:: - "TCPClientSocket", // TCPClientSocket:: - "UDPClientSocket", // UDPClientSocket:: "URLFetcher::Create", // This one is used with class as it's too generic. - "CreateDatagramClientSocket", // ClientSocketFactory:: - "CreateSSLClientSocket", // ClientSocketFactory:: - "CreateTransportClientSocket", // ClientSocketFactory:: - "CreateRequest", // URLRequestContext:: - nullptr // End Marker + "CreateRequest", // URLRequestContext:: + nullptr // End Marker }; } // namespace -TrafficAnnotationFileFilter::TrafficAnnotationFileFilter() {} +TrafficAnnotationFileFilter::TrafficAnnotationFileFilter() = default; -TrafficAnnotationFileFilter::~TrafficAnnotationFileFilter() {} +TrafficAnnotationFileFilter::~TrafficAnnotationFileFilter() = default; void TrafficAnnotationFileFilter::GetFilesFromGit( const base::FilePath& source_path) { @@ -101,6 +95,14 @@ return false; } + // Ignore unittest files to speed up the tests. They would be only tested when + // filters are disabled. + pos = file_path.length() - 12; + if (pos >= 0 && (!strcmp("_unittest.cc", file_path.c_str() + pos) || + !strcmp("_unittest.mm", file_path.c_str() + pos))) { + return false; + } + base::FilePath converted_file_path = #if defined(OS_WIN) base::FilePath(
diff --git a/tools/traffic_annotation/auditor/traffic_annotation_id_checker.cc b/tools/traffic_annotation/auditor/traffic_annotation_id_checker.cc new file mode 100644 index 0000000..235dcdc --- /dev/null +++ b/tools/traffic_annotation/auditor/traffic_annotation_id_checker.cc
@@ -0,0 +1,190 @@ +// Copyright 2017 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 "tools/traffic_annotation/auditor/traffic_annotation_id_checker.h" + +#include "base/stl_util.h" +#include "base/strings/string_util.h" +#include "base/strings/stringprintf.h" + +TrafficAnnotationIDChecker::TrafficAnnotationIDChecker( + const std::set<int>& reserved_ids, + const std::set<int>& deprecated_ids) + : deprecated_ids_(deprecated_ids), reserved_ids_(reserved_ids) {} + +TrafficAnnotationIDChecker::~TrafficAnnotationIDChecker() = default; + +void TrafficAnnotationIDChecker::Load( + const std::vector<AnnotationInstance>& extracted_annotations) { + annotations_.clear(); + for (const AnnotationInstance& instance : extracted_annotations) { + AnnotationItem item; + item.type = instance.type; + item.ids[0].hash_code = instance.unique_id_hash_code; + item.ids[0].text = instance.proto.unique_id(); + if (instance.NeedsTwoIDs()) { + item.ids_count = 2; + item.ids[1].hash_code = instance.second_id_hash_code; + item.ids[1].text = instance.second_id; + } else { + item.ids_count = 1; + } + item.file_path = instance.proto.source().file(); + item.line_number = instance.proto.source().line(); + item.loaded_from_archive = instance.is_loaded_from_archive; + annotations_.push_back(item); + } +} + +void TrafficAnnotationIDChecker::CheckIDs(std::vector<AuditorResult>* errors) { + CheckIDsFormat(errors); + CheckForSecondIDs(errors); + CheckForInvalidValues( + reserved_ids_, AuditorResult::Type::ERROR_RESERVED_ID_HASH_CODE, errors); + CheckForInvalidValues(deprecated_ids_, + AuditorResult::Type::ERROR_DEPRECATED_ID_HASH_CODE, + errors); + CheckForHashCollisions(errors); + CheckForInvalidRepeatedIDs(errors); +} + +void TrafficAnnotationIDChecker::CheckForInvalidValues( + const std::set<int>& invalid_set, + AuditorResult::Type error_type, + std::vector<AuditorResult>* errors) { + for (AnnotationItem& item : annotations_) { + for (int i = 0; i < item.ids_count; i++) { + if (base::ContainsKey(invalid_set, item.ids[i].hash_code)) { + errors->push_back(AuditorResult(error_type, item.ids[i].text, + item.file_path, item.line_number)); + } + } + } +} + +void TrafficAnnotationIDChecker::CheckForSecondIDs( + std::vector<AuditorResult>* errors) { + for (AnnotationItem& item : annotations_) { + if (item.ids_count == 2 && + (item.ids[1].text.empty() || + item.ids[0].hash_code == item.ids[1].hash_code)) { + errors->push_back( + AuditorResult(AuditorResult::Type::ERROR_MISSING_SECOND_ID, + std::string(), item.file_path, item.line_number)); + // Remove this id from next tests. + item.ids_count = 0; + } + } +} + +void TrafficAnnotationIDChecker::CheckForHashCollisions( + std::vector<AuditorResult>* errors) { + std::map<int, std::string> collisions; + for (AnnotationItem& item : annotations_) { + for (int i = 0; i < item.ids_count; i++) { + if (!base::ContainsKey(collisions, item.ids[i].hash_code)) { + // If item is loaded from archive, and it is the second id, do not keep + // the id for checks. Archive just keeps the hash code of the second id + // and the text value of it is not correct. + if (!item.loaded_from_archive || !i) { + collisions.insert( + std::make_pair(item.ids[i].hash_code, item.ids[i].text)); + } + } else { + if (item.loaded_from_archive && i) + continue; + if (item.ids[i].text != collisions[item.ids[i].hash_code]) { + AuditorResult error(AuditorResult::Type::ERROR_HASH_CODE_COLLISION, + item.ids[i].text); + error.AddDetail(collisions[item.ids[i].hash_code]); + errors->push_back(error); + } + } + } + } +} + +void TrafficAnnotationIDChecker::CheckForInvalidRepeatedIDs( + std::vector<AuditorResult>* errors) { + std::map<int, AnnotationItem*> first_ids; + std::map<int, AnnotationItem*> second_ids; + + // Check if first ids are unique. + for (AnnotationItem& item : annotations_) { + if (!base::ContainsKey(first_ids, item.ids[0].hash_code)) { + first_ids[item.ids[0].hash_code] = &item; + } else { + errors->push_back(CreateRepeatedIDError( + item.ids[0].text, item, *first_ids[item.ids[0].hash_code])); + } + } + + // If a second id is equal to a first id, owner of the second id should be of + // type PARTIAL and owner of the first id should be of type COMPLETING. + for (AnnotationItem& item : annotations_) { + if (item.ids_count == 2 && + base::ContainsKey(first_ids, item.ids[1].hash_code)) { + if (item.type != AnnotationInstance::Type::ANNOTATION_PARTIAL || + first_ids[item.ids[1].hash_code]->type != + AnnotationInstance::Type::ANNOTATION_COMPLETING) { + errors->push_back(CreateRepeatedIDError( + item.ids[1].text, item, *first_ids[item.ids[1].hash_code])); + } + } + } + + // If two second ids are equal, they should be either PARTIAL or + // BRANCHED_COMPLETING. + for (AnnotationItem& item : annotations_) { + if (item.ids_count != 2) + continue; + if (!base::ContainsKey(second_ids, item.ids[1].hash_code)) { + second_ids[item.ids[1].hash_code] = &item; + } else { + AnnotationInstance::Type other_type = + second_ids[item.ids[1].hash_code]->type; + if ((item.type != AnnotationInstance::Type::ANNOTATION_PARTIAL && + item.type != + AnnotationInstance::Type::ANNOTATION_BRANCHED_COMPLETING) || + (other_type != AnnotationInstance::Type::ANNOTATION_PARTIAL && + other_type != + AnnotationInstance::Type::ANNOTATION_BRANCHED_COMPLETING)) { + errors->push_back(CreateRepeatedIDError( + item.ids[1].text, item, *second_ids[item.ids[1].hash_code])); + } + } + } +} + +void TrafficAnnotationIDChecker::CheckIDsFormat( + std::vector<AuditorResult>* errors) { + for (AnnotationItem& item : annotations_) { + bool any_failed = false; + for (int i = 0; i < item.ids_count; i++) { + if (!base::ContainsOnlyChars(base::ToLowerASCII(item.ids[i].text), + "0123456789_abcdefghijklmnopqrstuvwxyz")) { + errors->push_back( + AuditorResult(AuditorResult::Type::ERROR_ID_INVALID_CHARACTER, + item.ids[i].text, item.file_path, item.line_number)); + any_failed = true; + } + } + // Remove this id from next tests. + if (any_failed) + item.ids_count = 0; + } +} + +AuditorResult TrafficAnnotationIDChecker::CreateRepeatedIDError( + const std::string& common_id, + const AnnotationItem& item1, + const AnnotationItem& item2) { + AuditorResult error( + AuditorResult::Type::ERROR_REPEATED_ID, + base::StringPrintf("%s in '%s:%i'", common_id.c_str(), + item1.file_path.c_str(), item1.line_number)); + error.AddDetail(base::StringPrintf("'%s:%i'", item2.file_path.c_str(), + item2.line_number)); + return error; +}
diff --git a/tools/traffic_annotation/auditor/traffic_annotation_id_checker.h b/tools/traffic_annotation/auditor/traffic_annotation_id_checker.h new file mode 100644 index 0000000..4f366052 --- /dev/null +++ b/tools/traffic_annotation/auditor/traffic_annotation_id_checker.h
@@ -0,0 +1,70 @@ +// Copyright 2017 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. + +#ifndef TRAFFIC_ANNOTATION_ID_CHECKER_H_ +#define TRAFFIC_ANNOTATION_ID_CHECKER_H_ + +#include <set> +#include <vector> + +#include "tools/traffic_annotation/auditor/instance.h" + +// Performs all tests that are required to ensure that annotations have correct +// ids. +class TrafficAnnotationIDChecker { + public: + TrafficAnnotationIDChecker(const std::set<int>& reserved_ids, + const std::set<int>& deprecated_ids); + ~TrafficAnnotationIDChecker(); + + // Loads |extracted_annotations| into |annotations_|; + void Load(const std::vector<AnnotationInstance>& extracted_annotations); + + // Checks loaded |annotations_| for all sort of ID related errors and writes + // errors to |errors|. + void CheckIDs(std::vector<AuditorResult>* errors); + + private: + // TODO(https://crbug.com/690323): Merge struct with AnnotationInstance. + struct AnnotationItem { + struct { + std::string text; + int hash_code; + } ids[2]; + int ids_count; // Number of existing ids (1 or 2). + AnnotationInstance::Type type; + std::string file_path; + int line_number; + bool loaded_from_archive; + }; + + // Checks if the ids in |invalid_set| are not used in annotations. If found, + // creates an error with |error_type| and writes it to |errors|. + void CheckForInvalidValues(const std::set<int>& invalid_set, + AuditorResult::Type error_type, + std::vector<AuditorResult>* errors); + + // Check if annotations that need two ids, have two and the second one is + // different from their unique id. + void CheckForSecondIDs(std::vector<AuditorResult>* errors); + + // Checks if there are ids with colliding hash values. + void CheckForHashCollisions(std::vector<AuditorResult>* errors); + + // Checks if there are invalid repeated ids. + void CheckForInvalidRepeatedIDs(std::vector<AuditorResult>* errors); + + // Checks if ids only include alphanumeric characters and underline. + void CheckIDsFormat(std::vector<AuditorResult>* errors); + + AuditorResult CreateRepeatedIDError(const std::string& common_id, + const AnnotationItem& item1, + const AnnotationItem& item2); + + std::vector<AnnotationItem> annotations_; + std::set<int> deprecated_ids_; + std::set<int> reserved_ids_; +}; + +#endif // TRAFFIC_ANNOTATION_ID_CHECKER_H_ \ No newline at end of file
diff --git a/tools/traffic_annotation/bin/linux64/traffic_annotation_auditor.sha1 b/tools/traffic_annotation/bin/linux64/traffic_annotation_auditor.sha1 new file mode 100644 index 0000000..8183dc4 --- /dev/null +++ b/tools/traffic_annotation/bin/linux64/traffic_annotation_auditor.sha1
@@ -0,0 +1 @@ +5fcf7e1a6e38b432a7246b791398115f388011e3 \ No newline at end of file
diff --git a/tools/traffic_annotation/bin/linux64/traffic_annotation_extractor.sha1 b/tools/traffic_annotation/bin/linux64/traffic_annotation_extractor.sha1 new file mode 100644 index 0000000..1a5d4cc1 --- /dev/null +++ b/tools/traffic_annotation/bin/linux64/traffic_annotation_extractor.sha1
@@ -0,0 +1 @@ +4cc69f7b5103f23d829020af44dabd3b1da6cfca \ No newline at end of file
diff --git a/tools/traffic_annotation/bin/win32/traffic_annotation_auditor.exe.sha1 b/tools/traffic_annotation/bin/win32/traffic_annotation_auditor.exe.sha1 new file mode 100644 index 0000000..9db1db54 --- /dev/null +++ b/tools/traffic_annotation/bin/win32/traffic_annotation_auditor.exe.sha1
@@ -0,0 +1 @@ +9dff1662640215f6989c0ba1644e49daf000998f \ No newline at end of file
diff --git a/tools/traffic_annotation/bin/win32/traffic_annotation_extractor.exe.sha1 b/tools/traffic_annotation/bin/win32/traffic_annotation_extractor.exe.sha1 new file mode 100644 index 0000000..7d1b871f1 --- /dev/null +++ b/tools/traffic_annotation/bin/win32/traffic_annotation_extractor.exe.sha1
@@ -0,0 +1 @@ +c318928a2767bbc822424fdb44ff6ee2f429d412 \ No newline at end of file
diff --git a/tools/traffic_annotation/sample_traffic_annotation.cc b/tools/traffic_annotation/sample_traffic_annotation.cc index 6e53fa0..361059e 100644 --- a/tools/traffic_annotation/sample_traffic_annotation.cc +++ b/tools/traffic_annotation/sample_traffic_annotation.cc
@@ -29,12 +29,13 @@ setting: "..." chrome_policy { [POLICY_NAME] { - policy_options {mode: MANDATORY/RECOMMENDED/UNSET} [POLICY_NAME]: ... } } policy_exception_justification = "..." - })"); + } + comments: "..." + )"); } // An example on one level traffic annotation. @@ -65,7 +66,6 @@ "Advanced. The feature is disabled by default." chrome_policy { SpellCheckServiceEnabled { - policy_options {mode: MANDATORY} SpellCheckServiceEnabled: false } } @@ -107,7 +107,6 @@ "feature is enabled by default." chrome_policy { SearchSuggestEnabled { - policy_options {mode: MANDATORY} SearchSuggestEnabled: false } } @@ -141,7 +140,6 @@ "'Passwords and forms'). There is no setting to disable the API." chrome_policy { PasswordManagerEnabled { - policy_options {mode: MANDATORY} PasswordManagerEnabled: false } } @@ -232,7 +230,6 @@ "feature is enabled by default." chrome_policy { MetricsReportingEnabled { - policy_options {mode: MANDATORY} MetricsReportingEnabled: false } }
diff --git a/tools/traffic_annotation/scripts/check_annotations.py b/tools/traffic_annotation/scripts/check_annotations.py new file mode 100755 index 0000000..0899468c --- /dev/null +++ b/tools/traffic_annotation/scripts/check_annotations.py
@@ -0,0 +1,195 @@ +#!/usr/bin/env python +# Copyright 2017 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. + +"""Runs traffic_annotation_auditor on the given change list or all files to make +sure network traffic annoations are syntactically and semantically correct and +all required functions are annotated. +""" + +import os +import argparse +import subprocess +import sys + + +# If this test starts failing, please set TEST_IS_ENABLED to "False" and file a +# bug to get this reenabled, and cc the people listed in +# //tools/traffic_annotation/OWNERS. +TEST_IS_ENABLED = sys.platform != 'win32' + + +class NetworkTrafficAnnotationChecker(): + EXTENSIONS = ['.cc', '.mm',] + COULD_NOT_RUN_MESSAGE = \ + 'Network traffic annotation presubmit check was not performed. To run ' \ + 'it, a compiled build directory and traffic_annotation_auditor binary ' \ + 'are required.' + + def __init__(self, build_path=None): + """Initializes a NetworkTrafficAnnotationChecker object. + + Args: + build_path: str Absolute or relative path to a fully compiled build + directory. If not specified, the script tries to find it based on + relative position of this file (src/tools/traffic_annotation). + """ + self.this_dir = os.path.dirname(os.path.abspath(__file__)) + + if not build_path: + build_path = self._FindPossibleBuildPath() + if build_path: + self.build_path = os.path.abspath(build_path) + + self.auditor_path = None + platform = { + 'linux2': 'linux64', + 'darwin': 'mac', + 'win32': 'win32', + }[sys.platform] + path = os.path.join(self.this_dir, '..', 'bin', platform, + 'traffic_annotation_auditor') + if sys.platform == 'win32': + path += '.exe' + if os.path.exists(path): + self.auditor_path = path + + def _FindPossibleBuildPath(self): + """Returns the first folder in //out that looks like a build dir.""" + # Assuming this file is in 'tools/traffic_annotation/scripts', three + # directories deeper is 'src' and hopefully there is an 'out' in it. + out = os.path.abspath(os.path.join(self.this_dir, '..', '..', '..', 'out')) + if os.path.exists(out): + for folder in os.listdir(out): + candidate = os.path.join(out, folder) + if (os.path.isdir(candidate) and + self._CheckIfDirectorySeemsAsBuild(candidate)): + return candidate + return None + + def _CheckIfDirectorySeemsAsBuild(self, path): + """Checks to see if a directory seems to be a compiled build directory by + searching for 'gen' folder and 'build.ninja' file in it. + """ + return all(os.path.exists( + os.path.join(path, item)) for item in ('gen', 'build.ninja')) + + def _AllArgsValid(self): + return self.auditor_path and self.build_path + + def ShouldCheckFile(self, file_path): + """Returns true if the input file has an extension relevant to network + traffic annotations.""" + return os.path.splitext(file_path)[1] in self.EXTENSIONS + + def CheckFiles(self, file_paths=None, limit=0): + """Passes all given files to traffic_annotation_auditor to be checked for + possible violations of network traffic annotation rules. + + Args: + file_paths: list of str List of files to check. If empty, the whole + repository will be checked. + limit: int Sets the upper threshold for number of errors and warnings, + use 0 for unlimited. + + Returns: + int Exit code of the network traffic annotation auditor. + """ + + if not TEST_IS_ENABLED: + return 0 + + if not self.build_path: + return [self.COULD_NOT_RUN_MESSAGE], [] + + if file_paths: + file_paths = [ + file_path for file_path in file_paths if self.ShouldCheckFile( + file_path)] + + if not file_paths: + return 0 + else: + file_paths = [] + + args = [self.auditor_path, "--test-only", "--limit=%i" % limit, + "--build-path=" + self.build_path, "--error-resilient"] + file_paths + + command = subprocess.Popen(args, stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + stdout_text, stderr_text = command.communicate() + + if stdout_text: + print(stdout_text) + if stderr_text: + print("\n[Runtime Messages]:\n%s" % stderr_text) + return command.returncode + + + def GetModifiedFiles(self): + """Gets the list of modified files from git. Returns None if any error + happens.""" + + # List of files is extracted almost the same way as the following test + # recipe: https://cs.chromium.org/chromium/tools/depot_tools/recipes/ + # recipe_modules/tryserver/api.py + # '--no-renames' switch is added so that if a file is renamed, both old and + # new name would be given. Old name is needed to discard its data in + # annotations.xml and new name is needed for updating the XML and checking + # its content for possible changes. + args = ["git.bat"] if sys.platform == "win32" else ["git"] + args += ["diff", "--cached", "--name-only", "--no-renames"] + + original_path = os.getcwd() + + # Change directory to src (two levels upper than build path). + os.chdir(os.path.join(self.build_path, "..", "..")) + command = subprocess.Popen(args, stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + stdout_text, stderr_text = command.communicate() + + if stderr_text: + print("Could not run '%s' to get the list of changed files " + "beacuse: %s" % (" ".join(args), stderr_text)) + os.chdir(original_path) + return None + + os.chdir(original_path) + return stdout_text.splitlines() + + +def main(): + parser = argparse.ArgumentParser( + description="Traffic Annotation Auditor Presubmit checker.") + parser.add_argument( + '--build-path', + help='Specifies a compiled build directory, e.g. out/Debug. If not ' + 'specified, the script tries to guess it. Will not proceed if not ' + 'found.') + parser.add_argument( + '--limit', default=5, + help='Limit for the maximum number of returned errors and warnings. ' + 'Default value is 5, use 0 for unlimited.') + parser.add_argument( + '--complete', action='store_true', + help='Run the test on the complete repository. Otherwise only the ' + 'modified files are tested.') + + args = parser.parse_args() + + checker = NetworkTrafficAnnotationChecker(args.build_path) + if args.complete: + file_paths = None + else: + file_paths = checker.GetModifiedFiles() + if file_paths is None: + return -1 + if len(file_paths) == 0: + return 0 + + return checker.CheckFiles(file_paths=file_paths, limit=args.limit) + + +if '__main__' == __name__: + sys.exit(main())
diff --git a/tools/traffic_annotation/summary/OWNERS b/tools/traffic_annotation/summary/OWNERS new file mode 100644 index 0000000..9f510e0b --- /dev/null +++ b/tools/traffic_annotation/summary/OWNERS
@@ -0,0 +1,7 @@ +set noparent + +dullweber@chromium.org +mkwst@chromium.org +msramek@chromium.org +rhalavati@chromium.org +tnagel@chromium.org
diff --git a/tools/traffic_annotation/summary/README.md b/tools/traffic_annotation/summary/README.md index 9fa21ff..eb4edb53 100644 --- a/tools/traffic_annotation/summary/README.md +++ b/tools/traffic_annotation/summary/README.md
@@ -1,5 +1,7 @@ # Network Traffic Annotations List This file describes the `tools/traffic_annotation/summary/annotations.xml`. +Please see `docs/network_traffic_annotations.md` for an introduction to network +traffic annotations. # Content Description `annotations.xml` includes the summary of all network traffic annotations in @@ -18,3 +20,5 @@ automatic update. After each modification of`annotations.xml`, auditor calls `tools/traffic_annotation/scripts/annotations_xml_downstream_updater.py` to update all users of this file. +The latest executable of `traffic_annotation_auditor` for supported platforms +can be found in `tools/traffic_annotation/bin/[platform]`.
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml index 06ef929..82eb0c0 100644 --- a/tools/traffic_annotation/summary/annotations.xml +++ b/tools/traffic_annotation/summary/annotations.xml
@@ -8,202 +8,236 @@ --> <annotations> - <item id="CRD_ice_config_request" hash_code="49825319" content_hash_code="8740825" os_list="linux,windows"/> - <item id="CRD_relay_session_request" hash_code="24058523" content_hash_code="36997811" os_list="linux,windows"/> - <item id="CRD_telemetry_log" hash_code="18670926" content_hash_code="49025478" os_list="linux,windows"/> - <item id="affiliation_lookup" hash_code="111904019" content_hash_code="81061452" os_list="linux,windows"/> - <item id="appcache_update_job" hash_code="25790702" content_hash_code="27424887" os_list="linux,windows"/> - <item id="asset_links" hash_code="89771989" content_hash_code="72216357" os_list="linux,windows"/> - <item id="autofill_query" hash_code="88863520" content_hash_code="15563339" os_list="linux,windows"/> - <item id="autofill_upload" hash_code="104798869" content_hash_code="110634763" os_list="linux,windows"/> - <item id="background_fetch_context" hash_code="16469669" content_hash_code="52235434" os_list="linux,windows"/> - <item id="background_performance_tracer" hash_code="84575287" content_hash_code="120154250" os_list="linux,windows"/> - <item id="blink_resource_loader" hash_code="101845102" content_hash_code="69137084" os_list="linux,windows"/> - <item id="blob_read" hash_code="112303907" content_hash_code="135449692" os_list="linux,windows"/> - <item id="blob_reader" hash_code="5154306" content_hash_code="39702178" os_list="linux,windows"/> - <item id="brandcode_config" hash_code="109679553" content_hash_code="128843792" os_list="linux,windows"/> - <item id="captive_portal_service" hash_code="88754904" content_hash_code="70737580" os_list="linux,windows"/> - <item id="certificate_verifier" hash_code="113553577" content_hash_code="62346354" os_list="linux,windows"/> - <item id="chrome_expect_ct_reporter" hash_code="57276415" content_hash_code="137551346" os_list="linux,windows"/> - <item id="chrome_feedback_report_app" hash_code="134729048" content_hash_code="73916972" os_list="linux,windows"/> - <item id="chrome_variations_service" hash_code="115188287" content_hash_code="32485683" os_list="linux,windows"/> - <item id="client_download_request" hash_code="125522256" content_hash_code="23897505" os_list="linux,windows"/> - <item id="cloud_print_backend" hash_code="71578042" content_hash_code="89544098" os_list="linux,windows"/> - <item id="cloud_print_privet_register" hash_code="24978481" content_hash_code="131359002" os_list="linux,windows"/> - <item id="cloud_print_proxy" hash_code="50859288" content_hash_code="25432720" os_list="linux,windows"/> - <item id="cloud_print_search" hash_code="132055347" content_hash_code="123783474" os_list="linux,windows"/> - <item id="component_updater_utils" hash_code="125596241" content_hash_code="12311195" os_list="linux,windows"/> - <item id="content_hash_verification_job" hash_code="64733114" content_hash_code="127912411" os_list="linux,windows"/> - <item id="content_resource_fetcher" hash_code="70796791" content_hash_code="135648626" os_list="windows,linux"/> - <item id="content_suggestion_get_favicon" hash_code="16653985" content_hash_code="134280933" os_list="linux,windows"/> - <item id="credenential_avatar" hash_code="53695122" content_hash_code="113035371" os_list="linux,windows"/> - <item id="cros_recovery_image_download" hash_code="101725581" content_hash_code="23088027" os_list="linux,windows"/> - <item id="cryptauth_device_sync_tickle" hash_code="96565489" content_hash_code="111962899" os_list="linux,windows"/> - <item id="cryptauth_enrollment_flow_finish" hash_code="54836939" content_hash_code="122011288" os_list="linux,windows"/> - <item id="cryptauth_enrollment_flow_setup" hash_code="84889397" content_hash_code="115692637" os_list="linux,windows"/> - <item id="cryptauth_find_eligible_for_promotion" hash_code="20053290" content_hash_code="98613425" os_list="linux,windows"/> - <item id="cryptauth_find_eligible_unlock_devices" hash_code="120000562" content_hash_code="124093652" os_list="linux,windows"/> - <item id="cryptauth_get_my_devices" hash_code="136498680" content_hash_code="83420739" os_list="linux,windows"/> - <item id="cryptauth_toggle_easyunlock" hash_code="25204343" content_hash_code="5092035" os_list="linux,windows"/> - <item id="data_reduction_proxy_config" hash_code="485305" content_hash_code="134075813" os_list="linux,windows"/> - <item id="data_reduction_proxy_pingback" hash_code="68561428" content_hash_code="78407792" os_list="linux,windows"/> - <item id="data_reduction_proxy_secure_proxy_check" hash_code="131236802" content_hash_code="122297136" os_list="linux,windows"/> - <item id="data_reduction_proxy_warmup" hash_code="8250451" content_hash_code="6321249" os_list="linux,windows"/> - <item id="desktop_ios_promotion" hash_code="13694792" content_hash_code="19776951" os_list="windows"/> - <item id="device_geolocation_request" hash_code="77673751" content_hash_code="97181773" os_list="linux,windows"/> - <item id="device_management_service" hash_code="117782019" content_hash_code="127535409" os_list="linux,windows"/> - <item id="devtools_free_data_source" hash_code="22774132" content_hash_code="136324050" os_list="linux,windows"/> - <item id="devtools_handle_front_end_messages" hash_code="135636011" content_hash_code="18422190" os_list="linux,windows"/> - <item id="devtools_hard_coded_data_source" hash_code="111565057" content_hash_code="46074423" os_list="linux,windows"/> - <item id="devtools_interceptor" hash_code="98123737" content_hash_code="19053470" os_list="linux,windows"/> - <item id="devtools_network_resource" hash_code="129652775" content_hash_code="24059212" os_list="linux,windows"/> - <item id="dial_get_device_description" hash_code="50422598" content_hash_code="129827780" os_list="linux,windows"/> - <item id="dom_distiller" hash_code="3989826" content_hash_code="106153970" os_list="linux,windows"/> - <item id="domain_reliability_report_upload" hash_code="108804096" content_hash_code="35902036" os_list="linux,windows"/> - <item id="domain_security_policy" hash_code="77597059" content_hash_code="30916983" os_list="linux,windows"/> - <item id="doodle_fetcher" hash_code="97199008" deprecated="2017-08-28" content_hash_code="87981692"/> - <item id="doodle_service" hash_code="41154842" deprecated="2017-08-28" content_hash_code="28273962"/> - <item id="download_manager_resume" hash_code="35380758" content_hash_code="41227674" os_list="linux,windows"/> - <item id="download_web_contents_frame" hash_code="56351037" content_hash_code="3657889" os_list="linux,windows"/> - <item id="downloads_api_run_async" hash_code="121068967" content_hash_code="87443585" os_list="linux,windows"/> - <item id="drag_download_file" hash_code="95910019" content_hash_code="126492858" os_list="linux,windows"/> - <item id="extension_blacklist" hash_code="59592717" content_hash_code="116742516" os_list="linux,windows"/> - <item id="extension_crx_fetcher" hash_code="21145003" content_hash_code="79150319" os_list="linux,windows"/> - <item id="extension_install_signer" hash_code="50464499" content_hash_code="88088656" os_list="linux,windows"/> - <item id="extension_manifest_fetcher" hash_code="5151071" content_hash_code="57885402" os_list="linux,windows"/> - <item id="external_policy_fetcher" hash_code="9459438" content_hash_code="64260484" os_list="linux,windows"/> - <item id="family_info" hash_code="30913825" content_hash_code="25369370" os_list="linux,windows"/> - <item id="gaia_auth_check_connection_info" hash_code="4598626" content_hash_code="57347000" os_list="linux,windows"/> - <item id="gaia_auth_exchange_cookies" hash_code="134289752" content_hash_code="66433230" os_list="linux,windows"/> - <item id="gaia_auth_exchange_device_id" hash_code="39877119" content_hash_code="61857947" os_list="linux,windows"/> - <item id="gaia_auth_fetch_for_uber" hash_code="97978464" content_hash_code="28006265" os_list="linux,windows"/> - <item id="gaia_auth_get_user_info" hash_code="82167736" content_hash_code="4695017" os_list="linux,windows"/> - <item id="gaia_auth_list_accounts" hash_code="35565745" content_hash_code="93669150" os_list="linux,windows"/> - <item id="gaia_auth_log_out" hash_code="116426676" content_hash_code="91154233" os_list="linux,windows"/> - <item id="gaia_auth_login" hash_code="91597383" content_hash_code="111911548" os_list="linux,windows"/> - <item id="gaia_auth_merge_sessions" hash_code="26216847" content_hash_code="30423843" os_list="linux,windows"/> - <item id="gaia_auth_revoke_token" hash_code="133982351" content_hash_code="96665330" os_list="linux,windows"/> - <item id="gaia_cookie_manager_external_cc_result" hash_code="4300475" content_hash_code="31188375" os_list="linux,windows"/> - <item id="gaia_oauth_client_get_token_info" hash_code="32585152" content_hash_code="128143346" os_list="linux,windows"/> - <item id="gaia_oauth_client_get_tokens" hash_code="5637379" content_hash_code="12099176" os_list="linux,windows"/> - <item id="gaia_oauth_client_get_user_info" hash_code="83476155" content_hash_code="35159007" os_list="linux,windows"/> - <item id="gaia_oauth_client_refresh_token" hash_code="82462683" content_hash_code="22305252" os_list="linux,windows"/> - <item id="gcm_channel_status_request" hash_code="18300705" content_hash_code="53862393" os_list="linux,windows"/> - <item id="gcm_checkin" hash_code="65957842" content_hash_code="98259579" os_list="linux,windows"/> - <item id="gcm_registration" hash_code="61656965" content_hash_code="113670632" os_list="linux,windows"/> - <item id="gcm_subscription" hash_code="56434025" content_hash_code="61632174" os_list="linux,windows"/> - <item id="gcm_unregistration" hash_code="119542033" content_hash_code="30144127" os_list="linux,windows"/> - <item id="google_url_tracker" hash_code="5492492" content_hash_code="54474899" os_list="linux,windows"/> - <item id="headless_url_request" hash_code="29865866" content_hash_code="76700151" os_list="linux,windows"/> - <item id="history_notice_utils_notice" hash_code="102595701" content_hash_code="4717759" os_list="linux,windows"/> - <item id="history_notice_utils_popup" hash_code="80832574" content_hash_code="11746153" os_list="linux,windows"/> - <item id="icon_cacher" hash_code="103133150" content_hash_code="116368348" os_list="linux,windows"/> - <item id="icon_catcher_get_large_icon" hash_code="44494884" content_hash_code="98262037" os_list="linux,windows"/> - <item id="indexed_db_internals_handler" hash_code="131180348" content_hash_code="59026406" os_list="linux,windows"/> - <item id="intranet_redirect_detector" hash_code="21785164" content_hash_code="62025595" os_list="linux,windows"/> - <item id="invalidation_service" hash_code="72354423" content_hash_code="78425687" os_list="linux,windows"/> - <item id="lib_address_input" hash_code="50816767" content_hash_code="57977576" os_list="linux,windows"/> - <item id="logo_tracker" hash_code="36859107" content_hash_code="67588075" os_list="linux,windows"/> - <item id="metrics_report_ukm" hash_code="727478" content_hash_code="40919254" os_list="linux,windows"/> - <item id="metrics_report_uma" hash_code="727528" content_hash_code="10176197" os_list="linux,windows"/> - <item id="missing" hash_code="77012883" reserved="1" os_list="all"/> - <item id="mojo_context_state" hash_code="93232258" content_hash_code="124821232" os_list="linux"/> - <item id="navigation_url_loader" hash_code="63171670" content_hash_code="129352907" os_list="linux,windows"/> - <item id="network_time_component" hash_code="46188932" content_hash_code="28051857" os_list="linux,windows"/> - <item id="notification_image_reporter" hash_code="70126372" content_hash_code="29754543" os_list="linux,windows"/> - <item id="ntp_contextual_suggestions_fetch" hash_code="95711309" content_hash_code="29742597" os_list="linux,windows"/> - <item id="ntp_snippets_fetch" hash_code="15418154" content_hash_code="10078959" os_list="linux,windows"/> - <item id="oauth2_access_token_fetcher" hash_code="27915688" content_hash_code="33501872" os_list="linux,windows"/> - <item id="oauth2_mint_token_flow" hash_code="1112842" content_hash_code="70101159" os_list="linux,windows"/> - <item id="ocsp_start_url_request" hash_code="60921996" content_hash_code="24127780" os_list="linux"/> - <item id="offline_prefetch" hash_code="19185953" content_hash_code="57248156" os_list="linux,windows"/> - <item id="omnibox_navigation_observer" hash_code="61684939" content_hash_code="70941231" os_list="linux,windows"/> - <item id="omnibox_prefetch_image" hash_code="109200878" content_hash_code="107906693" os_list="linux,windows"/> - <item id="omnibox_result_change" hash_code="73107389" content_hash_code="24802647" os_list="linux,windows"/> - <item id="omnibox_suggest" hash_code="47815025" content_hash_code="86297726" os_list="linux,windows"/> - <item id="omnibox_suggest_deletion" hash_code="84212388" content_hash_code="24981550" os_list="linux,windows"/> - <item id="omnibox_zerosuggest" hash_code="7687691" content_hash_code="119419625" os_list="linux,windows"/> - <item id="omnibox_zerosuggest_experimental" hash_code="3813491" content_hash_code="22929259" os_list="linux,windows"/> - <item id="one_google_bar_service" hash_code="78917933" content_hash_code="46527252" os_list="linux,windows"/> - <item id="open_search" hash_code="107267424" content_hash_code="25715812" os_list="linux,windows"/> - <item id="parallel_download_job" hash_code="135118587" content_hash_code="105330419" os_list="linux,windows"/> - <item id="password_protection_request" hash_code="66322287" content_hash_code="21270837" os_list="linux,windows"/> - <item id="payment_instrument_icon_fetcher" hash_code="73309970" content_hash_code="84709873" os_list="linux,windows"/> - <item id="payment_manifest_downloader" hash_code="84045030" content_hash_code="19293316" os_list="linux,windows"/> - <item id="payments_sync_cards" hash_code="95588446" content_hash_code="56526513" os_list="linux,windows"/> - <item id="pdf_plugin_placeholder" hash_code="56866367" content_hash_code="16907221" os_list="linux,windows"/> - <item id="permission_reporting" hash_code="131741641" content_hash_code="7213535" os_list="linux,windows"/> - <item id="permission_request_creator" hash_code="43206794" content_hash_code="73571699" os_list="linux,windows"/> - <item id="persist_blob_to_indexed_db" hash_code="32030464" content_hash_code="35410079" os_list="linux,windows"/> - <item id="plugins_resource_service" hash_code="49601082" content_hash_code="6877335" os_list="linux,windows"/> - <item id="popular_sites_fetch" hash_code="50755044" content_hash_code="6910083" os_list="linux,windows"/> - <item id="ppapi_download_request" hash_code="135967426" content_hash_code="110461402" os_list="linux,windows"/> - <item id="prefetch_download" hash_code="44583172" content_hash_code="100587691" os_list="linux,windows"/> - <item id="printer_job_handler" hash_code="67638271" content_hash_code="52577454" os_list="linux,windows"/> - <item id="privet_http_impl" hash_code="71251498" content_hash_code="107348604" os_list="linux,windows"/> - <item id="profile_avatar" hash_code="51164680" content_hash_code="113550845" os_list="linux,windows"/> - <item id="profile_resetter_upload" hash_code="105330607" content_hash_code="129329171" os_list="linux,windows"/> - <item id="proxy_script_fetcher" hash_code="37531401" content_hash_code="31866133" os_list="linux,windows"/> - <item id="ranker_url_fetcher" hash_code="95682324" content_hash_code="45958626" os_list="linux,windows"/> - <item id="rappor_report" hash_code="44606780" content_hash_code="111287826" os_list="linux,windows"/> - <item id="refresh_token_annotation_request" hash_code="7433837" content_hash_code="59226150" os_list="linux,windows"/> - <item id="remote_suggestions_provider" hash_code="49544361" content_hash_code="126329742" os_list="linux,windows"/> - <item id="render_view_context_menu" hash_code="25844439" content_hash_code="69471170" os_list="linux,windows"/> - <item id="renderer_initiated_download" hash_code="116443055" content_hash_code="37846436" os_list="linux,windows"/> - <item id="reporting" hash_code="109891200" content_hash_code="125758928" os_list="linux,windows"/> - <item id="resource_dispatcher_host" hash_code="81157007" content_hash_code="35725167" os_list="linux,windows"/> - <item id="resource_dispather_host" hash_code="58963098" deprecated="2017-08-23" content_hash_code="72581415"/> - <item id="resource_prefetch" hash_code="110815970" content_hash_code="39251261" os_list="linux,windows"/> - <item id="rlz_ping" hash_code="99279418" content_hash_code="102108802" os_list="windows"/> - <item id="safe_browsing_backup_request" hash_code="106980485" content_hash_code="101760679" os_list="linux,windows"/> - <item id="safe_browsing_cache_collector" hash_code="115907811" content_hash_code="36392362" os_list="linux,windows"/> - <item id="safe_browsing_certificate_error_reporting" hash_code="66590631" content_hash_code="50197576" os_list="linux,windows"/> - <item id="safe_browsing_chunk_backup_request" hash_code="79957943" content_hash_code="133850277" os_list="linux,windows"/> - <item id="safe_browsing_client_side_malware_detector" hash_code="102935425" content_hash_code="79591279" os_list="linux,windows"/> - <item id="safe_browsing_client_side_phishing_detector" hash_code="1313982" content_hash_code="50199143" os_list="linux,windows"/> - <item id="safe_browsing_extended_reporting" hash_code="42848942" content_hash_code="50089173" os_list="linux,windows"/> - <item id="safe_browsing_feedback" hash_code="44583821" content_hash_code="114076664" os_list="linux,windows"/> - <item id="safe_browsing_g4_update" hash_code="75153841" content_hash_code="112049516" os_list="linux,windows"/> - <item id="safe_browsing_get_full_hash" hash_code="68745894" content_hash_code="21739198" os_list="linux,windows"/> - <item id="safe_browsing_incident" hash_code="124950347" content_hash_code="58481082" os_list="linux,windows"/> - <item id="safe_browsing_module_loader" hash_code="6019475" content_hash_code="49511650" os_list="linux,windows"/> - <item id="safe_browsing_v4_get_hash" hash_code="8561691" content_hash_code="132435617" os_list="linux,windows"/> - <item id="safe_search_url_reporter" hash_code="119677115" content_hash_code="67393078" os_list="linux,windows"/> - <item id="save_file_manager" hash_code="56275203" content_hash_code="56692339" os_list="linux,windows"/> - <item id="sdch_dictionary_fetch" hash_code="47152935" content_hash_code="16764294" os_list="linux,windows"/> - <item id="service_worker_write_to_cache_job" hash_code="117963307" content_hash_code="18065724" os_list="linux,windows"/> - <item id="signed_in_profile_avatar" hash_code="108903331" content_hash_code="72850619" os_list="linux,windows"/> - <item id="speech_recognition_downstream" hash_code="26096088" content_hash_code="120733233" os_list="linux,windows"/> - <item id="speech_recognition_upstream" hash_code="66846958" content_hash_code="7706219" os_list="linux,windows"/> - <item id="spellcheck_hunspell_dictionary" hash_code="117649486" content_hash_code="45660952" os_list="linux,windows"/> - <item id="spellcheck_lookup" hash_code="132553989" content_hash_code="27978613" os_list="linux,windows"/> - <item id="ssl_name_mismatch_lookup" hash_code="114468207" content_hash_code="97619078" os_list="linux,windows"/> - <item id="suggestions_image_manager" hash_code="13211343" content_hash_code="36271280" os_list="linux,windows"/> - <item id="suggestions_service" hash_code="35370363" content_hash_code="66296423" os_list="linux,windows"/> - <item id="supervised_user_refresh_token_fetcher" hash_code="136117054" content_hash_code="101636136" os_list="linux,windows"/> - <item id="supervised_user_url_filter" hash_code="14257952" content_hash_code="30470003" os_list="linux,windows"/> - <item id="supervised_users_blacklist" hash_code="78544924" content_hash_code="10924669" os_list="linux,windows"/> - <item id="sync_attachment_downloader" hash_code="26372521" content_hash_code="70097603" os_list="linux,windows"/> - <item id="sync_attachment_uploader" hash_code="132657055" content_hash_code="25152853" os_list="linux,windows"/> - <item id="sync_file_system" hash_code="102819690" content_hash_code="52153962" os_list="linux,windows"/> - <item id="sync_http_bridge" hash_code="57144960" content_hash_code="32868346" os_list="linux,windows"/> - <item id="sync_stop_reporter" hash_code="5021348" content_hash_code="56902850" os_list="linux,windows"/> - <item id="test" hash_code="3556498" reserved="1" os_list="all"/> - <item id="test_partial" hash_code="22096011" reserved="1" os_list="all"/> - <item id="thumbnail_source" hash_code="135251783" content_hash_code="31086298" os_list="linux,windows"/> - <item id="translate_url_fetcher" hash_code="137116619" content_hash_code="1127120" os_list="linux,windows"/> - <item id="undefined" hash_code="45578882" reserved="1" os_list="all"/> - <item id="url_fetcher_downloader" hash_code="113231892" content_hash_code="61085066" os_list="linux,windows"/> - <item id="url_prevision_fetcher" hash_code="118389509" content_hash_code="66145513" os_list="linux,windows"/> - <item id="user_info_fetcher" hash_code="22265491" content_hash_code="72016232" os_list="linux,windows"/> - <item id="web_history_counter" hash_code="137457845" content_hash_code="16965644" os_list="linux,windows"/> - <item id="web_history_expire" hash_code="60946824" content_hash_code="137378962" os_list="linux,windows"/> - <item id="web_history_expire_between_dates" hash_code="126122632" content_hash_code="78470619" os_list="linux,windows"/> - <item id="web_history_query" hash_code="17400350" content_hash_code="126490106" os_list="linux,windows"/> - <item id="webrtc_log_upload" hash_code="62443804" content_hash_code="33661169" os_list="linux,windows"/> - <item id="websocket_stream" hash_code="17188928" content_hash_code="7250776" os_list="linux,windows"/> - <item id="webstore_data_fetcher" hash_code="26302604" content_hash_code="24000746" os_list="linux,windows"/> - <item id="webstore_install_helper" hash_code="25921771" content_hash_code="10206361" os_list="linux,windows"/> - <item id="webstore_installer" hash_code="18764319" content_hash_code="11030110" os_list="linux,windows"/> - <item id="webui_content_scripts_download" hash_code="100545943" content_hash_code="119898059" os_list="linux,windows"/> + <item id="CRD_ice_config_request" hash_code="49825319" type="0" content_hash_code="8740825" os_list="linux,windows" file_path="remoting/protocol/http_ice_config_request.cc"/> + <item id="CRD_relay_session_request" hash_code="24058523" type="0" content_hash_code="36997811" os_list="linux,windows" file_path="remoting/protocol/port_allocator.cc"/> + <item id="CRD_telemetry_log" hash_code="18670926" type="0" content_hash_code="49025478" os_list="linux,windows" file_path="remoting/base/telemetry_log_writer.cc"/> + <item id="accounts_image_fetcher" hash_code="98658519" type="0" content_hash_code="45432230" os_list="linux,windows" file_path="components/signin/core/browser/account_fetcher_service.cc"/> + <item id="adb_client_socket" hash_code="87775794" type="0" content_hash_code="56654828" os_list="linux,windows" file_path="chrome/browser/devtools/device/adb/adb_client_socket.cc"/> + <item id="affiliation_lookup" hash_code="111904019" type="0" content_hash_code="81061452" os_list="linux,windows" file_path="components/password_manager/core/browser/android_affiliation/affiliation_fetcher.cc"/> + <item id="android_device_manager_socket" hash_code="37249086" type="0" content_hash_code="6436865" os_list="linux,windows" file_path="chrome/browser/devtools/device/android_device_manager.cc"/> + <item id="android_web_socket" hash_code="39356976" type="0" content_hash_code="12310113" os_list="linux,windows" file_path="chrome/browser/devtools/device/android_web_socket.cc"/> + <item id="appcache_update_job" hash_code="25790702" type="0" content_hash_code="27424887" os_list="linux,windows" file_path="content/browser/appcache/appcache_update_request_base.cc"/> + <item id="asset_links" hash_code="89771989" type="0" content_hash_code="72216357" os_list="linux,windows" file_path="components/password_manager/core/browser/site_affiliation/asset_link_retriever.cc"/> + <item id="autofill_query" hash_code="88863520" type="0" content_hash_code="15563339" os_list="linux,windows" file_path="components/autofill/core/browser/autofill_download_manager.cc"/> + <item id="autofill_upload" hash_code="104798869" type="0" content_hash_code="110634763" os_list="linux,windows" file_path="components/autofill/core/browser/autofill_download_manager.cc"/> + <item id="background_fetch_context" hash_code="16469669" type="0" content_hash_code="52235434" os_list="linux,windows" file_path="content/browser/background_fetch/background_fetch_delegate_proxy.cc"/> + <item id="background_performance_tracer" hash_code="84575287" type="0" content_hash_code="120154250" os_list="linux,windows" file_path="chrome/browser/tracing/crash_service_uploader.cc"/> + <item id="blink_extension_resource_loader" hash_code="84165821" type="0" content_hash_code="3695143" os_list="linux,windows" file_path="content/renderer/loader/web_url_loader_impl.cc"/> + <item id="blink_resource_loader" hash_code="101845102" type="0" content_hash_code="75331172" os_list="linux,windows" file_path="content/renderer/loader/web_url_loader_impl.cc"/> + <item id="blob_read" hash_code="112303907" type="0" content_hash_code="135449692" os_list="linux,windows" file_path="storage/browser/blob/blob_url_request_job_factory.cc"/> + <item id="blob_reader" hash_code="5154306" type="0" content_hash_code="39702178" os_list="linux,windows" file_path="extensions/browser/blob_reader.cc"/> + <item id="bluetooth_socket" hash_code="94099818" type="0" content_hash_code="30932349" os_list="linux,windows" file_path="device/bluetooth/bluetooth_socket_net.cc"/> + <item id="brandcode_config" hash_code="109679553" type="0" content_hash_code="128843792" os_list="linux,windows" file_path="chrome/browser/profile_resetter/brandcode_config_fetcher.cc"/> + <item id="captive_portal_service" hash_code="88754904" type="0" content_hash_code="70737580" os_list="linux,windows" file_path="chrome/browser/captive_portal/captive_portal_service.cc"/> + <item id="cast_channel_send" hash_code="103172229" type="0" content_hash_code="33946302" os_list="linux,windows" file_path="extensions/browser/api/cast_channel/cast_channel_api.cc"/> + <item id="cast_keep_alive_delegate" hash_code="134755844" type="0" content_hash_code="66118796" os_list="linux,windows" file_path="components/cast_channel/keep_alive_delegate.cc"/> + <item id="cast_message_handler" hash_code="87558948" type="0" content_hash_code="49684899" os_list="linux,windows" file_path="components/cast_channel/cast_message_handler.cc"/> + <item id="cast_socket" hash_code="115192205" type="0" content_hash_code="63056899" os_list="linux,windows" file_path="components/cast_channel/cast_socket.cc"/> + <item id="cast_udp_transport" hash_code="5576536" type="0" content_hash_code="107643273" os_list="linux,windows" file_path="media/cast/net/udp_transport_impl.cc"/> + <item id="certificate_verifier" hash_code="113553577" type="0" content_hash_code="62346354" os_list="linux,windows" file_path="net/cert_net/cert_net_fetcher_impl.cc"/> + <item id="chrome_apps_socket_api" hash_code="8591273" type="0" content_hash_code="70868355" os_list="linux,windows" file_path="extensions/browser/api/socket/socket.cc"/> + <item id="chrome_cleaner" hash_code="27071967" type="0" content_hash_code="111240292" os_list="windows" file_path="chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_fetcher_win.cc"/> + <item id="chrome_expect_ct_reporter" hash_code="57276415" type="0" content_hash_code="137551346" os_list="linux,windows" file_path="chrome/browser/ssl/chrome_expect_ct_reporter.cc"/> + <item id="chrome_feedback_report_app" hash_code="134729048" type="0" content_hash_code="73916972" os_list="linux,windows" file_path="components/feedback/feedback_uploader.cc"/> + <item id="chrome_variations_service" hash_code="115188287" type="0" content_hash_code="32485683" os_list="linux,windows" file_path="components/variations/service/variations_service.cc"/> + <item id="client_download_request" hash_code="125522256" type="0" content_hash_code="23897505" os_list="linux,windows" file_path="chrome/browser/safe_browsing/download_protection/check_client_download_request.cc"/> + <item id="cloud_print" hash_code="111712433" type="2" content_hash_code="60926140" os_list="linux,windows" semantics_fields="1,5" policy_fields="-1,3,4" file_path="chrome/service/cloud_print/cloud_print_url_fetcher.cc"/> + <item id="cloud_print_backend" hash_code="71578042" type="1" second_id="111712433" content_hash_code="85425333" os_list="linux,windows" semantics_fields="2,3,4" file_path="chrome/service/cloud_print/cloud_print_proxy_backend.cc"/> + <item id="cloud_print_privet_register" hash_code="24978481" type="0" content_hash_code="131359002" os_list="linux,windows" file_path="chrome/browser/printing/cloud_print/gcd_api_flow_impl.cc"/> + <item id="cloud_print_proxy" hash_code="50859288" type="1" second_id="111712433" content_hash_code="90868083" os_list="linux,windows" semantics_fields="2,3,4" file_path="chrome/service/cloud_print/cloud_print_proxy.cc"/> + <item id="cloud_print_search" hash_code="132055347" type="0" content_hash_code="123783474" os_list="linux,windows" file_path="chrome/browser/printing/cloud_print/gcd_api_flow_impl.cc"/> + <item id="component_updater_utils" hash_code="125596241" type="0" content_hash_code="12311195" os_list="linux,windows" file_path="components/update_client/utils.cc"/> + <item id="content_hash_verification_job" hash_code="64733114" type="0" content_hash_code="127912411" os_list="linux,windows" file_path="extensions/browser/content_hash_fetcher.cc"/> + <item id="content_resource_fetcher" hash_code="70796791" type="0" deprecated="2017-09-16" content_hash_code="135648626" file_path=""/> + <item id="content_suggestion_get_favicon" hash_code="16653985" type="0" content_hash_code="134280933" os_list="linux,windows" file_path="components/ntp_snippets/content_suggestions_service.cc"/> + <item id="credenential_avatar" hash_code="53695122" type="0" content_hash_code="113035371" os_list="linux,windows" file_path="chrome/browser/ui/passwords/account_avatar_fetcher.cc"/> + <item id="cros_recovery_image_download" hash_code="101725581" type="0" content_hash_code="23088027" os_list="linux,windows" file_path="chrome/browser/extensions/api/image_writer_private/write_from_url_operation.cc"/> + <item id="cryptauth_device_sync_tickle" hash_code="96565489" type="1" second_id="29188932" content_hash_code="115714668" os_list="linux,windows" semantics_fields="1,2,3,4,5" policy_fields="3,4" file_path="components/proximity_auth/webui/reachable_phone_flow.cc"/> + <item id="cryptauth_enrollment_flow_finish" hash_code="54836939" type="1" second_id="29188932" content_hash_code="17060642" os_list="linux,windows" semantics_fields="1,2,3,4,5" policy_fields="3,4" file_path="components/cryptauth/cryptauth_client_impl.cc"/> + <item id="cryptauth_enrollment_flow_setup" hash_code="84889397" type="1" second_id="29188932" content_hash_code="128348931" os_list="linux,windows" semantics_fields="1,2,3,4,5" policy_fields="3,4" file_path="components/cryptauth/cryptauth_client_impl.cc"/> + <item id="cryptauth_find_eligible_for_promotion" hash_code="20053290" type="1" second_id="29188932" content_hash_code="93687383" os_list="linux,windows" semantics_fields="1,2,3,4,5" policy_fields="3,4" file_path="components/cryptauth/cryptauth_client_impl.cc"/> + <item id="cryptauth_find_eligible_unlock_devices" hash_code="120000562" type="1" second_id="29188932" content_hash_code="46773475" os_list="linux,windows" semantics_fields="1,2,3,4,5" policy_fields="3,4" file_path="components/cryptauth/cryptauth_client_impl.cc"/> + <item id="cryptauth_get_my_devices" hash_code="136498680" type="1" second_id="29188932" content_hash_code="73842435" os_list="linux,windows" semantics_fields="1,2,3,4,5" policy_fields="3,4" file_path="components/cryptauth/cryptauth_device_manager.cc"/> + <item id="cryptauth_toggle_easyunlock" hash_code="25204343" type="1" second_id="29188932" content_hash_code="13570943" os_list="linux,windows" semantics_fields="1,2,3,4,5" policy_fields="3,4" file_path="components/cryptauth/cryptauth_client_impl.cc"/> + <item id="data_reduction_proxy_config" hash_code="485305" type="0" content_hash_code="134075813" os_list="linux,windows" file_path="components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc"/> + <item id="data_reduction_proxy_pingback" hash_code="68561428" type="0" content_hash_code="78407792" os_list="linux,windows" file_path="components/data_reduction_proxy/content/browser/data_reduction_proxy_pingback_client_impl.cc"/> + <item id="data_reduction_proxy_secure_proxy_check" hash_code="131236802" type="0" content_hash_code="122297136" os_list="linux,windows" file_path="components/data_reduction_proxy/core/browser/secure_proxy_checker.cc"/> + <item id="data_reduction_proxy_warmup" hash_code="8250451" type="0" content_hash_code="6321249" os_list="linux,windows" file_path="components/data_reduction_proxy/core/browser/warmup_url_fetcher.cc"/> + <item id="desktop_ios_promotion" hash_code="13694792" type="0" content_hash_code="19776951" os_list="windows" file_path="chrome/browser/ui/desktop_ios_promotion/sms_service.cc"/> + <item id="device_geolocation_request" hash_code="77673751" type="0" deprecated="2017-10-20" content_hash_code="97181773" file_path=""/> + <item id="device_management_service" hash_code="117782019" type="0" content_hash_code="127535409" os_list="linux,windows" file_path="components/policy/core/common/cloud/device_management_service.cc"/> + <item id="devtools_free_data_source" hash_code="22774132" type="0" content_hash_code="136324050" os_list="linux,windows" file_path="chrome/browser/ui/webui/devtools_ui.cc"/> + <item id="devtools_handle_front_end_messages" hash_code="135636011" type="0" content_hash_code="18422190" os_list="linux,windows" file_path="content/shell/browser/shell_devtools_bindings.cc"/> + <item id="devtools_hard_coded_data_source" hash_code="111565057" type="0" content_hash_code="46074423" os_list="linux,windows" file_path="chrome/browser/ui/webui/devtools_ui.cc"/> + <item id="devtools_http_handler" hash_code="49160454" type="0" content_hash_code="88414393" os_list="linux,windows" file_path="content/browser/devtools/devtools_http_handler.cc"/> + <item id="devtools_interceptor" hash_code="98123737" type="0" content_hash_code="19053470" os_list="linux,windows" file_path="content/browser/devtools/devtools_url_interceptor_request_job.cc"/> + <item id="devtools_network_resource" hash_code="129652775" type="0" content_hash_code="24059212" os_list="linux,windows" file_path="chrome/browser/devtools/devtools_ui_bindings.cc"/> + <item id="dial_get_app_info" hash_code="15952025" type="0" content_hash_code="90542080" os_list="linux,windows" file_path="chrome/browser/media/router/discovery/dial/dial_app_info_fetcher.cc"/> + <item id="dial_get_device_description" hash_code="50422598" type="0" content_hash_code="129827780" os_list="linux,windows" file_path="chrome/browser/media/router/discovery/dial/device_description_fetcher.cc"/> + <item id="dns_transaction" hash_code="79227717" type="0" content_hash_code="132206495" os_list="linux,windows" file_path="net/dns/dns_transaction.cc"/> + <item id="dom_distiller" hash_code="3989826" type="0" content_hash_code="106153970" os_list="linux,windows" file_path="components/dom_distiller/core/distiller_url_fetcher.cc"/> + <item id="domain_reliability_report_upload" hash_code="108804096" type="0" content_hash_code="35902036" os_list="linux,windows" file_path="components/domain_reliability/uploader.cc"/> + <item id="domain_security_policy" hash_code="77597059" type="0" content_hash_code="30916983" os_list="linux,windows" file_path="chrome/browser/profiles/profile_io_data.cc"/> + <item id="doodle_fetcher" hash_code="97199008" type="0" deprecated="2017-08-28" content_hash_code="87981692" file_path=""/> + <item id="doodle_service" hash_code="41154842" type="0" deprecated="2017-08-28" content_hash_code="28273962" file_path=""/> + <item id="download_manager_resume" hash_code="35380758" type="0" content_hash_code="41227674" os_list="linux,windows" file_path="content/browser/download/download_item_impl.cc"/> + <item id="download_web_contents_frame" hash_code="56351037" type="0" content_hash_code="3657889" os_list="linux,windows" file_path="content/browser/web_contents/web_contents_impl.cc"/> + <item id="downloads_api_run_async" hash_code="121068967" type="0" content_hash_code="87443585" os_list="linux,windows" file_path="chrome/browser/extensions/api/downloads/downloads_api.cc"/> + <item id="drag_download_file" hash_code="95910019" type="0" content_hash_code="126492858" os_list="linux,windows" file_path="content/browser/download/drag_download_file.cc"/> + <item id="extension_blacklist" hash_code="59592717" type="0" content_hash_code="116742516" os_list="linux,windows" file_path="chrome/browser/extensions/blacklist_state_fetcher.cc"/> + <item id="extension_crx_fetcher" hash_code="21145003" type="0" content_hash_code="79150319" os_list="linux,windows" file_path="extensions/browser/updater/extension_downloader.cc"/> + <item id="extension_install_signer" hash_code="50464499" type="0" content_hash_code="88088656" os_list="linux,windows" file_path="chrome/browser/extensions/install_signer.cc"/> + <item id="extension_manifest_fetcher" hash_code="5151071" type="0" content_hash_code="57885402" os_list="linux,windows" file_path="extensions/browser/updater/extension_downloader.cc"/> + <item id="external_policy_fetcher" hash_code="9459438" type="0" content_hash_code="64260484" os_list="linux,windows" file_path="components/policy/core/common/cloud/external_policy_data_fetcher.cc"/> + <item id="family_info" hash_code="30913825" type="0" content_hash_code="25369370" os_list="linux,windows" file_path="chrome/browser/supervised_user/child_accounts/family_info_fetcher.cc"/> + <item id="favicon_loader" hash_code="112189210" type="0" content_hash_code="70773116" os_list="linux,windows" file_path="content/renderer/loader/web_url_loader_impl.cc"/> + <item id="gaia_auth_check_connection_info" hash_code="4598626" type="0" content_hash_code="57347000" os_list="linux,windows" file_path="google_apis/gaia/gaia_auth_fetcher.cc"/> + <item id="gaia_auth_exchange_cookies" hash_code="134289752" type="0" content_hash_code="66433230" os_list="linux,windows" file_path="google_apis/gaia/gaia_auth_fetcher.cc"/> + <item id="gaia_auth_exchange_device_id" hash_code="39877119" type="0" content_hash_code="61857947" os_list="linux,windows" file_path="google_apis/gaia/gaia_auth_fetcher.cc"/> + <item id="gaia_auth_fetch_for_uber" hash_code="97978464" type="0" content_hash_code="28006265" os_list="linux,windows" file_path="google_apis/gaia/gaia_auth_fetcher.cc"/> + <item id="gaia_auth_get_user_info" hash_code="82167736" type="0" content_hash_code="4695017" os_list="linux,windows" file_path="google_apis/gaia/gaia_auth_fetcher.cc"/> + <item id="gaia_auth_list_accounts" hash_code="35565745" type="0" content_hash_code="93669150" os_list="linux,windows" file_path="google_apis/gaia/gaia_auth_fetcher.cc"/> + <item id="gaia_auth_log_out" hash_code="116426676" type="0" content_hash_code="91154233" os_list="linux,windows" file_path="google_apis/gaia/gaia_auth_fetcher.cc"/> + <item id="gaia_auth_login" hash_code="91597383" type="0" content_hash_code="111911548" os_list="linux,windows" file_path="google_apis/gaia/gaia_auth_fetcher.cc"/> + <item id="gaia_auth_merge_sessions" hash_code="26216847" type="0" content_hash_code="30423843" os_list="linux,windows" file_path="google_apis/gaia/gaia_auth_fetcher.cc"/> + <item id="gaia_auth_revoke_token" hash_code="133982351" type="0" content_hash_code="96665330" os_list="linux,windows" file_path="google_apis/gaia/gaia_auth_fetcher.cc"/> + <item id="gaia_cookie_manager_external_cc_result" hash_code="4300475" type="0" content_hash_code="31188375" os_list="linux,windows" file_path="components/signin/core/browser/gaia_cookie_manager_service.cc"/> + <item id="gaia_oauth_client_get_token_info" hash_code="32585152" type="0" content_hash_code="128143346" os_list="linux,windows" file_path="google_apis/gaia/gaia_oauth_client.cc"/> + <item id="gaia_oauth_client_get_tokens" hash_code="5637379" type="0" content_hash_code="12099176" os_list="linux,windows" file_path="google_apis/gaia/gaia_oauth_client.cc"/> + <item id="gaia_oauth_client_get_user_info" hash_code="83476155" type="0" content_hash_code="35159007" os_list="linux,windows" file_path="google_apis/gaia/gaia_oauth_client.cc"/> + <item id="gaia_oauth_client_refresh_token" hash_code="82462683" type="0" content_hash_code="22305252" os_list="linux,windows" file_path="google_apis/gaia/gaia_oauth_client.cc"/> + <item id="gcm_channel_status_request" hash_code="18300705" type="0" content_hash_code="53862393" os_list="linux,windows" file_path="components/gcm_driver/gcm_channel_status_request.cc"/> + <item id="gcm_checkin" hash_code="65957842" type="0" content_hash_code="98259579" os_list="linux,windows" file_path="google_apis/gcm/engine/checkin_request.cc"/> + <item id="gcm_registration" hash_code="61656965" type="0" content_hash_code="113670632" os_list="linux,windows" file_path="google_apis/gcm/engine/registration_request.cc"/> + <item id="gcm_subscription" hash_code="56434025" type="0" content_hash_code="61632174" os_list="linux,windows" file_path="components/ntp_snippets/breaking_news/subscription_json_request.cc"/> + <item id="gcm_unregistration" hash_code="119542033" type="0" content_hash_code="30144127" os_list="linux,windows" file_path="google_apis/gcm/engine/unregistration_request.cc"/> + <item id="geo_language_provider" hash_code="52821843" type="1" second_id="96590038" content_hash_code="104675663" os_list="linux,windows" semantics_fields="1" policy_fields="3,4" file_path="components/language/content/browser/geo_language_provider.cc"/> + <item id="google_url_tracker" hash_code="5492492" type="0" content_hash_code="54474899" os_list="linux,windows" file_path="components/google/core/browser/google_url_tracker.cc"/> + <item id="headless_url_request" hash_code="29865866" type="0" content_hash_code="76700151" os_list="linux,windows" file_path="headless/public/util/http_url_fetcher.cc"/> + <item id="history_notice_utils_notice" hash_code="102595701" type="1" second_id="110307337" content_hash_code="130829410" os_list="linux,windows" semantics_fields="2,3,4" policy_fields="4" file_path="components/browsing_data/core/history_notice_utils.cc"/> + <item id="history_notice_utils_popup" hash_code="80832574" type="1" second_id="110307337" content_hash_code="30618510" os_list="linux,windows" semantics_fields="2,3,4" policy_fields="4" file_path="components/browsing_data/core/history_notice_utils.cc"/> + <item id="http_server_error_response" hash_code="32197336" type="0" content_hash_code="61082230" os_list="linux,windows" file_path="net/server/http_server.cc"/> + <item id="icon_cacher" hash_code="103133150" type="0" content_hash_code="116368348" os_list="linux,windows" file_path="components/ntp_tiles/icon_cacher_impl.cc"/> + <item id="icon_catcher_get_large_icon" hash_code="44494884" type="0" content_hash_code="98262037" os_list="linux,windows" file_path="components/ntp_tiles/icon_cacher_impl.cc"/> + <item id="indexed_db_internals_handler" hash_code="131180348" type="0" content_hash_code="59026406" os_list="linux,windows" file_path="content/browser/indexed_db/indexed_db_internals_ui.cc"/> + <item id="intranet_redirect_detector" hash_code="21785164" type="0" content_hash_code="62025595" os_list="linux,windows" file_path="chrome/browser/intranet_redirect_detector.cc"/> + <item id="invalidation_service" hash_code="72354423" type="0" content_hash_code="78425687" os_list="linux,windows" file_path="components/invalidation/impl/gcm_network_channel.cc"/> + <item id="lib_address_input" hash_code="50816767" type="0" content_hash_code="57977576" os_list="linux,windows" file_path="third_party/libaddressinput/chromium/chrome_metadata_source.cc"/> + <item id="logo_tracker" hash_code="36859107" type="0" content_hash_code="67588075" os_list="linux,windows" file_path="components/search_provider_logos/logo_tracker.cc"/> + <item id="metrics_report_ukm" hash_code="727478" type="0" content_hash_code="40919254" os_list="linux,windows" file_path="components/metrics/net/net_metrics_log_uploader.cc"/> + <item id="metrics_report_uma" hash_code="727528" type="0" content_hash_code="10176197" os_list="linux,windows" file_path="components/metrics/net/net_metrics_log_uploader.cc"/> + <item id="missing" hash_code="77012883" type="0" reserved="1" os_list="linux,windows" file_path=""/> + <item id="mojo_context_state" hash_code="93232258" type="0" deprecated="2017-10-20" content_hash_code="124821232" file_path=""/> + <item id="navigation_url_loader" hash_code="63171670" type="0" content_hash_code="129352907" os_list="linux,windows" file_path="content/browser/loader/navigation_url_loader_network_service.cc"/> + <item id="net_error_helper" hash_code="60071001" type="0" content_hash_code="68322861" os_list="linux,windows" file_path="chrome/renderer/net/net_error_helper.cc"/> + <item id="network_location_provider" hash_code="23472048" type="1" second_id="96590038" content_hash_code="41087976" os_list="linux,windows" semantics_fields="1" policy_fields="3,4" file_path="device/geolocation/network_location_provider.cc"/> + <item id="network_location_request" hash_code="96590038" type="2" content_hash_code="59824433" os_list="linux,windows" semantics_fields="2,3,4,5" policy_fields="-1" file_path="device/geolocation/network_location_request.cc"/> + <item id="network_time_component" hash_code="46188932" type="0" content_hash_code="28051857" os_list="linux,windows" file_path="components/network_time/network_time_tracker.cc"/> + <item id="notification_image_reporter" hash_code="70126372" type="0" content_hash_code="29754543" os_list="linux,windows" file_path="chrome/browser/safe_browsing/notification_image_reporter.cc"/> + <item id="ntp_contextual_suggestions_fetch" hash_code="95711309" type="0" content_hash_code="29742597" os_list="linux,windows" file_path="components/ntp_snippets/contextual/contextual_json_request.cc"/> + <item id="ntp_snippets_fetch" hash_code="15418154" type="0" content_hash_code="10078959" os_list="linux,windows" file_path="components/ntp_snippets/remote/json_request.cc"/> + <item id="oauth2_access_token_fetcher" hash_code="27915688" type="0" content_hash_code="33501872" os_list="linux,windows" file_path="google_apis/gaia/oauth2_access_token_fetcher_impl.cc"/> + <item id="oauth2_api_call_flow" hash_code="29188932" type="2" content_hash_code="108831236" os_list="linux,windows" policy_fields="-1" file_path="google_apis/gaia/oauth2_api_call_flow.cc"/> + <item id="oauth2_mint_token_flow" hash_code="1112842" type="1" second_id="29188932" content_hash_code="91581432" os_list="linux,windows" semantics_fields="1,2,3,4,5" policy_fields="3,4" file_path="google_apis/gaia/oauth2_mint_token_flow.cc"/> + <item id="ocsp_start_url_request" hash_code="60921996" type="0" content_hash_code="24127780" os_list="linux" file_path="net/cert_net/nss_ocsp.cc"/> + <item id="offline_prefetch" hash_code="19185953" type="0" content_hash_code="57248156" os_list="linux,windows" file_path="components/offline_pages/core/prefetch/prefetch_request_fetcher.cc"/> + <item id="omnibox_navigation_observer" hash_code="61684939" type="0" content_hash_code="70941231" os_list="linux,windows" file_path="chrome/browser/ui/omnibox/chrome_omnibox_navigation_observer.cc"/> + <item id="omnibox_prefetch_image" hash_code="109200878" type="0" content_hash_code="107906693" os_list="linux,windows" file_path="chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc"/> + <item id="omnibox_result_change" hash_code="73107389" type="0" content_hash_code="24802647" os_list="linux,windows" file_path="chrome/browser/ui/omnibox/chrome_omnibox_client.cc"/> + <item id="omnibox_suggest" hash_code="47815025" type="0" content_hash_code="86297726" os_list="linux,windows" file_path="components/omnibox/browser/search_provider.cc"/> + <item id="omnibox_suggest_deletion" hash_code="84212388" type="0" content_hash_code="24981550" os_list="linux,windows" file_path="components/omnibox/browser/base_search_provider.cc"/> + <item id="omnibox_zerosuggest" hash_code="7687691" type="0" content_hash_code="119419625" os_list="linux,windows" file_path="components/omnibox/browser/contextual_suggestions_service.cc"/> + <item id="omnibox_zerosuggest_experimental" hash_code="3813491" type="0" content_hash_code="22929259" os_list="linux,windows" file_path="components/omnibox/browser/contextual_suggestions_service.cc"/> + <item id="one_google_bar_service" hash_code="78917933" type="0" content_hash_code="46527252" os_list="linux,windows" file_path="chrome/browser/search/one_google_bar/one_google_bar_fetcher_impl.cc"/> + <item id="open_search" hash_code="107267424" type="0" content_hash_code="25715812" os_list="linux,windows" file_path="components/search_engines/template_url_fetcher.cc"/> + <item id="parallel_download_job" hash_code="135118587" type="0" content_hash_code="105330419" os_list="linux,windows" file_path="content/browser/download/parallel_download_job.cc"/> + <item id="password_protection_request" hash_code="66322287" type="0" content_hash_code="21270837" os_list="linux,windows" file_path="components/safe_browsing/password_protection/password_protection_request.cc"/> + <item id="payment_instrument_icon_fetcher" hash_code="73309970" type="0" deprecated="2017-09-16" content_hash_code="84709873" file_path=""/> + <item id="payment_manifest_downloader" hash_code="84045030" type="0" content_hash_code="19293316" os_list="linux,windows" file_path="components/payments/core/payment_manifest_downloader.cc"/> + <item id="payments_sync_cards" hash_code="95588446" type="0" content_hash_code="56526513" os_list="linux,windows" file_path="components/autofill/core/browser/payments/payments_client.cc"/> + <item id="pdf_plugin_placeholder" hash_code="56866367" type="0" content_hash_code="16907221" os_list="linux,windows" file_path="chrome/browser/plugins/pdf_plugin_placeholder_observer.cc"/> + <item id="pepper_tcp_socket" hash_code="120623198" type="0" content_hash_code="55474823" os_list="linux,windows" file_path="content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc"/> + <item id="permission_reporting" hash_code="131741641" type="0" content_hash_code="7213535" os_list="linux,windows" file_path="chrome/browser/safe_browsing/permission_reporter.cc"/> + <item id="permission_request_creator" hash_code="43206794" type="0" content_hash_code="73571699" os_list="linux,windows" file_path="chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary.cc"/> + <item id="persist_blob_to_indexed_db" hash_code="32030464" type="0" content_hash_code="35410079" os_list="linux,windows" file_path="content/browser/indexed_db/indexed_db_backing_store.cc"/> + <item id="plugins_resource_service" hash_code="49601082" type="0" content_hash_code="6877335" os_list="linux,windows" file_path="chrome/browser/plugins/plugins_resource_service.cc"/> + <item id="popular_sites_fetch" hash_code="50755044" type="0" content_hash_code="6910083" os_list="linux,windows" file_path="components/ntp_tiles/popular_sites_impl.cc"/> + <item id="port_forwarding_controller_socket" hash_code="95075845" type="0" content_hash_code="122163428" os_list="linux,windows" file_path="chrome/browser/devtools/device/port_forwarding_controller.cc"/> + <item id="ppapi_download_request" hash_code="135967426" type="0" content_hash_code="110461402" os_list="linux,windows" file_path="chrome/browser/safe_browsing/download_protection/ppapi_download_request.cc"/> + <item id="prefetch_download" hash_code="44583172" type="0" content_hash_code="100587691" os_list="linux,windows" file_path="components/offline_pages/core/prefetch/prefetch_downloader_impl.cc"/> + <item id="printer_job_handler" hash_code="67638271" type="1" second_id="111712433" content_hash_code="75712693" os_list="linux,windows" semantics_fields="2,3,4" file_path="chrome/service/cloud_print/printer_job_handler.cc"/> + <item id="privet_http_impl" hash_code="71251498" type="0" content_hash_code="107348604" os_list="linux,windows" file_path="chrome/browser/printing/cloud_print/privet_http_impl.cc"/> + <item id="profile_avatar" hash_code="51164680" type="0" content_hash_code="113550845" os_list="linux,windows" file_path="chrome/browser/profiles/profile_avatar_downloader.cc"/> + <item id="profile_resetter_upload" hash_code="105330607" type="0" content_hash_code="129329171" os_list="linux,windows" file_path="chrome/browser/profile_resetter/reset_report_uploader.cc"/> + <item id="proxy_script_fetcher" hash_code="37531401" type="0" content_hash_code="31866133" os_list="linux,windows" file_path="net/proxy_resolution/pac_file_fetcher_impl.cc"/> + <item id="ranker_url_fetcher" hash_code="95682324" type="0" content_hash_code="45958626" os_list="linux,windows" file_path="components/assist_ranker/ranker_url_fetcher.cc"/> + <item id="rappor_report" hash_code="44606780" type="0" content_hash_code="111287826" os_list="linux,windows" file_path="components/rappor/log_uploader.cc"/> + <item id="refresh_token_annotation_request" hash_code="7433837" type="1" second_id="29188932" deprecated="2018-01-17" content_hash_code="137103383" file_path=""/> + <item id="remote_suggestions_provider" hash_code="49544361" type="0" content_hash_code="126329742" os_list="linux,windows" file_path="components/ntp_snippets/remote/cached_image_fetcher.cc"/> + <item id="render_view_context_menu" hash_code="25844439" type="0" content_hash_code="69471170" os_list="linux,windows" file_path="chrome/browser/renderer_context_menu/render_view_context_menu.cc"/> + <item id="renderer_initiated_download" hash_code="116443055" type="0" content_hash_code="37846436" os_list="linux,windows" file_path="content/browser/frame_host/render_frame_message_filter.cc"/> + <item id="reporting" hash_code="109891200" type="0" content_hash_code="125758928" os_list="linux,windows" file_path="net/reporting/reporting_uploader.cc"/> + <item id="resource_dispatcher_host" hash_code="81157007" type="0" content_hash_code="35725167" os_list="linux,windows" file_path="content/browser/loader/resource_dispatcher_host_impl.cc"/> + <item id="resource_prefetch" hash_code="110815970" type="0" content_hash_code="39251261" os_list="linux,windows" file_path="chrome/browser/predictors/resource_prefetcher.cc"/> + <item id="rlz_ping" hash_code="99279418" type="0" content_hash_code="102108802" os_list="windows" file_path="rlz/lib/financial_ping.cc"/> + <item id="safe_browsing_backup_request" hash_code="106980485" type="0" content_hash_code="101760679" os_list="linux,windows" file_path="chrome/browser/safe_browsing/protocol_manager.cc"/> + <item id="safe_browsing_cache_collector" hash_code="115907811" type="0" content_hash_code="36392362" os_list="linux,windows" file_path="components/safe_browsing/browser/threat_details_cache.cc"/> + <item id="safe_browsing_certificate_error_reporting" hash_code="66590631" type="0" content_hash_code="50197576" os_list="linux,windows" file_path="components/certificate_reporting/error_reporter.cc"/> + <item id="safe_browsing_chunk_backup_request" hash_code="79957943" type="0" content_hash_code="133850277" os_list="linux,windows" file_path="chrome/browser/safe_browsing/protocol_manager.cc"/> + <item id="safe_browsing_client_side_malware_detector" hash_code="102935425" type="0" content_hash_code="79591279" os_list="linux,windows" file_path="chrome/browser/safe_browsing/client_side_detection_service.cc"/> + <item id="safe_browsing_client_side_phishing_detector" hash_code="1313982" type="0" content_hash_code="50199143" os_list="linux,windows" file_path="chrome/browser/safe_browsing/client_side_detection_service.cc"/> + <item id="safe_browsing_extended_reporting" hash_code="42848942" type="0" content_hash_code="50089173" os_list="linux,windows" file_path="components/safe_browsing/base_ping_manager.cc"/> + <item id="safe_browsing_feedback" hash_code="44583821" type="0" content_hash_code="114076664" os_list="linux,windows" file_path="chrome/browser/safe_browsing/download_protection/download_feedback.cc"/> + <item id="safe_browsing_g4_update" hash_code="75153841" type="0" content_hash_code="112049516" os_list="linux,windows" file_path="components/safe_browsing/db/v4_update_protocol_manager.cc"/> + <item id="safe_browsing_get_full_hash" hash_code="68745894" type="0" content_hash_code="21739198" os_list="linux,windows" file_path="chrome/browser/safe_browsing/protocol_manager.cc"/> + <item id="safe_browsing_incident" hash_code="124950347" type="0" content_hash_code="58481082" os_list="linux,windows" file_path="chrome/browser/safe_browsing/incident_reporting/incident_report_uploader_impl.cc"/> + <item id="safe_browsing_module_loader" hash_code="6019475" type="0" content_hash_code="49511650" os_list="linux,windows" file_path="chrome/browser/safe_browsing/client_side_model_loader.cc"/> + <item id="safe_browsing_v4_get_hash" hash_code="8561691" type="0" content_hash_code="132435617" os_list="linux,windows" file_path="components/safe_browsing/db/v4_get_hash_protocol_manager.cc"/> + <item id="safe_search_url_reporter" hash_code="119677115" type="0" content_hash_code="67393078" os_list="linux,windows" file_path="chrome/browser/supervised_user/experimental/safe_search_url_reporter.cc"/> + <item id="save_file_manager" hash_code="56275203" type="0" content_hash_code="56692339" os_list="linux,windows" file_path="content/browser/download/save_file_manager.cc"/> + <item id="sdch_dictionary_fetch" hash_code="47152935" type="0" deprecated="2017-09-16" content_hash_code="16764294" file_path=""/> + <item id="service_worker_navigation_preload" hash_code="129872904" type="0" content_hash_code="79473248" os_list="linux,windows" file_path="content/browser/service_worker/service_worker_fetch_dispatcher.cc"/> + <item id="service_worker_write_to_cache_job" hash_code="117963307" type="0" content_hash_code="18065724" os_list="linux,windows" file_path="content/browser/service_worker/service_worker_write_to_cache_job.cc"/> + <item id="sigined_exchange_cert_fetcher" hash_code="79442849" type="0" content_hash_code="8138156" os_list="linux,windows" file_path="content/browser/loader/signed_exchange_cert_fetcher.cc"/> + <item id="signed_in_profile_avatar" hash_code="108903331" type="0" content_hash_code="72850619" os_list="linux,windows" file_path="chrome/browser/profiles/profile_downloader.cc"/> + <item id="socket_bio_adapter" hash_code="516551" type="0" content_hash_code="21643352" os_list="linux,windows" file_path="net/socket/socket_bio_adapter.cc"/> + <item id="speech_recognition_downstream" hash_code="26096088" type="0" content_hash_code="120733233" os_list="linux,windows" file_path="content/browser/speech/speech_recognition_engine.cc"/> + <item id="speech_recognition_upstream" hash_code="66846958" type="0" content_hash_code="7706219" os_list="linux,windows" file_path="content/browser/speech/speech_recognition_engine.cc"/> + <item id="spellcheck_hunspell_dictionary" hash_code="117649486" type="0" content_hash_code="45660952" os_list="linux,windows" file_path="chrome/browser/spellchecker/spellcheck_hunspell_dictionary.cc"/> + <item id="spellcheck_lookup" hash_code="132553989" type="0" content_hash_code="27978613" os_list="linux,windows" file_path="components/spellcheck/browser/spelling_service_client.cc"/> + <item id="ssl_hmac_channel_authenticator" hash_code="106124561" type="0" content_hash_code="93707499" os_list="linux,windows" file_path="remoting/protocol/ssl_hmac_channel_authenticator.cc"/> + <item id="ssl_name_mismatch_lookup" hash_code="114468207" type="0" content_hash_code="97619078" os_list="linux,windows" file_path="chrome/browser/ssl/common_name_mismatch_handler.cc"/> + <item id="suggestions_image_manager" hash_code="13211343" type="0" content_hash_code="36271280" os_list="linux,windows" file_path="components/suggestions/image_manager.cc"/> + <item id="suggestions_service" hash_code="35370363" type="0" content_hash_code="66296423" os_list="linux,windows" file_path="components/suggestions/suggestions_service_impl.cc"/> + <item id="supervised_user_refresh_token_fetcher" hash_code="136117054" type="0" content_hash_code="101636136" os_list="linux,windows" file_path="chrome/browser/supervised_user/legacy/supervised_user_refresh_token_fetcher.cc"/> + <item id="supervised_user_url_filter" hash_code="14257952" type="0" content_hash_code="30470003" os_list="linux,windows" file_path="chrome/browser/supervised_user/supervised_user_url_filter.cc"/> + <item id="supervised_users_blacklist" hash_code="78544924" type="0" content_hash_code="10924669" os_list="linux,windows" file_path="chrome/browser/supervised_user/supervised_user_service.cc"/> + <item id="sync_attachment_downloader" hash_code="26372521" type="0" deprecated="2018-02-08" content_hash_code="70097603" file_path=""/> + <item id="sync_attachment_uploader" hash_code="132657055" type="0" deprecated="2018-02-08" content_hash_code="25152853" file_path=""/> + <item id="sync_file_system" hash_code="102819690" type="0" content_hash_code="52153962" os_list="linux,windows" file_path="chrome/browser/sync_file_system/drive_backend/sync_engine.cc"/> + <item id="sync_http_bridge" hash_code="57144960" type="0" content_hash_code="32868346" os_list="linux,windows" file_path="components/sync/engine/net/http_bridge.cc"/> + <item id="sync_stop_reporter" hash_code="5021348" type="0" content_hash_code="56902850" os_list="linux,windows" file_path="components/sync/driver/sync_stopped_reporter.cc"/> + <item id="test" hash_code="3556498" type="0" reserved="1" os_list="linux,windows" file_path=""/> + <item id="test_partial" hash_code="22096011" type="0" reserved="1" os_list="linux,windows" file_path=""/> + <item id="tethering_handler_socket" hash_code="113065062" type="0" content_hash_code="986296" os_list="linux,windows" file_path="content/browser/devtools/protocol/tethering_handler.cc"/> + <item id="thumbnail_source" hash_code="135251783" type="0" content_hash_code="31086298" os_list="linux,windows" file_path="chrome/browser/search/thumbnail_source.cc"/> + <item id="translate_url_fetcher" hash_code="137116619" type="0" content_hash_code="104217506" os_list="linux,windows" file_path="components/translate/core/browser/translate_url_fetcher.cc"/> + <item id="ui_devtools_server" hash_code="4986170" type="0" content_hash_code="62670263" os_list="linux,windows" file_path="components/ui_devtools/devtools_server.cc"/> + <item id="undefined" hash_code="45578882" type="0" reserved="1" os_list="linux,windows" file_path=""/> + <item id="undefined-656607" hash_code="28406789" type="0" reserved="1" os_list="linux,windows" file_path=""/> + <item id="url_fetcher_downloader" hash_code="113231892" type="0" content_hash_code="61085066" os_list="linux,windows" file_path="components/update_client/url_fetcher_downloader.cc"/> + <item id="url_prevision_fetcher" hash_code="118389509" type="0" content_hash_code="66145513" os_list="linux,windows" file_path="content/browser/media/url_provision_fetcher.cc"/> + <item id="user_info_fetcher" hash_code="22265491" type="0" content_hash_code="72016232" os_list="linux,windows" file_path="components/policy/core/common/cloud/user_info_fetcher.cc"/> + <item id="web_history_counter" hash_code="137457845" type="1" second_id="110307337" content_hash_code="49663381" os_list="linux,windows" semantics_fields="2,3,4" policy_fields="4" file_path="components/browsing_data/core/counters/history_counter.cc"/> + <item id="web_history_expire" hash_code="60946824" type="1" second_id="110307337" content_hash_code="92626030" os_list="linux,windows" semantics_fields="2,3,4" policy_fields="4" file_path="components/history/core/browser/browsing_history_service.cc"/> + <item id="web_history_expire_between_dates" hash_code="126122632" type="1" second_id="110307337" content_hash_code="34304787" os_list="linux,windows" semantics_fields="2,3,4" policy_fields="4" file_path="components/history/core/browser/history_service.cc"/> + <item id="web_history_query" hash_code="17400350" type="1" second_id="110307337" content_hash_code="36075147" os_list="linux,windows" semantics_fields="2,3,4" policy_fields="4" file_path="components/history/core/browser/browsing_history_service.cc"/> + <item id="web_history_service" hash_code="110307337" type="2" content_hash_code="16140045" os_list="linux,windows" semantics_fields="1,5" policy_fields="-1,3" file_path="components/history/core/browser/web_history_service.cc"/> + <item id="webrtc_log_upload" hash_code="62443804" type="0" content_hash_code="33661169" os_list="linux,windows" file_path="chrome/browser/media/webrtc/webrtc_log_uploader.cc"/> + <item id="websocket_basic_stream" hash_code="51586722" type="0" content_hash_code="68121427" os_list="linux,windows" file_path="net/websockets/websocket_basic_stream.cc"/> + <item id="websocket_stream" hash_code="17188928" type="0" content_hash_code="7250776" os_list="linux,windows" file_path="net/websockets/websocket_stream.cc"/> + <item id="webstore_data_fetcher" hash_code="26302604" type="0" content_hash_code="24000746" os_list="linux,windows" file_path="chrome/browser/extensions/webstore_data_fetcher.cc"/> + <item id="webstore_install_helper" hash_code="25921771" type="0" content_hash_code="10206361" os_list="linux,windows" file_path="chrome/browser/extensions/webstore_install_helper.cc"/> + <item id="webstore_installer" hash_code="18764319" type="0" content_hash_code="11030110" os_list="linux,windows" file_path="chrome/browser/extensions/webstore_installer.cc"/> + <item id="webui_content_scripts_download" hash_code="100545943" type="0" content_hash_code="119898059" os_list="linux,windows" file_path="extensions/browser/guest_view/web_view/web_ui/web_ui_url_fetcher.cc"/> </annotations>
diff --git a/tools/traffic_annotation/traffic_annotation.proto b/tools/traffic_annotation/traffic_annotation.proto index c2941da2..d00be7e 100644 --- a/tools/traffic_annotation/traffic_annotation.proto +++ b/tools/traffic_annotation/traffic_annotation.proto
@@ -12,7 +12,8 @@ // Describes a specific kind of network traffic based on a fine-grained // semantic classification of all network traffic generated by Chrome. -// Used for auditing purposes. +// Used for auditing purposes. Please refer to +// "/docs/network_traffic_annotations.md" for users guide. message NetworkTrafficAnnotation { // This is a globally unique identifier that must stay unchanged while the // network request carries the same semantic meaning. If the network request @@ -62,18 +63,11 @@ // Meta information about the network request. message TrafficSemantics { - // Justification for an empty AuditPolicy policy. - // Typically this can be either a TODO or a hint that the annotation is - // made upstream in the code. For example, if net::URLFetcher::Create() has - // an annotation, the net::TCPClientSocket() that is used by the URLFetcher - // does not need to be annotated as well. - string empty_policy_justification = 1; - // What component triggers the request. The components should be human // readable and don’t need to reflect the components/ directory. Avoid // abbreviations. - // Examples: spellchecker, component updater, website - string sender = 2; + // Examples: Online Spellcheck, Safe Browsing, WebView. + string sender = 1; // Plaintext description of the network request in language that is // understandable by admins (ideally also users). Please avoid acronyms. @@ -87,21 +81,21 @@ // language. Google returns a list of suggested spellings, which will be // displayed in the context menu. // - A network request that comes from web content (a page the user visits) - string description = 3; + string description = 2; // What triggered the network request. Use a textual description. This // should be a human readable string. // For things that are clearly part of the website (resource load, form // submission, fetch by a service worker,...), you *may* just put “website” // here. - string trigger = 4; + string trigger = 3; // What nature of data is being sent. This should be a human readable // string. Any user data and/or PII should be pointed out. // Examples: “log files from /var/...”, “statistics about foobar”, “the // signature of a form of a website”, “installed extensions and their // version”, “a word on a website the user tapped on” - string data = 5; + string data = 4; enum Destination { // Do not use this value. It's just a placeholder for default value. @@ -112,7 +106,10 @@ // guideline: If the source code has hardcoded that the request goes to // Google (e.g. for ZeroSuggest), use GOOGLE_OWNED_SERVICE. If the request // can go to other domains and is perceived as a part of a website rather - // than a native browser feature, use WEBSITE. In other cases use OTHER. + // than a native browser feature, use WEBSITE. Use LOCAL if the request is + // processed locally and does not go to network, otherwise use OTHER. If + // OTHER is used, please add plain text description in 'destination_other' + // tag. WEBSITE = 1; // A Google owned service, like SafeBrowsing, spellchecking, ... GOOGLE_OWNED_SERVICE = 2; @@ -123,10 +120,10 @@ // need more categories. OTHER = 1000; } - Destination destination = 6; + Destination destination = 5; // Human readable description in case the destination points to OTHER. - string destination_other = 7; + string destination_other = 6; } TrafficSemantics semantics = 3; @@ -159,12 +156,11 @@ string cookies_store = 2; // Human readable description of how to enable/disable a feature that - // triggers this network request by a user. Use “NA”, if no such setting - // exists (e.g. “Disable ‘Use a web service to help resolve spelling - // errors.’ in Chrome’s settings under Advanced”). + // triggers this network request by a user (e.g. “Disable ‘Use a web service + // to help resolve spelling errors.’ in settings under Advanced”). string setting = 3; - // Example policy configuration that disables this network request. + // Policy configuration(s) that disable or limit this network request. // This would be a text serialized protobuf of any enterprise policy. // see out/Debug/gen/components/policy/proto/chrome_settings.proto repeated enterprise_management.ChromeSettingsProto chrome_policy = 4;
diff --git a/tools/uberblame.py b/tools/uberblame.py new file mode 100755 index 0000000..52ff93a --- /dev/null +++ b/tools/uberblame.py
@@ -0,0 +1,643 @@ +#!/usr/bin/env python +# Copyright 2017 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 argparse +import cgi +import colorsys +import difflib +import random +import os +import re +import subprocess +import sys +import tempfile +import textwrap +import webbrowser + + +class TokenContext(object): + """Metadata about a token. + + Attributes: + row: Row index of the token in the data file. + column: Column index of the token in the data file. + token: The token string. + commit: A Commit object that corresponds to the commit that added + this token. + """ + def __init__(self, row, column, token, commit=None): + self.row = row + self.column = column + self.token = token + self.commit = commit + + +class Commit(object): + """Commit data. + + Attributes: + hash: The commit hash. + author_name: The author's name. + author_email: the author's email. + author_date: The date and time the author created this commit. + message: The commit message. + diff: The commit diff. + """ + def __init__(self, hash, author_name, author_email, author_date, message, + diff): + self.hash = hash + self.author_name = author_name + self.author_email = author_email + self.author_date = author_date + self.message = message + self.diff = diff + + +def tokenize_data(data): + """Tokenizes |data|. + + Args: + data: String to tokenize. + + Returns: + A list of TokenContexts. + """ + contexts = [] + in_identifier = False + identifier_start = 0 + identifier = '' + row = 0 + column = 0 + line_contexts = [] + + for c in data + '\n': + if c.isalnum() or c == '_': + if in_identifier: + identifier += c + else: + in_identifier = True + identifier_start = column + identifier = c + else: + if in_identifier: + line_contexts.append( + TokenContext(row, identifier_start, identifier)) + in_identifier = False + if not c.isspace(): + line_contexts.append(TokenContext(row, column, c)) + + if c == '\n': + row += 1 + column = 0 + contexts.append(line_contexts) + line_tokens = [] + line_contexts = [] + else: + column += 1 + return contexts + + +def compute_unified_diff(old_tokens, new_tokens): + """Computes the diff between |old_tokens| and |new_tokens|. + + Args: + old_tokens: Token strings corresponding to the old data. + new_tokens: Token strings corresponding to the new data. + + Returns: + The diff, in unified diff format. + """ + return difflib.unified_diff(old_tokens, new_tokens, n=0, lineterm='') + + +def parse_chunk_header_file_range(file_range): + """Parses a chunk header file range. + + Diff chunk headers have the form: + @@ -<file-range> +<file-range> @@ + File ranges have the form: + <start line number>,<number of lines changed> + + Args: + file_range: A chunk header file range. + + Returns: + A tuple (range_start, range_end). The endpoints are adjusted such that + iterating over [range_start, range_end) will give the changed indices. + """ + if ',' in file_range: + file_range_parts = file_range.split(',') + start = int(file_range_parts[0]) + amount = int(file_range_parts[1]) + if amount == 0: + return (start, start) + return (start - 1, start + amount - 1) + else: + return (int(file_range) - 1, int(file_range)) + + +def compute_changed_token_indices(previous_tokens, current_tokens): + """Computes changed and added tokens. + + Args: + previous_tokens: Tokens corresponding to the old file. + current_tokens: Tokens corresponding to the new file. + + Returns: + A tuple (added_tokens, changed_tokens). + added_tokens: A list of indices into |current_tokens|. + changed_tokens: A map of indices into |current_tokens| to + indices into |previous_tokens|. + """ + prev_file_chunk_end = 0 + prev_patched_chunk_end = 0 + added_tokens = [] + changed_tokens = {} + for line in compute_unified_diff(previous_tokens, current_tokens): + if line.startswith("@@"): + parts = line.split(' ') + removed = parts[1].lstrip('-') + removed_start, removed_end = parse_chunk_header_file_range(removed) + added = parts[2].lstrip('+') + added_start, added_end = parse_chunk_header_file_range(added) + for i in range(added_start, added_end): + added_tokens.append(i) + for i in range(0, removed_start - prev_patched_chunk_end): + changed_tokens[prev_file_chunk_end + i] = prev_patched_chunk_end + i + prev_patched_chunk_end = removed_end + prev_file_chunk_end = added_end + for i in range(0, len(previous_tokens) - prev_patched_chunk_end): + changed_tokens[prev_file_chunk_end + i] = prev_patched_chunk_end + i + return added_tokens, changed_tokens + + +def flatten_nested_list(l): + """Flattens a list and provides a mapping from elements in the list back + into the nested list. + + Args: + l: A list of lists. + + Returns: + A tuple (flattened, index_to_position): + flattened: The flattened list. + index_to_position: A list of pairs (r, c) such that + index_to_position[i] == (r, c); flattened[i] == l[r][c] + """ + flattened = [] + index_to_position = {} + r = 0 + c = 0 + for nested_list in l: + for element in nested_list: + index_to_position[len(flattened)] = (r, c) + flattened.append(element) + c += 1 + r += 1 + c = 0 + return (flattened, index_to_position) + + +def compute_changed_token_positions(previous_tokens, current_tokens): + """Computes changed and added token positions. + + Args: + previous_tokens: A list of lists of token strings. Lines in the file + correspond to the nested lists. + current_tokens: A list of lists of token strings. Lines in the file + correspond to the nested lists. + + Returns: + A tuple (added_token_positions, changed_token_positions): + added_token_positions: A list of pairs that index into |current_tokens|. + changed_token_positions: A map from pairs that index into + |current_tokens| to pairs that index into |previous_tokens|. + """ + flat_previous_tokens, previous_index_to_position = flatten_nested_list( + previous_tokens) + flat_current_tokens, current_index_to_position = flatten_nested_list( + current_tokens) + added_indices, changed_indices = compute_changed_token_indices( + flat_previous_tokens, flat_current_tokens) + added_token_positions = [current_index_to_position[i] for i in added_indices] + changed_token_positions = { + current_index_to_position[current_i]: + previous_index_to_position[changed_indices[current_i]] + for current_i in changed_indices + } + return (added_token_positions, changed_token_positions) + + +def parse_chunks_from_diff(diff): + """Returns a generator of chunk data from a diff. + + Args: + diff: A list of strings, with each string being a line from a diff + in unified diff format. + + Returns: + A generator of tuples (added_lines_start, added_lines_end, + removed_lines, removed_lines_start) + """ + in_chunk = False + chunk_previous = [] + previous_start = None + current_start = None + current_end = None + for line in diff: + if line.startswith('@@'): + if in_chunk: + yield (current_start, current_end, + chunk_previous, previous_start) + parts = line.split(' ') + previous = parts[1].lstrip('-') + previous_start, _ = parse_chunk_header_file_range(previous) + current = parts[2].lstrip('+') + current_start, current_end = parse_chunk_header_file_range(current) + in_chunk = True + chunk_previous = [] + elif in_chunk and line.startswith('-'): + chunk_previous.append(line[1:]) + if current_start != None: + yield (current_start, current_end, + chunk_previous, previous_start) + + +def should_skip_commit(commit): + """Decides if |commit| should be skipped when computing the blame. + + Commit 5d4451e deleted all files in the repo except for DEPS. The + next commit, 1e7896, brought them back. This is a hack to skip + those commits (except for the files they modified). If we did not + do this, changes would be incorrectly attributed to 1e7896. + + Args: + commit: A Commit object. + + Returns: + A boolean indicating if this commit should be skipped. + """ + banned_commits = [ + '1e78967ed2f1937b3809c19d91e7dd62d756d307', + '5d4451ebf298d9d71f716cc0135f465cec41fcd0', + ] + if commit.hash not in banned_commits: + return False + banned_commits_file_exceptions = [ + 'DEPS', + 'chrome/browser/ui/views/file_manager_dialog_browsertest.cc', + ] + for line in commit.diff: + if line.startswith('---') or line.startswith('+++'): + if line.split(' ')[1] in banned_commits_file_exceptions: + return False + elif line.startswith('@@'): + return True + assert False + + +def generate_substrings(file): + """Generates substrings from a file stream, where substrings are + separated by '\0'. + + For example, the input: + 'a\0bc\0\0\0d\0' + would produce the output: + ['a', 'bc', 'd'] + + Args: + file: A readable file. + """ + BUF_SIZE = 448 # Experimentally found to be pretty fast. + data = [] + while True: + buf = file.read(BUF_SIZE) + parts = buf.split('\0') + data.append(parts[0]) + if len(parts) > 1: + joined = ''.join(data) + if joined != '': + yield joined + for i in range(1, len(parts) - 1): + if parts[i] != '': + yield parts[i] + data = [parts[-1]] + if len(buf) < BUF_SIZE: + joined = ''.join(data) + if joined != '': + yield joined + return + + +def generate_commits(git_log_stdout): + """Parses git log output into a stream of Commit objects. + """ + substring_generator = generate_substrings(git_log_stdout) + while True: + hash = substring_generator.next() + author_name = substring_generator.next() + author_email = substring_generator.next() + author_date = substring_generator.next() + message = substring_generator.next() + diff = substring_generator.next().split('\n') + yield Commit(hash, author_name, author_email, author_date, message, diff) + + +def uberblame_aux(file_name, git_log_stdout, data): + """Computes the uberblame of file |file_name|. + + Args: + file_name: File to uberblame. + git_log_stdout: A file object that represents the git log output. + data: A string containing the data of file |file_name|. + + Returns: + A tuple (data, blame). + data: File contents. + blame: A list of TokenContexts. + """ + blame = tokenize_data(data) + + blamed_tokens = 0 + total_tokens = len(blame) + uber_blame = (data, blame[:]) + + for commit in generate_commits(git_log_stdout): + if should_skip_commit(commit): + continue + + offset = 0 + for (added_lines_start, added_lines_end, removed_lines, + removed_lines_start) in parse_chunks_from_diff(commit.diff): + added_lines_start += offset + added_lines_end += offset + previous_contexts = [token_lines + for line_previous in removed_lines + for token_lines in tokenize_data(line_previous)] + previous_tokens = [ + [context.token for context in contexts] + for contexts in previous_contexts + ] + current_contexts = blame[added_lines_start:added_lines_end] + current_tokens = [ + [context.token for context in contexts] + for contexts in current_contexts + ] + added_token_positions, changed_token_positions = ( + compute_changed_token_positions(previous_tokens, current_tokens)) + for r, c in added_token_positions: + current_contexts[r][c].commit = commit + blamed_tokens += 1 + for r, c in changed_token_positions: + pr, pc = changed_token_positions[(r, c)] + previous_contexts[pr][pc] = current_contexts[r][c] + + assert added_lines_start <= added_lines_end <= len(blame) + current_blame_size = len(blame) + blame[added_lines_start:added_lines_end] = previous_contexts + offset += len(blame) - current_blame_size + + assert blame == [] or blame == [[]] + return uber_blame + + +def uberblame(file_name, revision): + """Computes the uberblame of file |file_name|. + + Args: + file_name: File to uberblame. + revision: The revision to start the uberblame at. + + Returns: + A tuple (data, blame). + data: File contents. + blame: A list of TokenContexts. + """ + cmd_git_log = [ + 'git', + 'log', + '--minimal', + '--no-prefix', + '--follow', + '-m', + '--first-parent', + '-p', + '-U0', + '-z', + '--format=%x00%H%x00%an%x00%ae%x00%ad%x00%B', + revision, + '--', + file_name + ] + git_log = subprocess.Popen(cmd_git_log, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + data = subprocess.check_output( + ['git', 'show', '%s:%s' % (revision, file_name)]) + data, blame = uberblame_aux(file_name, git_log.stdout, data) + + _, stderr = git_log.communicate() + if git_log.returncode != 0: + raise subprocess.CalledProcessError(git_log.returncode, cmd_git_log, stderr) + return data, blame + + +def generate_pastel_color(): + (h, l, s) = (random.uniform(0, 1), + random.uniform(0.8, 0.9), + random.uniform(0.5, 1)) + (r, g, b) = colorsys.hls_to_rgb(h, l, s) + return "#%0.2X%0.2X%0.2X" % (int(r*255), int(g*255), int(b*255)) + + +def visualize_uberblame(data, blame): + """Creates and displays a web page to visualize |blame|. + + Args: + data: The data file as returned by uberblame(). + blame: A list of TokenContexts as returned by uberblame(). + """ + # Use the same seed for the color generator on each run so that + # loading the same blame of the same file twice will result in the + # same generated HTML page. + random.seed(0x52937865ec62d1ea) + html = """\ + <html> + <head> + <style> + body { + font-family: "Courier New"; + } + pre { + display: inline; + } + span { + outline: 1pt solid #00000030; + outline-offset: -1pt; + cursor: pointer; + } + #linenums { + text-align: right; + } + #file_display { + position: absolute; + left: 0; + top: 0; + width: 50%%; + height: 100%%; + overflow: scroll; + } + #commit_display_container { + position: absolute; + left: 50%%; + top: 0; + width: 50%%; + height: 100%%; + overflow: scroll; + } + </style> + <script> + commit_data = %s; + function display_commit(hash) { + var e = document.getElementById("commit_display"); + e.innerHTML = commit_data[hash] + } + </script> + </head> + <body> + <div id="file_display"> + <table> + <tbody> + <tr> + <td valign="top" id="linenums"> + <pre>%s</pre> + </td> + <td valign="top"> + <pre>%s</pre> + </td> + </tr> + </tbody> + </table> + </div> + <div id="commit_display_container" valign="top"> + <pre id="commit_display" /> + </div> + </body> + </html> + """ + html = textwrap.dedent(html) + commits = {} + lines = [] + commit_colors = {} + blame_index = 0 + blame = [context for contexts in blame for context in contexts] + row = 0 + lastline = '' + for line in data.split('\n'): + lastline = line + column = 0 + for c in line + '\n': + if blame_index < len(blame): + token_context = blame[blame_index] + if (row == token_context.row and + column == token_context.column + len(token_context.token)): + if (blame_index + 1 == len(blame) or + blame[blame_index].commit.hash != + blame[blame_index + 1].commit.hash): + lines.append('</span>') + blame_index += 1 + if blame_index < len(blame): + token_context = blame[blame_index] + if row == token_context.row and column == token_context.column: + if (blame_index == 0 or + blame[blame_index - 1].commit.hash != + blame[blame_index].commit.hash): + hash = token_context.commit.hash + commits[hash] = token_context.commit + if hash not in commit_colors: + commit_colors[hash] = generate_pastel_color() + color = commit_colors[hash] + lines.append( + ('<span style="background-color: %s" ' + + 'onclick="display_commit("%s")">') % (color, hash)) + lines.append(cgi.escape(c)) + column += 1 + row += 1 + commit_data = ['{'] + commit_display_format = """\ + commit: {hash} + Author: {author_name} <{author_email}> + Date: {author_date} + + {message} + """ + commit_display_format = textwrap.dedent(commit_display_format) + links = re.compile(r'(https?:\/\/\S+)') + for hash in commits: + commit = commits[hash] + commit_display = commit_display_format.format( + hash=hash, + author_name=commit.author_name, + author_email=commit.author_email, + author_date=commit.author_date, + message=commit.message, + ) + commit_display = cgi.escape(commit_display, quote=True) + commit_display = re.sub( + links, '<a href=\\"\\1\\">\\1</a>', commit_display) + commit_display = commit_display.replace('\n', '\\n') + commit_data.append('"%s": "%s",' % (hash, commit_display)) + commit_data.append('}') + commit_data = ''.join(commit_data) + line_nums = range(1, row if lastline.strip() == '' else row + 1) + line_nums = '\n'.join([str(num) for num in line_nums]) + lines = ''.join(lines) + return html % (commit_data, line_nums, lines) + + +def show_visualization(html): + """Display |html| in a web browser. + + Args: + html: The contents of the file to display, as a string. + """ + # Keep the temporary file around so the browser has time to open it. + # TODO(thomasanderson): spin up a temporary web server to serve this + # file so we don't have to leak it. + html_file = tempfile.NamedTemporaryFile(delete=False, suffix='.html') + html_file.write(html) + html_file.flush() + if sys.platform.startswith('linux'): + # Don't show any messages when starting the browser. + saved_stdout = os.dup(1) + saved_stderr = os.dup(2) + os.close(1) + os.close(2) + os.open(os.devnull, os.O_RDWR) + os.open(os.devnull, os.O_RDWR) + webbrowser.open('file://' + html_file.name) + if sys.platform.startswith('linux'): + os.dup2(saved_stdout, 1) + os.dup2(saved_stderr, 2) + os.close(saved_stdout) + os.close(saved_stderr) + + +def main(): + parser = argparse.ArgumentParser( + description='Show what revision last modified each token of a file') + parser.add_argument('revision', default='HEAD', nargs='?', + help='Show only commits starting from a revision.') + parser.add_argument('file', help='The file to uberblame.') + args = parser.parse_args() + + data, blame = uberblame(args.file, args.revision) + html = visualize_uberblame(data, blame) + show_visualization(html) + return 0 + + +if __name__ == '__main__': + sys.exit(main())
diff --git a/tools/v8_context_snapshot/BUILD.gn b/tools/v8_context_snapshot/BUILD.gn index 3792c69d..d6691a5 100644 --- a/tools/v8_context_snapshot/BUILD.gn +++ b/tools/v8_context_snapshot/BUILD.gn
@@ -7,22 +7,16 @@ # third_party/WebKit/Source/bindings/core/v8/V8ContextSnapshot.{cpp|h}. # to speedup creating a V8 context and setting up around it. +import("//tools/v8_context_snapshot/v8_context_snapshot.gni") + import("//build/config/c++/c++.gni") -import("//build/config/chromecast_build.gni") import("//build/config/compiler/compiler.gni") -import("//build/config/v8_target_cpu.gni") import("//v8/snapshot_toolchain.gni") if (is_android) { import("//build/config/android/rules.gni") } -declare_args() { - # TODO(crbug.com/764576): Enable the feature on more environments. - use_v8_context_snapshot = !is_chromeos && !is_android && !is_chromecast && - (v8_target_cpu == target_cpu || is_msan) -} - if (is_android) { android_assets("v8_context_snapshot_assets") { deps = [ @@ -40,12 +34,21 @@ public_deps = [ ":generate_v8_context_snapshot", ] + data = [ + "$root_out_dir/v8_context_snapshot.bin", + ] + } +} + +config("use_v8_context_snapshot") { + if (use_v8_context_snapshot) { + defines = [ "USE_V8_CONTEXT_SNAPSHOT" ] } } if (use_v8_context_snapshot) { action("generate_v8_context_snapshot") { - script = "run.py" + script = "//build/gn_run_binary.py" output_file = "$root_out_dir/v8_context_snapshot.bin" output_path = rebase_path(output_file, root_build_dir) @@ -89,6 +92,7 @@ deps = [ "//gin:gin", "//mojo/edk/system:system", + "//services/service_manager/public/cpp", "//third_party/WebKit/public:blink", "//v8", ]
diff --git a/tools/v8_context_snapshot/DEPS b/tools/v8_context_snapshot/DEPS index 4af288af..8bd2685 100644 --- a/tools/v8_context_snapshot/DEPS +++ b/tools/v8_context_snapshot/DEPS
@@ -3,5 +3,6 @@ "+v8", "+third_party/WebKit/public", "+gin/v8_initializer.h", - "+mojo/edk/embedder/embedder.h", + "+mojo/edk/embedder", + "+services/service_manager/public", ]
diff --git a/tools/v8_context_snapshot/run.py b/tools/v8_context_snapshot/run.py deleted file mode 100644 index a376b4c..0000000 --- a/tools/v8_context_snapshot/run.py +++ /dev/null
@@ -1,15 +0,0 @@ -# Copyright 2017 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. - -"""This program wraps an arbitrary command since gn currently can only execute -scripts.""" - -import os -import subprocess -import sys - -args = sys.argv[1:] -args[0] = os.path.abspath(args[0]) - -sys.exit(subprocess.call(args))
diff --git a/tools/v8_context_snapshot/v8_context_snapshot.gni b/tools/v8_context_snapshot/v8_context_snapshot.gni new file mode 100644 index 0000000..f8ce9764 --- /dev/null +++ b/tools/v8_context_snapshot/v8_context_snapshot.gni
@@ -0,0 +1,25 @@ +# Copyright 2017 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. + +# Targets in ths file are to take a V8 context snapshot on build time. +# Created V8 context snapshot is used in +# third_party/WebKit/Source/bindings/core/v8/V8ContextSnapshot.{cpp|h}. +# to speedup creating a V8 context and setting up around it. + +import("//build/config/chromecast_build.gni") +import("//build/config/v8_target_cpu.gni") +import("//v8/gni/v8.gni") + +declare_args() { + # TODO(crbug.com/764576): Enable the feature on more environments. + use_v8_context_snapshot = + !is_chromeos && !is_android && !is_chromecast && !is_fuchsia && + !(host_os == "mac" && current_cpu == "x86") && + (v8_target_cpu == target_cpu || is_msan) +} + +# We cannot use V8 context snapshot, if V8 doesn't use snapshot files. +if (use_v8_context_snapshot && !v8_use_external_startup_data) { + use_v8_context_snapshot = false +}
diff --git a/tools/v8_context_snapshot/v8_context_snapshot_generator.cc b/tools/v8_context_snapshot/v8_context_snapshot_generator.cc index 40fe7db..7b39fe6 100644 --- a/tools/v8_context_snapshot/v8_context_snapshot_generator.cc +++ b/tools/v8_context_snapshot/v8_context_snapshot_generator.cc
@@ -7,8 +7,10 @@ #include "base/files/file_util.h" #include "base/message_loop/message_loop.h" #include "base/task_scheduler/task_scheduler.h" +#include "base/threading/thread_task_runner_handle.h" #include "gin/v8_initializer.h" #include "mojo/edk/embedder/embedder.h" +#include "services/service_manager/public/cpp/binder_registry.h" #include "third_party/WebKit/public/platform/WebThread.h" #include "third_party/WebKit/public/web/WebKit.h" #include "third_party/WebKit/public/web/WebV8ContextSnapshot.h" @@ -20,7 +22,9 @@ public: bool IsCurrentThread() const override { return true; } blink::WebScheduler* Scheduler() const override { return nullptr; } - blink::WebTaskRunner* GetWebTaskRunner() override { return nullptr; } + scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner() const override { + return base::ThreadTaskRunnerHandle::Get(); + } }; class SnapshotPlatform final : public blink::Platform { @@ -54,7 +58,8 @@ // Take a snapshot. SnapshotPlatform platform; - blink::Initialize(&platform); + service_manager::BinderRegistry empty_registry; + blink::Initialize(&platform, &empty_registry); v8::StartupData blob = blink::WebV8ContextSnapshot::TakeSnapshot(); // Save the snapshot as a file. Filename is given in a command line option.
diff --git a/tools/valgrind/browser_wrapper_win.py b/tools/valgrind/browser_wrapper_win.py deleted file mode 100644 index 0023ca7..0000000 --- a/tools/valgrind/browser_wrapper_win.py +++ /dev/null
@@ -1,49 +0,0 @@ -# Copyright (c) 2011 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 glob -import os -import re -import sys -import subprocess - -# TODO(timurrrr): we may use it on POSIX too to avoid code duplication once we -# support layout_tests, remove Dr. Memory specific code and verify it works -# on a "clean" Mac. - -testcase_name = None -for arg in sys.argv: - m = re.match("\-\-gtest_filter=(.*)", arg) - if m: - assert testcase_name is None - testcase_name = m.groups()[0] - -# arg #0 is the path to this python script -cmd_to_run = sys.argv[1:] - -# TODO(timurrrr): this is Dr. Memory-specific -# Usually, we pass "-logdir" "foo\bar\spam path" args to Dr. Memory. -# To group reports per UI test, we want to put the reports for each test into a -# separate directory. This code can be simplified when we have -# https://github.com/DynamoRIO/drmemory/issues/684 fixed. -logdir_idx = cmd_to_run.index("-logdir") -old_logdir = cmd_to_run[logdir_idx + 1] - -wrapper_pid = str(os.getpid()) - -# On Windows, there is a chance of PID collision. We avoid it by appending the -# number of entries in the logdir at the end of wrapper_pid. -# This number is monotonic and we can't have two simultaneously running wrappers -# with the same PID. -wrapper_pid += "_%d" % len(glob.glob(old_logdir + "\\*")) - -cmd_to_run[logdir_idx + 1] += "\\testcase.%s.logs" % wrapper_pid -os.makedirs(cmd_to_run[logdir_idx + 1]) - -if testcase_name: - f = open(old_logdir + "\\testcase.%s.name" % wrapper_pid, "w") - print >>f, testcase_name - f.close() - -exit(subprocess.call(cmd_to_run))
diff --git a/tools/valgrind/drmemory.bat b/tools/valgrind/drmemory.bat deleted file mode 100755 index 46d5a4f0..0000000 --- a/tools/valgrind/drmemory.bat +++ /dev/null
@@ -1,5 +0,0 @@ -@echo off -:: Copyright (c) 2011 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. -%~dp0\chrome_tests.bat -t cmdline --tool drmemory %*
diff --git a/tools/valgrind/drmemory_analyze.py b/tools/valgrind/drmemory_analyze.py deleted file mode 100755 index 29fc0ed..0000000 --- a/tools/valgrind/drmemory_analyze.py +++ /dev/null
@@ -1,202 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2011 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. - -# drmemory_analyze.py - -''' Given a Dr. Memory output file, parses errors and uniques them.''' - -from collections import defaultdict -import common -import hashlib -import logging -import optparse -import os -import re -import subprocess -import sys -import time - -class DrMemoryError: - def __init__(self, report, suppression, testcase): - self._report = report - self._testcase = testcase - - # Chromium-specific transformations of the suppressions: - # Replace 'any_test.exe' and 'chrome.dll' with '*', then remove the - # Dr.Memory-generated error ids from the name= lines as they don't - # make sense in a multiprocess report. - supp_lines = suppression.split("\n") - for l in xrange(len(supp_lines)): - if supp_lines[l].startswith("name="): - supp_lines[l] = "name=<insert_a_suppression_name_here>" - if supp_lines[l].startswith("chrome.dll!"): - supp_lines[l] = supp_lines[l].replace("chrome.dll!", "*!") - bang_index = supp_lines[l].find("!") - d_exe_index = supp_lines[l].find(".exe!") - if bang_index >= 4 and d_exe_index + 4 == bang_index: - supp_lines[l] = "*" + supp_lines[l][bang_index:] - self._suppression = "\n".join(supp_lines) - - def __str__(self): - output = "" - output += "### BEGIN MEMORY TOOL REPORT (error hash=#%016X#)\n" % \ - self.ErrorHash() - output += self._report + "\n" - if self._testcase: - output += "The report came from the `%s` test.\n" % self._testcase - output += "Suppression (error hash=#%016X#):\n" % self.ErrorHash() - output += (" For more info on using suppressions see " - "http://dev.chromium.org/developers/how-tos/using-drmemory#TOC-Suppressing-error-reports-from-the-\n") - output += "{\n%s\n}\n" % self._suppression - output += "### END MEMORY TOOL REPORT (error hash=#%016X#)\n" % \ - self.ErrorHash() - return output - - # This is a device-independent hash identifying the suppression. - # By printing out this hash we can find duplicate reports between tests and - # different shards running on multiple buildbots - def ErrorHash(self): - return int(hashlib.md5(self._suppression).hexdigest()[:16], 16) - - def __hash__(self): - return hash(self._suppression) - - def __eq__(self, rhs): - return self._suppression == rhs - - -class DrMemoryAnalyzer: - ''' Given a set of Dr.Memory output files, parse all the errors out of - them, unique them and output the results.''' - - def __init__(self): - self.known_errors = set() - self.error_count = 0; - - def ReadLine(self): - self.line_ = self.cur_fd_.readline() - - def ReadSection(self): - result = [self.line_] - self.ReadLine() - while len(self.line_.strip()) > 0: - result.append(self.line_) - self.ReadLine() - return result - - def ParseReportFile(self, filename, testcase): - ret = [] - - # First, read the generated suppressions file so we can easily lookup a - # suppression for a given error. - supp_fd = open(filename.replace("results", "suppress"), 'r') - generated_suppressions = {} # Key -> Error #, Value -> Suppression text. - for line in supp_fd: - # NOTE: this regexp looks fragile. Might break if the generated - # suppression format slightly changes. - m = re.search("# Suppression for Error #([0-9]+)", line.strip()) - if not m: - continue - error_id = int(m.groups()[0]) - assert error_id not in generated_suppressions - # OK, now read the next suppression: - cur_supp = "" - for supp_line in supp_fd: - if supp_line.startswith("#") or supp_line.strip() == "": - break - cur_supp += supp_line - generated_suppressions[error_id] = cur_supp.strip() - supp_fd.close() - - self.cur_fd_ = open(filename, 'r') - while True: - self.ReadLine() - if (self.line_ == ''): break - - match = re.search("^Error #([0-9]+): (.*)", self.line_) - if match: - error_id = int(match.groups()[0]) - self.line_ = match.groups()[1].strip() + "\n" - report = "".join(self.ReadSection()).strip() - suppression = generated_suppressions[error_id] - ret.append(DrMemoryError(report, suppression, testcase)) - - if re.search("SUPPRESSIONS USED:", self.line_): - self.ReadLine() - while self.line_.strip() != "": - line = self.line_.strip() - (count, name) = re.match(" *([0-9\?]+)x(?: \(.*?\))?: (.*)", - line).groups() - if (count == "?"): - # Whole-module have no count available: assume 1 - count = 1 - else: - count = int(count) - self.used_suppressions[name] += count - self.ReadLine() - - if self.line_.startswith("ASSERT FAILURE"): - ret.append(self.line_.strip()) - - self.cur_fd_.close() - return ret - - def Report(self, filenames, testcase, check_sanity): - sys.stdout.flush() - # TODO(timurrrr): support positive tests / check_sanity==True - self.used_suppressions = defaultdict(int) - - to_report = [] - reports_for_this_test = set() - for f in filenames: - cur_reports = self.ParseReportFile(f, testcase) - - # Filter out the reports that were there in previous tests. - for r in cur_reports: - if r in reports_for_this_test: - # A similar report is about to be printed for this test. - pass - elif r in self.known_errors: - # A similar report has already been printed in one of the prev tests. - to_report.append("This error was already printed in some " - "other test, see 'hash=#%016X#'" % r.ErrorHash()) - reports_for_this_test.add(r) - else: - self.known_errors.add(r) - reports_for_this_test.add(r) - to_report.append(r) - - common.PrintUsedSuppressionsList(self.used_suppressions) - - if not to_report: - logging.info("PASS: No error reports found") - return 0 - - sys.stdout.flush() - sys.stderr.flush() - logging.info("Found %i error reports" % len(to_report)) - for report in to_report: - self.error_count += 1 - logging.info("Report #%d\n%s" % (self.error_count, report)) - logging.info("Total: %i error reports" % len(to_report)) - sys.stdout.flush() - return -1 - - -def main(): - '''For testing only. The DrMemoryAnalyze class should be imported instead.''' - parser = optparse.OptionParser("usage: %prog <files to analyze>") - - (options, args) = parser.parse_args() - if len(args) == 0: - parser.error("no filename specified") - filenames = args - - logging.getLogger().setLevel(logging.INFO) - return DrMemoryAnalyzer().Report(filenames, None, False) - - -if __name__ == '__main__': - sys.exit(main())
diff --git a/tools/valgrind/gtest_exclude/browser_tests.gtest-memcheck.txt b/tools/valgrind/gtest_exclude/browser_tests.gtest-memcheck.txt index 337b367..e3bc87e 100644 --- a/tools/valgrind/gtest_exclude/browser_tests.gtest-memcheck.txt +++ b/tools/valgrind/gtest_exclude/browser_tests.gtest-memcheck.txt
@@ -54,5 +54,4 @@ SafeBrowsingInterstitialVersions/SafeBrowsingBlockingPageBrowserTest.ProceedDisabled* SocketApiTest.SocketTCPExtension SocketApiTest.SocketUDPExtension -SSLUITest.TestWSSInvalidCertAndGoForward WebViewTest.Shim
diff --git a/tools/valgrind/gtest_exclude/unit_tests.gtest_linux.txt b/tools/valgrind/gtest_exclude/unit_tests.gtest_linux.txt deleted file mode 100644 index e30315a7..0000000 --- a/tools/valgrind/gtest_exclude/unit_tests.gtest_linux.txt +++ /dev/null
@@ -1,10 +0,0 @@ -# http://crbug.com/336349 -NTPUserDataLoggerTest.TestLogging - -# http://crbug.com/403533 -ExtensionPathUtilTest.BasicPrettifyPathTest - -# http://crbug.com/523600 -ClientCertStoreChromeOSTest.Filter -ClientCertStoreChromeOSTest.RequestsAfterNSSInitSucceed -ClientCertStoreChromeOSTest.CertRequestMatching
diff --git a/tools/valgrind/memcheck/suppressions.txt b/tools/valgrind/memcheck/suppressions.txt index 24bb24f2..14383d6 100644 --- a/tools/valgrind/memcheck/suppressions.txt +++ b/tools/valgrind/memcheck/suppressions.txt
@@ -2405,19 +2405,6 @@ fun:_ZN10extensions11ApiTestBase5SetUpEv } { - bug_448700_b - Memcheck:Leak - fun:_Znw* - ... - fun:_ZN10extensions12_GLOBAL__N_111TestNatives24GetObjectTemplateBuilderEPN2v87IsolateE - fun:_ZN3gin13WrappableBase14GetWrapperImplEPN2v87IsolateEPNS_11WrapperInfoE - fun:_ZN3gin9WrappableIN10extensions12_GLOBAL__N_111TestNativesEE10GetWrapperEPN2v87IsolateE - fun:_ZN3gin12CreateHandleIN10extensions12_GLOBAL__N_111TestNativesEEENS_6HandleIT_EEPN2v87IsolateEPS5_ - fun:_ZN10extensions12_GLOBAL__N_111TestNatives6CreateEPN2v87IsolateERKN4base8CallbackIFvvEEE - fun:_ZN10extensions11ApiTestBase7RunTestERKSsS2_ - fun:_ZN10extensions30MojoPrivateApiTest_Define_Test8TestBodyEv -} -{ bug_449156_a Memcheck:Leak fun:_Znw*
diff --git a/tools/valgrind/suppressions.py b/tools/valgrind/suppressions.py index e066bed..2653753f 100755 --- a/tools/valgrind/suppressions.py +++ b/tools/valgrind/suppressions.py
@@ -55,11 +55,6 @@ vg_mac = ReadSuppressionsFromFile(supp_filename) result['mac_suppressions'] = vg_mac - supp_filename = JOIN(suppressions_root, "drmemory", "suppressions.txt") - result['drmem_suppressions'] = ReadSuppressionsFromFile(supp_filename) - supp_filename = JOIN(suppressions_root, "drmemory", "suppressions_full.txt") - result['drmem_full_suppressions'] = ReadSuppressionsFromFile(supp_filename) - return result
diff --git a/tools/valgrind/test_suppressions.py b/tools/valgrind/test_suppressions.py index 3ad374d..d4aaf35 100755 --- a/tools/valgrind/test_suppressions.py +++ b/tools/valgrind/test_suppressions.py
@@ -145,10 +145,6 @@ cur_supp += supp['mac_suppressions'] elif all([re.search("Linux%20", url) for url in all_reports[r]]): cur_supp += supp['linux_suppressions'] - if all(["DrMemory" in url for url in all_reports[r]]): - cur_supp += supp['drmem_suppressions'] - if all(["DrMemory%20full" in url for url in all_reports[r]]): - cur_supp += supp['drmem_full_suppressions'] # Test if this report is already suppressed skip = False
diff --git a/tools/variations/OWNERS b/tools/variations/OWNERS index 986aba6..03a77ec22 100644 --- a/tools/variations/OWNERS +++ b/tools/variations/OWNERS
@@ -1,4 +1,3 @@ -asvitkine@chromium.org -danduong@chromium.org +file://base/metrics/OWNERS -# COMPONENT: Internals>Metrics +# COMPONENT: Internals>Metrics>Variations
diff --git a/tools/variations/fieldtrial_to_struct_unittest.py b/tools/variations/fieldtrial_to_struct_unittest.py index 4f10bac..b08f0245 100644 --- a/tools/variations/fieldtrial_to_struct_unittest.py +++ b/tools/variations/fieldtrial_to_struct_unittest.py
@@ -208,20 +208,22 @@ self.assertEqual(expected, result) def test_FieldTrialToStructMain(self): - schema = ('../../components/variations/field_trial_config/' - 'field_trial_testing_config_schema.json') + schema = (os.path.dirname(__file__) + + '/../../components/variations/field_trial_config/' + 'field_trial_testing_config_schema.json') + unittest_data_dir = os.path.dirname(__file__) + '/unittest_data/' test_output_filename = 'test_output' fieldtrial_to_struct.main([ '--schema=' + schema, '--output=' + test_output_filename, '--platform=win', '--year=2015', - 'unittest_data/test_config.json' + unittest_data_dir + 'test_config.json' ]) header_filename = test_output_filename + '.h' with open(header_filename, 'r') as header: test_header = header.read() - with open('unittest_data/expected_output.h', 'r') as expected: + with open(unittest_data_dir + 'expected_output.h', 'r') as expected: expected_header = expected.read() self.assertEqual(expected_header, test_header) os.unlink(header_filename) @@ -229,7 +231,7 @@ cc_filename = test_output_filename + '.cc' with open(cc_filename, 'r') as cc: test_cc = cc.read() - with open('unittest_data/expected_output.cc', 'r') as expected: + with open(unittest_data_dir + 'expected_output.cc', 'r') as expected: expected_cc = expected.read() self.assertEqual(expected_cc, test_cc) os.unlink(cc_filename)
diff --git a/tools/vim/mojom/syntax/mojom.vim b/tools/vim/mojom/syntax/mojom.vim index cdd3f7e7..f721637 100644 --- a/tools/vim/mojom/syntax/mojom.vim +++ b/tools/vim/mojom/syntax/mojom.vim
@@ -2,47 +2,60 @@ " Use of this source code is governed by a BSD-style license that can be " found in the LICENSE file. -" Vim syntax file " Language: Mojom +" Vim syntax file +" Language: Mojom " To get syntax highlighting for .mojom files, add the following to your .vimrc " file: -" set runtimepath^=/path/to/src/tools/vim/mojom +" set runtimepath+=/path/to/src/tools/vim/mojom + +if exists("b:current_syntax") + finish +endif syn case match syntax region mojomFold start="{" end="}" transparent fold -" keyword definitions -syntax keyword mojomType bool int8 int16 int32 int64 uint8 uint16 uint32 uint64 float double array +" Keywords +syntax keyword mojomType bool string int8 int16 int32 int64 uint8 uint16 +syntax keyword mojomType uint32 uint64 float double array syntax match mojomImport "^\(import\)\s" -syntax keyword mojomKeyword const module interface enum struct union +syntax keyword mojomKeyword const module interface enum struct union associated syntax match mojomOperator /=>/ syntax match mojomOperator /?/ " Comments syntax keyword mojomTodo contained TODO FIXME XXX +syntax region mojomDocLink contained start="\[" end="\]" syntax region mojomComment start="/\*" end="\*/" contains=mojomTodo,mojomDocLink,@Spell -syntax match mojomLineComment "//.*" contains=mojomTodo,@Spell -syntax match mojomLineDocComment "///.*" contains=mojomTodo,mojomDocLink,@Spell -syntax region mojomDocLink contained start=+\[+ end=+\]+ +syntax match mojomLineComment "//.*" contains=mojomTodo,mojomDocLink,@Spell -" Strings -syn region mojomString start=+L\="+ skip=+\\\\\|\\"+ end=+"+ contains=@Spell -hi def link mojomString String +" Literals +syntax match mojomBoolean /true\|false/ +" Negative lookahead for "." so floats are not partly highlighted as integers. +syntax match mojomInteger /-\=[0-9]\(\.\)\@!/ +syntax match mojomFloat /[0-9]\+\.[0-9]*\|[0-9]*\.[0-9]\+/ +syntax region mojomString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=@Spell + +" Attributes +syntax match mojomAttribute /\[[^\]]*\]/ " The default highlighting. highlight default link mojomTodo Todo highlight default link mojomComment Comment highlight default link mojomLineComment Comment -highlight default link mojomLineDocComment Comment highlight default link mojomDocLink SpecialComment highlight default link mojomType Type highlight default link mojomImport Include highlight default link mojomKeyword Keyword highlight default link mojomOperator Operator +highlight default link mojomString String +highlight default link mojomInteger Number +highlight default link mojomBoolean Boolean +highlight default link mojomFloat Float +highlight default link mojomAttribute Label let b:current_syntax = "mojom" let b:spell_options = "contained" syn sync minlines=500 - -let b:current_syntax = "mojom"
diff --git a/tools/web_bluetooth/OWNERS b/tools/web_bluetooth/OWNERS index 5a6a65e..0448c8c0 100644 --- a/tools/web_bluetooth/OWNERS +++ b/tools/web_bluetooth/OWNERS
@@ -1,2 +1,5 @@ -perja@opera.com -scheib@chromium.org +jyasskin@chromium.org +ortuno@chromium.org + +# TEAM: web-bluetooth@chromium.org +# COMPONENT: Blink>Bluetooth
diff --git a/tools/web_dev_style/html_checker.py b/tools/web_dev_style/html_checker.py index f646b9d..d9d796b 100644 --- a/tools/web_dev_style/html_checker.py +++ b/tools/web_dev_style/html_checker.py
@@ -16,13 +16,20 @@ self.file_filter = file_filter def ClassesUseDashFormCheck(self, line_number, line): - regex = self.input_api.re.compile(""" + msg = "Classes should use dash-form." + re = self.input_api.re + class_regex = re.compile(""" (?:^|\s) # start of line or whitespace (class="[^"]*[A-Z_][^"]*") # class contains caps or '_' """, - self.input_api.re.VERBOSE) - return regex_check.RegexCheck(self.input_api.re, line_number, line, regex, - "Classes should use dash-form.") + re.VERBOSE) + + # $i18n{...} messes with highlighting. Special path for this. + if "$i18n{" in line: + match = re.search(class_regex, re.sub("\$i18n{[^}]+}", "", line)) + return " line %d: %s" % (line_number, msg) if match else "" + + return regex_check.RegexCheck(re, line_number, line, class_regex, msg) def DoNotCloseSingleTagsCheck(self, line_number, line): regex = r"(/>)"
diff --git a/tools/web_dev_style/html_checker_test.py b/tools/web_dev_style/html_checker_test.py index f059f7d..0a9a0a4 100755 --- a/tools/web_dev_style/html_checker_test.py +++ b/tools/web_dev_style/html_checker_test.py
@@ -52,6 +52,7 @@ ' class="abc" ', 'class="foo-bar"', '<div class="foo-bar" id="classBar"', + '<div class="foo $i18n{barBazQux}" id="classBar"', ] for line in lines: self.ShouldPassCheck(line, self.checker.ClassesUseDashFormCheck)
diff --git a/tools/web_dev_style/js_checker.py b/tools/web_dev_style/js_checker.py index 46bc62f..117979ea 100644 --- a/tools/web_dev_style/js_checker.py +++ b/tools/web_dev_style/js_checker.py
@@ -86,11 +86,11 @@ return [self.output_api.PresubmitError(output)] if output else [] - def VarNameCheck(self, i, line): + def VariableNameCheck(self, i, line): """See the style guide. http://goo.gl/eQiXVW""" return self.RegexCheck(i, line, - r"var (?!g_\w+)(_?[a-z][a-zA-Z]*[_$][\w_$]*)(?<! \$)", - "Please use var namesLikeThis <https://goo.gl/eQiXVW>") + r"(?:var|let|const) (?!g_\w+)(_?[a-z][a-zA-Z]*[_$][\w_$]*)(?<! \$)", + "Please use variable namesLikeThis <https://goo.gl/eQiXVW>") def _GetErrorHighlight(self, start, length): """Takes a start position and a length, and produces a row of '^'s to @@ -123,7 +123,7 @@ self.ExtraDotInGenericCheck(i, line), self.InheritDocCheck(i, line), self.PolymerLocalIdCheck(i, line), - self.VarNameCheck(i, line), + self.VariableNameCheck(i, line), ]) if error_lines:
diff --git a/tools/web_dev_style/js_checker_test.py b/tools/web_dev_style/js_checker_test.py index a481a75..b5a4ced 100755 --- a/tools/web_dev_style/js_checker_test.py +++ b/tools/web_dev_style/js_checker_test.py
@@ -17,6 +17,9 @@ from testing_support.super_mox import SuperMoxTestBase +_DECLARATION_METHODS = 'const', 'let', 'var' + + class JsCheckerTest(SuperMoxTestBase): def setUp(self): SuperMoxTestBase.setUp(self) @@ -208,46 +211,48 @@ for line in lines: self.ShouldPassPolymerLocalIdCheck(line) - def ShouldFailVarNameCheck(self, line): + def ShouldFailVariableNameCheck(self, line): """Checks that var unix_hacker, $dollar are style errors.""" - error = self.checker.VarNameCheck(1, line) + error = self.checker.VariableNameCheck(1, line) self.assertNotEqual('', error, msg='Should be flagged as style error: ' + line) highlight = test_util.GetHighlight(line, error) - self.assertFalse('var ' in highlight); + self.assertFalse(any(dm in highlight for dm in _DECLARATION_METHODS)) - def ShouldPassVarNameCheck(self, line): + def ShouldPassVariableNameCheck(self, line): """Checks that variableNamesLikeThis aren't style errors.""" - self.assertEqual('', self.checker.VarNameCheck(1, line), + self.assertEqual('', self.checker.VariableNameCheck(1, line), msg='Should not be flagged as style error: ' + line) - def testVarNameFails(self): + def testVariableNameFails(self): lines = [ - "var private_;", - "var hostName_ = 'https://google.com';", - " var _super_private", - " var unix_hacker = someFunc();", + "%s private_;", + "%s hostName_ = 'https://google.com';", + " %s _super_private", + " %s unix_hacker = someFunc();", ] for line in lines: - self.ShouldFailVarNameCheck(line) + for declaration_method in _DECLARATION_METHODS: + self.ShouldFailVariableNameCheck(line % declaration_method) - def testVarNamePasses(self): + def testVariableNamePasses(self): lines = [ - " var namesLikeThis = [];", - " for (var i = 0; i < 10; ++i) { ", - "for (var i in obj) {", - " var one, two, three;", - " var magnumPI = {};", - " var g_browser = 'da browzer';", - "/** @const */ var Bla = options.Bla;", # goog.scope() replacement. - " var $ = function() {", # For legacy reasons. - " var StudlyCaps = cr.define('bla')", # Classes. - " var SCARE_SMALL_CHILDREN = [", # TODO(dbeam): add @const in + " %s namesLikeThis = [];", + " for (%s i = 0; i < 10; ++i) { ", + "for (%s i in obj) {", + " %s one, two, three;", + " %s magnumPI = {};", + " %s g_browser = 'da browzer';", + "/** @const */ %s Bla = options.Bla;", # goog.scope() replacement. + " %s $ = function() {", # For legacy reasons. + " %s StudlyCaps = cr.define('bla')", # Classes. + " %s SCARE_SMALL_CHILDREN = [", # TODO(dbeam): add @const in # front of all these vars like - "/** @const */ CONST_VAR = 1;", # this line has (<--). + # "/** @const */ %s CONST_VAR = 1;", # this line has (<--). ] for line in lines: - self.ShouldPassVarNameCheck(line) + for declaration_method in _DECLARATION_METHODS: + self.ShouldPassVariableNameCheck(line % declaration_method) if __name__ == '__main__':
diff --git a/tools/web_dev_style/presubmit_support.py b/tools/web_dev_style/presubmit_support.py index 09da594..a44995f 100644 --- a/tools/web_dev_style/presubmit_support.py +++ b/tools/web_dev_style/presubmit_support.py
@@ -9,10 +9,13 @@ import resource_checker +def IsResource(f): + return f.LocalPath().endswith(('.html', '.css', '.js')) + + def CheckStyle(input_api, output_api, file_filter=lambda f: True): apis = input_api, output_api - is_resource = lambda f: f.LocalPath().endswith(('.html', '.css', '.js')) - wrapped_filter = lambda f: file_filter(f) and is_resource(f) + wrapped_filter = lambda f: file_filter(f) and IsResource(f) checkers = [ css_checker.CSSChecker(*apis, file_filter=wrapped_filter), html_checker.HtmlChecker(*apis, file_filter=wrapped_filter), @@ -23,3 +26,16 @@ for checker in checkers: results.extend(checker.RunChecks()) return results + + +def CheckStyleESLint(input_api, output_api): + is_js = lambda f: f.LocalPath().endswith('.js') + js_files = input_api.AffectedFiles(file_filter=is_js, include_deletes=False) + if not js_files: + return [] + return js_checker.JSChecker(input_api, output_api).RunEsLintChecks(js_files) + + +def DisallowIncludes(input_api, output_api, msg): + return resource_checker.ResourceChecker( + input_api, output_api, file_filter=IsResource).DisallowIncludes(msg)
diff --git a/tools/web_dev_style/resource_checker.py b/tools/web_dev_style/resource_checker.py index 69b8185..4a74ff4 100644 --- a/tools/web_dev_style/resource_checker.py +++ b/tools/web_dev_style/resource_checker.py
@@ -15,31 +15,49 @@ self.output_api = output_api self.file_filter = file_filter - def IncludeCheck(self, line_number, line): + def DisallowIncludeCheck(self, msg, line_number, line): + return regex_check.RegexCheck(self.input_api.re, line_number, line, + '^\s*(?:\/[\*\/])?\s*(<include)\s*src=', msg) + + # This is intentionally not included in RunChecks(). It's an optional check + # that can be used from a PRESUBMIT.py in a directory that does not wish to + # use <include> (i.e. uses a different bundling mechanism, does not grit + # process, etc.). + def DisallowIncludes(self, msg): + check = lambda *args: self.DisallowIncludeCheck(msg, *args) + return self._RunCheckOnAffectedFiles(check, 'Found resource errors in %s', + is_error=True) + + def SelfClosingIncludeCheck(self, line_number, line): return regex_check.RegexCheck(self.input_api.re, line_number, line, "(</include>|<include.*/>)", "Closing <include> tags is unnecessary.") def RunChecks(self): + return self._RunCheckOnAffectedFiles( + self.SelfClosingIncludeCheck, 'Found resources style issues in %s') + + def _RunCheckOnAffectedFiles(self, check, msg_template, is_error=False): """Check for violations of the Chromium web development style guide. See https://chromium.googlesource.com/chromium/src/+/master/styleguide/web/web.md """ results = [] - affected_files = self.input_api.AffectedFiles(file_filter=self.file_filter, - include_deletes=False) - + affected_files= self.input_api.AffectedFiles(file_filter=self.file_filter, + include_deletes=False) for f in affected_files: errors = [] for line_number, line in enumerate(f.NewContents(), start=1): - error = self.IncludeCheck(line_number, line) + error = check(line_number, line) if error: errors.append(error) if errors: abs_local_path = f.AbsoluteLocalPath() - file_indicator = 'Found resources style issues in %s' % abs_local_path - prompt_msg = file_indicator + '\n\n' + '\n'.join(errors) + '\n' - results.append(self.output_api.PresubmitPromptWarning(prompt_msg)) + msg = msg_template % abs_local_path + '\n\n' + '\n'.join(errors) + '\n' + if is_error: + results.append(self.output_api.PresubmitError(msg)) + else: + results.append(self.output_api.PresubmitPromptWarning(msg)) return results
diff --git a/tools/web_dev_style/resource_checker_test.py b/tools/web_dev_style/resource_checker_test.py index 0f0abd9..da3877a 100755 --- a/tools/web_dev_style/resource_checker_test.py +++ b/tools/web_dev_style/resource_checker_test.py
@@ -26,17 +26,17 @@ output_api = self.mox.CreateMockAnything() self.checker = resource_checker.ResourceChecker(input_api, output_api) - def ShouldFailIncludeCheck(self, line): + def ShouldFailSelfClosingIncludeCheck(self, line): """Checks that the '</include>' checker flags |line| as a style error.""" - error = self.checker.IncludeCheck(1, line) + error = self.checker.SelfClosingIncludeCheck(1, line) self.assertNotEqual('', error, 'Should be flagged as style error: ' + line) highlight = test_util.GetHighlight(line, error).strip() self.assertTrue('include' in highlight and highlight[0] == '<') - def ShouldPassIncludeCheck(self, line): + def ShouldPassSelfClosingIncludeCheck(self, line): """Checks that the '</include>' checker doesn't flag |line| as an error.""" - self.assertEqual('', self.checker.IncludeCheck(1, line), + self.assertEqual('', self.checker.SelfClosingIncludeCheck(1, line), 'Should not be flagged as style error: ' + line) def testIncludeFails(self): @@ -48,7 +48,7 @@ '<include src="blee.js"/>', ] for line in lines: - self.ShouldFailIncludeCheck(line) + self.ShouldFailSelfClosingIncludeCheck(line) def testIncludePasses(self): lines = [ @@ -59,7 +59,33 @@ "</i>include", ] for line in lines: - self.ShouldPassIncludeCheck(line) + self.ShouldPassSelfClosingIncludeCheck(line) + + def ShouldPassDisallowIncludeCheck(self, line): + self.assertEqual('', self.checker.DisallowIncludeCheck('msg', 1, line), + 'Should not be flagged as error') + + def ShouldFailDisallowIncludeCheck(self, line): + error = self.checker.DisallowIncludeCheck('msg', 1, line) + self.assertNotEqual('', error, 'Should be flagged as error: ' + line) + self.assertEquals('<include', test_util.GetHighlight(line, error)) + + def testDisallowIncludesFails(self): + lines = [ + '<include src="blah.js">', + ' // <include src="blah.js">', + ' /* <include src="blah.js"> */ ', + ] + for line in lines: + self.ShouldFailDisallowIncludeCheck(line) + + def testDisallowIncludesPasses(self): + lines = [ + 'if (count < includeCount) {', + '// No <include>s allowed.', + ] + for line in lines: + self.ShouldPassDisallowIncludeCheck(line) if __name__ == '__main__':
diff --git a/tools/win/OWNERS b/tools/win/OWNERS index 09056fa8..7afbac6 100644 --- a/tools/win/OWNERS +++ b/tools/win/OWNERS
@@ -1,3 +1,2 @@ brucedawson@chromium.org scottmg@chromium.org -stanisc@chromium.org \ No newline at end of file
diff --git a/tools/win/ShowThreadNames/ReadMe.txt b/tools/win/ShowThreadNames/ReadMe.txt index e322aa3c..136e893 100644 --- a/tools/win/ShowThreadNames/ReadMe.txt +++ b/tools/win/ShowThreadNames/ReadMe.txt
@@ -37,7 +37,6 @@ 2256 AudioThread 9308 BrokerEvent 5668 BrowserWatchdog -8616 Chrome_FileThread 8280 Chrome_HistoryThread 7472 Chrome_IOThread 6336 Chrome_ProcessLauncherThread
diff --git a/tools/win/static_initializers/build.bat b/tools/win/static_initializers/build.bat index 46d493c..43f75f1c 100755 --- a/tools/win/static_initializers/build.bat +++ b/tools/win/static_initializers/build.bat
@@ -1,3 +1,3 @@ @setlocal call "%VS140COMNTOOLS%..\..\VC\vcvarsall.bat" -cl static_initializers.cc /EHsc /I "c:\Program Files (x86)\Microsoft Visual Studio 14.0\DIA SDK\include" /link Ole32.lib OleAut32.lib +cl static_initializers.cc /EHsc /I "c:\Program Files (x86)\Microsoft Visual Studio 14.0\DIA SDK\include" /link Ole32.lib OleAut32.lib dbghelp.lib
diff --git a/tools/win/static_initializers/static_initializers.cc b/tools/win/static_initializers/static_initializers.cc index fadda9a..2800ac3 100644 --- a/tools/win/static_initializers/static_initializers.cc +++ b/tools/win/static_initializers/static_initializers.cc
@@ -2,11 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <Windows.h> +#include <dbghelp.h> #include <dia2.h> #include <stdio.h> #include <string> +static const size_t kMaxSymbolLength = 4096; + // Create an IDiaData source and open a PDB file. static bool LoadDataFromPdb(const wchar_t* filename, IDiaDataSource** source, @@ -101,8 +105,31 @@ if (wcsstr(bstr_name, L"`dynamic initializer for '") || wcsstr(bstr_name, L"`dynamic atexit destructor for '")) { wprintf(L"%s: %s\n", module.c_str(), bstr_name); - SysFreeString(bstr_name); } + // If there are multiple dynamic initializers in one translation unit then + // a shared function is created and the individual initializers may be + // inlined into it. These functions start with a characteristic name that + // includes the source file. Finding the actual objects can be done through + // source inspection or by setting a breakpoint on the printed name. The + // "dynamic initializer" string is printed for consistent grepping. + if (wcsstr(bstr_name, L"_GLOBAL__sub_I")) { + wprintf(L"%s: %s (dynamic initializer)\n", module.c_str(), bstr_name); + } + // As of this writing, Clang does not undecorate the symbol names for + // dynamic initializers, so the debug info contains the decorated name, + // which starts with "??__E" or "??__F" for atexit destructors. Check for + // that, and print the undecorated name if it matches. + if (wcsncmp(bstr_name, L"??__E", 5) == 0 || + wcsncmp(bstr_name, L"??__F", 5) == 0) { + wchar_t undecorated[kMaxSymbolLength]; + if (UnDecorateSymbolNameW(bstr_name, undecorated, kMaxSymbolLength, + UNDNAME_NAME_ONLY) == 0) { + printf("UnDecorateSymbolNameW failed, %d\n", GetLastError()); + return; + } + wprintf(L"%s: %s\n", module.c_str(), undecorated); + } + SysFreeString(bstr_name); } }
diff --git a/tools/win/subtract_time.py b/tools/win/subtract_time.py index 4e1559b..e11c6bfc 100644 --- a/tools/win/subtract_time.py +++ b/tools/win/subtract_time.py
@@ -3,7 +3,7 @@ # found in the LICENSE file. """ -This script converts to %time% compatible strings passed to it into seconds, +This script converts two %time% compatible strings passed to it into seconds, subtracts them, and prints the difference. That's it. It's used by timeit.bat. """ @@ -11,8 +11,9 @@ import sys def ParseTime(time_string): - # Time looks like 15:19:30.32 - match = re.match("(.*):(.*):(.*)\.(.*)", time_string) + # Time looks like 15:19:30.32 or 15:19:30,32 depending on locale + # (and there might be other variants as well) + match = re.match("(.*):(.*):(.*)[\.,](.*)", time_string) hours, minutes, seconds, fraction = map(int, match.groups()) return hours * 3600 + minutes * 60 + seconds + fraction * .01