Index: tracing/tracing/metrics/blink/leak_detection_metric.html |
diff --git a/tracing/tracing/metrics/blink/leak_detection_metric.html b/tracing/tracing/metrics/blink/leak_detection_metric.html |
new file mode 100644 |
index 0000000000000000000000000000000000000000..0a2974b326d5ac36521a42554b15e62dd6288403 |
--- /dev/null |
+++ b/tracing/tracing/metrics/blink/leak_detection_metric.html |
@@ -0,0 +1,151 @@ |
+<!DOCTYPE html> |
+<!-- |
+Copyright 2017 The Chromium Authors. All rights reserved. |
+Use of this source code is governed by a BSD-style license that can be |
+found in the LICENSE file. |
+--> |
+ |
+<link rel="import" href="/tracing/base/unit.html"> |
+<link rel="import" href="/tracing/metrics/metric_registry.html"> |
+<link rel="import" href="/tracing/value/histogram.html"> |
+ |
+<script> |
+'use strict'; |
+ |
+tr.exportTo('tr.metrics.blink', function() { |
+ function leakDetectionMetric(histograms, model) { |
+ const pids = extractRendererPids(model); |
+ if (pids.length === 0) { |
+ // We couldn't find any renderer processes. |
+ return; |
+ } |
+ |
+ const chromeDumps = splitGlobalDumpsByBrowserName(model).get('chrome'); |
+ |
+ let sumCounter = {}; |
+ // Add up counters for all the renderer processes. |
+ pids.forEach(function(pid) { |
+ if (Object.keys(sumCounter).length === 0) { |
+ sumCounter = countLeakedBlinkObjects(chromeDumps, pid); |
+ } else { |
+ const counterForAnotherRenderer = |
+ countLeakedBlinkObjects(chromeDumps, pid); |
+ for (const key in counters) { |
+ sumCounter[key] += counterForAnotherRenderer[key]; |
+ } |
+ } |
+ }); |
+ |
+ for (const key in sumCounter) { |
+ const histogram = createNumericForBlinkObjectCounts(key); |
+ histogram.addSample(sumCounter[key]); |
keishi
2017/09/11 07:34:16
I think we should skip adding a sample if chromeDu
yuzuchan
2017/09/13 04:48:57
Added an error logic here. Thanks.
|
+ histograms.addHistogram(histogram); |
+ } |
+ } |
+ |
+ tr.metrics.MetricRegistry.register(leakDetectionMetric); |
+ |
+ const timeDurationInMs_smallerIsBetter = |
keishi
2017/09/11 07:34:16
unused?
yuzuchan
2017/09/13 04:48:57
True! Done.
|
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter; |
+ |
+ function extractRendererPids(model) { |
+ const modelHelper = model.getOrCreateHelper( |
+ tr.model.helpers.ChromeModelHelper); |
+ if (!modelHelper) { |
+ // Chrome isn't present. |
+ return; |
+ } |
+ const rendererHelpers = modelHelper.rendererHelpers; |
+ if (!rendererHelpers) { |
+ // We couldn't find any renderer processes. |
+ return; |
+ } |
+ return Object.keys(rendererHelpers); |
+ } |
+ |
+ const count_smallerIsBetter = tr.b.Unit.byName.count_smallerIsBetter; |
+ |
+ function createNumericForBlinkObjectCounts(name) { |
keishi
2017/09/11 07:34:16
nit: Existing similar functions seem to use use si
yuzuchan
2017/09/13 04:48:57
Done.
|
+ const n = new tr.v.Histogram(name, count_smallerIsBetter); |
+ n.customizeSummaryOptions({ |
+ avg: false, |
+ count: true, |
+ max: false, |
+ min: false, |
+ std: false, |
+ sum: true, |
+ percentile: [] |
+ }); |
+ return n; |
+ } |
+ |
+ function splitGlobalDumpsByBrowserName(model) { |
keishi
2017/09/11 07:34:16
I think we shouldn't have duplicate code so maybe
yuzuchan
2017/09/13 04:48:57
Done.
|
+ const chromeModelHelper = |
+ model.getOrCreateHelper(tr.model.helpers.ChromeModelHelper); |
+ const browserNameToGlobalDumps = new Map(); |
+ const globalDumpToBrowserHelper = new WeakMap(); |
+ |
+ if (chromeModelHelper) { |
+ chromeModelHelper.browserHelpers.forEach(function(helper) { |
+ const globalDumps = |
+ helper.process.memoryDumps.map(d => d.globalMemoryDump); |
+ |
+ globalDumps.forEach(function(globalDump) { |
+ const existingHelper = globalDumpToBrowserHelper.get(globalDump); |
+ if (existingHelper !== undefined) { |
+ throw new Error('Memory dump ID clash across multiple browsers ' + |
+ 'with PIDs: ' + existingHelper.pid + ' and ' + helper.pid); |
+ } |
+ globalDumpToBrowserHelper.set(globalDump, helper); |
+ }); |
+ |
+ makeKeyUniqueAndSet(browserNameToGlobalDumps, |
+ tr.e.chrome.chrome_processes.canonicalizeName(helper.browserName), |
+ globalDumps); |
+ }); |
+ } |
+ return browserNameToGlobalDumps; |
+ } |
+ |
+ function makeKeyUniqueAndSet(map, key, value) { |
+ let uniqueKey = key; |
+ let nextIndex = 2; |
+ while (map.has(uniqueKey)) { |
+ uniqueKey = key + nextIndex; |
+ nextIndex++; |
+ } |
+ map.set(uniqueKey, value); |
+ } |
+ |
+ function countLeakedBlinkObjects(dumps, pid) { |
+ const firstCounter = countBlinkObjects(dumps[0], pid); |
+ const lastCounter = countBlinkObjects(dumps[dumps.length - 1], pid); |
+ const diffCounter = {}; |
+ for (const key in lastCounter) { |
+ diffCounter[key] = lastCounter[key] - firstCounter[key]; |
+ } |
+ return diffCounter; |
+ } |
+ |
+ function countBlinkObjects(dump, pid) { |
+ const counter = {}; |
+ const processesMemoryDumps = dump.processMemoryDumps; |
+ if (pid in processesMemoryDumps) { |
+ const blinkObjectsDump = processesMemoryDumps[pid].memoryAllocatorDumps |
+ .find(isBlinkObjects); |
+ blinkObjectsDump.children.forEach(function(v) { |
+ counter[v.name] = v.numerics.object_count.value; |
+ }); |
+ } |
+ return counter; |
+ } |
+ |
+ function isBlinkObjects(memoryDump) { |
+ return memoryDump.fullName === 'blink_objects'; |
+ } |
+ |
+ return { |
+ leakDetectionMetric, |
+ }; |
+}); |
+</script> |