diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-12 14:27:29 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-13 09:35:20 +0000 |
commit | c30a6232df03e1efbd9f3b226777b07e087a1122 (patch) | |
tree | e992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/third_party/catapult | |
parent | 7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff) | |
download | qtwebengine-chromium-85-based.tar.gz |
BASELINE: Update Chromium to 85.0.4183.14085-based
Change-Id: Iaa42f4680837c57725b1344f108c0196741f6057
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/third_party/catapult')
33 files changed, 411 insertions, 2062 deletions
diff --git a/chromium/third_party/catapult/catapult_build/run_dev_server_tests.py b/chromium/third_party/catapult/catapult_build/run_dev_server_tests.py index 17cf3d94293..10bce608cd6 100644 --- a/chromium/third_party/catapult/catapult_build/run_dev_server_tests.py +++ b/chromium/third_party/catapult/catapult_build/run_dev_server_tests.py @@ -205,7 +205,7 @@ def RunTests(args, chrome_path): '--enable-logging', '--v=1', '--enable-features=ForceWebRequestProxyForTest', '--enable-blink-features=CustomElementsV0,' - 'HTMLImportsStyleApplication,ShadowDOMV0', + 'HTMLImports,ShadowDOMV0', ('http://localhost:%s/%s/tests.html?' % (port, args.tests)) + 'headless=true&testTypeToRun=all', ] diff --git a/chromium/third_party/catapult/common/py_utils/py_utils/chrome_binaries.json b/chromium/third_party/catapult/common/py_utils/py_utils/chrome_binaries.json index 4bbb24d6abc..badb3642c7f 100644 --- a/chromium/third_party/catapult/common/py_utils/py_utils/chrome_binaries.json +++ b/chromium/third_party/catapult/common/py_utils/py_utils/chrome_binaries.json @@ -6,22 +6,22 @@ "cloud_storage_bucket": "chrome-telemetry", "file_info": { "mac_x86_64": { - "cloud_storage_hash": "805bcd36abcadd252fc433b1b440edc9c1d1abaf", + "cloud_storage_hash": "841d45e806a296ce21f7f783cc7a2ae5f857924c", "download_path": "bin/reference_builds/chrome-mac64.zip", "path_within_archive": "chrome-mac/Google Chrome.app/Contents/MacOS/Google Chrome", - "version_in_cs": "80.0.3951.6" + "version_in_cs": "85.0.4169.0" }, "win_AMD64": { - "cloud_storage_hash": "7ad4063151c506f73b350665ca8e189e18565a3a", + "cloud_storage_hash": "c0b02f47afb6bacdd8d12eda6f03488583404b60", "download_path": "bin\\reference_build\\chrome-win64-clang.zip", "path_within_archive": "chrome-win64-clang\\chrome.exe", - "version_in_cs": "80.0.3951.4" + "version_in_cs": "85.0.4169.0" }, "win_x86": { - "cloud_storage_hash": "9ccaf1f26fc1f9d4e46258504a2de0f3808c1cf0", + "cloud_storage_hash": "5879958eda4edc5b0eaffeda4c7369a07937af73", "download_path": "bin\\reference_build\\chrome-win32-clang.zip", "path_within_archive": "chrome-win32-clang\\chrome.exe", - "version_in_cs": "80.0.3951.4" + "version_in_cs": "85.0.4169.0" } } }, @@ -30,10 +30,10 @@ "cloud_storage_bucket": "chrome-telemetry", "file_info": { "linux_x86_64": { - "cloud_storage_hash": "0db52435a728bbb0343791e275efd52904d059d6", + "cloud_storage_hash": "1b21a60f8e83a43d01e2ddbe83c5df56c8159d56", "download_path": "bin/reference_build/chrome-linux64.zip", "path_within_archive": "chrome-linux64/chrome", - "version_in_cs": "79.0.3945.16" + "version_in_cs": "85.0.4164.2" } } }, @@ -42,63 +42,63 @@ "cloud_storage_bucket": "chrome-telemetry", "file_info": { "android_k_armeabi-v7a": { - "cloud_storage_hash": "fcd18925f0929d38273c860e6fa4d1c3064b2037", + "cloud_storage_hash": "cf89ebbcf302fab3d4cd80b5566c5246cdf1504a", "download_path": "bin/reference_build/android_k_armeabi-v7a/ChromeStable.apk", - "version_in_cs": "78.0.3904.62" + "version_in_cs": "83.0.4103.101" }, "android_l_arm64-v8a": { - "cloud_storage_hash": "f2a8fd07fa7e082835a3c4ac228e66dc0dc89fee", + "cloud_storage_hash": "8d3d5fe99655f61a088d4b4d51cad028b1a60f9c", "download_path": "bin/reference_build/android_l_arm64-v8a/ChromeStable.apk", - "version_in_cs": "78.0.3904.62" + "version_in_cs": "83.0.4103.101" }, "android_l_armeabi-v7a": { - "cloud_storage_hash": "fcd18925f0929d38273c860e6fa4d1c3064b2037", + "cloud_storage_hash": "cf89ebbcf302fab3d4cd80b5566c5246cdf1504a", "download_path": "bin/reference_build/android_l_armeabi-v7a/ChromeStable.apk", - "version_in_cs": "78.0.3904.62" + "version_in_cs": "83.0.4103.101" }, "android_n_arm64-v8a": { - "cloud_storage_hash": "46943be19af7dd4dd70930d1838e7058a4a91235", + "cloud_storage_hash": "8a4a0e3be7c1043c63446b74c210c3bd1387c1f8", "download_path": "bin/reference_build/android_n_arm64-v8a/Monochrome.apk", - "version_in_cs": "78.0.3904.62" + "version_in_cs": "83.0.4103.101" }, "android_n_armeabi-v7a": { - "cloud_storage_hash": "628c0a492ac8c465b6da47909b3d1c92769da771", + "cloud_storage_hash": "3c80e59b2c0fede2a85a6b79dc71a5c787e01d30", "download_path": "bin/reference_build/android_n_armeabi-v7a/Monochrome.apk", - "version_in_cs": "78.0.3904.62" + "version_in_cs": "83.0.4103.101" }, "android_n_bundle_arm64-v8a": { - "cloud_storage_hash": "d294dad73aace7aad342b2448454700fa63987bf", + "cloud_storage_hash": "b369c1a955d49d246b52e93b8c5692a80d5356b1", "download_path": "bin/reference_build/android_n_bundle_arm64-v8a/Monochrome.apks", - "version_in_cs": "79.0.3945.93" + "version_in_cs": "83.0.4103.101" }, "android_n_bundle_armeabi-v7a": { - "cloud_storage_hash": "b36e829a0d9e73f39508b7bf033bd701ae26ed75", + "cloud_storage_hash": "8529aa69c987bcc731589e54543a870263dfa431", "download_path": "bin/reference_build/android_n_bundle_armeabi-v7a/Monochrome.apks", - "version_in_cs": "79.0.3945.93" + "version_in_cs": "83.0.4103.101" }, "linux_x86_64": { - "cloud_storage_hash": "6428da5968a0e69b84ee4525f8886517a45e4c92", + "cloud_storage_hash": "2eb0469024c127a4b99d6b20ac673e2be7ab1b2d", "download_path": "bin/reference_build/chrome-linux64.zip", "path_within_archive": "chrome-linux64/chrome", - "version_in_cs": "78.0.3904.70" + "version_in_cs": "83.0.4103.97" }, "mac_x86_64": { - "cloud_storage_hash": "40096f095b8f8b3694219c23b3f7254a60ca35e0", + "cloud_storage_hash": "012c5a5e7b1e69a0960462e7ba7f77f90464a10f", "download_path": "bin/reference_builds/chrome-mac64.zip", "path_within_archive": "chrome-mac/Google Chrome.app/Contents/MacOS/Google Chrome", - "version_in_cs": "78.0.3904.70" + "version_in_cs": "83.0.4103.97" }, "win_AMD64": { - "cloud_storage_hash": "7fcc267926ac55afe6fc28bc14eb252c98e20e08", + "cloud_storage_hash": "e6515496ebab0d02a5294a008fe8bbf9dd3dbc0c", "download_path": "bin\\reference_build\\chrome-win64-clang.zip", "path_within_archive": "chrome-win64-clang\\chrome.exe", - "version_in_cs": "78.0.3904.70" + "version_in_cs": "83.0.4103.97" }, "win_x86": { - "cloud_storage_hash": "d6fdf2a4858bf9ddcbdb97b29b68863dfa3574f7", + "cloud_storage_hash": "1749fac72241bc48e4adaf881a9278811b7ee406", "download_path": "bin\\reference_build\\chrome-win-clang.zip", "path_within_archive": "chrome-win-clang\\chrome.exe", - "version_in_cs": "78.0.3904.70" + "version_in_cs": "83.0.4103.97" } } }, @@ -107,22 +107,22 @@ "cloud_storage_bucket": "chrome-telemetry", "file_info": { "mac_x86_64": { - "cloud_storage_hash": "6502438babd29256ae0407c818123d7d25b439c4", + "cloud_storage_hash": "0e1a89d8aabd37e971aca506130d8ef7a1997b14", "download_path": "bin/reference_builds/chrome-mac.zip", "path_within_archive": "chrome-mac/Chromium.app/Contents/MacOS/Chromium", - "version_in_cs": "80.0.3951.6" + "version_in_cs": "85.0.4169.0" }, "win_AMD64": { - "cloud_storage_hash": "e177a29aa1bc1d86dae31fc80bca293011e8ff51", + "cloud_storage_hash": "fed673ad3f4744160b4997af461573be85153a1a", "download_path": "bin\\reference_build\\chrome-win.zip", "path_within_archive": "chrome-win\\chrome.exe", - "version_in_cs": "80.0.3951.4" + "version_in_cs": "85.0.4169.0" }, "win_x86": { - "cloud_storage_hash": "4f1bfd18c5cc386cb966ab48bf174d34ae9596ee", + "cloud_storage_hash": "e413191b7355f9bb8daad2cfc26cca924f48c44a", "download_path": "bin\\reference_build\\chrome-win32-clang.zip", "path_within_archive": "chrome-win32-clang\\chrome.exe", - "version_in_cs": "80.0.3951.4" + "version_in_cs": "85.0.4169.0" } } }, @@ -131,10 +131,10 @@ "cloud_storage_bucket": "chrome-telemetry", "file_info": { "linux_x86_64": { - "cloud_storage_hash": "5821ab5c8693c87b5a02c2684bb45e08ba901960", + "cloud_storage_hash": "b8b8aeaf5174ba09598ee637353b87f25fe9926e", "download_path": "bin/reference_build/chrome-linux.zip", "path_within_archive": "chrome-linux/chrome", - "version_in_cs": "79.0.3945.16" + "version_in_cs": "85.0.4164.2" } } }, @@ -143,30 +143,30 @@ "cloud_storage_bucket": "chrome-telemetry", "file_info": { "linux_x86_64": { - "cloud_storage_hash": "eb82b5d41759b6eeb2e61ef1a702be31aadf71c5", + "cloud_storage_hash": "9d7903d1e29589c9a9731b856893a0b6ee4de760", "download_path": "bin/reference_build/chrome-linux.zip", "path_within_archive": "chrome-linux/chrome", - "version_in_cs": "78.0.3904.70" + "version_in_cs": "83.0.4103.97" }, "mac_x86_64": { - "cloud_storage_hash": "0eb8d99f6ea6e1ff5bd9607d5be3e0eb29a9a497", + "cloud_storage_hash": "d1ddbcd3b1d2efd44c5a5030ae871308cca26000", "download_path": "bin/reference_builds/chrome-mac.zip", "path_within_archive": "chrome-mac/Chromium.app/Contents/MacOS/Chromium", - "version_in_cs": "78.0.3904.70" + "version_in_cs": "83.0.4103.97" }, "win_AMD64": { - "cloud_storage_hash": "c28d9e5bd2229164731fc7725293e361d9a850df", + "cloud_storage_hash": "5e503f1bfeae37061ddc80ae1660a1c41594b188", "download_path": "bin\\reference_build\\chrome-win.zip", "path_within_archive": "chrome-win\\chrome.exe", - "version_in_cs": "78.0.3904.70" + "version_in_cs": "83.0.4103.97" }, "win_x86": { - "cloud_storage_hash": "5af50c744ace488341a79e5f8d208ddaee04c5e7", + "cloud_storage_hash": "66e8c83cc4b57c38d71a56f6928bcafe7da17d80", "download_path": "bin\\reference_build\\chrome-win-clang.zip", "path_within_archive": "chrome-win-clang\\chrome.exe", - "version_in_cs": "78.0.3904.70" + "version_in_cs": "83.0.4103.97" } } } } -} +}
\ No newline at end of file diff --git a/chromium/third_party/catapult/common/py_utils/py_utils/webpagereplay_go_server.py b/chromium/third_party/catapult/common/py_utils/py_utils/webpagereplay_go_server.py index bc981934b08..950e8adcb79 100644 --- a/chromium/third_party/catapult/common/py_utils/py_utils/webpagereplay_go_server.py +++ b/chromium/third_party/catapult/common/py_utils/py_utils/webpagereplay_go_server.py @@ -129,6 +129,14 @@ class ReplayServer(object): 'wpr_go', py_utils.GetHostOsName(), py_utils.GetHostArchName()) return cls._go_binary_path + @classmethod + def SetGoBinaryPath(cls, go_binary_path): + """Overrides the _go_binary_path. + + This allows the server to use WPRGO files retrieved from somewhere + other than GCS, such as CIPD.""" + cls._go_binary_path = go_binary_path + @property def http_port(self): return self._started_ports['http'] diff --git a/chromium/third_party/catapult/tracing/trace_viewer.gni b/chromium/third_party/catapult/tracing/trace_viewer.gni index 0231304ed1f..f82c66eb418 100644 --- a/chromium/third_party/catapult/tracing/trace_viewer.gni +++ b/chromium/third_party/catapult/tracing/trace_viewer.gni @@ -199,12 +199,12 @@ tracing_js_html_files = [ "tracing/metrics/console_error_metric.html", "tracing/metrics/cpu_process_metric.html", "tracing/metrics/media_metric.html", + "tracing/metrics/memory_ablation_metric.html", "tracing/metrics/metric_map_function.html", "tracing/metrics/metric_registry.html", "tracing/metrics/rendering/cpu_utilization.html", "tracing/metrics/rendering/frame_time.html", "tracing/metrics/rendering/image_decode_time.html", - "tracing/metrics/rendering/pipeline.html", "tracing/metrics/rendering/pixels.html", "tracing/metrics/rendering/queueing_duration.html", "tracing/metrics/rendering/rendering_metric.html", @@ -590,16 +590,13 @@ tracing_js_html_files = [ "tracing/value/ui/histogram_set_view.html", "tracing/value/ui/histogram_set_view_state.html", "tracing/value/ui/histogram_span.html", - "tracing/value/ui/metrics_visualization.html", "tracing/value/ui/preferred_display_unit.html", - "tracing/value/ui/raster_visualization.html", "tracing/value/ui/related_event_set_span.html", "tracing/value/ui/scalar_context_controller.html", "tracing/value/ui/scalar_diagnostic_span.html", "tracing/value/ui/scalar_map_table.html", "tracing/value/ui/scalar_span.html", "tracing/value/ui/unmergeable_diagnostic_set_span.html", - "tracing/value/ui/visualizations_data_container.html", ] tracing_img_files = [ "tracing/ui/extras/chrome/cc/images/input-event.png", diff --git a/chromium/third_party/catapult/tracing/tracing/base/unit.html b/chromium/third_party/catapult/tracing/tracing/base/unit.html index 7292b99f58f..5f23254c296 100644 --- a/chromium/third_party/catapult/tracing/tracing/base/unit.html +++ b/chromium/third_party/catapult/tracing/tracing/base/unit.html @@ -484,6 +484,17 @@ tr.exportTo('tr.b', function() { }); Unit.define({ + baseUnitName: 'batteryChargeInAmpereHours', + baseJsonName: 'Ah', + formatSpec: { + baseSymbol: 'Ah', + unitScale: tr.b.UnitScale.defineUnitScaleFromPrefixScale( + 'Ah', 'AMPEREHOUR', tr.b.UnitPrefixScale.METRIC, 'AMPEREHOUR').AUTO, + minimumFractionDigits: 3 + } + }); + + Unit.define({ baseUnitName: 'electricPotentialInVolts', baseJsonName: 'V', formatSpec: { diff --git a/chromium/third_party/catapult/tracing/tracing/base/unit_test.html b/chromium/third_party/catapult/tracing/tracing/base/unit_test.html index e9428d890e0..216f254a0d7 100644 --- a/chromium/third_party/catapult/tracing/tracing/base/unit_test.html +++ b/chromium/third_party/catapult/tracing/tracing/base/unit_test.html @@ -399,6 +399,19 @@ tr.b.unittest.testSuite(function() { assert.strictEqual(Unit.byName.powerInWatts.format(.001005), '1.005 mW'); }); + test('batteryChargeInAmpereHours', function() { + assert.strictEqual( + Unit.byName.batteryChargeInAmpereHours.format(1000), '1.000 kAh'); + assert.strictEqual( + Unit.byName.batteryChargeInAmpereHours.format(1), '1.000 Ah'); + assert.strictEqual( + Unit.byName.batteryChargeInAmpereHours.format(0), '0.000 Ah'); + assert.strictEqual( + Unit.byName.batteryChargeInAmpereHours.format(.001), '1.000 mAh'); + assert.strictEqual( + Unit.byName.batteryChargeInAmpereHours.format(.001005), '1.005 mAh'); + }); + test('electricCurrentInAmperes', function() { assert.strictEqual( Unit.byName.electricCurrentInAmperes.format(1000), '1.000 kA'); diff --git a/chromium/third_party/catapult/tracing/tracing/extras/chrome/chrome_auditor.html b/chromium/third_party/catapult/tracing/tracing/extras/chrome/chrome_auditor.html index 6c626505880..a010398a1cc 100644 --- a/chromium/third_party/catapult/tracing/tracing/extras/chrome/chrome_auditor.html +++ b/chromium/third_party/catapult/tracing/tracing/extras/chrome/chrome_auditor.html @@ -52,16 +52,17 @@ tr.exportTo('tr.e.audits', function() { const thread = rendererHelper.compositorThread; const asyncSlices = Object.values(thread.asyncSliceGroup.slices); for (const slice of asyncSlices) { - if (slice.title !== 'PipelineReporter' || - !slice.args.termination_status || - slice.args.termination_status !== 'missed_frame') continue; - const alertSlices = [slice].concat(slice.subSlices); - alerts.push(new Alert( - new EventInfo( - 'Missed Frame', - 'Frame was not submitted before deadline.'), - slice.start, - alertSlices)); + if (slice.title === 'PipelineReporter' && + slice.args.chrome_frame_reporter && + slice.args.chrome_frame_reporter.state === 'STATE_DROPPED') { + const alertSlices = [slice].concat(slice.subSlices); + alerts.push(new Alert( + new EventInfo( + 'Dropped Frame', + 'Frame was dropped (i.e. not produced/presented).'), + slice.start, + alertSlices)); + } } } return alerts; diff --git a/chromium/third_party/catapult/tracing/tracing/extras/chrome/chrome_auditor_test.html b/chromium/third_party/catapult/tracing/tracing/extras/chrome/chrome_auditor_test.html index 217b87bf1ad..8b41fa056ad 100644 --- a/chromium/third_party/catapult/tracing/tracing/extras/chrome/chrome_auditor_test.html +++ b/chromium/third_party/catapult/tracing/tracing/extras/chrome/chrome_auditor_test.html @@ -146,7 +146,7 @@ tr.b.unittest.testSuite(function() { start: 200, duration: 15, args: { - termination_status: 'submitted_frame' + chrome_frame_reporter: {state: 'STATE_PRESENTED_ALL'} } }); @@ -155,7 +155,7 @@ tr.b.unittest.testSuite(function() { start: 200, duration: 15, args: { - termination_status: 'missed_frame' + chrome_frame_reporter: {state: 'STATE_DROPPED'} } }); diff --git a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/memreclaim_parser.html b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/memreclaim_parser.html index 027554eacfd..9db1f08e8c7 100644 --- a/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/memreclaim_parser.html +++ b/chromium/third_party/catapult/tracing/tracing/extras/importer/linux_perf/memreclaim_parser.html @@ -81,6 +81,7 @@ tr.exportTo('tr.e.importer.linux_perf', function() { kthread.openSliceTS = ts; kthread.order = order; } + kthread.waitingFor = 'kswapSleep'; return true; }, @@ -89,6 +90,8 @@ tr.exportTo('tr.e.importer.linux_perf', function() { const kthread = this.importer.getOrCreateKernelThread( eventBase.threadName, tgid, pid); + if (kthread.waitingFor !== 'kswapSleep') return false; + kthread.waitingFor = undefined; if (kthread.openSliceTS) { kthread.thread.sliceGroup.pushCompleteSlice( @@ -114,36 +117,40 @@ tr.exportTo('tr.e.importer.linux_perf', function() { const kthread = this.importer.getOrCreateKernelThread( eventBase.threadName, tgid, pid); - kthread.openSliceTS = ts; + kthread.openMemReclaimSliceTS = ts; kthread.order = order; kthread.gfp = gfp; + kthread.waitingFor = 'reclaimEnd'; return true; }, reclaimEnd(eventName, cpuNumber, pid, ts, eventBase) { const event = reclaimEndRE.exec(eventBase.details); if (!event) return false; - const nrReclaimed = parseInt(event[1]); const tgid = parseInt(eventBase.tgid); const kthread = this.importer.getOrCreateKernelThread( eventBase.threadName, tgid, pid); + if (kthread.waitingFor !== 'reclaimEnd') return false; + kthread.waitingFor = undefined; - if (kthread.openSliceTS !== undefined) { + if (kthread.openMemReclaimSliceTS !== undefined) { kthread.thread.sliceGroup.pushCompleteSlice('memreclaim', - 'direct reclaim', kthread.openSliceTS, ts - kthread.openSliceTS, + 'direct reclaim', kthread.openMemReclaimSliceTS, + ts - kthread.openMemReclaimSliceTS, 0, 0, { order: kthread.order, gfp: kthread.gfp, nr_reclaimed: nrReclaimed }); + kthread.openMemReclaimSliceTS = undefined; + kthread.order = undefined; + kthread.gfp = undefined; + return true; } - kthread.openSliceTS = undefined; - kthread.order = undefined; - kthread.gfp = undefined; - return true; + return false; }, lowmemoryKill(eventName, cpuNumber, pid, ts, eventBase) { diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/all_metrics.html b/chromium/third_party/catapult/tracing/tracing/metrics/all_metrics.html index d52a05b15bc..80696a7a243 100644 --- a/chromium/third_party/catapult/tracing/tracing/metrics/all_metrics.html +++ b/chromium/third_party/catapult/tracing/tracing/metrics/all_metrics.html @@ -12,6 +12,7 @@ found in the LICENSE file. <link rel="import" href="/tracing/metrics/console_error_metric.html"> <link rel="import" href="/tracing/metrics/cpu_process_metric.html"> <link rel="import" href="/tracing/metrics/media_metric.html"> +<link rel="import" href="/tracing/metrics/memory_ablation_metric.html"> <link rel="import" href="/tracing/metrics/rendering/rendering_metric.html"> <link rel="import" href="/tracing/metrics/reported_by_page_metric.html"> <link rel="import" href="/tracing/metrics/sample_exception_metric.html"> diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/memory_ablation_metric.html b/chromium/third_party/catapult/tracing/tracing/metrics/memory_ablation_metric.html new file mode 100644 index 00000000000..62ca340c637 --- /dev/null +++ b/chromium/third_party/catapult/tracing/tracing/metrics/memory_ablation_metric.html @@ -0,0 +1,65 @@ +<!DOCTYPE html> +<!-- +Copyright 2020 The Chromium Authors. All rights reserved. +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> + +<link rel="import" href="/tracing/base/base.html"> +<link rel="import" href="/tracing/base/unit.html"> +<link rel="import" href="/tracing/metrics/metric_registry.html"> +<link rel="import" href="/tracing/model/helpers/chrome_model_helper.html"> +<link rel="import" href="/tracing/value/histogram.html"> + +<script> +'use strict'; + +tr.exportTo('tr.metrics', function() { + /** + * Parses the trace to find PeakMemoryUsage related traces, building out + * histograms which track the time spent performing the actual memory + * ablation. + * + * These traces are reported under the category "gpu.memory". + * + * @param {HitogramSet} histograms - set of histograms to add results to. + * @param {tr.Model} model - model encompassing all trace events. + */ + function memoryAblationMetric(histograms, model) { + const modelHelper = model.getOrCreateHelper( + tr.model.helpers.ChromeModelHelper); + if (!modelHelper.gpuHelper) return; + const gpuProcess = modelHelper.gpuHelper.process; + const events = [...gpuProcess.findTopmostSlicesNamed( + 'Memory.GPU.PeakMemoryUsage.AblationTimes')]; + const allocHistogram = histograms.createHistogram('Ablation Alloc', + tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, [], { + binBoundaries: + tr.v.HistogramBinBoundaries.createLinear(0, 10000, 20), + description: 'The amount of time spent allocating the ablation ' + + 'memory', + summaryOptions: tr.metrics.rendering.SUMMARY_OPTIONS, + }); + const deallocHistogram = histograms.createHistogram('Ablation Dealloc', + tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, [], { + binBoundaries: + tr.v.HistogramBinBoundaries.createLinear(0, 10000, 20), + description: 'The amount of time spent deallocating the ablation ' + + 'memory', + summaryOptions: tr.metrics.rendering.SUMMARY_OPTIONS, + }); + for (let i = 0; i < events.length; i++) { + allocHistogram.addSample(events[i].args.alloc); + deallocHistogram.addSample(events[i].args.dealloc); + } + } + + tr.metrics.MetricRegistry.register(memoryAblationMetric, { + requiredCategories: ['gpu.memory'], + }); + + return { + memoryAblationMetric, + }; +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/rendering/pipeline.html b/chromium/third_party/catapult/tracing/tracing/metrics/rendering/pipeline.html deleted file mode 100644 index 7f89f204445..00000000000 --- a/chromium/third_party/catapult/tracing/tracing/metrics/rendering/pipeline.html +++ /dev/null @@ -1,260 +0,0 @@ -<!DOCTYPE html> -<!-- -Copyright 2018 The Chromium Authors. All rights reserved. -Use of this source code is governed by a BSD-style license that can be -found in the LICENSE file. ---> - -<link rel="import" href="/tracing/base/unit.html"> -<link rel="import" href="/tracing/model/helpers/chrome_model_helper.html"> -<link rel="import" href="/tracing/value/diagnostics/breakdown.html"> - -<script> -'use strict'; - -/** - * @fileoverview This file contains implementations of the following metrics. - * - * TODO(crbug.com/872334): document pipeline:* metrics here. - */ -tr.exportTo('tr.metrics.rendering', function() { - function eventIsValidGraphicsEvent_(event, eventMap) { - if (event.title !== 'Graphics.Pipeline' || !event.bindId || !event.args || - !event.args.step) { - return false; - } - const bindId = event.bindId; - if (eventMap.has(bindId) && event.args.step in eventMap.get(bindId)) { - // It is possible for a client to submit multiple compositor frames for - // one begin-message. So most steps can be present multiple times. - // However, a begin-frame is issued only once, and received only once. So - // these steps should not be repeated. - if (event.args.step === 'IssueBeginFrame' || - event.args.step === 'ReceiveBeginFrame') { - throw new Error('Unexpected duplicate step: ' + event.args.step); - } - return false; - } - return true; - } - - function generateBreakdownForCompositorPipelineInClient_(flow) { - const breakdown = new tr.v.d.Breakdown(); - breakdown.set('time before GenerateRenderPass', - flow.GenerateRenderPass.start - flow.ReceiveBeginFrame.start); - breakdown.set('GenerateRenderPass duration', - flow.GenerateRenderPass.duration); - breakdown.set('GenerateCompositorFrame duration', - flow.GenerateCompositorFrame.duration); - breakdown.set('SubmitCompositorFrame duration', - flow.SubmitCompositorFrame.duration); - return breakdown; - } - - function generateBreakdownForCompositorPipelineInService_(flow) { - const breakdown = new tr.v.d.Breakdown(); - breakdown.set('Processing CompositorFrame on reception', - flow.ReceiveCompositorFrame.duration); - breakdown.set('Delay before SurfaceAggregation', - flow.SurfaceAggregation.start - flow.ReceiveCompositorFrame.end); - breakdown.set('SurfaceAggregation duration', - flow.SurfaceAggregation.duration); - return breakdown; - } - - function generateBreakdownForDraw_(drawEvent) { - const breakdown = new tr.v.d.Breakdown(); - for (const slice of drawEvent.subSlices) { - breakdown.set(slice.title, slice.duration); - } - return breakdown; - } - - function getDisplayCompositorThread_(model) { - const chromeHelper = model.getOrCreateHelper( - tr.model.helpers.ChromeModelHelper); - const gpuHelper = chromeHelper.gpuHelper; - if (gpuHelper) { - const thread = - gpuHelper.process.findAtMostOneThreadNamed('VizCompositorThread'); - if (thread) { - return thread; - } - } - if (!chromeHelper.browserProcess) return null; - return chromeHelper.browserProcess.findAtMostOneThreadNamed( - 'CrBrowserMain'); - } - - function getRasterTaskTimes(sourceFrameNumber, model) { - const modelHelper = model.getOrCreateHelper( - tr.model.helpers.ChromeModelHelper); - - const renderers = modelHelper.telemetryHelper.renderersWithIR; - if (renderers.length === 0) return; - const rasterThreads = renderers[0].rasterWorkerThreads; - - let earliestStart = undefined; - let lastEnd = undefined; - for (const rasterThread of rasterThreads) { - for (const slice of [...rasterThread. - findTopmostSlicesNamed('TaskGraphRunner::RunTask')]) { - if (slice.args && - slice.args.source_frame_number_ && - slice.args.source_frame_number_ === sourceFrameNumber) { - if (earliestStart === undefined || slice.start < earliestStart) { - earliestStart = slice.start; - } - if (lastEnd === undefined || slice.end > lastEnd) { - lastEnd = slice.end; - } - } - } - } - return {start: earliestStart, end: lastEnd}; - } - - function addPipelineHistograms(histograms, model, segments) { - const ranges = segments.map(s => s.boundsRange); - const bindEvents = new Map(); - for (const thread of model.getAllThreads()) { - for (const event of thread.sliceGroup.childEvents()) { - if (!eventIsValidGraphicsEvent_(event, bindEvents)) continue; - for (const range of ranges) { - if (range.containsExplicitRangeInclusive(event.start, event.end)) { - if (!bindEvents.has(event.bindId)) bindEvents.set(event.bindId, {}); - break; - } - } - if (bindEvents.has(event.bindId)) { - bindEvents.get(event.bindId)[event.args.step] = event; - } - } - } - - const dcThread = getDisplayCompositorThread_(model); - const drawEvents = {}; - if (dcThread) { - const events = - [...dcThread.findTopmostSlicesNamed('Graphics.Pipeline.DrawAndSwap')]; - for (const segment of segments) { - const filteredEvents = segment.boundsRange.filterArray(events, - evt => evt.start); - for (const event of filteredEvents) { - if ((event.args && event.args.status === 'canceled') || - !event.id.startsWith(':ptr:')) { - continue; - } - const id = parseInt(event.id.substring(5), 16); - if (id in drawEvents) { - throw new Error('Duplicate draw events: ' + id); - } - drawEvents[id] = event; - } - } - } - - const issueToReceipt = histograms.createHistogram( - 'pipeline:begin_frame_transport', - tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, - [], { - description: 'Latency of begin-frame message from the display ' + - 'compositor to the client, including the IPC latency and task-' + - 'queue time in the client.', - summaryOptions: tr.metrics.rendering.SUMMARY_OPTIONS, - }); - const issueToRasterStart = histograms.createHistogram( - 'pipeline:begin_frame_to_raster_start', - tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, - [], { - description: 'Latency between begin-frame message and ' + - 'the beginning of the first CompositorTask run in the compositor.', - summaryOptions: tr.metrics.rendering.SUMMARY_OPTIONS, - }); - const issueToRasterEnd = histograms.createHistogram( - 'pipeline:begin_frame_to_raster_end', - tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, - [], { - description: 'Latency between begin-frame message and ' + - 'the end of the last CompositorTask run in the compositor.', - summaryOptions: tr.metrics.rendering.SUMMARY_OPTIONS, - }); - const receiptToSubmit = histograms.createHistogram( - 'pipeline:begin_frame_to_frame_submission', - tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, - [], { - description: 'Latency between begin-frame reception and ' + - 'CompositorFrame submission in the renderer.', - summaryOptions: tr.metrics.rendering.SUMMARY_OPTIONS, - }); - const submitToAggregate = histograms.createHistogram( - 'pipeline:frame_submission_to_display', - tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, - [], { - description: 'Latency between CompositorFrame submission in the ' + - 'renderer to display in the display-compositor, including IPC ' + - 'latency, task-queue time in the display-compositor, and ' + - 'additional processing (e.g. surface-sync etc.)', - summaryOptions: tr.metrics.rendering.SUMMARY_OPTIONS, - }); - const aggregateToDraw = histograms.createHistogram( - 'pipeline:draw', - tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, - [], { - description: 'How long it takes for the gpu-swap step.', - summaryOptions: tr.metrics.rendering.SUMMARY_OPTIONS, - }); - - for (const flow of bindEvents.values()) { - // Report only for the cases that go through the complete pipeline. - if (!flow.IssueBeginFrame || !flow.ReceiveBeginFrame || - !flow.SubmitCompositorFrame || !flow.SurfaceAggregation) { - continue; - } - - issueToReceipt.addSample(flow.ReceiveBeginFrame.start - - flow.IssueBeginFrame.start); - receiptToSubmit.addSample( - flow.SubmitCompositorFrame.end - flow.ReceiveBeginFrame.start, - {breakdown: generateBreakdownForCompositorPipelineInClient_(flow)}); - submitToAggregate.addSample( - flow.SurfaceAggregation.end - flow.SubmitCompositorFrame.end, - {breakdown: generateBreakdownForCompositorPipelineInService_(flow)}); - - if (flow.SubmitCompositorFrame.parentSlice) { - const sourceFrameNumber = flow.SubmitCompositorFrame.parentSlice - .args.source_frame_number_; - const rasterDuration = - getRasterTaskTimes(sourceFrameNumber, model); - if (rasterDuration && rasterDuration.start && rasterDuration.end) { - const receiveToStart = rasterDuration.start - - flow.ReceiveBeginFrame.start; - const receiveToEnd = rasterDuration.end - flow.ReceiveBeginFrame.end; - - // receiveToStart can be negative if the earliest raster task for - // a frame starts before receiveBeginFrame starts. - // The same is true for receiveToEnd - // Only positive samples are added. - if (receiveToEnd > 0) { - issueToRasterStart.addSample( - receiveToStart > 0 ? receiveToStart : 0); - issueToRasterEnd.addSample(receiveToEnd); - } - } - } - if (flow.SurfaceAggregation.args && - flow.SurfaceAggregation.args.display_trace) { - const displayTrace = flow.SurfaceAggregation.args.display_trace; - if (!(displayTrace in drawEvents)) continue; - const drawEvent = drawEvents[displayTrace]; - aggregateToDraw.addSample(drawEvent.duration, - {breakdown: generateBreakdownForDraw_(drawEvent)}); - } - } - } - - return { - addPipelineHistograms, - }; -}); -</script> diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/rendering/pipeline_test.html b/chromium/third_party/catapult/tracing/tracing/metrics/rendering/pipeline_test.html deleted file mode 100644 index 332767c0e79..00000000000 --- a/chromium/third_party/catapult/tracing/tracing/metrics/rendering/pipeline_test.html +++ /dev/null @@ -1,366 +0,0 @@ -<!DOCTYPE html> -<!-- -Copyright 2018 The Chromium Authors. All rights reserved. -Use of this source code is governed by a BSD-style license that can be -found in the LICENSE file. ---> - -<link rel="import" href="/tracing/core/test_utils.html"> -<link rel="import" href="/tracing/metrics/rendering/pipeline.html"> -<link rel="import" href="/tracing/model/user_model/segment.html"> -<link rel="import" href="/tracing/value/histogram_set.html"> - -<script> -'use strict'; - -tr.b.unittest.testSuite(function() { - function addPipelineForOneFrame(compositor, renderer, rasterWorker, - id, frame, displayTrace) { - const EVENT_NAME = 'Graphics.Pipeline'; - if (frame.IssueBeginFrame) { - compositor.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx( - { title: EVENT_NAME, - start: frame.IssueBeginFrame, duration: 1, bindId: id, - args: {step: 'IssueBeginFrame'}})); - } - if (frame.ReceiveBeginFrame) { - renderer.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx( - { title: EVENT_NAME, - start: frame.ReceiveBeginFrame, duration: 1, bindId: id, - args: {step: 'ReceiveBeginFrame'}})); - } - renderer.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx( - { title: EVENT_NAME, - start: frame.GenerateRenderPass, duration: 1, bindId: id, - args: {step: 'GenerateRenderPass'}})); - renderer.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx( - { title: EVENT_NAME, - start: frame.GenerateCompositorFrame, duration: 1, bindId: id, - args: {step: 'GenerateCompositorFrame'}})); - renderer.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx( - { title: EVENT_NAME, - start: frame.SubmitCompositorFrame, duration: 1, bindId: id, - args: {source_frame_number_: id}})); - renderer.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx( - { title: EVENT_NAME, - start: frame.SubmitCompositorFrame, duration: 1, bindId: id, - args: {step: 'SubmitCompositorFrame'}})); - compositor.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx( - { title: EVENT_NAME, - start: frame.ReceiveCompositorFrame, duration: 1, bindId: id, - args: {step: 'ReceiveCompositorFrame'}})); - compositor.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx( - { title: EVENT_NAME, - start: frame.SurfaceAggregation, duration: 1, bindId: id, - args: {step: 'SurfaceAggregation', display_trace: displayTrace}})); - renderer.sliceGroup.createSubSlices(); - rasterWorker.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx( - { title: 'TaskGraphRunner::RunTask', - start: frame.rasterTaskStart, duration: 6, bindId: id, - args: {source_frame_number_: id}})); - } - - function addDrawSlice(compositor, displayTrace, start, steps, opt_args) { - const EVENT_NAME = 'Graphics.Pipeline.DrawAndSwap'; - let totalDuration = 0; - for (const duration of Object.values(steps)) { - totalDuration += duration; - } - const slice = tr.c.TestUtils.newAsyncSliceNamed( - EVENT_NAME, start, totalDuration); - slice.id = ':ptr:' + displayTrace; - slice.args = opt_args; - compositor.sliceGroup.pushSlice(slice); - totalDuration = 0; - for (const step in steps) { - slice.subSlices.push(tr.c.TestUtils.newAsyncSliceNamed( - step, start + totalDuration, steps[step])); - totalDuration += steps[step]; - } - } - - test('graphicsPipeline', function() { - const model = tr.c.TestUtils.newModel((model) => { - const browserMain = model.getOrCreateProcess(0).getOrCreateThread(0); - browserMain.name = 'CrBrowserMain'; - const rendererCompositor = - model.getOrCreateProcess(1).getOrCreateThread(1); - rendererCompositor.name = 'Compositor'; - - // Creates a renderer thread - const renderer = model.getOrCreateProcess(2).getOrCreateThread(2); - renderer.name = 'CrRendererMain'; - renderer.asyncSliceGroup.push( - tr.c.TestUtils.newAsyncSliceNamed('Interaction.Action', 1, 1)); - - const rasterWorker = model.getOrCreateProcess(2).getOrCreateThread(5); - rasterWorker.name = 'CompositorTileWorker'; - - addPipelineForOneFrame(browserMain, rendererCompositor, - rasterWorker, 1, { - IssueBeginFrame: 1, ReceiveBeginFrame: 2, GenerateRenderPass: 3, - GenerateCompositorFrame: 4, SubmitCompositorFrame: 5, - ReceiveCompositorFrame: 6, SurfaceAggregation: 10, - rasterTaskStart: 2 - }); - addPipelineForOneFrame(browserMain, rendererCompositor, - rasterWorker, 2, { - IssueBeginFrame: 15, ReceiveBeginFrame: 16, - GenerateRenderPass: 17, GenerateCompositorFrame: 18, - SubmitCompositorFrame: 19, ReceiveCompositorFrame: 20, - SurfaceAggregation: 21, rasterTaskStart: 22 - }); - addPipelineForOneFrame(browserMain, rendererCompositor, - rasterWorker, 3, { - IssueBeginFrame: 32, ReceiveBeginFrame: 34, - GenerateRenderPass: 35, GenerateCompositorFrame: 36, - SubmitCompositorFrame: 37, SubmitCompositorFrame: 38, - ReceiveCompositorFrame: 41, SurfaceAggregation: 44, - rasterTaskStart: 25 - }); - }); - - const histograms = new tr.v.HistogramSet(); - tr.metrics.rendering.addPipelineHistograms( - histograms, model, [new tr.model.um.Segment(0, 50)]); - - - const beginFrameTransport = histograms.getHistogramNamed( - 'pipeline:begin_frame_transport'); - const frameSubmission = histograms.getHistogramNamed( - 'pipeline:begin_frame_to_frame_submission'); - const surfaceAggregation = histograms.getHistogramNamed( - 'pipeline:frame_submission_to_display'); - const rasterStart = histograms.getHistogramNamed( - 'pipeline:begin_frame_to_raster_start'); - const rasterEnd = histograms.getHistogramNamed( - 'pipeline:begin_frame_to_raster_end'); - assert.closeTo(beginFrameTransport.average, 4 / 3, 1e-6); - assert.closeTo(frameSubmission.average, 13 / 3, 1e-6); - assert.closeTo(surfaceAggregation.average, 13 / 3, 1e-6); - assert.closeTo(rasterStart.average, 6 / 2, 1e-6); - assert.closeTo(rasterEnd.average, 16 / 2, 1e-6); - }); - - test('graphicsPipeline_duplicateSteps', function() { - const model = tr.c.TestUtils.newModel((model) => { - const browserMain = model.getOrCreateProcess(0).getOrCreateThread(0); - browserMain.name = 'CrBrowserMain'; - const rendererCompositor = - model.getOrCreateProcess(1).getOrCreateThread(1); - rendererCompositor.name = 'Compositor'; - - // Creates a renderer thread - const renderer = model.getOrCreateProcess(2).getOrCreateThread(2); - renderer.name = 'CrRendererMain'; - renderer.asyncSliceGroup.push( - tr.c.TestUtils.newAsyncSliceNamed('Interaction.Action', 1, 1)); - - const rasterWorker = model.getOrCreateProcess(2).getOrCreateThread(5); - rasterWorker.name = 'CompositorTileWorker'; - - addPipelineForOneFrame(browserMain, rendererCompositor, - rasterWorker, 1, { - IssueBeginFrame: 1, ReceiveBeginFrame: 2, GenerateRenderPass: 3, - GenerateCompositorFrame: 4, SubmitCompositorFrame: 5, - ReceiveCompositorFrame: 6, SurfaceAggregation: 9, - rasterTaskStart: 3 - }); - - // Add duplicate steps for SubmitCompositorFrame and the subsequent - // steps for the same trace-id. - addPipelineForOneFrame(browserMain, rendererCompositor, - rasterWorker, 1, { - GenerateRenderPass: 10, GenerateCompositorFrame: 11, - SubmitCompositorFrame: 12, ReceiveCompositorFrame: 15, - SurfaceAggregation: 18, rasterTaskStart: 3 - }); - }); - const histograms = new tr.v.HistogramSet(); - tr.metrics.rendering.addPipelineHistograms( - histograms, model, - [new tr.model.um.Segment(0, 50), new tr.model.um.Segment(0, 20)]); - - const beginFrameTransport = histograms.getHistogramNamed( - 'pipeline:begin_frame_transport'); - const frameSubmission = histograms.getHistogramNamed( - 'pipeline:begin_frame_to_frame_submission'); - const surfaceAggregation = histograms.getHistogramNamed( - 'pipeline:frame_submission_to_display'); - const rasterStart = histograms.getHistogramNamed( - 'pipeline:begin_frame_to_raster_start'); - const rasterEnd = histograms.getHistogramNamed( - 'pipeline:begin_frame_to_raster_end'); - assert.strictEqual(beginFrameTransport.average, 1); - assert.strictEqual(frameSubmission.average, 4); - assert.strictEqual(surfaceAggregation.average, 4); - assert.strictEqual(rasterStart.average, 1); - assert.strictEqual(rasterEnd.average, 6); - }); - - test('graphicsPipeline_duplicateRenderers', function() { - const model = tr.c.TestUtils.newModel((model) => { - const browserMain = model.getOrCreateProcess(0).getOrCreateThread(0); - browserMain.name = 'CrBrowserMain'; - const rendererCompositor = - model.getOrCreateProcess(1).getOrCreateThread(1); - rendererCompositor.name = 'Compositor'; - - // Creates a renderer thread - const rendererWithIR = model.getOrCreateProcess(2).getOrCreateThread(2); - rendererWithIR.name = 'CrRendererMain'; - rendererWithIR.asyncSliceGroup.push( - tr.c.TestUtils.newAsyncSliceNamed('Interaction.Action', 1, 1)); - - const rasterWorkerWithIR = model.getOrCreateProcess(2) - .getOrCreateThread(5); - rasterWorkerWithIR.name = 'CompositorTileWorker'; - - const rendererWithoutIR = model.getOrCreateProcess(3) - .getOrCreateThread(2); - rendererWithoutIR.name = 'CrRendererMain'; - - const rasterWorkerWithoutIR = model.getOrCreateProcess(3) - .getOrCreateThread(5); - rasterWorkerWithoutIR.name = 'CompositorTileWorker'; - - addPipelineForOneFrame(browserMain, rendererCompositor, - rasterWorkerWithIR, 1, { - IssueBeginFrame: 1, ReceiveBeginFrame: 2, GenerateRenderPass: 3, - GenerateCompositorFrame: 4, SubmitCompositorFrame: 5, - ReceiveCompositorFrame: 6, SurfaceAggregation: 10, - rasterTaskStart: 3 - }); - addPipelineForOneFrame(browserMain, rendererCompositor, - rasterWorkerWithoutIR, 2, { - IssueBeginFrame: 1, ReceiveBeginFrame: 2, GenerateRenderPass: 3, - GenerateCompositorFrame: 4, SubmitCompositorFrame: 5, - ReceiveCompositorFrame: 6, SurfaceAggregation: 10, - rasterTaskStart: 4 - }); - }); - - const histograms = new tr.v.HistogramSet(); - tr.metrics.rendering.addPipelineHistograms( - histograms, model, [new tr.model.um.Segment(0, 50)]); - - const rasterStart = histograms.getHistogramNamed( - 'pipeline:begin_frame_to_raster_start'); - const rasterEnd = histograms.getHistogramNamed( - 'pipeline:begin_frame_to_raster_end'); - assert.strictEqual(rasterStart.average, 1); - assert.strictEqual(rasterEnd.average, 6); - }); - - test('graphicsPipeline_drawSteps', function() { - const model = tr.c.TestUtils.newModel((model) => { - const browserMain = model.getOrCreateProcess(0).getOrCreateThread(0); - browserMain.name = 'CrBrowserMain'; - const rendererCompositor = - model.getOrCreateProcess(1).getOrCreateThread(1); - rendererCompositor.name = 'Compositor'; - - // Creates a renderer thread - const renderer = model.getOrCreateProcess(2).getOrCreateThread(2); - renderer.name = 'CrRendererMain'; - renderer.asyncSliceGroup.push( - tr.c.TestUtils.newAsyncSliceNamed('Interaction.Action', 1, 1)); - - const rasterWorker = model.getOrCreateProcess(2).getOrCreateThread(5); - rasterWorker.name = 'CompositorTileWorker'; - - const displayTrace = '1'; - addPipelineForOneFrame(browserMain, rendererCompositor, - rasterWorker, 1, { - IssueBeginFrame: 1, ReceiveBeginFrame: 2, GenerateRenderPass: 3, - GenerateCompositorFrame: 4, SubmitCompositorFrame: 5, - ReceiveCompositorFrame: 6, SurfaceAggregation: 9, - rasterTaskStart: 3 - }, displayTrace); - - addDrawSlice(browserMain, displayTrace, 10, - {Draw: 2, Swap: 1, WaitForAck: 5}, {}); - }); - const histograms = new tr.v.HistogramSet(); - tr.metrics.rendering.addPipelineHistograms( - histograms, model, [new tr.model.um.Segment(0, 50)]); - - const drawHistogram = histograms.getHistogramNamed('pipeline:draw'); - assert.strictEqual(drawHistogram.average, 8); - }); - - test('graphicsPipeline_drawCanceled', function() { - const model = tr.c.TestUtils.newModel((model) => { - const browserMain = model.getOrCreateProcess(0).getOrCreateThread(0); - browserMain.name = 'CrBrowserMain'; - const rendererCompositor = - model.getOrCreateProcess(1).getOrCreateThread(1); - rendererCompositor.name = 'Compositor'; - - // Creates a renderer thread - const renderer = model.getOrCreateProcess(2).getOrCreateThread(2); - renderer.name = 'CrRendererMain'; - renderer.asyncSliceGroup.push( - tr.c.TestUtils.newAsyncSliceNamed('Interaction.Action', 1, 1)); - - const rasterWorker = model.getOrCreateProcess(2).getOrCreateThread(5); - rasterWorker.name = 'CompositorTileWorker'; - - const displayTrace = '1'; - addPipelineForOneFrame(browserMain, rendererCompositor, - rasterWorker, 1, { - IssueBeginFrame: 1, ReceiveBeginFrame: 2, GenerateRenderPass: 3, - GenerateCompositorFrame: 4, SubmitCompositorFrame: 5, - ReceiveCompositorFrame: 6, SurfaceAggregation: 9, - rasterTaskStart: 3 - }, displayTrace); - - addDrawSlice(browserMain, displayTrace, 10, - {Draw: 2, Swap: 1, WaitForAck: 5}, {status: 'canceled'}); - addDrawSlice(browserMain, displayTrace, 15, - {Draw: 2, Swap: 1, WaitForAck: 5}); - }); - const histograms = new tr.v.HistogramSet(); - tr.metrics.rendering.addPipelineHistograms( - histograms, model, [new tr.model.um.Segment(0, 50)]); - - const drawHistogram = histograms.getHistogramNamed('pipeline:draw'); - assert.strictEqual(drawHistogram.average, 8); - }); - - test('graphicsPipeline_receiveCFAfterAnimation', function() { - const model = tr.c.TestUtils.newModel((model) => { - const browserMain = model.getOrCreateProcess(0).getOrCreateThread(0); - browserMain.name = 'CrBrowserMain'; - const rendererCompositor = - model.getOrCreateProcess(1).getOrCreateThread(1); - rendererCompositor.name = 'Compositor'; - - // Creates a renderer thread - const renderer = model.getOrCreateProcess(2).getOrCreateThread(2); - renderer.name = 'CrRendererMain'; - renderer.asyncSliceGroup.push( - tr.c.TestUtils.newAsyncSliceNamed('Interaction.Action', 1, 1)); - - const rasterWorker = model.getOrCreateProcess(2).getOrCreateThread(5); - rasterWorker.name = 'CompositorTileWorker'; - - addPipelineForOneFrame(browserMain, rendererCompositor, - rasterWorker, 1, { - IssueBeginFrame: 1, ReceiveBeginFrame: 2, GenerateRenderPass: 3, - GenerateCompositorFrame: 4, SubmitCompositorFrame: 5, - ReceiveCompositorFrame: 11, SurfaceAggregation: 15, - rasterTaskStart: 2 - }); - }); - const histograms = new tr.v.HistogramSet(); - tr.metrics.rendering.addPipelineHistograms( - histograms, model, - [new tr.model.um.Segment(0, 10), new tr.model.um.Segment(14, 16)]); - - const surfaceAggregation = histograms.getHistogramNamed( - 'pipeline:frame_submission_to_display'); - assert.strictEqual(surfaceAggregation.average, 10); - }); -}); -</script> diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/rendering/rendering_metric.html b/chromium/third_party/catapult/tracing/tracing/metrics/rendering/rendering_metric.html index f5914853298..b7d292eec14 100644 --- a/chromium/third_party/catapult/tracing/tracing/metrics/rendering/rendering_metric.html +++ b/chromium/third_party/catapult/tracing/tracing/metrics/rendering/rendering_metric.html @@ -8,7 +8,6 @@ found in the LICENSE file. <link rel="import" href="/tracing/metrics/metric_registry.html"> <link rel="import" href="/tracing/metrics/rendering/frame_time.html"> <link rel="import" href="/tracing/metrics/rendering/image_decode_time.html"> -<link rel="import" href="/tracing/metrics/rendering/pipeline.html"> <link rel="import" href="/tracing/metrics/rendering/pixels.html"> <link rel="import" href="/tracing/metrics/rendering/queueing_duration.html"> @@ -32,7 +31,6 @@ tr.exportTo('tr.metrics.rendering', function() { tr.metrics.rendering.addFrameTimeHistograms(histograms, model, segments); tr.metrics.rendering.addImageDecodeTimeHistograms(histograms, model, segments); - tr.metrics.rendering.addPipelineHistograms(histograms, model, segments); tr.metrics.rendering.addPixelsHistograms(histograms, model, segments); tr.metrics.rendering.addQueueingDurationHistograms( histograms, model, segments); diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/v8/gc_metric.html b/chromium/third_party/catapult/tracing/tracing/metrics/v8/gc_metric.html index a16db407202..75cae51c2e1 100644 --- a/chromium/third_party/catapult/tracing/tracing/metrics/v8/gc_metric.html +++ b/chromium/third_party/catapult/tracing/tracing/metrics/v8/gc_metric.html @@ -35,6 +35,7 @@ tr.exportTo('tr.metrics.v8', function() { addMarkCompactorMutatorUtilization(histograms, model); addTotalMarkCompactorTime(histograms, model); addTotalMarkCompactorMarkingTime(histograms, model); + addScavengerSurvivedFromStackEvents(histograms, model); } tr.metrics.MetricRegistry.register(gcMetric); @@ -45,6 +46,8 @@ tr.exportTo('tr.metrics.v8', function() { tr.b.Unit.byName.normalizedPercentage_biggerIsBetter; const percentage_smallerIsBetter = tr.b.Unit.byName.normalizedPercentage_smallerIsBetter; + const bytes_smallerIsBetter = + tr.b.Unit.byName.sizeInBytes_smallerIsBetter; // 0.1 steps from 0 to 20 since it is the most common range. // Exponentially increasing steps from 20 to 200. @@ -217,6 +220,82 @@ tr.exportTo('tr.metrics.v8', function() { ); } + function createNumericForTotalBytes(name) { + const n = new tr.v.Histogram(name, + bytes_smallerIsBetter, CUSTOM_BOUNDARIES); + n.customizeSummaryOptions({ + avg: false, + count: false, + max: false, + min: false, + std: false, + sum: true, + percentile: [] + }); + return n; + } + + function createNumericForSampledPercent(name) { + const n = new tr.v.Histogram(name, + percentage_smallerIsBetter, CUSTOM_BOUNDARIES); + n.customizeSummaryOptions({ + avg: true, + count: false, + max: true, + min: true, + std: true, + sum: false, + percentile: [] + }); + return n; + } + + /** + * Adds the following metrics: + * - v8-gc-scavenger-survived-percentage-from-stack + * - v8-gc-scavenger-survived-total-bytes-without-stack + * - v8-gc-scavenger-survived-total-bytes-with-stack + * - v8-gc-scavenger-survived-total-percentage-from-stack + */ + function addScavengerSurvivedFromStackEvents(histograms, model) { + const baseName = 'v8-gc-scavenger-survived'; + tr.metrics.v8.utils.groupAndProcessEvents(model, + tr.metrics.v8.utils.isScavengerStackScanningEvent, + event => baseName, + function(name, events) { + const sampledPercentage = createNumericForSampledPercent( + baseName + '-percentage-from-stack'); + let survivedWithoutStack = 0; + let survivedWithStack = 0; + events.forEach(function(event) { + const bytesBefore = event.args.survived_bytes_before; + const bytesAfter = event.args.survived_bytes_after; + sampledPercentage.addSample((bytesAfter > 0) ? + (bytesAfter - bytesBefore) / bytesAfter : + 0); + survivedWithoutStack += bytesBefore; + survivedWithStack += bytesAfter; + }); + histograms.addHistogram(sampledPercentage); + const totalBytesSurvivedWithoutStack = createNumericForTotalBytes( + baseName + '-total-bytes-without-stack'); + totalBytesSurvivedWithoutStack.addSample(survivedWithoutStack); + histograms.addHistogram(totalBytesSurvivedWithoutStack); + const totalBytesSurvivedWithStack = createNumericForTotalBytes( + baseName + '-total-bytes-with-stack'); + totalBytesSurvivedWithStack.addSample(survivedWithStack); + histograms.addHistogram(totalBytesSurvivedWithStack); + const overallPercentage = createPercentage( + baseName + '-total-percentage-from-stack', + survivedWithStack - survivedWithoutStack, + survivedWithStack, + percentage_smallerIsBetter); + histograms.addHistogram(overallPercentage); + }, + [baseName] + ); + } + /** * Example output: * - v8-gc-full-mark-compactor-evacuate. diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/v8/gc_metric_test.html b/chromium/third_party/catapult/tracing/tracing/metrics/v8/gc_metric_test.html index fc3bd746773..4d0d3beca88 100644 --- a/chromium/third_party/catapult/tracing/tracing/metrics/v8/gc_metric_test.html +++ b/chromium/third_party/catapult/tracing/tracing/metrics/v8/gc_metric_test.html @@ -206,5 +206,43 @@ tr.b.unittest.testSuite(function() { 'v8-gc-mark-compactor-marking-total'); assert.closeTo(5.5, markCompactorTotal.sum, 1e-3); }); + + test('scavenverSurvivedFromStackEvents', function() { + const slices = [ + { + title: 'V8.GCScavengerStackScanning', + args: {'survived_bytes_before': 50, 'survived_bytes_after': 100}, + start: 100, end: 100, cpuStart: 100, cpuEnd: 100 + }, + { + title: 'V8.GCScavengerStackScanning', + args: {'survived_bytes_before': 0, 'survived_bytes_after': 0}, + start: 200, end: 200, cpuStart: 200, cpuEnd: 200 + }, + { + title: 'V8.GCScavengerStackScanning', + args: {'survived_bytes_before': 50, 'survived_bytes_after': 50}, + start: 300, end: 300, cpuStart: 300, cpuEnd: 300 + }, + { + title: 'V8.GCScavengerStackScanning', + args: {'survived_bytes_before': 0, 'survived_bytes_after': 250}, + start: 400, end: 400, cpuStart: 400, cpuEnd: 400 + }, + ]; + const histograms = run(slices); + const totalBytesWithoutStack = histograms.getHistogramNamed( + 'v8-gc-scavenger-survived-total-bytes-without-stack'); + assert.strictEqual(100, totalBytesWithoutStack.sum, 1e-3); + const totalBytesWithStack = histograms.getHistogramNamed( + 'v8-gc-scavenger-survived-total-bytes-with-stack'); + assert.strictEqual(400, totalBytesWithStack.sum, 1e-3); + const totalPercentageFromStack = histograms.getHistogramNamed( + 'v8-gc-scavenger-survived-total-percentage-from-stack'); + assert.closeTo(0.75, totalPercentageFromStack.average, 1e-3); + const percentageFromStack = histograms.getHistogramNamed( + 'v8-gc-scavenger-survived-percentage-from-stack'); + assert.closeTo(0.375, percentageFromStack.average, 1e-3); + }); }); </script> diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/v8/utils.html b/chromium/third_party/catapult/tracing/tracing/metrics/v8/utils.html index 32bf01e62e3..cf2a608ae32 100644 --- a/chromium/third_party/catapult/tracing/tracing/metrics/v8/utils.html +++ b/chromium/third_party/catapult/tracing/tracing/metrics/v8/utils.html @@ -145,6 +145,10 @@ tr.exportTo('tr.metrics.v8.utils', function() { return event.title === 'V8.GCMarkCompactorMarkingSummary'; } + function isScavengerStackScanningEvent(event) { + return event.title === 'V8.GCScavengerStackScanning'; + } + function isIncrementalMarkingEvent(event) { return event.title.startsWith('V8.GCIncrementalMarking'); } @@ -528,6 +532,7 @@ tr.exportTo('tr.metrics.v8.utils', function() { isNotForcedTopGarbageCollectionEvent, isNotForcedSubGarbageCollectionEvent, isScavengerEvent, + isScavengerStackScanningEvent, isSubGarbageCollectionEvent, isTopGarbageCollectionEvent, isTopV8ExecuteEvent, diff --git a/chromium/third_party/catapult/tracing/tracing/proto/histogram.proto b/chromium/third_party/catapult/tracing/tracing/proto/histogram.proto index 683bb5aafb0..ae91073d7dd 100644 --- a/chromium/third_party/catapult/tracing/tracing/proto/histogram.proto +++ b/chromium/third_party/catapult/tracing/tracing/proto/histogram.proto @@ -27,6 +27,7 @@ enum Unit { UNITLESS = 11; COUNT = 12; SIGMA = 13; + AH = 14; // Ampere-hours. } message UnitAndDirection { diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/file.html b/chromium/third_party/catapult/tracing/tracing/ui/base/file.html index 0c4945933f1..3056b6a4c6e 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/file.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/file.html @@ -21,7 +21,8 @@ tr.exportTo('tr.ui.b', function() { reject(err); }; - const isBinary = filename.endsWith('.gz') || filename.endsWith('.zip'); + const isBinary = filename.endsWith('.gz') || filename.endsWith('.zip') || + filename.endsWith('.pftrace'); if (isBinary) { reader.readAsArrayBuffer(fileBlob); } else { diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/profiling_view.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/profiling_view.html index 77c0e80af12..3590c525407 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/profiling_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/profiling_view.html @@ -6,6 +6,7 @@ found in the LICENSE file. --> <link rel="import" href="/tracing/base/base64.html"> +<link rel="import" href="/tracing/extras/importer/pako.html"> <link rel="import" href="/tracing/importer/import.html"> <link rel="import" href="/tracing/ui/base/file.html"> <link rel="import" href="/tracing/ui/base/hotkey_controller.html"> @@ -166,7 +167,7 @@ tr.exportTo('tr.ui.e.about_tracing', function() { this.isRecording_ = false; const traceName = tr.ui.e.about_tracing.defaultTraceName( this.tracingControllerClient_); - this.setActiveTrace(traceName, data, false); + this.setActiveTrace(traceName, data); }.bind(this), function(err) { this.isRecording_ = false; @@ -190,6 +191,11 @@ tr.exportTo('tr.ui.e.about_tracing', function() { }, setActiveTrace(filename, data) { + const isProtobufTrace = this.isProtobufTrace_(data); + if (isProtobufTrace) { + filename = filename.replace('.json', '.pftrace'); + } + this.activeTrace_ = { filename, data @@ -200,6 +206,25 @@ tr.exportTo('tr.ui.e.about_tracing', function() { this.saveButton_.disabled = false; this.timelineView_.viewTitle = filename; + // Bypass the standard importer pipeline for protobuf-format traces and + // redirect the user to the Perfetto UI instead. Note that we can't + // actually open the trace for the user due to chrome:// protocol + // restrictions. + if (isProtobufTrace) { + this.timelineView_.model = new tr.Model(); + this.timelineView_.updateDocumentFavicon(); + this.infoBarGroup_.addMessage( + 'Cannot display protobuf format trace. Please save the trace ' + + 'and view it in Perfetto UI instead.', + [{ + buttonText: 'Open Perfetto UI', + onClick(event, infobar) { + window.open('https://ui.perfetto.dev'); + } + }]); + return; + } + const m = new tr.Model(); const i = new tr.importer.Import(m); const p = i.importTracesWithProgressDialog([data]); @@ -215,6 +240,43 @@ tr.exportTo('tr.ui.e.about_tracing', function() { /////////////////////////////////////////////////////////////////////////// + // Detects a (possibly gzipped) Perfetto protobuf trace. + isProtobufTrace_(data) { + // We only look at the first ~4 KB to avoid reading the entire trace. + data = new Uint8Array(data, 0, 4096); + + // If the trace is gzipped, decompress the beginning first. + const GZIP_HEADER_ID1 = 0x1f; + const GZIP_HEADER_ID2 = 0x8b; + const GZIP_DEFLATE_COMPRESSION = 8; + if (data.length > 3 && + data[0] === GZIP_HEADER_ID1 && + data[1] === GZIP_HEADER_ID2 && + data[2] === GZIP_DEFLATE_COMPRESSION) { + data = pako.ungzip(data); + } + + // Look for Perfetto's sync marker. + const syncMarker = new Uint8Array([0x82, 0x47, 0x7a, 0x76, 0xb2, 0x8d, + 0x42, 0xba, 0x81, 0xdc, 0x33, 0x32, 0x6d, 0x57, 0xa0, 0x79]); + for (let i = 0; i < data.length; i++) { + let match = true; + for (let j = 0; j < syncMarker.length; j++) { + if (i + j >= data.length) { + return false; + } + if (data[i + j] !== syncMarker[j]) { + match = false; + break; + } + } + if (match) { + return true; + } + } + return false; + }, + initButtons_() { this.recordButton_.addEventListener( 'click', function(event) { @@ -242,9 +304,13 @@ tr.exportTo('tr.ui.e.about_tracing', function() { const defaultName = this.activeTrace_.filename; let fileExtension = '.json'; let fileRegex = /\.json$/; + if (/[.]pftrace/.test(defaultName)) { + fileExtension = '.pftrace'; + fileRegex = /\.pftrace$/; + } if (/[.]gz$/.test(defaultName)) { fileExtension += '.gz'; - fileRegex = /\.json\.gz$/; + fileRegex = new RegExp(fileExtension + '[.]gz$'); } else if (/[.]zip$/.test(defaultName)) { fileExtension = '.zip'; fileRegex = /\.zip$/; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/profiling_view_test.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/profiling_view_test.html index f52c491207f..1344c1a36f9 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/profiling_view_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/profiling_view_test.html @@ -71,6 +71,20 @@ tr.b.unittest.testSuite(function() { assert.fail(err); }); }); + + test('protobufTraceDetection', function() { + const protobufTrace = new Uint8Array([ + // Arbitrary data. + 0xda, 0xda, 0xca, 0xfe, + // Sync marker. + 0x82, 0x47, 0x7a, 0x76, 0xb2, 0x8d, 0x42, 0xba, 0x81, 0xdc, 0x33, 0x32, + 0x6d, 0x57, 0xa0, 0x79, + // More data + 0x0b, 0x0a, 0x0d, 0x0c, 0x00, 0x0d, 0x0e]); + const view = new ProfilingView(null); + view.setActiveTrace('trace.json', protobufTrace); + assert.strictEqual('trace.pftrace', view.activeTrace_.filename); + }); }); </script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/record_controller.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/record_controller.html index a9b42b589d8..9eaa7784d6d 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/record_controller.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/record_controller.html @@ -91,6 +91,7 @@ tr.exportTo('tr.ui.e.about_tracing', function() { excluded_categories: categories.excluded, enable_systrace: selectionDlg.useSystemTracing, record_mode: selectionDlg.tracingRecordMode, + stream_format: selectionDlg.useProtobuf ? 'protobuf' : 'json', }; if (categories.included.indexOf( 'disabled-by-default-memory-infra') !== -1) { diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/record_selection_dialog.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/record_selection_dialog.html index b628d6d973b..d07865be256 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/record_selection_dialog.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/record_selection_dialog.html @@ -244,6 +244,7 @@ tr.exportTo('tr.ui.e.about_tracing', function() { const DEFAULT_CONTINUOUS_TRACING = true; const DEFAULT_SYSTEM_TRACING = true; const DEFAULT_SAMPLING_TRACING = false; + const DEFAULT_USE_PROTOBUF = false; RecordSelectionDialog.prototype = { __proto__: tr.ui.b.Overlay.prototype, @@ -291,6 +292,10 @@ tr.exportTo('tr.ui.e.about_tracing', function() { undefined, undefined, 'recordSelectionDialog.useSampling', DEFAULT_SAMPLING_TRACING, 'State sampling'); + this.useProtobufBn_ = tr.ui.b.createCheckBox( + undefined, undefined, + 'recordSelectionDialog.useProtobuf', DEFAULT_USE_PROTOBUF, + 'Use protobuf'); this.tracingModesContainerEl_ = Polymer.dom(this).querySelector( '.tracing-modes'); Polymer.dom(this.tracingModesContainerEl_).appendChild( @@ -299,6 +304,8 @@ tr.exportTo('tr.ui.e.about_tracing', function() { this.systemTracingBn_); Polymer.dom(this.tracingModesContainerEl_).appendChild( this.samplingTracingBn_); + Polymer.dom(this.tracingModesContainerEl_).appendChild( + this.useProtobufBn_); this.enabledCategoriesContainerEl_ = Polymer.dom(this).querySelector( @@ -356,6 +363,13 @@ tr.exportTo('tr.ui.e.about_tracing', function() { this.samplingTracingBn_.checked = !!value; }, + get useProtobuf() { + return this.useProtobufBn_.checked; + }, + set useProtobuf(value) { + this.useProtobufBn_.checked = !!value; + }, + set categories(c) { if (!(c instanceof Array)) { throw new Error('categories must be an array'); diff --git a/chromium/third_party/catapult/tracing/tracing/value/histogram.cc b/chromium/third_party/catapult/tracing/tracing/value/histogram.cc index fbdc207e908..3c3ec422ea4 100644 --- a/chromium/third_party/catapult/tracing/tracing/value/histogram.cc +++ b/chromium/third_party/catapult/tracing/tracing/value/histogram.cc @@ -26,6 +26,7 @@ static constexpr std::pair<const char*, proto::Unit> kJsonUnitToProtoUnit[] = { {"J", proto::J}, {"W", proto::W}, {"A", proto::A}, + {"Ah", proto::AH}, {"V", proto::V}, {"Hz", proto::HERTZ}, {"unitless", proto::UNITLESS}, diff --git a/chromium/third_party/catapult/tracing/tracing/value/histogram.py b/chromium/third_party/catapult/tracing/tracing/value/histogram.py index f3551a53055..d94f1a12327 100644 --- a/chromium/third_party/catapult/tracing/tracing/value/histogram.py +++ b/chromium/third_party/catapult/tracing/tracing/value/histogram.py @@ -9,6 +9,7 @@ from __future__ import print_function import json import math import numbers +import pprint import random import six @@ -618,6 +619,8 @@ class HistogramBin(object): sample[1:], deserializer)) +# This list should be kept in sync with tracing/tracing/base/unit.html +# and tracing/tracing/value/histogram.cc. # TODO(#3814) Presubmit to compare with unit.html. UNIT_NAMES = [ 'ms', @@ -629,6 +632,7 @@ UNIT_NAMES = [ 'J', # Joule 'W', # Watt 'A', # Ampere + 'Ah', # Ampere-hours 'V', # Volt 'Hz', # Hertz 'unitless', @@ -647,13 +651,18 @@ def ExtendUnitNames(): ExtendUnitNames() +def UnrecognizedUnitMessage(unit): + output = 'Unrecognized unit "%r". ' % unit + output += "Use one of the following:\n" + output += pprint.pformat(UNIT_NAMES) + return output + class Scalar(object): __slots__ = '_unit', '_value' def __init__(self, unit, value): - assert unit in UNIT_NAMES, ( - 'Unrecognized unit "%r"' % unit) + assert unit in UNIT_NAMES, UnrecognizedUnitMessage(unit) self._unit = unit self._value = value @@ -705,8 +714,7 @@ class Histogram(object): '_max_num_sample_values') def __init__(self, name, unit, bin_boundaries=None): - assert unit in UNIT_NAMES, ( - 'Unrecognized unit "%r"' % unit) + assert unit in UNIT_NAMES, UnrecognizedUnitMessage(unit) if bin_boundaries is None: base_unit = unit.split('_')[0].strip('+-') @@ -1658,6 +1666,7 @@ DEFAULT_BOUNDARIES_FOR_UNIT = { 'J': HistogramBinBoundaries.CreateExponential(1e-3, 1e3, 50), 'W': HistogramBinBoundaries.CreateExponential(1e-3, 1, 50), 'A': HistogramBinBoundaries.CreateExponential(1e-3, 1, 50), + 'Ah': HistogramBinBoundaries.CreateExponential(1e-3, 1, 50), 'V': HistogramBinBoundaries.CreateExponential(1e-3, 1, 50), 'Hz': HistogramBinBoundaries.CreateExponential(1e-3, 1, 50), 'unitless': HistogramBinBoundaries.CreateExponential(1e-3, 1e3, 50), diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/histogram_set_controls.html b/chromium/third_party/catapult/tracing/tracing/value/ui/histogram_set_controls.html index c55093a90ec..61a13ac8482 100644 --- a/chromium/third_party/catapult/tracing/tracing/value/ui/histogram_set_controls.html +++ b/chromium/third_party/catapult/tracing/tracing/value/ui/histogram_set_controls.html @@ -108,10 +108,6 @@ found in the LICENSE file. margin-right: 20px; } - #show_visualization { - margin-right: 20px; - } - #export { margin-right: 20px; } @@ -159,8 +155,6 @@ found in the LICENSE file. <select id="statistic" value="{{displayStatisticName::change}}"> </select> - <button id="show_visualization" on-tap="loadVisualization_">Visualize</button> - <tr-ui-b-dropdown label="Export"> <tr-v-ui-histogram-set-controls-export> </tr-v-ui-histogram-set-controls-export> @@ -541,14 +535,6 @@ tr.exportTo('tr.v.ui', function() { } return ALPHA_OPTIONS.length - 1; }, - - set enableVisualization(enable) { - this.$.show_visualization.style.display = enable ? 'inline' : 'none'; - }, - - loadVisualization_() { - tr.b.dispatchSimpleEvent(this, 'loadVisualization', true, true, {}); - }, }); return { diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/histogram_set_view.html b/chromium/third_party/catapult/tracing/tracing/value/ui/histogram_set_view.html index 18ba824811f..97532f7ccf7 100644 --- a/chromium/third_party/catapult/tracing/tracing/value/ui/histogram_set_view.html +++ b/chromium/third_party/catapult/tracing/tracing/value/ui/histogram_set_view.html @@ -11,7 +11,6 @@ found in the LICENSE file. <link rel="import" href="/tracing/value/histogram_parameter_collector.html"> <link rel="import" href="/tracing/value/ui/histogram_set_controls.html"> <link rel="import" href="/tracing/value/ui/histogram_set_table.html"> -<link rel="import" href="/tracing/value/ui/visualizations_data_container.html"> <dom-module id="tr-v-ui-histogram-set-view"> <template> @@ -34,9 +33,6 @@ found in the LICENSE file. display: none; } - #visualizations{ - display: none; - } </style> <div id="zero">zero Histograms</div> @@ -45,9 +41,6 @@ found in the LICENSE file. <tr-v-ui-histogram-set-controls id="controls"> </tr-v-ui-histogram-set-controls> - <tr-v-ui-visualizations-data-container id="visualizations"> - </tr-v-ui-visualizations-data-container> - <tr-v-ui-histogram-set-table id="table"></tr-v-ui-histogram-set-table> </div> </template> @@ -61,13 +54,11 @@ tr.exportTo('tr.v.ui', function() { listeners: { export: 'onExport_', - loadVisualization: 'onLoadVisualization_' }, created() { this.brushingStateController_ = new tr.ui.NullBrushingStateController(); this.viewState_ = new tr.v.ui.HistogramSetViewState(); - this.visualizationLoaded_ = false; }, ready() { @@ -139,20 +130,6 @@ tr.exportTo('tr.v.ui', function() { this.$.controls.displayLabels = displayLabels; collectParametersMark.end(); - // Only show visualizer button if values are from rendering benchmarks - const hist = [...histograms][0]; - const benchmarks = hist.diagnostics.get(tr.v.d.RESERVED_NAMES.BENCHMARKS); - let enable = false; - if (benchmarks !== undefined && benchmarks.length > 0) { - for (const benchmark of benchmarks) { - if (benchmark.includes('rendering')) { - enable = true; - break; - } - } - } - this.$.controls.enableVisualization = enable; - // Table.build() displays its own progress. await this.$.table.build( histograms, sourceHistograms, displayLabels, progress); @@ -188,20 +165,6 @@ tr.exportTo('tr.v.ui', function() { anchor.click(); mark.end(); }, - - onLoadVisualization_(event) { - if (!this.visualizationLoaded_) { // Initial loading - this.$.visualizations.style.display = 'block'; - this.$.visualizations.build(this.$.table.leafHistograms, - this.histograms); - this.visualizationLoaded_ = true; - } else if (this.$.visualizations.style.display === 'none') { - // Toggle to hide - this.$.visualizations.style.display = 'block'; - } else { - this.$.visualizations.style.display = 'none'; - } - }, }); return { diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/metrics_visualization.html b/chromium/third_party/catapult/tracing/tracing/value/ui/metrics_visualization.html deleted file mode 100644 index 1bc6ea696b3..00000000000 --- a/chromium/third_party/catapult/tracing/tracing/value/ui/metrics_visualization.html +++ /dev/null @@ -1,353 +0,0 @@ -<!DOCTYPE html> -<!-- -Copyright (c) 2018 The Chromium Authors. All rights reserved. -Use of this source code is governed by a BSD-style license that can be -found in the LICENSE file. ---> - -<link rel="import" href="/tracing/base/math/math.html"> -<link rel="import" href="/tracing/base/math/running_statistics.html"> -<link rel="import" href="/tracing/ui/base/name_bar_chart.html"> -<link rel="import" href="/tracing/ui/base/name_column_chart.html"> -<dom-module id='tr-v-ui-metrics-visualization'> - <template> - <style> - button { - padding: 5px; - font-size: 14px; - } - - .text_input { - width: 50px; - padding: 4px; - font-size: 14px; - } - - .error { - color: red; - display: none; - } - - .container { - position: relative; - display: inline-block; - margin-left: 15px; - } - - #title { - font-size: 20px; - font-weight: bold; - padding-bottom: 5px; - } - - #selectors { - display: block; - padding-bottom: 10px; - } - - #search_page { - width: 200px; - margin-left: 30px; - } - - #close { - display: none; - vertical-align: top; - } - - #close svg{ - height: 1em; - } - - #close svg line { - stroke-width: 18; - stroke: black; - } - - #close:hover svg { - background: black; - } - - #close:hover svg line { - stroke: white; - } - </style> - <span id="aggregateContainer" class="container"> - </span> - <span id="pageByPageContainer" class="container"> - <span id="selectors"> - <span id="percentile_label">Percentile Range:</span> - <input id="start" class="text_input" placeholder="0"> - <input id="end" class="text_input" placeholder="100"> - <button id="filter" on-tap="filterByPercentile_">Filter</button> - <input id="search_page" class="text_input" placeholder="Page Name"> - <button id="search" on-tap="searchByPage_">Search</button> - <span id="search_error" class="error">Sorry, could not find that page!</span> - </span> - </span> - <div id="submetricsContainer" display="block"> - <span id="close"> - <svg viewbox="0 0 128 128"> - <line x1="28" y1="28" x2="100" y2="100"/> - <line x1="28" y1="100" x2="100" y2="28"/> - </svg> - </span> - </div> - </template> -</dom-module> -<script> -'use strict'; - -tr.exportTo('tr.v.ui', function() { - const PAGE_BREAKDOWN_KEY = 'pageBreakdown'; - - Polymer({ - is: 'tr-v-ui-metrics-visualization', - - created() { - this.charts_ = new Map(); - }, - - ready() { - this.$.start.addEventListener ('keydown', (e) => { - if (e.key === 'Enter') this.filterByPercentile_(); - }); - - this.$.end.addEventListener ('keydown', (e) => { - if (e.key === 'Enter') this.filterByPercentile_(); - }); - - this.$.search_page.addEventListener ('keydown', (e) => { - if (e.key === 'Enter') this.searchByPage_(); - }); - }, - - build(chartData) { - this.title_ = chartData.title; - this.aggregateData_ = chartData.aggregate; - this.data_ = chartData.page; - this.submetricsData_ = chartData.submetrics; - this.benchmarkCount_ = chartData.aggregate.length; - - // build aggregate chart - const aggregateChart = this.initializeColumnChart(this.title_); - Polymer.dom(this.$.aggregateContainer).appendChild(aggregateChart); - this.charts_.set(tr.v.ui.AGGREGATE_KEY, aggregateChart); - this.setChartColors_(tr.v.ui.AGGREGATE_KEY); - aggregateChart.data = chartData.aggregate; - this.setChartSize_(tr.v.ui.AGGREGATE_KEY); - - // build page by page - const newChart = this.initializeColumnChart(this.title_ + ' Breakdown'); - newChart.enableToolTip = true; - newChart.toolTipCallBack = (rect) => - this.openChildChart_(rect); - Polymer.dom(this.$.pageByPageContainer).appendChild(newChart); - this.charts_.set(PAGE_BREAKDOWN_KEY, newChart); - this.setChartColors_(PAGE_BREAKDOWN_KEY); - newChart.data = this.data_; - this.setChartSize_(PAGE_BREAKDOWN_KEY); - }, - - setChartSize_(page) { - const chart = this.charts_.get(page); - const pageCount = chart.data.length; - chart.graphHeight = tr.b.math.clamp(pageCount * 20, 400, 600); - chart.graphWidth = tr.b.math.clamp(pageCount * 30, 200, 1000); - }, - - // Assign color gradient to series in chart - setChartColors_(page) { - const chart = this.charts_.get(page); - const metrics = tr.v.ui.METRICS.get(this.title_); - for (let i = 0; i < this.benchmarkCount_; ++i) { - for (let j = 0; j < metrics.length; ++j) { - const mainColorIndex = j % tr.v.ui.COLORS.length; - const subColorIndex = i % tr.v.ui.COLORS[mainColorIndex].length; - const color = tr.v.ui.COLORS[mainColorIndex][subColorIndex]; - const series = metrics[j] + '-' + this.aggregateData_[i].x; - chart.getDataSeries(series).color = color; - if (i === 0) { - chart.getDataSeries(series).title = metrics[j]; - } else { - chart.getDataSeries(series).title = ''; - } - } - } - }, - - // Element creation - initializeColumnChart(title) { - const newChart = new tr.ui.b.NameColumnChart(); - newChart.hideLegend = false; - newChart.isStacked = true; - newChart.yAxisLabel = 'ms'; - newChart.hideXAxis = true; - newChart.displayXInHover = true; - newChart.isGrouped = true; - newChart.showTitleInLegend = true; - newChart.chartTitle = title; - newChart.titleHeight = '14pt'; - return newChart; - }, - - initializeChildChart_(title, height, width) { - const div = document.createElement('div'); - div.classList.add('container'); - Polymer.dom(this.$.submetricsContainer). - insertBefore(div, this.$.submetricsContainer.firstChild); - - const childChart = new tr.ui.b.NameBarChart(); - childChart.xAxisLabel = 'ms'; - childChart.chartTitle = title; - childChart.graphHeight = height; - childChart.graphWidth = width; - childChart.titleHeight = '14pt'; - childChart.isStacked = true; - childChart.hideLegend = true; - childChart.isGrouped = true; - childChart.isWaterfall = true; - - div.appendChild(childChart); - - const button = this.initializeCloseButton_(div, - this.$.submetricsContainer); - div.appendChild(button); - return childChart; - }, - - initializeCloseButton_(div, parent) { - const button = this.$.close.cloneNode(true); - button.style.display = 'inline-block'; - button.addEventListener ('click', () => { - Polymer.dom(parent).removeChild(div); - }); - return button; - }, - - // Create child chart and populate it - openChildChart_(rect) { - // Find main metric and corresponding sub-metrics - const metrics = tr.v.ui.METRICS.get(this.title_); - let metric; - let metricIndex; - for (let i = 0; i < metrics.length; ++i) { - if (rect.key.startsWith(metrics[i])) { - metric = metrics[i]; - metricIndex = i; - break; - } - } - - // Create child chart - const page = rect.datum.group; - const title = this.title_ + ' ' + metric + ': ' + page; - const submetrics = this.submetricsData_.get(page).get(metric); - const width = tr.b.math.clamp(submetrics.size * 150, 300, 700); - const height = tr.b.math.clamp(submetrics.size * - this.benchmarkCount_ * 50, 300, 700); - - const childChart = this.initializeChildChart_(title, height, width); - - // Get breakdown data for main step - childChart.data = this.processSubmetrics_(childChart, - submetrics, 0, metricIndex).data; - }, - - processSubmetrics_(chart, submetrics, hideValue, metricIndex) { - const finalData = []; - let submetricIndex = 0; - for (const submetric of submetrics.values()) { - let benchmarkIndex = 0; - for (const benchmark of submetric.values()) { - benchmark.hide = !hideValue ? 0 : hideValue; - const series = benchmark.x + '-' + benchmark.group; - const mainColorIndex = metricIndex % tr.v.ui.COLORS.length; - const subColorIndex = benchmarkIndex % - tr.v.ui.COLORS[mainColorIndex].length; - chart.getDataSeries(series).color = - tr.v.ui.COLORS[mainColorIndex][subColorIndex]; - if (benchmarkIndex === (this.benchmarkCount_ - 1)) { - hideValue += benchmark[series]; - } - finalData.push(benchmark); - benchmarkIndex++; - } - submetricIndex++; - } - return {data: finalData, hide: hideValue}; - }, - - // Handle filtering by start and end percentiles - filterByPercentile_() { - const startPercentile = this.$.start.value; - const endPercentile = this.$.end.value; - - if (startPercentile === '' || endPercentile === '') return; - - const length = this.data_.length / (this.benchmarkCount_ + 1); - const startIndex = this.getPercentileIndex_(startPercentile, length); - const endIndex = this.getPercentileIndex_(endPercentile, length); - this.charts_.get(PAGE_BREAKDOWN_KEY).data = - this.data_.slice(startIndex, endIndex); - }, - - // Get index of x percentile value - getPercentileIndex_(percentile, arrayLength) { - const index = Math.ceil(arrayLength * (percentile / 100.0)); - if (index === -1) return 0; - if (index >= arrayLength) return arrayLength; - return index * this.benchmarkCount_; - }, - - // Handle searching by page name - searchByPage_() { - const criteria = this.$.search_page.value; - if (criteria === '') return; - - const query = new RegExp(criteria); - - const filteredData = [...this.data_] - .filter(group => { - if (group.group) return group.group.match(query); - return false; - }); - - if (filteredData.length < 1) { - this.$.search_error.style.display = 'block'; - return; - } - - // Create child chart with breakdown data - const page = filteredData[0].group; - const title = this.title_ + ' Breakdown: ' + page; - const metricToSubmetricMap = this.submetricsData_.get(page); - - let totalSubmetrics = 0; - for (const submetrics of metricToSubmetricMap.values()) { - for (const benchmark of submetrics.values()) { - totalSubmetrics += benchmark.length; - } - } - const width = tr.b.math.clamp(totalSubmetrics * 150, 300, 700); - const height = tr.b.math.clamp(totalSubmetrics * - this.benchmarkCount_ * 30, 300, 700); - - const childChart = this.initializeChildChart_(title, height, width); - - const childData = []; - let hide = 0; - let metricIndex = 0; - for (const submetrics of metricToSubmetricMap.values()) { - const submetricsData = this.processSubmetrics_(childChart, submetrics, - hide, metricIndex); - childData.push(...submetricsData.data); - hide = submetricsData.hide; - metricIndex++; - } - childChart.data = childData; - }, - - }); -}); -</script> diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/metrics_visualization_test.html b/chromium/third_party/catapult/tracing/tracing/value/ui/metrics_visualization_test.html deleted file mode 100644 index 0d062557f63..00000000000 --- a/chromium/third_party/catapult/tracing/tracing/value/ui/metrics_visualization_test.html +++ /dev/null @@ -1,86 +0,0 @@ -<!DOCTYPE html> -<!-- -Copyright (c) 2018 The Chromium Authors. All rights reserved. -Use of this source code is governed by a BSD-style license that can be -found in the LICENSE file. ---> - -<link rel="import" href="/tracing/value/ui/metrics_visualization.html"> -<link rel="import" href="/tracing/value/ui/visualizations_data_container.html"> - -<script> -'use strict'; -tr.b.unittest.testSuite(function() { - function generateChartBar(metrics, benchmark, page) { - const data = {x: benchmark, group: page}; - for (const metric of metrics) { - const key = metric + '-' + benchmark; - const mean = Math.random() * 100; - data[key] = Math.round(mean * 100) / 100; - } - return data; - } - - function generateSubmetricBar(submetric, benchmark, page, - metricToSubmetricMap) { - let submetricToBenchmarkMap = metricToSubmetricMap.get(submetric); - if (!submetricToBenchmarkMap) { - submetricToBenchmarkMap = []; - metricToSubmetricMap.set(submetric, submetricToBenchmarkMap); - } - const data = {x: submetric, hide: 0, group: benchmark}; - const mean = Math.random() * 100; - data[submetric + '-' + benchmark] = Math.round(mean * 100) / 100; - submetricToBenchmarkMap.push(data); - } - - test('instantiate', function() { - const mv = document.createElement('tr-v-ui-metrics-visualization'); - this.addHTMLOutput(mv); - - const testMetrics = tr.v.ui.METRICS.get('Thread'); - - // generate aggregate chart - const aggregateChart = []; - for (let i = 1; i <= 5; i++) { - aggregateChart.push(generateChartBar(testMetrics, - 'Run ' + i, 'aggregate')); - } - - // generate chart with individual page metrics - const chartData = []; - for (let i = 1; i <= 5; i++) { - for (let j = 1; j <= 5; j++) { - chartData.push(generateChartBar(testMetrics, - 'Run ' + i, 'Page ' + j)); - } - } - - // generate submetrics - const submetricsData = new Map(); - for (const metric in testMetrics) { - const testSubmetrics = [metric + 'a', metric + 'b', metric + 'c']; - for (let i = 1; i <= 5; i++) { - const page = 'Page ' + i; - const pageToMetricMap = tr.v.ui.getValueFromMap(page, - submetricsData); - const metricToSubmetricMap = tr.v.ui.getValueFromMap(metric, - pageToMetricMap); - for (let j = 1; j <= 5; j++) { - for (const submetric in testSubmetrics) { - generateSubmetricBar(submetric, 'Run ' + j, page, - metricToSubmetricMap); - } - } - } - } - - mv.build({ - title: 'Thread', - aggregate: aggregateChart, - page: chartData, - submetrics: submetricsData - }); - }); -}); -</script>
\ No newline at end of file diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/raster_visualization.html b/chromium/third_party/catapult/tracing/tracing/value/ui/raster_visualization.html deleted file mode 100644 index d3253d8eff9..00000000000 --- a/chromium/third_party/catapult/tracing/tracing/value/ui/raster_visualization.html +++ /dev/null @@ -1,274 +0,0 @@ -<!DOCTYPE html> -<!-- -Copyright (c) 2018 The Chromium Authors. All rights reserved. -Use of this source code is governed by a BSD-style license that can be -found in the LICENSE file. ---> -<dom-module id='tr-v-ui-raster-visualization'> - <template> - <style> - button { - padding: 5px; - font-size: 14px; - } - .error { - color: red; - display: none; - } - - .text_input { - width: 200px; - padding: 4px; - font-size: 14px; - } - - .selector_container{ - padding: 5px; - } - - #search { - display: inline-block; - padding-bottom: 10px; - } - - #search_page { - width: 200px; - } - - #pageSelector { - display: inline-block; - font-size: 12pt; - } - - #close { - display: none; - vertical-align: top; - } - - #close svg{ - height: 1em; - } - - #close svg line { - stroke-width: 18; - stroke: black; - } - - #close:hover svg { - background: black; - } - - #close:hover svg line { - stroke: white; - } - </style> - <span id="aggregateContainer"> - <div> - <div class="selector_container"> - <span id="select_page_label">Individual Page Results:</span> - <select id="pageSelector"> - <option id="select_page" value="">Select a page</option> - </select> - </div> - <div class="selector_container"> - <div id="search_page_label">Search for a page:</div> - <input id="search_page" class="text_input" placeholder="Page Name"> - <button id="search_button">Search</button> - <div id="search_error" class="error">Sorry, could not find that page!</div> - </div> - </div> - </span> - <span id="pageContainer"> - <span id="close"> - <svg viewbox="0 0 128 128"> - <line x1="28" y1="28" x2="100" y2="100"/> - <line x1="28" y1="100" x2="100" y2="28"/> - </svg> - </span> - </span> - </template> -</dom-module> -<script> -'use strict'; - -Polymer({ - is: 'tr-v-ui-raster-visualization', - - ready() { - this.$.pageSelector.addEventListener ('click', () => { - this.selectPage_(); - }); - - this.$.search_page.addEventListener ('keydown', (e) => { - if (e.key === 'Enter') this.searchByPage_(); - }); - - this.$.search_button.addEventListener ('click', () => { - this.searchByPage_(); - }); - }, - - - build(chartData) { - this.data_ = chartData; - const aggregateChart = this.createChart_('Aggregate Data by Run'); - Polymer.dom(this.$.aggregateContainer).appendChild(aggregateChart); - aggregateChart.enableToolTip = true; - aggregateChart.toolTipCallBack = (rect) => - this.openBenchmarkChart_(rect); - this.setChartColors_(aggregateChart, this.data_.get(tr.v.ui.AGGREGATE_KEY)); - aggregateChart.data = this.data_.get(tr.v.ui.AGGREGATE_KEY); - this.setChartSize_(aggregateChart, - this.data_.get(tr.v.ui.AGGREGATE_KEY).length); - - for (const page of this.data_.keys()) { - if (page === tr.v.ui.AGGREGATE_KEY) continue; - const option = document.createElement('option'); - option.textContent = page; - option.value = page; - this.$.pageSelector.appendChild(option); - } - }, - - setChartSize_(chart, pageCount, dataLength) { - chart.graphHeight = tr.b.math.clamp(pageCount * 25, 175, 1000); - chart.graphWidth = tr.b.math.clamp(pageCount * 25, 500, 1000); - }, - - setChartColors_(chart, data) { - const metrics = new Map(); - let count = 0; - for (const thread of tr.v.ui.FRAME.values()) { - for (const metric of thread.keys()) { - metrics.set(metric, count); - count++; - } - } - for (let i = 0; i < Math.floor(data.length / tr.v.ui.FRAME.length); ++i) { - let j = 0; - for (const [threadName, thread] of tr.v.ui.FRAME.entries()) { - for (const metric of thread.keys()) { - let color = 'transparent'; - if (thread.get(metric)) { - const mainColorIndex = metrics.get(metric) % tr.v.ui.COLORS.length; - const subColorIndex = i % tr.v.ui.COLORS[mainColorIndex].length; - color = tr.v.ui.COLORS[mainColorIndex][subColorIndex]; - } - const series = metric + '-' + data[i * 2 + j].x + '-' + threadName; - chart.getDataSeries(series).color = color; - chart.getDataSeries(series).title = !i ? metric : ''; - } - j++; - } - } - }, - - createChart_(title) { - const newChart = new tr.ui.b.NameBarChart(); - newChart.chartTitle = title; - newChart.xAxisLabel = 'ms'; - newChart.hideLegend = false; - newChart.showTitleInLegend = true; - newChart.hideYAxis = true; - newChart.isStacked = true; - newChart.displayXInHover = true; - newChart.isGrouped = true; - return newChart; - }, - - openBenchmarkChart_(rect) { - // Find main metric and corresponding sub-metrics - const benchmarkIndex = Math.floor(rect.index / tr.v.ui.FRAME.length); - const title = rect.datum.x; - - // Create child chart with breakdown data - const div = document.createElement('div'); - Polymer.dom(this.$.pageContainer). - insertBefore(div, this.$.pageContainer.firstChild); - - const chart = this.createChart_(title); - - div.appendChild(chart); - const button = this.initializeCloseButton_(div, this.$.pageContainer); - div.appendChild(button); - - const newDataSet = []; - - for (const page of this.data_.keys()) { - if (page === tr.v.ui.AGGREGATE_KEY) continue; - for (let i = 0; i < tr.v.ui.FRAME.length; i++) { - newDataSet.push(this.data_ - .get(page)[benchmarkIndex * tr.v.ui.FRAME.length + i]); - } - } - - this.setChartColors_(chart, newDataSet); - chart.data = newDataSet; - this.setChartSize_(chart, newDataSet.length); - }, - - selectPage_() { - // Create child chart with breakdown data - const div = document.createElement('div'); - const page = this.$.pageSelector.value; - if (page === '') return; - Polymer.dom(this.$.pageContainer). - insertBefore(div, this.$.pageContainer.firstChild); - - const pageChart = this.createChart_(page); - - div.appendChild(pageChart); - const button = this.initializeCloseButton_(div, this.$.pageContainer); - div.appendChild(button); - - const pageData = this.data_.get(page); - - this.setChartColors_(pageChart, pageData); - pageChart.data = pageData; - this.setChartSize_(pageChart, pageData.length); - }, - - searchByPage_() { - const criteria = this.$.search_page.value; - if (criteria === '') return; - - const query = new RegExp(criteria); - - const filteredData = [...this.data_.keys()] - .filter(page => page.match(query)); - - if (filteredData.length < 1) { - this.$.search_error.style.display = 'block'; - return; - } - - // Create child chart with breakdown data - const page = filteredData[0]; - - const div = document.createElement('div'); - Polymer.dom(this.$.pageContainer). - insertBefore(div, this.$.pageContainer.firstChild); - - const pageChart = this.createChart_(page); - - div.appendChild(pageChart); - const button = this.initializeCloseButton_(div, this.$.pageContainer); - div.appendChild(button); - - const pageData = this.data_.get(page); - - this.setChartColors_(pageChart, pageData); - pageChart.data = pageData; - this.setChartSize_(pageChart, pageData.length); - }, - - initializeCloseButton_(div, parent) { - const button = this.$.close.cloneNode(true); - button.style.display = 'inline-block'; - button.addEventListener('click', () => { - Polymer.dom(parent).removeChild(div); - }); - return button; - }, -}); -</script> diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/raster_visualization_test.html b/chromium/third_party/catapult/tracing/tracing/value/ui/raster_visualization_test.html deleted file mode 100644 index eaf3ee61842..00000000000 --- a/chromium/third_party/catapult/tracing/tracing/value/ui/raster_visualization_test.html +++ /dev/null @@ -1,57 +0,0 @@ -<!DOCTYPE html> -<!-- -Copyright (c) 2018 The Chromium Authors. All rights reserved. -Use of this source code is governed by a BSD-style license that can be -found in the LICENSE file. ---> - -<link rel="import" href="/tracing/value/ui/raster_visualization.html"> -<link rel="import" href="/tracing/value/ui/visualizations_data_container.html"> - -<script> -'use strict'; - -tr.b.unittest.testSuite(function() { - function generateBars(page, benchmark) { - const benchmarkData = []; - for (const [threadName, thread] of tr.v.ui.FRAME.entries()) { - const data = {x: benchmark, hide: 0}; - if (page !== tr.v.ui.AGGREGATE_KEY) data.group = page; - for (const metric of thread.keys()) { - const key = metric + '-' + data.x + '-' + threadName; - const mean = Math.random() * 100; - data[key] = Math.round(mean * 100) / 100; - } - benchmarkData.push(data); - } - return benchmarkData; - } - - test('instantiate', function() { - const rv = document.createElement('tr-v-ui-raster-visualization'); - this.addHTMLOutput(rv); - - const allChartData = new Map(); - - // generate aggregate data - let aggregateData = []; - for (let i = 1; i <= 5; i++) { - aggregateData = aggregateData.concat(generateBars(tr.v.ui.AGGREGATE_KEY, - 'Run ' + i)); - } - allChartData.set(tr.v.ui.AGGREGATE_KEY, aggregateData); - - // generate data per page - for (let i = 1; i <= 5; i++) { - const page = 'Page ' + i; - let chartData = []; - for (let j = 1; j <= 5; j++) { - chartData = chartData.concat(generateBars(page, 'Run ' + j)); - } - allChartData.set(page, chartData); - } - - rv.build(allChartData); - }); -}); -</script>
\ No newline at end of file diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/visualizations_data_container.html b/chromium/third_party/catapult/tracing/tracing/value/ui/visualizations_data_container.html deleted file mode 100644 index 0adeaf55e3c..00000000000 --- a/chromium/third_party/catapult/tracing/tracing/value/ui/visualizations_data_container.html +++ /dev/null @@ -1,410 +0,0 @@ -<!DOCTYPE html> -<!-- -Copyright (c) 2018 The Chromium Authors. All rights reserved. -Use of this source code is governed by a BSD-style license that can be -found in the LICENSE file. ---> -<link rel="import" href="/tracing/value/ui/metrics_visualization.html"> -<link rel="import" href="/tracing/value/ui/raster_visualization.html"> -<meta charset="utf-8"> -<dom-module id='tr-v-ui-visualizations-data-container'> - <template> - <style> - .error { - color: red; - display: none; - } - - .sample{ - display: none; - } - - .subtitle{ - font-size: 20px; - font-weight: bold; - padding-bottom: 5px; - } - - .description{ - font-size: 15px; - padding-bottom: 5px; - } - - #title { - font-size: 30px; - font-weight: bold; - padding-bottom: 5px; - } - </style> - <div id="title">Visualizations</div> - <div id="data_error" class="error">Invalid data provided.</div> - <div id="pipeline_per_frame_container"> - <div class="subtitle">Graphics Pipeline and Raster Tasks</div> - <div class="description"> - When raster tasks are completed in comparison to the rest of the graphics pipeline.<br> - Only pages where raster tasks are completed after beginFrame is issued are included. - </div> - <tr-v-ui-raster-visualization id="rasterVisualization"> - </tr-v-ui-raster-visualization> - </div> - <div id=metrics_container> - <div class="subtitle">Metrics</div> - <div class="description">Total amount of time taken for the indicated metrics.</div> - <tr-v-ui-metrics-visualization id="metricsVisualization" class="sample"> - </tr-v-ui-metrics-visualization> - </div> - </template> -</dom-module> -<script> -'use strict'; - -tr.exportTo('tr.v.ui', function() { - const STATISTICS_KEY = 'statistics'; - const SUBMETRICS_KEY = 'submetrics'; - const AGGREGATE_KEY = 'aggregate'; - const RASTER_START_METRIC_KEY = 'pipeline:begin_frame_to_raster_start'; - - const COLORS = [ - ['#FFD740', '#FFC400', '#FFAB00', '#E29800'], - ['#FF6E40', '#FF3D00', '#DD2C00', '#A32000'], - ['#40C4FF', '#00B0FF', '#0091EA', '#006DAF'], - ['#89C641', '#54B503', '#4AA510', '#377A0D'], - ['#B388FF', '#7C4DFF', '#651FFF', '#6200EA'], - ['#FF80AB', '#FF4081', '#F50057', '#C51162'], - ['#FFAB40', '#FF9100', '#FF6D00', '#D65C02'], - ['#8C9EFF', '#536DFE', '#3D5AFE', '#304FFE']]; - - const FRAME = [new Map([ - ['pipeline:begin_frame_to_raster_start', false], - ['pipeline:begin_frame_to_raster_end', true]]), new Map([ - ['pipeline:begin_frame_transport', true], - ['pipeline:begin_frame_to_frame_submission', true], - ['pipeline:frame_submission_to_display', true], - ['pipeline:draw', true]])]; - - const METRICS = new Map([ - ['Pipeline', [ - 'pipeline:begin_frame_transport', - 'pipeline:begin_frame_to_frame_submission', - 'pipeline:frame_submission_to_display', - 'pipeline:draw']], - ['Thread', [ - 'thread_browser_cpu_time_per_frame', - 'thread_display_compositor_cpu_time_per_frame', - 'thread_GPU_cpu_time_per_frame', - 'thread_IO_cpu_time_per_frame', - 'thread_other_cpu_time_per_frame', - 'thread_raster_cpu_time_per_frame', - 'thread_renderer_compositor_cpu_time_per_frame', - 'thread_renderer_main_cpu_time_per_frame']]]); - - function getValueFromMap(key, map) { - let retrievedValue = map.get(key); - if (!retrievedValue) { - retrievedValue = new Map(); - map.set(key, retrievedValue); - } - return retrievedValue; - } - - Polymer({ - is: 'tr-v-ui-visualizations-data-container', - - created() { - // from earliest to latest - this.orderedBenchmarks_ = []; - // aggregate/page -> benchmark -> metric -> statistics/submetrics - this.groupedData_ = new Map(); - }, - - build(leafHistograms, histograms) { - if (!leafHistograms || leafHistograms.length < 1 || - !histograms || histograms.length < 1) { - this.$.data_error.style.display = 'block'; - return; - } - - this.processHistograms_(this.groupHistograms_(histograms), - this.groupHistograms_(leafHistograms)); - this.buildCharts_(); - }, - - processHistograms_(histograms, leafHistograms) { - const benchmarkStartGrouping = tr.v.HistogramGrouping.BY_KEY.get( - tr.v.d.RESERVED_NAMES.BENCHMARK_START); - - const benchmarkToStartTime = new Map(); - for (const [metric, benchmarks] of histograms.entries()) { - // process aggregate data - for (const [benchmark, pages] of leafHistograms.get(metric).entries()) { - for (const [page, histograms] of pages.entries()) { - for (const histogram of histograms) { - const aggregateToBenchmarkMap = getValueFromMap(AGGREGATE_KEY, - this.groupedData_); - const benchmarkToMetricMap = getValueFromMap(benchmark, - aggregateToBenchmarkMap); - - benchmarkToMetricMap.set(metric, new Map([ - [STATISTICS_KEY, histogram.running]])); - } - } - } - - // process data per page - for (const [benchmark, pages] of benchmarks.entries()) { - for (const [page, histograms] of pages.entries()) { - for (const histogram of histograms) { - if (!benchmarkToStartTime.get(benchmark)) { - benchmarkToStartTime.set(benchmark, - benchmarkStartGrouping.callback(histogram)); - } - - const pageToBenchmarkMap = getValueFromMap(page, - this.groupedData_); - const benchmarkToMetricMap = getValueFromMap(benchmark, - pageToBenchmarkMap); - - // retrieving submetric _ta - const mergedSubmetrics = new tr.v.d.DiagnosticMap(); - for (const bin of histogram.allBins) { - for (const map of bin.diagnosticMaps) { - mergedSubmetrics.addDiagnostics(map); - } - } - - if (benchmarkToMetricMap.get(metric)) continue; - benchmarkToMetricMap.set(metric, new Map([ - [STATISTICS_KEY, histogram.running], - [SUBMETRICS_KEY, mergedSubmetrics.get('breakdown')]])); - } - } - } - } - this.orderedBenchmarks_ = this.sortBenchmarks_(benchmarkToStartTime); - }, - - groupHistograms_(histograms) { - const groupings = [ - tr.v.HistogramGrouping.HISTOGRAM_NAME, - tr.v.HistogramGrouping.DISPLAY_LABEL, - tr.v.HistogramGrouping.BY_KEY.get(tr.v.d.RESERVED_NAMES.STORIES)]; - - return histograms.groupHistogramsRecursively(groupings); - }, - - sortBenchmarks_(benchmarks) { - return Array.from(benchmarks.keys()).sort((a, b) => { - Date.parse(benchmarks.get(a)) - Date.parse(benchmarks.get(b)); - }); - }, - - getSeriesKey_(metric, benchmark) { - return metric + '-' + benchmark; - }, - - buildCharts_() { - const rasterDataToBePassed = this.buildRasterChart_(); - this.$.rasterVisualization.build(rasterDataToBePassed); - - for (const chartName of METRICS.keys()) { - const metricsDataToBePassed = this.buildMetricsData_(chartName); - const newChart = this.$.metricsVisualization.cloneNode(true); - newChart.style.display = 'block'; - Polymer.dom(this.$.metrics_container).appendChild(newChart); - newChart.build(metricsDataToBePassed); - } - }, - - buildRasterChart_() { - const orderedPages = [...this.groupedData_.keys()] - .filter((page) => this.filterPagesWithoutRasterMetric_(page)) - .sort((a, b) => this.sortByRasterStart_(a, b)); - const allChartData = new Map(); - for (const page of orderedPages) { - const pageMap = this.groupedData_.get(page); - let chartData = []; - for (const benchmark of this.orderedBenchmarks_) { - if (!pageMap.has(benchmark)) continue; - const benchmarkMap = pageMap.get(benchmark); - const benchmarkData = []; - if (benchmarkMap.get(RASTER_START_METRIC_KEY) === undefined) { - continue; - } - for (const [threadName, thread] of FRAME.entries()) { - const data = {x: benchmark, hide: 0}; - if (page !== AGGREGATE_KEY) data.group = page; - let rasterBegin = 0; - for (const metric of thread.keys()) { - const metricMap = benchmarkMap.get(metric); - const key = this.getSeriesKey_(metric, - data.x + '-' + threadName); - const stats = metricMap.get(STATISTICS_KEY); - const mean = stats ? stats.mean : 0; - let roundedMean = Math.round(mean * 100) / 100; - if (metric === RASTER_START_METRIC_KEY) { - rasterBegin = roundedMean; - } else if (metric === 'pipeline:begin_frame_to_raster_end') { - roundedMean -= rasterBegin; - } - data[key] = roundedMean; - } - benchmarkData.push(data); - } - chartData = chartData.concat(benchmarkData); - } - allChartData.set(page, chartData); - } - return allChartData; - }, - - buildMetricsData_(chartName) { - // pages are ordered from smallest to largest by their total - // values for the first benchmark - const orderedPages = [...this.groupedData_.keys()].sort((a, b) => - this.sortByTotal_(a, b, chartName)); - const chartData = []; - const aggregateChart = []; - for (const page of orderedPages) { - const pageMap = this.groupedData_.get(page); - for (const benchmark of this.orderedBenchmarks_) { - if (!pageMap.has(benchmark)) continue; - const data = {x: benchmark, group: page}; - const benchmarkMap = pageMap.get(benchmark); - for (const metric of METRICS.get(chartName)) { - const metricMap = benchmarkMap.get(metric); - const key = this.getSeriesKey_(metric, benchmark); - const stats = metricMap.get(STATISTICS_KEY); - const mean = stats ? stats.mean : 0; - data[key] = Math.round(mean * 100) / 100; - } - if (page === AGGREGATE_KEY) { - aggregateChart.push(data); - } else { - chartData.push(data); - } - } - chartData.push({}); - } - chartData.shift(); - return { - title: chartName, - aggregate: aggregateChart, - page: chartData, - submetrics: this.processSubmetricsData_(chartName) - }; - }, - - submetricsHelper_(submetric, value, benchmark, metricToSubmetricMap) { - let submetricToBenchmarkMap = metricToSubmetricMap.get(submetric); - if (!submetricToBenchmarkMap) { - submetricToBenchmarkMap = []; - metricToSubmetricMap.set(submetric, submetricToBenchmarkMap); - } - const data = {x: submetric, hide: 0, group: benchmark}; - const mean = value; - const roundedMean = Math.round(mean * 100) / 100; - if (!roundedMean) return; - data[this.getSeriesKey_(submetric, benchmark)] = roundedMean; - submetricToBenchmarkMap.push(data); - }, - - // Get data for breakdown of a main step - processSubmetricsData_(chartName) { - // page -> metric -> submetric -> - // array of submetrics across all benchmarks - const submetrics = new Map(); - for (const [page, pageMap] of this.groupedData_.entries()) { - if (page === AGGREGATE_KEY) continue; - const pageToMetricMap = getValueFromMap(page, submetrics); - for (const benchmark of this.orderedBenchmarks_) { - const benchmarkMap = pageMap.get(benchmark); - if (!benchmarkMap) continue; - for (const metric of METRICS.get(chartName)) { - const metricMap = benchmarkMap.get(metric); - const metricToSubmetricMap = getValueFromMap(metric, - pageToMetricMap); - const submetrics = metricMap.get(SUBMETRICS_KEY); - if (!submetrics) { - this.submetricsHelper_(metric, metricMap.get(STATISTICS_KEY), - benchmark, metricToSubmetricMap); - continue; - } - for (const [submetric, value] of [...submetrics]) { - this.submetricsHelper_(submetric, value, benchmark, - metricToSubmetricMap); - } - } - } - } - return submetrics; - }, - - sortByTotal_(a, b, chartName) { - if (a === AGGREGATE_KEY) return -1; - if (b === AGGREGATE_KEY) return 1; - let aValue = 0; - const aMap = this.groupedData_.get(a); - if (aMap.get(this.orderedBenchmarks_[0]) !== undefined) { - for (const metric of METRICS.get(chartName)) { - const aMetricMap = aMap.get(this.orderedBenchmarks_[0]).get(metric); - const aStats = aMetricMap.get(STATISTICS_KEY); - aValue += aStats ? aStats.mean : 0; - } - } - let bValue = 0; - const bMap = this.groupedData_.get(b); - if (bMap.get(this.orderedBenchmarks_[0]) !== undefined) { - for (const metric of METRICS.get(chartName)) { - const bMetricMap = bMap.get(this.orderedBenchmarks_[0]).get(metric); - const bStats = bMetricMap.get(STATISTICS_KEY); - bValue += bStats ? bStats.mean : 0; - } - } - return aValue - bValue; - }, - - filterPagesWithoutRasterMetric_(page) { - const pageMap = this.groupedData_.get(page); - for (const benchmark of this.orderedBenchmarks_) { - const pageMetricMap = pageMap.get(benchmark); - if (!pageMetricMap) continue; - const wantedMetric = pageMetricMap.get(RASTER_START_METRIC_KEY); - if (wantedMetric !== undefined) return true; - } - return false; - }, - - sortByRasterStart_(a, b) { - if (a === AGGREGATE_KEY) return 1; - if (b === AGGREGATE_KEY) return -1; - let aValue = 0; - const aMap = this.groupedData_.get(a); - if (aMap.get(this.orderedBenchmarks_[0]) !== undefined) { - const aMetricMap = aMap.get(this.orderedBenchmarks_[0]) - .get(RASTER_START_METRIC_KEY); - const aStats = aMetricMap.get(STATISTICS_KEY); - aValue = aStats ? aStats.mean : 0; - } - let bValue = 0; - const bMap = this.groupedData_.get(b); - if (bMap.get(this.orderedBenchmarks_[0]) !== undefined) { - const bMetricMap = bMap.get(this.orderedBenchmarks_[0]) - .get(RASTER_START_METRIC_KEY); - const bStats = bMetricMap.get(STATISTICS_KEY); - bValue = bStats ? bStats.mean : 0; - } - return bValue - aValue; - }, - }); - - return { - STATISTICS_KEY, - SUBMETRICS_KEY, - AGGREGATE_KEY, - COLORS, - FRAME, - METRICS, - getValueFromMap, - }; -}); -</script> diff --git a/chromium/third_party/catapult/tracing/tracing/value/ui/visualizations_data_container_test.html b/chromium/third_party/catapult/tracing/tracing/value/ui/visualizations_data_container_test.html deleted file mode 100644 index 1199d8ed731..00000000000 --- a/chromium/third_party/catapult/tracing/tracing/value/ui/visualizations_data_container_test.html +++ /dev/null @@ -1,124 +0,0 @@ -<!DOCTYPE html> -<!-- -Copyright (c) 2018 The Chromium Authors. All rights reserved. -Use of this source code is governed by a BSD-style license that can be -found in the LICENSE file. ---> - -<link rel="import" href="/tracing/value/histogram.html"> -<link rel="import" href="/tracing/value/histogram_set.html"> -<link rel="import" href="/tracing/value/ui/visualizations_data_container.html"> - -<script> -'use strict'; - -tr.b.unittest.testSuite(function() { - function getHistogram(name) { - const samples = []; - for (let i = 0; i < 5; ++i) { - const total = Math.random(); - const values = {}; - values[name + 'a'] = total / 2.0; - values[name + 'b'] = total / 4.0; - values[name + 'c'] = total / 4.0; - samples.push({ - value: total, - diagnostics: new Map([ - [ - tr.v.d.RESERVED_NAMES.BENCHMARK_START, - new tr.v.d.DateRange(Date.now()), - ], [ - 'breakdown', tr.v.d.Breakdown.fromDict({values}), - ], - ]), - }); - } - return tr.v.Histogram.create(name, tr.b.Unit.byName.count, samples); - } - - function getHistogramSet(displayLabel, story, containsRasterStart = true) { - const histograms = new tr.v.HistogramSet(); - let metrics = []; - for (const category of tr.v.ui.METRICS.values()) { - metrics = metrics.concat(category); - } - for (const metric of metrics) { - histograms.addHistogram(getHistogram(metric)); - } - - if (containsRasterStart) { - histograms.addHistogram( - getHistogram('pipeline:begin_frame_to_raster_start')); - histograms.addHistogram( - getHistogram('pipeline:begin_frame_to_raster_end')); - } - histograms.addSharedDiagnosticToAllHistograms( - tr.v.d.RESERVED_NAMES.LABELS, new tr.v.d.GenericSet([displayLabel])); - histograms.addSharedDiagnosticToAllHistograms( - tr.v.d.RESERVED_NAMES.STORIES, new tr.v.d.GenericSet([story])); - return histograms; - } - - test('instantiate', function() { - const cp = document.createElement('tr-v-ui-visualizations-data-container'); - this.addHTMLOutput(cp); - - const histograms = getHistogramSet('Run 1', 'test.com'); - - const histograms2 = getHistogramSet('Run 2', 'test.com'); - histograms.importDicts(histograms2.asDicts()); - - const histograms3 = getHistogramSet('Run 1', 'abc.com'); - histograms.importDicts(histograms3.asDicts()); - - const histograms4 = getHistogramSet('Run 2', 'abc.com'); - histograms.importDicts(histograms4.asDicts()); - - cp.build(histograms, histograms); - }); - - test('instantiateWithRepeat', function() { - const cp = document.createElement('tr-v-ui-visualizations-data-container'); - this.addHTMLOutput(cp); - - const histograms = getHistogramSet('Run 1', 'repeat.com'); - const histograms2 = getHistogramSet('Run 1', 'repeat.com'); - histograms.importDicts(histograms2.asDicts()); - - cp.build(histograms, histograms); - }); - - test('instantiateWithoutRasterTasks', function() { - const cp = document.createElement('tr-v-ui-visualizations-data-container'); - this.addHTMLOutput(cp); - - const histograms = getHistogramSet('Run 1', 'test.com', false); - - const histograms2 = getHistogramSet('Run 2', 'test.com', false); - histograms.importDicts(histograms2.asDicts()); - - const histograms3 = getHistogramSet('Run 1', 'abc.com'); - histograms.importDicts(histograms3.asDicts()); - - const histograms4 = getHistogramSet('Run 2', 'abc.com'); - histograms.importDicts(histograms4.asDicts()); - - cp.build(histograms, histograms); - }); - - test('instantiateWithDifferentStorySets', function() { - const cp = document.createElement('tr-v-ui-visualizations-data-container'); - this.addHTMLOutput(cp); - - const histograms = getHistogramSet('Run 1', 'test.com'); - - const histograms2 = getHistogramSet('Run 1', 'abc.com'); - histograms.importDicts(histograms2.asDicts()); - - const histograms3 = getHistogramSet('Run 2', 'abc.com'); - histograms.importDicts(histograms3.asDicts()); - - cp.build(histograms, histograms); - }); -}); -</script> |