summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorTorne (Richard Coles) <torne@google.com>2014-06-09 12:00:27 +0100
committerTorne (Richard Coles) <torne@google.com>2014-06-09 12:00:27 +0100
commit46d4c2bc3267f3f028f39e7e311b0f89aba2e4fd (patch)
treeed52337c337f5fd1db77873d9ff980ca3e334b35 /tools
parent7ef4c70daab901f557268ad466f62cd2f7896916 (diff)
downloadchromium_org-46d4c2bc3267f3f028f39e7e311b0f89aba2e4fd.tar.gz
Merge from Chromium at DEPS revision 275586
This commit was generated by merge_to_master.py. Change-Id: Ief3a0ffd810858bfddbe0ec5931e3ee90d53f78c
Diffstat (limited to 'tools')
-rwxr-xr-xtools/binary_size/run_binary_size_analysis.py77
-rwxr-xr-xtools/bisect-perf-regression.py121
-rw-r--r--tools/checkdeps/PRESUBMIT.py2
-rwxr-xr-xtools/checkdeps/builddeps.py2
-rwxr-xr-xtools/checkdeps/checkdeps.py2
-rwxr-xr-xtools/checkdeps/checkdeps_test.py2
-rw-r--r--tools/checkdeps/cpp_checker.py2
-rwxr-xr-xtools/checkdeps/graphdeps.py2
-rw-r--r--tools/checkdeps/java_checker.py2
-rw-r--r--tools/checkdeps/results.py2
-rw-r--r--tools/checkdeps/rules.py2
-rw-r--r--tools/checkdeps/testdata/allowed/foo_unittest.cc2
-rw-r--r--tools/checkdeps/testdata/allowed/not_a_test.cc2
-rw-r--r--tools/checkdeps/testdata/allowed/test.h2
-rw-r--r--tools/checkdeps/testdata/checkdeps_test/allowed/foo_unittest.cc2
-rw-r--r--tools/checkdeps/testdata/checkdeps_test/allowed/not_a_test.cc2
-rw-r--r--tools/checkdeps/testdata/checkdeps_test/allowed/test.h2
-rw-r--r--tools/checkdeps/testdata/checkdeps_test/disallowed/allowed/skipped/test.h2
-rw-r--r--tools/checkdeps/testdata/checkdeps_test/disallowed/allowed/test.h2
-rw-r--r--tools/checkdeps/testdata/checkdeps_test/disallowed/test.h2
-rw-r--r--tools/checkdeps/testdata/disallowed/allowed/skipped/test.h2
-rw-r--r--tools/checkdeps/testdata/disallowed/allowed/test.h2
-rw-r--r--tools/checkdeps/testdata/disallowed/foo_unittest.cc2
-rw-r--r--tools/checkdeps/testdata/disallowed/test.h2
-rwxr-xr-xtools/checklicenses/checklicenses.py40
-rwxr-xr-xtools/checkperms/checkperms.py73
-rw-r--r--tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp9
-rw-r--r--tools/clang/blink_gc_plugin/tests/own_ptr_to_gc_managed_class.h1
-rw-r--r--tools/clang/blink_gc_plugin/tests/own_ptr_to_gc_managed_class.txt3
-rw-r--r--tools/cr/cr/targets/chrome_shell.py2
-rw-r--r--tools/cygprofile/PRESUBMIT.py34
-rw-r--r--tools/cygprofile/cygprofile.cc592
-rw-r--r--tools/cygprofile/cygprofile.gyp23
-rw-r--r--tools/cygprofile/cygprofile.h166
-rw-r--r--tools/cygprofile/cygprofile_unittest.cc101
-rwxr-xr-xtools/cygprofile/mergetraces.py68
-rw-r--r--tools/cygprofile/mergetraces_unittest.py51
-rwxr-xr-xtools/cygprofile/run_tests25
-rwxr-xr-xtools/gen_keyboard_overlay_data/gen_keyboard_overlay_data.py26
-rw-r--r--tools/gn/BUILD.gn4
-rw-r--r--tools/gn/bin/linux/gn.sha12
-rw-r--r--tools/gn/bin/linux/gn32.sha12
-rw-r--r--tools/gn/bin/mac/gn.sha12
-rw-r--r--tools/gn/bin/win/gn.exe.sha12
-rw-r--r--tools/gn/builder_unittest.cc2
-rw-r--r--tools/gn/command_desc.cc45
-rw-r--r--tools/gn/escape.cc191
-rw-r--r--tools/gn/escape.h27
-rw-r--r--tools/gn/escape_unittest.cc84
-rw-r--r--tools/gn/file_template.cc6
-rw-r--r--tools/gn/file_template_unittest.cc10
-rw-r--r--tools/gn/function_get_path_info.cc197
-rw-r--r--tools/gn/function_get_path_info_unittest.cc89
-rw-r--r--tools/gn/function_rebase_path.cc7
-rw-r--r--tools/gn/functions.cc1
-rw-r--r--tools/gn/functions.h8
-rw-r--r--tools/gn/gn.gyp4
-rw-r--r--tools/gn/ninja_action_target_writer.cc5
-rw-r--r--tools/gn/ninja_action_target_writer_unittest.cc82
-rw-r--r--tools/gn/ninja_binary_target_writer.cc50
-rw-r--r--tools/gn/ninja_binary_target_writer_unittest.cc36
-rw-r--r--tools/gn/ninja_build_writer.cc4
-rw-r--r--tools/gn/ninja_target_writer.cc7
-rw-r--r--tools/gn/ninja_toolchain_writer.cc4
-rw-r--r--tools/gn/path_output.cc16
-rw-r--r--tools/gn/path_output.h17
-rw-r--r--tools/gn/path_output_unittest.cc80
-rw-r--r--tools/gn/run_all_unittests.cc13
-rw-r--r--tools/gn/secondary/chrome/BUILD.gn6
-rw-r--r--tools/gn/secondary/sdch/BUILD.gn62
-rw-r--r--tools/gn/secondary/testing/BUILD.gn11
-rw-r--r--tools/gn/secondary/testing/gmock/BUILD.gn3
-rw-r--r--tools/gn/secondary/third_party/angle/BUILD.gn2
-rw-r--r--tools/gn/secondary/third_party/icu/BUILD.gn11
-rw-r--r--tools/gn/secondary/third_party/nss/BUILD.gn8
-rw-r--r--tools/gn/secondary/tools/grit/grit_rule.gni25
-rw-r--r--tools/gn/target.cc9
-rw-r--r--tools/gn/target_unittest.cc9
-rw-r--r--tools/gn/visibility.cc30
-rw-r--r--tools/gn/visibility.h7
-rw-r--r--tools/gritsettings/resource_ids7
-rwxr-xr-xtools/gypv8sh.py18
-rw-r--r--tools/ipc_fuzzer/mutate/generate.cc13
-rw-r--r--tools/ipc_fuzzer/replay/replay_process.cc9
-rwxr-xr-xtools/isolate_driver.py32
-rw-r--r--tools/json_schema_compiler/api_gen_util.target.darwin-arm.mk2
-rw-r--r--tools/json_schema_compiler/api_gen_util.target.darwin-arm64.mk2
-rw-r--r--tools/json_schema_compiler/api_gen_util.target.darwin-mips.mk2
-rw-r--r--tools/json_schema_compiler/api_gen_util.target.darwin-x86.mk2
-rw-r--r--tools/json_schema_compiler/api_gen_util.target.darwin-x86_64.mk2
-rw-r--r--tools/json_schema_compiler/api_gen_util.target.linux-arm.mk2
-rw-r--r--tools/json_schema_compiler/api_gen_util.target.linux-arm64.mk2
-rw-r--r--tools/json_schema_compiler/api_gen_util.target.linux-mips.mk2
-rw-r--r--tools/json_schema_compiler/api_gen_util.target.linux-x86.mk2
-rw-r--r--tools/json_schema_compiler/api_gen_util.target.linux-x86_64.mk2
-rw-r--r--tools/json_schema_compiler/cc_generator.py16
-rw-r--r--tools/json_schema_compiler/idl_schema.py10
-rw-r--r--tools/json_schema_compiler/test/enums_unittest.cc5
-rw-r--r--tools/metrics/histograms/histograms.xml886
-rw-r--r--tools/metrics/rappor/rappor.xml39
-rw-r--r--tools/msan/blacklist.txt14
-rw-r--r--tools/perf/OWNERS2
-rw-r--r--tools/perf/PRESUBMIT.py2
-rw-r--r--tools/perf/benchmarks/benchmark_unittest.py2
-rw-r--r--tools/perf/benchmarks/blink_perf.py2
-rw-r--r--tools/perf/benchmarks/chrome_proxy.py35
-rw-r--r--tools/perf/benchmarks/dom_perf.py2
-rw-r--r--tools/perf/benchmarks/doyouevenbench.py62
-rw-r--r--tools/perf/benchmarks/dromaeo.py2
-rw-r--r--tools/perf/benchmarks/image_decoding.py2
-rw-r--r--tools/perf/benchmarks/jetstream.py83
-rw-r--r--tools/perf/benchmarks/jsgamebench.py12
-rw-r--r--tools/perf/benchmarks/kraken.py2
-rw-r--r--tools/perf/benchmarks/memory.py14
-rw-r--r--tools/perf/benchmarks/memory_pressure.py2
-rw-r--r--tools/perf/benchmarks/octane.py2
-rw-r--r--tools/perf/benchmarks/page_cycler.py4
-rw-r--r--tools/perf/benchmarks/robohornet_pro.py2
-rw-r--r--tools/perf/benchmarks/session_restore.py51
-rw-r--r--tools/perf/benchmarks/session_restore_with_url.py24
-rw-r--r--tools/perf/benchmarks/smoothness.py2
-rw-r--r--tools/perf/benchmarks/spaceport.py2
-rw-r--r--tools/perf/benchmarks/speedometer.py47
-rw-r--r--tools/perf/benchmarks/sunspider.py2
-rw-r--r--tools/perf/benchmarks/tab_switching.py3
-rw-r--r--tools/perf/benchmarks/thread_times.py2
-rw-r--r--tools/perf/measurements/image_decoding.py2
-rw-r--r--tools/perf/measurements/memory.py2
-rw-r--r--tools/perf/measurements/page_cycler.py2
-rw-r--r--tools/perf/measurements/rasterize_and_record_micro.py2
-rw-r--r--tools/perf/measurements/session_restore.py15
-rw-r--r--tools/perf/measurements/skpicture_printer.py2
-rw-r--r--tools/perf/measurements/smoothness.py2
-rw-r--r--tools/perf/measurements/smoothness_controller.py7
-rw-r--r--tools/perf/measurements/smoothness_unittest.py17
-rw-r--r--tools/perf/measurements/timeline_controller.py7
-rw-r--r--tools/perf/page_sets/PRESUBMIT.py2
-rw-r--r--tools/perf/page_sets/__init__.py2
-rw-r--r--tools/perf/page_sets/calendar_forward_backward.py17
-rw-r--r--tools/perf/page_sets/data/jetstream.json (renamed from tools/perf/page_sets/data/doyouevenbench.json)4
-rw-r--r--tools/perf/page_sets/data/jetstream_000.wpr.sha11
-rw-r--r--tools/perf/page_sets/data/speedometer.json8
-rw-r--r--tools/perf/page_sets/data/speedometer_000.wpr.sha11
-rw-r--r--tools/perf/page_sets/data/tough_compositor_cases.json10
-rw-r--r--tools/perf/page_sets/data/tough_compositor_cases_001.wpr.sha11
-rw-r--r--tools/perf/page_sets/data/typical_25.json6
-rw-r--r--tools/perf/page_sets/data/typical_25_001.wpr.sha11
-rw-r--r--tools/perf/page_sets/gmail_compose_discard.py8
-rw-r--r--tools/perf/page_sets/image_decoding_measurement.py5
-rw-r--r--tools/perf/page_sets/key_silk_cases.py17
-rw-r--r--tools/perf/page_sets/polymer.py14
-rw-r--r--tools/perf/page_sets/top_10.py12
-rw-r--r--tools/perf/page_sets/top_25.py107
-rw-r--r--tools/perf/page_sets/tough_compositor_cases.py6
-rw-r--r--tools/perf/page_sets/webrtc_cases.py5
-rw-r--r--tools/perf/profile_creators/__init__.py2
-rw-r--r--tools/perf/profile_creators/small_profile_creator.py6
-rw-r--r--tools/perf/unit-info.json4
-rw-r--r--tools/post_perf_builder_job.py39
-rwxr-xr-xtools/safely-roll-deps.py2
-rw-r--r--tools/telemetry/PRESUBMIT.py2
-rw-r--r--tools/telemetry/docs/telemetry.core.browser_finder.html4
-rwxr-xr-xtools/telemetry/examples/telemetry_perf_test.py2
-rw-r--r--tools/telemetry/telemetry/__init__.py2
-rw-r--r--tools/telemetry/telemetry/core/__init__.py2
-rw-r--r--tools/telemetry/telemetry/core/backends/chrome/android_browser_finder.py17
-rw-r--r--tools/telemetry/telemetry/core/backends/chrome/chrome_browser_backend.py9
-rw-r--r--tools/telemetry/telemetry/core/backends/chrome/cros_interface.py3
-rw-r--r--tools/telemetry/telemetry/core/backends/chrome/desktop_browser_backend.py33
-rw-r--r--tools/telemetry/telemetry/core/backends/chrome/inspector_backend.py10
-rw-r--r--tools/telemetry/telemetry/core/backends/chrome/inspector_page.py29
-rw-r--r--tools/telemetry/telemetry/core/backends/chrome/inspector_page_unittest.py9
-rw-r--r--tools/telemetry/telemetry/core/backends/webdriver/webdriver_tab_backend.py5
-rw-r--r--tools/telemetry/telemetry/core/browser.py2
-rw-r--r--tools/telemetry/telemetry/core/browser_credentials.py15
-rw-r--r--tools/telemetry/telemetry/core/browser_credentials_unittest.py2
-rw-r--r--tools/telemetry/telemetry/core/browser_finder.py2
-rw-r--r--tools/telemetry/telemetry/core/browser_options.py26
-rw-r--r--tools/telemetry/telemetry/core/browser_options_unittest.py9
-rw-r--r--tools/telemetry/telemetry/core/browser_unittest.py2
-rw-r--r--tools/telemetry/telemetry/core/discover.py2
-rw-r--r--tools/telemetry/telemetry/core/discover_unittest.py2
-rw-r--r--tools/telemetry/telemetry/core/environment.py2
-rw-r--r--tools/telemetry/telemetry/core/exceptions.py2
-rw-r--r--tools/telemetry/telemetry/core/extension_dict.py2
-rw-r--r--tools/telemetry/telemetry/core/extension_page.py2
-rw-r--r--tools/telemetry/telemetry/core/extension_to_load.py2
-rw-r--r--tools/telemetry/telemetry/core/extension_unittest.py2
-rw-r--r--tools/telemetry/telemetry/core/memory_cache_http_server.py2
-rw-r--r--tools/telemetry/telemetry/core/platform/__init__.py2
-rw-r--r--tools/telemetry/telemetry/core/platform/android_platform_backend.py2
-rw-r--r--tools/telemetry/telemetry/core/platform/cros_platform_backend.py2
-rw-r--r--tools/telemetry/telemetry/core/platform/linux_platform_backend.py2
-rw-r--r--tools/telemetry/telemetry/core/platform/mac_platform_backend.py2
-rw-r--r--tools/telemetry/telemetry/core/platform/platform_backend.py2
-rw-r--r--tools/telemetry/telemetry/core/platform/profiler/__init__.py2
-rw-r--r--tools/telemetry/telemetry/core/platform/profiler/iprofiler_profiler.py2
-rw-r--r--tools/telemetry/telemetry/core/platform/profiler/java_heap_profiler.py2
-rw-r--r--tools/telemetry/telemetry/core/platform/profiler/perf_profiler.py2
-rw-r--r--tools/telemetry/telemetry/core/platform/profiler/profiler_finder.py2
-rw-r--r--tools/telemetry/telemetry/core/platform/profiler/sample_profiler.py2
-rw-r--r--tools/telemetry/telemetry/core/platform/profiler/tcmalloc_heap_profiler.py2
-rw-r--r--tools/telemetry/telemetry/core/platform/win_platform_backend.py2
-rw-r--r--tools/telemetry/telemetry/core/possible_browser.py2
-rw-r--r--tools/telemetry/telemetry/core/profile_types.py2
-rw-r--r--tools/telemetry/telemetry/core/profile_types_unittest.py2
-rw-r--r--tools/telemetry/telemetry/core/tab.py22
-rw-r--r--tools/telemetry/telemetry/core/tab_list.py2
-rw-r--r--tools/telemetry/telemetry/core/tab_unittest.py20
-rw-r--r--tools/telemetry/telemetry/core/timeline/event.py2
-rw-r--r--tools/telemetry/telemetry/core/timeline/event_unittest.py2
-rw-r--r--tools/telemetry/telemetry/core/timeline/importer.py2
-rw-r--r--tools/telemetry/telemetry/core/timeline/inspector_importer.py2
-rw-r--r--tools/telemetry/telemetry/core/timeline/inspector_importer_unittest.py2
-rw-r--r--tools/telemetry/telemetry/core/timeline/model.py2
-rw-r--r--tools/telemetry/telemetry/core/timeline/model_unittest.py2
-rw-r--r--tools/telemetry/telemetry/core/user_agent.py2
-rw-r--r--tools/telemetry/telemetry/core/user_agent_unittest.py2
-rw-r--r--tools/telemetry/telemetry/core/util.py2
-rw-r--r--tools/telemetry/telemetry/core/util_unittest.py2
-rw-r--r--tools/telemetry/telemetry/core/web_contents.py2
-rw-r--r--tools/telemetry/telemetry/core/webpagereplay.py2
-rw-r--r--tools/telemetry/telemetry/core/wpr_modes.py2
-rw-r--r--tools/telemetry/telemetry/core/wpr_server.py2
-rw-r--r--tools/telemetry/telemetry/page/__init__.py2
-rw-r--r--tools/telemetry/telemetry/page/actions/action_runner.py97
-rw-r--r--tools/telemetry/telemetry/page/actions/action_runner_unittest.py25
-rw-r--r--tools/telemetry/telemetry/page/actions/all_page_actions.py3
-rw-r--r--tools/telemetry/telemetry/page/actions/gesture_action.py8
-rw-r--r--tools/telemetry/telemetry/page/actions/javascript.py4
-rw-r--r--tools/telemetry/telemetry/page/actions/js_collect_garbage.py2
-rw-r--r--tools/telemetry/telemetry/page/actions/page_action.py2
-rw-r--r--tools/telemetry/telemetry/page/actions/play.py2
-rw-r--r--tools/telemetry/telemetry/page/actions/reload.py2
-rw-r--r--tools/telemetry/telemetry/page/actions/scroll.py2
-rw-r--r--tools/telemetry/telemetry/page/actions/scroll_unittest.py2
-rw-r--r--tools/telemetry/telemetry/page/actions/wait.py2
-rw-r--r--tools/telemetry/telemetry/page/actions/wait_unittest.py2
-rw-r--r--tools/telemetry/telemetry/page/actions/wait_until.py8
-rw-r--r--tools/telemetry/telemetry/page/block_page_measurement_results.py2
-rw-r--r--tools/telemetry/telemetry/page/block_page_measurement_results_unittest.py2
-rw-r--r--tools/telemetry/telemetry/page/buildbot_page_measurement_results.py2
-rw-r--r--tools/telemetry/telemetry/page/buildbot_page_measurement_results_unittest.py2
-rw-r--r--tools/telemetry/telemetry/page/cloud_storage.py2
-rw-r--r--tools/telemetry/telemetry/page/csv_page_measurement_results.py2
-rw-r--r--tools/telemetry/telemetry/page/csv_page_measurement_results_unittest.py2
-rw-r--r--tools/telemetry/telemetry/page/gtest_test_results.py2
-rw-r--r--tools/telemetry/telemetry/page/page.py2
-rw-r--r--tools/telemetry/telemetry/page/page_filter.py2
-rw-r--r--tools/telemetry/telemetry/page/page_measurement.py2
-rw-r--r--tools/telemetry/telemetry/page/page_measurement_results.py2
-rw-r--r--tools/telemetry/telemetry/page/page_measurement_results_unittest.py2
-rw-r--r--tools/telemetry/telemetry/page/page_measurement_unittest.py2
-rw-r--r--tools/telemetry/telemetry/page/page_measurement_unittest_base.py2
-rw-r--r--tools/telemetry/telemetry/page/page_runner.py2
-rw-r--r--tools/telemetry/telemetry/page/page_runner_unittest.py2
-rw-r--r--tools/telemetry/telemetry/page/page_set.py2
-rw-r--r--tools/telemetry/telemetry/page/page_set_archive_info.py2
-rw-r--r--tools/telemetry/telemetry/page/page_set_archive_info_unittest.py2
-rw-r--r--tools/telemetry/telemetry/page/page_set_unittest.py2
-rw-r--r--tools/telemetry/telemetry/page/page_test.py2
-rw-r--r--tools/telemetry/telemetry/page/page_test_results.py2
-rw-r--r--tools/telemetry/telemetry/page/page_test_unittest.py2
-rw-r--r--tools/telemetry/telemetry/page/page_unittest.py2
-rw-r--r--tools/telemetry/telemetry/page/perf_tests_helper.py2
-rwxr-xr-xtools/telemetry/telemetry/page/record_wpr.py27
-rw-r--r--tools/telemetry/telemetry/test.py23
-rw-r--r--tools/telemetry/telemetry/test_runner.py4
-rw-r--r--tools/telemetry/telemetry/unittest/__init__.py2
-rwxr-xr-xtools/telemetry/telemetry/unittest/gtest_testrunner.py2
-rw-r--r--tools/telemetry/telemetry/unittest/options_for_unittests.py2
-rw-r--r--tools/telemetry/telemetry/unittest/page_set_smoke_test.py122
-rw-r--r--tools/telemetry/telemetry/unittest/run_tests.py2
-rw-r--r--tools/telemetry/telemetry/unittest/simple_mock.py2
-rw-r--r--tools/telemetry/telemetry/unittest/simple_mock_unittest.py2
-rw-r--r--tools/telemetry/telemetry/unittest/system_stub.py2
-rw-r--r--tools/telemetry/telemetry/unittest/tab_test_case.py2
-rw-r--r--tools/telemetry/telemetry/web_components/__init__.py2
-rw-r--r--tools/telemetry/telemetry/web_components/dev_server.py2
-rw-r--r--tools/telemetry/telemetry/web_components/results_viewer.py2
-rw-r--r--tools/telemetry/telemetry/web_components/tvcm_stub.py2
-rw-r--r--tools/telemetry/telemetry/web_components/web_components_project.py2
-rw-r--r--tools/telemetry/telemetry/web_components/web_components_unittest.py2
-rw-r--r--tools/telemetry/telemetry/web_perf/metrics/mainthread_jank_stats.py91
-rw-r--r--tools/telemetry/telemetry/web_perf/metrics/mainthread_jank_stats_unittest.py118
-rw-r--r--tools/telemetry/telemetry/web_perf/metrics/rendering_stats.py136
-rw-r--r--tools/telemetry/telemetry/web_perf/metrics/rendering_stats_unittest.py107
-rw-r--r--tools/telemetry/telemetry/web_perf/metrics/responsiveness_metric.py47
-rw-r--r--tools/telemetry/telemetry/web_perf/metrics/smoothness.py38
-rw-r--r--tools/telemetry/telemetry/web_perf/timeline_based_measurement.py8
-rw-r--r--tools/telemetry/telemetry/web_perf/timeline_based_measurement_unittest.py67
-rw-r--r--tools/telemetry/telemetry/web_perf/timeline_interaction_record.py42
-rw-r--r--tools/telemetry/telemetry/web_perf/timeline_interaction_record_unittest.py39
-rw-r--r--tools/telemetry/unittest_data/discoverable_classes/__init__.py2
-rw-r--r--tools/telemetry/unittest_data/discoverable_classes/discover_dummyclass.py2
-rw-r--r--tools/telemetry/unittest_data/interaction_enabled_page.html15
-rw-r--r--tools/valgrind/drmemory/suppressions.txt35
-rw-r--r--tools/valgrind/drmemory/suppressions_full.txt18
-rw-r--r--tools/valgrind/gtest_exclude/browser_tests.gtest-drmemory_win32.txt33
-rw-r--r--tools/valgrind/memcheck/suppressions.txt144
-rw-r--r--tools/valgrind/memcheck/suppressions_mac.txt22
-rw-r--r--tools/valgrind/tsan/suppressions.txt33
302 files changed, 4241 insertions, 1894 deletions
diff --git a/tools/binary_size/run_binary_size_analysis.py b/tools/binary_size/run_binary_size_analysis.py
index aa46f6f675..4168874c86 100755
--- a/tools/binary_size/run_binary_size_analysis.py
+++ b/tools/binary_size/run_binary_size_analysis.py
@@ -455,26 +455,41 @@ def RunElfSymbolizer(outfile, library, addr2line_binary, nm_binary, jobs):
symbolizer = elf_symbolizer.ELFSymbolizer(library, addr2line_binary,
map_address_symbol,
max_concurrent_jobs=jobs)
- for line in nm_output_lines:
- match = sNmPattern.match(line)
- if match:
- location = match.group(5)
- if not location:
- addr = int(match.group(1), 16)
- size = int(match.group(2), 16)
- if addr in address_symbol: # Already looked up, shortcut ELFSymbolizer.
- map_address_symbol(address_symbol[addr], addr)
- continue
- elif size == 0:
- # Save time by not looking up empty symbols (do they even exist?)
- print('Empty symbol: ' + line)
- else:
- symbolizer.SymbolizeAsync(addr, addr)
- continue
+ user_interrupted = False
+ try:
+ for line in nm_output_lines:
+ match = sNmPattern.match(line)
+ if match:
+ location = match.group(5)
+ if not location:
+ addr = int(match.group(1), 16)
+ size = int(match.group(2), 16)
+ if addr in address_symbol: # Already looked up, shortcut
+ # ELFSymbolizer.
+ map_address_symbol(address_symbol[addr], addr)
+ continue
+ elif size == 0:
+ # Save time by not looking up empty symbols (do they even exist?)
+ print('Empty symbol: ' + line)
+ else:
+ symbolizer.SymbolizeAsync(addr, addr)
+ continue
+
+ progress.skip_count += 1
+ except KeyboardInterrupt:
+ user_interrupted = True
+ print('Interrupting - killing subprocesses. Please wait.')
- progress.skip_count += 1
+ try:
+ symbolizer.Join()
+ except KeyboardInterrupt:
+ # Don't want to abort here since we will be finished in a few seconds.
+ user_interrupted = True
+ print('Patience you must have my young padawan.')
- symbolizer.Join()
+ if user_interrupted:
+ print('Skipping the rest of the file mapping. '
+ 'Output will not be fully classified.')
with open(outfile, 'w') as out:
for line in nm_output_lines:
@@ -483,15 +498,16 @@ def RunElfSymbolizer(outfile, library, addr2line_binary, nm_binary, jobs):
location = match.group(5)
if not location:
addr = int(match.group(1), 16)
- symbol = address_symbol[addr]
- path = '??'
- if symbol.source_path is not None:
- path = symbol.source_path
- line_number = 0
- if symbol.source_line is not None:
- line_number = symbol.source_line
- out.write('%s\t%s:%d\n' % (line, path, line_number))
- continue
+ symbol = address_symbol.get(addr)
+ if symbol is not None:
+ path = '??'
+ if symbol.source_path is not None:
+ path = symbol.source_path
+ line_number = 0
+ if symbol.source_line is not None:
+ line_number = symbol.source_line
+ out.write('%s\t%s:%d\n' % (line, path, line_number))
+ continue
out.write('%s\n' % line)
@@ -500,7 +516,8 @@ def RunElfSymbolizer(outfile, library, addr2line_binary, nm_binary, jobs):
def RunNm(binary, nm_binary):
print('Starting nm')
- cmd = [nm_binary, '-C', '--print-size', binary]
+ cmd = [nm_binary, '-C', '--print-size', '--size-sort', '--reverse-sort',
+ binary]
nm_process = subprocess.Popen(cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
@@ -678,12 +695,10 @@ def main():
'template')
shutil.copy(os.path.join(d3_src, 'LICENSE'), d3_out)
shutil.copy(os.path.join(d3_src, 'd3.js'), d3_out)
- print('Copying index.html')
shutil.copy(os.path.join(template_src, 'index.html'), opts.destdir)
shutil.copy(os.path.join(template_src, 'D3SymbolTreeMap.js'), opts.destdir)
- if opts.verbose:
- print 'Report saved to ' + opts.destdir + '/index.html'
+ print 'Report saved to ' + opts.destdir + '/index.html'
if __name__ == '__main__':
diff --git a/tools/bisect-perf-regression.py b/tools/bisect-perf-regression.py
index 674a782df2..7444d37003 100755
--- a/tools/bisect-perf-regression.py
+++ b/tools/bisect-perf-regression.py
@@ -54,7 +54,7 @@ import zipfile
sys.path.append(os.path.join(os.path.dirname(__file__), 'telemetry'))
import bisect_utils
-import post_perf_builder_job
+import post_perf_builder_job as bisect_builder
from telemetry.page import cloud_storage
# The additional repositories that might need to be bisected.
@@ -522,10 +522,15 @@ def ExtractZip(filename, output_dir, verbose=True):
# handle links and file bits (executable), which is much
# easier then trying to do that with ZipInfo options.
#
+ # The Mac Version of unzip unfortunately does not support Zip64, whereas
+ # the python module does, so we have to fallback to the python zip module
+ # on Mac if the filesize is greater than 4GB.
+ #
# On Windows, try to use 7z if it is installed, otherwise fall back to python
# zip module and pray we don't have files larger than 512MB to unzip.
unzip_cmd = None
- if IsMac() or IsLinux():
+ if ((IsMac() and os.path.getsize(filename) < 4 * 1024 * 1024 * 1024)
+ or IsLinux()):
unzip_cmd = ['unzip', '-o']
elif IsWindows() and os.path.exists('C:\\Program Files\\7-Zip\\7z.exe'):
unzip_cmd = ['C:\\Program Files\\7-Zip\\7z.exe', 'x', '-y']
@@ -541,12 +546,16 @@ def ExtractZip(filename, output_dir, verbose=True):
if result:
raise IOError('unzip failed: %s => %s' % (str(command), result))
else:
- assert IsWindows()
+ assert IsWindows() or IsMac()
zf = zipfile.ZipFile(filename)
for name in zf.namelist():
if verbose:
print 'Extracting %s' % name
zf.extract(name, output_dir)
+ if IsMac():
+ # Restore permission bits.
+ os.chmod(os.path.join(output_dir, name),
+ zf.getinfo(name).external_attr >> 16L)
def RunProcess(command):
@@ -1429,16 +1438,17 @@ class BisectPerformanceMetrics(object):
continue
if (depot_data.get('recurse') and depot in depot_data.get('from')):
- src_dir = (deps_data.get(depot_data.get('src')) or
- deps_data.get(depot_data.get('src_old')))
+ depot_data_src = depot_data.get('src') or depot_data.get('src_old')
+ src_dir = deps_data.get(depot_data_src)
if src_dir:
- self.depot_cwd[depot_name] = os.path.join(self.src_cwd, src_dir[4:])
- re_results = rxp.search(deps_data.get(src_dir, ''))
+ self.depot_cwd[depot_name] = os.path.join(self.src_cwd,
+ depot_data_src[4:])
+ re_results = rxp.search(src_dir)
if re_results:
results[depot_name] = re_results.group('revision')
else:
warning_text = ('Couldn\'t parse revision for %s while bisecting '
- '%s' % (depot_name, depot))
+ '%s' % (depot_name, depot))
if not warning_text in self.warnings:
self.warnings.append(warning_text)
else:
@@ -1574,7 +1584,7 @@ class BisectPerformanceMetrics(object):
if not fetch_build_func():
if not self.PostBuildRequestAndWait(revision,
- condition=fetch_build_func,
+ fetch_build=fetch_build_func,
patch=patch):
raise RuntimeError('Somewthing went wrong while processing build'
'request for: %s' % revision)
@@ -1606,7 +1616,59 @@ class BisectPerformanceMetrics(object):
os.remove(downloaded_file)
return False
- def PostBuildRequestAndWait(self, revision, condition, patch=None):
+ def WaitUntilBuildIsReady(self, fetch_build, bot_name, builder_host,
+ builder_port, build_request_id, max_timeout):
+ """Waits until build is produced by bisect builder on tryserver.
+
+ Args:
+ fetch_build: Function to check and download build from cloud storage.
+ bot_name: Builder bot name on tryserver.
+ builder_host Tryserver hostname.
+ builder_port: Tryserver port.
+ build_request_id: A unique ID of the build request posted to tryserver.
+ max_timeout: Maximum time to wait for the build.
+
+ Returns:
+ True if build exists and download is successful, otherwise throws
+ RuntimeError exception when time elapse.
+ """
+ # Build number on the tryserver.
+ build_num = None
+ # Interval to check build on cloud storage.
+ poll_interval = 60
+ # Interval to check build status on tryserver.
+ status_check_interval = 600
+ last_status_check = time.time()
+ start_time = time.time()
+ while True:
+ # Checks for build on gs://chrome-perf and download if exists.
+ res = fetch_build()
+ if res:
+ return (res, 'Build successfully found')
+ elapsed_status_check = time.time() - last_status_check
+ # To avoid overloading tryserver with status check requests, we check
+ # build status for every 10 mins.
+ if elapsed_status_check > status_check_interval:
+ last_status_check = time.time()
+ if not build_num:
+ # Get the build number on tryserver for the current build.
+ build_num = bisect_builder.GetBuildNumFromBuilder(
+ build_request_id, bot_name, builder_host, builder_port)
+ # Check the status of build using the build number.
+ # Note: Build is treated as PENDING if build number is not found
+ # on the the tryserver.
+ build_status, status_link = bisect_builder.GetBuildStatus(
+ build_num, bot_name, builder_host, builder_port)
+ if build_status == bisect_builder.FAILED:
+ return (False, 'Failed to produce build, log: %s' % status_link)
+ elapsed_time = time.time() - start_time
+ if elapsed_time > max_timeout:
+ return (False, 'Timed out: %ss without build' % max_timeout)
+
+ print 'Time elapsed: %ss without build.' % elapsed_time
+ time.sleep(poll_interval)
+
+ def PostBuildRequestAndWait(self, revision, fetch_build, patch=None):
"""POSTs the build request job to the tryserver instance."""
def GetBuilderNameAndBuildTime(target_arch='ia32'):
@@ -1622,19 +1684,20 @@ class BisectPerformanceMetrics(object):
if IsMac():
return ('mac_perf_bisect_builder', MAX_MAC_BUILD_TIME)
raise NotImplementedError('Unsupported Platform "%s".' % sys.platform)
- if not condition:
+ if not fetch_build:
return False
bot_name, build_timeout = GetBuilderNameAndBuildTime(self.opts.target_arch)
-
- # Create a unique ID for each build request posted to try server builders.
+ builder_host = self.opts.builder_host
+ builder_port = self.opts.builder_port
+ # Create a unique ID for each build request posted to tryserver builders.
# This ID is added to "Reason" property in build's json.
- # TODO: Use this id to track the build status.
- build_request_id = GetSHA1HexDigest('%s-%s' % (revision, patch))
+ build_request_id = GetSHA1HexDigest(
+ '%s-%s-%s' % (revision, patch, time.time()))
# Creates a try job description.
- job_args = {'host': self.opts.builder_host,
- 'port': self.opts.builder_port,
+ job_args = {'host': builder_host,
+ 'port': builder_port,
'revision': 'src@%s' % revision,
'bot': bot_name,
'name': build_request_id
@@ -1643,20 +1706,16 @@ class BisectPerformanceMetrics(object):
if patch:
job_args['patch'] = patch
# Posts job to build the revision on the server.
- if post_perf_builder_job.PostTryJob(job_args):
- poll_interval = 60
- start_time = time.time()
- while True:
- res = condition()
- if res:
- return res
- elapsed_time = time.time() - start_time
- if elapsed_time > build_timeout:
- raise RuntimeError('Timed out while waiting %ds for %s build.' %
- (build_timeout, revision))
- print ('Time elapsed: %ss, still waiting for %s build' %
- (elapsed_time, revision))
- time.sleep(poll_interval)
+ if bisect_builder.PostTryJob(job_args):
+ status, error_msg = self.WaitUntilBuildIsReady(fetch_build,
+ bot_name,
+ builder_host,
+ builder_port,
+ build_request_id,
+ build_timeout)
+ if not status:
+ raise RuntimeError('%s [revision: %s]' % (error_msg, revision))
+ return True
return False
def IsDownloadable(self, depot):
diff --git a/tools/checkdeps/PRESUBMIT.py b/tools/checkdeps/PRESUBMIT.py
index 10ef63212f..5880d2647e 100644
--- a/tools/checkdeps/PRESUBMIT.py
+++ b/tools/checkdeps/PRESUBMIT.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/checkdeps/builddeps.py b/tools/checkdeps/builddeps.py
index 0057f635c2..16dd7f3c17 100755
--- a/tools/checkdeps/builddeps.py
+++ b/tools/checkdeps/builddeps.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-# Copyright 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/checkdeps/checkdeps.py b/tools/checkdeps/checkdeps.py
index 5bf7907606..83f59ae4dd 100755
--- a/tools/checkdeps/checkdeps.py
+++ b/tools/checkdeps/checkdeps.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-# Copyright 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/checkdeps/checkdeps_test.py b/tools/checkdeps/checkdeps_test.py
index e8835a5ca8..1f93db5389 100755
--- a/tools/checkdeps/checkdeps_test.py
+++ b/tools/checkdeps/checkdeps_test.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/checkdeps/cpp_checker.py b/tools/checkdeps/cpp_checker.py
index 94fd37a921..ca28e4d4ac 100644
--- a/tools/checkdeps/cpp_checker.py
+++ b/tools/checkdeps/cpp_checker.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/checkdeps/graphdeps.py b/tools/checkdeps/graphdeps.py
index 208772f057..e6dee8ec6a 100755
--- a/tools/checkdeps/graphdeps.py
+++ b/tools/checkdeps/graphdeps.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-# Copyright 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/checkdeps/java_checker.py b/tools/checkdeps/java_checker.py
index 36e46230f4..1d5cecf627 100644
--- a/tools/checkdeps/java_checker.py
+++ b/tools/checkdeps/java_checker.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/checkdeps/results.py b/tools/checkdeps/results.py
index b52880ccca..6f69514f0d 100644
--- a/tools/checkdeps/results.py
+++ b/tools/checkdeps/results.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/checkdeps/rules.py b/tools/checkdeps/rules.py
index 199c18f367..9dfdc4a126 100644
--- a/tools/checkdeps/rules.py
+++ b/tools/checkdeps/rules.py
@@ -1,4 +1,4 @@
-# Copyright 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/checkdeps/testdata/allowed/foo_unittest.cc b/tools/checkdeps/testdata/allowed/foo_unittest.cc
index 754f295eb5..027adf856a 100644
--- a/tools/checkdeps/testdata/allowed/foo_unittest.cc
+++ b/tools/checkdeps/testdata/allowed/foo_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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.
diff --git a/tools/checkdeps/testdata/allowed/not_a_test.cc b/tools/checkdeps/testdata/allowed/not_a_test.cc
index 7b2a105d53..57fa942831 100644
--- a/tools/checkdeps/testdata/allowed/not_a_test.cc
+++ b/tools/checkdeps/testdata/allowed/not_a_test.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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.
diff --git a/tools/checkdeps/testdata/allowed/test.h b/tools/checkdeps/testdata/allowed/test.h
index ea33090050..b78bb2d7c9 100644
--- a/tools/checkdeps/testdata/allowed/test.h
+++ b/tools/checkdeps/testdata/allowed/test.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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.
diff --git a/tools/checkdeps/testdata/checkdeps_test/allowed/foo_unittest.cc b/tools/checkdeps/testdata/checkdeps_test/allowed/foo_unittest.cc
index 1a507eca4e..68beabfa9d 100644
--- a/tools/checkdeps/testdata/checkdeps_test/allowed/foo_unittest.cc
+++ b/tools/checkdeps/testdata/checkdeps_test/allowed/foo_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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.
diff --git a/tools/checkdeps/testdata/checkdeps_test/allowed/not_a_test.cc b/tools/checkdeps/testdata/checkdeps_test/allowed/not_a_test.cc
index 4278d64763..9e5e0cfd78 100644
--- a/tools/checkdeps/testdata/checkdeps_test/allowed/not_a_test.cc
+++ b/tools/checkdeps/testdata/checkdeps_test/allowed/not_a_test.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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.
diff --git a/tools/checkdeps/testdata/checkdeps_test/allowed/test.h b/tools/checkdeps/testdata/checkdeps_test/allowed/test.h
index 2dbd7a38b4..f8e4e65d07 100644
--- a/tools/checkdeps/testdata/checkdeps_test/allowed/test.h
+++ b/tools/checkdeps/testdata/checkdeps_test/allowed/test.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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.
diff --git a/tools/checkdeps/testdata/checkdeps_test/disallowed/allowed/skipped/test.h b/tools/checkdeps/testdata/checkdeps_test/disallowed/allowed/skipped/test.h
index 80105968e2..96fde19e45 100644
--- a/tools/checkdeps/testdata/checkdeps_test/disallowed/allowed/skipped/test.h
+++ b/tools/checkdeps/testdata/checkdeps_test/disallowed/allowed/skipped/test.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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.
diff --git a/tools/checkdeps/testdata/checkdeps_test/disallowed/allowed/test.h b/tools/checkdeps/testdata/checkdeps_test/disallowed/allowed/test.h
index aa5013d25d..54f08c339a 100644
--- a/tools/checkdeps/testdata/checkdeps_test/disallowed/allowed/test.h
+++ b/tools/checkdeps/testdata/checkdeps_test/disallowed/allowed/test.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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.
diff --git a/tools/checkdeps/testdata/checkdeps_test/disallowed/test.h b/tools/checkdeps/testdata/checkdeps_test/disallowed/test.h
index 5520a68c8f..15c4d5e893 100644
--- a/tools/checkdeps/testdata/checkdeps_test/disallowed/test.h
+++ b/tools/checkdeps/testdata/checkdeps_test/disallowed/test.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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.
diff --git a/tools/checkdeps/testdata/disallowed/allowed/skipped/test.h b/tools/checkdeps/testdata/disallowed/allowed/skipped/test.h
index 80105968e2..96fde19e45 100644
--- a/tools/checkdeps/testdata/disallowed/allowed/skipped/test.h
+++ b/tools/checkdeps/testdata/disallowed/allowed/skipped/test.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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.
diff --git a/tools/checkdeps/testdata/disallowed/allowed/test.h b/tools/checkdeps/testdata/disallowed/allowed/test.h
index f7dc822c4b..3d46a5efcf 100644
--- a/tools/checkdeps/testdata/disallowed/allowed/test.h
+++ b/tools/checkdeps/testdata/disallowed/allowed/test.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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.
diff --git a/tools/checkdeps/testdata/disallowed/foo_unittest.cc b/tools/checkdeps/testdata/disallowed/foo_unittest.cc
index 144c05eb36..1186ccfe13 100644
--- a/tools/checkdeps/testdata/disallowed/foo_unittest.cc
+++ b/tools/checkdeps/testdata/disallowed/foo_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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.
diff --git a/tools/checkdeps/testdata/disallowed/test.h b/tools/checkdeps/testdata/disallowed/test.h
index d0128e3a96..59d712183e 100644
--- a/tools/checkdeps/testdata/disallowed/test.h
+++ b/tools/checkdeps/testdata/disallowed/test.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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.
diff --git a/tools/checklicenses/checklicenses.py b/tools/checklicenses/checklicenses.py
index 3c288d5067..c657efff9b 100755
--- a/tools/checklicenses/checklicenses.py
+++ b/tools/checklicenses/checklicenses.py
@@ -6,6 +6,7 @@
"""Makes sure that all files contain proper licensing information."""
+import json
import optparse
import os.path
import subprocess
@@ -261,9 +262,6 @@ PATH_SPECIFIC_WHITELISTED_LICENSES = {
'third_party/ocmock/OCMock': [ # http://crbug.com/98454
'UNKNOWN',
],
- 'third_party/pdfium': [ # http://crbug.com/374943
- 'UNKNOWN',
- ],
'third_party/ply/__init__.py': [
'UNKNOWN',
],
@@ -425,8 +423,8 @@ def check_licenses(options, args):
return 1
used_suppressions = set()
+ errors = []
- success = True
for line in stdout.splitlines():
filename, license = line.split(':', 1)
filename = os.path.relpath(filename.strip(), options.base_directory)
@@ -455,21 +453,16 @@ def check_licenses(options, args):
used_suppressions.update(set(matched_prefixes))
continue
- print "'%s' has non-whitelisted license '%s'" % (filename, license)
- success = False
+ errors.append({'filename': filename, 'license': license})
- if success:
- print "\nSUCCESS\n"
+ if options.json:
+ with open(options.json, 'w') as f:
+ json.dump(errors, f)
- if not len(args):
- unused_suppressions = set(
- PATH_SPECIFIC_WHITELISTED_LICENSES.keys()).difference(used_suppressions)
- if unused_suppressions:
- print "\nNOTE: unused suppressions detected:\n"
- print '\n'.join(unused_suppressions)
-
- return 0
- else:
+ if errors:
+ for error in errors:
+ print "'%s' has non-whitelisted license '%s'" % (
+ error['filename'], error['license'])
print "\nFAILED\n"
print "Please read",
print "http://www.chromium.org/developers/adding-3rd-party-libraries"
@@ -484,6 +477,18 @@ def check_licenses(options, args):
return 1
+ print "\nSUCCESS\n"
+
+ if not len(args):
+ unused_suppressions = set(
+ PATH_SPECIFIC_WHITELISTED_LICENSES.iterkeys()).difference(
+ used_suppressions)
+ if unused_suppressions:
+ print "\nNOTE: unused suppressions detected:\n"
+ print '\n'.join(unused_suppressions)
+
+ return 0
+
def main():
default_root = os.path.abspath(
@@ -500,6 +505,7 @@ def main():
action='store_true',
default=False,
help='Ignore path-specific license whitelist.')
+ option_parser.add_option('--json', help='Path to JSON output file')
options, args = option_parser.parse_args()
return check_licenses(options, args)
diff --git a/tools/checkperms/checkperms.py b/tools/checkperms/checkperms.py
index 9395c00d27..ffb08043c1 100755
--- a/tools/checkperms/checkperms.py
+++ b/tools/checkperms/checkperms.py
@@ -25,6 +25,7 @@ backslashes. All directories should be relative to the source root and all
file paths should be only lowercase.
"""
+import json
import logging
import optparse
import os
@@ -298,9 +299,9 @@ def has_shebang_or_is_elf(full_path):
return (data[:3] == '#!/', data == '\x7fELF')
-def check_file(root_path, rel_path, bare_output):
+def check_file(root_path, rel_path):
"""Checks the permissions of the file whose path is root_path + rel_path and
- returns an error if it is inconsistent.
+ returns an error if it is inconsistent. Returns None on success.
It is assumed that the file is not ignored by is_ignored().
@@ -310,6 +311,12 @@ def check_file(root_path, rel_path, bare_output):
shebang or ELF header and compares this with the executable bit on the file.
"""
full_path = os.path.join(root_path, rel_path)
+ def result_dict(error):
+ return {
+ 'error': error,
+ 'full_path': full_path,
+ 'rel_path': rel_path,
+ }
try:
bit = has_executable_bit(full_path)
except OSError:
@@ -320,40 +327,26 @@ def check_file(root_path, rel_path, bare_output):
if must_be_executable(rel_path):
if not bit:
- if bare_output:
- return full_path
- return '%s: Must have executable bit set' % full_path
+ return result_dict('Must have executable bit set')
return
if must_not_be_executable(rel_path):
if bit:
- if bare_output:
- return full_path
- return '%s: Must not have executable bit set' % full_path
+ return result_dict('Must not have executable bit set')
return
# For the others, it depends on the file header.
(shebang, elf) = has_shebang_or_is_elf(full_path)
if bit != (shebang or elf):
- if bare_output:
- return full_path
if bit:
- return '%s: Has executable bit but not shebang or ELF header' % full_path
+ return result_dict('Has executable bit but not shebang or ELF header')
if shebang:
- return '%s: Has shebang but not executable bit' % full_path
- return '%s: Has ELF header but not executable bit' % full_path
+ return result_dict('Has shebang but not executable bit')
+ return result_dict('Has ELF header but not executable bit')
-def check_files(root, files, bare_output):
- errors = []
- for rel_path in files:
- if is_ignored(rel_path):
- continue
-
- error = check_file(root, rel_path, bare_output)
- if error:
- errors.append(error)
-
- return errors
+def check_files(root, files):
+ gen = (check_file(root, f) for f in files if not is_ignored(f))
+ return filter(None, gen)
class ApiBase(object):
@@ -371,7 +364,7 @@ class ApiBase(object):
not must_not_be_executable(rel_path)):
self.count_read_header += 1
- return check_file(self.root_dir, rel_path, self.bare_output)
+ return check_file(self.root_dir, rel_path)
def check_dir(self, rel_path):
return self.check(rel_path)
@@ -502,6 +495,7 @@ Examples:
'--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('--json', help='Path to JSON output file')
options, args = parser.parse_args()
levels = [logging.ERROR, logging.INFO, logging.DEBUG]
@@ -514,26 +508,29 @@ Examples:
options.root = os.path.abspath(options.root)
if options.files:
- errors = check_files(options.root, options.files, options.bare)
- print '\n'.join(errors)
- return bool(errors)
+ # --file implies --bare (for PRESUBMIT.py).
+ options.bare = True
- api = get_scm(options.root, options.bare)
- if args:
- start_dir = args[0]
+ errors = check_files(options.root, options.files)
else:
- start_dir = api.root_dir
+ api = get_scm(options.root, options.bare)
+ start_dir = args[0] if args else api.root_dir
+ errors = api.check(start_dir)
- errors = api.check(start_dir)
+ if not options.bare:
+ print('Processed %s files, %d files where tested for shebang/ELF '
+ 'header' % (api.count, api.count_read_header))
- if not options.bare:
- print 'Processed %s files, %d files where tested for shebang/ELF header' % (
- api.count, api.count_read_header)
+ if options.json:
+ with open(options.json, 'w') as f:
+ json.dump(errors, f)
if errors:
- if not options.bare:
+ if options.bare:
+ print '\n'.join(e['full_path'] for e in errors)
+ else:
print '\nFAILED\n'
- print '\n'.join(errors)
+ print '\n'.join('%s: %s' % (e['full_path'], e['error']) for e in errors)
return 1
if not options.bare:
print '\nSUCCESS\n'
diff --git a/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp b/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp
index 0ea8f4cac3..d1d3a468ec 100644
--- a/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp
+++ b/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp
@@ -486,7 +486,7 @@ class CheckFieldsVisitor : public RecursiveEdgeVisitor {
return !invalid_fields_.empty();
}
- void VisitMember(Member* edge) override {
+ void AtMember(Member* edge) override {
if (managed_host_)
return;
// A member is allowed to appear in the context of a root.
@@ -499,7 +499,7 @@ class CheckFieldsVisitor : public RecursiveEdgeVisitor {
invalid_fields_.push_back(std::make_pair(current_, kMemberInUnmanaged));
}
- void VisitValue(Value* edge) override {
+ void AtValue(Value* edge) override {
// TODO: what should we do to check unions?
if (edge->value()->record()->isUnion())
return;
@@ -540,6 +540,11 @@ class CheckFieldsVisitor : public RecursiveEdgeVisitor {
}
}
+ void AtCollection(Collection* edge) override {
+ if (edge->on_heap() && Parent() && Parent()->IsOwnPtr())
+ invalid_fields_.push_back(std::make_pair(current_, kOwnPtrToGCManaged));
+ }
+
private:
Error InvalidSmartPtr(Edge* ptr) {
if (ptr->IsRawPtr())
diff --git a/tools/clang/blink_gc_plugin/tests/own_ptr_to_gc_managed_class.h b/tools/clang/blink_gc_plugin/tests/own_ptr_to_gc_managed_class.h
index 52062a1d2d..db6955f7b5 100644
--- a/tools/clang/blink_gc_plugin/tests/own_ptr_to_gc_managed_class.h
+++ b/tools/clang/blink_gc_plugin/tests/own_ptr_to_gc_managed_class.h
@@ -22,6 +22,7 @@ public:
void trace(Visitor*);
private:
Vector<OwnPtr<HeapObject> > m_objs;
+ OwnPtr<HeapVector<Member<HeapObject> > > m_objs2;
};
}
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
index b1dac2c6f1..4102e86b32 100644
--- 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
@@ -11,4 +11,7 @@ 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/cr/cr/targets/chrome_shell.py b/tools/cr/cr/targets/chrome_shell.py
index 65ff6270c8..016d5b681f 100644
--- a/tools/cr/cr/targets/chrome_shell.py
+++ b/tools/cr/cr/targets/chrome_shell.py
@@ -20,6 +20,6 @@ class ChromeShellTarget(cr.NamedTarget):
class ChromeShellTestTarget(cr.NamedTarget):
NAME = 'chrome_shell_test'
CONFIG = cr.Config.From(
- CR_TARGET_NAME='ChromiumTestShellTest',
+ CR_TARGET_NAME='ChromeShellTest',
)
diff --git a/tools/cygprofile/PRESUBMIT.py b/tools/cygprofile/PRESUBMIT.py
new file mode 100644
index 0000000000..dd28746631
--- /dev/null
+++ b/tools/cygprofile/PRESUBMIT.py
@@ -0,0 +1,34 @@
+# 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.
+
+"""Top-level presubmit script for cygprofile.
+
+See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts for
+details on the presubmit API built into gcl.
+"""
+
+
+def CommonChecks(input_api, output_api):
+ output = []
+ blacklist = []
+ output.extend(input_api.canned_checks.RunPylint(
+ input_api, output_api, black_list=blacklist))
+ output.extend(input_api.canned_checks.RunUnitTests(
+ input_api,
+ output_api,
+ [input_api.os_path.join(input_api.PresubmitLocalPath(), 'run_tests')]))
+
+ if input_api.is_committing:
+ output.extend(input_api.canned_checks.PanProjectChecks(input_api,
+ output_api,
+ owners_check=False))
+ return output
+
+
+def CheckChangeOnUpload(input_api, output_api):
+ return CommonChecks(input_api, output_api)
+
+
+def CheckChangeOnCommit(input_api, output_api):
+ return CommonChecks(input_api, output_api)
diff --git a/tools/cygprofile/cygprofile.cc b/tools/cygprofile/cygprofile.cc
index 980fa9e070..5d0e370554 100644
--- a/tools/cygprofile/cygprofile.cc
+++ b/tools/cygprofile/cygprofile.cc
@@ -1,401 +1,373 @@
// 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.
-//
-// Tool to log the execution of the process (Chrome). Writes logs containing
-// time and address of the callback being called for the first time.
-//
-// To speed up the logging, buffering logs is implemented. Every thread have its
-// own buffer and log file so the contention between threads is minimal. As a
-// side-effect, functions called might be mentioned in many thread logs.
-//
-// Special thread is created in the process to periodically flushes logs for all
-// threads for the case the thread has stopped before flushing its logs.
-//
-// Use this profiler with use_allocator!="none".
-//
-// Note for the ChromeOS Chrome. Remove renderer process from the sandbox (add
-// --no-sandbox option to running Chrome in /sbin/session_manager_setup.sh).
-// Otherwise renderer will not be able to write logs (and will assert on that).
-//
-// Also note that the instrumentation code is self-activated. It begins to
-// record the log data when it is called first, including the run-time startup.
-// Have it in mind when modifying it, in particular do not use global objects
-// with constructors as they are called during startup (too late for us).
+
+#include "tools/cygprofile/cygprofile.h"
#include <fcntl.h>
-#include <fstream>
#include <pthread.h>
-#include <stdarg.h>
-#include <string>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <sys/types.h>
+
+#include <cstdio>
+#include <fstream>
+#include <string>
#include <vector>
+#include "base/bind.h"
#include "base/containers/hash_tables.h"
+#include "base/files/scoped_file.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
-#include "base/memory/singleton.h"
+#include "base/macros.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/stringprintf.h"
#include "base/synchronization/lock.h"
namespace cygprofile {
+namespace {
-extern "C" {
+// Allow 8 MBytes of data for each thread log.
+const int kMaxBufferSize = 8 * 1024 * 1024 / sizeof(LogEntry);
-// Note that these are linked internally by the compiler. Don't call
-// them directly!
-void __cyg_profile_func_enter(void* this_fn, void* call_site)
- __attribute__((no_instrument_function));
-void __cyg_profile_func_exit(void* this_fn, void* call_site)
- __attribute__((no_instrument_function));
+// Have the background internal thread do its flush every 15 sec.
+const int kFlushThreadIdleTimeSec = 15;
-}
+const char kLogFileNamePrefix[] = "/data/local/tmp/chrome/cyglog/";
-// Single log entry layout.
-struct CygLogEntry {
- time_t seconds;
- long int usec;
- pid_t pid;
- pthread_t tid;
- const void* this_fn;
- CygLogEntry(time_t seconds, long int usec,
- pid_t pid, pthread_t tid, const void* this_fn)
- : seconds(seconds), usec(usec),
- pid(pid), tid(tid), this_fn(this_fn) {}
-};
+// "cyglog.PID.LWP.PPID"
+const char kLogFilenameFormat[] = "%scyglog.%d.%d-%d";
-// Common data for the process. Singleton.
-class CygCommon {
- public:
- static CygCommon* GetInstance();
- std::string header() const { return header_line_; }
- private:
- CygCommon();
- std::string header_line_;
- friend struct DefaultSingletonTraits<CygCommon>;
+// Magic value of above to prevent instrumentation. Used when ThreadLog is being
+// constructed (to prevent reentering by malloc, for example) and by the flush
+// log thread (to prevent it from being logged0.
+ThreadLog* const kMagicBeingConstructed = reinterpret_cast<ThreadLog*>(1);
- DISALLOW_COPY_AND_ASSIGN(CygCommon);
-};
+// Per-thread pointer to the current log object.
+static __thread ThreadLog* g_tls_log = NULL;
-// Returns light-weight process ID. On linux, this is a system-wide
-// unique thread id.
-static pid_t GetLwp() {
+// Returns light-weight process ID. On Linux, this is a system-wide unique
+// thread id.
+pid_t GetTID() {
return syscall(__NR_gettid);
}
-// A per-thread structure representing the log itself.
-class CygTlsLog {
- public:
- CygTlsLog()
- : in_use_(false), lwp_(GetLwp()), pthread_self_(pthread_self()) { }
+timespec GetCurrentTime() {
+ timespec timestamp;
+ clock_gettime(CLOCK_MONOTONIC, &timestamp);
+ return timestamp;
+}
- // Enter a log entity.
- void LogEnter(void* this_fn);
+// Sleeps for |sec| seconds.
+void SleepSec(int sec) {
+ for (int secs_to_sleep = sec; secs_to_sleep != 0;)
+ secs_to_sleep = sleep(secs_to_sleep);
+}
- // Add newly created CygTlsLog object to the list of all such objects.
- // Needed for the timer callback: it will enumerate each object and flush.
- static void AddNewLog(CygTlsLog* newlog);
+// Exposes the string header that will appear at the top of every trace file.
+// This string contains memory mapping information for the mapped
+// library/executable which is used offline during symbolization. Note that
+// this class is meant to be instantiated once per process and lazily (during
+// the first flush).
+struct ImmutableFileHeaderLine {
+ ImmutableFileHeaderLine() : value(MakeFileHeaderLine()) {}
- // Starts a thread in this process that periodically flushes all the threads.
- // Must be called once per process.
- static void StartFlushLogThread();
+ const std::string value;
private:
- static const int kBufMaxSize;
- static const char kLogFilenameFmt[];
- static const char kLogFileNamePrefix[];
-
- // Flush the log to file. Create file if needed.
- // Must be called with locked log_mutex_.
- void FlushLog();
+ // Returns whether the integer representation of the hexadecimal address
+ // stored in |line| at position |start_offset| was successfully stored in
+ // |result|.
+ static bool ParseAddress(const std::string& line,
+ off_t start_offset,
+ size_t length,
+ uint64* result) {
+ if (start_offset >= line.length())
+ return false;
+
+ uint64 address;
+ const bool ret = HexStringToUInt64(
+ base::StringPiece(line.c_str() + start_offset, length), &address);
+ if (!ret)
+ return false;
+
+ *result = address;
+ return true;
+ }
- // Fork hooks. Needed to keep data in consistent state during fork().
- static void AtForkPrepare();
- static void AtForkParent();
- static void AtForkChild();
+ // Parses /proc/self/maps and returns a two line string such as:
+ // 758c6000-79f4b000 r-xp 00000000 b3:17 309475 libchrome.2009.0.so
+ // secs usecs pid:threadid func
+ static std::string MakeFileHeaderLine() {
+ std::ifstream mapsfile("/proc/self/maps");
+ CHECK(mapsfile.good());
+ std::string result;
+
+ for (std::string line; std::getline(mapsfile, line); ) {
+ if (line.find("r-xp") == std::string::npos)
+ continue;
+
+ const size_t address_length = line.find('-');
+ uint64 start_address = 0;
+ CHECK(ParseAddress(line, 0, address_length, &start_address));
+
+ uint64 end_address = 0;
+ CHECK(ParseAddress(line, address_length + 1, address_length,
+ &end_address));
+
+ const uintptr_t current_func_addr = reinterpret_cast<uintptr_t>(
+ &MakeFileHeaderLine);
+ if (current_func_addr >= start_address &&
+ current_func_addr < end_address) {
+ result.swap(line);
+ break;
+ }
+ }
+ CHECK(!result.empty());
+ result.append("\nsecs\tusecs\tpid:threadid\tfunc\n");
+ return result;
+ }
+};
- // Thread callback to flush all logs periodically.
- static void* FlushLogThread(void*);
+base::LazyInstance<ThreadLogsManager>::Leaky g_logs_manager =
+ LAZY_INSTANCE_INITIALIZER;
- std::string log_filename_;
- std::vector<CygLogEntry> buf_;
+base::LazyInstance<ImmutableFileHeaderLine>::Leaky g_file_header_line =
+ LAZY_INSTANCE_INITIALIZER;
- // A lock that guards buf_ usage between per-thread instrumentation
- // routine and timer flush callback. So the contention could happen
- // only during the flush, every 30 secs.
- base::Lock log_mutex_;
+} // namespace
- // Current thread is inside the instrumentation routine.
- bool in_use_;
+// Custom thread implementation that joins on destruction. Note that
+// base::Thread has non-trivial dependencies on e.g. AtExitManager which makes
+// it hard to use it early.
+class Thread {
+ public:
+ Thread(const base::Closure& thread_callback)
+ : thread_callback_(thread_callback) {
+ CHECK_EQ(0, pthread_create(&handle_, NULL, &Thread::EntryPoint, this));
+ }
- // Keeps track of all functions that have been logged on this thread
- // so we do not record dublicates.
- std::hash_set<void*> functions_called_;
+ ~Thread() {
+ CHECK_EQ(0, pthread_join(handle_, NULL));
+ }
- // Thread identifier as Linux kernel shows it. For debugging purposes.
- // LWP (light-weight process) is a unique ID of the thread in the system,
- // unlike pthread_self() which is the same for fork()-ed threads.
- pid_t lwp_;
- pthread_t pthread_self_;
+ private:
+ static void* EntryPoint(void* data) {
+ // Disable logging on this thread. Although this routine is not instrumented
+ // (cygprofile.gyp provides that), the called routines are and thus will
+ // call instrumentation.
+ CHECK(g_tls_log == NULL); // Must be 0 as this is a new thread.
+ g_tls_log = kMagicBeingConstructed;
+
+ Thread* const instance = reinterpret_cast<Thread*>(data);
+ instance->thread_callback_.Run();
+ return NULL;
+ }
- DISALLOW_COPY_AND_ASSIGN(CygTlsLog);
-};
+ const base::Closure thread_callback_;
+ pthread_t handle_;
-// Storage for logs for all threads in the process.
-// Using std::list may be better, but it fails when used before main().
-struct AllLogs {
- std::vector<CygTlsLog*> logs;
- base::Lock mutex;
+ DISALLOW_COPY_AND_ASSIGN(Thread);
};
-base::LazyInstance<AllLogs>::Leaky all_logs_ = LAZY_INSTANCE_INITIALIZER;
-
-// Per-thread pointer to the current log object.
-static __thread CygTlsLog* tls_current_log = NULL;
-
-// Magic value of above to prevent the instrumentation. Used when CygTlsLog is
-// being constructed (to prevent reentering by malloc, for example) and by
-// the FlushLogThread (to prevent it being logged - see comment in its code).
-CygTlsLog* const kMagicBeingConstructed = reinterpret_cast<CygTlsLog*>(1);
-
-// Number of entries in the per-thread log buffer before we flush.
-// Note, that we also flush by timer so not all thread logs may grow up to this.
-const int CygTlsLog::kBufMaxSize = 3000;
-
-#if defined(OS_ANDROID)
-const char CygTlsLog::kLogFileNamePrefix[] =
- "/data/local/tmp/chrome/cyglog/";
-#else
-const char CygTlsLog::kLogFileNamePrefix[] = "/var/log/chrome/";
-#endif
+// Single log entry recorded for each function call.
+LogEntry::LogEntry(const void* address)
+ : time(GetCurrentTime()),
+ pid(getpid()),
+ tid(GetTID()),
+ address(address) {
+}
-// "cyglog.PID.LWP.pthread_self.PPID"
-const char CygTlsLog::kLogFilenameFmt[] = "%scyglog.%d.%d.%ld-%d";
+ThreadLog::ThreadLog()
+ : tid_(GetTID()),
+ in_use_(false),
+ flush_callback_(
+ base::Bind(&ThreadLog::FlushInternal, base::Unretained(this))) {
+}
-CygCommon* CygCommon::GetInstance() {
- return Singleton<CygCommon>::get();
+ThreadLog::ThreadLog(const FlushCallback& flush_callback)
+ : tid_(GetTID()),
+ in_use_(false),
+ flush_callback_(flush_callback) {
}
-CygCommon::CygCommon() {
- // Determine our module addresses.
- std::ifstream mapsfile("/proc/self/maps");
- CHECK(mapsfile.good());
- static const int kMaxLineSize = 512;
- char line[kMaxLineSize];
- void (*this_fn)(void) =
- reinterpret_cast<void(*)()>(__cyg_profile_func_enter);
- while (mapsfile.getline(line, kMaxLineSize)) {
- const std::string str_line = line;
- size_t permindex = str_line.find("r-xp");
- if (permindex != std::string::npos) {
- int dashindex = str_line.find("-");
- int spaceindex = str_line.find(" ");
- char* p;
- void* start = reinterpret_cast<void*>
- (strtol((str_line.substr(0, dashindex)).c_str(),
- &p, 16));
- CHECK(*p == 0); // Could not determine start address.
- void* end = reinterpret_cast<void*>
- (strtol((str_line.substr(dashindex + 1,
- spaceindex - dashindex - 1)).c_str(),
- &p, 16));
- CHECK(*p == 0); // Could not determine end address.
-
- if (this_fn >= start && this_fn < end)
- header_line_ = str_line;
- }
- }
- mapsfile.close();
- header_line_.append("\nsecs\tusecs\tpid:threadid\tfunc\n");
+ThreadLog::~ThreadLog() {
+ g_tls_log = NULL;
}
-void CygTlsLog::LogEnter(void* this_fn) {
+void ThreadLog::AddEntry(void* address) {
if (in_use_)
return;
in_use_ = true;
- if (functions_called_.find(this_fn) ==
- functions_called_.end()) {
- functions_called_.insert(this_fn);
- base::AutoLock lock(log_mutex_);
- if (buf_.capacity() < kBufMaxSize)
- buf_.reserve(kBufMaxSize);
- struct timespec timestamp;
- clock_gettime(CLOCK_MONOTONIC, &timestamp);
- buf_.push_back(CygLogEntry(timestamp.tv_sec, timestamp.tv_nsec / 1000,
- getpid(), pthread_self(), this_fn));
- if (buf_.size() == kBufMaxSize) {
- FlushLog();
- }
+ CHECK_EQ(tid_, GetTID());
+ const std::pair<std::hash_set<void*>::iterator, bool> pair =
+ called_functions_.insert(address);
+ const bool did_insert = pair.second;
+
+ if (did_insert) {
+ base::AutoLock auto_lock(lock_);
+ entries_.push_back(LogEntry(address));
+ // Crash in a quickly understandable way instead of crashing (or maybe not
+ // though) due to OOM.
+ CHECK_LE(entries_.size(), kMaxBufferSize);
}
in_use_ = false;
}
-void CygTlsLog::AtForkPrepare() {
- CHECK(tls_current_log);
- CHECK(tls_current_log->lwp_ == GetLwp());
- CHECK(tls_current_log->pthread_self_ == pthread_self());
- all_logs_.Get().mutex.Acquire();
+void ThreadLog::TakeEntries(std::vector<LogEntry>* destination) {
+ base::AutoLock auto_lock(lock_);
+ destination->swap(entries_);
+ STLClearObject(&entries_);
}
-void CygTlsLog::AtForkParent() {
- CHECK(tls_current_log);
- CHECK(tls_current_log->lwp_ == GetLwp());
- CHECK(tls_current_log->pthread_self_ == pthread_self());
- all_logs_.Get().mutex.Release();
+void ThreadLog::Flush(std::vector<LogEntry>* entries) const {
+ flush_callback_.Run(entries);
}
-void CygTlsLog::AtForkChild() {
- CHECK(tls_current_log);
+void ThreadLog::FlushInternal(std::vector<LogEntry>* entries) const {
+ const std::string log_filename(
+ base::StringPrintf(
+ kLogFilenameFormat, kLogFileNamePrefix, getpid(), tid_, getppid()));
+ const base::ScopedFILE file(fopen(log_filename.c_str(), "a"));
+ CHECK(file.get());
+
+ const long offset = ftell(file.get());
+ if (offset == 0)
+ fprintf(file.get(), "%s", g_file_header_line.Get().value.c_str());
+
+ for (std::vector<LogEntry>::const_iterator it = entries->begin();
+ it != entries->end(); ++it) {
+ fprintf(file.get(), "%ld %ld\t%d:%ld\t%p\n", it->time.tv_sec,
+ it->time.tv_nsec / 1000, it->pid, it->tid, it->address);
+ }
- // Update the IDs of this new thread of the new process.
- // Note that the process may (and Chrome main process forks zygote this way)
- // call exec(self) after we return (to launch new shiny self). If done like
- // that, PID and LWP will remain the same, but pthread_self() changes.
- pid_t lwp = GetLwp();
- CHECK(tls_current_log->lwp_ != lwp); // LWP is system-wide unique thread ID.
- tls_current_log->lwp_ = lwp;
+ STLClearObject(entries);
+}
- CHECK(tls_current_log->pthread_self_ == pthread_self());
+ThreadLogsManager::ThreadLogsManager()
+ : wait_callback_(base::Bind(&SleepSec, kFlushThreadIdleTimeSec)) {
+}
- // Leave the only current thread tls object because fork() clones only the
- // current thread (the one that called fork) to the child process.
- AllLogs& all_logs = all_logs_.Get();
- all_logs.logs.clear();
- all_logs.logs.push_back(tls_current_log);
- CHECK(all_logs.logs.size() == 1);
+ThreadLogsManager::ThreadLogsManager(const base::Closure& wait_callback,
+ const base::Closure& notify_callback)
- // Clear log filename so it will be re-calculated with the new PIDs.
- tls_current_log->log_filename_.clear();
+ : wait_callback_(wait_callback),
+ notify_callback_(notify_callback) {
+}
- // Create the thread that will periodically flush all logs for this process.
- StartFlushLogThread();
+ThreadLogsManager::~ThreadLogsManager() {
+ // Note that the internal thread does some work until it sees |flush_thread_|
+ // = NULL.
+ scoped_ptr<Thread> flush_thread;
+ {
+ base::AutoLock auto_lock(lock_);
+ flush_thread_.swap(flush_thread);
+ }
+ flush_thread.reset(); // Joins the flush thread.
- // We do not update log header line (CygCommon data) as it will be the same
- // because the new process is just a forked copy.
- all_logs.mutex.Release();
+ STLDeleteContainerPointers(logs_.begin(), logs_.end());
}
-void CygTlsLog::StartFlushLogThread() {
- pthread_t tid;
- CHECK(!pthread_create(&tid, NULL, &CygTlsLog::FlushLogThread, NULL));
+void ThreadLogsManager::AddLog(scoped_ptr<ThreadLog> new_log) {
+ base::AutoLock auto_lock(lock_);
+
+ if (logs_.empty())
+ StartInternalFlushThread_Locked();
+
+ logs_.push_back(new_log.release());
}
-void CygTlsLog::AddNewLog(CygTlsLog* newlog) {
- CHECK(tls_current_log == kMagicBeingConstructed);
- AllLogs& all_logs = all_logs_.Get();
- base::AutoLock lock(all_logs.mutex);
- if (all_logs.logs.empty()) {
-
- // An Android app never fork, it always starts with a pre-defined number of
- // process descibed by the android manifest file. In fact, there is not
- // support for pthread_atfork at the android system libraries. All chrome
- // for android processes will start as independent processs and each one
- // will generate its own logs that will later have to be merged as usual.
-#if !defined(OS_ANDROID)
- CHECK(!pthread_atfork(CygTlsLog::AtForkPrepare,
- CygTlsLog::AtForkParent,
- CygTlsLog::AtForkChild));
-#endif
-
- // The very first process starts its flush thread here. Forked processes
- // will do it in AtForkChild().
- StartFlushLogThread();
- }
- all_logs.logs.push_back(newlog);
+void ThreadLogsManager::StartInternalFlushThread_Locked() {
+ lock_.AssertAcquired();
+ CHECK(!flush_thread_);
+ // Note that the |flush_thread_| joins at destruction which guarantees that it
+ // will never outlive |this|, i.e. it's safe not to use ref-counting.
+ flush_thread_.reset(
+ new Thread(base::Bind(&ThreadLogsManager::FlushAllLogsOnFlushThread,
+ base::Unretained(this))));
}
-// Printf-style routine to write to open file.
-static void WriteLogLine(int fd, const char* fmt, ...) {
- va_list arg_ptr;
- va_start(arg_ptr, fmt);
- char msg[160];
- int len = vsnprintf(msg, sizeof(msg), fmt, arg_ptr);
- int rc = write(fd, msg, (len > sizeof(msg))? sizeof(msg): len);
- va_end(arg_ptr);
+// Type used below for flushing.
+struct LogData {
+ LogData(ThreadLog* thread_log) : thread_log(thread_log) {}
+
+ ThreadLog* const thread_log;
+ std::vector<LogEntry> entries;
};
-void CygTlsLog::FlushLog() {
- bool first_log_write = false;
- if (log_filename_.empty()) {
- first_log_write = true;
- char buf[80];
- snprintf(buf, sizeof(buf), kLogFilenameFmt,
- kLogFileNamePrefix, getpid(), lwp_, pthread_self_, getppid());
- log_filename_ = buf;
- unlink(log_filename_.c_str());
- }
+void ThreadLogsManager::FlushAllLogsOnFlushThread() {
+ while (true) {
+ {
+ base::AutoLock auto_lock(lock_);
+ // The |flush_thread_| field is reset during destruction.
+ if (!flush_thread_)
+ return;
+ }
+ // Sleep for a few secs and then flush all thread's buffers. There is a
+ // danger that, when quitting Chrome, this thread may see unallocated data
+ // and segfault. We do not care because we need logs when Chrome is working.
+ wait_callback_.Run();
+
+ // Copy the ThreadLog pointers to avoid acquiring both the logs manager's
+ // lock and the one for individual thread logs.
+ std::vector<ThreadLog*> thread_logs_copy;
+ {
+ base::AutoLock auto_lock(lock_);
+ thread_logs_copy = logs_;
+ }
- int file = open(log_filename_.c_str(), O_CREAT | O_WRONLY | O_APPEND, 00600);
- CHECK(file != -1);
+ // Move the logs' data before flushing them so that the mutexes are not
+ // acquired for too long.
+ std::vector<LogData> logs;
+ for (std::vector<ThreadLog*>::const_iterator it =
+ thread_logs_copy.begin();
+ it != thread_logs_copy.end(); ++it) {
+ ThreadLog* const thread_log = *it;
+ LogData log_data(thread_log);
+ logs.push_back(log_data);
+ thread_log->TakeEntries(&logs.back().entries);
+ }
- if (first_log_write)
- WriteLogLine(file, "%s", CygCommon::GetInstance()->header().c_str());
+ for (std::vector<LogData>::iterator it = logs.begin();
+ it != logs.end(); ++it) {
+ if (!it->entries.empty())
+ it->thread_log->Flush(&it->entries);
+ }
- for (int i = 0; i != buf_.size(); ++i) {
- const CygLogEntry& p = buf_[i];
- WriteLogLine(file, "%ld %ld\t%d:%ld\t%p\n",
- p.seconds, p.usec, p.pid, p.tid, p.this_fn);
+ if (!notify_callback_.is_null())
+ notify_callback_.Run();
}
-
- close(file);
- buf_.clear();
}
-void* CygTlsLog::FlushLogThread(void*) {
- // Disable logging this thread. Although this routine is not instrumented
- // (cygprofile.gyp provides that), the called routines are and thus will
- // call instrumentation.
- CHECK(tls_current_log == NULL); // Must be 0 as this is a new thread.
- tls_current_log = kMagicBeingConstructed;
-
- // Run this loop infinitely: sleep 30 secs and the flush all thread's
- // buffers. There is a danger that, when quitting Chrome, this thread may
- // see unallocated data and segfault. We do not care because we need logs
- // when Chrome is working.
- while (true) {
- for(int secs_to_sleep = 30; secs_to_sleep != 0;)
- secs_to_sleep = sleep(secs_to_sleep);
-
- AllLogs& all_logs = all_logs_.Get();
- base::AutoLock lock(all_logs.mutex);
- for (int i = 0; i != all_logs.logs.size(); ++i) {
- CygTlsLog* current_log = all_logs.logs[i];
- base::AutoLock current_lock(current_log->log_mutex_);
- if (current_log->buf_.size()) {
- current_log->FlushLog();
- } else {
- // The thread's log is still empty. Probably the thread finished prior
- // to previous timer fired - deallocate its buffer. Even if the thread
- // ever resumes, it will allocate its buffer again in
- // std::vector::push_back().
- current_log->buf_.clear();
- }
- }
- }
-}
+extern "C" {
-// Gcc Compiler callback, called on every function invocation providing
+// The GCC compiler callbacks, called on every function invocation providing
// addresses of caller and callee codes.
+void __cyg_profile_func_enter(void* this_fn, void* call_site)
+ __attribute__((no_instrument_function));
+void __cyg_profile_func_exit(void* this_fn, void* call_site)
+ __attribute__((no_instrument_function));
+
void __cyg_profile_func_enter(void* this_fn, void* callee_unused) {
- if (tls_current_log == NULL) {
- tls_current_log = kMagicBeingConstructed;
- CygTlsLog* newlog = new CygTlsLog;
- CHECK(newlog);
- CygTlsLog::AddNewLog(newlog);
- tls_current_log = newlog;
+ if (g_tls_log == NULL) {
+ g_tls_log = kMagicBeingConstructed;
+ ThreadLog* new_log = new ThreadLog();
+ CHECK(new_log);
+ g_logs_manager.Pointer()->AddLog(make_scoped_ptr(new_log));
+ g_tls_log = new_log;
}
- if (tls_current_log != kMagicBeingConstructed) {
- tls_current_log->LogEnter(this_fn);
- }
-}
-// Gcc Compiler callback, called after every function invocation providing
-// addresses of caller and callee codes.
-void __cyg_profile_func_exit(void* this_fn, void* call_site) {
+ if (g_tls_log != kMagicBeingConstructed)
+ g_tls_log->AddEntry(this_fn);
}
+void __cyg_profile_func_exit(void* this_fn, void* call_site) {}
+
+} // extern "C"
} // namespace cygprofile
diff --git a/tools/cygprofile/cygprofile.gyp b/tools/cygprofile/cygprofile.gyp
index 1e7c751ae4..910ef54c3c 100644
--- a/tools/cygprofile/cygprofile.gyp
+++ b/tools/cygprofile/cygprofile.gyp
@@ -3,8 +3,6 @@
# found in the LICENSE file.
{
- 'variables': {
- },
'targets': [
{
'target_name': 'cygprofile',
@@ -12,8 +10,29 @@
'include_dirs': [ '../..', ],
'sources': [
'cygprofile.cc',
+ 'cygprofile.h',
],
'cflags!': [ '-finstrument-functions' ],
+ 'dependencies': [
+ # 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/base.gyp:base',
+ ],
+ },
+ {
+ 'target_name': 'cygprofile_unittests',
+ 'type': 'executable',
+ 'include_dirs': [ '../..', ],
+ 'sources': [
+ 'cygprofile_unittest.cc',
+ ],
+ 'cflags!': [ '-finstrument-functions' ],
+ 'dependencies': [
+ 'cygprofile',
+ '../../base/base.gyp:base',
+ '../../testing/gtest.gyp:gtest',
+ ],
},
],
}
diff --git a/tools/cygprofile/cygprofile.h b/tools/cygprofile/cygprofile.h
new file mode 100644
index 0000000000..eeb3ffbcdf
--- /dev/null
+++ b/tools/cygprofile/cygprofile.h
@@ -0,0 +1,166 @@
+// 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.
+//
+// Tool to log the execution of the process (Chrome). Writes logs containing
+// time and address of the callback being called for the first time.
+//
+// For performance reasons logs are buffered. Every thread has its own buffer
+// and log file so the contention between threads is minimal. As a side-effect,
+// functions called might be mentioned in many thread logs.
+//
+// A special thread is created in the process to periodically flush logs for all
+// threads in case the thread had stopped before flushing its logs.
+//
+// Also note that the instrumentation code is self-activated. It begins to
+// record the log data when it is called first, including the run-time startup.
+// Have it in mind when modifying it, in particular do not use global objects
+// with constructors as they are called during startup (too late for us).
+
+#ifndef TOOLS_CYGPROFILE_CYGPROFILE_H_
+#define TOOLS_CYGPROFILE_CYGPROFILE_H_
+
+#include <vector>
+
+#include <sys/time.h>
+#include <sys/types.h>
+
+#include "base/callback.h"
+#include "base/containers/hash_tables.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/synchronization/lock.h"
+#include "build/build_config.h"
+
+#if !defined(OS_ANDROID)
+// This is only supported on Android thanks to the fact that on Android
+// processes (other than the system's zygote) don't fork.
+//
+// To make cygprofile truly work (i.e. without any deadlock) on Chrome
+// platforms that use fork(), cygprofile.cc should be written in a way that
+// guarantees that:
+// - No lock is acquired by a foreign thread during fork(). In particular this
+// means that cygprofile.cc should not perform any heap allocation (since heap
+// allocators, including TCMalloc generally use locks).
+// - Only cygprofile.cc uses pthread_atfork() in the whole process. Unlike POSIX
+// signals, pthread_atfork() doesn't provide a way to install multiple handlers.
+// Calling pthread_atfork() in cygprofile.cc would override any handler that
+// could have been installed previously.
+//
+// Chrome happens to violate the first requirement at least once by having its
+// process launcher thread fork. However the child process in that case, when
+// it's not instrumented with cygprofile, directly calls exec(). This is safe
+// since the child process doesn't try to release a lock acquired by another
+// thread in the parent process which would lead to a deadlock. This problem was
+// actually observed by trying to port the current version of cygprofile.cc to
+// Linux.
+#error This is only supported on Android.
+#endif
+
+// The following is only exposed for testing.
+namespace cygprofile {
+
+class Thread;
+
+// Single log entry recorded for each function call.
+struct LogEntry {
+ LogEntry(const void* address);
+
+ const timespec time;
+ const pid_t pid;
+ const pid_t tid;
+ const void* const address;
+};
+
+// Per-thread function calls log.
+class ThreadLog {
+ public:
+ // Callback invoked for flushing that can be provided for testing.
+ typedef base::Callback<void (std::vector<LogEntry>*)> FlushCallback;
+
+ ThreadLog();
+
+ // Used for testing.
+ ThreadLog(const FlushCallback& flush_callback);
+
+ ~ThreadLog();
+
+ // Must only be called from the thread this ThreadLog instance is watching.
+ void AddEntry(void* address);
+
+ // Can be called from any thread.
+ void TakeEntries(std::vector<LogEntry>* output);
+
+ // Flushes the provided vector of entries to a file and clears it. Note that
+ // this can be called from any thread.
+ void Flush(std::vector<LogEntry>* entries) const;
+
+ private:
+ // Default implementation (that can be overridden for testing) of the method
+ // above.
+ void FlushInternal(std::vector<LogEntry>* entries) const;
+
+ // Thread identifier as Linux kernel shows it. LWP (light-weight process) is
+ // a unique ID of the thread in the system, unlike pthread_self() which is the
+ // same for fork()-ed threads.
+ const pid_t tid_;
+
+ // Current thread is inside the instrumentation routine.
+ bool in_use_;
+
+ // Callback used to flush entries.
+ const FlushCallback flush_callback_;
+
+ // Keeps track of all functions that have been logged on this thread so we do
+ // not record duplicates.
+ std::hash_set<void*> called_functions_;
+
+ // A lock that guards |entries_| usage between per-thread instrumentation
+ // routine and timer flush callback. So the contention could happen only
+ // during the flush, every 15 secs.
+ base::Lock lock_;
+
+ std::vector<LogEntry> entries_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThreadLog);
+};
+
+// Manages a list of per-thread logs.
+class ThreadLogsManager {
+ public:
+ ThreadLogsManager();
+
+ // Used for testing. The provided callbacks are used for testing to
+ // synchronize the internal thread with the unit test running on the main
+ // thread.
+ ThreadLogsManager(const base::Closure& wait_callback,
+ const base::Closure& notify_callback);
+
+ ~ThreadLogsManager();
+
+ // Can be called from any thread.
+ void AddLog(scoped_ptr<ThreadLog> new_log);
+
+ private:
+ void StartInternalFlushThread_Locked();
+
+ // Flush thread's entry point.
+ void FlushAllLogsOnFlushThread();
+
+ // Used to make the internal thread sleep before each flush iteration.
+ const base::Closure wait_callback_;
+ // Used to trigger a notification when a flush happened on the internal
+ // thread.
+ const base::Closure notify_callback_;
+
+ // Protects the state below.
+ base::Lock lock_;
+ scoped_ptr<Thread> flush_thread_;
+ std::vector<ThreadLog*> logs_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThreadLogsManager);
+};
+
+} // namespace cygprofile
+
+#endif // TOOLS_CYGPROFILE_CYGPROFILE_H_
diff --git a/tools/cygprofile/cygprofile_unittest.cc b/tools/cygprofile/cygprofile_unittest.cc
new file mode 100644
index 0000000000..7a1a3e2909
--- /dev/null
+++ b/tools/cygprofile/cygprofile_unittest.cc
@@ -0,0 +1,101 @@
+// 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.
+
+#include "tools/cygprofile/cygprofile.h"
+
+#include <vector>
+
+#include <sys/time.h>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/synchronization/waitable_event.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cygprofile {
+namespace {
+
+void FlushEntries(std::vector<LogEntry>* destination,
+ std::vector<LogEntry>* entries) {
+ CHECK_EQ(0U, destination->size());
+ // Move the provided |entries| vector to the provided |destination| so that
+ // the unit test that triggered the flush can check it.
+ destination->swap(*entries);
+}
+
+// Flush callback that should not be invoked.
+void CheckFlushDoesNotHappen(std::vector<LogEntry>* entries) {
+ NOTREACHED();
+}
+
+uint64_t GetUsecSecTimeFromTimeSpec(struct timespec timespec) {
+ return timespec.tv_sec * 1000 * 1000 + timespec.tv_nsec / 1000;
+}
+
+TEST(CygprofileTest, ThreadLogBasic) {
+ ThreadLog thread_log(base::Bind(&CheckFlushDoesNotHappen));
+
+ thread_log.AddEntry(reinterpret_cast<void*>(0x2));
+ thread_log.AddEntry(reinterpret_cast<void*>(0x1));
+
+ std::vector<LogEntry> entries;
+ thread_log.TakeEntries(&entries);
+
+ ASSERT_EQ(2U, entries.size());
+ // The entries should appear in their insertion order.
+ const LogEntry& first_entry = entries[0];
+ ASSERT_EQ(reinterpret_cast<int>(first_entry.address), 2);
+ ASSERT_EQ(getpid(), first_entry.pid);
+ ASSERT_LT(0, first_entry.tid);
+
+ const LogEntry& second_entry = entries[1];
+ ASSERT_EQ(1, reinterpret_cast<int>(second_entry.address));
+ ASSERT_EQ(first_entry.pid, second_entry.pid);
+ ASSERT_EQ(first_entry.tid, second_entry.tid);
+
+ ASSERT_GE(GetUsecSecTimeFromTimeSpec(second_entry.time),
+ GetUsecSecTimeFromTimeSpec(first_entry.time));
+}
+
+TEST(CygprofileTest, ManagerBasic) {
+ base::WaitableEvent wait_event(true, false);
+ base::WaitableEvent notify_event(true, false);
+
+ ThreadLogsManager manager(
+ base::Bind(&base::WaitableEvent::Wait, base::Unretained(&wait_event)),
+ base::Bind(&base::WaitableEvent::Signal,
+ base::Unretained(&notify_event)));
+
+ std::vector<LogEntry> entries;
+ scoped_ptr<ThreadLog> thread_log(
+ new ThreadLog(base::Bind(&FlushEntries, base::Unretained(&entries))));
+
+ thread_log->AddEntry(reinterpret_cast<void*>(0x2));
+ thread_log->AddEntry(reinterpret_cast<void*>(0x3));
+
+ // This should make the manager spawn its internal flush thread which will
+ // wait for a notification before it starts doing some work.
+ manager.AddLog(thread_log.Pass());
+
+ EXPECT_EQ(0U, entries.size());
+ // This will wake up the internal thread.
+ wait_event.Signal();
+ // Now it's our turn to wait until it performed the flush.
+ notify_event.Wait();
+
+ // The flush should have moved the data to the local vector of entries.
+ EXPECT_EQ(2U, entries.size());
+ ASSERT_EQ(2, reinterpret_cast<int>(entries[0].address));
+ ASSERT_EQ(3, reinterpret_cast<int>(entries[1].address));
+}
+
+} // namespace
+} // 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/mergetraces.py b/tools/cygprofile/mergetraces.py
index 1c7627a8df..93a00cacef 100755
--- a/tools/cygprofile/mergetraces.py
+++ b/tools/cygprofile/mergetraces.py
@@ -13,9 +13,7 @@ create a single log that is an ordered trace of calls by both processes.
"""
import optparse
-import os
import string
-import subprocess
import sys
def ParseLogLines(lines):
@@ -55,7 +53,7 @@ def ParseLogLines(lines):
return (call_lines, vm_start, vm_end)
def HasDuplicates(calls):
- """Funcition is a sanity check to make sure that calls are only logged once.
+ """Makes sure that calls are only logged once.
Args:
calls: list of calls logged
@@ -63,12 +61,12 @@ def HasDuplicates(calls):
Returns:
boolean indicating if calls has duplicate calls
"""
- seen = []
+ seen = set([])
for call in calls:
if call[3] in seen:
- return true
- else:
- seen.append(call[3])
+ return True
+ seen.add(call[3])
+ return False
def CheckTimestamps(calls):
"""Prints warning to stderr if the call timestamps are not in order.
@@ -137,6 +135,55 @@ def AddTrace (tracemap, trace):
Timestamp(tracemap[call]) > Timestamp(trace_entry)):
tracemap[call] = trace_entry
+def GroupByProcessAndThreadId(input_trace):
+ """Returns an array of traces grouped by pid and tid.
+
+ This is used to make the order of functions not depend on thread scheduling
+ which can be greatly impacted when profiling is done with cygprofile. As a
+ result each thread has its own contiguous segment of code (ordered by
+ timestamp) and processes also have their code isolated (i.e. not interleaved).
+ """
+ def MakeTimestamp(sec, usec):
+ return sec * 1000000 + usec
+
+ def PidAndTidFromString(pid_and_tid):
+ strings = pid_and_tid.split(':')
+ return (int(strings[0]), int(strings[1]))
+
+ tid_to_pid_map = {}
+ pid_first_seen = {}
+ tid_first_seen = {}
+
+ for (sec, usec, pid_and_tid, _) in input_trace:
+ (pid, tid) = PidAndTidFromString(pid_and_tid)
+
+ # Make sure that thread IDs are unique since this is a property we rely on.
+ if tid_to_pid_map.setdefault(tid, pid) != pid:
+ raise Exception(
+ 'Seen PIDs %d and %d for TID=%d. Thread-IDs must be unique' % (
+ tid_to_pid_map[tid], pid, tid))
+
+ if not pid in pid_first_seen:
+ pid_first_seen[pid] = MakeTimestamp(sec, usec)
+ if not tid in tid_first_seen:
+ tid_first_seen[tid] = MakeTimestamp(sec, usec)
+
+ def CompareEvents(event1, event2):
+ (sec1, usec1, pid_and_tid, _) = event1
+ (pid1, tid1) = PidAndTidFromString(pid_and_tid)
+ (sec2, usec2, pid_and_tid, _) = event2
+ (pid2, tid2) = PidAndTidFromString(pid_and_tid)
+
+ pid_cmp = cmp(pid_first_seen[pid1], pid_first_seen[pid2])
+ if pid_cmp != 0:
+ return pid_cmp
+ tid_cmp = cmp(tid_first_seen[tid1], tid_first_seen[tid2])
+ if tid_cmp != 0:
+ return tid_cmp
+ return cmp(MakeTimestamp(sec1, usec1), MakeTimestamp(sec2, usec2))
+
+ return sorted(input_trace, cmp=CompareEvents)
+
def main():
"""Merge two traces for code in specified library and write to stdout.
@@ -151,7 +198,10 @@ def main():
parser.error('expected at least the following args: trace1 trace2')
step = 0
+
+ # Maps function addresses to their corresponding trace entry.
tracemap = dict()
+
for trace_file in args:
step += 1
sys.stderr.write(" " + str(step) + "/" + str(len(args)) +
@@ -176,9 +226,11 @@ def main():
merged_trace.append(tracemap[call])
merged_trace.sort(key=Timestamp)
+ grouped_trace = GroupByProcessAndThreadId(merged_trace)
+
print "0-ffffffff r-xp 00000000 xx:00 00000 ./"
print "secs\tusecs\tpid:threadid\tfunc"
- for call in merged_trace:
+ for call in grouped_trace:
print (str(call[0]) + "\t" + str(call[1]) + "\t" + call[2] + "\t" +
hex(call[3]))
diff --git a/tools/cygprofile/mergetraces_unittest.py b/tools/cygprofile/mergetraces_unittest.py
new file mode 100644
index 0000000000..de881379d6
--- /dev/null
+++ b/tools/cygprofile/mergetraces_unittest.py
@@ -0,0 +1,51 @@
+# 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 unittest
+
+import mergetraces
+
+class GroupByProcessAndThreadIdTestBasic(unittest.TestCase):
+ def runTest(self):
+ # (sec, usec, 'pid:tid', function address).
+ input_trace = [
+ (100, 10, '2000:2001', 0x5),
+ (100, 11, '2000:2001', 0x3),
+ (100, 13, '2000:1999', 0x8),
+ (100, 14, '2000:2000', 0x7),
+ (120, 13, '2001:2003', 0x9),
+ (150, 12, '2001:2004', 0x6),
+ (180, 11, '2000:2000', 0x1),
+ ]
+
+ # Functions should be grouped by thread-id and PIDs should not be
+ # interleaved.
+ expected_trace = [
+ (100, 10, '2000:2001', 0x5),
+ (100, 11, '2000:2001', 0x3),
+ (100, 13, '2000:1999', 0x8),
+ (100, 14, '2000:2000', 0x7),
+ (180, 11, '2000:2000', 0x1),
+ (120, 13, '2001:2003', 0x9),
+ (150, 12, '2001:2004', 0x6),
+ ]
+
+ grouped_trace = mergetraces.GroupByProcessAndThreadId(input_trace)
+
+ self.assertEqual(grouped_trace, expected_trace)
+
+class GroupByProcessAndThreadIdFailsWithNonUniqueTIDs(unittest.TestCase):
+ def runTest(self):
+ # (sec, usec, 'pid:tid', function address).
+ input_trace = [
+ (100, 10, '1999:2001', 0x5),
+ (100, 10, '1988:2001', 0x5),
+ ]
+
+ try:
+ mergetraces.GroupByProcessAndThreadId(input_trace)
+ except Exception:
+ return
+
+ self.fail('Multiple processes should not have a same thread-ID.')
diff --git a/tools/cygprofile/run_tests b/tools/cygprofile/run_tests
new file mode 100755
index 0000000000..70eb64981a
--- /dev/null
+++ b/tools/cygprofile/run_tests
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+# 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 logging
+import os
+import sys
+import unittest
+
+
+if __name__ == '__main__':
+ logging.basicConfig(
+ level=logging.DEBUG if '-v' in sys.argv else logging.WARNING,
+ format='%(levelname)5s %(filename)15s(%(lineno)3d): %(message)s')
+
+ suite = unittest.TestSuite()
+ loader = unittest.TestLoader()
+ suite.addTests(loader.discover(start_dir=os.path.dirname(__file__),
+ pattern='*_unittest.py'))
+ res = unittest.TextTestRunner(verbosity=2).run(suite)
+ if res.wasSuccessful():
+ sys.exit(0)
+ else:
+ sys.exit(1)
diff --git a/tools/gen_keyboard_overlay_data/gen_keyboard_overlay_data.py b/tools/gen_keyboard_overlay_data/gen_keyboard_overlay_data.py
index 8531241f28..67b5bebd1e 100755
--- a/tools/gen_keyboard_overlay_data/gen_keyboard_overlay_data.py
+++ b/tools/gen_keyboard_overlay_data/gen_keyboard_overlay_data.py
@@ -84,25 +84,6 @@ LABEL_MAP = {
};
INPUT_METHOD_ID_TO_OVERLAY_ID = {
- 'm17n:ar:kbd': 'ar',
- 'm17n:fa:isiri': 'ar',
- 'm17n:hi:itrans': 'hi',
- 'm17n:th:kesmanee': 'th',
- 'm17n:th:pattachote': 'th',
- 'm17n:th:tis820': 'th',
- 'm17n:vi:tcvn': 'vi',
- 'm17n:vi:telex': 'vi',
- 'm17n:vi:viqr': 'vi',
- 'm17n:vi:vni': 'vi',
- 'm17n:zh:cangjie': 'zh_TW',
- 'm17n:zh:quick': 'zh_TW',
- 'mozc': 'en_US',
- 'mozc-chewing': 'zh_TW',
- 'mozc-dv': 'en_US_dvorak',
- 'mozc-hangul': 'ko',
- 'mozc-jp': 'ja',
- 'pinyin': 'zh_CN',
- 'pinyin-dv': 'en_US_dvorak',
'xkb:be::fra': 'fr',
'xkb:be::ger': 'de',
'xkb:be::nld': 'nl',
@@ -130,7 +111,6 @@ INPUT_METHOD_ID_TO_OVERLAY_ID = {
'xkb:il::heb': 'iw',
'xkb:it::ita': 'it',
'xkb:jp::jpn': 'ja',
- 'xkb:kr:kr104:kor': 'ko',
'xkb:latam::spa': 'es_419',
'xkb:lt::lit': 'lt',
'xkb:lv:apostrophe:lav': 'lv',
@@ -147,11 +127,15 @@ INPUT_METHOD_ID_TO_OVERLAY_ID = {
'xkb:tr::tur': 'tr',
'xkb:ua::ukr': 'uk',
'xkb:us::eng': 'en_US',
+ 'xkb:us::fil': 'en_US',
+ 'xkb:us::ind': 'en_US',
+ 'xkb:us::msa': 'en_US',
'xkb:us:altgr-intl:eng': 'en_US_altgr_intl',
'xkb:us:colemak:eng': 'en_US_colemak',
'xkb:us:dvorak:eng': 'en_US_dvorak',
'xkb:us:intl:eng': 'en_US_intl',
- 'zinnia-japanese': 'ja',
+ 'xkb:us:intl:nld': 'en_US_intl',
+ 'xkb:us:intl:por': 'en_US_intl'
}
# The file was first generated in 2012 and we have a policy of not updating
diff --git a/tools/gn/BUILD.gn b/tools/gn/BUILD.gn
index 39dc92ba10..87ec6c664d 100644
--- a/tools/gn/BUILD.gn
+++ b/tools/gn/BUILD.gn
@@ -54,6 +54,7 @@ static_library("gn_lib") {
"function_exec_script.cc",
"function_foreach.cc",
"function_get_label_info.cc",
+ "function_get_path_info.cc",
"function_get_target_outputs.cc",
"function_process_file_template.cc",
"function_read_file.cc",
@@ -182,6 +183,7 @@ test("gn_unittests") {
"file_template_unittest.cc",
"function_foreach_unittest.cc",
"function_get_label_info_unittest.cc",
+ "function_get_path_info_unittest.cc",
"function_get_target_outputs_unittest.cc",
"function_rebase_path_unittest.cc",
"function_write_file_unittest.cc",
@@ -200,6 +202,7 @@ test("gn_unittests") {
"parser_unittest.cc",
"path_output_unittest.cc",
"pattern_unittest.cc",
+ "run_all_unittests.cc",
"scope_per_file_provider_unittest.cc",
"scope_unittest.cc",
"source_dir_unittest.cc",
@@ -215,7 +218,6 @@ test("gn_unittests") {
]
deps = [
":gn_lib",
- "//base/test:run_all_unittests",
"//base/test:test_support",
"//testing/gtest",
]
diff --git a/tools/gn/bin/linux/gn.sha1 b/tools/gn/bin/linux/gn.sha1
index b2e67f6345..7a3cec8803 100644
--- a/tools/gn/bin/linux/gn.sha1
+++ b/tools/gn/bin/linux/gn.sha1
@@ -1 +1 @@
-8b2de69dd544188ae7813d4e08b5b1b04f9aa9f1 \ No newline at end of file
+224b6fd62d2187c3dfad190e998187f6ee20b727 \ No newline at end of file
diff --git a/tools/gn/bin/linux/gn32.sha1 b/tools/gn/bin/linux/gn32.sha1
index 2640fac329..d4183faf74 100644
--- a/tools/gn/bin/linux/gn32.sha1
+++ b/tools/gn/bin/linux/gn32.sha1
@@ -1 +1 @@
-1d1659f5d656746c5be525ce2b924faae4e237db \ No newline at end of file
+ca1b68df96b5b9013258d30d078354e9bf81d407 \ No newline at end of file
diff --git a/tools/gn/bin/mac/gn.sha1 b/tools/gn/bin/mac/gn.sha1
index a479b665cb..22ffdf7d64 100644
--- a/tools/gn/bin/mac/gn.sha1
+++ b/tools/gn/bin/mac/gn.sha1
@@ -1 +1 @@
-34f931d05f6f0d949911c48d223d3af282feb393
+6d7917d003a4776641b6ba19bfcef618e6daf3a9
diff --git a/tools/gn/bin/win/gn.exe.sha1 b/tools/gn/bin/win/gn.exe.sha1
index 8e1e546919..80dfd638d2 100644
--- a/tools/gn/bin/win/gn.exe.sha1
+++ b/tools/gn/bin/win/gn.exe.sha1
@@ -1,2 +1,2 @@
-753fae83cdf54ffdc241a3206d0f27e07ac4ad8c
+f8c407945b6af5ae2742a5ba59ee848a21e506ae
diff --git a/tools/gn/builder_unittest.cc b/tools/gn/builder_unittest.cc
index 75e01e5efb..9bf4bf52c3 100644
--- a/tools/gn/builder_unittest.cc
+++ b/tools/gn/builder_unittest.cc
@@ -45,7 +45,7 @@ class MockLoader : public Loader {
bool match = (
(files_[0] == a && files_[1] == b) ||
- (files_[0] == b && files_[0] == a));
+ (files_[0] == b && files_[1] == a));
files_.clear();
return match;
}
diff --git a/tools/gn/command_desc.cc b/tools/gn/command_desc.cc
index 4fea269b58..f4e97bfae7 100644
--- a/tools/gn/command_desc.cc
+++ b/tools/gn/command_desc.cc
@@ -69,6 +69,17 @@ void RecursivePrintDeps(const Target* target,
std::string indent(indent_level * 2, ' ');
for (size_t i = 0; i < sorted_deps.size(); i++) {
+ // Don't print groups. Groups are flattened such that the deps of the
+ // group are added directly to the target that depended on the group.
+ // Printing and recursing into groups here will cause such targets to be
+ // duplicated.
+ //
+ // It would be much more intuitive to do the opposite and not display the
+ // deps that were copied from the group to the target and instead display
+ // the group, but the source of those dependencies is not tracked.
+ if (sorted_deps[i].ptr->output_type() == Target::GROUP)
+ continue;
+
OutputString(indent +
sorted_deps[i].label.GetUserVisibleName(default_toolchain) + "\n");
RecursivePrintDeps(sorted_deps[i].ptr, default_toolchain, indent_level + 1);
@@ -145,6 +156,28 @@ void PrintLibs(const Target* target, bool display_header) {
OutputString(" " + libs[i] + "\n");
}
+void PrintPublic(const Target* target, bool display_header) {
+ if (display_header)
+ OutputString("\npublic\n");
+
+ if (target->all_headers_public()) {
+ OutputString(" [All headers listed in the sources are public.]\n");
+ return;
+ }
+
+ Target::FileList public_headers = target->public_headers();
+ std::sort(public_headers.begin(), public_headers.end());
+ for (size_t i = 0; i < public_headers.size(); i++)
+ OutputString(" " + public_headers[i].value() + "\n");
+}
+
+void PrintVisibility(const Target* target, bool display_header) {
+ if (display_header)
+ OutputString("\nvisibility\n");
+
+ OutputString(target->visibility().Describe(2, false));
+}
+
void PrintConfigs(const Target* target, bool display_header) {
// Configs (don't sort since the order determines how things are processed).
if (display_header)
@@ -247,6 +280,12 @@ const char kDesc_Help[] =
" sources\n"
" Source files.\n"
"\n"
+ " public\n"
+ " Public header files.\n"
+ "\n"
+ " visibility\n"
+ " Prints which targets can depend on this one.\n"
+ "\n"
" configs\n"
" Shows configs applied to the given target, sorted in the order\n"
" they're specified. This includes both configs specified in the\n"
@@ -320,6 +359,10 @@ int RunDesc(const std::vector<std::string>& args) {
PrintConfigs(target, false);
} else if (what == "sources") {
PrintSources(target, false);
+ } else if (what == "public") {
+ PrintPublic(target, false);
+ } else if (what == "visibility") {
+ PrintVisibility(target, false);
} else if (what == "deps") {
PrintDeps(target, false);
} else if (what == "lib_dirs") {
@@ -362,6 +405,8 @@ int RunDesc(const std::vector<std::string>& args) {
OutputString(target_toolchain.GetUserVisibleName(false) + "\n");
PrintSources(target, true);
+ PrintPublic(target, true);
+ PrintVisibility(target, true);
PrintConfigs(target, true);
OUTPUT_CONFIG_VALUE(defines, std::string)
diff --git a/tools/gn/escape.cc b/tools/gn/escape.cc
index 1658a8ad1e..7028a38b0b 100644
--- a/tools/gn/escape.cc
+++ b/tools/gn/escape.cc
@@ -5,10 +5,11 @@
#include "tools/gn/escape.h"
#include "base/containers/stack_container.h"
+#include "base/logging.h"
namespace {
-// A "1" in this lookup table means that char is valid in the shell.
+// A "1" in this lookup table means that char is valid in the Posix shell.
const char kShellValid[0x80] = {
// 00-1f: all are invalid
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -26,70 +27,150 @@ const char kShellValid[0x80] = {
// p q r s t u v w x y z { | } ~
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0 };
+// Append one character to the given string, escaping it for Ninja.
+//
+// Ninja's escaping rules are very simple. We always escape colons even
+// though they're OK in many places, in case the resulting string is used on
+// the left-hand-side of a rule.
template<typename DestString>
-void EscapeStringToString(const base::StringPiece& str,
- const EscapeOptions& options,
- DestString* dest,
- bool* needed_quoting) {
- bool used_quotes = false;
+inline void NinjaEscapeChar(char ch, DestString* dest) {
+ if (ch == '$' || ch == ' ' || ch == ':')
+ dest->push_back('$');
+ dest->push_back(ch);
+}
- for (size_t i = 0; i < str.size(); i++) {
- if (str[i] == '$' && (options.mode & ESCAPE_NINJA)) {
- // Escape dollars signs since ninja treats these specially. If we're also
- // escaping for the shell, we need to backslash-escape that again.
- if (options.mode & ESCAPE_SHELL)
- dest->push_back('\\');
- dest->push_back('$');
- dest->push_back('$');
- } else if (str[i] == ' ') {
- if (options.mode & ESCAPE_NINJA) {
- // For Ninja just escape spaces with $.
- dest->push_back('$');
+template<typename DestString>
+void EscapeStringToString_Ninja(const base::StringPiece& str,
+ const EscapeOptions& options,
+ DestString* dest,
+ bool* needed_quoting) {
+ for (size_t i = 0; i < str.size(); i++)
+ NinjaEscapeChar(str[i], dest);
+ if (needed_quoting)
+ *needed_quoting = false;
+}
+
+// Escape for CommandLineToArgvW and additionally escape Ninja characters.
+//
+// The basic algorithm is if the string doesn't contain any parse-affecting
+// characters, don't do anything (other than the Ninja processing). If it does,
+// quote the string, and backslash-escape all quotes and backslashes.
+// See:
+// http://blogs.msdn.com/b/twistylittlepassagesallalike/archive/2011/04/23/everyone-quotes-arguments-the-wrong-way.aspx
+// http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx
+template<typename DestString>
+void EscapeStringToString_WindowsNinjaFork(const base::StringPiece& str,
+ const EscapeOptions& options,
+ DestString* dest,
+ bool* needed_quoting) {
+ // We assume we don't have any whitespace chars that aren't spaces.
+ DCHECK(str.find_first_of("\r\n\v\t") == std::string::npos);
+
+ if (str.find_first_of(" \"") == std::string::npos) {
+ // Simple case, don't quote.
+ EscapeStringToString_Ninja(str, options, dest, needed_quoting);
+ } else {
+ if (!options.inhibit_quoting)
+ dest->push_back('"');
+
+ for (size_t i = 0; i < str.size(); i++) {
+ // Count backslashes in case they're followed by a quote.
+ size_t backslash_count = 0;
+ while (i < str.size() && str[i] == '\\') {
+ i++;
+ backslash_count++;
}
- if (options.mode & ESCAPE_SHELL) {
- // For the shell, quote the whole string.
- if (needed_quoting)
- *needed_quoting = true;
- if (!options.inhibit_quoting) {
- if (!used_quotes) {
- used_quotes = true;
- dest->insert(dest->begin(), '"');
- }
- }
+ if (i == str.size()) {
+ // Backslashes at end of string. Backslash-escape all of them since
+ // they'll be followed by a quote.
+ dest->append(backslash_count * 2, '\\');
+ } else if (str[i] == '"') {
+ // 0 or more backslashes followed by a quote. Backslash-escape the
+ // backslashes, then backslash-escape the quote.
+ dest->append(backslash_count * 2 + 1, '\\');
+ dest->push_back('"');
+ } else {
+ // Non-special Windows character, just escape for Ninja. Also, add any
+ // backslashes we read previously, these are literals.
+ dest->append(backslash_count, '\\');
+ NinjaEscapeChar(str[i], dest);
}
- dest->push_back(' ');
- } else if (str[i] == '\'' && (options.mode & ESCAPE_JSON)) {
- dest->push_back('\\');
- dest->push_back('\'');
-#if defined(OS_WIN)
- } else if (str[i] == '/' && options.convert_slashes) {
- // Convert slashes on Windows if requested.
- dest->push_back('\\');
-#else
- } else if (str[i] == '\\' && (options.mode & ESCAPE_SHELL)) {
- // For non-Windows shell, escape backslashes.
- dest->push_back('\\');
- dest->push_back('\\');
-#endif
- } else if (str[i] == '\\' && (options.mode & ESCAPE_JSON)) {
- dest->push_back('\\');
+ }
+
+ if (!options.inhibit_quoting)
+ dest->push_back('"');
+ if (needed_quoting)
+ *needed_quoting = true;
+ }
+}
+
+template<typename DestString>
+void EscapeStringToString_PosixNinjaFork(const base::StringPiece& str,
+ const EscapeOptions& options,
+ DestString* dest,
+ bool* needed_quoting) {
+ for (size_t i = 0; i < str.size(); i++) {
+ if (str[i] == '$' || str[i] == ' ') {
+ // Space and $ are special to both Ninja and the shell. '$' escape for
+ // Ninja, then backslash-escape for the shell.
dest->push_back('\\');
- } else if (str[i] == ':' && (options.mode & ESCAPE_NINJA)) {
+ dest->push_back('$');
+ dest->push_back(str[i]);
+ } else if (str[i] == ':') {
+ // Colon is the only other Ninja special char, which is not special to
+ // the shell.
dest->push_back('$');
dest->push_back(':');
- } else if ((options.mode & ESCAPE_SHELL) &&
- (static_cast<unsigned>(str[i]) >= 0x80 ||
- !kShellValid[static_cast<int>(str[i])])) {
+ } else if (static_cast<unsigned>(str[i]) >= 0x80 ||
+ !kShellValid[static_cast<int>(str[i])]) {
// All other invalid shell chars get backslash-escaped.
dest->push_back('\\');
dest->push_back(str[i]);
} else {
+ // Everything else is a literal.
dest->push_back(str[i]);
}
}
+}
- if (used_quotes)
- dest->push_back('"');
+template<typename DestString>
+void EscapeStringToString(const base::StringPiece& str,
+ const EscapeOptions& options,
+ DestString* dest,
+ bool* needed_quoting) {
+ switch (options.mode) {
+ case ESCAPE_NONE:
+ dest->append(str.data(), str.size());
+ break;
+ case ESCAPE_NINJA:
+ EscapeStringToString_Ninja(str, options, dest, needed_quoting);
+ break;
+ case ESCAPE_NINJA_COMMAND:
+ switch (options.platform) {
+ case ESCAPE_PLATFORM_CURRENT:
+#if defined(OS_WIN)
+ EscapeStringToString_WindowsNinjaFork(str, options, dest,
+ needed_quoting);
+#else
+ EscapeStringToString_PosixNinjaFork(str, options, dest,
+ needed_quoting);
+#endif
+ break;
+ case ESCAPE_PLATFORM_WIN:
+ EscapeStringToString_WindowsNinjaFork(str, options, dest,
+ needed_quoting);
+ break;
+ case ESCAPE_PLATFORM_POSIX:
+ EscapeStringToString_PosixNinjaFork(str, options, dest,
+ needed_quoting);
+ break;
+ default:
+ NOTREACHED();
+ }
+ break;
+ default:
+ NOTREACHED();
+ }
}
} // namespace
@@ -106,10 +187,8 @@ std::string EscapeString(const base::StringPiece& str,
void EscapeStringToStream(std::ostream& out,
const base::StringPiece& str,
const EscapeOptions& options) {
- // Escape to a stack buffer and then write out to the stream.
- base::StackVector<char, 256> result;
- result->reserve(str.size() + 4); // Guess we'll add a couple of extra chars.
- EscapeStringToString(str, options, &result.container(), NULL);
- if (!result->empty())
- out.write(&result[0], result->size());
+ base::StackString<256> escaped;
+ EscapeStringToString(str, options, &escaped.container(), NULL);
+ if (!escaped->empty())
+ out.write(escaped->data(), escaped->size());
}
diff --git a/tools/gn/escape.h b/tools/gn/escape.h
index 1e4fa68977..6f8cf9cc3b 100644
--- a/tools/gn/escape.h
+++ b/tools/gn/escape.h
@@ -14,35 +14,42 @@ enum EscapingMode {
ESCAPE_NONE,
// Ninja string escaping.
- ESCAPE_NINJA = 1,
+ ESCAPE_NINJA,
- // Shell string escaping.
- ESCAPE_SHELL = 2,
+ // For writing commands to ninja files.
+ ESCAPE_NINJA_COMMAND,
+};
- // For writing shell commands to ninja files.
- ESCAPE_NINJA_SHELL = ESCAPE_NINJA | ESCAPE_SHELL,
+enum EscapingPlatform {
+ // Do escaping for the current platform.
+ ESCAPE_PLATFORM_CURRENT,
- ESCAPE_JSON = 4,
+ // Force escaping for the given platform.
+ ESCAPE_PLATFORM_POSIX,
+ ESCAPE_PLATFORM_WIN,
};
struct EscapeOptions {
EscapeOptions()
: mode(ESCAPE_NONE),
- convert_slashes(false),
+ platform(ESCAPE_PLATFORM_CURRENT),
inhibit_quoting(false) {
}
EscapingMode mode;
- // When set, converts forward-slashes to system-specific path separators.
- bool convert_slashes;
+ // Controls how "fork" escaping is done. You will generally want to keep the
+ // default "current" platform.
+ EscapingPlatform platform;
// When the escaping mode is ESCAPE_SHELL, the escaper will normally put
// quotes around things with spaces. If this value is set to true, we'll
// disable the quoting feature and just add the spaces.
//
// This mode is for when quoting is done at some higher-level. Defaults to
- // false.
+ // false. Note that Windows has strange behavior where the meaning of the
+ // backslashes changes according to if it is followed by a quote. The
+ // escaping rules assume that a double-quote will be appended to the result.
bool inhibit_quoting;
};
diff --git a/tools/gn/escape_unittest.cc b/tools/gn/escape_unittest.cc
index 9d0cf7a900..1a79a78b67 100644
--- a/tools/gn/escape_unittest.cc
+++ b/tools/gn/escape_unittest.cc
@@ -12,69 +12,41 @@ TEST(Escape, Ninja) {
EXPECT_EQ("asdf$:$ \"$$\\bar", result);
}
-TEST(Escape, Shell) {
+TEST(Escape, WindowsCommand) {
EscapeOptions opts;
- opts.mode = ESCAPE_SHELL;
- std::string result = EscapeString("asdf: \"$\\bar", opts, NULL);
-#if defined(OS_WIN)
- // Windows shell doesn't escape backslashes, but it does backslash-escape
- // quotes.
- EXPECT_EQ("\"asdf: \\\"\\$\\bar\"", result);
-#else
- EXPECT_EQ("\"asdf: \\\"\\$\\\\bar\"", result);
-#endif
-
- // Some more generic shell chars.
- result = EscapeString("a_;<*b", opts, NULL);
- EXPECT_EQ("a_\\;\\<\\*b", result);
-}
+ opts.mode = ESCAPE_NINJA_COMMAND;
+ opts.platform = ESCAPE_PLATFORM_WIN;
-TEST(Escape, NinjaShell) {
- EscapeOptions opts;
- opts.mode = ESCAPE_NINJA_SHELL;
+ // Regular string is passed, even if it has backslashes.
+ EXPECT_EQ("foo\\bar", EscapeString("foo\\bar", opts, NULL));
- // When escaping for Ninja and the shell, we would escape a $, then escape
- // the backslash again.
- std::string result = EscapeString("a$b", opts, NULL);
- EXPECT_EQ("a\\$$b", result);
-}
+ // Spaces means the string is quoted, normal backslahes untouched.
+ bool needs_quoting = false;
+ EXPECT_EQ("\"foo\\$ bar\"", EscapeString("foo\\ bar", opts, &needs_quoting));
+ EXPECT_TRUE(needs_quoting);
-TEST(Escape, UsedQuotes) {
- EscapeOptions shell_options;
- shell_options.mode = ESCAPE_SHELL;
+ // Inhibit quoting.
+ needs_quoting = false;
+ opts.inhibit_quoting = true;
+ EXPECT_EQ("foo\\$ bar", EscapeString("foo\\ bar", opts, &needs_quoting));
+ EXPECT_TRUE(needs_quoting);
+ opts.inhibit_quoting = false;
- EscapeOptions ninja_options;
- ninja_options.mode = ESCAPE_NINJA;
+ // Backslashes at the end of the string get escaped.
+ EXPECT_EQ("\"foo$ bar\\\\\\\\\"", EscapeString("foo bar\\\\", opts, NULL));
- EscapeOptions ninja_shell_options;
- ninja_shell_options.mode = ESCAPE_NINJA_SHELL;
-
- // Shell escaping with quoting inhibited.
- bool used_quotes = false;
- shell_options.inhibit_quoting = true;
- EXPECT_EQ("foo bar", EscapeString("foo bar", shell_options, &used_quotes));
- EXPECT_TRUE(used_quotes);
-
- // Shell escaping with regular quoting.
- used_quotes = false;
- shell_options.inhibit_quoting = false;
- EXPECT_EQ("\"foo bar\"",
- EscapeString("foo bar", shell_options, &used_quotes));
- EXPECT_TRUE(used_quotes);
+ // Backslashes preceeding quotes are escaped, and the quote is escaped.
+ EXPECT_EQ("\"foo\\\\\\\"$ bar\"", EscapeString("foo\\\" bar", opts, NULL));
+}
- // Ninja shell escaping should be the same.
- used_quotes = false;
- EXPECT_EQ("\"foo$ bar\"",
- EscapeString("foo bar", ninja_shell_options, &used_quotes));
- EXPECT_TRUE(used_quotes);
+TEST(Escape, PosixCommand) {
+ EscapeOptions opts;
+ opts.mode = ESCAPE_NINJA_COMMAND;
+ opts.platform = ESCAPE_PLATFORM_POSIX;
- // Ninja escaping shouldn't use quoting.
- used_quotes = false;
- EXPECT_EQ("foo$ bar", EscapeString("foo bar", ninja_options, &used_quotes));
- EXPECT_FALSE(used_quotes);
+ // : and $ ninja escaped with $. Then Shell-escape backslashes and quotes.
+ EXPECT_EQ("a$:\\$ \\\"\\$$\\\\b", EscapeString("a: \"$\\b", opts, NULL));
- // Used quotes not reset if it's already true.
- used_quotes = true;
- EscapeString("foo", ninja_options, &used_quotes);
- EXPECT_TRUE(used_quotes);
+ // Some more generic shell chars.
+ EXPECT_EQ("a_\\;\\<\\*b", EscapeString("a_;<*b", opts, NULL));
}
diff --git a/tools/gn/file_template.cc b/tools/gn/file_template.cc
index b6264829e9..b00eb39173 100644
--- a/tools/gn/file_template.cc
+++ b/tools/gn/file_template.cc
@@ -166,7 +166,7 @@ void FileTemplate::ApplyString(const std::string& str,
void FileTemplate::WriteWithNinjaExpansions(std::ostream& out) const {
EscapeOptions escape_options;
- escape_options.mode = ESCAPE_NINJA_SHELL;
+ escape_options.mode = ESCAPE_NINJA_COMMAND;
escape_options.inhibit_quoting = true;
for (size_t template_i = 0;
@@ -184,8 +184,10 @@ void FileTemplate::WriteWithNinjaExpansions(std::ostream& out) const {
for (size_t subrange_i = 0; subrange_i < t.container().size();
subrange_i++) {
if (t[subrange_i].type == Subrange::LITERAL) {
+ bool cur_needs_quoting = false;
item_str.append(EscapeString(t[subrange_i].literal, escape_options,
- &needs_quoting));
+ &cur_needs_quoting));
+ needs_quoting |= cur_needs_quoting;
} else {
// Don't escape this since we need to preserve the $.
item_str.append("${");
diff --git a/tools/gn/file_template_unittest.cc b/tools/gn/file_template_unittest.cc
index cd5611c1df..8e3bf40b90 100644
--- a/tools/gn/file_template_unittest.cc
+++ b/tools/gn/file_template_unittest.cc
@@ -63,11 +63,19 @@ TEST(FileTemplate, NinjaExpansions) {
std::ostringstream out;
t.WriteWithNinjaExpansions(out);
+#if defined(OS_WIN)
// The third argument should get quoted since it contains a space, and the
// embedded quotes should get shell escaped.
EXPECT_EQ(
" -i ${source} \"--out=foo$ bar\\\"${source_name_part}\\\".o\" \"\"",
out.str());
+#else
+ // On Posix we don't need to quote the whole thing and can escape all
+ // individual bad chars.
+ EXPECT_EQ(
+ " -i ${source} --out=foo\\$ bar\\\"${source_name_part}\\\".o \"\"",
+ out.str());
+#endif
}
TEST(FileTemplate, NinjaVariables) {
@@ -80,7 +88,7 @@ TEST(FileTemplate, NinjaVariables) {
std::ostringstream out;
EscapeOptions options;
- options.mode = ESCAPE_NINJA_SHELL;
+ options.mode = ESCAPE_NINJA_COMMAND;
t.WriteNinjaVariablesForSubstitution(out, "../../foo/bar.txt", options);
// Just the variables used above should be written.
diff --git a/tools/gn/function_get_path_info.cc b/tools/gn/function_get_path_info.cc
new file mode 100644
index 0000000000..23f690cfdc
--- /dev/null
+++ b/tools/gn/function_get_path_info.cc
@@ -0,0 +1,197 @@
+// 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.
+
+#include "tools/gn/err.h"
+#include "tools/gn/filesystem_utils.h"
+#include "tools/gn/functions.h"
+#include "tools/gn/parse_tree.h"
+#include "tools/gn/scope.h"
+#include "tools/gn/value.h"
+
+namespace functions {
+
+namespace {
+
+// Corresponds to the various values of "what" in the function call.
+enum What {
+ WHAT_FILE,
+ WHAT_NAME,
+ WHAT_EXTENSION,
+ WHAT_DIR,
+ WHAT_ABSPATH,
+};
+
+std::string GetOnePathInfo(const SourceDir& current_dir,
+ What what,
+ const Value& input,
+ Err* err) {
+ if (!input.VerifyTypeIs(Value::STRING, err))
+ return std::string();
+ const std::string& input_string = input.string_value();
+ if (input_string.empty()) {
+ *err = Err(input, "Calling get_path_info on an empty string.");
+ return std::string();
+ }
+
+ switch (what) {
+ case WHAT_FILE: {
+ return FindFilename(&input_string).as_string();
+ }
+ case WHAT_NAME: {
+ std::string file = FindFilename(&input_string).as_string();
+ size_t extension_offset = FindExtensionOffset(file);
+ if (extension_offset == std::string::npos)
+ return file;
+ // Trim extension and dot.
+ return file.substr(0, extension_offset - 1);
+ }
+ case WHAT_EXTENSION: {
+ return FindExtension(&input_string).as_string();
+ }
+ case WHAT_DIR: {
+ base::StringPiece dir_incl_slash = FindDir(&input_string);
+ if (dir_incl_slash.empty())
+ return std::string(".");
+ // Trim slash since this function doesn't return trailing slashes. The
+ // times we don't do this are if the result is "/" and "//" since those
+ // slashes can't be trimmed.
+ if (dir_incl_slash == "/")
+ return std::string("/.");
+ if (dir_incl_slash == "//")
+ return std::string("//.");
+ return dir_incl_slash.substr(0, dir_incl_slash.size() - 1).as_string();
+ }
+ case WHAT_ABSPATH: {
+ if (!input_string.empty() && input_string[input_string.size() - 1] == '/')
+ return current_dir.ResolveRelativeDir(input_string).value();
+ else
+ return current_dir.ResolveRelativeFile(input_string).value();
+ }
+ default:
+ NOTREACHED();
+ return std::string();
+ }
+}
+
+} // namespace
+
+const char kGetPathInfo[] = "get_path_info";
+const char kGetPathInfo_HelpShort[] =
+ "get_path_info: Extract parts of a file or directory name.";
+const char kGetPathInfo_Help[] =
+ "get_path_info: Extract parts of a file or directory name.\n"
+ "\n"
+ " get_path_info(input, what)\n"
+ "\n"
+ " The first argument is either a string representing a file or\n"
+ " directory name, or a list of such strings. If the input is a list\n"
+ " the return value will be a list containing the result of applying the\n"
+ " rule to each item in the input.\n"
+ "\n"
+ "Possible values for the \"what\" parameter\n"
+ "\n"
+ " \"file\"\n"
+ " The substring after the last slash in the path, including the name\n"
+ " and extension. If the input ends in a slash, the empty string will\n"
+ " be returned.\n"
+ " \"foo/bar.txt\" => \"bar.txt\"\n"
+ " \"bar.txt\" => \"bar.txt\"\n"
+ " \"foo/\" => \"\"\n"
+ " \"\" => \"\"\n"
+ "\n"
+ " \"name\"\n"
+ " The substring of the file name not including the extension.\n"
+ " \"foo/bar.txt\" => \"bar\"\n"
+ " \"foo/bar\" => \"bar\"\n"
+ " \"foo/\" => \"\"\n"
+ "\n"
+ " \"extension\"\n"
+ " The substring following the last period following the last slash,\n"
+ " or the empty string if not found. The period is not included.\n"
+ " \"foo/bar.txt\" => \"txt\"\n"
+ " \"foo/bar\" => \"\"\n"
+ "\n"
+ " \"dir\"\n"
+ " The directory portion of the name, not including the slash.\n"
+ " \"foo/bar.txt\" => \"foo\"\n"
+ " \"//foo/bar\" => \"//foo\"\n"
+ " \"foo\" => \".\"\n"
+ "\n"
+ " The result will never end in a slash, so if the resulting\n"
+ " is empty, the system (\"/\") or source (\"//\") roots, a \".\"\n"
+ " will be appended such that it is always legal to append a slash\n"
+ " and a filename and get a valid path.\n"
+ "\n"
+ " \"abspath\"\n"
+ " The full absolute path name to the file or directory. It will be\n"
+ " resolved relative to the currebt directory, and then the source-\n"
+ " absolute version will be returned. If the input is system-\n"
+ " absolute, the same input will be returned.\n"
+ " \"foo/bar.txt\" => \"//mydir/foo/bar.txt\"\n"
+ " \"foo/\" => \"//mydir/foo/\"\n"
+ " \"//foo/bar\" => \"//foo/bar\" (already absolute)\n"
+ " \"/usr/include\" => \"/usr/include\" (already absolute)\n"
+ "\n"
+ " If you want to make the path relative to another directory, or to\n"
+ " be system-absolute, see rebase_path().\n"
+ "\n"
+ "Examples\n"
+ " sources = [ \"foo.cc\", \"foo.h\" ]\n"
+ " result = get_path_info(source, \"abspath\")\n"
+ " # result will be [ \"//mydir/foo.cc\", \"//mydir/foo.h\" ]\n"
+ "\n"
+ " result = get_path_info(\"//foo/bar/baz.cc\", \"dir\")\n"
+ " # result will be \"//foo/bar\"\n"
+ "\n"
+ " # Extract the source-absolute directory name,\n"
+ " result = get_path_info(get_path_info(path, \"dir\"), \"abspath\")\n";
+
+Value RunGetPathInfo(Scope* scope,
+ const FunctionCallNode* function,
+ const std::vector<Value>& args,
+ Err* err) {
+ if (args.size() != 2) {
+ *err = Err(function, "Expecting two arguments to get_path_info.");
+ return Value();
+ }
+
+ // Extract the "what".
+ if (!args[1].VerifyTypeIs(Value::STRING, err))
+ return Value();
+ What what;
+ if (args[1].string_value() == "file") {
+ what = WHAT_FILE;
+ } else if (args[1].string_value() == "name") {
+ what = WHAT_NAME;
+ } else if (args[1].string_value() == "extension") {
+ what = WHAT_EXTENSION;
+ } else if (args[1].string_value() == "dir") {
+ what = WHAT_DIR;
+ } else if (args[1].string_value() == "abspath") {
+ what = WHAT_ABSPATH;
+ } else {
+ *err = Err(args[1], "Unknown value for 'what'.");
+ return Value();
+ }
+
+ const SourceDir& current_dir = scope->GetSourceDir();
+ if (args[0].type() == Value::STRING) {
+ return Value(function, GetOnePathInfo(current_dir, what, args[0], err));
+ } else if (args[0].type() == Value::LIST) {
+ const std::vector<Value>& input_list = args[0].list_value();
+ Value result(function, Value::LIST);
+ for (size_t i = 0; i < input_list.size(); i++) {
+ result.list_value().push_back(Value(function,
+ GetOnePathInfo(current_dir, what, input_list[i], err)));
+ if (err->has_error())
+ return Value();
+ }
+ return result;
+ }
+
+ *err = Err(args[0], "Path must be a string or a list of strings.");
+ return Value();
+}
+
+} // namespace functions
diff --git a/tools/gn/function_get_path_info_unittest.cc b/tools/gn/function_get_path_info_unittest.cc
new file mode 100644
index 0000000000..12bdc2a5ad
--- /dev/null
+++ b/tools/gn/function_get_path_info_unittest.cc
@@ -0,0 +1,89 @@
+// 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.
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "tools/gn/functions.h"
+#include "tools/gn/test_with_scope.h"
+
+namespace {
+
+class GetPathInfoTest : public testing::Test {
+ public:
+ GetPathInfoTest() : testing::Test() {
+ setup_.scope()->set_source_dir(SourceDir("//src/foo/"));
+ }
+
+ // Convenience wrapper to call GetLabelInfo.
+ std::string Call(const std::string& input, const std::string& what) {
+ FunctionCallNode function;
+
+ std::vector<Value> args;
+ args.push_back(Value(NULL, input));
+ args.push_back(Value(NULL, what));
+
+ Err err;
+ Value result = functions::RunGetPathInfo(setup_.scope(), &function,
+ args, &err);
+ if (err.has_error()) {
+ EXPECT_TRUE(result.type() == Value::NONE);
+ return std::string();
+ }
+ return result.string_value();
+ }
+
+ protected:
+ TestWithScope setup_;
+};
+
+} // namespace
+
+TEST_F(GetPathInfoTest, File) {
+ EXPECT_EQ("bar.txt", Call("foo/bar.txt", "file"));
+ EXPECT_EQ("bar.txt", Call("bar.txt", "file"));
+ EXPECT_EQ("bar.txt", Call("/bar.txt", "file"));
+ EXPECT_EQ("", Call("foo/", "file"));
+ EXPECT_EQ("", Call("//", "file"));
+ EXPECT_EQ("", Call("/", "file"));
+}
+
+TEST_F(GetPathInfoTest, Name) {
+ EXPECT_EQ("bar", Call("foo/bar.txt", "name"));
+ EXPECT_EQ("bar", Call("bar.", "name"));
+ EXPECT_EQ("", Call("/.txt", "name"));
+ EXPECT_EQ("", Call("foo/", "name"));
+ EXPECT_EQ("", Call("//", "name"));
+ EXPECT_EQ("", Call("/", "name"));
+}
+
+TEST_F(GetPathInfoTest, Extension) {
+ EXPECT_EQ("txt", Call("foo/bar.txt", "extension"));
+ EXPECT_EQ("", Call("bar.", "extension"));
+ EXPECT_EQ("txt", Call("/.txt", "extension"));
+ EXPECT_EQ("", Call("f.oo/", "extension"));
+ EXPECT_EQ("", Call("//", "extension"));
+ EXPECT_EQ("", Call("/", "extension"));
+}
+
+TEST_F(GetPathInfoTest, Dir) {
+ EXPECT_EQ("foo", Call("foo/bar.txt", "dir"));
+ EXPECT_EQ(".", Call("bar.txt", "dir"));
+ EXPECT_EQ("foo/bar", Call("foo/bar/baz", "dir"));
+ EXPECT_EQ("//foo", Call("//foo/", "dir"));
+ EXPECT_EQ("//.", Call("//", "dir"));
+ EXPECT_EQ("/foo", Call("/foo/", "dir"));
+ EXPECT_EQ("/.", Call("/", "dir"));
+}
+
+// Note "current dir" is "//src/foo"
+TEST_F(GetPathInfoTest, AbsPath) {
+ EXPECT_EQ("//src/foo/foo/bar.txt", Call("foo/bar.txt", "abspath"));
+ EXPECT_EQ("//src/foo/bar.txt", Call("bar.txt", "abspath"));
+ EXPECT_EQ("//src/foo/bar/", Call("bar/", "abspath"));
+ EXPECT_EQ("//foo", Call("//foo", "abspath"));
+ EXPECT_EQ("//foo/", Call("//foo/", "abspath"));
+ EXPECT_EQ("//", Call("//", "abspath"));
+ EXPECT_EQ("/foo", Call("/foo", "abspath"));
+ EXPECT_EQ("/foo/", Call("/foo/", "abspath"));
+ EXPECT_EQ("/", Call("/", "abspath"));
+}
diff --git a/tools/gn/function_rebase_path.cc b/tools/gn/function_rebase_path.cc
index 4f66688e86..dd5e903ec8 100644
--- a/tools/gn/function_rebase_path.cc
+++ b/tools/gn/function_rebase_path.cc
@@ -131,6 +131,13 @@ const char kRebasePath_Help[] =
" current directory to be relative to the build directory (which will\n"
" be the current directory when executing scripts).\n"
"\n"
+ " If you want to convert a file path to be source-absolute (that is,\n"
+ " beginning with a double slash like \"//foo/bar\"), you should use\n"
+ " the get_path_info() function. This function won't work because it will\n"
+ " always make relative paths, and it needs to support making paths\n"
+ " relative to the source root, so can't also generate source-absolute\n"
+ " paths without more special-cases.\n"
+ "\n"
"Arguments:\n"
"\n"
" input\n"
diff --git a/tools/gn/functions.cc b/tools/gn/functions.cc
index 97c2592c46..e973f2ee5c 100644
--- a/tools/gn/functions.cc
+++ b/tools/gn/functions.cc
@@ -660,6 +660,7 @@ struct FunctionInfoInitializer {
INSERT_FUNCTION(ForEach, false)
INSERT_FUNCTION(GetEnv, false)
INSERT_FUNCTION(GetLabelInfo, false)
+ INSERT_FUNCTION(GetPathInfo, false)
INSERT_FUNCTION(GetTargetOutputs, false)
INSERT_FUNCTION(Import, false)
INSERT_FUNCTION(Print, false)
diff --git a/tools/gn/functions.h b/tools/gn/functions.h
index 4b1384ab10..45bb4ded28 100644
--- a/tools/gn/functions.h
+++ b/tools/gn/functions.h
@@ -163,6 +163,14 @@ Value RunGetLabelInfo(Scope* scope,
const std::vector<Value>& args,
Err* err);
+extern const char kGetPathInfo[];
+extern const char kGetPathInfo_HelpShort[];
+extern const char kGetPathInfo_Help[];
+Value RunGetPathInfo(Scope* scope,
+ const FunctionCallNode* function,
+ const std::vector<Value>& args,
+ Err* err);
+
extern const char kGetTargetOutputs[];
extern const char kGetTargetOutputs_HelpShort[];
extern const char kGetTargetOutputs_Help[];
diff --git a/tools/gn/gn.gyp b/tools/gn/gn.gyp
index b43e700705..d972b5b999 100644
--- a/tools/gn/gn.gyp
+++ b/tools/gn/gn.gyp
@@ -58,6 +58,7 @@
'function_exec_script.cc',
'function_foreach.cc',
'function_get_label_info.cc',
+ 'function_get_path_info.cc',
'function_get_target_outputs.cc',
'function_process_file_template.cc',
'function_read_file.cc',
@@ -183,6 +184,7 @@
'file_template_unittest.cc',
'function_foreach_unittest.cc',
'function_get_label_info_unittest.cc',
+ 'function_get_path_info_unittest.cc',
'function_get_target_outputs_unittest.cc',
'function_rebase_path_unittest.cc',
'function_write_file_unittest.cc',
@@ -201,6 +203,7 @@
'parser_unittest.cc',
'path_output_unittest.cc',
'pattern_unittest.cc',
+ 'run_all_unittests.cc',
'scope_per_file_provider_unittest.cc',
'scope_unittest.cc',
'source_dir_unittest.cc',
@@ -215,7 +218,6 @@
],
'dependencies': [
'gn_lib',
- '../../base/base.gyp:run_all_unittests',
'../../base/base.gyp:test_support_base',
'../../testing/gtest.gyp:gtest',
],
diff --git a/tools/gn/ninja_action_target_writer.cc b/tools/gn/ninja_action_target_writer.cc
index 1b71fced9c..27bd8a4c58 100644
--- a/tools/gn/ninja_action_target_writer.cc
+++ b/tools/gn/ninja_action_target_writer.cc
@@ -16,7 +16,7 @@ NinjaActionTargetWriter::NinjaActionTargetWriter(const Target* target,
: NinjaTargetWriter(target, toolchain, out),
path_output_no_escaping_(
target->settings()->build_settings()->build_dir(),
- ESCAPE_NONE, false) {
+ ESCAPE_NONE) {
}
NinjaActionTargetWriter::~NinjaActionTargetWriter() {
@@ -144,8 +144,7 @@ void NinjaActionTargetWriter::WriteArgsSubstitutions(
path_output_no_escaping_.WriteFile(source_file_stream, source);
EscapeOptions template_escape_options;
- template_escape_options.mode = ESCAPE_NINJA_SHELL;
- template_escape_options.inhibit_quoting = true;
+ template_escape_options.mode = ESCAPE_NINJA_COMMAND;
args_template.WriteNinjaVariablesForSubstitution(
out_, source_file_stream.str(), template_escape_options);
diff --git a/tools/gn/ninja_action_target_writer_unittest.cc b/tools/gn/ninja_action_target_writer_unittest.cc
index 10b5f81e84..9c6f2f1c3b 100644
--- a/tools/gn/ninja_action_target_writer_unittest.cc
+++ b/tools/gn/ninja_action_target_writer_unittest.cc
@@ -29,11 +29,7 @@ TEST(NinjaActionTargetWriter, WriteOutputFilesForBuildLine) {
std::vector<OutputFile> output_files;
writer.WriteOutputFilesForBuildLine(output_template, source, &output_files);
- std::string out_str = out.str();
-#if defined(OS_WIN)
- std::replace(out_str.begin(), out_str.end(), '\\', '/');
-#endif
- EXPECT_EQ(" gen/a$ bbar.h gen/bar.cc", out_str);
+ EXPECT_EQ(" gen/a$ bbar.h gen/bar.cc", out.str());
}
TEST(NinjaActionTargetWriter, WriteOutputFilesForBuildLineWithDepfile) {
@@ -57,11 +53,7 @@ TEST(NinjaActionTargetWriter, WriteOutputFilesForBuildLineWithDepfile) {
std::vector<OutputFile> output_files;
writer.WriteOutputFilesForBuildLine(output_template, source, &output_files);
- std::string out_str = out.str();
-#if defined(OS_WIN)
- std::replace(out_str.begin(), out_str.end(), '\\', '/');
-#endif
- EXPECT_EQ(" gen/bar.d gen/bar.h gen/bar.cc", out_str);
+ EXPECT_EQ(" gen/bar.d gen/bar.h gen/bar.cc", out.str());
}
TEST(NinjaActionTargetWriter, WriteArgsSubstitutions) {
@@ -79,13 +71,15 @@ TEST(NinjaActionTargetWriter, WriteArgsSubstitutions) {
FileTemplate args_template(args);
writer.WriteArgsSubstitutions(SourceFile("//foo/b ar.in"), args_template);
-
- std::string out_str = out.str();
#if defined(OS_WIN)
- std::replace(out_str.begin(), out_str.end(), '\\', '/');
+ EXPECT_EQ(" source = \"../../foo/b$ ar.in\"\n"
+ " source_name_part = \"b$ ar\"\n",
+ out.str());
+#else
+ EXPECT_EQ(" source = ../../foo/b\\$ ar.in\n"
+ " source_name_part = b\\$ ar\n",
+ out.str());
#endif
- EXPECT_EQ(" source = ../../foo/b$ ar.in\n source_name_part = b$ ar\n",
- out_str);
}
// Makes sure that we write sources as input dependencies for actions with
@@ -126,11 +120,7 @@ TEST(NinjaActionTargetWriter, ActionWithSources) {
"build foo.out: __foo_bar___rule | obj/foo/bar.inputdeps.stamp\n"
"\n"
"build obj/foo/bar.stamp: stamp foo.out\n";
- std::string out_str = out.str();
-#if defined(OS_WIN)
- std::replace(out_str.begin(), out_str.end(), '\\', '/');
-#endif
- EXPECT_EQ(expected_linux, out_str);
+ EXPECT_EQ(expected_linux, out.str());
}
// Windows.
@@ -145,8 +135,6 @@ TEST(NinjaActionTargetWriter, ActionWithSources) {
NinjaActionTargetWriter writer(&target, setup.toolchain(), out);
writer.Run();
- // TODO(brettw) I think we'll need to worry about backslashes here
- // depending if we're on actual Windows or Linux pretending to be Windows.
const char expected_win[] =
"rule __foo_bar___rule\n"
" command = C$:/python/python.exe gyp-win-tool action-wrapper environment.x86 __foo_bar___rule.$unique_name.rsp\n"
@@ -160,11 +148,7 @@ TEST(NinjaActionTargetWriter, ActionWithSources) {
"build foo.out: __foo_bar___rule | obj/foo/bar.inputdeps.stamp\n"
"\n"
"build obj/foo/bar.stamp: stamp foo.out\n";
- std::string out_str = out.str();
-#if defined(OS_WIN)
- std::replace(out_str.begin(), out_str.end(), '\\', '/');
-#endif
- EXPECT_EQ(expected_win, out_str);
+ EXPECT_EQ(expected_win, out.str());
}
}
@@ -214,7 +198,12 @@ TEST(NinjaActionTargetWriter, ForEach) {
const char expected_linux[] =
"rule __foo_bar___rule\n"
" command = /usr/bin/python ../../foo/script.py -i ${source} "
+ // Escaping is different between Windows and Posix.
+#if defined(OS_WIN)
"\"--out=foo$ bar${source_name_part}.o\"\n"
+#else
+ "--out=foo\\$ bar${source_name_part}.o\n"
+#endif
" description = ACTION //foo:bar()\n"
" restat = 1\n"
"build obj/foo/bar.inputdeps.stamp: stamp ../../foo/script.py "
@@ -241,8 +230,6 @@ TEST(NinjaActionTargetWriter, ForEach) {
// Windows.
{
- // Note: we use forward slashes here so that the output will be the same on
- // Linux and Windows.
setup.build_settings()->set_python_path(base::FilePath(FILE_PATH_LITERAL(
"C:/python/python.exe")));
setup.settings()->set_target_os(Settings::WIN);
@@ -251,8 +238,6 @@ TEST(NinjaActionTargetWriter, ForEach) {
NinjaActionTargetWriter writer(&target, setup.toolchain(), out);
writer.Run();
- // TODO(brettw) I think we'll need to worry about backslashes here
- // depending if we're on actual Windows or Linux pretending to be Windows.
const char expected_win[] =
"rule __foo_bar___rule\n"
" command = C$:/python/python.exe gyp-win-tool action-wrapper "
@@ -261,7 +246,11 @@ TEST(NinjaActionTargetWriter, ForEach) {
" restat = 1\n"
" rspfile = __foo_bar___rule.$unique_name.rsp\n"
" rspfile_content = C$:/python/python.exe ../../foo/script.py -i "
+#if defined(OS_WIN)
"${source} \"--out=foo$ bar${source_name_part}.o\"\n"
+#else
+ "${source} --out=foo\\$ bar${source_name_part}.o\n"
+#endif
"build obj/foo/bar.inputdeps.stamp: stamp ../../foo/script.py "
"../../foo/included.txt obj/foo/dep.stamp\n"
"\n"
@@ -278,11 +267,7 @@ TEST(NinjaActionTargetWriter, ForEach) {
"\n"
"build obj/foo/bar.stamp: "
"stamp input1.out input2.out obj/foo/datadep.stamp\n";
- std::string out_str = out.str();
-#if defined(OS_WIN)
- std::replace(out_str.begin(), out_str.end(), '\\', '/');
-#endif
- EXPECT_EQ(expected_win, out_str);
+ EXPECT_EQ(expected_win, out.str());
}
}
@@ -322,7 +307,11 @@ TEST(NinjaActionTargetWriter, ForEachWithDepfile) {
const char expected_linux[] =
"rule __foo_bar___rule\n"
" command = /usr/bin/python ../../foo/script.py -i ${source} "
+#if defined(OS_WIN)
"\"--out=foo$ bar${source_name_part}.o\"\n"
+#else
+ "--out=foo\\$ bar${source_name_part}.o\n"
+#endif
" description = ACTION //foo:bar()\n"
" restat = 1\n"
"build obj/foo/bar.inputdeps.stamp: stamp ../../foo/script.py "
@@ -340,18 +329,11 @@ TEST(NinjaActionTargetWriter, ForEachWithDepfile) {
" depfile = gen/input2.d\n"
"\n"
"build obj/foo/bar.stamp: stamp input1.out input2.out\n";
-
- std::string out_str = out.str();
-#if defined(OS_WIN)
- std::replace(out_str.begin(), out_str.end(), '\\', '/');
-#endif
- EXPECT_EQ(expected_linux, out_str);
+ EXPECT_EQ(expected_linux, out.str());
}
// Windows.
{
- // Note: we use forward slashes here so that the output will be the same on
- // Linux and Windows.
setup.build_settings()->set_python_path(base::FilePath(FILE_PATH_LITERAL(
"C:/python/python.exe")));
setup.settings()->set_target_os(Settings::WIN);
@@ -360,8 +342,6 @@ TEST(NinjaActionTargetWriter, ForEachWithDepfile) {
NinjaActionTargetWriter writer(&target, setup.toolchain(), out);
writer.Run();
- // TODO(brettw) I think we'll need to worry about backslashes here
- // depending if we're on actual Windows or Linux pretending to be Windows.
const char expected_win[] =
"rule __foo_bar___rule\n"
" command = C$:/python/python.exe gyp-win-tool action-wrapper "
@@ -370,7 +350,11 @@ TEST(NinjaActionTargetWriter, ForEachWithDepfile) {
" restat = 1\n"
" rspfile = __foo_bar___rule.$unique_name.rsp\n"
" rspfile_content = C$:/python/python.exe ../../foo/script.py -i "
+#if defined(OS_WIN)
"${source} \"--out=foo$ bar${source_name_part}.o\"\n"
+#else
+ "${source} --out=foo\\$ bar${source_name_part}.o\n"
+#endif
"build obj/foo/bar.inputdeps.stamp: stamp ../../foo/script.py "
"../../foo/included.txt\n"
"\n"
@@ -388,10 +372,6 @@ TEST(NinjaActionTargetWriter, ForEachWithDepfile) {
" depfile = gen/input2.d\n"
"\n"
"build obj/foo/bar.stamp: stamp input1.out input2.out\n";
- std::string out_str = out.str();
-#if defined(OS_WIN)
- std::replace(out_str.begin(), out_str.end(), '\\', '/');
-#endif
- EXPECT_EQ(expected_win, out_str);
+ EXPECT_EQ(expected_win, out.str());
}
}
diff --git a/tools/gn/ninja_binary_target_writer.cc b/tools/gn/ninja_binary_target_writer.cc
index 1204d4f473..9cfbdfb4fe 100644
--- a/tools/gn/ninja_binary_target_writer.cc
+++ b/tools/gn/ninja_binary_target_writer.cc
@@ -17,7 +17,7 @@ namespace {
// Returns the proper escape options for writing compiler and linker flags.
EscapeOptions GetFlagOptions() {
EscapeOptions opts;
- opts.mode = ESCAPE_NINJA;
+ opts.mode = ESCAPE_NINJA_COMMAND;
// Some flag strings are actually multiple flags that expect to be just
// added to the command line. We assume that quoting is done by the
@@ -29,7 +29,7 @@ EscapeOptions GetFlagOptions() {
struct DefineWriter {
DefineWriter() {
- options.mode = ESCAPE_SHELL;
+ options.mode = ESCAPE_NINJA_COMMAND;
}
void operator()(const std::string& s, std::ostream& out) const {
@@ -41,33 +41,20 @@ struct DefineWriter {
};
struct IncludeWriter {
- IncludeWriter(PathOutput& path_output,
- const NinjaHelper& h)
+ IncludeWriter(PathOutput& path_output, const NinjaHelper& h)
: helper(h),
- path_output_(path_output),
- old_inhibit_quoting_(path_output.inhibit_quoting()) {
- // Inhibit quoting since we'll put quotes around the whole thing ourselves.
- // Since we're writing in NINJA escaping mode, this won't actually do
- // anything, but I think we may need to change to shell-and-then-ninja
- // escaping for this in the future.
- path_output_.set_inhibit_quoting(true);
+ path_output_(path_output) {
}
~IncludeWriter() {
- path_output_.set_inhibit_quoting(old_inhibit_quoting_);
}
void operator()(const SourceDir& d, std::ostream& out) const {
- out << " \"-I";
- // It's important not to include the trailing slash on directories or on
- // Windows it will be a backslash and the compiler might think we're
- // escaping the quote!
+ out << " -I";
path_output_.WriteDir(out, d, PathOutput::DIR_NO_LAST_SLASH);
- out << "\"";
}
const NinjaHelper& helper;
PathOutput& path_output_;
- bool old_inhibit_quoting_; // So we can put the PathOutput back.
};
Toolchain::ToolType GetToolTypeForTarget(const Target* target) {
@@ -268,8 +255,8 @@ void NinjaBinaryTargetWriter::WriteLinkerFlags(
if (!all_lib_dirs.empty()) {
// Since we're passing these on the command line to the linker and not
// to Ninja, we need to do shell escaping.
- PathOutput lib_path_output(
- path_output_.current_dir(), ESCAPE_NINJA_SHELL, false);
+ PathOutput lib_path_output(path_output_.current_dir(),
+ ESCAPE_NINJA_COMMAND);
for (size_t i = 0; i < all_lib_dirs.size(); i++) {
out_ << " " << tool.lib_dir_prefix;
lib_path_output.WriteDir(out_, all_lib_dirs[i],
@@ -291,7 +278,7 @@ void NinjaBinaryTargetWriter::WriteLibs(const Toolchain::Tool& tool) {
// Libraries that have been recursively pushed through the dependency tree.
EscapeOptions lib_escape_opts;
- lib_escape_opts.mode = ESCAPE_NINJA_SHELL;
+ lib_escape_opts.mode = ESCAPE_NINJA_COMMAND;
const OrderedSet<std::string> all_libs = target_->all_libs();
const std::string framework_ending(".framework");
for (size_t i = 0; i < all_libs.size(); i++) {
@@ -426,14 +413,19 @@ void NinjaBinaryTargetWriter::ClassifyDependency(
target_->output_type() == Target::SHARED_LIBRARY);
if (dep->output_type() == Target::SOURCE_SET) {
- if (target_->output_type() == Target::SOURCE_SET) {
- // When a source set depends on another source set, add it as a data
- // dependency so if the user says "ninja second_source_set" it will
- // also compile the first (what you would expect) even though we'll
- // never do anything with the first one's files.
- non_linkable_deps->push_back(dep);
- } else {
- // Linking in a source set, copy its object files.
+ // Source sets have their object files linked into final targets (shared
+ // libraries and executables). Intermediate static libraries and other
+ // source sets just forward the dependency, otherwise the files in the
+ // source set can easily get linked more than once which will cause
+ // multiple definition errors.
+ //
+ // In the future, we may need a way to specify a "complete" static library
+ // for cases where you want a static library that includes all source sets
+ // (like if you're shipping that to customers to link against).
+ if (target_->output_type() != Target::SOURCE_SET &&
+ target_->output_type() != Target::STATIC_LIBRARY) {
+ // Linking in a source set to an executable or shared library, copy its
+ // object files.
for (size_t i = 0; i < dep->sources().size(); i++) {
SourceFileType input_file_type = GetSourceFileType(dep->sources()[i]);
if (input_file_type != SOURCE_UNKNOWN &&
diff --git a/tools/gn/ninja_binary_target_writer_unittest.cc b/tools/gn/ninja_binary_target_writer_unittest.cc
index 4f120c285f..bcaeae720f 100644
--- a/tools/gn/ninja_binary_target_writer_unittest.cc
+++ b/tools/gn/ninja_binary_target_writer_unittest.cc
@@ -94,6 +94,42 @@ TEST(NinjaBinaryTargetWriter, SourceSet) {
#endif
EXPECT_EQ(expected_win, out_str);
}
+
+ // A static library that depends on the source set (should not link it).
+ Target stlib_target(setup.settings(), Label(SourceDir("//foo/"), "stlib"));
+ stlib_target.set_output_type(Target::STATIC_LIBRARY);
+ stlib_target.deps().push_back(LabelTargetPair(&target));
+ stlib_target.OnResolved();
+
+ {
+ std::ostringstream out;
+ NinjaBinaryTargetWriter writer(&stlib_target, setup.toolchain(), out);
+ writer.Run();
+
+ // TODO(brettw) I think we'll need to worry about backslashes here
+ // depending if we're on actual Windows or Linux pretending to be Windows.
+ const char expected_win[] =
+ "defines =\n"
+ "includes =\n"
+ "cflags =\n"
+ "cflags_c =\n"
+ "cflags_cc =\n"
+ "cflags_objc =\n"
+ "cflags_objcc =\n"
+ "\n"
+ "\n"
+ "manifests = obj/foo/stlib.intermediate.manifest\n"
+ "ldflags = /MANIFEST /ManifestFile:obj/foo/stlib.intermediate.manifest\n"
+ "libs =\n"
+ // There are no sources so there are no params to alink.
+ "build obj/foo/stlib.lib: alink\n\n";
+ std::string out_str = out.str();
+#if defined(OS_WIN)
+ std::replace(out_str.begin(), out_str.end(), '\\', '/');
+#endif
+ EXPECT_EQ(expected_win, out_str);
+ }
+
}
TEST(NinjaBinaryTargetWriter, ProductExtension) {
diff --git a/tools/gn/ninja_build_writer.cc b/tools/gn/ninja_build_writer.cc
index f9039046a7..007089ddf2 100644
--- a/tools/gn/ninja_build_writer.cc
+++ b/tools/gn/ninja_build_writer.cc
@@ -39,7 +39,7 @@ std::string GetSelfInvocationCommand(const BuildSettings* build_settings) {
cmdline.AppendSwitch("-q"); // Don't write output.
EscapeOptions escape_shell;
- escape_shell.mode = ESCAPE_SHELL;
+ escape_shell.mode = ESCAPE_NINJA_COMMAND;
#if defined(OS_WIN)
// The command line code quoting varies by platform. We have one string,
// possibly with spaces, that we want to quote. The Windows command line
@@ -82,7 +82,7 @@ NinjaBuildWriter::NinjaBuildWriter(
default_toolchain_targets_(default_toolchain_targets),
out_(out),
dep_out_(dep_out),
- path_output_(build_settings->build_dir(), ESCAPE_NINJA, false),
+ path_output_(build_settings->build_dir(), ESCAPE_NINJA),
helper_(build_settings) {
}
diff --git a/tools/gn/ninja_target_writer.cc b/tools/gn/ninja_target_writer.cc
index 778e9832b6..d59582e6b9 100644
--- a/tools/gn/ninja_target_writer.cc
+++ b/tools/gn/ninja_target_writer.cc
@@ -26,9 +26,7 @@ NinjaTargetWriter::NinjaTargetWriter(const Target* target,
target_(target),
toolchain_(toolchain),
out_(out),
- path_output_(settings_->build_settings()->build_dir(),
- ESCAPE_NINJA,
- false),
+ path_output_(settings_->build_settings()->build_dir(), ESCAPE_NINJA),
helper_(settings_->build_settings()) {
}
@@ -116,7 +114,8 @@ std::string NinjaTargetWriter::WriteInputDepsStampAndGetDep(
path_output_.WriteFile(stamp_file_stream, input_stamp_file);
std::string stamp_file_string = stamp_file_stream.str();
- out_ << "build " << stamp_file_string << ": stamp";
+ out_ << "build " << stamp_file_string << ": " +
+ helper_.GetRulePrefix(settings_) + "stamp";
// Script file (if applicable).
if (add_script_source_as_dep) {
diff --git a/tools/gn/ninja_toolchain_writer.cc b/tools/gn/ninja_toolchain_writer.cc
index 44d2586241..99087c68f2 100644
--- a/tools/gn/ninja_toolchain_writer.cc
+++ b/tools/gn/ninja_toolchain_writer.cc
@@ -23,9 +23,7 @@ NinjaToolchainWriter::NinjaToolchainWriter(
toolchain_(toolchain),
targets_(targets),
out_(out),
- path_output_(settings_->build_settings()->build_dir(),
- ESCAPE_NINJA,
- false),
+ path_output_(settings_->build_settings()->build_dir(), ESCAPE_NINJA),
helper_(settings->build_settings()) {
}
diff --git a/tools/gn/path_output.cc b/tools/gn/path_output.cc
index 4e71f9bdc9..7e739b6edc 100644
--- a/tools/gn/path_output.cc
+++ b/tools/gn/path_output.cc
@@ -9,9 +9,7 @@
#include "tools/gn/output_file.h"
#include "tools/gn/string_utils.h"
-PathOutput::PathOutput(const SourceDir& current_dir,
- EscapingMode escaping,
- bool convert_slashes)
+PathOutput::PathOutput(const SourceDir& current_dir, EscapingMode escaping)
: current_dir_(current_dir) {
CHECK(current_dir.is_source_absolute())
<< "Currently this only supports writing to output directories inside "
@@ -20,11 +18,6 @@ PathOutput::PathOutput(const SourceDir& current_dir,
inverse_current_dir_ = InvertDir(current_dir_);
options_.mode = escaping;
- options_.convert_slashes = convert_slashes;
- options_.inhibit_quoting = false;
-
- if (convert_slashes)
- ConvertPathToSystem(&inverse_current_dir_);
}
PathOutput::~PathOutput() {
@@ -91,12 +84,9 @@ void PathOutput::WriteFile(std::ostream& out,
void PathOutput::WriteSourceRelativeString(
std::ostream& out,
const base::StringPiece& str) const {
- if (options_.mode == ESCAPE_SHELL) {
+ if (options_.mode == ESCAPE_NINJA_COMMAND) {
// Shell escaping needs an intermediate string since it may end up
- // quoting the whole thing. On Windows, the slashes may already be
- // converted to backslashes in inverse_current_dir_, but we assume that on
- // Windows the escaper won't try to then escape the preconverted
- // backslashes and will just pass them, so this is fine.
+ // quoting the whole thing.
std::string intermediate;
intermediate.reserve(inverse_current_dir_.size() + str.size());
intermediate.assign(inverse_current_dir_.c_str(),
diff --git a/tools/gn/path_output.h b/tools/gn/path_output.h
index 33227d4864..ba4a5f6073 100644
--- a/tools/gn/path_output.h
+++ b/tools/gn/path_output.h
@@ -33,9 +33,7 @@ class PathOutput {
DIR_NO_LAST_SLASH,
};
- PathOutput(const SourceDir& current_dir,
- EscapingMode escaping,
- bool convert_slashes);
+ PathOutput(const SourceDir& current_dir, EscapingMode escaping);
~PathOutput();
// Read-only since inverse_current_dir_ is computed depending on this.
@@ -43,19 +41,10 @@ class PathOutput {
const SourceDir& current_dir() const { return current_dir_; }
- // When true, converts slashes to the system-type path separators (on
- // Windows, this is a backslash, this is a NOP otherwise).
- //
- // Read-only since inverse_current_dir_ is computed depending on this.
- bool convert_slashes_to_system() const { return options_.convert_slashes; }
-
- // When the output escaping is ESCAPE_SHELL, the escaper will normally put
- // quotes around suspect things. If this value is set to true, we'll disable
- // the quoting feature. This means that in ESCAPE_SHELL mode, strings with
- // spaces in them qon't be quoted. This mode is for when quoting is done at
- // some higher-level. Defaults to false.
+ // Getter/setters for flags inside the escape options.
bool inhibit_quoting() const { return options_.inhibit_quoting; }
void set_inhibit_quoting(bool iq) { options_.inhibit_quoting = iq; }
+ void set_escape_platform(EscapingPlatform p) { options_.platform = p; }
void WriteFile(std::ostream& out, const SourceFile& file) const;
void WriteFile(std::ostream& out, const OutputFile& file) const;
diff --git a/tools/gn/path_output_unittest.cc b/tools/gn/path_output_unittest.cc
index 49f29c9a55..389f96a404 100644
--- a/tools/gn/path_output_unittest.cc
+++ b/tools/gn/path_output_unittest.cc
@@ -11,7 +11,7 @@
TEST(PathOutput, Basic) {
SourceDir build_dir("//out/Debug/");
- PathOutput writer(build_dir, ESCAPE_NONE, false);
+ PathOutput writer(build_dir, ESCAPE_NONE);
{
// Normal source-root path.
std::ostringstream out;
@@ -52,7 +52,7 @@ TEST(PathOutput, Basic) {
// Same as basic but the output dir is the root.
TEST(PathOutput, BasicInRoot) {
SourceDir build_dir("//");
- PathOutput writer(build_dir, ESCAPE_NONE, false);
+ PathOutput writer(build_dir, ESCAPE_NONE);
{
// Normal source-root path.
std::ostringstream out;
@@ -69,7 +69,7 @@ TEST(PathOutput, BasicInRoot) {
TEST(PathOutput, NinjaEscaping) {
SourceDir build_dir("//out/Debug/");
- PathOutput writer(build_dir, ESCAPE_NINJA, false);
+ PathOutput writer(build_dir, ESCAPE_NINJA);
{
// Spaces and $ in filenames.
std::ostringstream out;
@@ -84,63 +84,85 @@ TEST(PathOutput, NinjaEscaping) {
}
}
-TEST(PathOutput, ShellEscaping) {
+TEST(PathOutput, NinjaForkEscaping) {
SourceDir build_dir("//out/Debug/");
- PathOutput writer(build_dir, ESCAPE_SHELL, false);
+ PathOutput writer(build_dir, ESCAPE_NINJA_COMMAND);
+
+ // Spaces in filenames should get quoted on Windows.
+ writer.set_escape_platform(ESCAPE_PLATFORM_WIN);
{
- // Spaces in filenames should get quoted.
std::ostringstream out;
writer.WriteFile(out, SourceFile("//foo/foo bar.cc"));
- EXPECT_EQ("\"../../foo/foo bar.cc\"", out.str());
+ EXPECT_EQ("\"../../foo/foo$ bar.cc\"", out.str());
+ }
+
+ // Spaces in filenames should get escaped on Posix.
+ writer.set_escape_platform(ESCAPE_PLATFORM_POSIX);
+ {
+ std::ostringstream out;
+ writer.WriteFile(out, SourceFile("//foo/foo bar.cc"));
+ EXPECT_EQ("../../foo/foo\\$ bar.cc", out.str());
+ }
+
+ // Quotes should get blackslash-escaped on Windows and Posix.
+ writer.set_escape_platform(ESCAPE_PLATFORM_WIN);
+ {
+ std::ostringstream out;
+ writer.WriteFile(out, SourceFile("//foo/\"foobar\".cc"));
+ // Our Windows code currently quotes the whole thing in this case for
+ // code simplicity, even though it's strictly unnecessary. This might
+ // change in the future.
+ EXPECT_EQ("\"../../foo/\\\"foobar\\\".cc\"", out.str());
}
+ writer.set_escape_platform(ESCAPE_PLATFORM_POSIX);
{
- // Quotes should get blackslash-escaped.
std::ostringstream out;
writer.WriteFile(out, SourceFile("//foo/\"foobar\".cc"));
EXPECT_EQ("../../foo/\\\"foobar\\\".cc", out.str());
}
+
+
+ // Backslashes should get escaped on non-Windows and preserved on Windows.
+ writer.set_escape_platform(ESCAPE_PLATFORM_WIN);
{
- // Backslashes should get escaped on non-Windows and preserved on Windows.
std::ostringstream out;
writer.WriteFile(out, SourceFile("//foo\\bar.cc"));
-#if defined(OS_WIN)
EXPECT_EQ("../../foo\\bar.cc", out.str());
-#else
- EXPECT_EQ("../../foo\\\\bar.cc", out.str());
-#endif
}
-}
-
-TEST(PathOutput, SlashConversion) {
- SourceDir build_dir("//out/Debug/");
- PathOutput writer(build_dir, ESCAPE_NINJA, true);
+ writer.set_escape_platform(ESCAPE_PLATFORM_POSIX);
{
std::ostringstream out;
- writer.WriteFile(out, SourceFile("//foo/bar.cc"));
-#if defined(OS_WIN)
- EXPECT_EQ("..\\..\\foo\\bar.cc", out.str());
-#else
- EXPECT_EQ("../../foo/bar.cc", out.str());
-#endif
+ writer.WriteFile(out, SourceFile("//foo\\bar.cc"));
+ EXPECT_EQ("../../foo\\\\bar.cc", out.str());
}
}
TEST(PathOutput, InhibitQuoting) {
SourceDir build_dir("//out/Debug/");
- PathOutput writer(build_dir, ESCAPE_SHELL, false);
+ PathOutput writer(build_dir, ESCAPE_NINJA_COMMAND);
writer.set_inhibit_quoting(true);
+
+ writer.set_escape_platform(ESCAPE_PLATFORM_WIN);
{
// We should get unescaped spaces in the output with no quotes.
std::ostringstream out;
writer.WriteFile(out, SourceFile("//foo/foo bar.cc"));
- EXPECT_EQ("../../foo/foo bar.cc", out.str());
+ EXPECT_EQ("../../foo/foo$ bar.cc", out.str());
+ }
+
+ writer.set_escape_platform(ESCAPE_PLATFORM_POSIX);
+ {
+ // Escapes the space.
+ std::ostringstream out;
+ writer.WriteFile(out, SourceFile("//foo/foo bar.cc"));
+ EXPECT_EQ("../../foo/foo\\$ bar.cc", out.str());
}
}
TEST(PathOutput, WriteDir) {
{
SourceDir build_dir("//out/Debug/");
- PathOutput writer(build_dir, ESCAPE_NINJA, false);
+ PathOutput writer(build_dir, ESCAPE_NINJA);
{
std::ostringstream out;
writer.WriteDir(out, SourceDir("//foo/bar/"),
@@ -191,6 +213,8 @@ TEST(PathOutput, WriteDir) {
// Output inside current dir.
{
std::ostringstream out;
+
+
writer.WriteDir(out, SourceDir("//out/Debug/"),
PathOutput::DIR_INCLUDE_LAST_SLASH);
EXPECT_EQ("./", out.str());
@@ -216,7 +240,7 @@ TEST(PathOutput, WriteDir) {
}
{
// Empty build dir writer.
- PathOutput root_writer(SourceDir("//"), ESCAPE_NINJA, false);
+ PathOutput root_writer(SourceDir("//"), ESCAPE_NINJA);
{
std::ostringstream out;
root_writer.WriteDir(out, SourceDir("//"),
diff --git a/tools/gn/run_all_unittests.cc b/tools/gn/run_all_unittests.cc
new file mode 100644
index 0000000000..edd80fed5d
--- /dev/null
+++ b/tools/gn/run_all_unittests.cc
@@ -0,0 +1,13 @@
+// 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.
+
+#include "base/bind.h"
+#include "base/test/test_suite.h"
+
+// Don't use the multiprocess test harness. This test suite is fast enough and
+// it makes the output more difficult to read.
+int main(int argc, char** argv) {
+ base::TestSuite test_suite(argc, argv);
+ return test_suite.Run();
+}
diff --git a/tools/gn/secondary/chrome/BUILD.gn b/tools/gn/secondary/chrome/BUILD.gn
index c9a7278956..aaff67facd 100644
--- a/tools/gn/secondary/chrome/BUILD.gn
+++ b/tools/gn/secondary/chrome/BUILD.gn
@@ -122,6 +122,12 @@ source_set("debugger") {
"browser/devtools/devtools_file_helper.h",
"browser/devtools/devtools_file_system_indexer.cc",
"browser/devtools/devtools_file_system_indexer.h",
+ "browser/devtools/devtools_network_controller.cpp",
+ "browser/devtools/devtools_network_controller.h",
+ "browser/devtools/devtools_network_transaction.cpp",
+ "browser/devtools/devtools_network_transaction.h",
+ "browser/devtools/devtools_network_transaction_factory.cpp",
+ "browser/devtools/devtools_network_transaction_factory.h",
"browser/devtools/devtools_protocol.cc",
"browser/devtools/devtools_protocol.h",
"browser/devtools/devtools_toggle_action.h",
diff --git a/tools/gn/secondary/sdch/BUILD.gn b/tools/gn/secondary/sdch/BUILD.gn
deleted file mode 100644
index 73f3afb8d7..0000000000
--- a/tools/gn/secondary/sdch/BUILD.gn
+++ /dev/null
@@ -1,62 +0,0 @@
-# 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.
-
-config("sdch_config") {
- include_dirs = [ "open-vcdiff/src" ]
-}
-
-static_library("sdch") {
- sources = [
- "open-vcdiff/src/addrcache.cc",
- "open-vcdiff/src/blockhash.cc",
- "open-vcdiff/src/blockhash.h",
- "open-vcdiff/src/checksum.h",
- "open-vcdiff/src/codetable.cc",
- "open-vcdiff/src/codetable.h",
- "open-vcdiff/src/compile_assert.h",
- "open-vcdiff/src/decodetable.cc",
- "open-vcdiff/src/decodetable.h",
- "open-vcdiff/src/encodetable.cc",
- "open-vcdiff/src/encodetable.h",
- "open-vcdiff/src/google/output_string.h",
- "open-vcdiff/src/google/vcdecoder.h",
- "open-vcdiff/src/headerparser.cc",
- "open-vcdiff/src/headerparser.h",
- "open-vcdiff/src/instruction_map.cc",
- "open-vcdiff/src/instruction_map.h",
- "open-vcdiff/src/logging.cc",
- "open-vcdiff/src/logging.h",
- "open-vcdiff/src/rolling_hash.h",
- "open-vcdiff/src/testing.h",
- "open-vcdiff/src/varint_bigendian.cc",
- "open-vcdiff/src/varint_bigendian.h",
- "open-vcdiff/src/vcdecoder.cc",
- "open-vcdiff/src/vcdiff_defs.h",
- "open-vcdiff/src/vcdiffengine.cc",
- "open-vcdiff/src/vcdiffengine.h",
- "open-vcdiff/vsprojects/config.h",
- "open-vcdiff/vsprojects/stdint.h",
- ]
-
- direct_dependent_configs = [ ":sdch_config" ]
-
- if (is_linux || is_android) {
- include_dirs = [ "linux" ]
- } else if (is_ios) {
- include_dirs = [ "ios" ]
- } else if (is_mac) {
- include_dirs = [ "mac" ]
- } else if (is_win) {
- include_dirs = [ "win" ]
- }
-
- deps = [ "//third_party/zlib" ]
-
- if (is_clang) {
- cflags = [
- # TODO(mostynb): remove this if open-vcdiff is ever updated for c++11:
- "-Wno-deprecated-declarations",
- ]
- }
-}
diff --git a/tools/gn/secondary/testing/BUILD.gn b/tools/gn/secondary/testing/BUILD.gn
new file mode 100644
index 0000000000..2cafa68a28
--- /dev/null
+++ b/tools/gn/secondary/testing/BUILD.gn
@@ -0,0 +1,11 @@
+# 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.
+
+source_set("gmock_mutant") {
+ sources = [
+ "gmock_mutant.h", # gMock helpers
+ ]
+
+ deps = [ "//base" ]
+}
diff --git a/tools/gn/secondary/testing/gmock/BUILD.gn b/tools/gn/secondary/testing/gmock/BUILD.gn
index 8b5f8dbeb9..e682abf58b 100644
--- a/tools/gn/secondary/testing/gmock/BUILD.gn
+++ b/tools/gn/secondary/testing/gmock/BUILD.gn
@@ -28,7 +28,6 @@ static_library("gmock") {
"src/gmock-matchers.cc",
"src/gmock-spec-builders.cc",
"src/gmock.cc",
- "../gmock_mutant.h", # gMock helpers
]
# This project includes some stuff form gtest's guts.
@@ -38,8 +37,6 @@ static_library("gmock") {
":gmock_config",
"//testing/gtest:gtest_config",
]
-
- deps = [ "//base" ]
}
static_library("gmock_main") {
diff --git a/tools/gn/secondary/third_party/angle/BUILD.gn b/tools/gn/secondary/third_party/angle/BUILD.gn
index ec3fd6b289..651d42f7ae 100644
--- a/tools/gn/secondary/third_party/angle/BUILD.gn
+++ b/tools/gn/secondary/third_party/angle/BUILD.gn
@@ -568,7 +568,7 @@ if (is_win) {
]
if (is_debug) {
- defines += [ "ANGLE_ENABLE_PERF" ]
+ defines = [ "ANGLE_ENABLE_PERF" ]
}
include_dirs = [ "src/libGLESv2" ]
diff --git a/tools/gn/secondary/third_party/icu/BUILD.gn b/tools/gn/secondary/third_party/icu/BUILD.gn
index 21c4efa714..df268cb145 100644
--- a/tools/gn/secondary/third_party/icu/BUILD.gn
+++ b/tools/gn/secondary/third_party/icu/BUILD.gn
@@ -16,6 +16,11 @@ config("icu_config") {
defines = [
"U_USING_ICU_NAMESPACE=0",
]
+
+ if (component_mode != "shared_library") {
+ defines += [ "U_STATIC_IMPLEMENTATION" ]
+ }
+
include_dirs = [
"source/common",
"source/i18n",
@@ -24,10 +29,6 @@ config("icu_config") {
# Config used only by ICU code.
config("icu_code") {
- if (component_mode == "static_library") {
- defines = [ "U_STATIC_IMPLEMENTATION" ]
- }
-
if (is_win) {
# Disable some compiler warnings.
cflags = [
@@ -426,7 +427,7 @@ if (is_win) {
outputs = [ "$root_out_dir/icudt.dll" ]
}
} else {
- static_library("icudata") {
+ source_set("icudata") {
sources = [
# These are hand-generated, but will do for now. The linux version is an
# identical copy of the (mac) icudt46l_dat.S file, modulo removal of the
diff --git a/tools/gn/secondary/third_party/nss/BUILD.gn b/tools/gn/secondary/third_party/nss/BUILD.gn
index 6ce1d2fd96..a0c1674585 100644
--- a/tools/gn/secondary/third_party/nss/BUILD.gn
+++ b/tools/gn/secondary/third_party/nss/BUILD.gn
@@ -356,7 +356,7 @@ if (is_linux) {
if (component_mode == "shared_library") {
if (is_mac) {
- cflags = [ "-all_load" ]
+ ldflags = [ "-all_load" ]
} else if (is_win) {
# Pass the def file to the linker.
ldflags = [ rebase_path("nss/exports_win.def", root_build_dir) ]
@@ -1090,10 +1090,6 @@ if (is_linux) {
}
if (is_win) {
- sources -= [
- "nss/lib/freebl/mpi/mpi_amd64.c",
- "nss/lib/freebl/mpi/mpi_x86_asm.c",
- ]
defines += [
"SHLIB_SUFFIX=\"dll\"",
"SHLIB_PREFIX=\"\"",
@@ -1104,6 +1100,7 @@ if (is_linux) {
]
if (cpu_arch == "x86") {
+ sources -= [ "nss/lib/freebl/mpi/mpi_amd64.c" ]
defines += [
"NSS_X86_OR_X64",
"NSS_X86",
@@ -1115,6 +1112,7 @@ if (is_linux) {
"MP_NO_MP_WORD",
]
} else if (cpu_arch == "x64") {
+ sources -= [ "nss/lib/freebl/mpi/mpi_x86_asm.c" ]
defines += [
"NSS_USE_64",
"NSS_X86_OR_X64",
diff --git a/tools/gn/secondary/tools/grit/grit_rule.gni b/tools/gn/secondary/tools/grit/grit_rule.gni
index 31307e4184..c3e0a5c41a 100644
--- a/tools/gn/secondary/tools/grit/grit_rule.gni
+++ b/tools/gn/secondary/tools/grit/grit_rule.gni
@@ -12,6 +12,28 @@
# # You can also put deps here if the grit source depends on generated
# # files.
# }
+import ("//build/config/ui.gni")
+
+grit_defines = []
+
+if (is_chromeos) {
+ grit_defines += [
+ "-D", "chromeos",
+ "-D", "scale_factors=2x"
+ ]
+}
+
+if (is_desktop_linux) {
+ grit_defines += [ "-D", "desktop_linux" ]
+}
+
+if (is_android) {
+ grit_defines += [
+ "-t", "android",
+ "-E", "ANDROID_JAVA_TAGGED_ONLY=true",
+ ]
+}
+
template("grit") {
assert(defined(invoker.source),
"\"source\" must be defined for the grit template $target_name")
@@ -70,12 +92,11 @@ template("grit") {
source_prereqs = grit_inputs
outputs = grit_outputs
- # TODO(brettw) grit_defines.
args = [
"-i", source_path, "build",
"-f", resource_ids,
"-o", output_dir,
- ] + grit_flags
+ ] + grit_defines + grit_flags
visibility = target_visibility
}
diff --git a/tools/gn/target.cc b/tools/gn/target.cc
index 9bfae3593c..2ddbde91cf 100644
--- a/tools/gn/target.cc
+++ b/tools/gn/target.cc
@@ -177,13 +177,8 @@ void Target::PullDependentTargetInfo(std::set<const Config*>* unique_configs) {
dep->output_type() != EXECUTABLE) {
const std::set<const Target*> inherited = dep->inherited_libraries();
for (std::set<const Target*>::const_iterator i = inherited.begin();
- i != inherited.end(); ++i) {
- // Don't copy source sets across static library boundaries. The static
- // library will include all the files from the source set.
- if (!(dep->output_type() == STATIC_LIBRARY &&
- (*i)->output_type() == SOURCE_SET))
- inherited_libraries_.insert(*i);
- }
+ i != inherited.end(); ++i)
+ inherited_libraries_.insert(*i);
// Inherited library settings.
all_lib_dirs_.append(dep->all_lib_dirs());
diff --git a/tools/gn/target_unittest.cc b/tools/gn/target_unittest.cc
index 6219374c94..f9a1f972a4 100644
--- a/tools/gn/target_unittest.cc
+++ b/tools/gn/target_unittest.cc
@@ -225,15 +225,14 @@ TEST_F(TargetTest, InheritLibs) {
EXPECT_EQ(1u, c_inherited.size());
EXPECT_TRUE(c_inherited.find(&d) != c_inherited.end());
- // B should have C in its inherited libs, but not D (the static library will
- // include the source sets's code).
+ // B should have C and D in its inherited libs.
const std::set<const Target*>& b_inherited = b.inherited_libraries();
- EXPECT_EQ(1u, b_inherited.size());
+ EXPECT_EQ(2u, b_inherited.size());
EXPECT_TRUE(b_inherited.find(&c) != b_inherited.end());
+ EXPECT_TRUE(b_inherited.find(&d) != b_inherited.end());
// A should have B in its inherited libs, but not any others (the shared
- // library will include the static library, which will include the source
- // set).
+ // library will include the static library and source set).
const std::set<const Target*>& a_inherited = a.inherited_libraries();
EXPECT_EQ(1u, a_inherited.size());
EXPECT_TRUE(a_inherited.find(&b) != a_inherited.end());
diff --git a/tools/gn/visibility.cc b/tools/gn/visibility.cc
index 41bfc63f41..6fc8fa125d 100644
--- a/tools/gn/visibility.cc
+++ b/tools/gn/visibility.cc
@@ -97,28 +97,40 @@ bool Visibility::CanSeeMe(const Label& label) const {
return false;
}
-std::string Visibility::Describe() const {
+std::string Visibility::Describe(int indent, bool include_brackets) const {
+ std::string outer_indent_string(indent, ' ');
+
if (patterns_.empty())
- return std::string("[] (no visibility)");
- std::string result = "[\n";
+ return outer_indent_string + "[] (no visibility)\n";
+
+ std::string result;
+
+ std::string inner_indent_string = outer_indent_string;
+ if (include_brackets) {
+ result += outer_indent_string + "[\n";
+ // Indent the insides more if brackets are requested.
+ inner_indent_string += " ";
+ }
for (size_t i = 0; i < patterns_.size(); i++) {
switch (patterns_[i].type()) {
case VisPattern::MATCH:
- result += " " + patterns_[i].dir().value() + ":" +
+ result += inner_indent_string +
+ DirectoryWithNoLastSlash(patterns_[i].dir()) + ":" +
patterns_[i].name() + "\n";
break;
case VisPattern::DIRECTORY:
- result += " " + DirectoryWithNoLastSlash(patterns_[i].dir()) +
- ":*\n";
+ result += inner_indent_string +
+ DirectoryWithNoLastSlash(patterns_[i].dir()) + ":*\n";
break;
case VisPattern::RECURSIVE_DIRECTORY:
- result += " " + patterns_[i].dir().value() + "*\n";
+ result += inner_indent_string + patterns_[i].dir().value() + "*\n";
break;
}
}
- result += "]";
+ if (include_brackets)
+ result += outer_indent_string + "]\n";
return result;
}
@@ -244,7 +256,7 @@ bool Visibility::CheckItemVisibility(const Item* from,
"The item " + from->label().GetUserVisibleName(false) + "\n"
"can not depend on " + to_label + "\n"
"because it is not in " + to_label + "'s visibility list: " +
- to->visibility().Describe());
+ to->visibility().Describe(0, true));
return false;
}
return true;
diff --git a/tools/gn/visibility.h b/tools/gn/visibility.h
index 52ec73ca15..7ce2b7845f 100644
--- a/tools/gn/visibility.h
+++ b/tools/gn/visibility.h
@@ -68,8 +68,11 @@ class Visibility {
// current visibility.
bool CanSeeMe(const Label& label) const;
- // Returns a string listing the visibility.
- std::string Describe() const;
+ // Returns a string listing the visibility. |indent| number of spaces will
+ // be added on the left side of the output. If |include_brackets| is set, the
+ // result will be wrapped in "[ ]" and the contents further indented. The
+ // result will end in a newline.
+ std::string Describe(int indent, bool include_brackets) const;
// Converts the given input string to a pattern. This does special stuff
// to treat the pattern as a label. Sets the error on failure.
diff --git a/tools/gritsettings/resource_ids b/tools/gritsettings/resource_ids
index 45eb5a4d6b..21d8a69685 100644
--- a/tools/gritsettings/resource_ids
+++ b/tools/gritsettings/resource_ids
@@ -163,10 +163,13 @@
"messages": [26000],
},
"chrome/common/extensions_api_resources.grd": {
- "includes": [26500],
+ "includes": [26400],
},
"extensions/extensions_resources.grd": {
- "includes": [26750],
+ "includes": [26600],
+ },
+ "extensions/renderer/resources/extensions_renderer_resources.grd": {
+ "includes": [26800],
},
"extensions/extensions_strings.grd": {
"messages": [27000],
diff --git a/tools/gypv8sh.py b/tools/gypv8sh.py
index 5c93e51bf7..b8bd4066ec 100755
--- a/tools/gypv8sh.py
+++ b/tools/gypv8sh.py
@@ -5,10 +5,6 @@
"""This script is used by chrome_tests.gypi's js2webui action to maintain the
argument lists and to generate inlinable tests.
-
-Usage:
- python tools/gypv8sh.py v8_shell mock.js test_api.js js2webui.js \
- inputfile inputrelfile cxxoutfile jsoutfile
"""
import json
@@ -22,24 +18,28 @@ import shutil
def main ():
parser = optparse.OptionParser()
parser.set_usage(
- "%prog v8_shell mock.js axs_testing.js test_api.js js2webui.js "
+ "%prog v8_shell mock.js test_api.js js2webui.js "
"testtype inputfile inputrelfile cxxoutfile jsoutfile")
parser.add_option('-v', '--verbose', action='store_true')
parser.add_option('-n', '--impotent', action='store_true',
help="don't execute; just print (as if verbose)")
+ parser.add_option('--deps_js', action="store",
+ help=("Path to deps.js for dependency resolution, " +
+ "optional."))
(opts, args) = parser.parse_args()
- if len(args) != 10:
+ if len(args) != 9:
parser.error('all arguments are required.')
- (v8_shell, mock_js, axs_testing_js, test_api, js2webui, test_type,
+ (v8_shell, mock_js, test_api, js2webui, test_type,
inputfile, inputrelfile, cxxoutfile, jsoutfile) = args
cmd = [v8_shell]
icudatafile = os.path.join(os.path.dirname(v8_shell), 'icudtl.dat')
if os.path.exists(icudatafile):
cmd.extend(['--icu-data-file=%s' % icudatafile])
- arguments = [js2webui, inputfile, inputrelfile, cxxoutfile, test_type]
+ arguments = [js2webui, inputfile, inputrelfile, opts.deps_js,
+ cxxoutfile, test_type]
cmd.extend(['-e', "arguments=" + json.dumps(arguments), mock_js,
- axs_testing_js, test_api, js2webui])
+ test_api, js2webui])
if opts.verbose or opts.impotent:
print cmd
if not opts.impotent:
diff --git a/tools/ipc_fuzzer/mutate/generate.cc b/tools/ipc_fuzzer/mutate/generate.cc
index 9ed43b78dc..d741b7f3ac 100644
--- a/tools/ipc_fuzzer/mutate/generate.cc
+++ b/tools/ipc_fuzzer/mutate/generate.cc
@@ -515,19 +515,6 @@ struct GenerateTraits<base::TimeTicks> {
};
template <>
-struct GenerateTraits<base::PlatformFileInfo> {
- static bool Generate(base::PlatformFileInfo* p, Generator* generator) {
- return
- GenerateParam(&p->size, generator) &&
- GenerateParam(&p->is_directory, generator) &&
- GenerateParam(&p->last_modified, generator) &&
- GenerateParam(&p->last_accessed, generator) &&
- GenerateParam(&p->creation_time, generator);
- }
-};
-
-
-template <>
struct GenerateTraits<base::ListValue> {
static bool Generate(base::ListValue* p, Generator* generator) {
++g_depth;
diff --git a/tools/ipc_fuzzer/replay/replay_process.cc b/tools/ipc_fuzzer/replay/replay_process.cc
index b141cd0029..1e6f4c28c5 100644
--- a/tools/ipc_fuzzer/replay/replay_process.cc
+++ b/tools/ipc_fuzzer/replay/replay_process.cc
@@ -55,11 +55,10 @@ void ReplayProcess::OpenChannel() {
CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kProcessChannelID);
- channel_.reset(
- new IPC::ChannelProxy(channel_name,
- IPC::Channel::MODE_CLIENT,
- this,
- io_thread_.message_loop_proxy()));
+ channel_ = IPC::ChannelProxy::Create(channel_name,
+ IPC::Channel::MODE_CLIENT,
+ this,
+ io_thread_.message_loop_proxy());
}
bool ReplayProcess::OpenTestcase() {
diff --git a/tools/isolate_driver.py b/tools/isolate_driver.py
index 4db823e444..192de2cb83 100755
--- a/tools/isolate_driver.py
+++ b/tools/isolate_driver.py
@@ -113,8 +113,9 @@ def using_blacklist(item):
this list. This is simply an optimization.
"""
IGNORED = (
- '.a', '.cc', '.css', '.def', '.h', '.html', '.js', '.json', '.manifest',
- '.o', '.obj', '.pak', '.png', '.pdb', '.strings', '.txt',
+ '.a', '.cc', '.css', '.def', '.frag', '.h', '.html', '.js', '.json',
+ '.manifest', '.o', '.obj', '.pak', '.png', '.pdb', '.strings', '.test',
+ '.txt', '.vert',
)
# ninja files use native path format.
ext = os.path.splitext(item)[1]
@@ -138,31 +139,26 @@ def raw_build_to_deps(item):
return filter(using_blacklist, item.split(' ')[1:])
-def recurse(target, build_steps, rules_seen):
- """Recursively returns all the interesting dependencies for root_item."""
- out = []
+def collect_deps(target, build_steps, dependencies_added, rules_seen):
+ """Recursively adds all the interesting dependencies for |target|
+ into |dependencies_added|.
+ """
if rules_seen is None:
rules_seen = set()
if target in rules_seen:
# TODO(maruel): Figure out how it happens.
logging.warning('Circular dependency for %s!', target)
- return []
+ return
rules_seen.add(target)
try:
dependencies = raw_build_to_deps(build_steps[target])
except KeyError:
logging.info('Failed to find a build step to generate: %s', target)
- return []
- logging.debug('recurse(%s) -> %s', target, dependencies)
+ return
+ logging.debug('collect_deps(%s) -> %s', target, dependencies)
for dependency in dependencies:
- out.append(dependency)
- dependency_raw_dependencies = build_steps.get(dependency)
- if dependency_raw_dependencies:
- for i in raw_build_to_deps(dependency_raw_dependencies):
- out.extend(recurse(i, build_steps, rules_seen))
- else:
- logging.info('Failed to find a build step to generate: %s', dependency)
- return out
+ dependencies_added.add(dependency)
+ collect_deps(dependency, build_steps, dependencies_added, rules_seen)
def post_process_deps(build_dir, dependencies):
@@ -219,7 +215,9 @@ def create_wrapper(args, isolate_index, isolated_index):
# complain to maruel@.
target = isolate[:-len('.isolate')] + '_run'
build_steps = load_ninja(build_dir)
- binary_deps = post_process_deps(build_dir, recurse(target, build_steps, None))
+ binary_deps = set()
+ collect_deps(target, build_steps, binary_deps, None)
+ binary_deps = post_process_deps(build_dir, binary_deps)
logging.debug(
'Binary dependencies:%s', ''.join('\n ' + i for i in binary_deps))
diff --git a/tools/json_schema_compiler/api_gen_util.target.darwin-arm.mk b/tools/json_schema_compiler/api_gen_util.target.darwin-arm.mk
index 09950a8eab..ab912d72d6 100644
--- a/tools/json_schema_compiler/api_gen_util.target.darwin-arm.mk
+++ b/tools/json_schema_compiler/api_gen_util.target.darwin-arm.mk
@@ -79,7 +79,6 @@ MY_DEFS_Debug := \
'-DENABLE_WEBRTC=1' \
'-DUSE_PROPRIETARY_CODECS' \
'-DENABLE_CONFIGURATION_POLICY' \
- '-DENABLE_NEW_GAMEPAD_API=1' \
'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
'-DENABLE_EGLIMAGE=1' \
@@ -177,7 +176,6 @@ MY_DEFS_Release := \
'-DENABLE_WEBRTC=1' \
'-DUSE_PROPRIETARY_CODECS' \
'-DENABLE_CONFIGURATION_POLICY' \
- '-DENABLE_NEW_GAMEPAD_API=1' \
'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
'-DENABLE_EGLIMAGE=1' \
diff --git a/tools/json_schema_compiler/api_gen_util.target.darwin-arm64.mk b/tools/json_schema_compiler/api_gen_util.target.darwin-arm64.mk
index 02dccb89b6..18cafcd952 100644
--- a/tools/json_schema_compiler/api_gen_util.target.darwin-arm64.mk
+++ b/tools/json_schema_compiler/api_gen_util.target.darwin-arm64.mk
@@ -69,7 +69,6 @@ MY_DEFS_Debug := \
'-DENABLE_WEBRTC=1' \
'-DUSE_PROPRIETARY_CODECS' \
'-DENABLE_CONFIGURATION_POLICY' \
- '-DENABLE_NEW_GAMEPAD_API=1' \
'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
'-DENABLE_EGLIMAGE=1' \
@@ -156,7 +155,6 @@ MY_DEFS_Release := \
'-DENABLE_WEBRTC=1' \
'-DUSE_PROPRIETARY_CODECS' \
'-DENABLE_CONFIGURATION_POLICY' \
- '-DENABLE_NEW_GAMEPAD_API=1' \
'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
'-DENABLE_EGLIMAGE=1' \
diff --git a/tools/json_schema_compiler/api_gen_util.target.darwin-mips.mk b/tools/json_schema_compiler/api_gen_util.target.darwin-mips.mk
index 4270b14a26..80470fd453 100644
--- a/tools/json_schema_compiler/api_gen_util.target.darwin-mips.mk
+++ b/tools/json_schema_compiler/api_gen_util.target.darwin-mips.mk
@@ -73,7 +73,6 @@ MY_DEFS_Debug := \
'-DENABLE_WEBRTC=1' \
'-DUSE_PROPRIETARY_CODECS' \
'-DENABLE_CONFIGURATION_POLICY' \
- '-DENABLE_NEW_GAMEPAD_API=1' \
'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
'-DENABLE_EGLIMAGE=1' \
@@ -165,7 +164,6 @@ MY_DEFS_Release := \
'-DENABLE_WEBRTC=1' \
'-DUSE_PROPRIETARY_CODECS' \
'-DENABLE_CONFIGURATION_POLICY' \
- '-DENABLE_NEW_GAMEPAD_API=1' \
'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
'-DENABLE_EGLIMAGE=1' \
diff --git a/tools/json_schema_compiler/api_gen_util.target.darwin-x86.mk b/tools/json_schema_compiler/api_gen_util.target.darwin-x86.mk
index 8b45aacf61..b6d95e70e9 100644
--- a/tools/json_schema_compiler/api_gen_util.target.darwin-x86.mk
+++ b/tools/json_schema_compiler/api_gen_util.target.darwin-x86.mk
@@ -74,7 +74,6 @@ MY_DEFS_Debug := \
'-DENABLE_WEBRTC=1' \
'-DUSE_PROPRIETARY_CODECS' \
'-DENABLE_CONFIGURATION_POLICY' \
- '-DENABLE_NEW_GAMEPAD_API=1' \
'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
'-DENABLE_EGLIMAGE=1' \
@@ -166,7 +165,6 @@ MY_DEFS_Release := \
'-DENABLE_WEBRTC=1' \
'-DUSE_PROPRIETARY_CODECS' \
'-DENABLE_CONFIGURATION_POLICY' \
- '-DENABLE_NEW_GAMEPAD_API=1' \
'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
'-DENABLE_EGLIMAGE=1' \
diff --git a/tools/json_schema_compiler/api_gen_util.target.darwin-x86_64.mk b/tools/json_schema_compiler/api_gen_util.target.darwin-x86_64.mk
index 6ee3f8c374..d647d70903 100644
--- a/tools/json_schema_compiler/api_gen_util.target.darwin-x86_64.mk
+++ b/tools/json_schema_compiler/api_gen_util.target.darwin-x86_64.mk
@@ -73,7 +73,6 @@ MY_DEFS_Debug := \
'-DENABLE_WEBRTC=1' \
'-DUSE_PROPRIETARY_CODECS' \
'-DENABLE_CONFIGURATION_POLICY' \
- '-DENABLE_NEW_GAMEPAD_API=1' \
'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
'-DENABLE_EGLIMAGE=1' \
@@ -164,7 +163,6 @@ MY_DEFS_Release := \
'-DENABLE_WEBRTC=1' \
'-DUSE_PROPRIETARY_CODECS' \
'-DENABLE_CONFIGURATION_POLICY' \
- '-DENABLE_NEW_GAMEPAD_API=1' \
'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
'-DENABLE_EGLIMAGE=1' \
diff --git a/tools/json_schema_compiler/api_gen_util.target.linux-arm.mk b/tools/json_schema_compiler/api_gen_util.target.linux-arm.mk
index 09950a8eab..ab912d72d6 100644
--- a/tools/json_schema_compiler/api_gen_util.target.linux-arm.mk
+++ b/tools/json_schema_compiler/api_gen_util.target.linux-arm.mk
@@ -79,7 +79,6 @@ MY_DEFS_Debug := \
'-DENABLE_WEBRTC=1' \
'-DUSE_PROPRIETARY_CODECS' \
'-DENABLE_CONFIGURATION_POLICY' \
- '-DENABLE_NEW_GAMEPAD_API=1' \
'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
'-DENABLE_EGLIMAGE=1' \
@@ -177,7 +176,6 @@ MY_DEFS_Release := \
'-DENABLE_WEBRTC=1' \
'-DUSE_PROPRIETARY_CODECS' \
'-DENABLE_CONFIGURATION_POLICY' \
- '-DENABLE_NEW_GAMEPAD_API=1' \
'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
'-DENABLE_EGLIMAGE=1' \
diff --git a/tools/json_schema_compiler/api_gen_util.target.linux-arm64.mk b/tools/json_schema_compiler/api_gen_util.target.linux-arm64.mk
index 02dccb89b6..18cafcd952 100644
--- a/tools/json_schema_compiler/api_gen_util.target.linux-arm64.mk
+++ b/tools/json_schema_compiler/api_gen_util.target.linux-arm64.mk
@@ -69,7 +69,6 @@ MY_DEFS_Debug := \
'-DENABLE_WEBRTC=1' \
'-DUSE_PROPRIETARY_CODECS' \
'-DENABLE_CONFIGURATION_POLICY' \
- '-DENABLE_NEW_GAMEPAD_API=1' \
'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
'-DENABLE_EGLIMAGE=1' \
@@ -156,7 +155,6 @@ MY_DEFS_Release := \
'-DENABLE_WEBRTC=1' \
'-DUSE_PROPRIETARY_CODECS' \
'-DENABLE_CONFIGURATION_POLICY' \
- '-DENABLE_NEW_GAMEPAD_API=1' \
'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
'-DENABLE_EGLIMAGE=1' \
diff --git a/tools/json_schema_compiler/api_gen_util.target.linux-mips.mk b/tools/json_schema_compiler/api_gen_util.target.linux-mips.mk
index 4270b14a26..80470fd453 100644
--- a/tools/json_schema_compiler/api_gen_util.target.linux-mips.mk
+++ b/tools/json_schema_compiler/api_gen_util.target.linux-mips.mk
@@ -73,7 +73,6 @@ MY_DEFS_Debug := \
'-DENABLE_WEBRTC=1' \
'-DUSE_PROPRIETARY_CODECS' \
'-DENABLE_CONFIGURATION_POLICY' \
- '-DENABLE_NEW_GAMEPAD_API=1' \
'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
'-DENABLE_EGLIMAGE=1' \
@@ -165,7 +164,6 @@ MY_DEFS_Release := \
'-DENABLE_WEBRTC=1' \
'-DUSE_PROPRIETARY_CODECS' \
'-DENABLE_CONFIGURATION_POLICY' \
- '-DENABLE_NEW_GAMEPAD_API=1' \
'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
'-DENABLE_EGLIMAGE=1' \
diff --git a/tools/json_schema_compiler/api_gen_util.target.linux-x86.mk b/tools/json_schema_compiler/api_gen_util.target.linux-x86.mk
index 8b45aacf61..b6d95e70e9 100644
--- a/tools/json_schema_compiler/api_gen_util.target.linux-x86.mk
+++ b/tools/json_schema_compiler/api_gen_util.target.linux-x86.mk
@@ -74,7 +74,6 @@ MY_DEFS_Debug := \
'-DENABLE_WEBRTC=1' \
'-DUSE_PROPRIETARY_CODECS' \
'-DENABLE_CONFIGURATION_POLICY' \
- '-DENABLE_NEW_GAMEPAD_API=1' \
'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
'-DENABLE_EGLIMAGE=1' \
@@ -166,7 +165,6 @@ MY_DEFS_Release := \
'-DENABLE_WEBRTC=1' \
'-DUSE_PROPRIETARY_CODECS' \
'-DENABLE_CONFIGURATION_POLICY' \
- '-DENABLE_NEW_GAMEPAD_API=1' \
'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
'-DENABLE_EGLIMAGE=1' \
diff --git a/tools/json_schema_compiler/api_gen_util.target.linux-x86_64.mk b/tools/json_schema_compiler/api_gen_util.target.linux-x86_64.mk
index 6ee3f8c374..d647d70903 100644
--- a/tools/json_schema_compiler/api_gen_util.target.linux-x86_64.mk
+++ b/tools/json_schema_compiler/api_gen_util.target.linux-x86_64.mk
@@ -73,7 +73,6 @@ MY_DEFS_Debug := \
'-DENABLE_WEBRTC=1' \
'-DUSE_PROPRIETARY_CODECS' \
'-DENABLE_CONFIGURATION_POLICY' \
- '-DENABLE_NEW_GAMEPAD_API=1' \
'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
'-DENABLE_EGLIMAGE=1' \
@@ -164,7 +163,6 @@ MY_DEFS_Release := \
'-DENABLE_WEBRTC=1' \
'-DUSE_PROPRIETARY_CODECS' \
'-DENABLE_CONFIGURATION_POLICY' \
- '-DENABLE_NEW_GAMEPAD_API=1' \
'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
'-DENABLE_EGLIMAGE=1' \
diff --git a/tools/json_schema_compiler/cc_generator.py b/tools/json_schema_compiler/cc_generator.py
index 96492ba103..61f5bf1f04 100644
--- a/tools/json_schema_compiler/cc_generator.py
+++ b/tools/json_schema_compiler/cc_generator.py
@@ -146,11 +146,16 @@ class _Generator(object):
def _GenerateInitializersAndBody(self, type_):
items = []
for prop in type_.properties.values():
- if prop.optional:
- continue
-
t = prop.type_
- if t.property_type == PropertyType.INTEGER:
+
+ real_t = self._type_helper.FollowRef(t)
+ if real_t.property_type == PropertyType.ENUM:
+ items.append('%s(%s)' % (
+ prop.unix_name,
+ self._type_helper.GetEnumNoneValue(t)))
+ elif prop.optional:
+ continue
+ elif t.property_type == PropertyType.INTEGER:
items.append('%s(0)' % prop.unix_name)
elif t.property_type == PropertyType.DOUBLE:
items.append('%s(0.0)' % prop.unix_name)
@@ -160,12 +165,11 @@ class _Generator(object):
t.property_type == PropertyType.ARRAY or
t.property_type == PropertyType.BINARY or # mapped to std::string
t.property_type == PropertyType.CHOICES or
- t.property_type == PropertyType.ENUM or
t.property_type == PropertyType.OBJECT or
t.property_type == PropertyType.FUNCTION or
t.property_type == PropertyType.REF or
t.property_type == PropertyType.STRING):
- # TODO(miket): It would be nice to initialize CHOICES and ENUM, but we
+ # TODO(miket): It would be nice to initialize CHOICES, but we
# don't presently have the semantics to indicate which one of a set
# should be the default.
continue
diff --git a/tools/json_schema_compiler/idl_schema.py b/tools/json_schema_compiler/idl_schema.py
index 72e4d13b4f..89bb8816b0 100644
--- a/tools/json_schema_compiler/idl_schema.py
+++ b/tools/json_schema_compiler/idl_schema.py
@@ -469,8 +469,14 @@ def Main():
Dump a json serialization of parse result for the IDL files whose names
were passed in on the command line.
'''
- for filename in sys.argv[1:]:
- schema = Load(filename)
+ if len(sys.argv) > 1:
+ for filename in sys.argv[1:]:
+ schema = Load(filename)
+ print json.dumps(schema, indent=2)
+ else:
+ contents = sys.stdin.read()
+ idl = idl_parser.IDLParser().ParseData(contents, '<stdin>')
+ schema = IDLSchema(idl).process()
print json.dumps(schema, indent=2)
diff --git a/tools/json_schema_compiler/test/enums_unittest.cc b/tools/json_schema_compiler/test/enums_unittest.cc
index 0a2d5d1176..9bbadd9192 100644
--- a/tools/json_schema_compiler/test/enums_unittest.cc
+++ b/tools/json_schema_compiler/test/enums_unittest.cc
@@ -42,6 +42,11 @@ TEST(JsonSchemaCompilerEnumsTest, EnumsAsTypes) {
}
{
HasEnumeration enumeration;
+ EXPECT_EQ(ENUMERATION_NONE, enumeration.enumeration);
+ EXPECT_EQ(ENUMERATION_NONE, enumeration.optional_enumeration);
+ }
+ {
+ HasEnumeration enumeration;
base::DictionaryValue value;
ASSERT_FALSE(HasEnumeration::Populate(value, &enumeration));
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 96b852964a..c174ad2f48 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -1610,6 +1610,21 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<summary>Tracks whether Autofill is enabled when Chrome launches.</summary>
</histogram>
+<histogram name="Autofill.MacAddressBook" enum="AutofillMacAddressBook">
+ <owner>erikchen@chromium.org</owner>
+ <summary>
+ When Chrome tries to access the user's Address Book, OSX presents a blocking
+ dialog which disrupts the user experience. A new Chrome feature has been
+ introduced wherein Chrome only shows this blocking dialog if the user
+ explicitly asked Chrome to access the user's Address Book. If a form's field
+ looks like it might support Autofill suggestions from the user's Address
+ Book and there are no other suggestions, Chrome shows an Autofill entry that
+ prompts the user to give Chrome access to the user's Address Book. This
+ histogram tracks the frequency that this Autofill entry is presented, and
+ the frequency that this Autofill entry is selected.
+ </summary>
+</histogram>
+
<histogram name="AutoFill.ProfileCount">
<obsolete>
Deprecated as of 3/2011, replaced by Autofill.StoredProfileCount.
@@ -6787,7 +6802,21 @@ Therefore, the affected-histogram name has to have at least one dot in it.
</histogram>
<histogram name="Extensions.Permissions_AutoDisable" enum="ExtensionPermission">
- <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
+ <obsolete>
+ Deprecated as of 5/2014, replaced by Extensions.Permissions_AutoDisable2.
+ </obsolete>
+ <owner>kalman@chromium.org</owner>
+ <owner>rpaquay@chromium.org</owner>
+ <summary>
+ The permissions present in an extension when it is automatically disabled
+ due to a permission increase (e.g., after an extension upgrade).
+ </summary>
+</histogram>
+
+<histogram name="Extensions.Permissions_AutoDisable2"
+ enum="ExtensionPermission2">
+ <owner>kalman@chromium.org</owner>
+ <owner>rpaquay@chromium.org</owner>
<summary>
The permissions present in an extension when it is automatically disabled
due to a permission increase (e.g., after an extension upgrade).
@@ -6795,7 +6824,19 @@ Therefore, the affected-histogram name has to have at least one dot in it.
</histogram>
<histogram name="Extensions.Permissions_Install" enum="ExtensionPermission">
- <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
+ <obsolete>
+ Deprecated as of 5/2014, replaced by Extensions.Permissions_Install2.
+ </obsolete>
+ <owner>kalman@chromium.org</owner>
+ <owner>rpaquay@chromium.org</owner>
+ <summary>
+ The permissions present in an extension when it was installed.
+ </summary>
+</histogram>
+
+<histogram name="Extensions.Permissions_Install2" enum="ExtensionPermission2">
+ <owner>kalman@chromium.org</owner>
+ <owner>rpaquay@chromium.org</owner>
<summary>
The permissions present in an extension when it was installed.
</summary>
@@ -6803,7 +6844,21 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<histogram name="Extensions.Permissions_InstallAbort"
enum="ExtensionPermission">
- <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
+ <obsolete>
+ Deprecated as of 5/2014, replaced by Extensions.Permissions_InstallAbort2.
+ </obsolete>
+ <owner>kalman@chromium.org</owner>
+ <owner>rpaquay@chromium.org</owner>
+ <summary>
+ The permissions present in an extension when installation was aborted, not
+ including installation errors and user cancels.
+ </summary>
+</histogram>
+
+<histogram name="Extensions.Permissions_InstallAbort2"
+ enum="ExtensionPermission2">
+ <owner>kalman@chromium.org</owner>
+ <owner>rpaquay@chromium.org</owner>
<summary>
The permissions present in an extension when installation was aborted, not
including installation errors and user cancels.
@@ -6812,19 +6867,55 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<histogram name="Extensions.Permissions_InstallCancel"
enum="ExtensionPermission">
- <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
+ <obsolete>
+ Deprecated as of 5/2014, replaced by Extensions.Permissions_InstallCancel2.
+ </obsolete>
+ <owner>kalman@chromium.org</owner>
+ <owner>rpaquay@chromium.org</owner>
+ <summary>
+ The permissions present in an extension when installation was canceled.
+ </summary>
+</histogram>
+
+<histogram name="Extensions.Permissions_InstallCancel2"
+ enum="ExtensionPermission2">
+ <owner>kalman@chromium.org</owner>
+ <owner>rpaquay@chromium.org</owner>
<summary>
The permissions present in an extension when installation was canceled.
</summary>
</histogram>
<histogram name="Extensions.Permissions_Load" enum="ExtensionPermission">
- <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
+ <obsolete>
+ Deprecated as of 5/2014, replaced by Extensions.Permissions_Load2.
+ </obsolete>
+ <owner>kalman@chromium.org</owner>
+ <owner>rpaquay@chromium.org</owner>
+ <summary>The permissions present in an extension when it was loaded.</summary>
+</histogram>
+
+<histogram name="Extensions.Permissions_Load2" enum="ExtensionPermission2">
+ <owner>kalman@chromium.org</owner>
+ <owner>rpaquay@chromium.org</owner>
<summary>The permissions present in an extension when it was loaded.</summary>
</histogram>
<histogram name="Extensions.Permissions_ReEnable" enum="ExtensionPermission">
- <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
+ <obsolete>
+ Deprecated as of 5/2014, replaced by Extensions.Permissions_ReEnable2.
+ </obsolete>
+ <owner>kalman@chromium.org</owner>
+ <owner>rpaquay@chromium.org</owner>
+ <summary>
+ The permissions present in an extension when it was re-enabled from a
+ confirmation prompt.
+ </summary>
+</histogram>
+
+<histogram name="Extensions.Permissions_ReEnable2" enum="ExtensionPermission2">
+ <owner>kalman@chromium.org</owner>
+ <owner>rpaquay@chromium.org</owner>
<summary>
The permissions present in an extension when it was re-enabled from a
confirmation prompt.
@@ -6833,7 +6924,21 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<histogram name="Extensions.Permissions_ReEnableAbort"
enum="ExtensionPermission">
- <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
+ <obsolete>
+ Deprecated as of 5/2014, replaced by Extensions.Permissions_ReEnableAbort2.
+ </obsolete>
+ <owner>kalman@chromium.org</owner>
+ <owner>rpaquay@chromium.org</owner>
+ <summary>
+ The permissions present in an extension when the re-enable prompt was
+ aborted, not including installation errors and manual user cancels.
+ </summary>
+</histogram>
+
+<histogram name="Extensions.Permissions_ReEnableAbort2"
+ enum="ExtensionPermission2">
+ <owner>kalman@chromium.org</owner>
+ <owner>rpaquay@chromium.org</owner>
<summary>
The permissions present in an extension when the re-enable prompt was
aborted, not including installation errors and manual user cancels.
@@ -6842,7 +6947,21 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<histogram name="Extensions.Permissions_ReEnableCancel"
enum="ExtensionPermission">
- <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
+ <obsolete>
+ Deprecated as of 5/2014, replaced by Extensions.Permissions_ReEnableCancel2.
+ </obsolete>
+ <owner>kalman@chromium.org</owner>
+ <owner>rpaquay@chromium.org</owner>
+ <summary>
+ The permissions present in an extension when the re-enable was canceled from
+ the confirmation prompt.
+ </summary>
+</histogram>
+
+<histogram name="Extensions.Permissions_ReEnableCancel2"
+ enum="ExtensionPermission2">
+ <owner>kalman@chromium.org</owner>
+ <owner>rpaquay@chromium.org</owner>
<summary>
The permissions present in an extension when the re-enable was canceled from
the confirmation prompt.
@@ -6850,7 +6969,19 @@ Therefore, the affected-histogram name has to have at least one dot in it.
</histogram>
<histogram name="Extensions.Permissions_Uninstall" enum="ExtensionPermission">
- <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
+ <obsolete>
+ Deprecated as of 5/2014, replaced by Extensions.Permissions_Uninstall2.
+ </obsolete>
+ <owner>kalman@chromium.org</owner>
+ <owner>rpaquay@chromium.org</owner>
+ <summary>
+ The permissions present in an extension when it was uninstalled.
+ </summary>
+</histogram>
+
+<histogram name="Extensions.Permissions_Uninstall2" enum="ExtensionPermission2">
+ <owner>kalman@chromium.org</owner>
+ <owner>rpaquay@chromium.org</owner>
<summary>
The permissions present in an extension when it was uninstalled.
</summary>
@@ -6858,7 +6989,22 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<histogram name="Extensions.Permissions_WebStoreInstall"
enum="ExtensionPermission">
- <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
+ <obsolete>
+ Deprecated as of 5/2014, replaced by
+ Extensions.Permissions_WebStoreInstall2.
+ </obsolete>
+ <owner>kalman@chromium.org</owner>
+ <owner>rpaquay@chromium.org</owner>
+ <summary>
+ The permissions present in an extension when it was installed through the
+ web store.
+ </summary>
+</histogram>
+
+<histogram name="Extensions.Permissions_WebStoreInstall2"
+ enum="ExtensionPermission2">
+ <owner>kalman@chromium.org</owner>
+ <owner>rpaquay@chromium.org</owner>
<summary>
The permissions present in an extension when it was installed through the
web store.
@@ -6867,7 +7013,22 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<histogram name="Extensions.Permissions_WebStoreInstallAbort"
enum="ExtensionPermission">
- <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
+ <obsolete>
+ Deprecated as of 5/2014, replaced by
+ Extensions.Permissions_WebStoreInstallAbort2.
+ </obsolete>
+ <owner>kalman@chromium.org</owner>
+ <owner>rpaquay@chromium.org</owner>
+ <summary>
+ The permissions present in an extension when installation from the web store
+ was aborted, not including installation errors and user cancels.
+ </summary>
+</histogram>
+
+<histogram name="Extensions.Permissions_WebStoreInstallAbort2"
+ enum="ExtensionPermission2">
+ <owner>kalman@chromium.org</owner>
+ <owner>rpaquay@chromium.org</owner>
<summary>
The permissions present in an extension when installation from the web store
was aborted, not including installation errors and user cancels.
@@ -6876,7 +7037,22 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<histogram name="Extensions.Permissions_WebStoreInstallCancel"
enum="ExtensionPermission">
- <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
+ <obsolete>
+ Deprecated as of 5/2014, replaced by
+ Extensions.Permissions_WebStoreInstallCancel2.
+ </obsolete>
+ <owner>kalman@chromium.org</owner>
+ <owner>rpaquay@chromium.org</owner>
+ <summary>
+ The permissions present in an extension when installation from the web store
+ was canceled.
+ </summary>
+</histogram>
+
+<histogram name="Extensions.Permissions_WebStoreInstallCancel2"
+ enum="ExtensionPermission2">
+ <owner>kalman@chromium.org</owner>
+ <owner>rpaquay@chromium.org</owner>
<summary>
The permissions present in an extension when installation from the web store
was canceled.
@@ -9266,6 +9442,25 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<summary>Chrome OS login success reason.</summary>
</histogram>
+<histogram name="Login.UsersActiveWeekly" units="users">
+ <owner>alemate@chromium.org</owner>
+ <owner>nkostylev@chromium.org</owner>
+ <summary>
+ Chrome OS histogram that keeps track of number of users who have logged in
+ in the last 7 days. Reported on every boot and once a day after that.
+ </summary>
+</histogram>
+
+<histogram name="Login.UsersActiveWeekly.Percent" units="%">
+ <owner>alemate@chromium.org</owner>
+ <owner>nkostylev@chromium.org</owner>
+ <summary>
+ Chrome OS histogram that keeps track of percentage of local users who have
+ logged in in the last 7 days. Reported on every boot and once a day after
+ that.
+ </summary>
+</histogram>
+
<histogram name="Login.UserType" enum="LoginUserType">
<owner>cmasone@chromium.org</owner>
<summary>
@@ -11302,6 +11497,337 @@ Therefore, the affected-histogram name has to have at least one dot in it.
</summary>
</histogram>
+<histogram name="NCN.CM.FastestRTTOn2G" units="milliseconds">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ Rough estimate of the fastest round-trip-time seen on a 2G connection,
+ before the NetworkChangeNotifier detected a connectivity change.
+ </summary>
+</histogram>
+
+<histogram name="NCN.CM.FastestRTTOn3G" units="milliseconds">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ Rough estimate of the fastest round-trip-time seen on a 3G connection,
+ before the NetworkChangeNotifier detected a connectivity change.
+ </summary>
+</histogram>
+
+<histogram name="NCN.CM.FastestRTTOn4G" units="milliseconds">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ Rough estimate of the fastest round-trip-time seen on a 4G connection,
+ before the NetworkChangeNotifier detected a connectivity change.
+ </summary>
+</histogram>
+
+<histogram name="NCN.CM.FastestRTTOnEthernet" units="milliseconds">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ Rough estimate of the fastest round-trip-time seen on an Ethernet
+ connection, before the NetworkChangeNotifier detected a connectivity change.
+ </summary>
+</histogram>
+
+<histogram name="NCN.CM.FastestRTTOnNone" units="milliseconds">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ Rough estimate of the fastest round-trip-time seen while the
+ NetworkChangeNotifier thought there was no network connection, before the
+ NetworkChangeNotifier detected a connectivity change.
+ </summary>
+</histogram>
+
+<histogram name="NCN.CM.FastestRTTOnUnknown" units="milliseconds">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ Rough estimate of the fastest round-trip-time seen on an unknown connection
+ type, before the NetworkChangeNotifier detected a connectivity change.
+ </summary>
+</histogram>
+
+<histogram name="NCN.CM.FastestRTTOnWifi" units="milliseconds">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ Rough estimate of the fastest round-trip-time seen on a Wifi connection,
+ before the NetworkChangeNotifier detected a connectivity change.
+ </summary>
+</histogram>
+
+<histogram name="NCN.CM.FirstReadOn2G" units="milliseconds">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ Time between switching to a 2G connection and receiving the first network
+ data.
+ </summary>
+</histogram>
+
+<histogram name="NCN.CM.FirstReadOn3G" units="milliseconds">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ Time between switching to a 3G connection and receiving the first network
+ data.
+ </summary>
+</histogram>
+
+<histogram name="NCN.CM.FirstReadOn4G" units="milliseconds">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ Time between switching to a 4G connection and receiving the first network
+ data.
+ </summary>
+</histogram>
+
+<histogram name="NCN.CM.FirstReadOnEthernet" units="milliseconds">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ Time between switching to an Ethernet connection and receiving the first
+ network data.
+ </summary>
+</histogram>
+
+<histogram name="NCN.CM.FirstReadOnNone" units="milliseconds">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ Time between disconnecting and receiving the first network data.
+ </summary>
+</histogram>
+
+<histogram name="NCN.CM.FirstReadOnUnknown" units="milliseconds">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ Time between switching to an unknown connection type and receiving the first
+ network data.
+ </summary>
+</histogram>
+
+<histogram name="NCN.CM.FirstReadOnWifi" units="milliseconds">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ Time between switching to a Wifi connection and receiving the first network
+ data.
+ </summary>
+</histogram>
+
+<histogram name="NCN.CM.KBTransferedOn2G" units="KB">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ How much data was transfered while connected via a 2G connection, before the
+ NetworkChangeNotifier detected a connectivity change.
+ </summary>
+</histogram>
+
+<histogram name="NCN.CM.KBTransferedOn3G" units="KB">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ How much data was transfered while connected via a 3G connection, before the
+ NetworkChangeNotifier detected a connectivity change.
+ </summary>
+</histogram>
+
+<histogram name="NCN.CM.KBTransferedOn4G" units="KB">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ How much data was transfered while connected via a 4G connection, before the
+ NetworkChangeNotifier detected a connectivity change.
+ </summary>
+</histogram>
+
+<histogram name="NCN.CM.KBTransferedOnEthernet" units="KB">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ How much data was transfered while connected via an Ethernet connection,
+ before the NetworkChangeNotifier detected a connectivity change.
+ </summary>
+</histogram>
+
+<histogram name="NCN.CM.KBTransferedOnNone" units="KB">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ How much data was transfered while the NetworkChangeNotifier thought there
+ was no network connection, before the NetworkChangeNotifier detected a
+ connectivity change.
+ </summary>
+</histogram>
+
+<histogram name="NCN.CM.KBTransferedOnUnknown" units="KB">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ How much data was transfered while connected via an unknown connection type,
+ before the NetworkChangeNotifier detected a connectivity change.
+ </summary>
+</histogram>
+
+<histogram name="NCN.CM.KBTransferedOnWifi" units="KB">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ How much data was transfered while connected via a Wifi connection, before
+ the NetworkChangeNotifier detected a connectivity change.
+ </summary>
+</histogram>
+
+<histogram name="NCN.CM.PeakKbpsOn2G" units="Kbps">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ Rough estimate of peak throughput seen on a 2G connection, before the
+ NetworkChangeNotifier detected a connectivity change.
+ </summary>
+</histogram>
+
+<histogram name="NCN.CM.PeakKbpsOn3G" units="Kbps">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ Rough estimate of peak throughput seen on a 3G connection, before the
+ NetworkChangeNotifier detected a connectivity change.
+ </summary>
+</histogram>
+
+<histogram name="NCN.CM.PeakKbpsOn4G" units="Kbps">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ Rough estimate of peak throughput seen on a 4G connection, before the
+ NetworkChangeNotifier detected a connectivity change.
+ </summary>
+</histogram>
+
+<histogram name="NCN.CM.PeakKbpsOnEthernet" units="Kbps">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ Rough estimate of peak throughput seen on an Ethernet connection, before the
+ NetworkChangeNotifier detected a connectivity change.
+ </summary>
+</histogram>
+
+<histogram name="NCN.CM.PeakKbpsOnNone" units="Kbps">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ Rough estimate of peak throughput seen while the NetworkChangeNotifier
+ thought there was no network connection, before the NetworkChangeNotifier
+ detected a connectivity change.
+ </summary>
+</histogram>
+
+<histogram name="NCN.CM.PeakKbpsOnUnknown" units="Kbps">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ Rough estimate of peak throughput seen on an unknown connection type, before
+ the NetworkChangeNotifier detected a connectivity change.
+ </summary>
+</histogram>
+
+<histogram name="NCN.CM.PeakKbpsOnWifi" units="Kbps">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ Rough estimate of peak throughput seen on a Wifi connection, before the
+ NetworkChangeNotifier detected a connectivity change.
+ </summary>
+</histogram>
+
+<histogram name="NCN.CM.TimeOn2G" units="milliseconds">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ How long was spent connected via a 2G connection, before the
+ NetworkChangeNotifier detected a connectivity change.
+ </summary>
+</histogram>
+
+<histogram name="NCN.CM.TimeOn3G" units="milliseconds">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ How long was spent connected via a 3G connection, before the
+ NetworkChangeNotifier detected a connectivity change.
+ </summary>
+</histogram>
+
+<histogram name="NCN.CM.TimeOn4G" units="milliseconds">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ How long was spent connected via a 4G connection, before the
+ NetworkChangeNotifier detected a connectivity change.
+ </summary>
+</histogram>
+
+<histogram name="NCN.CM.TimeOnEthernet" units="milliseconds">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ How long was spent connected via an Ethernet connection, before the
+ NetworkChangeNotifier detected a connectivity change.
+ </summary>
+</histogram>
+
+<histogram name="NCN.CM.TimeOnNone" units="milliseconds">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ How long was spent disconnected, before the NetworkChangeNotifier detected a
+ connectivity change.
+ </summary>
+</histogram>
+
+<histogram name="NCN.CM.TimeOnUnknown" units="milliseconds">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ How long was spent connected via an unknown connection type, before the
+ NetworkChangeNotifier detected a connectivity change.
+ </summary>
+</histogram>
+
+<histogram name="NCN.CM.TimeOnWifi" units="milliseconds">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ How long was spent connected via a Wifi connection, before the
+ NetworkChangeNotifier detected a connectivity change.
+ </summary>
+</histogram>
+
+<histogram name="NCN.ConnectionTypeChangeToIPAddressChange"
+ units="milliseconds">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ Time from ConnectionTypeChanged message until IPAddressChanged message.
+ </summary>
+</histogram>
+
+<histogram name="NCN.DNSConfigChange" units="milliseconds">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>Time between DNS configuration change messages.</summary>
+</histogram>
+
+<histogram name="NCN.GetConnectionTypeTime" units="milliseconds">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ How long does each call to NetworkChangeNotifier::GetConnectionType() take.
+ </summary>
+</histogram>
+
+<histogram name="NCN.IPAddressChange" units="milliseconds">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>Time between IP address change messages.</summary>
+</histogram>
+
+<histogram name="NCN.IPAddressChangeToConnectionTypeChange"
+ units="milliseconds">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ Time from IPAddressChanged message until ConnectionTypeChanged message.
+ </summary>
+</histogram>
+
+<histogram name="NCN.NetworkOfflineChange" units="milliseconds">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ Time between going online until we go offline change messages, using new
+ filtered signal.
+ </summary>
+</histogram>
+
+<histogram name="NCN.NetworkOnlineChange" units="milliseconds">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ Time between going offline until we go online change messages, using new
+ filtered signal.
+ </summary>
+</histogram>
+
<histogram name="NCN.NetworkOperatorMCCMNC">
<owner>bolian@chromium.org</owner>
<owner>bengr@google.com</owner>
@@ -11314,6 +11840,62 @@ Therefore, the affected-histogram name has to have at least one dot in it.
</summary>
</histogram>
+<histogram name="NCN.OfflineChange" units="milliseconds">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ Time between going online until we go offline change messages.
+ </summary>
+</histogram>
+
+<histogram name="NCN.OfflineDataRecv" units="milliseconds">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ Time between when we thought we went offline and when we received some
+ network data (a URLRequest read completed).
+ </summary>
+</histogram>
+
+<histogram name="NCN.OfflineDataRecvAny5sBeforeOnline">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ Count of how many times we received network data (a URLRequest read
+ completed) while offline when some data was received at most five seconds
+ before going online.
+ </summary>
+</histogram>
+
+<histogram name="NCN.OfflineDataRecvUntilOnline" units="milliseconds">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ Time between when we received the last network data (a URLRequest read
+ completed) while offline and when we thought we went online.
+ </summary>
+</histogram>
+
+<histogram name="NCN.OfflinePolls">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ Count of how many times we polled the online/offline status before detecting
+ an offline to online transition.
+ </summary>
+</histogram>
+
+<histogram name="NCN.OnlineChange" units="milliseconds">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ Time between going offline until we go online change messages.
+ </summary>
+</histogram>
+
+<histogram name="NCN.PollingOfflineDataRecv" units="milliseconds">
+ <owner>pauljensen@chromium.org</owner>
+ <summary>
+ Time between when we thought we went offline and when we received some
+ network data (a URLRequest read completed), while polling
+ NetworkChangeNotifier::GetConnectionType() still told us we were offline.
+ </summary>
+</histogram>
+
<histogram name="Net.AlternateProtocolBrokenLocation"
enum="BrokenAlternateProtocolLocation">
<owner>rch@chromium.org</owner>
@@ -13506,6 +14088,13 @@ Therefore, the affected-histogram name has to have at least one dot in it.
</summary>
</histogram>
+<histogram name="Net.QuicActiveSessions">
+ <owner>rtenneti@chromium.org</owner>
+ <summary>
+ The number of active QUIC sessions before we activate a new QUIC session.
+ </summary>
+</histogram>
+
<histogram name="Net.QuicEphemeralPortsSuggested">
<owner>rch@chromium.org</owner>
<summary>The number of ports suggested per server.</summary>
@@ -17357,6 +17946,16 @@ Therefore, the affected-histogram name has to have at least one dot in it.
</summary>
</histogram>
+<histogram name="Omnibox.HasLegalDefaultMatchWithoutCompletion" enum="Boolean">
+ <owner>mpearson@chromium.org</owner>
+ <summary>
+ Whether there was at least one legal default match without an
+ |inline_autocompletion|. Recorded every time
+ AutocompleteResult::SortAndCull() is called, which could happen multiple
+ times on each keystroke.
+ </summary>
+</histogram>
+
<histogram name="Omnibox.Paste" units="count">
<owner>mpearson@chromium.org</owner>
<summary>
@@ -21289,6 +21888,15 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<summary>The frequency of ways that new user profiles are added.</summary>
</histogram>
+<histogram name="Profile.AndroidAccountManagementMenu"
+ enum="ProfileAndroidAccountManagementMenu">
+ <owner>aruslan@chromium.org</owner>
+ <summary>
+ Track user interactions that can be performed in the Android account
+ management menu.
+ </summary>
+</histogram>
+
<histogram name="Profile.AppCount">
<owner>Please list the metric's owners. Add more owner tags as needed.</owner>
<summary>The number of installed apps when a profile is opened.</summary>
@@ -21463,7 +22071,7 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<owner>rlp@chromium.org</owner>
<summary>
Counts the number of signed-in profiles on a user's machine when Chrome
- starts up, among cases with at least one profile.
+ starts up.
</summary>
</histogram>
@@ -21479,6 +22087,15 @@ Therefore, the affected-histogram name has to have at least one dot in it.
</summary>
</histogram>
+<histogram name="Profile.NumberOfSignedInProfilesWithGAIAIcons">
+ <owner>mlerman@chromium.org</owner>
+ <summary>
+ Counts the number of signed-in profiles that are using the GAIA image as the
+ avatar icon. This is counted when a profile is loaded, including when Chrome
+ starts up.
+ </summary>
+</histogram>
+
<histogram name="Profile.Opening" enum="ProfileOpen">
<obsolete>
Deprecated because it did not present the information clearly.
@@ -22214,6 +22831,40 @@ Therefore, the affected-histogram name has to have at least one dot in it.
</summary>
</histogram>
+<histogram name="Renderer4.GpuRasterizationEnabled" units="BooleanEnabled">
+ <owner>alokp@chromium.org</owner>
+ <summary>
+ Whether gpu rasterization is enabled (checked once after the page is painted
+ for the first time).
+ </summary>
+</histogram>
+
+<histogram name="Renderer4.GpuRasterizationSuitableContent"
+ units="BooleanEnabled">
+ <owner>alokp@chromium.org</owner>
+ <summary>
+ If gpu rasterization is enabled, whether the page contents are suitable for
+ gpu rasterization (checked once after the page is painted for the first
+ time).
+ </summary>
+</histogram>
+
+<histogram name="Renderer4.GpuRasterizationTriggered" units="BooleanEnabled">
+ <owner>alokp@chromium.org</owner>
+ <summary>
+ If gpu rasterization is enabled, whether it was triggered (checked once
+ after the page is painted for the first time).
+ </summary>
+</histogram>
+
+<histogram name="Renderer4.GpuRasterizationUsed" units="BooleanEnabled">
+ <owner>alokp@chromium.org</owner>
+ <summary>
+ If gpu rasterization is enabled, whether it was actually used for the page
+ (checked once after the page is painted for the first time).
+ </summary>
+</histogram>
+
<histogram name="Renderer4.InvalidationRegionApproximateRectCount"
units="rects">
<owner>wiltzius@chromium.org</owner>
@@ -23384,8 +24035,11 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<owner>mattm@chromium.org</owner>
<summary>
Records the total time it takes for the SafeBrowsing download service to
- check whether the content of a download is malicious or not. This histogram
- only includes requests that are sent to the SafeBrowsing server.
+ check whether the content of a download is malicious or not, including file
+ feature extraction, whitelist checking, and server ping. This histogram only
+ includes checks that sent a ping to the SafeBrowsing server. It does not
+ include requests that were cancelled, but does include requests that
+ received a bad response.
</summary>
</histogram>
@@ -23396,6 +24050,24 @@ Therefore, the affected-histogram name has to have at least one dot in it.
</summary>
</histogram>
+<histogram name="SBClientDownload.DownloadRequestNetworkDuration"
+ units="milliseconds">
+ <owner>mattm@chromium.org</owner>
+ <summary>
+ Records the time it takes for the SafeBrowsing download service ping. It is
+ not recorded for requests that were cancelled.
+ </summary>
+</histogram>
+
+<histogram name="SBClientDownload.DownloadRequestNetworkStats"
+ enum="SBClientDownloadCheckDownloadStats">
+ <owner>mattm@chromium.org</owner>
+ <summary>
+ Records the results of SafeBrowsing binary download checks which caused a
+ server ping.
+ </summary>
+</histogram>
+
<histogram name="SBClientDownload.DownloadRequestPayloadSize" units="bytes">
<owner>mattm@chromium.org</owner>
<summary>
@@ -23411,6 +24083,27 @@ Therefore, the affected-histogram name has to have at least one dot in it.
</summary>
</histogram>
+<histogram name="SBClientDownload.DownloadRequestTimeoutDuration"
+ units="milliseconds">
+ <owner>mattm@chromium.org</owner>
+ <summary>
+ Records the portion of the SafeBrowsing download service check starting with
+ the point CheckClientDownloadRequest::StartTimeout() is called. It is
+ recorded regardless if a ping was sent or not. It is not recorded for
+ requests that were cancelled.
+ </summary>
+</histogram>
+
+<histogram name="SBClientDownload.DownloadRequestTimeoutStats"
+ enum="SBClientDownloadCheckDownloadStats">
+ <owner>mattm@chromium.org</owner>
+ <summary>
+ For SafeBrowsing binary download checks which reached the
+ CheckClientDownloadRequest::StartTimeout() call, records the final result
+ (once the check finishes or is cancelled).
+ </summary>
+</histogram>
+
<histogram name="SBClientDownload.ExtractImageHeadersTime" units="milliseconds">
<owner>grt@chromium.org</owner>
<summary>
@@ -23890,6 +24583,28 @@ Therefore, the affected-histogram name has to have at least one dot in it.
</summary>
</histogram>
+<histogram name="ServiceWorker.Database.OpenResult"
+ enum="ServiceWorkerDatabaseStatus">
+ <owner>nhiroki@chromium.org</owner>
+ <summary>
+ Records result of opening a database for ServiceWorkerDatabase.
+ </summary>
+</histogram>
+
+<histogram name="ServiceWorker.Database.ReadResult"
+ enum="ServiceWorkerDatabaseStatus">
+ <owner>nhiroki@chromium.org</owner>
+ <summary>Records result of read operations in ServiceWorkerDatabase.</summary>
+</histogram>
+
+<histogram name="ServiceWorker.Database.WriteResult"
+ enum="ServiceWorkerDatabaseStatus">
+ <owner>nhiroki@chromium.org</owner>
+ <summary>
+ Records result of write operations in ServiceWorkerDatabase.
+ </summary>
+</histogram>
+
<histogram name="Settings.DefaultSearchProvider" enum="OmniboxSearchEngine">
<obsolete>
Deprecated in Chrome 30. Use Search.DefaultSearchProviderType instead.
@@ -31109,6 +31824,34 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<summary>The success or failure of web fonts CORS-enabled fetching.</summary>
</histogram>
+<histogram name="WebFont.DiskCache.ReuseCount.Evict">
+ <owner>kenjibaheux@chromium.org</owner>
+ <owner>ksakamoto@chromium.org</owner>
+ <summary>
+ When a cache entry for a font in Google Fonts is evicted, records the reuse
+ count of the cache entry.
+ </summary>
+</histogram>
+
+<histogram name="WebFont.DiskCache.ReuseCount.Hit">
+ <owner>kenjibaheux@chromium.org</owner>
+ <owner>ksakamoto@chromium.org</owner>
+ <summary>
+ Recorded upon a cache hit for a font in Google Fonts. Records the reuse
+ count of the cache entry.
+ </summary>
+</histogram>
+
+<histogram name="WebFont.DiskCacheHit.opensans" enum="WebFontDiskCacheHit">
+ <owner>kenjibaheux@chromium.org</owner>
+ <owner>ksakamoto@chromium.org</owner>
+ <summary>
+ Whether the font was in the cache or not. &quot;Previously in the
+ cache&quot; means there was an evicted entry for the font in the cache.
+ Recorded upon a disk cache query for a font in Google Fonts.
+ </summary>
+</histogram>
+
<histogram name="WebFont.DownloadTime.0.Under10KB" units="milliseconds">
<owner>kenjibaheux@chromium.org</owner>
<owner>ksakamoto@chromium.org</owner>
@@ -32216,6 +32959,11 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<int value="17" label="fp05cc03e1"/>
</enum>
+<enum name="AutofillMacAddressBook" type="int">
+ <int value="0" label="Showed popup entry"/>
+ <int value="1" label="Selected popup entry"/>
+</enum>
+
<enum name="AutofillQuality" type="int">
<int value="0" label="Submitted"/>
<int value="1" label="Autofilled"/>
@@ -34106,6 +34854,7 @@ Therefore, the affected-histogram name has to have at least one dot in it.
label="Restrict the UDP port range used by the remote access host"/>
<int value="265" label="Enables the old web-based signin"/>
<int value="266" label="Block developer mode"/>
+ <int value="267" label="Show the apps shortcut in the bookmark bar"/>
</enum>
<enum name="EnterprisePolicyInvalidations" type="int">
@@ -34387,8 +35136,8 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<int value="28" label="DELETED_FILEBROWSERPRIVATE_ISFULLSCREEN"/>
<int value="29" label="AUTOTESTPRIVATE_LOGOUT"/>
<int value="30" label="EXPERIMENTAL_HISTORY_GETMOSTVISITED"/>
- <int value="31" label="BLUETOOTH_DISCONNECT"/>
- <int value="32" label="BLUETOOTH_SETOUTOFBANDPAIRINGDATA"/>
+ <int value="31" label="DELETED_BLUETOOTH_DISCONNECT"/>
+ <int value="32" label="DELETED_BLUETOOTH_SETOUTOFBANDPAIRINGDATA"/>
<int value="33" label="BOOKMARKMANAGERPRIVATE_CANPASTE"/>
<int value="34" label="AUTOTESTPRIVATE_RESTART"/>
<int value="35" label="USB_CLAIMINTERFACE"/>
@@ -34494,7 +35243,7 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<int value="135" label="CONTEXTMENUS_UPDATE"/>
<int value="136" label="BOOKMARKS_SEARCH"/>
<int value="137" label="EXPERIMENTAL_APP_CLEARALLNOTIFICATIONS"/>
- <int value="138" label="BLUETOOTH_GETLOCALOUTOFBANDPAIRINGDATA"/>
+ <int value="138" label="DELETED_BLUETOOTH_GETLOCALOUTOFBANDPAIRINGDATA"/>
<int value="139" label="SYSTEMPRIVATE_GETUPDATESTATUS"/>
<int value="140" label="FONTSETTINGS_CLEARMINIMUMFONTSIZE"/>
<int value="141" label="DELETED_FILEBROWSERPRIVATE_GETFILELOCATIONS"/>
@@ -34632,11 +35381,11 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<int value="272" label="PAGEACTIONS_DISABLEFORTAB"/>
<int value="273" label="DEVELOPERPRIVATE_ALLOWFILEACCESS"/>
<int value="274" label="FILEBROWSERPRIVATE_REMOVEMOUNT"/>
- <int value="275" label="BLUETOOTH_CONNECT"/>
+ <int value="275" label="DELETED_BLUETOOTH_CONNECT"/>
<int value="276" label="TABCAPTURE_CAPTURE"/>
<int value="277" label="NOTIFICATIONS_CREATE"/>
<int value="278" label="TABS_DUPLICATE"/>
- <int value="279" label="BLUETOOTH_WRITE"/>
+ <int value="279" label="DELETED_BLUETOOTH_WRITE"/>
<int value="280" label="PAGEACTION_SHOW"/>
<int value="281" label="WALLPAPERPRIVATE_GETTHUMBNAIL"/>
<int value="282" label="DOWNLOADS_PAUSE"/>
@@ -34702,7 +35451,7 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<int value="342" label="BROWSERACTION_SETPOPUP"/>
<int value="343" label="TABS_GETSELECTED"/>
<int value="344" label="FONTSETTINGS_GETFONT"/>
- <int value="345" label="BLUETOOTH_READ"/>
+ <int value="345" label="DELETED_BLUETOOTH_READ"/>
<int value="346" label="WEBREQUESTINTERNAL_EVENTHANDLED"/>
<int value="347" label="EVENTS_ADDRULES"/>
<int value="348" label="CONTEXTMENUS_CREATE"/>
@@ -34810,8 +35559,8 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<int value="450" label="NETWORKINGPRIVATE_GETMANAGEDPROPERTIES"/>
<int value="451" label="LOCATION_WATCHLOCATION"/>
<int value="452" label="LOCATION_CLEARWATCH"/>
- <int value="453" label="BLUETOOTH_ADDPROFILE"/>
- <int value="454" label="BLUETOOTH_REMOVEPROFILE"/>
+ <int value="453" label="DELETED_BLUETOOTH_ADDPROFILE"/>
+ <int value="454" label="DELETED_BLUETOOTH_REMOVEPROFILE"/>
<int value="455" label="DELETED_BLUETOOTH_GETPROFILES"/>
<int value="456" label="EXPERIMENTAL_IDENTITY_REMOVECACHEDAUTHTOKEN"/>
<int value="457" label="AUDIO_GETINFO"/>
@@ -35061,7 +35810,7 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<int value="696" label="WEBVIEW_CONTEXTMENUSUPDATE"/>
<int value="697" label="WEBVIEW_CONTEXTMENUSREMOVE"/>
<int value="698" label="WEBVIEW_CONTEXTMENUSREMOVEALL"/>
- <int value="699" label="AUTOMATIONINTERNAL_ENABLECURRENTTAB"/>
+ <int value="699" label="AUTOMATIONINTERNAL_ENABLETAB"/>
<int value="700" label="APP_CURRENTWINDOWINTERNAL_SETSIZECONSTRAINTS"/>
<int value="701" label="BLUETOOTH_GETDEVICE"/>
<int value="702" label="GCM_UNREGISTER"/>
@@ -35074,10 +35823,10 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<int value="709" label="BLUETOOTHPRIVATE_SETPAIRINGRESPONSE"/>
<int value="710" label="NETWORKINGPRIVATE_GETCAPTIVEPORTALSTATUS"/>
<int value="711" label="AUTOMATIONINTERNAL_PERFORMACTION"/>
- <int value="712" label="BLUETOOTH_UPDATE_SOCKET"/>
- <int value="713" label="BLUETOOTH_SET_SOCKET_PAUSED"/>
- <int value="714" label="BLUETOOTH_GET_SOCKET"/>
- <int value="715" label="BLUETOOTH_GET_SOCKETS"/>
+ <int value="712" label="DELETED_BLUETOOTH_UPDATE_SOCKET"/>
+ <int value="713" label="DELETED_BLUETOOTH_SET_SOCKET_PAUSED"/>
+ <int value="714" label="DELETED_BLUETOOTH_GET_SOCKET"/>
+ <int value="715" label="DELETED_BLUETOOTH_GET_SOCKETS"/>
<int value="716" label="FILESYSTEMPROVIDER_UNMOUNT"/>
<int value="717" label="FILESYSTEMPROVIDERINTERNAL_UNMOUNTREQUESTEDSUCCESS"/>
<int value="718" label="FILESYSTEMPROVIDERINTERNAL_UNMOUNTREQUESTEDERROR"/>
@@ -35152,6 +35901,7 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<int value="782" label="FILEBROWSERPRIVATE_OPENINSPECTOR"/>
<int value="783" label="STREAMSPRIVATE_ABORT"/>
<int value="784" label="MANAGEMENT_SETLAUNCHTYPE"/>
+ <int value="785" label="MANAGEMENT_GENERATEAPPFORLINK"/>
</enum>
<enum name="ExtensionInstallCause" type="int">
@@ -36908,6 +37658,8 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<int value="23" label="GetDatabaseNames"/>
<int value="24" label="ReadBlobJournal"/>
<int value="25" label="DecodeBlobJournal"/>
+ <int value="26" label="GetBlobKeyGeneratorCurrentNumber"/>
+ <int value="27" label="GetBlobInfoForRecord"/>
</enum>
<enum name="IDBLevelDBBackingStoreOpenResult" type="int">
@@ -37126,6 +37878,7 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<int value="1" label="PeerConnection00"/>
<int value="2" label="DeprecatedPeerConnection"/>
<int value="3" label="RTCPeerConnection"/>
+ <int value="4" label="GetMediaDevices"/>
</enum>
<enum name="KeyboardControlEvent" type="int">
@@ -40377,6 +41130,7 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<int value="286711" label="PPB_FlashFullscreen;0.1"/>
<int value="2804066" label="PPB_AudioConfig;1.1"/>
<int value="8760108" label="PPB_Testing_Private;1.0"/>
+ <int value="12033600" label="PPB_Compositor;0.1"/>
<int value="13662160" label="PPB_CharSet(Dev);0.4"/>
<int value="22816901" label="PPB_FileChooser(Dev);0.5"/>
<int value="28187368" label="PPB_IMEInputEvent(Dev);0.2"/>
@@ -40390,6 +41144,7 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<int value="156766028" label="PPB_UMA_Private;0.3"/>
<int value="162107265" label="PPB_NetworkMonitor;1.0"/>
<int value="180906214" label="PPB_Instance_Private;0.1"/>
+ <int value="206043276" label="PPB_CompositorLayer;0.1"/>
<int value="221802429" label="PPB_URLUtil(Dev);0.7"/>
<int value="225125520" label="PPB_Find(Private);0.3"/>
<int value="226206264" label="PPB_FileRef;1.1"/>
@@ -40466,6 +41221,7 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<int value="1260990020" label="PPB_Ext_Socket(Dev);0.2"/>
<int value="1262240942" label="PPB_FileIO;1.1"/>
<int value="1272679676" label="PPB_TCPSocket_Private;0.5"/>
+ <int value="1296231808" label="PPB_VideoDecoder;0.1"/>
<int value="1316246754" label="PPB_KeyboardInputEvent;1.0"/>
<int value="1316320941" label="PPB_Graphics2D(Dev);0.1"/>
<int value="1321620067" label="PPB_Instance;1.0"/>
@@ -41176,6 +41932,33 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<int value="3" label="Add new user from the User Manager"/>
</enum>
+<enum name="ProfileAndroidAccountManagementMenu" type="int">
+ <int value="0" label="Opened Menu">
+ User arrived at the Account management screen.
+ </int>
+ <int value="1" label="Add Account">
+ User arrived at the Account management screen, and clicked Add account.
+ </int>
+ <int value="2" label="Go Incognito">
+ User arrived at the Account management screen, and clicked Go incognito.
+ </int>
+ <int value="3" label="Primary Account">
+ User arrived at the Account management screen, and clicked on primary.
+ </int>
+ <int value="4" label="Secondary Account">
+ User arrived at the Account management screen, and clicked on secondary.
+ </int>
+ <int value="5" label="Toggled Signout">
+ User arrived at the Account management screen, toggled Chrome signout.
+ </int>
+ <int value="6" label="Confirm Signout">
+ User toggled Chrome signout, and clicked Signout.
+ </int>
+ <int value="7" label="Cancel Signout">
+ User toggled Chrome signout, and clicked Cancel.
+ </int>
+</enum>
+
<enum name="ProfileAuth" type="int">
<int value="0" label="Authentication was unnecessary (profile not locked)"/>
<int value="1" label="Authentication performed using local credentials"/>
@@ -41688,6 +42471,7 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<int value="55" label="IDC_CONTENT_CONTEXT_SPELLING_TOGGLE"/>
<int value="56" label="IDC_SPELLCHECK_LANGUAGES_FIRST"/>
<int value="57" label="IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE"/>
+ <int value="58" label="IDC_SPELLCHECK_SUGGESTION"/>
</enum>
<enum name="ResolutionCategory" type="int">
@@ -42122,6 +42906,14 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<int value="10" label="SERVICE_UTILITY_SEMANTIC_CAPS_FAILED"/>
</enum>
+<enum name="ServiceWorkerDatabaseStatus" type="int">
+ <int value="0" label="OK"/>
+ <int value="1" label="Not Found Error"/>
+ <int value="2" label="IO Error"/>
+ <int value="3" label="Corruption Error"/>
+ <int value="4" label="Operation Error"/>
+</enum>
+
<enum name="SessionStartupPref" type="int">
<int value="0" label="Open home page (unused)"/>
<int value="1" label="Continue from last opened pages"/>
@@ -44034,6 +44826,12 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<int value="2" label="Served from data URL"/>
</enum>
+<enum name="WebFontDiskCacheHit" type="int">
+ <int value="0" label="Not in the cache"/>
+ <int value="1" label="In the cache"/>
+ <int value="2" label="Previously in the cache"/>
+</enum>
+
<enum name="WebFontUsageType" type="int">
<int value="0" label="Styled, and used"/>
<int value="1" label="Styled, but not used"/>
@@ -45123,6 +45921,9 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<suffix name="CONNECTION_4G" label="mobile 4G are tallied."/>
<suffix name="CONNECTION_NONE"
label="NO(?) network are tallied (should be empty)."/>
+ <suffix name="CONNECTION_BLUETOOTH"
+ label="Bluetooth are tallied, but this may include connections to a
+ mobile hotspot."/>
<affected-histogram
name="Net.QuicSession.21CumulativePacketsReceived_First21"/>
<affected-histogram
@@ -46748,7 +47549,7 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<affected-histogram name="Prerender.TimeUntilUsed2"/>
</histogram_suffixes>
-<histogram_suffixes name="Profile.DesktopMenu" separator=".">
+<histogram_suffixes name="Profile.AndroidAccountManagementMenu" separator=".">
<suffix name="NonGAIA" label="Interaction was not initiated from GAIA"/>
<suffix name="GAIASignout"
label="GAIA-initiated interaction indicating a service type of Signout"/>
@@ -46763,6 +47564,24 @@ Therefore, the affected-histogram name has to have at least one dot in it.
Reauthenticate this user"/>
<suffix name="GAIADefault"
label="GAIA-initiated interaction indicating the default service type"/>
+ <affected-histogram name="Profile.AndroidAccountManagementMenu"/>
+</histogram_suffixes>
+
+<histogram_suffixes name="Profile.DesktopMenu" separator=".">
+ <suffix name="NonGAIA" label="Interaction was not initiated from GAIA"/>
+ <suffix name="GAIASignout"
+ label="GAIA-initiated interaction indicating a service type of Signout"/>
+ <suffix name="GAIAIncognito"
+ label="GAIA-initiated interaction indicating a service type of
+ Incogntio"/>
+ <suffix name="GAIAAddSession"
+ label="GAIA-initiated interaction indicating a service type of Add a
+ Session"/>
+ <suffix name="GAIAReAuth"
+ label="GAIA-initiated interaction indicating a service type of
+ Reauthenticate this user"/>
+ <suffix name="GAIADefault"
+ label="GAIA-initiated interaction indicating the default service type"/>
<affected-histogram name="Profile.DesktopMenu"/>
</histogram_suffixes>
@@ -47183,6 +48002,15 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<affected-histogram name="Settings.TrackedSplitPreferenceChanged"/>
</histogram_suffixes>
+<histogram_suffixes name="WebFontFamily">
+ <suffix name="roboto" label="Roboto font"/>
+ <suffix name="opensans" label="Open Sans font"/>
+ <suffix name="others" label="Fonts other than Roboto and Open Sans"/>
+ <affected-histogram name="WebFont.DiskCache.ReuseCount.Evict"/>
+ <affected-histogram name="WebFont.DiskCache.ReuseCount.Hit"/>
+ <affected-histogram name="WebFont.DiskCacheHit"/>
+</histogram_suffixes>
+
<histogram_suffixes name="WebStoreLinkExperiment">
<suffix name="Disabled" label="Neither extra webstore link is visible"/>
<suffix name="FooterLink" label="Link in bottom right of footer"/>
diff --git a/tools/metrics/rappor/rappor.xml b/tools/metrics/rappor/rappor.xml
new file mode 100644
index 0000000000..4d2651d62c
--- /dev/null
+++ b/tools/metrics/rappor/rappor.xml
@@ -0,0 +1,39 @@
+<!--
+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 is used to generate a comprehensive list of Chrome rappor metrics
+along with a detailed description for each histogram. See the design doc at
+http://www.chromium.org/developers/design-documents/rappor
+for a description of rappor metrics.
+
+TODO(holte): Add validation and pretty printing scripts.
+-->
+
+<rappor-configuration>
+
+<!-- Rappor metric definitions -->
+
+<rappor-metrics>
+
+<rappor-metric name="Settings.HomePage2" type="ETLD_PLUS_ONE">
+ <owner>holte@chromium.org</owner>
+ <summary>
+ The eTLD+1 of the prefs::kHomePage setting. Only recorded if the URL is
+ valid and prefs::kHomePageIsNewTabPage is false.
+ </summary>
+</rappor-metric>
+
+<rappor-metric name="Extensions.PossibleAdInjection2" type="ETLD_PLUS_ONE">
+ <owner>rdevlin.cronin@chromium.org</owner>
+ <summary>
+ The eTLD+1 of a URL that might be doing ad injection.
+ </summary>
+</rappor-metric>
+
+</rappor-metrics>
+
+</rappor-configuration>
diff --git a/tools/msan/blacklist.txt b/tools/msan/blacklist.txt
index e38e1ed1f5..0d14c12999 100644
--- a/tools/msan/blacklist.txt
+++ b/tools/msan/blacklist.txt
@@ -14,12 +14,10 @@ fun:*MOZ_Z_deflate*
fun:unpack_RGBA8888
fun:unpack_RGB888
-# http://crbug.com/363487
-fun:*WebCore*RenderLayerCompositor*updateIfNeeded*
+# Bug in MSan, fixed in clang r210020. http://crbug.com/378909
+fun:*convolveVertically_SSE2*
-# Fixed in clang r207227.
-# http://code.google.com/p/memory-sanitizer/issues/detail?id=53
-fun:getc_unlocked
-
-# http://crbug.com/158510
-fun:_ZN7WebCore11RenderTable6layoutEv
+# MSan issue, http://crbug.com/381233
+# (Both functions call __mm_maddubs_epi16()).
+fun:*ProcessPixelPairHelper*
+fun:*ProcessOnePixel*
diff --git a/tools/perf/OWNERS b/tools/perf/OWNERS
index 16b912ee91..af60bc01ae 100644
--- a/tools/perf/OWNERS
+++ b/tools/perf/OWNERS
@@ -5,7 +5,7 @@ ernstm@chromium.org
hartmanng@chromium.org
marja@chromium.org
nduca@chromium.org
-nednguyen@chromium.org
+nednguyen@google.com
qyearsley@chromium.org
skyostil@chromium.org
tonyg@chromium.org
diff --git a/tools/perf/PRESUBMIT.py b/tools/perf/PRESUBMIT.py
index 3b20bf6f83..2c269c882a 100644
--- a/tools/perf/PRESUBMIT.py
+++ b/tools/perf/PRESUBMIT.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/perf/benchmarks/benchmark_unittest.py b/tools/perf/benchmarks/benchmark_unittest.py
index f1e0eef9dd..f1c356e742 100644
--- a/tools/perf/benchmarks/benchmark_unittest.py
+++ b/tools/perf/benchmarks/benchmark_unittest.py
@@ -22,7 +22,7 @@ def SmokeTestGenerator(benchmark):
# In general you should @test.Disabled individual benchmarks that fail,
# instead of this entire smoke test suite.
# TODO(achuith): Multiple tests failing on CrOS. crbug.com/351114
- @test.Disabled('android', 'chromeos', 'win')
+ @test.Disabled('chromeos')
def BenchmarkSmokeTest(self):
# Only measure a single page so that this test cycles reasonably quickly.
benchmark.options['pageset_repeat'] = 1
diff --git a/tools/perf/benchmarks/blink_perf.py b/tools/perf/benchmarks/blink_perf.py
index 2e17ca9eed..ae38e48ca1 100644
--- a/tools/perf/benchmarks/blink_perf.py
+++ b/tools/perf/benchmarks/blink_perf.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/perf/benchmarks/chrome_proxy.py b/tools/perf/benchmarks/chrome_proxy.py
index 5c58709946..4414d24a97 100644
--- a/tools/perf/benchmarks/chrome_proxy.py
+++ b/tools/perf/benchmarks/chrome_proxy.py
@@ -4,12 +4,17 @@
from telemetry import test
from measurements import chrome_proxy
-
+from page_sets.chrome_proxy import bypass
+from page_sets.chrome_proxy import fallback_viaheader
+from page_sets.chrome_proxy import safebrowsing
+from page_sets.chrome_proxy import smoke
+from page_sets.chrome_proxy import synthetic
+from page_sets.chrome_proxy import top_20
class ChromeProxyLatency(test.Test):
tag = 'latency'
test = chrome_proxy.ChromeProxyLatency
- page_set = 'page_sets/chrome_proxy/top_20.py'
+ page_set = top_20.Top20PageSet()
options = {'pageset_repeat_iters': 2}
def CustomizeBrowserOptions(self, options):
@@ -19,22 +24,22 @@ class ChromeProxyLatency(test.Test):
class ChromeProxyLatencyDirect(test.Test):
tag = 'latency_direct'
test = chrome_proxy.ChromeProxyLatency
- page_set = 'page_sets/chrome_proxy/top_20.py'
+ page_set = top_20.Top20PageSet()
options = {'pageset_repeat_iters': 2}
class ChromeProxyLatencySynthetic(ChromeProxyLatency):
- page_set = 'page_sets/chrome_proxy/synthetic.py'
+ page_set = synthetic.SyntheticPageSet()
class ChromeProxyLatencySyntheticDirect(ChromeProxyLatencyDirect):
- page_set = 'page_sets/chrome_proxy/synthetic.py'
+ page_set = synthetic.SyntheticPageSet()
class ChromeProxyDataSaving(test.Test):
tag = 'data_saving'
test = chrome_proxy.ChromeProxyDataSaving
- page_set = 'page_sets/chrome_proxy/top_20.py'
+ page_set = top_20.Top20PageSet()
options = {'pageset_repeat_iters': 1}
def CustomizeBrowserOptions(self, options):
options.AppendExtraBrowserArgs('--enable-spdy-proxy-auth')
@@ -44,48 +49,48 @@ class ChromeProxyDataSavingDirect(test.Test):
tag = 'data_saving_direct'
test = chrome_proxy.ChromeProxyDataSaving
options = {'pageset_repeat_iters': 2}
- page_set = 'page_sets/chrome_proxy/top_20.py'
+ page_set = top_20.Top20PageSet()
class ChromeProxyDataSavingSynthetic(ChromeProxyDataSaving):
- page_set = 'page_sets/chrome_proxy/synthetic.py'
+ page_set = synthetic.SyntheticPageSet()
class ChromeProxyDataSavingSyntheticDirect(ChromeProxyDataSavingDirect):
- page_set = 'page_sets/chrome_proxy/synthetic.py'
+ page_set = synthetic.SyntheticPageSet()
class ChromeProxyHeaderValidation(test.Test):
tag = 'header_validation'
test = chrome_proxy.ChromeProxyHeaders
- page_set = 'page_sets/chrome_proxy/top_20.py'
+ page_set = top_20.Top20PageSet()
class ChromeProxyBypass(test.Test):
tag = 'bypass'
test = chrome_proxy.ChromeProxyBypass
- page_set = 'page_sets/chrome_proxy/bypass.py'
+ page_set = bypass.BypassPageSet()
class ChromeProxySafeBrowsing(test.Test):
tag = 'safebrowsing'
test = chrome_proxy.ChromeProxySafebrowsing
- page_set = 'page_sets/chrome_proxy/safebrowsing.py'
+ page_set = safebrowsing.SafebrowsingPageSet()
class ChromeProxyHTTPFallbackProbeURL(test.Test):
tag = 'fallback-probe'
test = chrome_proxy.ChromeProxyHTTPFallbackProbeURL
- page_set = 'page_sets/chrome_proxy/synthetic.py'
+ page_set = synthetic.SyntheticPageSet()
class ChromeProxyHTTPFallbackViaHeader(test.Test):
tag = 'fallback-viaheader'
test = chrome_proxy.ChromeProxyHTTPFallbackViaHeader
- page_set = 'page_sets/chrome_proxy/fallback_viaheader.py'
+ page_set = fallback_viaheader.FallbackViaHeaderPageSet()
class ChromeProxySmoke(test.Test):
tag = 'smoke'
test = chrome_proxy.ChromeProxySmoke
- page_set = 'page_sets/chrome_proxy/smoke.py'
+ page_set = smoke.SmokePageSet()
diff --git a/tools/perf/benchmarks/dom_perf.py b/tools/perf/benchmarks/dom_perf.py
index a20a2542ef..b3d8735509 100644
--- a/tools/perf/benchmarks/dom_perf.py
+++ b/tools/perf/benchmarks/dom_perf.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/perf/benchmarks/doyouevenbench.py b/tools/perf/benchmarks/doyouevenbench.py
deleted file mode 100644
index a4af53ad75..0000000000
--- a/tools/perf/benchmarks/doyouevenbench.py
+++ /dev/null
@@ -1,62 +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.
-
-"""DoYouEvenBench performance benchmark .
-
-DoYouEvenBench performance benchmark UI performance related to DOM using
-popular JS frameworks. This benchmark uses http://todomvc.com and emulates user
-actions: adding 100 todo items, completing them, and then deleting
-them with Ember.js, Backbone.js, jQuery, and plain-old DOM.
-"""
-
-import os
-
-from telemetry import test
-from telemetry.page import page_measurement
-from telemetry.page import page_set
-from telemetry.value import scalar
-
-
-class DoYouEvenBenchMeasurement(page_measurement.PageMeasurement):
-
- def MeasurePage(self, _, tab, results):
- tab.WaitForDocumentReadyStateToBeComplete()
- # Tests are ran 5 iteration, results are displayed in the form of HTML
- # table. Each row represents timetaken in that iteration and adds rows for
- # Arithmetic Mean and 95th Percentile. Total 7 rows in the results table.
- tab.WaitForJavaScriptExpression(
- 'document.getElementsByTagName("tr").length >= 7', 200)
- # Parse results and result for each run including mean and 95th percentile.
- js_results = """ function JsResults() {
- var _result = {}
- _rows = document.getElementsByTagName("tr");
- for(var i=0; i< _rows.length; i++) {
- if (_rows[i].cells[0].innerText.indexOf("95th Percentile") == -1) {
- _result[_rows[i].cells[0].innerText] = _rows[i].cells[1].innerText;
- }
- }
- return _result;
- }; JsResults();"""
- results_log = tab.EvaluateJavaScript(js_results)
- for name, value in results_log.iteritems():
- score = float(value.replace('ms', '').strip())
- # Add time taken for each iteration to run tests.
- if name != 'Arithmetic Mean':
- results.Add(name, 'ms', score, data_type='unimportant')
- else:
- results.AddSummaryValue(scalar.ScalarValue(None, name, 'ms', score))
-
-class DoYouEvenBench(test.Test):
- """DoYouEvenBench benchmark related to DOMs using JS frameworks."""
- test = DoYouEvenBenchMeasurement
-
- def CreatePageSet(self, options):
- ps = page_set.PageSet(
- file_path=os.path.abspath(__file__),
- archive_data_file='../page_sets/data/doyouevenbench.json',
- make_javascript_deterministic=False)
- ps.AddPageWithDefaultRunNavigate(
- 'https://trac.webkit.org/export/164157/trunk/'
- 'PerformanceTests/DoYouEvenBench/Full.html')
- return ps
diff --git a/tools/perf/benchmarks/dromaeo.py b/tools/perf/benchmarks/dromaeo.py
index eb47892e20..f608e32485 100644
--- a/tools/perf/benchmarks/dromaeo.py
+++ b/tools/perf/benchmarks/dromaeo.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/perf/benchmarks/image_decoding.py b/tools/perf/benchmarks/image_decoding.py
index 7611f58631..bb1692a103 100644
--- a/tools/perf/benchmarks/image_decoding.py
+++ b/tools/perf/benchmarks/image_decoding.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/perf/benchmarks/jetstream.py b/tools/perf/benchmarks/jetstream.py
new file mode 100644
index 0000000000..bd8b2bf9ce
--- /dev/null
+++ b/tools/perf/benchmarks/jetstream.py
@@ -0,0 +1,83 @@
+# 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.
+
+"""Runs Apple's JetStream benchmark.
+
+JetStream combines a variety of JavaScript benchmarks, covering a variety of
+advanced workloads and programming techniques, and reports a single score that
+balances them using geometric mean.
+
+Each benchmark measures a distinct workload, and no single optimization
+technique is sufficient to speed up all benchmarks. Latency tests measure that
+a web application can start up quickly, ramp up to peak performance quickly,
+and run smoothly without interruptions. Throughput tests measure the sustained
+peak performance of a web application, ignoring ramp-up time and spikes in
+smoothness. Some benchmarks demonstrate tradeoffs, and aggressive or
+specialized optimization for one benchmark might make another benchmark slower.
+"""
+
+import json
+import os
+
+from telemetry import test
+from telemetry.page import page_measurement
+from telemetry.page import page_set
+from telemetry.util import statistics
+from telemetry.value import scalar
+
+
+class _JetstreamMeasurement(page_measurement.PageMeasurement):
+ def __init__(self):
+ super(_JetstreamMeasurement, self).__init__()
+
+ def WillNavigateToPage(self, page, tab):
+ page.script_to_evaluate_on_commit = """
+ var __results = [];
+ var __real_log = window.console.log;
+ window.console.log = function() {
+ __results.push(Array.prototype.join.call(arguments, ' '));
+ __real_log.apply(this, arguments);
+ }
+ """
+
+ def MeasurePage(self, page, tab, results):
+ get_results_js = """
+ (function() {
+ for (var i = 0; i < __results.length; i++) {
+ if (!__results[i].indexOf('Raw results: ')) return __results[i];
+ }
+ return null;
+ })();
+ """
+
+ tab.WaitForDocumentReadyStateToBeComplete()
+ tab.EvaluateJavaScript('JetStream.start()')
+ tab.WaitForJavaScriptExpression(get_results_js, 600)
+
+ result = tab.EvaluateJavaScript(get_results_js)
+ result = json.loads(result.partition(': ')[2])
+
+ all_scores = []
+ for k, v in result.iteritems():
+ results.Add(k.replace('.', '_'), 'score', v['result'],
+ data_type='unimportant')
+ # Collect all test scores to compute geometric mean.
+ all_scores.extend(v['result'])
+ total = statistics.GeometricMean(all_scores)
+ results.AddSummaryValue(
+ scalar.ScalarValue(None, 'Score', 'score', total))
+
+
+@test.Disabled('android') # Crashes on GN.
+@test.Disabled('xp') # Crashes on Win XP. See crbug.com/381742 for an example.
+class Jetstream(test.Test):
+ test = _JetstreamMeasurement
+
+ def CreatePageSet(self, options):
+ ps = page_set.PageSet(
+ archive_data_file='../page_sets/data/jetstream.json',
+ make_javascript_deterministic=False,
+ file_path=os.path.abspath(__file__))
+ ps.AddPageWithDefaultRunNavigate('http://browserbench.org/JetStream/')
+ return ps
diff --git a/tools/perf/benchmarks/jsgamebench.py b/tools/perf/benchmarks/jsgamebench.py
index fbb9cbacbb..762e8ba496 100644
--- a/tools/perf/benchmarks/jsgamebench.py
+++ b/tools/perf/benchmarks/jsgamebench.py
@@ -1,8 +1,14 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
-"""Runs Facebook's JSGameBench benchmark."""
+"""Runs Facebook's JSGameBench benchmark.
+
+As of May 14, 2014, JSGameBench is no longer maintained. See README.md:
+https://github.com/facebookarchive/jsgamebench
+
+The benchmark is kept here for historical purposes but is disabled on the bots.
+"""
import os
@@ -25,7 +31,7 @@ class _JsgamebenchMeasurement(page_measurement.PageMeasurement):
results.Add('Score', 'score (bigger is better)', result)
-@test.Disabled('linux') # crbug.com/365237
+@test.Disabled
class Jsgamebench(test.Test):
"""Counts how many animating sprites can move around on the screen at once."""
test = _JsgamebenchMeasurement
diff --git a/tools/perf/benchmarks/kraken.py b/tools/perf/benchmarks/kraken.py
index 0401862cb0..4843115205 100644
--- a/tools/perf/benchmarks/kraken.py
+++ b/tools/perf/benchmarks/kraken.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/perf/benchmarks/memory.py b/tools/perf/benchmarks/memory.py
index b009305f77..cc5e464f83 100644
--- a/tools/perf/benchmarks/memory.py
+++ b/tools/perf/benchmarks/memory.py
@@ -1,29 +1,33 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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 import test
from measurements import memory
+from page_sets import mobile_memory
+from page_sets import top_25
+from page_sets import top_desktop_sites_2012Q3
+from page_sets import tough_dom_memory_cases
@test.Disabled('android') # crbug.com/370977
class MemoryMobile(test.Test):
test = memory.Memory
- page_set = 'page_sets/mobile_memory.py'
+ page_set = mobile_memory.MobileMemoryPageSet()
class MemoryTop25(test.Test):
test = memory.Memory
- page_set = 'page_sets/top_25.py'
+ page_set = top_25.Top25PageSet()
class Reload2012Q3(test.Test):
tag = 'reload'
test = memory.Memory
- page_set = 'page_sets/top_desktop_sites_2012Q3.py'
+ page_set = top_desktop_sites_2012Q3.Top2012Q3PageSet()
@test.Disabled('android') # crbug.com/371153
class MemoryToughDomMemoryCases(test.Test):
test = memory.Memory
- page_set = 'page_sets/tough_dom_memory_cases.py'
+ page_set = tough_dom_memory_cases.ToughDomMemoryCasesPageSet()
diff --git a/tools/perf/benchmarks/memory_pressure.py b/tools/perf/benchmarks/memory_pressure.py
index e1e21812e1..f8f76bbc6c 100644
--- a/tools/perf/benchmarks/memory_pressure.py
+++ b/tools/perf/benchmarks/memory_pressure.py
@@ -5,6 +5,8 @@
from telemetry import test
from measurements import memory_pressure
+
+@test.Disabled('android') # crbug.com/379561
class MemoryPressure(test.Test):
test = memory_pressure.MemoryPressure
page_set = 'page_sets/typical_25.py'
diff --git a/tools/perf/benchmarks/octane.py b/tools/perf/benchmarks/octane.py
index 4fc6a3e8d0..c53b63bce7 100644
--- a/tools/perf/benchmarks/octane.py
+++ b/tools/perf/benchmarks/octane.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/perf/benchmarks/page_cycler.py b/tools/perf/benchmarks/page_cycler.py
index 1a62a89613..aafd5e961f 100644
--- a/tools/perf/benchmarks/page_cycler.py
+++ b/tools/perf/benchmarks/page_cycler.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
@@ -36,7 +36,7 @@ class PageCyclerIntlHiRu(test.Test):
options = {'pageset_repeat': 10}
-@test.Disabled('win') # crbug.com/330909
+@test.Disabled('android', 'win') # crbug.com/379564, crbug.com/330909
class PageCyclerIntlJaZh(test.Test):
test = page_cycler.PageCycler
page_set = 'page_sets/intl_ja_zh.py'
diff --git a/tools/perf/benchmarks/robohornet_pro.py b/tools/perf/benchmarks/robohornet_pro.py
index f8a3e38eab..99f3dc43e7 100644
--- a/tools/perf/benchmarks/robohornet_pro.py
+++ b/tools/perf/benchmarks/robohornet_pro.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/perf/benchmarks/session_restore.py b/tools/perf/benchmarks/session_restore.py
index a5f2a8ca90..98af7dd25e 100644
--- a/tools/perf/benchmarks/session_restore.py
+++ b/tools/perf/benchmarks/session_restore.py
@@ -2,13 +2,35 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import os
+import tempfile
+
from measurements import session_restore
+from measurements import session_restore_with_url
+from profile_creators import small_profile_creator
from telemetry import test
+from telemetry.page import profile_generator
+
+
+class _SessionRestoreTest(test.Test):
+
+ @classmethod
+ def ProcessCommandLineArgs(cls, parser, args):
+ super(_SessionRestoreTest, cls).ProcessCommandLineArgs(parser, args)
+ profile_type = 'small_profile'
+ if not args.browser_options.profile_dir:
+ profile_dir = os.path.join(tempfile.gettempdir(), profile_type)
+ if not os.path.exists(profile_dir):
+ new_args = args.Copy()
+ new_args.pageset_repeat = 1
+ new_args.output_dir = profile_dir
+ profile_generator.GenerateProfiles(
+ small_profile_creator.SmallProfileCreator, profile_type, new_args)
+ args.browser_options.profile_dir = os.path.join(profile_dir, profile_type)
-# crbug.com/325479: Disabling this test for now since it never ran before.
-@test.Disabled('android', 'linux')
-class SessionRestoreColdTypical25(test.Test):
+@test.Disabled('android') # crbug.com/325479
+class SessionRestoreColdTypical25(_SessionRestoreTest):
tag = 'cold'
test = session_restore.SessionRestore
page_set = 'page_sets/typical_25.py'
@@ -16,9 +38,30 @@ class SessionRestoreColdTypical25(test.Test):
'pageset_repeat': 5}
-class SessionRestoreWarmTypical25(test.Test):
+@test.Disabled('android') # crbug.com/325479
+class SessionRestoreWarmTypical25(_SessionRestoreTest):
tag = 'warm'
test = session_restore.SessionRestore
page_set = 'page_sets/typical_25.py'
options = {'warm': True,
'pageset_repeat': 20}
+
+
+@test.Disabled('android') # crbug.com/325479
+class SessionRestoreWithUrlCold(_SessionRestoreTest):
+ """Measure Chrome cold session restore with startup URLs."""
+ tag = 'cold'
+ test = session_restore_with_url.SessionRestoreWithUrl
+ page_set = 'page_sets/startup_pages.py'
+ options = {'cold': True,
+ 'pageset_repeat': 5}
+
+
+@test.Disabled('android') # crbug.com/325479
+class SessionRestoreWithUrlWarm(_SessionRestoreTest):
+ """Measure Chrome warm session restore with startup URLs."""
+ tag = 'warm'
+ test = session_restore_with_url.SessionRestoreWithUrl
+ page_set = 'page_sets/startup_pages.py'
+ options = {'warm': True,
+ 'pageset_repeat': 10}
diff --git a/tools/perf/benchmarks/session_restore_with_url.py b/tools/perf/benchmarks/session_restore_with_url.py
deleted file mode 100644
index d4914e7fca..0000000000
--- a/tools/perf/benchmarks/session_restore_with_url.py
+++ /dev/null
@@ -1,24 +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 import test
-
-from measurements import session_restore_with_url
-
-
-class SessionRestoreWithUrlCold(test.Test):
- """Measure Chrome cold session restore with startup URLs."""
- tag = 'cold'
- test = session_restore_with_url.SessionRestoreWithUrl
- page_set = 'page_sets/startup_pages.py'
- options = {'cold': True,
- 'pageset_repeat': 5}
-
-class SessionRestoreWithUrlWarm(test.Test):
- """Measure Chrome warm session restore with startup URLs."""
- tag = 'warm'
- test = session_restore_with_url.SessionRestoreWithUrl
- page_set = 'page_sets/startup_pages.py'
- options = {'warm': True,
- 'pageset_repeat': 10}
-
diff --git a/tools/perf/benchmarks/smoothness.py b/tools/perf/benchmarks/smoothness.py
index e98e6f1e29..078639e386 100644
--- a/tools/perf/benchmarks/smoothness.py
+++ b/tools/perf/benchmarks/smoothness.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/perf/benchmarks/spaceport.py b/tools/perf/benchmarks/spaceport.py
index fa16a38247..cd4d773d35 100644
--- a/tools/perf/benchmarks/spaceport.py
+++ b/tools/perf/benchmarks/spaceport.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/perf/benchmarks/speedometer.py b/tools/perf/benchmarks/speedometer.py
new file mode 100644
index 0000000000..260d55e91f
--- /dev/null
+++ b/tools/perf/benchmarks/speedometer.py
@@ -0,0 +1,47 @@
+# 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.
+
+"""Apple's Speedometer performance benchmark.
+
+Speedometer measures simulated user interactions in web applications.
+
+The current benchmark uses TodoMVC to simulate user actions for adding,
+completing, and removing to-do items. Speedometer repeats the same actions using
+DOM APIs - a core set of web platform APIs used extensively in web applications-
+as well as six popular JavaScript frameworks: Ember.js, Backbone.js, jQuery,
+AngularJS, React, and Flight. Many of these frameworks are used on the most
+popular websites in the world, such as Facebook and Twitter. The performance of
+these types of operations depends on the speed of the DOM APIs, the JavaScript
+engine, CSS style resolution, layout, and other technologies.
+"""
+
+import os
+
+from telemetry import test
+from telemetry.page import page_measurement
+from telemetry.page import page_set
+
+
+class SpeedometerMeasurement(page_measurement.PageMeasurement):
+
+ def MeasurePage(self, _, tab, results):
+ tab.WaitForDocumentReadyStateToBeComplete()
+ tab.ExecuteJavaScript('benchmarkClient.iterationCount = 10; startTest();')
+ tab.WaitForJavaScriptExpression(
+ 'benchmarkClient._finishedTestCount == benchmarkClient.testsCount', 600)
+ results.Add(
+ 'Total', 'ms', tab.EvaluateJavaScript('benchmarkClient._timeValues'))
+
+
+@test.Disabled('android') # Times out
+class Speedometer(test.Test):
+ test = SpeedometerMeasurement
+
+ def CreatePageSet(self, options):
+ ps = page_set.PageSet(
+ file_path=os.path.abspath(__file__),
+ archive_data_file='../page_sets/data/speedometer.json',
+ make_javascript_deterministic=False)
+ ps.AddPageWithDefaultRunNavigate('http://browserbench.org/Speedometer/')
+ return ps
diff --git a/tools/perf/benchmarks/sunspider.py b/tools/perf/benchmarks/sunspider.py
index a7ce2b0e87..776eee2bef 100644
--- a/tools/perf/benchmarks/sunspider.py
+++ b/tools/perf/benchmarks/sunspider.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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 collections
diff --git a/tools/perf/benchmarks/tab_switching.py b/tools/perf/benchmarks/tab_switching.py
index d04cafe407..0a16fb6be8 100644
--- a/tools/perf/benchmarks/tab_switching.py
+++ b/tools/perf/benchmarks/tab_switching.py
@@ -11,11 +11,14 @@ class TabSwitchingTop10(test.Test):
test = tab_switching.TabSwitching
page_set = 'page_sets/top_10.py'
+
class TabSwitchingFiveBlankTabs(test.Test):
test = tab_switching.TabSwitching
page_set = 'page_sets/five_blank_pages.py'
options = {'pageset_repeat': 10}
+
+@test.Disabled('android') # crbug.com/379561
class TabSwitchingToughEnergyCases(test.Test):
test = tab_switching.TabSwitching
page_set = 'page_sets/tough_energy_cases.py'
diff --git a/tools/perf/benchmarks/thread_times.py b/tools/perf/benchmarks/thread_times.py
index 06fb468b50..a2d97aa34e 100644
--- a/tools/perf/benchmarks/thread_times.py
+++ b/tools/perf/benchmarks/thread_times.py
@@ -7,7 +7,6 @@ from benchmarks import silk_flags
from measurements import thread_times
-@test.Disabled('android') # crbug.com/355952
class ThreadTimesKeySilkCases(test.Test):
"""Measures timeline metrics while performing smoothness action on key silk
cases."""
@@ -16,7 +15,6 @@ class ThreadTimesKeySilkCases(test.Test):
options = {"report_silk_results": True}
-@test.Disabled('android') # crbug.com/355952
class ThreadTimesFastPathKeySilkCases(test.Test):
"""Measures timeline metrics while performing smoothness action on key silk
cases using bleeding edge rendering fast paths."""
diff --git a/tools/perf/measurements/image_decoding.py b/tools/perf/measurements/image_decoding.py
index 867459cdc8..7d89c4753c 100644
--- a/tools/perf/measurements/image_decoding.py
+++ b/tools/perf/measurements/image_decoding.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/perf/measurements/memory.py b/tools/perf/measurements/memory.py
index 0ce01f0e23..cd40199c15 100644
--- a/tools/perf/measurements/memory.py
+++ b/tools/perf/measurements/memory.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/perf/measurements/page_cycler.py b/tools/perf/measurements/page_cycler.py
index 37f9ab22ea..bb394b089b 100644
--- a/tools/perf/measurements/page_cycler.py
+++ b/tools/perf/measurements/page_cycler.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/perf/measurements/rasterize_and_record_micro.py b/tools/perf/measurements/rasterize_and_record_micro.py
index 8728d1705c..d1182e1cce 100644
--- a/tools/perf/measurements/rasterize_and_record_micro.py
+++ b/tools/perf/measurements/rasterize_and_record_micro.py
@@ -11,7 +11,7 @@ from telemetry.page import page_test
class RasterizeAndRecordMicro(page_measurement.PageMeasurement):
def __init__(self):
- super(RasterizeAndRecordMicro, self).__init__('', True)
+ super(RasterizeAndRecordMicro, self).__init__('')
self._chrome_branch_number = None
@classmethod
diff --git a/tools/perf/measurements/session_restore.py b/tools/perf/measurements/session_restore.py
index ff210b4f3b..46d4019da8 100644
--- a/tools/perf/measurements/session_restore.py
+++ b/tools/perf/measurements/session_restore.py
@@ -1,13 +1,16 @@
# 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 collections
from measurements import startup
from metrics import cpu
+from metrics import histogram_util
from metrics import startup_metric
from telemetry.core import util
+
class SessionRestore(startup.Startup):
"""Performs a measurement of Chromium's Session restore performance.
@@ -23,14 +26,20 @@ class SessionRestore(startup.Startup):
def CustomizeBrowserOptions(self, options):
super(SessionRestore, self).CustomizeBrowserOptions(options)
+ histogram_util.CustomizeBrowserOptions(options)
options.AppendExtraBrowserArgs([
'--restore-last-session'
])
def TabForPage(self, page, browser):
# Detect that the session restore has completed.
- util.WaitFor(lambda: len(browser.tabs), 30)
- return browser.tabs[0]
+ util.WaitFor(lambda: browser.tabs and
+ histogram_util.GetHistogramCount(
+ histogram_util.BROWSER_HISTOGRAM,
+ 'SessionRestore.AllTabsLoaded',
+ browser.foreground_tab),
+ 30)
+ return browser.foreground_tab
def CanRunForPage(self, page):
# No matter how many pages in the pageset, just perform one test iteration.
@@ -59,7 +68,7 @@ class SessionRestore(startup.Startup):
self._cpu_metric.Start(None, None)
def MeasurePage(self, page, tab, results):
- tab.browser.foreground_tab.WaitForDocumentReadyStateToBeComplete()
+ tab.WaitForDocumentReadyStateToBeComplete()
# Record CPU usage from browser start to when the foreground page is loaded.
self._cpu_metric.Stop(None, None)
diff --git a/tools/perf/measurements/skpicture_printer.py b/tools/perf/measurements/skpicture_printer.py
index 152d3ec8d8..de2a761e1d 100644
--- a/tools/perf/measurements/skpicture_printer.py
+++ b/tools/perf/measurements/skpicture_printer.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
import glob
diff --git a/tools/perf/measurements/smoothness.py b/tools/perf/measurements/smoothness.py
index 9ca784c733..48ab7b1ea3 100644
--- a/tools/perf/measurements/smoothness.py
+++ b/tools/perf/measurements/smoothness.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/perf/measurements/smoothness_controller.py b/tools/perf/measurements/smoothness_controller.py
index fd38609fa0..0739a8d177 100644
--- a/tools/perf/measurements/smoothness_controller.py
+++ b/tools/perf/measurements/smoothness_controller.py
@@ -23,6 +23,7 @@ class SmoothnessController(object):
def __init__(self):
self._timeline_model = None
self._tracing_timeline_data = None
+ self._interaction = None
def Start(self, page, tab):
custom_categories = ['webkit.console', 'benchmark']
@@ -32,12 +33,12 @@ class SmoothnessController(object):
tab.browser.platform.StartRawDisplayFrameRateMeasurement()
# Start the smooth marker for all smooth actions.
runner = action_runner.ActionRunner(tab)
- runner.BeginInteraction(RUN_SMOOTH_ACTIONS, [tir_module.IS_SMOOTH])
+ self._interaction = runner.BeginInteraction(
+ RUN_SMOOTH_ACTIONS, is_smooth=True)
def Stop(self, tab):
# End the smooth marker for all smooth actions.
- runner = action_runner.ActionRunner(tab)
- runner.EndInteraction(RUN_SMOOTH_ACTIONS, [tir_module.IS_SMOOTH])
+ self._interaction.End()
# Stop tracing for smoothness metric.
if tab.browser.platform.IsRawDisplayFrameRateSupported():
tab.browser.platform.StopRawDisplayFrameRateMeasurement()
diff --git a/tools/perf/measurements/smoothness_unittest.py b/tools/perf/measurements/smoothness_unittest.py
index 0aba865864..55cd39edb9 100644
--- a/tools/perf/measurements/smoothness_unittest.py
+++ b/tools/perf/measurements/smoothness_unittest.py
@@ -106,19 +106,12 @@ class SmoothnessUnitTest(
self.assertEquals(len(mostly_smooth), 1)
self.assertGreaterEqual(mostly_smooth[0].GetRepresentativeNumber(), 0)
- mean_mouse_wheel_latency = results.FindAllPageSpecificValuesNamed(
- 'mean_mouse_wheel_latency')
- if mean_mouse_wheel_latency:
- self.assertEquals(len(mean_mouse_wheel_latency), 1)
+ mean_input_event_latency = results.FindAllPageSpecificValuesNamed(
+ 'mean_input_event_latency')
+ if mean_input_event_latency:
+ self.assertEquals(len(mean_input_event_latency), 1)
self.assertGreater(
- mean_mouse_wheel_latency[0].GetRepresentativeNumber(), 0)
-
- mean_touch_scroll_latency = results.FindAllPageSpecificValuesNamed(
- 'mean_touch_scroll_latency')
- if mean_touch_scroll_latency:
- self.assertEquals(len(mean_touch_scroll_latency), 1)
- self.assertGreater(
- mean_touch_scroll_latency[0].GetRepresentativeNumber(), 0)
+ mean_input_event_latency[0].GetRepresentativeNumber(), 0)
def testSmoothnessForPageWithNoGesture(self):
ps = self.CreateEmptyPageSet()
diff --git a/tools/perf/measurements/timeline_controller.py b/tools/perf/measurements/timeline_controller.py
index aa1c6bbab6..b34ec4fa39 100644
--- a/tools/perf/measurements/timeline_controller.py
+++ b/tools/perf/measurements/timeline_controller.py
@@ -19,6 +19,7 @@ class TimelineController(object):
self._model = None
self._renderer_process = None
self._smooth_records = []
+ self._interaction = None
def Start(self, page, tab):
"""Starts gathering timeline data.
@@ -37,12 +38,12 @@ class TimelineController(object):
tab.browser.StartTracing(','.join(categories))
# Start the smooth marker for all actions.
runner = action_runner.ActionRunner(tab)
- runner.BeginInteraction(RUN_SMOOTH_ACTIONS, [tir_module.IS_SMOOTH])
+ self._interaction = runner.BeginInteraction(
+ RUN_SMOOTH_ACTIONS, is_smooth=True)
def Stop(self, tab):
# End the smooth marker for all actions.
- runner = action_runner.ActionRunner(tab)
- runner.EndInteraction(RUN_SMOOTH_ACTIONS, [tir_module.IS_SMOOTH])
+ self._interaction.End()
# Stop tracing.
timeline_data = tab.browser.StopTracing()
self._model = TimelineModel(timeline_data)
diff --git a/tools/perf/page_sets/PRESUBMIT.py b/tools/perf/page_sets/PRESUBMIT.py
index 98623e7e32..0ad52734a4 100644
--- a/tools/perf/page_sets/PRESUBMIT.py
+++ b/tools/perf/page_sets/PRESUBMIT.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/perf/page_sets/__init__.py b/tools/perf/page_sets/__init__.py
index 96196cffb2..efcc9c35d2 100644
--- a/tools/perf/page_sets/__init__.py
+++ b/tools/perf/page_sets/__init__.py
@@ -1,3 +1,3 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/perf/page_sets/calendar_forward_backward.py b/tools/perf/page_sets/calendar_forward_backward.py
index 0e369a3b86..f4ca483ef4 100644
--- a/tools/perf/page_sets/calendar_forward_backward.py
+++ b/tools/perf/page_sets/calendar_forward_backward.py
@@ -32,16 +32,13 @@ class CalendarForwardBackwardPage(page_module.Page):
'condition': 'element',
'selector': 'div[class~="navForward"]'
}))
- action_runner.RunAction(JavascriptAction(
- {
- 'expression': '''
- (function() {
- var elem = document.createElement('meta');
- elem.name='viewport';
- elem.content='initial-scale=1';
- document.body.appendChild(elem);
- })();'''
- }))
+ action_runner.ExecuteJavaScript('''
+ (function() {
+ var elem = document.createElement('meta');
+ elem.name='viewport';
+ elem.content='initial-scale=1';
+ document.body.appendChild(elem);
+ })();''')
def RunEndure(self, action_runner):
action_runner.RunAction(ClickElementAction(
diff --git a/tools/perf/page_sets/data/doyouevenbench.json b/tools/perf/page_sets/data/jetstream.json
index abb6ce3218..cc59cf6dc8 100644
--- a/tools/perf/page_sets/data/doyouevenbench.json
+++ b/tools/perf/page_sets/data/jetstream.json
@@ -1,8 +1,8 @@
{
"description": "Describes the Web Page Replay archives for a page set. Don't edit by hand! Use record_wpr for updating.",
"archives": {
- "doyouevenbench_000.wpr": [
- "https://trac.webkit.org/export/164157/trunk/PerformanceTests/DoYouEvenBench/Full.html"
+ "jetstream_000.wpr": [
+ "http://browserbench.org/JetStream/"
]
}
} \ No newline at end of file
diff --git a/tools/perf/page_sets/data/jetstream_000.wpr.sha1 b/tools/perf/page_sets/data/jetstream_000.wpr.sha1
new file mode 100644
index 0000000000..c37a279f9b
--- /dev/null
+++ b/tools/perf/page_sets/data/jetstream_000.wpr.sha1
@@ -0,0 +1 @@
+1212f1ea3fc3e8e2f2a6694032e86fc036cad108 \ No newline at end of file
diff --git a/tools/perf/page_sets/data/speedometer.json b/tools/perf/page_sets/data/speedometer.json
new file mode 100644
index 0000000000..676d6ae3c4
--- /dev/null
+++ b/tools/perf/page_sets/data/speedometer.json
@@ -0,0 +1,8 @@
+{
+ "description": "Describes the Web Page Replay archives for a page set. Don't edit by hand! Use record_wpr for updating.",
+ "archives": {
+ "speedometer_000.wpr": [
+ "http://browserbench.org/Speedometer/"
+ ]
+ }
+} \ No newline at end of file
diff --git a/tools/perf/page_sets/data/speedometer_000.wpr.sha1 b/tools/perf/page_sets/data/speedometer_000.wpr.sha1
new file mode 100644
index 0000000000..53885253db
--- /dev/null
+++ b/tools/perf/page_sets/data/speedometer_000.wpr.sha1
@@ -0,0 +1 @@
+d9a5aa1403c33b623aafdcaa3be65a3edc568499 \ No newline at end of file
diff --git a/tools/perf/page_sets/data/tough_compositor_cases.json b/tools/perf/page_sets/data/tough_compositor_cases.json
index 0eda9eb4f1..f73567c9b6 100644
--- a/tools/perf/page_sets/data/tough_compositor_cases.json
+++ b/tools/perf/page_sets/data/tough_compositor_cases.json
@@ -1,14 +1,18 @@
{
"description": "Describes the Web Page Replay archives for a page set. Don't edit by hand! Use record_wpr for updating.",
"archives": {
- "tough_compositor_cases_000.wpr": [
+ "tough_compositor_cases_001.wpr": [
"http://jsbin.com/pixavefe/1/quiet?CC_SCROLL_TEXT_ONLY",
- "http://jsbin.com/wixadinu/1/quiet?JS_SCROLL_TEXT_ONLY",
+ "http://jsbin.com/wixadinu/2/quiet?JS_SCROLL_TEXT_ONLY",
"http://jsbin.com/yakagevo/1/quiet?CC_SCROLL_200_LAYER_GRID",
- "http://jsbin.com/jevibahi/1/quiet?JS_SCROLL_200_LAYER_GRID",
+ "http://jsbin.com/jevibahi/4/quiet?JS_SCROLL_200_LAYER_GRID",
"http://jsbin.com/falefice/1/quiet?CC_POSTER_CIRCLE",
"http://jsbin.com/giqafofe/1/quiet?JS_POSTER_CIRCLE",
"http://jsbin.com/beqojupo/1/quiet?JS_FULL_SCREEN_INVALIDATION"
+ ],
+ "tough_compositor_cases_000.wpr": [
+ "http://jsbin.com/wixadinu/1/quiet?JS_SCROLL_TEXT_ONLY",
+ "http://jsbin.com/jevibahi/1/quiet?JS_SCROLL_200_LAYER_GRID"
]
}
} \ No newline at end of file
diff --git a/tools/perf/page_sets/data/tough_compositor_cases_001.wpr.sha1 b/tools/perf/page_sets/data/tough_compositor_cases_001.wpr.sha1
new file mode 100644
index 0000000000..1b97dc81cb
--- /dev/null
+++ b/tools/perf/page_sets/data/tough_compositor_cases_001.wpr.sha1
@@ -0,0 +1 @@
+a39aa0f60060145e2a0a70693f6cea18551d7321 \ No newline at end of file
diff --git a/tools/perf/page_sets/data/typical_25.json b/tools/perf/page_sets/data/typical_25.json
index e038b6573f..4f619983b6 100644
--- a/tools/perf/page_sets/data/typical_25.json
+++ b/tools/perf/page_sets/data/typical_25.json
@@ -1,6 +1,9 @@
{
"description": "Describes the Web Page Replay archives for a page set. Don't edit by hand! Use record_wpr for updating.",
"archives": {
+ "typical_25_001.wpr": [
+ "http://www.nationalgeographic.com/"
+ ],
"typical_25_000.wpr": [
"http://www.nick.com/games",
"http://www.rei.com/",
@@ -17,7 +20,6 @@
"http://www.imdb.com/title/tt0910970/",
"http://www.flickr.com/search/?q=monkeys&f=hp",
"http://money.cnn.com/",
- "http://www.nationalgeographic.com/",
"http://premierleague.com",
"http://www.osubeavers.com/",
"http://walgreens.com",
@@ -29,4 +31,4 @@
"http://www.fda.gov"
]
}
-}
+} \ No newline at end of file
diff --git a/tools/perf/page_sets/data/typical_25_001.wpr.sha1 b/tools/perf/page_sets/data/typical_25_001.wpr.sha1
new file mode 100644
index 0000000000..0676eca8f1
--- /dev/null
+++ b/tools/perf/page_sets/data/typical_25_001.wpr.sha1
@@ -0,0 +1 @@
+17e3515c9a39dcf343c9fa2d914b3be4827c4254 \ No newline at end of file
diff --git a/tools/perf/page_sets/gmail_compose_discard.py b/tools/perf/page_sets/gmail_compose_discard.py
index 4bab258d45..264878ba90 100644
--- a/tools/perf/page_sets/gmail_compose_discard.py
+++ b/tools/perf/page_sets/gmail_compose_discard.py
@@ -29,18 +29,16 @@ class GmailComposeDiscardPage(page_module.Page):
}))
def ComposeClick(self, action_runner):
- action_runner.RunAction(JavascriptAction({
- 'expression': '''
+ action_runner.ExecuteJavaScript('''
var button=document.evaluate('//div[text()="COMPOSE"]',
- document,null,XPathResult.FIRST_ORDERED_NODE_TYPE,null)
+ document,null,XPathResult.FIRST_ORDERED_NODE_TYPE,null)
.singleNodeValue;
var mousedownevent=new MouseEvent('mousedown',true,true,window,0,0,0,0,0,
false,false,false,false,0,null);
var mouseupevent=new MouseEvent('mouseup',true,true,window,0,0,0,0,0,
false,false,false,false,0,null);
button.dispatchEvent(mousedownevent);
- button.dispatchEvent(mouseupevent);'''
- }))
+ button.dispatchEvent(mouseupevent);''')
def RunEndure(self, action_runner):
action_runner.RunAction(WaitAction(
diff --git a/tools/perf/page_sets/image_decoding_measurement.py b/tools/perf/page_sets/image_decoding_measurement.py
index 7f7c19f129..7b8fe61623 100644
--- a/tools/perf/page_sets/image_decoding_measurement.py
+++ b/tools/perf/page_sets/image_decoding_measurement.py
@@ -16,10 +16,7 @@ class ImageDecodingMeasurementPage(page_module.Page):
def RunNavigateSteps(self, action_runner):
action_runner.NavigateToPage(self)
- action_runner.RunAction(JavascriptAction(
- {
- 'expression': 'runBenchmark();'
- }))
+ action_runner.ExecuteJavaScript('runBenchmark();')
action_runner.RunAction(WaitAction(
{
'javascript': 'isDone'
diff --git a/tools/perf/page_sets/key_silk_cases.py b/tools/perf/page_sets/key_silk_cases.py
index 4a1482988f..a55bb4de80 100644
--- a/tools/perf/page_sets/key_silk_cases.py
+++ b/tools/perf/page_sets/key_silk_cases.py
@@ -5,7 +5,6 @@
from telemetry.page.actions.all_page_actions import *
from telemetry.page import page as page_module
from telemetry.page import page_set as page_set_module
-from telemetry.web_perf import timeline_interaction_record as tir_module
class KeySilkCasesPage(page_module.Page):
@@ -299,11 +298,11 @@ class Page16(KeySilkCasesPage):
}''',
'speed': 5000
}))
- action_runner.BeginInteraction('Wait', [tir_module.IS_SMOOTH])
+ interaction = action_runner.BeginInteraction('Wait', is_smooth=True)
action_runner.RunAction(WaitAction({
'javascript': 'document.getElementsByClassName("message").length < 18'
}))
- action_runner.EndInteraction('Wait', [tir_module.IS_SMOOTH])
+ interaction.End()
def RunSmoothness(self, action_runner):
self.SwipeToDismiss(action_runner)
@@ -391,11 +390,11 @@ class Page19(KeySilkCasesPage):
{
'selector': '#menu-button'
}))
- action_runner.BeginInteraction('Wait', [tir_module.IS_SMOOTH])
+ interaction = action_runner.BeginInteraction('Wait', is_smooth=True)
action_runner.RunAction(WaitAction({
'javascript': 'document.getElementById("nav-drawer").active'
}))
- action_runner.EndInteraction('Wait', [tir_module.IS_SMOOTH])
+ interaction.End()
def RunNavigateSteps(self, action_runner):
@@ -535,9 +534,9 @@ class Page23(KeySilkCasesPage):
'scroll_distance_function':
'function() { return window.innerHeight / 2; }'
}))
- action_runner.BeginInteraction('Wait', [tir_module.IS_SMOOTH])
+ interaction = action_runner.BeginInteraction('Wait', is_smooth=True)
action_runner.RunAction(WaitAction({'seconds' : 1}))
- action_runner.EndInteraction('Wait', [tir_module.IS_SMOOTH])
+ interaction.End()
class Page24(KeySilkCasesPage):
@@ -600,9 +599,9 @@ class Page25(KeySilkCasesPage):
callback(document.getElementById(':f'));
}'''
}))
- action_runner.BeginInteraction('Wait', [tir_module.IS_SMOOTH])
+ interaction = action_runner.BeginInteraction('Wait', is_smooth=True)
action_runner.RunAction(WaitAction({'seconds' : 1}))
- action_runner.EndInteraction('Wait', [tir_module.IS_SMOOTH])
+ interaction.End()
class Page26(KeySilkCasesPage):
diff --git a/tools/perf/page_sets/polymer.py b/tools/perf/page_sets/polymer.py
index dc04c15ca6..84b57d330f 100644
--- a/tools/perf/page_sets/polymer.py
+++ b/tools/perf/page_sets/polymer.py
@@ -92,10 +92,8 @@ class PolymerShadowPage(PolymerPage):
self.archive_data_file = 'data/polymer.json'
def RunSmoothness(self, action_runner):
- action_runner.RunAction(JavascriptAction(
- {
- 'expression': "document.getElementById('fab').scrollIntoView()"
- }))
+ action_runner.ExecuteJavaScript(
+ "document.getElementById('fab').scrollIntoView()")
action_runner.RunAction(WaitAction(
{
'seconds': 5
@@ -105,12 +103,8 @@ class PolymerShadowPage(PolymerPage):
def AnimateShadow(self, action_runner, eid):
for i in range(1, 6):
- action_runner.RunAction(JavascriptAction(
- {
- 'expression': '''
- document.getElementById("{0}").z = {1}
- '''.format(eid, i)
- }))
+ action_runner.ExecuteJavaScript(
+ 'document.getElementById("{0}").z = {1}'.format(eid, i))
action_runner.RunAction(WaitAction(
{
'seconds': 1
diff --git a/tools/perf/page_sets/top_10.py b/tools/perf/page_sets/top_10.py
index 34ffd1114b..0668d79116 100644
--- a/tools/perf/page_sets/top_10.py
+++ b/tools/perf/page_sets/top_10.py
@@ -49,12 +49,12 @@ class GoogleCalendar(SimpleScrollPage):
def RunNavigateSteps(self, action_runner):
super(GoogleCalendar, self).RunNavigateSteps(action_runner)
- action_runner.RunAction(JavascriptAction(
- { 'expression' :
- '(function() { var elem = document.createElement("meta");'
- 'elem.name="viewport";'
- 'elem.content="initial-scale=1";'
- 'document.body.appendChild(elem); })();'}))
+ action_runner.ExecuteJavaScript('''
+ (function() { var elem = document.createElement("meta");
+ elem.name="viewport";
+ elem.content="initial-scale=1";
+ document.body.appendChild(elem);
+ })();''')
action_runner.RunAction(WaitAction({'seconds' : 2}))
action_runner.RunAction(WaitAction({
'condition' : 'element', 'selector' : 'div[class~="navForward"]'}))
diff --git a/tools/perf/page_sets/top_25.py b/tools/perf/page_sets/top_25.py
index 9fead4bf2f..a437eb04a0 100644
--- a/tools/perf/page_sets/top_25.py
+++ b/tools/perf/page_sets/top_25.py
@@ -205,16 +205,13 @@ class GoogleCalendarPage(Top25Page):
'condition': 'element',
'selector': 'div[class~="navForward"]'
}))
- action_runner.RunAction(JavascriptAction(
- {
- 'expression': '''
- (function() {
- var elem = document.createElement('meta');
- elem.name='viewport';
- elem.content='initial-scale=1';
- document.body.appendChild(elem);
- })();'''
- }))
+ action_runner.ExecuteJavaScript('''
+ (function() {
+ var elem = document.createElement('meta');
+ elem.name='viewport';
+ elem.content='initial-scale=1';
+ document.body.appendChild(elem);
+ })();''')
action_runner.RunAction(WaitAction(
{
'seconds': 1
@@ -515,37 +512,17 @@ class BlogspotPage(Top25Page):
}))
def RunStressMemory(self, action_runner):
- action_runner.RunAction(ClickElementAction(
- {
- 'text' : 'accessibility',
- 'wait_until': {
- 'condition': 'navigate'
- }
- }))
+ action_runner.RunAction(ClickElementAction({'text' : 'accessibility'}))
+ action_runner.WaitForNavigate()
action_runner.RunAction(ScrollAction())
- action_runner.RunAction(ClickElementAction(
- {
- 'text' : 'advanced',
- 'wait_until': {
- 'condition': 'navigate'
- }
- }))
+ action_runner.RunAction(ClickElementAction({'text' : 'advanced'}))
+ action_runner.WaitForNavigate()
action_runner.RunAction(ScrollAction())
- action_runner.RunAction(ClickElementAction(
- {
- 'text' : 'beginner',
- 'wait_until': {
- 'condition': 'navigate'
- }
- }))
+ action_runner.RunAction(ClickElementAction({'text' : 'beginner'}))
+ action_runner.WaitForNavigate()
action_runner.RunAction(ScrollAction())
- action_runner.RunAction(ClickElementAction(
- {
- 'text' : 'Home',
- 'wait_until': {
- 'condition': 'navigate'
- }
- }))
+ action_runner.RunAction(ClickElementAction({'text' : 'Home'}))
+ action_runner.WaitForNavigate()
class WordpressPage(Top25Page):
@@ -572,30 +549,17 @@ class WordpressPage(Top25Page):
def RunStressMemory(self, action_runner):
action_runner.RunAction(ScrollAction())
action_runner.RunAction(ClickElementAction(
- {
- 'wait_until': {
- 'condition': 'navigate'
- },
- 'selector':
+ {'selector':
# pylint: disable=C0301
'a[href="http://en.blog.wordpress.com/2012/08/30/new-themes-able-and-sight/"]'
}))
+ action_runner.WaitForNavigate()
action_runner.RunAction(ScrollAction())
- action_runner.RunAction(ClickElementAction(
- {
- 'text' : 'Features',
- 'wait_until': {
- 'condition': 'navigate'
- }
- }))
+ action_runner.RunAction(ClickElementAction({'text' : 'Features'}))
+ action_runner.WaitForNavigate()
action_runner.RunAction(ScrollAction())
- action_runner.RunAction(ClickElementAction(
- {
- 'text' : 'News',
- 'wait_until': {
- 'condition': 'navigate'
- }
- }))
+ action_runner.RunAction(ClickElementAction({'text' : 'News'}))
+ action_runner.WaitForNavigate()
action_runner.RunAction(ScrollAction())
@@ -619,48 +583,33 @@ class FacebookPage(Top25Page):
}))
def RunStressMemory(self, action_runner):
- action_runner.RunAction(ClickElementAction(
- {
- 'text' : 'About',
- 'wait_until': {
- 'condition': 'navigate'
- }
- }))
+ action_runner.RunAction(ClickElementAction({'text' : 'About'}))
+ action_runner.WaitForNavigate()
action_runner.RunAction(ClickElementAction(
{
'text' : 'The Audacity of Hope',
- 'wait_until': {
- 'condition': 'navigate'
- }
}))
+ action_runner.WaitForNavigate()
action_runner.RunAction(ClickElementAction(
{
'text' : 'Back to Barack Obama\'s Timeline',
- 'wait_until': {
- 'condition': 'navigate'
- }
}))
+ action_runner.WaitForNavigate()
action_runner.RunAction(ClickElementAction(
{
'text' : 'About',
- 'wait_until': {
- 'condition': 'navigate'
- }
}))
+ action_runner.WaitForNavigate()
action_runner.RunAction(ClickElementAction(
{
'text' : 'Elected to U.S. Senate',
- 'wait_until': {
- 'condition': 'navigate'
- }
}))
+ action_runner.WaitForNavigate()
action_runner.RunAction(ClickElementAction(
{
'text' : 'Home',
- 'wait_until': {
- 'condition': 'navigate'
- }
}))
+ action_runner.WaitForNavigate()
def RunSmoothness(self, action_runner):
action_runner.RunAction(ScrollAction(
diff --git a/tools/perf/page_sets/tough_compositor_cases.py b/tools/perf/page_sets/tough_compositor_cases.py
index 9c08bafdba..b86e317d6e 100644
--- a/tools/perf/page_sets/tough_compositor_cases.py
+++ b/tools/perf/page_sets/tough_compositor_cases.py
@@ -39,7 +39,7 @@ class ToughCompositorWaitPage(ToughCompositorPage):
def RunSmoothness(self, action_runner):
# We scroll back and forth a few times to reduce noise in the tests.
- action_runner.RunAction(WaitAction({'seconds': 10}))
+ action_runner.RunAction(WaitAction({'seconds': 8}))
class ToughCompositorCasesPageSet(page_set_module.PageSet):
@@ -56,11 +56,11 @@ class ToughCompositorCasesPageSet(page_set_module.PageSet):
# Why: Baseline CC scrolling page. A long page with only text. """
'http://jsbin.com/pixavefe/1/quiet?CC_SCROLL_TEXT_ONLY',
# Why: Baseline JS scrolling page. A long page with only text. """
- 'http://jsbin.com/wixadinu/1/quiet?JS_SCROLL_TEXT_ONLY',
+ 'http://jsbin.com/wixadinu/2/quiet?JS_SCROLL_TEXT_ONLY',
# Why: Scroll by a large number of CC layers """
'http://jsbin.com/yakagevo/1/quiet?CC_SCROLL_200_LAYER_GRID',
# Why: Scroll by a large number of JS layers """
- 'http://jsbin.com/jevibahi/1/quiet?JS_SCROLL_200_LAYER_GRID',
+ 'http://jsbin.com/jevibahi/4/quiet?JS_SCROLL_200_LAYER_GRID',
]
wait_urls_list = [
diff --git a/tools/perf/page_sets/webrtc_cases.py b/tools/perf/page_sets/webrtc_cases.py
index aac321cc66..54c8f48b4f 100644
--- a/tools/perf/page_sets/webrtc_cases.py
+++ b/tools/perf/page_sets/webrtc_cases.py
@@ -28,10 +28,7 @@ class Page1(WebrtcCasesPage):
{
'seconds': 10
}))
- action_runner.RunAction(JavascriptAction(
- {
- 'expression': 'checkForErrors();'
- }))
+ action_runner.ExecuteJavaScript('checkForErrors();')
class Page2(WebrtcCasesPage):
diff --git a/tools/perf/profile_creators/__init__.py b/tools/perf/profile_creators/__init__.py
index f1e2bf49a7..6220954c33 100644
--- a/tools/perf/profile_creators/__init__.py
+++ b/tools/perf/profile_creators/__init__.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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."""
diff --git a/tools/perf/profile_creators/small_profile_creator.py b/tools/perf/profile_creators/small_profile_creator.py
index b9c2de8157..90c21bb478 100644
--- a/tools/perf/profile_creators/small_profile_creator.py
+++ b/tools/perf/profile_creators/small_profile_creator.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
@@ -32,6 +32,4 @@ class SmallProfileCreator(profile_creator.ProfileCreator):
return browser.tabs.New()
def MeasurePage(self, _, tab, results):
- # Can't use WaitForDocumentReadyStateToBeComplete() here due to
- # crbug.com/280750 .
- tab.WaitForDocumentReadyStateToBeInteractiveOrBetter()
+ tab.WaitForDocumentReadyStateToBeComplete()
diff --git a/tools/perf/unit-info.json b/tools/perf/unit-info.json
index 5ace7830ef..57a79a9d30 100644
--- a/tools/perf/unit-info.json
+++ b/tools/perf/unit-info.json
@@ -59,6 +59,10 @@
"improvement_direction": "up",
"why": "Higher frequencies are faster."
},
+ "janks": {
+ "improvement_direction": "down",
+ "why": "Fewer janks is better."
+ },
"kb": {
"improvement_direction": "down",
"why": "Synonym for KB, used in memory and io metrics."
diff --git a/tools/post_perf_builder_job.py b/tools/post_perf_builder_job.py
index b1e4e857e1..00262c95e5 100644
--- a/tools/post_perf_builder_job.py
+++ b/tools/post_perf_builder_job.py
@@ -26,7 +26,7 @@ TRY_SERVER_URL = 'http://build.chromium.org/p/tryserver.chromium'
# for posting build request to tryserver.
BISECT_BUILDER_HOST = 'master4.golo.chromium.org'
# 'try_job_port' on tryserver to post build request.
-BISECT_BUILDER_PORT = '8328'
+BISECT_BUILDER_PORT = 8328
# From buildbot.status.builder.
@@ -234,25 +234,26 @@ def GetBuildStatus(build_num, bot_name, builder_host, builder_port):
A tuple consists of build status (SUCCESS, FAILED or PENDING) and a link
to build status page on the waterfall.
"""
- # Gets the buildbot url for the given host and port.
- server_url = _GetBuildBotUrl(builder_host, builder_port)
- buildbot_url = BUILDER_JSON_URL % {'server_url': server_url,
- 'bot_name': bot_name,
- 'build_num': build_num
- }
- build_data = _GetBuildData(buildbot_url)
results_url = None
- if build_data:
- # Link to build on the buildbot showing status of build steps.
- results_url = BUILDER_HTML_URL % {'server_url': server_url,
- 'bot_name': bot_name,
- 'build_num': build_num
- }
- if _IsBuildFailed(build_data):
- return (FAILED, results_url)
-
- elif _IsBuildSuccessful(build_data):
- return (OK, results_url)
+ if build_num:
+ # Gets the buildbot url for the given host and port.
+ server_url = _GetBuildBotUrl(builder_host, builder_port)
+ buildbot_url = BUILDER_JSON_URL % {'server_url': server_url,
+ 'bot_name': bot_name,
+ 'build_num': build_num
+ }
+ build_data = _GetBuildData(buildbot_url)
+ if build_data:
+ # Link to build on the buildbot showing status of build steps.
+ results_url = BUILDER_HTML_URL % {'server_url': server_url,
+ 'bot_name': bot_name,
+ 'build_num': build_num
+ }
+ if _IsBuildFailed(build_data):
+ return (FAILED, results_url)
+
+ elif _IsBuildSuccessful(build_data):
+ return (OK, results_url)
return (PENDING, results_url)
diff --git a/tools/safely-roll-deps.py b/tools/safely-roll-deps.py
index 0e75715c32..e37fde43ee 100755
--- a/tools/safely-roll-deps.py
+++ b/tools/safely-roll-deps.py
@@ -142,7 +142,7 @@ def main():
prnt_subprocess.check_output(['git', 'commit', '-m', commit_msg, 'DEPS'])
prnt_subprocess.check_call(['git', 'diff', '--no-ext-diff',
options.upstream])
- upload_cmd = ['git', 'cl', 'upload']
+ upload_cmd = ['git', 'cl', 'upload', '--bypass-hooks']
if options.commit:
upload_cmd.append('--use-commit-queue')
if options.reviewers:
diff --git a/tools/telemetry/PRESUBMIT.py b/tools/telemetry/PRESUBMIT.py
index e7b66d64c9..52c88064f5 100644
--- a/tools/telemetry/PRESUBMIT.py
+++ b/tools/telemetry/PRESUBMIT.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
import os
diff --git a/tools/telemetry/docs/telemetry.core.browser_finder.html b/tools/telemetry/docs/telemetry.core.browser_finder.html
index 7ac001c2b8..f88a87955e 100644
--- a/tools/telemetry/docs/telemetry.core.browser_finder.html
+++ b/tools/telemetry/docs/telemetry.core.browser_finder.html
@@ -190,6 +190,6 @@ Raises:<br>
<font color="#ffffff" face="helvetica, arial"><big><strong>Data</strong></big></font></td></tr>
<tr><td bgcolor="#55aa55"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
-<td width="100%"><strong>ALL_BROWSER_TYPES</strong> = ['exact', 'release', 'release_x64', 'debug', 'debug_x64', 'canary', 'content-shell-debug', 'content-shell-debug_x64', 'content-shell-release', 'content-shell-release_x64', 'system', 'android-chrome-beta', 'android-chrome-dev', 'android-chromium-testshell', 'android-jb-system-chrome', 'android-chrome-canary', 'android-chrome', 'android-webview', 'android-content-shell', 'cros-chrome', ...]<br>
+<td width="100%"><strong>ALL_BROWSER_TYPES</strong> = ['exact', 'release', 'release_x64', 'debug', 'debug_x64', 'canary', 'content-shell-debug', 'content-shell-debug_x64', 'content-shell-release', 'content-shell-release_x64', 'system', 'android-chrome-beta', 'android-chrome-dev', 'android-chrome-shell', 'android-chromium-testshell', 'android-jb-system-chrome', 'android-chrome-canary', 'android-chrome', 'android-webview', 'android-content-shell', 'cros-chrome', ...]<br>
<strong>BROWSER_FINDERS</strong> = [&lt;module 'telemetry.core.backends.chrome.desktop_...core/backends/chrome/desktop_browser_finder.pyc'&gt;, &lt;module 'telemetry.core.backends.chrome.android_...core/backends/chrome/android_browser_finder.pyc'&gt;, &lt;module 'telemetry.core.backends.chrome.cros_bro...ry/core/backends/chrome/cros_browser_finder.pyc'&gt;, &lt;module 'telemetry.core.backends.webdriver.webdr.../webdriver/webdriver_desktop_browser_finder.pyc'&gt;]</td></tr></table>
-</body></html> \ No newline at end of file
+</body></html>
diff --git a/tools/telemetry/examples/telemetry_perf_test.py b/tools/telemetry/examples/telemetry_perf_test.py
index bb1d21a43b..6321911aef 100755
--- a/tools/telemetry/examples/telemetry_perf_test.py
+++ b/tools/telemetry/examples/telemetry_perf_test.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/__init__.py b/tools/telemetry/telemetry/__init__.py
index 4d3fdc0101..395ffe2f69 100644
--- a/tools/telemetry/telemetry/__init__.py
+++ b/tools/telemetry/telemetry/__init__.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/core/__init__.py b/tools/telemetry/telemetry/core/__init__.py
index 96196cffb2..efcc9c35d2 100644
--- a/tools/telemetry/telemetry/core/__init__.py
+++ b/tools/telemetry/telemetry/core/__init__.py
@@ -1,3 +1,3 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/core/backends/chrome/android_browser_finder.py b/tools/telemetry/telemetry/core/backends/chrome/android_browser_finder.py
index 33fd1fc31b..365a61db9f 100644
--- a/tools/telemetry/telemetry/core/backends/chrome/android_browser_finder.py
+++ b/tools/telemetry/telemetry/core/backends/chrome/android_browser_finder.py
@@ -30,6 +30,10 @@ CHROME_PACKAGE_NAMES = {
['org.chromium.chrome.shell',
android_browser_backend.ChromeShellBackendSettings,
'ChromeShell.apk'],
+ 'android-chrome-shell':
+ ['org.chromium.chrome.shell',
+ android_browser_backend.ChromeShellBackendSettings,
+ 'ChromeShell.apk'],
'android-webview':
['com.android.webview.chromium.shell',
android_browser_backend.WebviewBackendSettings,
@@ -220,13 +224,12 @@ def FindAllAvailableBrowsers(finder_options, logging=real_logging):
if ret:
logging.warn('Failed to taskset %d (%s)', pid, ret)
- if not os.environ.get('BUILDBOT_BUILDERNAME'):
- # Killing adbd before running tests has proven to make them less likely to
- # flake out during the test. We skip this if Telemetry is running under a
- # buildbot because build/android/test_runner.py wrapper already took care
- # of it before starting the shards.
- adb.RestartAdbdOnDevice()
- adb.WaitForDevicePm()
+ if not os.environ.get('BUILDBOT_BUILDERNAME'):
+ # Killing adbd before running tests has proven to make them less likely to
+ # flake out during the test. We skip this if Telemetry is running under a
+ # buildbot because build/android/test_runner.py wrapper already took care
+ # of it before starting the shards.
+ adb.RestartAdbdOnDevice()
packages = adb.RunShellCommand('pm list packages')
possible_browsers = []
diff --git a/tools/telemetry/telemetry/core/backends/chrome/chrome_browser_backend.py b/tools/telemetry/telemetry/core/backends/chrome/chrome_browser_backend.py
index 497ac73bcf..cc9d437806 100644
--- a/tools/telemetry/telemetry/core/backends/chrome/chrome_browser_backend.py
+++ b/tools/telemetry/telemetry/core/backends/chrome/chrome_browser_backend.py
@@ -89,6 +89,15 @@ class ChromeBrowserBackend(browser_backend.BrowserBackend):
args.append('--no-default-browser-check')
args.append('--no-first-run')
+ # TODO(tonyg): Telemetry runs on release build bots which enable DCHECKs.
+ # While, we'd really like for Chrome to be DCHECK clean, pragmatically, it
+ # is far from it and the Telemetry unittests are hitting DCHECKS so often
+ # that the flakiness is becoming untenable.
+ #
+ # We should remove this as soon as we're ready to get serious about the
+ # DCHECK problem and keep Chrome clean.
+ args.append('--silent-dump-on-dcheck')
+
# Turn on GPU benchmarking extension for all runs. The only side effect of
# the extension being on is that render stats are tracked. This is believed
# to be effectively free. And, by doing so here, it avoids us having to
diff --git a/tools/telemetry/telemetry/core/backends/chrome/cros_interface.py b/tools/telemetry/telemetry/core/backends/chrome/cros_interface.py
index b5add7d4e9..890e0b15ce 100644
--- a/tools/telemetry/telemetry/core/backends/chrome/cros_interface.py
+++ b/tools/telemetry/telemetry/core/backends/chrome/cros_interface.py
@@ -297,7 +297,8 @@ class CrOSInterface(object):
"""Returns the pid of the session_manager process, given the list of
processes."""
for pid, process, _, _ in procs:
- if process.startswith('/sbin/session_manager '):
+ argv = process.split()
+ if argv and os.path.basename(argv[0]) == 'session_manager':
return pid
return None
diff --git a/tools/telemetry/telemetry/core/backends/chrome/desktop_browser_backend.py b/tools/telemetry/telemetry/core/backends/chrome/desktop_browser_backend.py
index bfbc687314..a9f1fa5186 100644
--- a/tools/telemetry/telemetry/core/backends/chrome/desktop_browser_backend.py
+++ b/tools/telemetry/telemetry/core/backends/chrome/desktop_browser_backend.py
@@ -7,6 +7,7 @@ import glob
import heapq
import logging
import os
+import os.path
import shutil
import subprocess as subprocess
import sys
@@ -74,6 +75,20 @@ class DesktopBrowserBackend(chrome_browser_backend.ChromeBrowserBackend):
logging.info("Using profile directory:'%s'." % profile_dir)
shutil.rmtree(self._tmp_profile_dir)
shutil.copytree(profile_dir, self._tmp_profile_dir)
+ if self.browser_options.use_devtools_active_port:
+ # No matter whether we're using an existing profile directory or
+ # creating a new one, always delete the well-known file containing
+ # the active DevTools port number.
+ port_file = self._GetDevToolsActivePortPath()
+ if os.path.isfile(port_file):
+ try:
+ os.remove(port_file)
+ except Exception as e:
+ logging.critical('Unable to remove DevToolsActivePort file: %s' % e)
+ sys.exit(1)
+
+ def _GetDevToolsActivePortPath(self):
+ return os.path.join(self.profile_directory, 'DevToolsActivePort')
def _GetCrashServicePipeName(self):
# Ensure a unique pipe name by using the name of the temp dir.
@@ -119,11 +134,27 @@ class DesktopBrowserBackend(chrome_browser_backend.ChromeBrowserBackend):
if not self.IsBrowserRunning():
raise exceptions.ProcessGoneException(
"Return code: %d" % self._proc.returncode)
+ if self.browser_options.use_devtools_active_port:
+ # The Telemetry user selected the new code path to start DevTools on
+ # an ephemeral port. Wait for the well-known file containing the port
+ # number to exist.
+ port_file = self._GetDevToolsActivePortPath()
+ if not os.path.isfile(port_file):
+ # File isn't ready yet. Return false. Will retry.
+ return False
+ with open(port_file) as f:
+ port_string = f.read()
+ self._port = int(port_string)
+ logging.info('Discovered ephemeral port %s' % self._port)
return super(DesktopBrowserBackend, self).HasBrowserFinishedLaunching()
def GetBrowserStartupArgs(self):
args = super(DesktopBrowserBackend, self).GetBrowserStartupArgs()
- self._port = util.GetUnreservedAvailableLocalPort()
+ if self.browser_options.use_devtools_active_port:
+ self._port = 0
+ else:
+ self._port = util.GetUnreservedAvailableLocalPort()
+ logging.info('Requested remote debugging port: %d' % self._port)
args.append('--remote-debugging-port=%i' % self._port)
args.append('--enable-crash-reporter-for-testing')
args.append('--use-mock-keychain')
diff --git a/tools/telemetry/telemetry/core/backends/chrome/inspector_backend.py b/tools/telemetry/telemetry/core/backends/chrome/inspector_backend.py
index bd7680c073..5fe86c2091 100644
--- a/tools/telemetry/telemetry/core/backends/chrome/inspector_backend.py
+++ b/tools/telemetry/telemetry/core/backends/chrome/inspector_backend.py
@@ -74,15 +74,11 @@ class InspectorBackend(inspector_websocket.InspectorWebsocket):
@property
def url(self):
for c in self._browser_backend.ListInspectableContexts():
- if c['id'] == self.id:
+ if c['id'] == self._context['id']:
return c['url']
return None
@property
- def id(self):
- return self._context['id']
-
- @property
def debugger_url(self):
return self._context['webSocketDebuggerUrl']
@@ -158,8 +154,8 @@ class InspectorBackend(inspector_websocket.InspectorWebsocket):
# Page public methods.
- def PerformActionAndWaitForNavigate(self, action_function, timeout):
- self._page.PerformActionAndWaitForNavigate(action_function, timeout)
+ def WaitForNavigate(self, timeout):
+ self._page.WaitForNavigate(timeout)
def Navigate(self, url, script_to_evaluate_on_commit, timeout):
self._page.Navigate(url, script_to_evaluate_on_commit, timeout)
diff --git a/tools/telemetry/telemetry/core/backends/chrome/inspector_page.py b/tools/telemetry/telemetry/core/backends/chrome/inspector_page.py
index cd3a529de9..cd5d1a524e 100644
--- a/tools/telemetry/telemetry/core/backends/chrome/inspector_page.py
+++ b/tools/telemetry/telemetry/core/backends/chrome/inspector_page.py
@@ -30,7 +30,7 @@ class InspectorPage(object):
(not url == 'chrome://newtab/' and not url == 'about:blank'
and not 'parentId' in msg['params']['frame'])):
# Marks the navigation as complete and unblocks the
- # PerformActionAndWaitForNavigate call.
+ # WaitForNavigate call.
self._navigation_pending = False
def _OnClose(self):
@@ -70,16 +70,14 @@ class InspectorPage(object):
res = self._inspector_backend.SyncRequest(request, timeout)
assert len(res['result'].keys()) == 0
- def PerformActionAndWaitForNavigate(self, action_function, timeout=60):
- """Executes action_function, and waits for the navigation to complete.
+ def WaitForNavigate(self, timeout=60):
+ """Waits for the navigation to complete.
- action_function is expect to result in a navigation. This function returns
+ The current page is expect to be in a navigation. This function returns
when the navigation is complete or when the timeout has been exceeded.
"""
start_time = time.time()
remaining_time = timeout
-
- action_function()
self._navigation_pending = True
try:
while self._navigation_pending and remaining_time > 0:
@@ -99,17 +97,16 @@ class InspectorPage(object):
the page exists, but before any script on the page itself has executed.
"""
- def DoNavigate():
- self._SetScriptToEvaluateOnCommit(script_to_evaluate_on_commit)
- request = {
- 'method': 'Page.navigate',
- 'params': {
- 'url': url,
- }
- }
- self._inspector_backend.SyncRequest(request, timeout)
+ self._SetScriptToEvaluateOnCommit(script_to_evaluate_on_commit)
+ request = {
+ 'method': 'Page.navigate',
+ 'params': {
+ 'url': url,
+ }
+ }
+ self._inspector_backend.SyncRequest(request, timeout)
self._navigation_url = url
- self.PerformActionAndWaitForNavigate(DoNavigate, timeout)
+ self.WaitForNavigate(timeout)
def GetCookieByName(self, name, timeout=60):
"""Returns the value of the cookie by the given |name|."""
diff --git a/tools/telemetry/telemetry/core/backends/chrome/inspector_page_unittest.py b/tools/telemetry/telemetry/core/backends/chrome/inspector_page_unittest.py
index 0343920432..7408a092c6 100644
--- a/tools/telemetry/telemetry/core/backends/chrome/inspector_page_unittest.py
+++ b/tools/telemetry/telemetry/core/backends/chrome/inspector_page_unittest.py
@@ -21,14 +21,9 @@ class InspectorPageTest(tab_test_case.TabTestCase):
self._tab.EvaluateJavaScript('document.location.pathname;'),
'/page_with_link.html')
- custom_action_called = [False]
- def CustomAction():
- custom_action_called[0] = True
- self._tab.ExecuteJavaScript('document.getElementById("clickme").click();')
+ self._tab.ExecuteJavaScript('document.getElementById("clickme").click();')
+ self._tab.WaitForNavigate()
- self._tab.PerformActionAndWaitForNavigate(CustomAction)
-
- self.assertTrue(custom_action_called[0])
self.assertEquals(
self._tab.EvaluateJavaScript('document.location.pathname;'),
'/blank.html')
diff --git a/tools/telemetry/telemetry/core/backends/webdriver/webdriver_tab_backend.py b/tools/telemetry/telemetry/core/backends/webdriver/webdriver_tab_backend.py
index c65f70b3cd..07f7d6bbf0 100644
--- a/tools/telemetry/telemetry/core/backends/webdriver/webdriver_tab_backend.py
+++ b/tools/telemetry/telemetry/core/backends/webdriver/webdriver_tab_backend.py
@@ -66,9 +66,8 @@ class WebDriverTabBackend(object):
# Webdriver has no API for DOM status.
raise NotImplementedError()
- def PerformActionAndWaitForNavigate(self, action_function, _):
- # TODO(chrisgao): Double check of navigation.
- action_function()
+ def WaitForNavigate(self):
+ raise NotImplementedError()
def Navigate(self, url, script_to_evaluate_on_commit=None, timeout=None):
if script_to_evaluate_on_commit:
diff --git a/tools/telemetry/telemetry/core/browser.py b/tools/telemetry/telemetry/core/browser.py
index 39a18cfb30..b36c565c41 100644
--- a/tools/telemetry/telemetry/core/browser.py
+++ b/tools/telemetry/telemetry/core/browser.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/core/browser_credentials.py b/tools/telemetry/telemetry/core/browser_credentials.py
index 80fb181c54..607cd8a133 100644
--- a/tools/telemetry/telemetry/core/browser_credentials.py
+++ b/tools/telemetry/telemetry/core/browser_credentials.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
@@ -12,6 +12,10 @@ from telemetry.core.backends import google_credentials_backend
from telemetry.unittest import options_for_unittests
+class CredentialsError(Exception):
+ """Error that can be thrown when logging in."""
+
+
class BrowserCredentials(object):
def __init__(self, backends = None):
self._credentials = {}
@@ -33,19 +37,22 @@ class BrowserCredentials(object):
def IsLoggedIn(self, credentials_type):
if credentials_type not in self._backends:
- raise Exception('Unrecognized credentials type: %s', credentials_type)
+ raise CredentialsError(
+ 'Unrecognized credentials type: %s', credentials_type)
if credentials_type not in self._credentials:
return False
return self._backends[credentials_type].IsLoggedIn()
def CanLogin(self, credentials_type):
if credentials_type not in self._backends:
- raise Exception('Unrecognized credentials type: %s', credentials_type)
+ raise CredentialsError(
+ 'Unrecognized credentials type: %s', credentials_type)
return credentials_type in self._credentials
def LoginNeeded(self, tab, credentials_type):
if credentials_type not in self._backends:
- raise Exception('Unrecognized credentials type: %s', credentials_type)
+ raise CredentialsError(
+ 'Unrecognized credentials type: %s', credentials_type)
if credentials_type not in self._credentials:
return False
return self._backends[credentials_type].LoginNeeded(
diff --git a/tools/telemetry/telemetry/core/browser_credentials_unittest.py b/tools/telemetry/telemetry/core/browser_credentials_unittest.py
index cd77aed5d7..84bc39bcaa 100644
--- a/tools/telemetry/telemetry/core/browser_credentials_unittest.py
+++ b/tools/telemetry/telemetry/core/browser_credentials_unittest.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
import os
diff --git a/tools/telemetry/telemetry/core/browser_finder.py b/tools/telemetry/telemetry/core/browser_finder.py
index 9e30db2e4f..5103fae8eb 100644
--- a/tools/telemetry/telemetry/core/browser_finder.py
+++ b/tools/telemetry/telemetry/core/browser_finder.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/core/browser_options.py b/tools/telemetry/telemetry/core/browser_options.py
index aefaa7fa24..1a4514093e 100644
--- a/tools/telemetry/telemetry/core/browser_options.py
+++ b/tools/telemetry/telemetry/core/browser_options.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
@@ -204,6 +204,11 @@ class BrowserOptions(object):
self.platform = None
+ # Whether to use the new code path for choosing an ephemeral port for
+ # DevTools. The bots set this to true. When Chrome 37 reaches stable,
+ # remove this setting and the old code path. http://crbug.com/379980
+ self.use_devtools_active_port = False
+
def __repr__(self):
return str(sorted(self.__dict__.items()))
@@ -244,6 +249,11 @@ class BrowserOptions(object):
group.add_option('--show-stdout',
action='store_true',
help='When possible, will display the stdout of the process')
+ # This hidden option is to be removed, and the older code path deleted,
+ # once Chrome 37 reaches Stable. http://crbug.com/379980
+ group.add_option('--use-devtools-active-port',
+ action='store_true',
+ help=optparse.SUPPRESS_HELP)
parser.add_option_group(group)
group = optparse.OptionGroup(parser, 'Compatibility options')
@@ -274,6 +284,7 @@ class BrowserOptions(object):
'profile_type',
'show_stdout',
'synthetic_gesture_source_type',
+ 'use_devtools_active_port',
]
for o in browser_options_list:
a = getattr(finder_options, o, None)
@@ -297,12 +308,17 @@ class BrowserOptions(object):
self.dont_override_profile = True
if self.profile_dir and self.profile_type != 'clean':
- raise Exception("It's illegal to specify both --profile-type and"
- " --profile-dir.")
+ logging.critical(
+ "It's illegal to specify both --profile-type and --profile-dir.\n"
+ "For more information see: http://goo.gl/ngdGD5")
+ sys.exit(1)
if self.profile_dir and not os.path.isdir(self.profile_dir):
- raise Exception("Directory specified by --profile-dir (%s) doesn't"
- " exist or isn't a directory." % (self.profile_dir))
+ logging.critical(
+ "Directory specified by --profile-dir (%s) doesn't exist "
+ "or isn't a directory.\n"
+ "For more information see: http://goo.gl/ngdGD5" % self.profile_dir)
+ sys.exit(1)
if not self.profile_dir:
self.profile_dir = profile_types.GetProfileDir(self.profile_type)
diff --git a/tools/telemetry/telemetry/core/browser_options_unittest.py b/tools/telemetry/telemetry/core/browser_options_unittest.py
index 8e5cb11de9..3d95c3638e 100644
--- a/tools/telemetry/telemetry/core/browser_options_unittest.py
+++ b/tools/telemetry/telemetry/core/browser_options_unittest.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
import optparse
@@ -83,6 +83,13 @@ class BrowserOptionsTest(unittest.TestCase):
self.assertEquals(options.browser_options.extra_browser_args,
set(['--foo','--bar']))
+ def testUseDevToolsActivePort(self):
+ options = browser_options.BrowserFinderOptions()
+ parser = options.CreateParser()
+ parser.parse_args(['--use-devtools-active-port'])
+
+ self.assertEquals(options.browser_options.use_devtools_active_port, True)
+
def testMergeDefaultValues(self):
options = browser_options.BrowserFinderOptions()
options.already_true = True
diff --git a/tools/telemetry/telemetry/core/browser_unittest.py b/tools/telemetry/telemetry/core/browser_unittest.py
index 38f061ac3c..5d0fd66228 100644
--- a/tools/telemetry/telemetry/core/browser_unittest.py
+++ b/tools/telemetry/telemetry/core/browser_unittest.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/core/discover.py b/tools/telemetry/telemetry/core/discover.py
index c68dab81db..d815bdf99c 100644
--- a/tools/telemetry/telemetry/core/discover.py
+++ b/tools/telemetry/telemetry/core/discover.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/core/discover_unittest.py b/tools/telemetry/telemetry/core/discover_unittest.py
index 5de88ff19e..6937f20aca 100644
--- a/tools/telemetry/telemetry/core/discover_unittest.py
+++ b/tools/telemetry/telemetry/core/discover_unittest.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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
diff --git a/tools/telemetry/telemetry/core/environment.py b/tools/telemetry/telemetry/core/environment.py
index 284dba7194..04bafc8ed2 100644
--- a/tools/telemetry/telemetry/core/environment.py
+++ b/tools/telemetry/telemetry/core/environment.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2014 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/core/exceptions.py b/tools/telemetry/telemetry/core/exceptions.py
index 83ac24be60..671e2b8f1d 100644
--- a/tools/telemetry/telemetry/core/exceptions.py
+++ b/tools/telemetry/telemetry/core/exceptions.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/core/extension_dict.py b/tools/telemetry/telemetry/core/extension_dict.py
index 53e2d328d9..042651f331 100644
--- a/tools/telemetry/telemetry/core/extension_dict.py
+++ b/tools/telemetry/telemetry/core/extension_dict.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/core/extension_page.py b/tools/telemetry/telemetry/core/extension_page.py
index b76d7b8015..2f4c092d5a 100644
--- a/tools/telemetry/telemetry/core/extension_page.py
+++ b/tools/telemetry/telemetry/core/extension_page.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/core/extension_to_load.py b/tools/telemetry/telemetry/core/extension_to_load.py
index 85244db5b9..6549e8aa76 100644
--- a/tools/telemetry/telemetry/core/extension_to_load.py
+++ b/tools/telemetry/telemetry/core/extension_to_load.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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
diff --git a/tools/telemetry/telemetry/core/extension_unittest.py b/tools/telemetry/telemetry/core/extension_unittest.py
index 549836865f..23cac65334 100644
--- a/tools/telemetry/telemetry/core/extension_unittest.py
+++ b/tools/telemetry/telemetry/core/extension_unittest.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/core/memory_cache_http_server.py b/tools/telemetry/telemetry/core/memory_cache_http_server.py
index 9423a25dad..6aae8fd801 100644
--- a/tools/telemetry/telemetry/core/memory_cache_http_server.py
+++ b/tools/telemetry/telemetry/core/memory_cache_http_server.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/core/platform/__init__.py b/tools/telemetry/telemetry/core/platform/__init__.py
index b17abd9a1a..db7e7c299b 100644
--- a/tools/telemetry/telemetry/core/platform/__init__.py
+++ b/tools/telemetry/telemetry/core/platform/__init__.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/core/platform/android_platform_backend.py b/tools/telemetry/telemetry/core/platform/android_platform_backend.py
index a0e2642300..daef2e1e1b 100644
--- a/tools/telemetry/telemetry/core/platform/android_platform_backend.py
+++ b/tools/telemetry/telemetry/core/platform/android_platform_backend.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/core/platform/cros_platform_backend.py b/tools/telemetry/telemetry/core/platform/cros_platform_backend.py
index 81f5b002bd..e64c9f966c 100644
--- a/tools/telemetry/telemetry/core/platform/cros_platform_backend.py
+++ b/tools/telemetry/telemetry/core/platform/cros_platform_backend.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/core/platform/linux_platform_backend.py b/tools/telemetry/telemetry/core/platform/linux_platform_backend.py
index 679e56c45a..2be32c8c6c 100644
--- a/tools/telemetry/telemetry/core/platform/linux_platform_backend.py
+++ b/tools/telemetry/telemetry/core/platform/linux_platform_backend.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/core/platform/mac_platform_backend.py b/tools/telemetry/telemetry/core/platform/mac_platform_backend.py
index 7990176dac..04ac55fcc9 100644
--- a/tools/telemetry/telemetry/core/platform/mac_platform_backend.py
+++ b/tools/telemetry/telemetry/core/platform/mac_platform_backend.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/core/platform/platform_backend.py b/tools/telemetry/telemetry/core/platform/platform_backend.py
index fe68cb7481..e75973d148 100644
--- a/tools/telemetry/telemetry/core/platform/platform_backend.py
+++ b/tools/telemetry/telemetry/core/platform/platform_backend.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/core/platform/profiler/__init__.py b/tools/telemetry/telemetry/core/platform/profiler/__init__.py
index 806229e907..4f035a3a1a 100644
--- a/tools/telemetry/telemetry/core/platform/profiler/__init__.py
+++ b/tools/telemetry/telemetry/core/platform/profiler/__init__.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/core/platform/profiler/iprofiler_profiler.py b/tools/telemetry/telemetry/core/platform/profiler/iprofiler_profiler.py
index f10e1e6eb6..77769f53cc 100644
--- a/tools/telemetry/telemetry/core/platform/profiler/iprofiler_profiler.py
+++ b/tools/telemetry/telemetry/core/platform/profiler/iprofiler_profiler.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/core/platform/profiler/java_heap_profiler.py b/tools/telemetry/telemetry/core/platform/profiler/java_heap_profiler.py
index a02e84c2c5..48a46c2edc 100644
--- a/tools/telemetry/telemetry/core/platform/profiler/java_heap_profiler.py
+++ b/tools/telemetry/telemetry/core/platform/profiler/java_heap_profiler.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/core/platform/profiler/perf_profiler.py b/tools/telemetry/telemetry/core/platform/profiler/perf_profiler.py
index 53ff8af68d..4e0c9eae9f 100644
--- a/tools/telemetry/telemetry/core/platform/profiler/perf_profiler.py
+++ b/tools/telemetry/telemetry/core/platform/profiler/perf_profiler.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/core/platform/profiler/profiler_finder.py b/tools/telemetry/telemetry/core/platform/profiler/profiler_finder.py
index d610fff8ec..ab95dc83de 100644
--- a/tools/telemetry/telemetry/core/platform/profiler/profiler_finder.py
+++ b/tools/telemetry/telemetry/core/platform/profiler/profiler_finder.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/core/platform/profiler/sample_profiler.py b/tools/telemetry/telemetry/core/platform/profiler/sample_profiler.py
index a666ca975c..bc09c4f603 100644
--- a/tools/telemetry/telemetry/core/platform/profiler/sample_profiler.py
+++ b/tools/telemetry/telemetry/core/platform/profiler/sample_profiler.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/core/platform/profiler/tcmalloc_heap_profiler.py b/tools/telemetry/telemetry/core/platform/profiler/tcmalloc_heap_profiler.py
index e04f65580c..ba494ea1e9 100644
--- a/tools/telemetry/telemetry/core/platform/profiler/tcmalloc_heap_profiler.py
+++ b/tools/telemetry/telemetry/core/platform/profiler/tcmalloc_heap_profiler.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/core/platform/win_platform_backend.py b/tools/telemetry/telemetry/core/platform/win_platform_backend.py
index a6d28996c6..4597c40c7c 100644
--- a/tools/telemetry/telemetry/core/platform/win_platform_backend.py
+++ b/tools/telemetry/telemetry/core/platform/win_platform_backend.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/core/possible_browser.py b/tools/telemetry/telemetry/core/possible_browser.py
index 817ec9ab84..21d51e8b98 100644
--- a/tools/telemetry/telemetry/core/possible_browser.py
+++ b/tools/telemetry/telemetry/core/possible_browser.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/core/profile_types.py b/tools/telemetry/telemetry/core/profile_types.py
index 957fd92a21..f031b4783e 100644
--- a/tools/telemetry/telemetry/core/profile_types.py
+++ b/tools/telemetry/telemetry/core/profile_types.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/core/profile_types_unittest.py b/tools/telemetry/telemetry/core/profile_types_unittest.py
index 764e2f229f..9695ed0606 100644
--- a/tools/telemetry/telemetry/core/profile_types_unittest.py
+++ b/tools/telemetry/telemetry/core/profile_types_unittest.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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
diff --git a/tools/telemetry/telemetry/core/tab.py b/tools/telemetry/telemetry/core/tab.py
index 5e6138dedf..b6d6371a79 100644
--- a/tools/telemetry/telemetry/core/tab.py
+++ b/tools/telemetry/telemetry/core/tab.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
@@ -109,7 +109,9 @@ class Tab(web_contents.WebContents):
screen.style.zIndex = '2147483638';
document.body.appendChild(screen);
requestAnimationFrame(function() {
- window.__telemetry_screen_%d = screen;
+ requestAnimationFrame(function() {
+ window.__telemetry_screen_%d = screen;
+ });
});
})();
""" % (color.r, color.g, color.b, color.a, int(color)))
@@ -122,7 +124,11 @@ class Tab(web_contents.WebContents):
(function() {
document.body.removeChild(window.__telemetry_screen_%d);
requestAnimationFrame(function() {
- window.__telemetry_screen_%d = null;
+ requestAnimationFrame(function() {
+ window.__telemetry_screen_%d = null;
+ console.time('__ClearHighlight.video_capture_start');
+ console.timeEnd('__ClearHighlight.video_capture_start');
+ });
});
})();
""" % (int(color), int(color)))
@@ -231,16 +237,14 @@ class Tab(web_contents.WebContents):
for timestamp, bmp in frame_generator:
yield timestamp - start_time, bmp.Crop(*content_box)
- def PerformActionAndWaitForNavigate(
- self, action_function, timeout=DEFAULT_TAB_TIMEOUT):
- """Executes action_function, and waits for the navigation to complete.
+ def WaitForNavigate(self, timeout=DEFAULT_TAB_TIMEOUT):
+ """Waits for the navigation to complete.
- action_function must be a Python function that results in a navigation.
+ The current page is expect to be in a navigation.
This function returns when the navigation is complete or when
the timeout has been exceeded.
"""
- self._inspector_backend.PerformActionAndWaitForNavigate(
- action_function, timeout)
+ self._inspector_backend.WaitForNavigate(timeout)
def Navigate(self, url, script_to_evaluate_on_commit=None,
timeout=DEFAULT_TAB_TIMEOUT):
diff --git a/tools/telemetry/telemetry/core/tab_list.py b/tools/telemetry/telemetry/core/tab_list.py
index 3e34bbb216..06cb667e1f 100644
--- a/tools/telemetry/telemetry/core/tab_list.py
+++ b/tools/telemetry/telemetry/core/tab_list.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
class TabList(object):
diff --git a/tools/telemetry/telemetry/core/tab_unittest.py b/tools/telemetry/telemetry/core/tab_unittest.py
index 91bdb51f58..89eaddca0a 100644
--- a/tools/telemetry/telemetry/core/tab_unittest.py
+++ b/tools/telemetry/telemetry/core/tab_unittest.py
@@ -1,12 +1,15 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
import logging
from telemetry import test
+from telemetry.core import bitmap
from telemetry.core import util
from telemetry.core import exceptions
+from telemetry.core.backends.chrome import tracing_backend
+from telemetry.core.timeline import model
from telemetry.unittest import tab_test_case
@@ -93,6 +96,21 @@ class TabTest(tab_test_case.TabTestCase):
self.assertFalse(self._tab.is_video_capture_running)
self._tab.browser._platform = original_platform
+ def testHighlight(self):
+ self.assertEquals(self._tab.url, 'about:blank')
+ self._browser.StartTracing(tracing_backend.DEFAULT_TRACE_CATEGORIES)
+ self._tab.Highlight(bitmap.WEB_PAGE_TEST_ORANGE)
+ self._tab.ClearHighlight(bitmap.WEB_PAGE_TEST_ORANGE)
+ trace_data = self._browser.StopTracing()
+ timeline_model = model.TimelineModel(trace_data)
+ renderer_thread = timeline_model.GetRendererThreadFromTab(self._tab)
+ found_video_start_event = False
+ for event in renderer_thread.async_slices:
+ if event.name == '__ClearHighlight.video_capture_start':
+ found_video_start_event = True
+ break
+ self.assertTrue(found_video_start_event)
+
class GpuTabTest(tab_test_case.TabTestCase):
def setUp(self):
diff --git a/tools/telemetry/telemetry/core/timeline/event.py b/tools/telemetry/telemetry/core/timeline/event.py
index 874a89576e..1898c0a6c6 100644
--- a/tools/telemetry/telemetry/core/timeline/event.py
+++ b/tools/telemetry/telemetry/core/timeline/event.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/core/timeline/event_unittest.py b/tools/telemetry/telemetry/core/timeline/event_unittest.py
index d336a777b4..44aac65e89 100644
--- a/tools/telemetry/telemetry/core/timeline/event_unittest.py
+++ b/tools/telemetry/telemetry/core/timeline/event_unittest.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/core/timeline/importer.py b/tools/telemetry/telemetry/core/timeline/importer.py
index 3cb058b0c7..4a82ce53f8 100644
--- a/tools/telemetry/telemetry/core/timeline/importer.py
+++ b/tools/telemetry/telemetry/core/timeline/importer.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/core/timeline/inspector_importer.py b/tools/telemetry/telemetry/core/timeline/inspector_importer.py
index b0084113fc..c3f3aab32c 100644
--- a/tools/telemetry/telemetry/core/timeline/inspector_importer.py
+++ b/tools/telemetry/telemetry/core/timeline/inspector_importer.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
'''Imports event data obtained from the inspector's timeline.'''
diff --git a/tools/telemetry/telemetry/core/timeline/inspector_importer_unittest.py b/tools/telemetry/telemetry/core/timeline/inspector_importer_unittest.py
index a9063dbb8d..49789bede7 100644
--- a/tools/telemetry/telemetry/core/timeline/inspector_importer_unittest.py
+++ b/tools/telemetry/telemetry/core/timeline/inspector_importer_unittest.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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
diff --git a/tools/telemetry/telemetry/core/timeline/model.py b/tools/telemetry/telemetry/core/timeline/model.py
index 113227b43b..8473a64ad1 100644
--- a/tools/telemetry/telemetry/core/timeline/model.py
+++ b/tools/telemetry/telemetry/core/timeline/model.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
'''A container for timeline-based events and traces and can handle importing
diff --git a/tools/telemetry/telemetry/core/timeline/model_unittest.py b/tools/telemetry/telemetry/core/timeline/model_unittest.py
index 85537be453..009baa3086 100644
--- a/tools/telemetry/telemetry/core/timeline/model_unittest.py
+++ b/tools/telemetry/telemetry/core/timeline/model_unittest.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2014 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/core/user_agent.py b/tools/telemetry/telemetry/core/user_agent.py
index 811aca2bd7..4fa2f68043 100644
--- a/tools/telemetry/telemetry/core/user_agent.py
+++ b/tools/telemetry/telemetry/core/user_agent.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/core/user_agent_unittest.py b/tools/telemetry/telemetry/core/user_agent_unittest.py
index 32cbbb7056..74b662215e 100644
--- a/tools/telemetry/telemetry/core/user_agent_unittest.py
+++ b/tools/telemetry/telemetry/core/user_agent_unittest.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/core/util.py b/tools/telemetry/telemetry/core/util.py
index b982c16569..efeab5aa7f 100644
--- a/tools/telemetry/telemetry/core/util.py
+++ b/tools/telemetry/telemetry/core/util.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
import glob
diff --git a/tools/telemetry/telemetry/core/util_unittest.py b/tools/telemetry/telemetry/core/util_unittest.py
index 767ee43cd7..05df311add 100644
--- a/tools/telemetry/telemetry/core/util_unittest.py
+++ b/tools/telemetry/telemetry/core/util_unittest.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
import os
diff --git a/tools/telemetry/telemetry/core/web_contents.py b/tools/telemetry/telemetry/core/web_contents.py
index 4af1c8f14b..0b3594b259 100644
--- a/tools/telemetry/telemetry/core/web_contents.py
+++ b/tools/telemetry/telemetry/core/web_contents.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/core/webpagereplay.py b/tools/telemetry/telemetry/core/webpagereplay.py
index 71e1f35989..e290e44f32 100644
--- a/tools/telemetry/telemetry/core/webpagereplay.py
+++ b/tools/telemetry/telemetry/core/webpagereplay.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/core/wpr_modes.py b/tools/telemetry/telemetry/core/wpr_modes.py
index 64ffe08853..85a3dd0826 100644
--- a/tools/telemetry/telemetry/core/wpr_modes.py
+++ b/tools/telemetry/telemetry/core/wpr_modes.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
WPR_OFF = 'wpr-off'
diff --git a/tools/telemetry/telemetry/core/wpr_server.py b/tools/telemetry/telemetry/core/wpr_server.py
index fb52e4c6e6..9e65b53b61 100644
--- a/tools/telemetry/telemetry/core/wpr_server.py
+++ b/tools/telemetry/telemetry/core/wpr_server.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/page/__init__.py b/tools/telemetry/telemetry/page/__init__.py
index 96196cffb2..efcc9c35d2 100644
--- a/tools/telemetry/telemetry/page/__init__.py
+++ b/tools/telemetry/telemetry/page/__init__.py
@@ -1,3 +1,3 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/page/actions/action_runner.py b/tools/telemetry/telemetry/page/actions/action_runner.py
index c0847031ef..084b5ef4c3 100644
--- a/tools/telemetry/telemetry/page/actions/action_runner.py
+++ b/tools/telemetry/telemetry/page/actions/action_runner.py
@@ -1,49 +1,104 @@
# 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.actions.javascript import JavaScriptAction
from telemetry.page.actions.navigate import NavigateAction
from telemetry.web_perf import timeline_interaction_record as tir_module
class ActionRunner(object):
+
def __init__(self, tab):
self._tab = tab
- #TODO(nednguyen): remove this when crbug.com/361809 is marked fixed
+ # TODO(nednguyen): remove this (or make private) when
+ # crbug.com/361809 is marked fixed
def RunAction(self, action):
if not action.WillWaitAfterRun():
action.WillRunAction(self._tab)
action.RunActionAndMaybeWait(self._tab)
- def BeginInteraction(self, logical_name, flags):
- """ Issues the begin of interaction record.
- flags contains any flags in web_perf.timeline_interaction_record.
- """
- assert self._tab
- self._tab.ExecuteJavaScript('console.time("%s");' %
- tir_module.TimelineInteractionRecord.GetJavascriptMarker(logical_name,
- flags))
-
- def EndInteraction(self, logical_name, flags):
- """ Issues the begin of interaction record.
- flags contains any flags in web_perf.timeline_interaction_record.
+ def BeginInteraction(self, label, is_smooth=False, is_responsive=False):
+ """Marks the beginning of an interaction record.
+
+ An interaction record is a labeled time period containing
+ interaction that developers care about. Each set of metrics
+ specified in flags will be calculated for this time period.. The
+ End() method in the returned object must be called once to mark
+ the end of the timeline.
+
+ Args:
+ label: A label for this particular interaction. This can be any
+ user-defined string, but must not contain '/'.
+ is_smooth: Whether to check for smoothness metrics for this interaction.
+ is_responsive: Whether to check for responsiveness metrics for
+ this interaction.
"""
- assert self._tab
- self._tab.ExecuteJavaScript('console.timeEnd("%s");' %
- tir_module.TimelineInteractionRecord.GetJavascriptMarker(logical_name,
- flags))
+ flags = []
+ if is_smooth:
+ flags.append(tir_module.IS_SMOOTH)
+ if is_responsive:
+ flags.append(tir_module.IS_RESPONSIVE)
+
+ interaction = Interaction(self._tab, label, flags)
+ interaction.Begin()
+ return interaction
def NavigateToPage(self, page, timeout_seconds=None):
- """ Navigate to page.
- page is an instance of page.Page
+ """ Navigate to the given page.
+
+ Args:
+ page: page is an instance of page.Page
"""
if page.is_file:
target_side_url = self._tab.browser.http_server.UrlOf(page.file_path_url)
else:
target_side_url = page.url
attributes = {
- 'url': target_side_url ,
- 'script_to_evaluate_on_commit': page.script_to_evaluate_on_commit}
+ 'url': target_side_url,
+ 'script_to_evaluate_on_commit': page.script_to_evaluate_on_commit}
if timeout_seconds:
attributes['timeout_seconds'] = timeout_seconds
self.RunAction(NavigateAction(attributes))
+
+ def WaitForNavigate(self, timeout_seconds=60):
+ self._tab.WaitForNavigate(timeout_seconds)
+ self._tab.WaitForDocumentReadyStateToBeInteractiveOrBetter()
+
+ def ExecuteJavaScript(self, js_expression):
+ """Executes a given JavaScript expression.
+
+ Example: runner.ExecuteJavaScript('var foo = 1;');
+
+ Args:
+ js_expression: The expression to execute (provided as string).
+ """
+ self.RunAction(JavaScriptAction({'expression': js_expression}))
+
+
+class Interaction(object):
+
+ def __init__(self, action_runner, label, flags):
+ assert action_runner
+ assert label
+ assert isinstance(flags, list)
+
+ self._action_runner = action_runner
+ self._label = label
+ self._flags = flags
+ self._started = False
+
+ def Begin(self):
+ assert not self._started
+ self._started = True
+ self._action_runner.ExecuteJavaScript('console.time("%s");' %
+ tir_module.TimelineInteractionRecord.GetJavaScriptMarker(
+ self._label, self._flags))
+
+ def End(self):
+ assert self._started
+ self._started = False
+ self._action_runner.ExecuteJavaScript('console.timeEnd("%s");' %
+ tir_module.TimelineInteractionRecord.GetJavaScriptMarker(
+ self._label, self._flags))
diff --git a/tools/telemetry/telemetry/page/actions/action_runner_unittest.py b/tools/telemetry/telemetry/page/actions/action_runner_unittest.py
index ab33a19893..0920194cf2 100644
--- a/tools/telemetry/telemetry/page/actions/action_runner_unittest.py
+++ b/tools/telemetry/telemetry/page/actions/action_runner_unittest.py
@@ -1,6 +1,7 @@
# 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.core.backends.chrome import tracing_backend
from telemetry.core.timeline import model
from telemetry.page.actions import action_runner as action_runner_module
@@ -16,8 +17,9 @@ class ActionRunnerTest(tab_test_case.TabTestCase):
self.Navigate('interaction_enabled_page.html')
action_runner.RunAction(WaitAction({'seconds': 1}))
self._browser.StartTracing(tracing_backend.DEFAULT_TRACE_CATEGORIES)
- action_runner.BeginInteraction('TestInteraction', [tir_module.IS_SMOOTH])
- action_runner.EndInteraction('TestInteraction', [tir_module.IS_SMOOTH])
+ interaction = action_runner.BeginInteraction(
+ 'TestInteraction', is_smooth=True)
+ interaction.End()
trace_data = self._browser.StopTracing()
timeline_model = model.TimelineModel(trace_data)
@@ -32,3 +34,22 @@ class ActionRunnerTest(tab_test_case.TabTestCase):
' Trace data:\n%s' % repr(trace_data.EventData()))
self.assertEqual('TestInteraction', records[0].logical_name)
self.assertTrue(records[0].is_smooth)
+
+ def testExecuteJavaScript(self):
+ action_runner = action_runner_module.ActionRunner(self._tab)
+ self.Navigate('blank.html')
+ action_runner.ExecuteJavaScript('var testing = 42;')
+ self.assertEqual(42, self._tab.EvaluateJavaScript('testing'))
+
+ def testWaitForNavigate(self):
+ self.Navigate('page_with_link.html')
+ action_runner = action_runner_module.ActionRunner(self._tab)
+ action_runner.RunAction(ClickElementAction({'xpath': 'id("clickme")'}))
+ action_runner.WaitForNavigate()
+
+ self.assertTrue(self._tab.EvaluateJavaScript(
+ 'document.readyState == "interactive" || '
+ 'document.readyState == "complete"'))
+ self.assertEquals(
+ self._tab.EvaluateJavaScript('document.location.pathname;'),
+ '/blank.html')
diff --git a/tools/telemetry/telemetry/page/actions/all_page_actions.py b/tools/telemetry/telemetry/page/actions/all_page_actions.py
index 25fd7cfca9..695e769d6b 100644
--- a/tools/telemetry/telemetry/page/actions/all_page_actions.py
+++ b/tools/telemetry/telemetry/page/actions/all_page_actions.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
import os
@@ -11,7 +11,6 @@ from telemetry.page.actions import page_action
# TODO(nednguyen): Remove all of these imports when we done porting all actions
# to action_runner
from telemetry.page.actions.interact import InteractAction
-from telemetry.page.actions.javascript import JavascriptAction
from telemetry.page.actions.javascript_click import ClickElementAction
from telemetry.page.actions.js_collect_garbage import JsCollectGarbageAction
from telemetry.page.actions.loop import LoopAction
diff --git a/tools/telemetry/telemetry/page/actions/gesture_action.py b/tools/telemetry/telemetry/page/actions/gesture_action.py
index 0bbd977a94..04503e5a53 100644
--- a/tools/telemetry/telemetry/page/actions/gesture_action.py
+++ b/tools/telemetry/telemetry/page/actions/gesture_action.py
@@ -6,7 +6,6 @@ from telemetry.page.actions import page_action
from telemetry.page.actions import wait
from telemetry import decorators
from telemetry.page.actions import action_runner
-from telemetry.web_perf import timeline_interaction_record as tir_module
class GestureAction(page_action.PageAction):
def __init__(self, attributes=None):
@@ -29,15 +28,16 @@ class GestureAction(page_action.PageAction):
else:
interaction_name = 'Gesture_%s' % self.__class__.__name__
+ interaction = None
if self.automatically_record_interaction:
- runner.BeginInteraction(interaction_name, [tir_module.IS_SMOOTH])
+ interaction = runner.BeginInteraction(interaction_name, is_smooth=True)
self.RunGesture(tab)
if self.wait_action:
self.wait_action.RunAction(tab)
- if self.automatically_record_interaction:
- runner.EndInteraction(interaction_name, [tir_module.IS_SMOOTH])
+ if interaction is not None:
+ interaction.End()
def RunGesture(self, tab):
raise NotImplementedError()
diff --git a/tools/telemetry/telemetry/page/actions/javascript.py b/tools/telemetry/telemetry/page/actions/javascript.py
index 4bd8d6b367..8a0bb092f3 100644
--- a/tools/telemetry/telemetry/page/actions/javascript.py
+++ b/tools/telemetry/telemetry/page/actions/javascript.py
@@ -5,9 +5,9 @@
from telemetry.page.actions import page_action
-class JavascriptAction(page_action.PageAction):
+class JavaScriptAction(page_action.PageAction):
def __init__(self, attributes=None):
- super(JavascriptAction, self).__init__(attributes)
+ super(JavaScriptAction, self).__init__(attributes)
def RunAction(self, tab):
assert hasattr(self, 'expression')
diff --git a/tools/telemetry/telemetry/page/actions/js_collect_garbage.py b/tools/telemetry/telemetry/page/actions/js_collect_garbage.py
index 43aa72a0ba..bda2d7bed7 100644
--- a/tools/telemetry/telemetry/page/actions/js_collect_garbage.py
+++ b/tools/telemetry/telemetry/page/actions/js_collect_garbage.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.actions import page_action
diff --git a/tools/telemetry/telemetry/page/actions/page_action.py b/tools/telemetry/telemetry/page/actions/page_action.py
index e7b95a801f..9388ca2e78 100644
--- a/tools/telemetry/telemetry/page/actions/page_action.py
+++ b/tools/telemetry/telemetry/page/actions/page_action.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
from telemetry.page.actions import wait_until
diff --git a/tools/telemetry/telemetry/page/actions/play.py b/tools/telemetry/telemetry/page/actions/play.py
index c81c4336da..62a2c55a7c 100644
--- a/tools/telemetry/telemetry/page/actions/play.py
+++ b/tools/telemetry/telemetry/page/actions/play.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/page/actions/reload.py b/tools/telemetry/telemetry/page/actions/reload.py
index 09d5e4a4c9..fca82d998d 100644
--- a/tools/telemetry/telemetry/page/actions/reload.py
+++ b/tools/telemetry/telemetry/page/actions/reload.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/page/actions/scroll.py b/tools/telemetry/telemetry/page/actions/scroll.py
index 1d7aeb83a6..2f6dbd7169 100644
--- a/tools/telemetry/telemetry/page/actions/scroll.py
+++ b/tools/telemetry/telemetry/page/actions/scroll.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
import os
diff --git a/tools/telemetry/telemetry/page/actions/scroll_unittest.py b/tools/telemetry/telemetry/page/actions/scroll_unittest.py
index a60b089b60..82478cfc31 100644
--- a/tools/telemetry/telemetry/page/actions/scroll_unittest.py
+++ b/tools/telemetry/telemetry/page/actions/scroll_unittest.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/page/actions/wait.py b/tools/telemetry/telemetry/page/actions/wait.py
index ce1d86b73a..6ff37d8035 100644
--- a/tools/telemetry/telemetry/page/actions/wait.py
+++ b/tools/telemetry/telemetry/page/actions/wait.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/page/actions/wait_unittest.py b/tools/telemetry/telemetry/page/actions/wait_unittest.py
index 7278404c3e..1601bff2ee 100644
--- a/tools/telemetry/telemetry/page/actions/wait_unittest.py
+++ b/tools/telemetry/telemetry/page/actions/wait_unittest.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/page/actions/wait_until.py b/tools/telemetry/telemetry/page/actions/wait_until.py
index f50a810c66..e7ce56120c 100644
--- a/tools/telemetry/telemetry/page/actions/wait_until.py
+++ b/tools/telemetry/telemetry/page/actions/wait_until.py
@@ -13,13 +13,7 @@ class WaitUntil(object):
self._previous_action = previous_action
def RunActionAndWait(self, tab):
- if getattr(self, 'condition', None) == 'navigate':
- self._previous_action.WillRunAction(tab)
- action_to_perform = lambda: self._previous_action.RunAction(tab)
- tab.PerformActionAndWaitForNavigate(action_to_perform, self.timeout)
- tab.WaitForDocumentReadyStateToBeInteractiveOrBetter()
-
- elif getattr(self, 'condition', None) == 'href_change':
+ if getattr(self, 'condition', None) == 'href_change':
self._previous_action.WillRunAction(tab)
old_url = tab.EvaluateJavaScript('document.location.href')
self._previous_action.RunAction(tab)
diff --git a/tools/telemetry/telemetry/page/block_page_measurement_results.py b/tools/telemetry/telemetry/page/block_page_measurement_results.py
index d92ae86c43..f1f865f5da 100644
--- a/tools/telemetry/telemetry/page/block_page_measurement_results.py
+++ b/tools/telemetry/telemetry/page/block_page_measurement_results.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
import os
diff --git a/tools/telemetry/telemetry/page/block_page_measurement_results_unittest.py b/tools/telemetry/telemetry/page/block_page_measurement_results_unittest.py
index 234aa01596..0536dd017c 100644
--- a/tools/telemetry/telemetry/page/block_page_measurement_results_unittest.py
+++ b/tools/telemetry/telemetry/page/block_page_measurement_results_unittest.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
import StringIO
diff --git a/tools/telemetry/telemetry/page/buildbot_page_measurement_results.py b/tools/telemetry/telemetry/page/buildbot_page_measurement_results.py
index 55147c4db8..f960f6a520 100644
--- a/tools/telemetry/telemetry/page/buildbot_page_measurement_results.py
+++ b/tools/telemetry/telemetry/page/buildbot_page_measurement_results.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/page/buildbot_page_measurement_results_unittest.py b/tools/telemetry/telemetry/page/buildbot_page_measurement_results_unittest.py
index 7593805d98..e5feb81757 100644
--- a/tools/telemetry/telemetry/page/buildbot_page_measurement_results_unittest.py
+++ b/tools/telemetry/telemetry/page/buildbot_page_measurement_results_unittest.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
import os
diff --git a/tools/telemetry/telemetry/page/cloud_storage.py b/tools/telemetry/telemetry/page/cloud_storage.py
index be7db6c70d..2c54785748 100644
--- a/tools/telemetry/telemetry/page/cloud_storage.py
+++ b/tools/telemetry/telemetry/page/cloud_storage.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/page/csv_page_measurement_results.py b/tools/telemetry/telemetry/page/csv_page_measurement_results.py
index fdbb812f83..56eac05c9c 100644
--- a/tools/telemetry/telemetry/page/csv_page_measurement_results.py
+++ b/tools/telemetry/telemetry/page/csv_page_measurement_results.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
import csv
diff --git a/tools/telemetry/telemetry/page/csv_page_measurement_results_unittest.py b/tools/telemetry/telemetry/page/csv_page_measurement_results_unittest.py
index 3891e57965..023eab4ff6 100644
--- a/tools/telemetry/telemetry/page/csv_page_measurement_results_unittest.py
+++ b/tools/telemetry/telemetry/page/csv_page_measurement_results_unittest.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
import StringIO
diff --git a/tools/telemetry/telemetry/page/gtest_test_results.py b/tools/telemetry/telemetry/page/gtest_test_results.py
index ada547431f..2bed68449e 100644
--- a/tools/telemetry/telemetry/page/gtest_test_results.py
+++ b/tools/telemetry/telemetry/page/gtest_test_results.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/page/page.py b/tools/telemetry/telemetry/page/page.py
index 58ced5e780..5ebce2242f 100644
--- a/tools/telemetry/telemetry/page/page.py
+++ b/tools/telemetry/telemetry/page/page.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/page/page_filter.py b/tools/telemetry/telemetry/page/page_filter.py
index c15c313fe3..ea009b5424 100644
--- a/tools/telemetry/telemetry/page/page_filter.py
+++ b/tools/telemetry/telemetry/page/page_filter.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/page/page_measurement.py b/tools/telemetry/telemetry/page/page_measurement.py
index 993897e1c2..967ecf5cae 100644
--- a/tools/telemetry/telemetry/page/page_measurement.py
+++ b/tools/telemetry/telemetry/page/page_measurement.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/page/page_measurement_results.py b/tools/telemetry/telemetry/page/page_measurement_results.py
index 028e2992e8..ee22b2fc69 100644
--- a/tools/telemetry/telemetry/page/page_measurement_results.py
+++ b/tools/telemetry/telemetry/page/page_measurement_results.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/page/page_measurement_results_unittest.py b/tools/telemetry/telemetry/page/page_measurement_results_unittest.py
index b5b35dfdd8..d30763e8e9 100644
--- a/tools/telemetry/telemetry/page/page_measurement_results_unittest.py
+++ b/tools/telemetry/telemetry/page/page_measurement_results_unittest.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
import os
diff --git a/tools/telemetry/telemetry/page/page_measurement_unittest.py b/tools/telemetry/telemetry/page/page_measurement_unittest.py
index e81f2f49ad..7134c9d683 100644
--- a/tools/telemetry/telemetry/page/page_measurement_unittest.py
+++ b/tools/telemetry/telemetry/page/page_measurement_unittest.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/page/page_measurement_unittest_base.py b/tools/telemetry/telemetry/page/page_measurement_unittest_base.py
index 76c98d1851..24ac840744 100644
--- a/tools/telemetry/telemetry/page/page_measurement_unittest_base.py
+++ b/tools/telemetry/telemetry/page/page_measurement_unittest_base.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/page/page_runner.py b/tools/telemetry/telemetry/page/page_runner.py
index 7a7a943c54..5df0d9ab43 100644
--- a/tools/telemetry/telemetry/page/page_runner.py
+++ b/tools/telemetry/telemetry/page/page_runner.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/page/page_runner_unittest.py b/tools/telemetry/telemetry/page/page_runner_unittest.py
index b39a308f32..14ea12f4f1 100644
--- a/tools/telemetry/telemetry/page/page_runner_unittest.py
+++ b/tools/telemetry/telemetry/page/page_runner_unittest.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/page/page_set.py b/tools/telemetry/telemetry/page/page_set.py
index d58f0aeaf4..2285b2958c 100644
--- a/tools/telemetry/telemetry/page/page_set.py
+++ b/tools/telemetry/telemetry/page/page_set.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/page/page_set_archive_info.py b/tools/telemetry/telemetry/page/page_set_archive_info.py
index ee235859e6..575f9e172e 100644
--- a/tools/telemetry/telemetry/page/page_set_archive_info.py
+++ b/tools/telemetry/telemetry/page/page_set_archive_info.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/page/page_set_archive_info_unittest.py b/tools/telemetry/telemetry/page/page_set_archive_info_unittest.py
index f94b76bd80..f060c74a85 100644
--- a/tools/telemetry/telemetry/page/page_set_archive_info_unittest.py
+++ b/tools/telemetry/telemetry/page/page_set_archive_info_unittest.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
import os
diff --git a/tools/telemetry/telemetry/page/page_set_unittest.py b/tools/telemetry/telemetry/page/page_set_unittest.py
index 0b5b4ea83e..cb08bc7644 100644
--- a/tools/telemetry/telemetry/page/page_set_unittest.py
+++ b/tools/telemetry/telemetry/page/page_set_unittest.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/page/page_test.py b/tools/telemetry/telemetry/page/page_test.py
index 4a8497b6e8..c952df1f34 100644
--- a/tools/telemetry/telemetry/page/page_test.py
+++ b/tools/telemetry/telemetry/page/page_test.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/page/page_test_results.py b/tools/telemetry/telemetry/page/page_test_results.py
index e909e7992b..dc653be582 100644
--- a/tools/telemetry/telemetry/page/page_test_results.py
+++ b/tools/telemetry/telemetry/page/page_test_results.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/page/page_test_unittest.py b/tools/telemetry/telemetry/page/page_test_unittest.py
index ff4c7316a4..56b4a6a458 100644
--- a/tools/telemetry/telemetry/page/page_test_unittest.py
+++ b/tools/telemetry/telemetry/page/page_test_unittest.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/page/page_unittest.py b/tools/telemetry/telemetry/page/page_unittest.py
index 61fabc07bd..fcb9ddcce8 100644
--- a/tools/telemetry/telemetry/page/page_unittest.py
+++ b/tools/telemetry/telemetry/page/page_unittest.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/page/perf_tests_helper.py b/tools/telemetry/telemetry/page/perf_tests_helper.py
index cf5744e32c..9c24287843 100644
--- a/tools/telemetry/telemetry/page/perf_tests_helper.py
+++ b/tools/telemetry/telemetry/page/perf_tests_helper.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
from __future__ import absolute_import
diff --git a/tools/telemetry/telemetry/page/record_wpr.py b/tools/telemetry/telemetry/page/record_wpr.py
index a55b238570..07ab64bd4a 100755
--- a/tools/telemetry/telemetry/page/record_wpr.py
+++ b/tools/telemetry/telemetry/page/record_wpr.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
import logging
@@ -41,6 +41,7 @@ class RecordPage(page_test.PageTest): # pylint: disable=W0223
"""Override to ensure all resources are fetched from network."""
tab.ClearCache(force=False)
if self.test:
+ self.test.options = self.options
self.test.WillNavigateToPage(page, tab)
def DidNavigateToPage(self, page, tab):
@@ -49,20 +50,14 @@ class RecordPage(page_test.PageTest): # pylint: disable=W0223
self.test.DidNavigateToPage(page, tab)
def RunPage(self, page, tab, results):
- # When recording, sleep to catch any resources that load post-onload.
tab.WaitForDocumentReadyStateToBeComplete()
- if self.test:
- dummy_results = page_measurement_results.PageMeasurementResults()
- dummy_results.WillMeasurePage(page)
- self.test.MeasurePage(page, tab, dummy_results)
- dummy_results.DidMeasurePage()
- else:
- # TODO(tonyg): This should probably monitor resource timing for activity
- # and sleep until 2s since the last network event with some timeout like
- # 20s. We could wrap this up as WaitForNetworkIdle() and share with the
- # speed index metric.
- time.sleep(3)
+ # When recording, sleep to catch any resources that load post-onload.
+ # TODO(tonyg): This should probably monitor resource timing for activity
+ # and sleep until 2s since the last network event with some timeout like
+ # 20s. We could wrap this up as WaitForNetworkIdle() and share with the
+ # speed index metric.
+ time.sleep(3)
# Run the actions for all measurements. Reload the page between
# actions.
@@ -80,6 +75,12 @@ class RecordPage(page_test.PageTest): # pylint: disable=W0223
self._RunMethod(page, action_name, action_runner)
should_reload = True
+ # Run the PageTest's validator, so that we capture any additional resources
+ # that are loaded by the test.
+ if self.test:
+ dummy_results = page_measurement_results.PageMeasurementResults()
+ self.test.ValidatePage(page, tab, dummy_results)
+
def Main(base_dir):
measurements = {
diff --git a/tools/telemetry/telemetry/test.py b/tools/telemetry/telemetry/test.py
index b23f43503b..5764776064 100644
--- a/tools/telemetry/telemetry/test.py
+++ b/tools/telemetry/telemetry/test.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
@@ -37,8 +37,14 @@ class Test(command_line.Command):
name = cls.__module__.split('.')[-1]
if hasattr(cls, 'tag'):
name += '.' + cls.tag
- if hasattr(cls, 'page_set'):
- name += '.' + os.path.basename(os.path.splitext(cls.page_set)[0])
+ page_set_name = None
+ if hasattr(cls, 'page_set') and isinstance(cls.page_set, page_set.PageSet):
+ page_set_name = os.path.basename(
+ os.path.splitext(cls.page_set.file_path)[0])
+ elif hasattr(cls, 'page_set') and isinstance(cls.page_set, str):
+ page_set_name = os.path.basename(os.path.splitext(cls.page_set)[0])
+ if page_set_name:
+ name += '.' + page_set_name
return name
@classmethod
@@ -172,8 +178,15 @@ class Test(command_line.Command):
"""
if not hasattr(cls, 'page_set'):
raise NotImplementedError('This test has no "page_set" attribute.')
- return page_set.PageSet.FromFile(
- file_path=os.path.join(util.GetBaseDir(), cls.page_set))
+
+ if isinstance(cls.page_set, str):
+ return page_set.PageSet.FromFile(
+ file_path=os.path.join(util.GetBaseDir(), cls.page_set))
+ elif isinstance(cls.page_set, page_set.PageSet):
+ return cls.page_set
+ else:
+ raise TypeError('The page_set field of %s has unsupported type.' %
+ cls.Name)
@classmethod
def CreateExpectations(cls, ps): # pylint: disable=W0613
diff --git a/tools/telemetry/telemetry/test_runner.py b/tools/telemetry/telemetry/test_runner.py
index 66b923bb19..95437c5b2f 100644
--- a/tools/telemetry/telemetry/test_runner.py
+++ b/tools/telemetry/telemetry/test_runner.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
@@ -155,8 +155,8 @@ class Run(command_line.OptparseCommand):
assert issubclass(test_class, test.Test), 'Trying to run a non-Test?!'
- test_class.ProcessCommandLineArgs(parser, args)
test.ProcessCommandLineArgs(parser, args)
+ test_class.ProcessCommandLineArgs(parser, args)
cls._test = test_class
diff --git a/tools/telemetry/telemetry/unittest/__init__.py b/tools/telemetry/telemetry/unittest/__init__.py
index 950282d0c1..4d6aabb953 100644
--- a/tools/telemetry/telemetry/unittest/__init__.py
+++ b/tools/telemetry/telemetry/unittest/__init__.py
@@ -1,3 +1,3 @@
-# Copyright (c) 2014 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/unittest/gtest_testrunner.py b/tools/telemetry/telemetry/unittest/gtest_testrunner.py
index b33bf6ebff..33191762e7 100755
--- a/tools/telemetry/telemetry/unittest/gtest_testrunner.py
+++ b/tools/telemetry/telemetry/unittest/gtest_testrunner.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/unittest/options_for_unittests.py b/tools/telemetry/telemetry/unittest/options_for_unittests.py
index 766a6413b9..fd87bdaf1f 100644
--- a/tools/telemetry/telemetry/unittest/options_for_unittests.py
+++ b/tools/telemetry/telemetry/unittest/options_for_unittests.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/unittest/page_set_smoke_test.py b/tools/telemetry/telemetry/unittest/page_set_smoke_test.py
index aa30415223..b5e22aed03 100644
--- a/tools/telemetry/telemetry/unittest/page_set_smoke_test.py
+++ b/tools/telemetry/telemetry/unittest/page_set_smoke_test.py
@@ -6,6 +6,7 @@ import logging
import os
import unittest
+from telemetry.core import browser_credentials
from telemetry.core import discover
from telemetry.page import page_set as page_set_module
from telemetry.page import page_set_archive_info
@@ -13,35 +14,102 @@ from telemetry.page import page_set_archive_info
class PageSetSmokeTest(unittest.TestCase):
- def RunSmokeTest(self, page_sets_dir):
- """
- Run smoke test on all page sets in page_sets_dir. Subclass of
- PageSetSmokeTest is supposed to call this in some test method to run smoke
- test.
- """
- # Instantiate all page sets and verify that all URLs have an associated
- # archive.
- page_sets = discover.GetAllPageSetFilenames(page_sets_dir)
- for page_set_path in page_sets:
- page_set = page_set_module.PageSet.FromFile(page_set_path)
+ def CheckArchive(self, page_set):
+ """Verify that all URLs of pages in page_set have an associated archive. """
+ # TODO: Eventually these should be fatal.
+ if not page_set.archive_data_file:
+ logging.warning('Skipping %s: no archive data file', page_set.file_path)
+ return
+
+ logging.info('Testing %s', page_set.file_path)
- # TODO: Eventually these should be fatal.
- if not page_set.archive_data_file:
- logging.warning('Skipping %s: no archive data file', page_set_path)
+ archive_data_file_path = os.path.join(page_set.base_dir,
+ page_set.archive_data_file)
+ self.assertTrue(os.path.exists(archive_data_file_path),
+ msg='Archive data file not found for %s' %
+ page_set.file_path)
+
+ wpr_archive_info = page_set_archive_info.PageSetArchiveInfo.FromFile(
+ archive_data_file_path, ignore_archive=True)
+ for page in page_set.pages:
+ if not page.url.startswith('http'):
continue
+ self.assertTrue(wpr_archive_info.WprFilePathForPage(page),
+ msg='No archive found for %s in %s' % (
+ page.url, page_set.archive_data_file))
+
+ def CheckCredentials(self, page_set):
+ """Verify that all pages in page_set use proper credentials"""
+ credentials = browser_credentials.BrowserCredentials()
+ if page_set.credentials_path:
+ credentials.credentials_path = (
+ os.path.join(page_set.base_dir, page_set.credentials_path))
+ for page in page_set.pages:
+ fail_message = ('page %s of %s has invalid credentials %s' %
+ (page.url, page_set.file_path, page.credentials))
+ if page.credentials:
+ try:
+ self.assertTrue(credentials.CanLogin(page.credentials), fail_message)
+ except browser_credentials.CredentialsError:
+ self.fail(fail_message)
- logging.info('Testing %s', page_set_path)
+ def CheckTypes(self, page_set):
+ """Verify that page_set and its page's base attributes have the right types.
+ """
+ self.CheckTypesOfPageSetBasicAttributes(page_set)
+ for page in page_set.pages:
+ self.CheckTypesOfPageBasicAttributes(page)
- archive_data_file_path = os.path.join(page_set.base_dir,
- page_set.archive_data_file)
- self.assertTrue(os.path.exists(archive_data_file_path),
- msg='Archive data file not found for %s' % page_set_path)
+ def CheckTypesOfPageSetBasicAttributes(self, page_set):
+ if page_set.file_path is not None:
+ self.assertTrue(
+ isinstance(page_set.file_path, str),
+ msg='page_set %\'s file_path must have type string')
- wpr_archive_info = page_set_archive_info.PageSetArchiveInfo.FromFile(
- archive_data_file_path, ignore_archive=True)
- for page in page_set.pages:
- if not page.url.startswith('http'):
- continue
- self.assertTrue(wpr_archive_info.WprFilePathForPage(page),
- msg='No archive found for %s in %s' % (
- page.url, page_set.archive_data_file))
+ self.assertTrue(
+ isinstance(page_set.description, str),
+ msg='page_set\'s description must have type string')
+
+ self.assertTrue(
+ isinstance(page_set.archive_data_file, str),
+ msg='page_set\'s archive_data_file path must have type string')
+
+ if page_set.user_agent_type is not None:
+ self.assertTrue(
+ isinstance(page_set.user_agent_type, str),
+ msg='page_set\'s user_agent_type must have type string')
+
+ self.assertTrue(
+ isinstance(page_set.make_javascript_deterministic, bool),
+ msg='page_set\'s make_javascript_deterministic must have type bool')
+
+ self.assertTrue(
+ isinstance(page_set.startup_url, str),
+ msg='page_set\'s startup_url must have type string')
+
+ def CheckTypesOfPageBasicAttributes(self, page):
+ self.assertTrue(
+ isinstance(page.url, str),
+ msg='page %s \'s url must have type string' % page.display_name)
+ self.assertTrue(
+ isinstance(page.page_set, page_set_module.PageSet),
+ msg='page %s \'s page_set must be an instance of '
+ 'telemetry.page.page_set.PageSet' % page.display_name)
+ self.assertTrue(
+ isinstance(page.name, str),
+ msg='page %s \'s name field must have type string' % page.display_name)
+
+ def RunSmokeTest(self, page_sets_dir):
+ """Run smoke test on all page sets in page_sets_dir.
+
+ Subclass of PageSetSmokeTest is supposed to call this in some test
+ method to run smoke test.
+ """
+ page_sets = discover.GetAllPageSetFilenames(page_sets_dir)
+
+ for page_set_path in page_sets:
+ page_set = page_set_module.PageSet.FromFile(page_set_path)
+ logging.info('Testing %s', page_set.file_path)
+ self.CheckArchive(page_set)
+ self.CheckCredentials(page_set)
+ self.CheckTypes(page_set)
diff --git a/tools/telemetry/telemetry/unittest/run_tests.py b/tools/telemetry/telemetry/unittest/run_tests.py
index ac5841f8c6..6ca96764cf 100644
--- a/tools/telemetry/telemetry/unittest/run_tests.py
+++ b/tools/telemetry/telemetry/unittest/run_tests.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/unittest/simple_mock.py b/tools/telemetry/telemetry/unittest/simple_mock.py
index 6d22ffd106..14ecf38bfc 100644
--- a/tools/telemetry/telemetry/unittest/simple_mock.py
+++ b/tools/telemetry/telemetry/unittest/simple_mock.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
"""A very very simple mock object harness."""
diff --git a/tools/telemetry/telemetry/unittest/simple_mock_unittest.py b/tools/telemetry/telemetry/unittest/simple_mock_unittest.py
index f62febc690..9102caa1b0 100644
--- a/tools/telemetry/telemetry/unittest/simple_mock_unittest.py
+++ b/tools/telemetry/telemetry/unittest/simple_mock_unittest.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
import unittest
diff --git a/tools/telemetry/telemetry/unittest/system_stub.py b/tools/telemetry/telemetry/unittest/system_stub.py
index c314bb30f8..879eaf9c09 100644
--- a/tools/telemetry/telemetry/unittest/system_stub.py
+++ b/tools/telemetry/telemetry/unittest/system_stub.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/unittest/tab_test_case.py b/tools/telemetry/telemetry/unittest/tab_test_case.py
index 1802dbe302..51fc2d1a1f 100644
--- a/tools/telemetry/telemetry/unittest/tab_test_case.py
+++ b/tools/telemetry/telemetry/unittest/tab_test_case.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/web_components/__init__.py b/tools/telemetry/telemetry/web_components/__init__.py
index db87381f93..31fb645580 100644
--- a/tools/telemetry/telemetry/web_components/__init__.py
+++ b/tools/telemetry/telemetry/web_components/__init__.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2014 The Chromium Authors. All rights reserved.
+# 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.
"""Web components used by telemetry.
diff --git a/tools/telemetry/telemetry/web_components/dev_server.py b/tools/telemetry/telemetry/web_components/dev_server.py
index 895df7d126..516c95de59 100644
--- a/tools/telemetry/telemetry/web_components/dev_server.py
+++ b/tools/telemetry/telemetry/web_components/dev_server.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2014 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/web_components/results_viewer.py b/tools/telemetry/telemetry/web_components/results_viewer.py
index 6eddcac12b..3e4c80c1fa 100644
--- a/tools/telemetry/telemetry/web_components/results_viewer.py
+++ b/tools/telemetry/telemetry/web_components/results_viewer.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2014 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/web_components/tvcm_stub.py b/tools/telemetry/telemetry/web_components/tvcm_stub.py
index d19f633e3d..214d0f1c6a 100644
--- a/tools/telemetry/telemetry/web_components/tvcm_stub.py
+++ b/tools/telemetry/telemetry/web_components/tvcm_stub.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2014 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/web_components/web_components_project.py b/tools/telemetry/telemetry/web_components/web_components_project.py
index 572918629c..e7b0079a3b 100644
--- a/tools/telemetry/telemetry/web_components/web_components_project.py
+++ b/tools/telemetry/telemetry/web_components/web_components_project.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2014 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/web_components/web_components_unittest.py b/tools/telemetry/telemetry/web_components/web_components_unittest.py
index a43d5db0e6..52314da2a1 100644
--- a/tools/telemetry/telemetry/web_components/web_components_unittest.py
+++ b/tools/telemetry/telemetry/web_components/web_components_unittest.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2014 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/telemetry/web_perf/metrics/mainthread_jank_stats.py b/tools/telemetry/telemetry/web_perf/metrics/mainthread_jank_stats.py
new file mode 100644
index 0000000000..66a86a7052
--- /dev/null
+++ b/tools/telemetry/telemetry/web_perf/metrics/mainthread_jank_stats.py
@@ -0,0 +1,91 @@
+# 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.
+
+
+# A top level slice of a main thread can cause the webapp to behave
+# unresponsively if its thread duration is greater than or equals to
+# USER_PERCEIVABLE_DELAY_THRESHOLD_MS. Human eyes can perceive delay at low as
+# 100ms, but since we use thread time instead of wall-time, we reduce the
+# threshold further to 50ms to make room for other OS's activities.
+USER_PERCEIVABLE_DELAY_THRESHOLD_MS = 50
+
+
+class _MainthreadJankStat(object):
+ """A small wrapper class for storing mainthread jank stats computed for
+ single record.
+ """
+
+ def __init__(self):
+ self.sum_big_top_slices_thread_time = 0
+ self.biggest_top_slice_thread_time = 0
+
+
+def _ComputeMainthreadJankStatsForRecord(renderer_thread, record):
+ """Computes the mainthread jank stat on a record range.
+
+ Returns:
+ An instance of _MainthreadJankStat, which has:
+
+ sum_big_top_slices_thread_time is the total thread duration of all top
+ slices whose thread time ranges overlapped with (thread_start, thread_end)
+ and the overlapped thread duration is greater than or equal
+ USER_PERCEIVABLE_DELAY_THRESHOLD_MS.
+
+ biggest_top_slice_thread_time is the biggest thread duration of all
+ top slices whose thread time ranges overlapped with
+ (thread_start, thread_end).
+
+ Note: thread duration of each slices is computed using overlapped range
+ with (thread_start, thread_end).
+ """
+ stat = _MainthreadJankStat()
+ for s in renderer_thread.toplevel_slices:
+ jank_thread_duration = record.GetOverlappedThreadTimeForSlice(s)
+ stat.biggest_top_slice_thread_time = max(
+ stat.biggest_top_slice_thread_time, jank_thread_duration)
+ if jank_thread_duration >= USER_PERCEIVABLE_DELAY_THRESHOLD_MS:
+ stat.sum_big_top_slices_thread_time += jank_thread_duration
+ return stat
+
+
+class MainthreadJankStats(object):
+ """
+ Utility class for extracting main thread jank statistics from the timeline
+ (or other loggin facilities), and providing them in a common format to
+ classes that compute benchmark metrics from this data.
+
+ total_big_jank_thread_time is the total thread duration of all top
+ slices whose thread time ranges overlapped with any thread time ranges of
+ the records and the overlapped thread duration is greater than or equal
+ USER_PERCEIVABLE_DELAY_THRESHOLD_MS.
+
+ biggest_jank_thread_time is the biggest thread duration of all
+ top slices whose thread time ranges overlapped with any of records' thread
+ time ranges.
+ """
+
+ def __init__(self, renderer_thread, interaction_records):
+ self._renderer_thread = renderer_thread
+ self._interaction_records = interaction_records
+ self._total_big_jank_thread_time = 0
+ self._biggest_jank_thread_time = 0
+ self._ComputeMainthreadJankStats()
+
+ @property
+ def total_big_jank_thread_time(self):
+ return self._total_big_jank_thread_time
+
+ @property
+ def biggest_jank_thread_time(self):
+ return self._biggest_jank_thread_time
+
+ def _ComputeMainthreadJankStats(self):
+ for record in self._interaction_records:
+ record_jank_stat = _ComputeMainthreadJankStatsForRecord(
+ self._renderer_thread, record)
+ self._total_big_jank_thread_time += (
+ record_jank_stat.sum_big_top_slices_thread_time)
+ self._biggest_jank_thread_time = (
+ max(self._biggest_jank_thread_time,
+ record_jank_stat.biggest_top_slice_thread_time))
diff --git a/tools/telemetry/telemetry/web_perf/metrics/mainthread_jank_stats_unittest.py b/tools/telemetry/telemetry/web_perf/metrics/mainthread_jank_stats_unittest.py
new file mode 100644
index 0000000000..b1cbca0154
--- /dev/null
+++ b/tools/telemetry/telemetry/web_perf/metrics/mainthread_jank_stats_unittest.py
@@ -0,0 +1,118 @@
+# 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 unittest
+
+from telemetry.core.timeline import model as model_module
+from telemetry.core.timeline import async_slice
+from telemetry.web_perf import timeline_interaction_record as tir_module
+from telemetry.web_perf.metrics import mainthread_jank_stats
+
+
+class MainthreadJankTests(unittest.TestCase):
+
+ def CreateTestRecord(self, name, start, end, thread_start, thread_end,
+ parent_thread):
+ s = async_slice.AsyncSlice(
+ 'cat', 'Interaction.%s/is_responsive' % name,
+ timestamp=start, duration=end - start, start_thread=parent_thread,
+ end_thread=parent_thread, thread_start=thread_start,
+ thread_duration=thread_end - thread_start)
+ return tir_module.TimelineInteractionRecord.FromAsyncEvent(s)
+
+ def testComputeMainthreadJankStatsForRecord(self):
+ # The slice hierarchy should look something like this:
+ # [ MessageLoop::RunTask ] [MessageLoop::RunTask][ MessagLoop::RunTask ]
+ # [ foo ] [ bar ]
+ # | |
+ # 200ms 800ms
+ # (thread_start) (thread_end)
+ #
+ # Note: all timings mentioned here and in comments below are thread time.
+
+ model = model_module.TimelineModel()
+ renderer_main = model.GetOrCreateProcess(1).GetOrCreateThread(2)
+ renderer_main.name = 'CrRendererMain'
+
+ # [ MessageLoop::RunTask ]
+ # 100ms 300ms
+ renderer_main.BeginSlice('toplevel', 'MessageLoop::RunTask', 112, 100)
+ renderer_main.EndSlice(240, 300)
+
+ # [ MessageLoop::RunTask ]
+ # 450ms [ foo ] 475 ms
+ # 460ms 470ms
+ renderer_main.BeginSlice('toplevel', 'MessageLoop::RunTask', 462, 450)
+ renderer_main.BeginSlice('otherlevel', 'foo', 468, 460)
+ renderer_main.EndSlice(475, 470)
+ renderer_main.EndSlice(620, 475)
+
+ # [ MessageLoop::RunTask ]
+ # 620ms [ bar ] 900ms
+ # 750ms 850ms
+ renderer_main.BeginSlice('toplevel', 'MessageLoop::RunTask', 652, 620)
+ renderer_main.BeginSlice('otherlevel', 'bar', 785, 750)
+ renderer_main.EndSlice(875, 850)
+ renderer_main.EndSlice(1040, 900)
+
+ model.FinalizeImport(shift_world_to_zero=False)
+
+ # Make a record that starts at 200ms and ends at 800ms in thread time
+ record = self.CreateTestRecord('test', 100, 700, 200, 800, renderer_main)
+ # pylint: disable=W0212
+ stat = mainthread_jank_stats._ComputeMainthreadJankStatsForRecord(
+ renderer_main, record)
+
+ # The overlapped between thread time range(200ms -> 800ms)
+ # with the first top slice (100ms -> 300ms) is 300 - 200 = 100ms,
+ # with the second slice (450ms -> 475ms) is 475 - 450 = 25 ms,
+ # with the third slice (620ms -> 900ms) is 800 - 620 = 180 ms.
+ #
+ # Hence we have 2 big top slices which overlapped duration > 50ms,
+ # the biggest top slice is 180ms, and the total big top slice's thread time
+ # is 100 + 180 = 280ms.
+ self.assertEquals(180, stat.biggest_top_slice_thread_time)
+ self.assertEquals(280, stat.sum_big_top_slices_thread_time)
+
+ def testMainthreadJankStats(self):
+ # [ MessageLoop::RunTask] [MessageLoop::RunTask] [MessagLoop::RunTask]
+ # 10 100 120 400 450 750
+ # [ record_1 ] [ record_2 ] [ record_3 ]
+ # 40 70 120 200 220 900
+
+ model = model_module.TimelineModel()
+ renderer_main = model.GetOrCreateProcess(1).GetOrCreateThread(2)
+ renderer_main.name = 'CrRendererMain'
+
+ # [ MessageLoop::RunTask ]
+ # 10ms 100ms
+ renderer_main.BeginSlice('toplevel', 'MessageLoop::RunTask', 12, 10)
+ renderer_main.EndSlice(120, 100)
+
+ # [ MessageLoop::RunTask ]
+ # 120ms 200ms
+ renderer_main.BeginSlice('toplevel', 'MessageLoop::RunTask', 115, 120)
+ renderer_main.EndSlice(410, 400)
+
+ # [ MessageLoop::RunTask ]
+ # 220ms 900ms
+ renderer_main.BeginSlice('toplevel', 'MessageLoop::RunTask', 477, 450)
+ renderer_main.EndSlice(772, 750)
+
+ model.FinalizeImport(shift_world_to_zero=False)
+
+ test_records = [
+ self.CreateTestRecord('record_1', 10, 80, 40, 70, renderer_main),
+ self.CreateTestRecord('record_2', 100, 210, 120, 200, renderer_main),
+ self.CreateTestRecord('record_3', 215, 920, 220, 900, renderer_main)
+ ]
+
+ stats = mainthread_jank_stats.MainthreadJankStats(
+ renderer_main, test_records)
+ # Main thread janks covered by records' ranges are:
+ # Record 1: (40ms -> 70ms)
+ # Record 2: (120ms -> 200ms)
+ # Record 3: (220ms -> 400ms), (450ms -> 750ms)
+ self.assertEquals(560, stats.total_big_jank_thread_time)
+ self.assertEquals(300, stats.biggest_jank_thread_time)
diff --git a/tools/telemetry/telemetry/web_perf/metrics/rendering_stats.py b/tools/telemetry/telemetry/web_perf/metrics/rendering_stats.py
index 1a483b8e4b..e53bf41701 100644
--- a/tools/telemetry/telemetry/web_perf/metrics/rendering_stats.py
+++ b/tools/telemetry/telemetry/web_perf/metrics/rendering_stats.py
@@ -30,76 +30,53 @@ class NotEnoughFramesError(page_measurement.MeasurementFailure):
'- Pages that can\'t be scrolled')
-def GetScrollInputLatencyEvents(scroll_type, browser_process, timeline_range):
- """Get scroll events' LatencyInfo from the browser process's trace buffer
- that are within the timeline_range.
+def GetInputLatencyEvents(process, timeline_range):
+ """Get input events' LatencyInfo from the process's trace buffer that are
+ within the timeline_range.
- Scroll events (MouseWheel, GestureScrollUpdate or JS scroll on TouchMove)
- dump their LatencyInfo into trace buffer as async trace event with name
- "InputLatency". The trace event has a memeber 'step' containing its event
- type and a memeber 'data' containing its latency history.
+ Input events dump their LatencyInfo into trace buffer as async trace event
+ with name "InputLatency". The trace event has a memeber 'data' containing
+ its latency history.
"""
- scroll_events = []
- if not browser_process:
- return scroll_events
- for event in browser_process.IterAllAsyncSlicesOfName("InputLatency"):
+ input_events = []
+ if not process:
+ return input_events
+ for event in process.IterAllAsyncSlicesOfName("InputLatency"):
if event.start >= timeline_range.min and event.end <= timeline_range.max:
for ss in event.sub_slices:
- if 'step' not in ss.args:
- continue
- if 'data' not in ss.args:
- continue
- if ss.args['step'] == scroll_type:
- scroll_events.append(ss)
- return scroll_events
-
-
-def ComputeMouseWheelScrollLatency(mouse_wheel_events):
- """ Compute the mouse wheel scroll latency.
-
- Mouse wheel scroll latency is the time from when mouse wheel event is sent
- from browser RWH to renderer (the timestamp of component
- 'INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT') to when the scrolled page is
- buffer swapped (the timestamp of component
- 'INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT')
-
- """
- mouse_wheel_latency = []
- for event in mouse_wheel_events:
- data = event.args['data']
- if BEGIN_COMP_NAME in data and END_COMP_NAME in data:
- latency = data[END_COMP_NAME]['time'] - data[BEGIN_COMP_NAME]['time']
- mouse_wheel_latency.append(latency / 1000.0)
- return mouse_wheel_latency
-
-
-def ComputeTouchScrollLatency(touch_scroll_events):
- """ Compute the touch scroll latency.
-
- Touch scroll latency is the time from when the touch event is created to
- when the scrolled page is buffer swapped.
- Touch event on differnt platforms uses different LatencyInfo component to
- record its creation timestamp. On Aura, the creation time is kept in
- 'INPUT_EVENT_LATENCY_UI_COMPONENT' . On Android, the creation time is kept
- in 'INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT'.
+ if 'data' in ss.args:
+ input_events.append(ss)
+ return input_events
+
+def ComputeInputEventLatency(input_events):
+ """ Compute the input event latency.
+
+ Input event latency is the time from when the input event is created to
+ when its resulted page is swap buffered.
+ Input event on differnt platforms uses different LatencyInfo component to
+ record its creation timestamp. We go through the following component list
+ to find the creation timestamp:
+ 1. INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT -- when event is created in OS
+ 2. INPUT_EVENT_LATENCY_UI_COMPONENT -- when event reaches Chrome
+ 3. INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT -- when event reaches RenderWidget
"""
- touch_scroll_latency = []
- for event in touch_scroll_events:
+ input_event_latency = []
+ for event in input_events:
data = event.args['data']
if END_COMP_NAME in data:
end_time = data[END_COMP_NAME]['time']
- if UI_COMP_NAME in data and ORIGINAL_COMP_NAME in data:
- raise ValueError, 'LatencyInfo has both UI and ORIGINAL component'
- if UI_COMP_NAME in data:
- latency = end_time - data[UI_COMP_NAME]['time']
- touch_scroll_latency.append(latency / 1000.0)
- elif ORIGINAL_COMP_NAME in data:
+ if ORIGINAL_COMP_NAME in data:
latency = end_time - data[ORIGINAL_COMP_NAME]['time']
- touch_scroll_latency.append(latency / 1000.0)
- return touch_scroll_latency
-
+ elif UI_COMP_NAME in data:
+ latency = end_time - data[UI_COMP_NAME]['time']
+ elif BEGIN_COMP_NAME in data:
+ latency = end_time - data[BEGIN_COMP_NAME]['time']
+ else:
+ raise ValueError, 'LatencyInfo has no begin component'
+ input_event_latency.append(latency / 1000.0)
+ return input_event_latency
def HasRenderingStats(process):
""" Returns True if the process contains at least one
@@ -146,15 +123,9 @@ class RenderingStats(object):
self.rasterize_times = []
self.rasterized_pixel_counts = []
self.approximated_pixel_percentages = []
- # End-to-end latency for MouseWheel scroll - from when mouse wheel event is
- # generated to when the scrolled page is buffer swapped.
- self.mouse_wheel_scroll_latency = []
- # End-to-end latency for GestureScrollUpdate scroll - from when the touch
- # event is generated to the scrolled page is buffer swapped.
- self.touch_scroll_latency = []
- # End-to-end latency for JS touch handler scrolling - from when the touch
- # event is generated to the scrolled page is buffer swapped.
- self.js_touch_scroll_latency = []
+ # End-to-end latency for input event - from when input event is
+ # generated to when the its resulted page is swap buffered.
+ self.input_event_latency = []
for timeline_range in timeline_ranges:
self.frame_timestamps.append([])
@@ -166,9 +137,7 @@ class RenderingStats(object):
self.rasterize_times.append([])
self.rasterized_pixel_counts.append([])
self.approximated_pixel_percentages.append([])
- self.mouse_wheel_scroll_latency.append([])
- self.touch_scroll_latency.append([])
- self.js_touch_scroll_latency.append([])
+ self.input_event_latency.append([])
if timeline_range.is_empty:
continue
@@ -177,7 +146,8 @@ class RenderingStats(object):
renderer_process, timeline_range)
self._InitImplThreadRenderingStatsFromTimeline(
renderer_process, timeline_range)
- self._InitScrollLatencyStatsFromTimeline(browser_process, timeline_range)
+ self._InitInputLatencyStatsFromTimeline(
+ browser_process, renderer_process, timeline_range)
# Check if we have collected at least 2 frames in every range. Otherwise we
# can't compute any meaningful metrics.
@@ -185,21 +155,13 @@ class RenderingStats(object):
if len(segment) < 2:
raise NotEnoughFramesError(len(segment))
- def _InitScrollLatencyStatsFromTimeline(
- self, browser_process, timeline_range):
- mouse_wheel_events = GetScrollInputLatencyEvents(
- "MouseWheel", browser_process, timeline_range)
- self.mouse_wheel_scroll_latency = ComputeMouseWheelScrollLatency(
- mouse_wheel_events)
-
- touch_scroll_events = GetScrollInputLatencyEvents(
- "GestureScrollUpdate", browser_process, timeline_range)
- self.touch_scroll_latency = ComputeTouchScrollLatency(touch_scroll_events)
-
- js_touch_scroll_events = GetScrollInputLatencyEvents(
- "TouchMove", browser_process, timeline_range)
- self.js_touch_scroll_latency = ComputeTouchScrollLatency(
- js_touch_scroll_events)
+ def _InitInputLatencyStatsFromTimeline(
+ self, browser_process, renderer_process, timeline_range):
+ latency_events = GetInputLatencyEvents(browser_process, timeline_range)
+ # Plugin input event's latency slice is generated in renderer process.
+ latency_events.extend(GetInputLatencyEvents(renderer_process,
+ timeline_range))
+ self.input_event_latency[-1] = ComputeInputEventLatency(latency_events)
def _GatherEvents(self, event_name, process, timeline_range):
events = []
diff --git a/tools/telemetry/telemetry/web_perf/metrics/rendering_stats_unittest.py b/tools/telemetry/telemetry/web_perf/metrics/rendering_stats_unittest.py
index 4ec6644e36..20b0132ac9 100644
--- a/tools/telemetry/telemetry/web_perf/metrics/rendering_stats_unittest.py
+++ b/tools/telemetry/telemetry/web_perf/metrics/rendering_stats_unittest.py
@@ -6,12 +6,9 @@ import random
import unittest
from telemetry.web_perf.metrics.rendering_stats import (
- UI_COMP_NAME, BEGIN_COMP_NAME, END_COMP_NAME)
-from telemetry.web_perf.metrics.rendering_stats import (
- GetScrollInputLatencyEvents)
-from telemetry.web_perf.metrics.rendering_stats import (
- ComputeMouseWheelScrollLatency)
-from telemetry.web_perf.metrics.rendering_stats import ComputeTouchScrollLatency
+ UI_COMP_NAME, BEGIN_COMP_NAME, ORIGINAL_COMP_NAME, END_COMP_NAME)
+from telemetry.web_perf.metrics.rendering_stats import ComputeInputEventLatency
+from telemetry.web_perf.metrics.rendering_stats import GetInputLatencyEvents
from telemetry.web_perf.metrics.rendering_stats import HasRenderingStats
from telemetry.web_perf.metrics.rendering_stats import RenderingStats
from telemetry.web_perf.metrics.rendering_stats import NotEnoughFramesError
@@ -67,12 +64,8 @@ class ReferenceRenderingStats(object):
class ReferenceInputLatencyStats(object):
""" Stores expected data for comparison with actual input latency stats """
def __init__(self):
- self.mouse_wheel_scroll_latency = []
- self.touch_scroll_latency = []
- self.js_touch_scroll_latency = []
- self.mouse_wheel_scroll_events = []
- self.touch_scroll_events = []
- self.js_touch_scroll_events = []
+ self.input_event_latency = []
+ self.input_event = []
def AddMainThreadRenderingStats(mock_timer, thread, first_frame,
ref_stats = None):
@@ -155,24 +148,26 @@ def AddImplThreadRenderingStats(mock_timer, thread, first_frame,
data['visible_content_area']) * 100.0, 3))
-def AddInputLatencyStats(mock_timer, input_type, start_thread, end_thread,
+def AddInputLatencyStats(mock_timer, start_thread, end_thread,
ref_latency_stats = None):
""" Adds a random input latency stats event.
- input_type: The input type for which the latency slice is generated.
start_thread: The start thread on which the async slice is added.
end_thread: The end thread on which the async slice is ended.
ref_latency_stats: A ReferenceInputLatencyStats object for expected values.
"""
mock_timer.Advance(2, 4)
+ original_comp_time = mock_timer.Get() * 1000.0
+ mock_timer.Advance(2, 4)
ui_comp_time = mock_timer.Get() * 1000.0
mock_timer.Advance(2, 4)
begin_comp_time = mock_timer.Get() * 1000.0
mock_timer.Advance(10, 20)
end_comp_time = mock_timer.Get() * 1000.0
- data = { UI_COMP_NAME: {'time': ui_comp_time},
+ data = { ORIGINAL_COMP_NAME: {'time': original_comp_time},
+ UI_COMP_NAME: {'time': ui_comp_time},
BEGIN_COMP_NAME: {'time': begin_comp_time},
END_COMP_NAME: {'time': end_comp_time} }
@@ -183,7 +178,7 @@ def AddInputLatencyStats(mock_timer, input_type, start_thread, end_thread,
async_sub_slice = tracing_async_slice.AsyncSlice(
'benchmark', 'InputLatency', timestamp)
- async_sub_slice.args = {'data': data, 'step': input_type}
+ async_sub_slice.args = {'data': data}
async_sub_slice.parent_slice = async_slice
async_sub_slice.start_thread = start_thread
async_sub_slice.end_thread = end_thread
@@ -196,20 +191,9 @@ def AddInputLatencyStats(mock_timer, input_type, start_thread, end_thread,
if not ref_latency_stats:
return
- if input_type == 'MouseWheel':
- ref_latency_stats.mouse_wheel_scroll_events.append(async_sub_slice)
- ref_latency_stats.mouse_wheel_scroll_latency.append(
- (data[END_COMP_NAME]['time'] - data[BEGIN_COMP_NAME]['time']) / 1000.0)
-
- if input_type == 'GestureScrollUpdate':
- ref_latency_stats.touch_scroll_events.append(async_sub_slice)
- ref_latency_stats.touch_scroll_latency.append(
- (data[END_COMP_NAME]['time'] - data[UI_COMP_NAME]['time']) / 1000.0)
-
- if input_type == 'TouchMove':
- ref_latency_stats.js_touch_scroll_events.append(async_sub_slice)
- ref_latency_stats.js_touch_scroll_latency.append(
- (data[END_COMP_NAME]['time'] - data[UI_COMP_NAME]['time']) / 1000.0)
+ ref_latency_stats.input_event.append(async_sub_slice)
+ ref_latency_stats.input_event_latency.append(
+ (data[END_COMP_NAME]['time'] - data[ORIGINAL_COMP_NAME]['time']) / 1000.0)
class RenderingStatsUnitTest(unittest.TestCase):
def testHasRenderingStats(self):
@@ -379,7 +363,7 @@ class RenderingStatsUnitTest(unittest.TestCase):
self.assertEquals(stats.recorded_pixel_counts,
renderer_ref_stats.recorded_pixel_counts)
- def testScrollLatencyFromTimeline(self):
+ def testInputLatencyFromTimeline(self):
timeline = model.TimelineModel()
# Create a browser process and a renderer process.
@@ -389,41 +373,26 @@ class RenderingStatsUnitTest(unittest.TestCase):
renderer_main = renderer.GetOrCreateThread(tid = 21)
timer = MockTimer()
- ref_latency_stats = ReferenceInputLatencyStats()
+ ref_latency = ReferenceInputLatencyStats()
# Create 10 input latency stats events for Action A.
timer.Advance(2, 4)
renderer_main.BeginSlice('webkit.console', 'ActionA', timer.Get(), '')
for _ in xrange(0, 10):
- AddInputLatencyStats(timer, 'MouseWheel', browser_main,
- renderer_main, ref_latency_stats)
- AddInputLatencyStats(timer, 'GestureScrollUpdate', browser_main,
- renderer_main, ref_latency_stats)
- AddInputLatencyStats(timer, 'TouchMove', browser_main,
- renderer_main, ref_latency_stats)
+ AddInputLatencyStats(timer, browser_main, renderer_main, ref_latency)
timer.Advance(2, 4)
renderer_main.EndSlice(timer.Get())
# Create 5 input latency stats events not within any action.
timer.Advance(2, 4)
for _ in xrange(0, 5):
- AddInputLatencyStats(timer, 'MouseWheel', browser_main,
- renderer_main, None)
- AddInputLatencyStats(timer, 'GestureScrollUpdate', browser_main,
- renderer_main, None)
- AddInputLatencyStats(timer, 'TouchMove', browser_main,
- renderer_main, None)
+ AddInputLatencyStats(timer, browser_main, renderer_main, None)
# Create 10 input latency stats events for Action B.
timer.Advance(2, 4)
renderer_main.BeginSlice('webkit.console', 'ActionB', timer.Get(), '')
for _ in xrange(0, 10):
- AddInputLatencyStats(timer, 'MouseWheel', browser_main,
- renderer_main, ref_latency_stats)
- AddInputLatencyStats(timer, 'GestureScrollUpdate', browser_main,
- renderer_main, ref_latency_stats)
- AddInputLatencyStats(timer, 'TouchMove', browser_main,
- renderer_main, ref_latency_stats)
+ AddInputLatencyStats(timer, browser_main, renderer_main, ref_latency)
timer.Advance(2, 4)
renderer_main.EndSlice(timer.Get())
@@ -431,21 +400,14 @@ class RenderingStatsUnitTest(unittest.TestCase):
timer.Advance(2, 4)
renderer_main.BeginSlice('webkit.console', 'ActionA', timer.Get(), '')
for _ in xrange(0, 10):
- AddInputLatencyStats(timer, 'MouseWheel', browser_main,
- renderer_main, ref_latency_stats)
- AddInputLatencyStats(timer, 'GestureScrollUpdate', browser_main,
- renderer_main, ref_latency_stats)
- AddInputLatencyStats(timer, 'TouchMove', browser_main,
- renderer_main, ref_latency_stats)
+ AddInputLatencyStats(timer, browser_main, renderer_main, ref_latency)
timer.Advance(2, 4)
renderer_main.EndSlice(timer.Get())
browser.FinalizeImport()
renderer.FinalizeImport()
- mouse_wheel_scroll_events = []
- touch_scroll_events = []
- js_touch_scroll_events = []
+ input_events = []
timeline_markers = timeline.FindTimelineMarkers(
['ActionA', 'ActionB', 'ActionA'])
@@ -453,25 +415,8 @@ class RenderingStatsUnitTest(unittest.TestCase):
for marker in timeline_markers ]:
if timeline_range.is_empty:
continue
- tmp_mouse_events = GetScrollInputLatencyEvents(
- 'MouseWheel', browser, timeline_range)
- tmp_touch_scroll_events = GetScrollInputLatencyEvents(
- 'GestureScrollUpdate', browser, timeline_range)
- tmp_js_touch_scroll_events = GetScrollInputLatencyEvents(
- 'TouchMove', browser, timeline_range)
- mouse_wheel_scroll_events.extend(tmp_mouse_events)
- touch_scroll_events.extend(tmp_touch_scroll_events)
- js_touch_scroll_events.extend(tmp_js_touch_scroll_events)
-
- self.assertEquals(mouse_wheel_scroll_events,
- ref_latency_stats.mouse_wheel_scroll_events)
- self.assertEquals(touch_scroll_events,
- ref_latency_stats.touch_scroll_events)
- self.assertEquals(js_touch_scroll_events,
- ref_latency_stats.js_touch_scroll_events)
- self.assertEquals(ComputeMouseWheelScrollLatency(mouse_wheel_scroll_events),
- ref_latency_stats.mouse_wheel_scroll_latency)
- self.assertEquals(ComputeTouchScrollLatency(touch_scroll_events),
- ref_latency_stats.touch_scroll_latency)
- self.assertEquals(ComputeTouchScrollLatency(js_touch_scroll_events),
- ref_latency_stats.js_touch_scroll_latency)
+ input_events.extend(GetInputLatencyEvents(browser, timeline_range))
+
+ self.assertEquals(input_events, ref_latency.input_event)
+ self.assertEquals(ComputeInputEventLatency(input_events),
+ ref_latency.input_event_latency)
diff --git a/tools/telemetry/telemetry/web_perf/metrics/responsiveness_metric.py b/tools/telemetry/telemetry/web_perf/metrics/responsiveness_metric.py
new file mode 100644
index 0000000000..17e765afee
--- /dev/null
+++ b/tools/telemetry/telemetry/web_perf/metrics/responsiveness_metric.py
@@ -0,0 +1,47 @@
+# 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 logging
+
+from telemetry.web_perf import timeline_interaction_record as tir_module
+from telemetry.web_perf.metrics import mainthread_jank_stats
+from telemetry.web_perf.metrics import timeline_based_metric
+
+
+class ResponsivenessMetric(timeline_based_metric.TimelineBasedMetric):
+ """Computes metrics that measure respsonsiveness on the record ranges.
+
+ total_big_jank_thread_time is the total thread duration of all top
+ slices whose thread time ranges overlapped with any thread time ranges of
+ the records and the overlapped thread duration is greater than or equal
+ USER_PERCEIVABLE_DELAY_THRESHOLD_MS.
+
+ biggest_jank_thread_time is the biggest thread duration of all
+ top slices whose thread time ranges overlapped with any of records' thread
+ time ranges.
+
+ All *_time values are measured in milliseconds.
+ """
+
+ def __init__(self):
+ super(ResponsivenessMetric, self).__init__()
+
+ def AddResults(self, _, renderer_thread, interaction_records, results):
+ self.VerifyNonOverlappedRecords(interaction_records)
+ try:
+ jank_stats = mainthread_jank_stats.MainthreadJankStats(
+ renderer_thread, interaction_records)
+ # TODO(nednguyen): maybe fall back to use wall-time for computing the
+ # metrics.
+ except tir_module.NoThreadTimeDataException as e:
+ #TODO(nednguyen): Report the warning with page_results system.
+ logging.warning(
+ 'Main thread jank metrics cannot be computed for records %s since '
+ 'trace does not contain thread time data. %s',
+ repr(interaction_records), repr(e))
+ return
+
+ results.Add('responsive-total_big_jank_thread_time', 'ms',
+ jank_stats.total_big_jank_thread_time)
+ results.Add('responsive-biggest_jank_thread_time', 'ms',
+ jank_stats.biggest_jank_thread_time)
diff --git a/tools/telemetry/telemetry/web_perf/metrics/smoothness.py b/tools/telemetry/telemetry/web_perf/metrics/smoothness.py
index fff1f1ec7a..a8158870f8 100644
--- a/tools/telemetry/telemetry/web_perf/metrics/smoothness.py
+++ b/tools/telemetry/telemetry/web_perf/metrics/smoothness.py
@@ -18,35 +18,17 @@ class SmoothnessMetric(timeline_based_metric.TimelineBasedMetric):
stats = rendering_stats.RenderingStats(
renderer_process, model.browser_process,
[r.GetBounds() for r in interaction_records])
- if stats.mouse_wheel_scroll_latency:
- mean_mouse_wheel_scroll_latency = statistics.ArithmeticMean(
- stats.mouse_wheel_scroll_latency)
- mouse_wheel_scroll_latency_discrepancy = statistics.DurationsDiscrepancy(
- stats.mouse_wheel_scroll_latency)
- results.Add('mean_mouse_wheel_scroll_latency', 'ms',
- round(mean_mouse_wheel_scroll_latency, 3))
- results.Add('mouse_wheel_scroll_latency_discrepancy', 'ms',
- round(mouse_wheel_scroll_latency_discrepancy, 4))
- if stats.touch_scroll_latency:
- mean_touch_scroll_latency = statistics.ArithmeticMean(
- stats.touch_scroll_latency)
- touch_scroll_latency_discrepancy = statistics.DurationsDiscrepancy(
- stats.touch_scroll_latency)
- results.Add('mean_touch_scroll_latency', 'ms',
- round(mean_touch_scroll_latency, 3))
- results.Add('touch_scroll_latency_discrepancy', 'ms',
- round(touch_scroll_latency_discrepancy, 4))
-
- if stats.js_touch_scroll_latency:
- mean_js_touch_scroll_latency = statistics.ArithmeticMean(
- stats.js_touch_scroll_latency)
- js_touch_scroll_latency_discrepancy = statistics.DurationsDiscrepancy(
- stats.js_touch_scroll_latency)
- results.Add('mean_js_touch_scroll_latency', 'ms',
- round(mean_js_touch_scroll_latency, 3))
- results.Add('js_touch_scroll_latency_discrepancy', 'ms',
- round(js_touch_scroll_latency_discrepancy, 4))
+ input_event_latency = FlattenList(stats.input_event_latency)
+ if input_event_latency:
+ mean_input_event_latency = statistics.ArithmeticMean(
+ input_event_latency)
+ input_event_latency_discrepancy = statistics.DurationsDiscrepancy(
+ input_event_latency)
+ results.Add('mean_input_event_latency', 'ms',
+ round(mean_input_event_latency, 3))
+ results.Add('input_event_latency_discrepancy', 'ms',
+ round(input_event_latency_discrepancy, 4))
# List of raw frame times.
frame_times = FlattenList(stats.frame_times)
diff --git a/tools/telemetry/telemetry/web_perf/timeline_based_measurement.py b/tools/telemetry/telemetry/web_perf/timeline_based_measurement.py
index f8266390a3..cdf66bb160 100644
--- a/tools/telemetry/telemetry/web_perf/timeline_based_measurement.py
+++ b/tools/telemetry/telemetry/web_perf/timeline_based_measurement.py
@@ -10,6 +10,7 @@ from telemetry.core.backends.chrome import tracing_backend
from telemetry.core.timeline import model as model_module
from telemetry.web_perf import timeline_interaction_record as tir_module
from telemetry.web_perf.metrics import smoothness
+from telemetry.web_perf.metrics import responsiveness_metric
from telemetry.page import page_measurement
from telemetry.value import string as string_value_module
@@ -58,7 +59,6 @@ class _TimelineBasedMetrics(object):
event in self._renderer_thread.async_slices
if tir_module.IsTimelineInteractionRecord(event.name)]
-
def AddResults(self, results):
interactions = self.FindTimelineInteractionRecords()
if len(interactions) == 0:
@@ -101,12 +101,12 @@ class TimelineBasedMeasurement(page_measurement.PageMeasurement):
@classmethod
def AddCommandLineArgs(cls, parser):
parser.add_option(
- '--overhead-level', type='choice',
+ '--overhead-level', dest='overhead_level', type='choice',
choices=ALL_OVERHEAD_LEVELS,
default=NO_OVERHEAD_LEVEL,
help='How much overhead to incur during the measurement.')
parser.add_option(
- '--trace-dir', type='string', default=None,
+ '--trace-dir', dest='trace_dir', type='string', default=None,
help=('Where to save the trace after the run. If this flag '
'is not set, the trace will not be saved.'))
@@ -131,6 +131,8 @@ class TimelineBasedMeasurement(page_measurement.PageMeasurement):
res = []
if interaction.is_smooth:
res.append(smoothness.SmoothnessMetric())
+ if interaction.is_responsive:
+ res.append(responsiveness_metric.ResponsivenessMetric())
return res
def MeasurePage(self, page, tab, results):
diff --git a/tools/telemetry/telemetry/web_perf/timeline_based_measurement_unittest.py b/tools/telemetry/telemetry/web_perf/timeline_based_measurement_unittest.py
index c4eeae9e8f..99444fbd0f 100644
--- a/tools/telemetry/telemetry/web_perf/timeline_based_measurement_unittest.py
+++ b/tools/telemetry/telemetry/web_perf/timeline_based_measurement_unittest.py
@@ -12,11 +12,16 @@ from telemetry.core.timeline import async_slice
from telemetry.page import page_measurement_results
from telemetry.page import page_measurement_unittest_base
from telemetry.page import page_set
+from telemetry.page import page as page_module
+# pylint: disable=W0401,W0614
+from telemetry.page.actions.all_page_actions import *
from telemetry.unittest import options_for_unittests
from telemetry.web_perf import timeline_based_measurement as tbm_module
from telemetry.web_perf.metrics import timeline_based_metric
+
class TimelineBasedMetricsTests(unittest.TestCase):
+
def setUp(self):
model = model_module.TimelineModel()
renderer_thread = model.GetOrCreateProcess(1).GetOrCreateThread(2)
@@ -33,7 +38,7 @@ class TimelineBasedMetricsTests(unittest.TestCase):
start_thread=renderer_thread, end_thread=renderer_thread,
thread_start=5, thread_duration=15))
renderer_thread.async_slices.append(async_slice.AsyncSlice(
- 'cat', 'Interaction.LogicalName2/is_loading_resources',
+ 'cat', 'Interaction.LogicalName2/is_responsive',
timestamp=25, duration=5,
start_thread=renderer_thread, end_thread=renderer_thread,
thread_start=25, thread_duration=5))
@@ -43,26 +48,29 @@ class TimelineBasedMetricsTests(unittest.TestCase):
self.renderer_thread = renderer_thread
def testFindTimelineInteractionRecords(self):
- metric = tbm_module._TimelineBasedMetrics( # pylint: disable=W0212
- self.model, self.renderer_thread, lambda _: [] )
+ metric = tbm_module._TimelineBasedMetrics( # pylint: disable=W0212
+ self.model, self.renderer_thread, lambda _: [])
interactions = metric.FindTimelineInteractionRecords()
self.assertEquals(2, len(interactions))
self.assertTrue(interactions[0].is_smooth)
self.assertEquals(0, interactions[0].start)
self.assertEquals(20, interactions[0].end)
- self.assertTrue(interactions[1].is_loading_resources)
+ self.assertTrue(interactions[1].is_responsive)
self.assertEquals(25, interactions[1].start)
self.assertEquals(30, interactions[1].end)
def testAddResults(self):
results = page_measurement_results.PageMeasurementResults()
+
class FakeSmoothMetric(timeline_based_metric.TimelineBasedMetric):
+
def AddResults(self, model, renderer_thread,
interaction_records, results):
results.Add('FakeSmoothMetric', 'ms', 1)
class FakeLoadingMetric(timeline_based_metric.TimelineBasedMetric):
+
def AddResults(self, model, renderer_thread,
interaction_records, results):
for r in interaction_records:
@@ -73,11 +81,11 @@ class TimelineBasedMetricsTests(unittest.TestCase):
res = []
if interaction.is_smooth:
res.append(FakeSmoothMetric())
- if interaction.is_loading_resources:
+ if interaction.is_responsive:
res.append(FakeLoadingMetric())
return res
- metric = tbm_module._TimelineBasedMetrics( # pylint: disable=W0212
+ metric = tbm_module._TimelineBasedMetrics( # pylint: disable=W0212
self.model, self.renderer_thread,
CreateMetricsForTimelineInteractionRecord)
ps = page_set.PageSet(file_path=os.path.dirname(__file__))
@@ -93,19 +101,33 @@ class TimelineBasedMetricsTests(unittest.TestCase):
self.assertEquals(len(v), 1)
+class TestTimelinebasedMeasurementPage(page_module.Page):
+
+ def __init__(self, ps, base_dir):
+ super(TestTimelinebasedMeasurementPage, self).__init__(
+ 'file://interaction_enabled_page.html', ps, base_dir)
+
+ def RunSmoothness(self, action_runner):
+ action_runner.RunAction(WaitAction({'seconds': 2}))
+ action_runner.RunAction(TapAction(
+ {'selector': '#drawer', 'automatically_record_interaction': False}))
+ action_runner.RunAction(WaitAction({'seconds': 1}))
+
+
class TimelineBasedMeasurementTest(
- page_measurement_unittest_base.PageMeasurementUnitTestBase):
+ page_measurement_unittest_base.PageMeasurementUnitTestBase):
+
def setUp(self):
self._options = options_for_unittests.GetCopy()
self._options.browser_options.wpr_mode = wpr_modes.WPR_OFF
# Disabled due to flakiness: crbug.com/368386
@test.Disabled
- def testTimelineBasedForSmoke(self):
+ def testSmoothnessTimelineBasedMeasurementForSmoke(self):
ps = self.CreatePageSetFromFileInUnittestDataDir(
'interaction_enabled_page.html')
- setattr(ps.pages[0], 'RunSmoothness', {'action': 'wait',
- 'javascript': 'window.animationDone'})
+ setattr(ps.pages[0], 'RunSmoothness', {
+ 'action': 'wait', 'javascript': 'window.animationDone'})
measurement = tbm_module.TimelineBasedMeasurement()
results = self.RunMeasurement(measurement, ps,
options=self._options)
@@ -115,3 +137,28 @@ class TimelineBasedMeasurementTest(
v = results.FindAllPageSpecificValuesNamed('DrawerAnimation-jank')
self.assertEquals(len(v), 1)
+ # Disabled since mainthread_jank metric is not supported on windows platform.
+ @test.Disabled('win')
+ def testMainthreadJankTimelineBasedMeasurement(self):
+ ps = self.CreateEmptyPageSet()
+ ps.AddPage(TestTimelinebasedMeasurementPage(ps, ps.base_dir))
+
+ measurement = tbm_module.TimelineBasedMeasurement()
+ results = self.RunMeasurement(measurement, ps,
+ options=self._options)
+ self.assertEquals(0, len(results.failures))
+
+ # In interaction_enabled_page.html, we create a jank loop based on
+ # window.performance.now() (basically loop for x milliseconds).
+ # Since window.performance.now() uses wall-time
+ # instead of thread time, we set time to looping to 100ms in
+ # interaction_enabled_page.html and only assert the biggest jank > 50ms here
+ # to account for the fact that the browser may deschedule during the jank
+ # loop.
+ v = results.FindAllPageSpecificValuesNamed(
+ 'JankThreadJSRun-responsive-biggest_jank_thread_time')
+ self.assertGreaterEqual(v[0].value, 50)
+
+ v = results.FindAllPageSpecificValuesNamed(
+ 'JankThreadJSRun-responsive-total_big_jank_thread_time')
+ self.assertGreaterEqual(v[0].value, 50)
diff --git a/tools/telemetry/telemetry/web_perf/timeline_interaction_record.py b/tools/telemetry/telemetry/web_perf/timeline_interaction_record.py
index 40ab2c2d3c..45e6a34978 100644
--- a/tools/telemetry/telemetry/web_perf/timeline_interaction_record.py
+++ b/tools/telemetry/telemetry/web_perf/timeline_interaction_record.py
@@ -9,11 +9,11 @@ import telemetry.core.timeline.bounds as timeline_bounds
IS_SMOOTH = 'is_smooth'
-IS_LOADING_RESOURCES = 'is_loading_resources'
+IS_RESPONSIVE = 'is_responsive'
FLAGS = [
IS_SMOOTH,
- IS_LOADING_RESOURCES
+ IS_RESPONSIVE
]
@@ -22,6 +22,9 @@ class ThreadTimeRangeOverlappedException(Exception):
with other events.
"""
+class NoThreadTimeDataException(ThreadTimeRangeOverlappedException):
+ """Exception that can be thrown if there is not sufficient thread time data
+ to compute the overlapped thread time range."""
def IsTimelineInteractionRecord(event_name):
return event_name.startswith('Interaction.')
@@ -52,7 +55,7 @@ class TimelineInteractionRecord(object):
is currently done by pushing markers into the console.time/timeEnd API: this
for instance can be issued in JS:
- var str = 'Interaction.SendEmail/is_smooth,is_loading_resources';
+ var str = 'Interaction.SendEmail/is_smooth,is_responsive';
console.time(str);
setTimeout(function() {
console.timeEnd(str);
@@ -71,7 +74,7 @@ class TimelineInteractionRecord(object):
self.start = start
self.end = end
self.is_smooth = False
- self.is_loading_resources = False
+ self.is_responsive = False
self._async_event = async_event
# TODO(nednguyen): After crbug.com/367175 is marked fixed, we should be able
@@ -84,6 +87,9 @@ class TimelineInteractionRecord(object):
async_event: An instance of
telemetry.core.timeline.async_slices.AsyncSlice
"""
+ assert async_event.start_thread == async_event.end_thread, (
+ 'Start thread of this record\'s async event is not the same as its '
+ 'end thread')
m = re.match('Interaction\.(.+)\/(.+)', async_event.name)
if m:
logical_name = m.group(1)
@@ -104,7 +110,7 @@ class TimelineInteractionRecord(object):
raise Exception(
'Unrecognized flag in timeline Interaction record: %s' % f)
record.is_smooth = IS_SMOOTH in flags
- record.is_loading_resources = IS_LOADING_RESOURCES in flags
+ record.is_responsive = IS_RESPONSIVE in flags
return record
def GetResultNameFor(self, result_name):
@@ -118,7 +124,7 @@ class TimelineInteractionRecord(object):
return bounds
@staticmethod
- def GetJavascriptMarker(logical_name, flags):
+ def GetJavaScriptMarker(logical_name, flags):
""" Get the marker string of an interaction record with logical_name
and flags.
"""
@@ -169,16 +175,12 @@ class TimelineInteractionRecord(object):
if not self._async_event:
raise ThreadTimeRangeOverlappedException(
'This record was not constructed from async event')
- if self._async_event.start_thread != self._async_event.end_thread:
- raise ThreadTimeRangeOverlappedException(
- 'Start thread of this record\'s async event is not the same as its '
- 'end thread')
if not self._async_event.has_thread_timestamps:
- raise ThreadTimeRangeOverlappedException(
+ raise NoThreadTimeDataException(
'This record\'s async_event does not contain thread time data. '
'Event data: %s' % repr(self._async_event))
if not timeline_slice.has_thread_timestamps:
- raise ThreadTimeRangeOverlappedException(
+ raise NoThreadTimeDataException(
'slice does not contain thread time data')
if timeline_slice.parent_thread == self._async_event.start_thread:
@@ -210,3 +212,19 @@ class TimelineInteractionRecord(object):
self._async_event.thread_duration / float(self._async_event.duration))
return (overlapped_walltime_duration * timeline_slice_scheduled_ratio *
record_scheduled_ratio)
+
+ def __repr__(self):
+ flags = []
+ if self.is_smooth:
+ flags.append(IS_SMOOTH)
+ elif self.is_responsive:
+ flags.append(IS_RESPONSIVE)
+ flags_str = ','.join(flags)
+
+ return ('TimelineInteractionRecord(logical_name=\'%s\', start=%f, end=%f,' +
+ ' flags=%s, async_event=%s)') % (
+ self.logical_name,
+ self.start,
+ self.end,
+ flags_str,
+ repr(self._async_event))
diff --git a/tools/telemetry/telemetry/web_perf/timeline_interaction_record_unittest.py b/tools/telemetry/telemetry/web_perf/timeline_interaction_record_unittest.py
index f2248c5381..8a30d193a8 100644
--- a/tools/telemetry/telemetry/web_perf/timeline_interaction_record_unittest.py
+++ b/tools/telemetry/telemetry/web_perf/timeline_interaction_record_unittest.py
@@ -40,32 +40,32 @@ class TimelineInteractionRecordTests(unittest.TestCase):
r = self.CreateSimpleRecordWithName('Interaction.LogicalName')
self.assertEquals('LogicalName', r.logical_name)
self.assertEquals(False, r.is_smooth)
- self.assertEquals(False, r.is_loading_resources)
+ self.assertEquals(False, r.is_responsive)
r = self.CreateSimpleRecordWithName('Interaction.LogicalName/is_smooth')
self.assertEquals('LogicalName', r.logical_name)
self.assertEquals(True, r.is_smooth)
- self.assertEquals(False, r.is_loading_resources)
+ self.assertEquals(False, r.is_responsive)
r = self.CreateSimpleRecordWithName(
'Interaction.LogicalNameWith/Slash/is_smooth')
self.assertEquals('LogicalNameWith/Slash', r.logical_name)
self.assertEquals(True, r.is_smooth)
- self.assertEquals(False, r.is_loading_resources)
+ self.assertEquals(False, r.is_responsive)
r = self.CreateSimpleRecordWithName(
- 'Interaction.LogicalNameWith/Slash/is_smooth,is_loading_resources')
+ 'Interaction.LogicalNameWith/Slash/is_smooth,is_responsive')
self.assertEquals('LogicalNameWith/Slash', r.logical_name)
self.assertEquals(True, r.is_smooth)
- self.assertEquals(True, r.is_loading_resources)
+ self.assertEquals(True, r.is_responsive)
- def testGetJavascriptMarker(self):
- smooth_marker = tir_module.TimelineInteractionRecord.GetJavascriptMarker(
+ def testGetJavaScriptMarker(self):
+ smooth_marker = tir_module.TimelineInteractionRecord.GetJavaScriptMarker(
'LogicalName', [tir_module.IS_SMOOTH])
self.assertEquals('Interaction.LogicalName/is_smooth', smooth_marker)
- slr_marker = tir_module.TimelineInteractionRecord.GetJavascriptMarker(
- 'LogicalName', [tir_module.IS_SMOOTH, tir_module.IS_LOADING_RESOURCES])
- self.assertEquals('Interaction.LogicalName/is_smooth,is_loading_resources',
+ slr_marker = tir_module.TimelineInteractionRecord.GetJavaScriptMarker(
+ 'LogicalName', [tir_module.IS_SMOOTH, tir_module.IS_RESPONSIVE])
+ self.assertEquals('Interaction.LogicalName/is_smooth,is_responsive',
slr_marker)
def testGetOverlappedThreadTimeForSliceInSameThread(self):
@@ -101,6 +101,25 @@ class TimelineInteractionRecordTests(unittest.TestCase):
s5 = self.CreateTestSliceFromTimeRanges(renderer_main, 0, 100, 50, 90)
self.assertEquals(10, record.GetOverlappedThreadTimeForSlice(s5))
+ def testRepr(self):
+ # Create a renderer thread.
+ model = model_module.TimelineModel()
+ renderer_main = model.GetOrCreateProcess(1).GetOrCreateThread(2)
+ model.FinalizeImport()
+
+ s = async_slice.AsyncSlice(
+ 'cat', 'Interaction.Test/is_smooth',
+ timestamp=0, duration=200, start_thread=renderer_main,
+ end_thread=renderer_main, thread_start=30, thread_duration=30)
+ record = tir_module.TimelineInteractionRecord.FromAsyncEvent(s)
+ expected_repr = (
+ 'TimelineInteractionRecord(logical_name=\'Test\', '
+ 'start=0.000000, end=200.000000, flags=is_smooth, '
+ 'async_event=TimelineEvent(name=\'Interaction.Test/is_smooth\','
+ ' start=0.000000, duration=200, thread_start=30, thread_duration=30))')
+ self.assertEquals(expected_repr, repr(record))
+
+
def testGetOverlappedThreadTimeForSliceInDifferentThread(self):
# Create a renderer thread and another thread.
model = model_module.TimelineModel()
diff --git a/tools/telemetry/unittest_data/discoverable_classes/__init__.py b/tools/telemetry/unittest_data/discoverable_classes/__init__.py
index 4e943c4b36..9228df89b0 100644
--- a/tools/telemetry/unittest_data/discoverable_classes/__init__.py
+++ b/tools/telemetry/unittest_data/discoverable_classes/__init__.py
@@ -1,3 +1,3 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/unittest_data/discoverable_classes/discover_dummyclass.py b/tools/telemetry/unittest_data/discoverable_classes/discover_dummyclass.py
index b25cf9e04d..e41eccc4db 100644
--- a/tools/telemetry/unittest_data/discoverable_classes/discover_dummyclass.py
+++ b/tools/telemetry/unittest_data/discoverable_classes/discover_dummyclass.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# 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.
diff --git a/tools/telemetry/unittest_data/interaction_enabled_page.html b/tools/telemetry/unittest_data/interaction_enabled_page.html
index cadb1fa515..d7c7cfa013 100644
--- a/tools/telemetry/unittest_data/interaction_enabled_page.html
+++ b/tools/telemetry/unittest_data/interaction_enabled_page.html
@@ -53,5 +53,20 @@
<div id="drawer">
This is a drawer.
</div>
+ <script>
+ 'use strict';
+ var jankMs = 100;
+ function jankThread() {
+ console.time('Interaction.JankThreadJSRun/is_responsive');
+ var startTime = window.performance.now();
+ var currTime = startTime;
+ while (currTime - startTime < jankMs) {
+ var currTime = window.performance.now();
+ }
+ console.timeEnd('Interaction.JankThreadJSRun/is_responsive');
+ }
+ var drawer = document.getElementById('drawer');
+ drawer.addEventListener('click', jankThread);
+ </script>
</body>
</html>
diff --git a/tools/valgrind/drmemory/suppressions.txt b/tools/valgrind/drmemory/suppressions.txt
index 97b3680789..37455b7f52 100644
--- a/tools/valgrind/drmemory/suppressions.txt
+++ b/tools/valgrind/drmemory/suppressions.txt
@@ -423,20 +423,20 @@ skia.dll!HDCOffscreen::draw
skia.dll!SkScalerContext_GDI::generateImage
skia.dll!SkScalerContext::getImage
skia.dll!SkGlyphCache::findImage
-skia.dll!D1G_NoBounder_RectClip
+skia.dll!D1G_RectClip
skia.dll!SkDraw::drawText
HANDLE LEAK
name=http://crbug.com/346842
system call NtGdiCreateDIBSection
-GDI32.dll!CreateDIBSection
-skia.dll!HDCOffscreen::draw
-skia.dll!SkScalerContext_GDI::generateImage
-skia.dll!SkScalerContext::getImage
-skia.dll!SkGlyphCache::findImage
-skia.dll!D1G_NoBounder_RectClip
-skia.dll!SkDraw::drawPosText
-skia.dll!SkBitmapDevice::drawPosText
+*!CreateDIBSection
+*!HDCOffscreen::draw
+*!SkScalerContext_GDI::generateImage
+*!SkScalerContext::getImage
+*!SkGlyphCache::findImage
+*!D1G*RectClip
+*!SkDraw::drawPosText
+*!SkBitmapDevice::drawPosText
HANDLE LEAK
name=http://crbug.com/346993
@@ -557,7 +557,20 @@ system call NtCreate*
UNADDRESSABLE ACCESS
name=http://crbug.com/379204
...
-*!WTF::PlatformCondition::timedWait
-*!WTF::ThreadCondition::timedWait
*!WTF::MessageQueue<>::waitForMessageWithTimeout
*!WebCore::WorkerRunLoop::run
+*!WebCore::WorkerRunLoop::run
+*!WebCore::WorkerThread::workerThread
+*!WTF::threadEntryPoint
+
+GDI USAGE ERROR
+name=379774
+system call NtUserCallOneParam.RELEASEDC
+USER32.dll!ReleaseDC
+*!std::_Tree<>::_Erase
+*!std::_Tree<>::erase
+*!DefaultSingletonTraits<>::Delete
+*!Singleton<>::OnExit
+*!base::AtExitManager::ProcessCallbacksNow
+*!base::AtExitManager::~AtExitManager
+*!base::TestSuite::~TestSuite
diff --git a/tools/valgrind/drmemory/suppressions_full.txt b/tools/valgrind/drmemory/suppressions_full.txt
index 10de956faf..998e30d4a4 100644
--- a/tools/valgrind/drmemory/suppressions_full.txt
+++ b/tools/valgrind/drmemory/suppressions_full.txt
@@ -1455,12 +1455,6 @@ name=bug_145244
*!WebCore::StyleSheetContents::requestImportedStyleSheets
UNINITIALIZED READ
-name=bug_158510
-*!WebCore::RenderTable::layout
-...
-*!WebCore::RenderBlock::layout
-
-UNINITIALIZED READ
name=bug_159005
*!WebCore::RenderMarquee::updateMarqueeStyle
*!WebCore::RenderLayer::styleChanged
@@ -2063,14 +2057,6 @@ blink_web.dll!WebCore::FrameView::updateLayoutAndStyleForPainting
blink_web.dll!WebCore::PageAnimator::updateLayoutAndStyleForPainting
UNINITIALIZED READ
-name=bug_364675
-blink_web.dll!WebCore::AutoTableLayout::layout
-blink_web.dll!WebCore::RenderTable::layout
-blink_web.dll!...
-blink_web.dll!WebCore::RenderBlockFlow::layoutBlockFlow
-blink_web.dll!WebCore::RenderBlockFlow::layoutBlock
-
-UNINITIALIZED READ
name=bug_365101
*!device::BluetoothAdapterWin::AdapterStateChanged
@@ -2176,10 +2162,6 @@ name=bug_374410
*!ui::NativeThemeWin::PaintDirect
UNINITIALIZED READ
-name=bug_376814
-*!content::PepperPluginInstanceImpl::UpdateLayer
-
-UNINITIALIZED READ
name=bug_377728
...
*!Hunspell::suggest
diff --git a/tools/valgrind/gtest_exclude/browser_tests.gtest-drmemory_win32.txt b/tools/valgrind/gtest_exclude/browser_tests.gtest-drmemory_win32.txt
index 294f5e019c..5f68c7f1ae 100644
--- a/tools/valgrind/gtest_exclude/browser_tests.gtest-drmemory_win32.txt
+++ b/tools/valgrind/gtest_exclude/browser_tests.gtest-drmemory_win32.txt
@@ -9,59 +9,46 @@
# it takes too long to run all browser_tests with Dr.Memory,
# and we only select subset to run
# A*: ~70 tests
+A*
# DrM-i#1052-c#52
# AutofillTest.*
# AcceleratedCompositingBlockedTest.*
# AppApiTest.*
-A*
# BrowserAccessibilityStateImplTest.*
B*
# C*: ~190 tests
-C*
-# D*: ~210 tests
D*
-# E*: ~535 tests
E*
F*
G*
# H*: ~52 tests
-H*
# DrM-i#1052-c#53
-# HistoryWebUITest.*
+HistoryWebUITest.*
# I*: ~10 tests
-I*
# DrM-i#1052-c#53
-# InfoBarsTest.*
+InfoBarsTest.*
# DrM-i#1052-c#56
-# InspectUITest.*
+InspectUITest.*
# J*: 0 tests
-J*
# K*: 1 tests
-K*
# L*: 62 tests
-L*
M*
N*
O*
P*
-# Q*
-# R*
-# S*
-# T*
+Q*
+R*
+S*
+T*
# U*: ~20 tests
-U*
# DrM-i#1052-c#53
-# UnloadTest.*
+UnloadTest.*
# V*: 5 tests
-V*
# W*: ~150 tests
-# W*
+W*
# X*: 0 tests
-X*
# Y*: 0 tests
-Y*
# Z*: 0 tests
-Z*
# http://crbug.com/302993
InstantNTPURLRewriteTest.UberURLHandler_InstantExtendedNewTabPage
diff --git a/tools/valgrind/memcheck/suppressions.txt b/tools/valgrind/memcheck/suppressions.txt
index 9689e8bf89..b1d438b344 100644
--- a/tools/valgrind/memcheck/suppressions.txt
+++ b/tools/valgrind/memcheck/suppressions.txt
@@ -4208,13 +4208,6 @@
fun:_ZN7content23AudioInputDeviceManager23EnumerateOnDeviceThread*
}
{
- bug_158510
- Memcheck:Uninitialized
- fun:_ZN7WebCore11RenderTable6layoutEv
- ...
- fun:_ZN7WebCore11RenderBlock6layoutEv
-}
-{
bug_158514
Memcheck:Uninitialized
...
@@ -5447,20 +5440,6 @@
fun:_ZN7content12_GLOBAL__N_121ClearOriginOnIOThreadEjRK4GURLRK13scoped_refptrIN3net23URLRequestContextGetterEERKS4_IN5quota12QuotaManagerEE
}
{
- bug_258466
- Memcheck:Leak
- fun:_Znw*
- fun:_ZN22ChromeBrowserMainParts25PreMainMessageLoopRunImplEv
- fun:_ZN22ChromeBrowserMainParts21PreMainMessageLoopRunEv
- fun:_ZN7content15BrowserMainLoop13CreateThreadsEv
- fun:_ZN7content21BrowserMainRunnerImpl10InitializeERKNS_18MainFunctionParamsE
- fun:_ZN7content11BrowserMainERKNS_18MainFunctionParamsE
- fun:_ZN7content23RunNamedProcessTypeMainERKSsRKNS_18MainFunctionParamsEPNS_19ContentMainDelegateE
- fun:_ZN7content21ContentMainRunnerImpl3RunEv
- fun:_ZN7content11ContentMainEiPPKcPNS_19ContentMainDelegateE
- fun:ChromeMain
-}
-{
bug_258132a
Memcheck:Leak
fun:_Znw*
@@ -5832,21 +5811,19 @@
fun:_ZN12_GLOBAL__N_119test_pm_conversionsEP9GrContextPiS2_
fun:_ZN9GrContext19createPMToUPMEffectEP9GrTexturebRK8SkMatrix
fun:_ZN9GrContext22readRenderTargetPixelsEP14GrRenderTargetiiii13GrPixelConfigPvmj
- fun:_ZN11SkGpuDevice12onReadPixelsERK8SkBitmapiiN8SkCanvas10Config8888E
- fun:_ZN12SkBaseDevice10readPixelsEP8SkBitmapiiN8SkCanvas10Config8888E
- fun:_ZN8SkCanvas10readPixelsEP8SkBitmapiiNS_10Config8888E
- fun:_ZN14DeferredDevice12onReadPixelsERK8SkBitmapiiN8SkCanvas10Config8888E
- fun:_ZN12SkBaseDevice10readPixelsEP8SkBitmapiiN8SkCanvas10Config8888E
- fun:_ZN8SkCanvas10readPixelsEP8SkBitmapiiNS_10Config8888E
- fun:_ZN7WebCore15GraphicsContext10readPixelsEP8SkBitmapiiN8SkCanvas10Config8888E
- fun:_ZN7WebCore12getImageDataILNS_8MultiplyE1EEEN3WTF10PassRefPtrINS2_17Uint8ClampedArrayEEERKNS_7IntRectEPNS_15GraphicsContextERKNS_7IntSizeE
- fun:_ZNK7WebCore11ImageBuffer24getUnmultipliedImageDataERKNS_7IntRectENS0_16CoordinateSystemE
- fun:_ZNK7WebCore24CanvasRenderingContext2D12getImageDataENS_11ImageBuffer16CoordinateSystemEffffRNS_14ExceptionStateE
- fun:_ZNK7WebCore24CanvasRenderingContext2D12getImageDataEffffRNS_14ExceptionStateE
+ fun:_ZN11SkGpuDevice12onReadPixelsE*
+ fun:_ZN12SkBaseDevice10readPixelsE*
+ fun:_ZN8SkCanvas10readPixelsE*
+ fun:_ZN*DeferredDevice12onReadPixelsE*
+ fun:_ZN12SkBaseDevice10readPixelsE*
+ fun:_ZN8SkCanvas10readPixelsE*
+ fun:_ZN7WebCore15GraphicsContext10readPixelsE*
+ fun:_ZN7WebCore12getImageDataILNS_8MultiplyE*
+ fun:_ZNK7WebCore11ImageBuffer24getUnmultipliedImageDataE*
+ fun:_ZNK7WebCore24CanvasRenderingContext2D12getImageDataE*
+ ...
fun:_ZN7WebCore34CanvasRenderingContext2DV8InternalL18getImageDataMethodERKN2v820FunctionCallbackInfoINS1_5ValueEEE
fun:_ZN7WebCore34CanvasRenderingContext2DV8InternalL26getImageDataMethodCallbackERKN2v820FunctionCallbackInfoINS1_5ValueEEE
- fun:_ZN2v88internal25FunctionCallbackArguments4CallEPFvRKNS_20FunctionCallbackInfoINS_5ValueEEEE
- fun:_ZN2v88internalL19HandleApiCallHelperILb0EEEPNS0_11MaybeObjectENS0_12_GLOBAL__N_116BuiltinArgumentsILNS0_21BuiltinExtraArgumentsE1EEEPNS0_7IsolateE
}
{
bug_309468
@@ -6297,9 +6274,7 @@
fun:_ZN3WTF10fastMallocEm
fun:_ZN3WTF10RefCountedIN7WebCore11ScriptStateEEnwEm
fun:_ZN7WebCore11ScriptState6createEN2v86HandleINS1_7ContextEEEN3WTF10PassRefPtrINS_15DOMWrapperWorldEEE
- fun:_ZN7WebCore22WorkerScriptController25initializeContextIfNeededEv
- fun:_ZN7WebCore22WorkerScriptController8evaluateERKN3WTF6StringES4_RKNS1_12TextPositionEPNS_31WorkerGlobalScopeExecutionStateE
- fun:_ZN7WebCore22WorkerScriptController8evaluateERKNS_16ScriptSourceCodeEPN3WTF6RefPtrINS_10ErrorEventEEE
+ ...
fun:_ZN7WebCore12WorkerThread12workerThreadEv
fun:_ZN7WebCore12WorkerThread17workerThreadStartEPv
fun:_ZN3WTFL16threadEntryPointEPv
@@ -6490,3 +6465,98 @@
fun:_Znw*
fun:_ZN7content27ServiceWorkerContextWrapper12InitInternalERKN4base8FilePathEPNS1_19SequencedTaskRunnerEPNS1_16MessageLoopProxyEPN5quota17QuotaManagerProxyE
}
+{
+ bug_379359
+ Memcheck:Leak
+ fun:_Znw*
+ fun:_ZN7content27ServiceWorkerContextWrapperC1EPNS_14BrowserContextE
+ fun:_ZN7content20StoragePartitionImpl6CreateEPNS_14BrowserContextEbRKN4base8FilePathE
+ fun:_ZN7content23StoragePartitionImplMap3GetERKSsS2_b
+ fun:_ZN7content12_GLOBAL__N_129GetStoragePartitionFromConfigEPNS_14BrowserContextERKSsS4_b
+ fun:_ZN7content14BrowserContext19GetStoragePartitionEPS0_PNS_12SiteInstanceE
+ fun:_ZN7content14BrowserContext26GetDefaultStoragePartitionEPS0_
+ fun:_ZN7content21ShellBrowserMainParts21PreMainMessageLoopRunEv
+ fun:_ZN7content15BrowserMainLoop21PreMainMessageLoopRunEv
+}
+{
+ bug_379943
+ Memcheck:Leak
+ fun:_Znw*
+ ...
+ fun:_ZN7content23CreateFileSystemContextEPNS_14BrowserContextERKN4base8FilePathEbPN5quota17QuotaManagerProxyE
+ fun:_ZN7content20StoragePartitionImpl6CreateEPNS_14BrowserContextEbRKN4base8FilePathE
+ fun:_ZN7content23StoragePartitionImplMap3GetERKSsS2_b
+ fun:_ZN7content12_GLOBAL__N_129GetStoragePartitionFromConfigEPNS_14BrowserContextERKSsS4_b
+ fun:_ZN7content14BrowserContext19GetStoragePartitionEPS0_PNS_12SiteInstanceE
+ fun:_ZN7content14BrowserContext26GetDefaultStoragePartitionEPS0_
+ fun:_ZN7content21ShellBrowserMainParts21PreMainMessageLoopRunEv
+ fun:_ZN7content15BrowserMainLoop21PreMainMessageLoopRunEv
+}
+{
+ bug_380575
+ Memcheck:Leak
+ fun:_Znw*
+ fun:_ZN9__gnu_cxx13new_allocatorISt13_Rb_tree_nodeISt4pairIKSsPN3net20URLRequestJobFactory15ProtocolHandlerEEEE8allocateEmPKv
+ ...
+ fun:_ZNSt8_Rb_treeISsSt4pairIKSsPN3net20URLRequestJobFactory15ProtocolHandlerEESt10_Select1stIS6_ESt4lessISsESaIS6_EE17_M_insert_unique_ESt23_Rb_tree_const_iteratorIS6_ERKS6_
+ fun:_ZNSt3mapISsPN3net20URLRequestJobFactory15ProtocolHandlerESt4lessISsESaISt4pairIKSsS3_EEE6insertESt17_Rb_tree_iteratorIS8_ERKS8_
+ fun:_ZNSt3mapISsPN3net20URLRequestJobFactory15ProtocolHandlerESt4lessISsESaISt4pairIKSsS3_EEEixERS7_
+ fun:_ZN3net24URLRequestJobFactoryImpl18SetProtocolHandlerERKSsPNS_20URLRequestJobFactory15ProtocolHandlerE
+ ...
+ fun:_ZN7content28ShellURLRequestContextGetter20GetURLRequestContextEv
+ fun:_ZN7content21ChromeAppCacheService20InitializeOnIOThreadERKN4base8FilePathEPNS_15ResourceContextEPN3net23URLRequestContextGetterE13scoped_refptrIN5quota20SpecialStoragePolicyEE
+}
+{
+ bug_381065
+ Memcheck:Leak
+ fun:_Znw*
+ ...
+ fun:_ZN7WebCore18ModulesInitializer20registerEventFactoryEv
+ fun:_ZN7WebCore15CoreInitializer4initEv
+ fun:_ZN5blink19initializeWithoutV8EPNS_8PlatformE
+ fun:_ZN5blink10initializeEPNS_8PlatformE
+ fun:_ZN7content25TestWebKitPlatformSupportC2Ev
+ fun:_ZN7content25TestWebKitPlatformSupportC1Ev
+ fun:_ZN7content17UnitTestTestSuiteC2EPN4base9TestSuiteE
+ fun:_ZN7content17UnitTestTestSuiteC1EPN4base9TestSuiteE
+}
+{
+ bug_381156
+ Memcheck:Uninitialized
+ ...
+ fun:_ZN*14SkTDynamicHashI10SkFlatData*
+ fun:_ZN16SkFlatDictionaryI7SkPaintNS0_16FlatteningTraitsEE24findAndReturnMutableFlatERKS0_
+ fun:_ZN16SkFlatDictionaryI7SkPaintNS0_16FlatteningTraitsEE17findAndReturnFlatERKS0_
+ fun:_ZN15SkPictureRecord16getFlatPaintDataERK7SkPaint
+ fun:_ZN15SkPictureRecord11addPaintPtrEPK7SkPaint
+ fun:_ZN15SkPictureRecord8addPaintERK7SkPaint
+ fun:_ZN15SkPictureRecord8drawPathERK6SkPathRK7SkPaint
+ fun:_ZN12SkBBoxRecord8drawPathERK6SkPathRK7SkPaint
+ fun:_ZN7WebCore15GraphicsContext8drawPathERK6SkPathRK7SkPaint
+ fun:_ZN7WebCore15GraphicsContext10strokePathERKNS_4PathE
+ fun:_ZNK7WebCore14RenderSVGShape11strokeShapeEPNS_15GraphicsContextE
+ fun:_ZNK7WebCore13RenderSVGPath11strokeShapeEPNS_15GraphicsContextE
+ fun:_ZN7WebCore27RenderSVGResourceSolidColor17postApplyResourceEPNS_12RenderObjectERPNS_15GraphicsContextEtPKNS_4PathEPKNS_14RenderSVGShapeE
+ fun:_ZN7WebCore14RenderSVGShape11strokeShapeEPNS_11RenderStyleEPNS_15GraphicsContextE
+ fun:_ZN7WebCore14RenderSVGShape5paintERNS_9PaintInfoERKNS_11LayoutPointE
+ fun:_ZN7WebCore9RenderBox5paintERNS_9PaintInfoERKNS_11LayoutPointE
+ fun:_ZN7WebCore13RenderSVGRoot13paintReplacedERNS_9PaintInfoERKNS_11LayoutPointE
+ fun:_ZN7WebCore14RenderReplaced5paintERNS_9PaintInfoERKNS_11LayoutPointE
+ fun:_ZN7WebCore11RenderBlock18paintAsInlineBlockEPNS_12RenderObjectERNS_9PaintInfoERKNS_11LayoutPointE
+}
+{
+ bug_381584
+ Memcheck:Leak
+ fun:_Znw*
+ fun:_ZN4base8internal20PostTaskAndReplyImpl16PostTaskAndReplyERKN15tracked_objects8LocationERKNS_8CallbackIFvvEEESA_
+ fun:_ZN4base10TaskRunner16PostTaskAndReplyERKN15tracked_objects8LocationERKNS_8CallbackIFvvEEES9_
+ fun:_ZN4base26PostTaskAndReplyWithResultI13scoped_refptrIN8chromeos8OwnerKeyEES4_EEbPNS_10TaskRunnerERKN15tracked_objects8LocationERKNS_8CallbackIFT_vEEERKNSB_IFvT0_EEE
+ fun:_ZN8chromeos23SessionManagerOperation14EnsureOwnerKeyERKN4base8CallbackIFvvEEE
+ fun:_ZN8chromeos23SessionManagerOperation12StartLoadingEv
+ fun:_ZN8chromeos21LoadSettingsOperation3RunEv
+ fun:_ZN8chromeos23SessionManagerOperation5StartEPNS_20SessionManagerClientE13scoped_refptrINS_12OwnerKeyUtilEES3_INS_8OwnerKeyEE
+ fun:_ZN8chromeos21DeviceSettingsService18StartNextOperationEv
+ fun:_ZN8chromeos21DeviceSettingsService7EnqueueEPNS_23SessionManagerOperationE
+ fun:_ZN8chromeos21DeviceSettingsService11EnqueueLoadEb
+ fun:_ZN8chromeos21DeviceSettingsService4LoadEv
+}
diff --git a/tools/valgrind/memcheck/suppressions_mac.txt b/tools/valgrind/memcheck/suppressions_mac.txt
index 705ddb9a93..9b6a97824b 100644
--- a/tools/valgrind/memcheck/suppressions_mac.txt
+++ b/tools/valgrind/memcheck/suppressions_mac.txt
@@ -112,14 +112,7 @@
bug_257276_b
Memcheck:Leak
fun:malloc_zone_malloc
- fun:_CFRuntimeCreateInstance
- fun:CFNumberCreate
- fun:get_colorspace
- fun:initImagePng
- fun:_CGImagePluginInitPNG
- fun:makeImagePlus
- fun:CGImageSourceCreateImageAtIndex
- fun:CGImageCreateWithPNGDataProvider
+ ...
fun:setCursorFromBundle
fun:CoreCursorSet
fun:-[NSCursor set]
@@ -2459,3 +2452,16 @@
fun:_ZN7content17UnitTestTestSuiteC2EPN4base9TestSuiteE
fun:_ZN7content17UnitTestTestSuiteC1EPN4base9TestSuiteE
}
+{
+ bug_380568
+ Memcheck:Leak
+ fun:calloc
+ fun:_internal_class_createInstanceFromZone
+ fun:_internal_class_createInstance
+ fun:NSAllocateObject
+ fun:+[NSObject(NSObject) alloc]
+ fun:-[VideoCaptureDeviceQTKit initWithFrameReceiver:]
+ fun:_ZN5media21VideoCaptureDeviceMac4InitENS_18VideoCaptureDevice4Name14CaptureApiTypeE
+ fun:_ZN5media28VideoCaptureDeviceFactoryMac6CreateERKNS_18VideoCaptureDevice4NameE
+ fun:_ZN5media45VideoCaptureDeviceTest_OpenInvalidDevice_Test8TestBodyEv
+}
diff --git a/tools/valgrind/tsan/suppressions.txt b/tools/valgrind/tsan/suppressions.txt
index ac3386bb0d..0568d4cc52 100644
--- a/tools/valgrind/tsan/suppressions.txt
+++ b/tools/valgrind/tsan/suppressions.txt
@@ -828,26 +828,6 @@
fun:_vsnprintf_helper
}
{
- bug_137973_a
- ThreadSanitizer:Race
- fun:media::Pipeline::OnVideoTimeUpdate
- fun:base::internal::RunnableAdapter::Run
-}
-{
- bug_137973_b
- ThreadSanitizer:Race
- fun:media::Pipeline::SetState
- fun:media::Pipeline::StopTask
- fun:base::internal::RunnableAdapter::Run
-}
-{
- bug_137973_c
- ThreadSanitizer:Race
- fun:media::Pipeline::SetState
- fun:media::Pipeline::SeekTask
- fun:base::internal::RunnableAdapter::Run
-}
-{
bug_144894
ThreadSanitizer:Race
fun:av_parser_close
@@ -1051,7 +1031,7 @@
fun:base::internal::RunnableAdapter::Run
}
{
- bug_344704
+ bug_344704_a
ThreadSanitizer:Race
fun:base::Thread::message_loop
fun:printing::PrintJob::UpdatePrintedDocument
@@ -1060,6 +1040,17 @@
fun:PrintJobTest_SimplePrint_Test::TestBody
}
{
+ bug_344704_b
+ ThreadSanitizer:Race
+ fun:scoped_refptr::operator=
+ fun:base::MessageLoop::~MessageLoop
+ fun:base::MessageLoop::~MessageLoop
+ fun:base::DefaultDeleter::operator*
+ fun:base::internal::scoped_ptr_impl::~scoped_ptr_impl
+ fun:scoped_ptr::~scoped_ptr
+ fun:base::Thread::ThreadMain
+}
+{
bug_350982
ThreadSanitizer:Race
fun:change_state