Chromium Code Reviews| 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> |