diff options
Diffstat (limited to 'chromium/third_party/catapult/tracing/tracing/metrics/partition_alloc')
3 files changed, 335 insertions, 0 deletions
diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/partition_alloc/OWNERS b/chromium/third_party/catapult/tracing/tracing/metrics/partition_alloc/OWNERS new file mode 100644 index 00000000000..228f0c3184b --- /dev/null +++ b/chromium/third_party/catapult/tracing/tracing/metrics/partition_alloc/OWNERS @@ -0,0 +1,2 @@ +bikineev@chromium.org +mlippautz@chromium.org diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/partition_alloc/pcscan_metric.html b/chromium/third_party/catapult/tracing/tracing/metrics/partition_alloc/pcscan_metric.html new file mode 100644 index 00000000000..33743f757a5 --- /dev/null +++ b/chromium/third_party/catapult/tracing/tracing/metrics/partition_alloc/pcscan_metric.html @@ -0,0 +1,195 @@ +<!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/math/range.html"> +<link rel="import" href="/tracing/base/unit.html"> +<link rel="import" href="/tracing/extras/chrome/chrome_processes.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'; + +/** + * @fileoverview This file contains implementations of PCScan metrics. PCScan + * is the algorithm that eliminates use-after-free bugs by verifying that there + * are no pointers in memory which point to explicitly freed objects before + * actually releasing their memory. + * + * pa:pcscan:<process_name>:<scanner|mutator> + * ======================== + * The overall time spent on scanning the partition alloc heap for a specific + * process either in the scanner or mutator thread (process_name can be either 'browser_process' or 'renderer_processes'). + * + * pa:pcscan:<process_name>:<scanner|mutator>:<phase> + * ======================== + * Time spent on a certain PCScan phase ('clear', 'scan' or 'sweep'). + */ +tr.exportTo('tr.metrics.pa', function() { + function pcscanMetric(histograms, model) { + function createTimeNumericForProcess(name, processName, context, desc) { + function createNumeric(name, desc) { + const n = new tr.v.Histogram(name, + tr.b.Unit.byName.timeDurationInMs_smallerIsBetter); + n.description = desc; + n.customizeSummaryOptions({ + avg: true, + count: true, + max: true, + min: true, + std: true, + sum: true}); + return n; + } + const scheme = ['pa', 'pcscan', processName, context]; + if (name) scheme.push(name); + return createNumeric(scheme.join(':'), desc); + } + + function createSizeNumericForProcess(name, processName, desc) { + function createNumeric(name, desc) { + const n = new tr.v.Histogram(name, + tr.b.Unit.byName.sizeInBytes_smallerIsBetter); + n.description = desc; + n.customizeSummaryOptions({ + avg: true, + count: true, + max: true, + min: true, + std: true, + sum: true}); + return n; + } + const scheme = ['pa', 'pcscan', processName, name]; + return createNumeric(scheme.join(':'), desc); + } + + function createPercentNumericForProcess(name, processName, desc) { + function createNumeric(name, desc) { + const n = new tr.v.Histogram(name, + tr.b.Unit.byName.normalizedPercentage_smallerIsBetter); + n.description = desc; + n.customizeSummaryOptions({ + avg: true, + count: true, + max: true, + min: true, + std: true, + sum: true}); + return n; + } + const scheme = ['pa', 'pcscan', processName, name]; + return createNumeric(scheme.join(':'), desc); + } + + + function createHistsForProcess(processName) { + return { + scanner_scan: createTimeNumericForProcess('scan', processName, 'scanner', + 'Time for scanning heap for quarantine pointers on concurrent threads'), + scanner_sweep: createTimeNumericForProcess('sweep', processName, 'scanner', + 'Time for sweeping quarantine'), + scanner_clear: createTimeNumericForProcess('clear', processName, 'scanner', + 'Time for clearing quarantine entries'), + scanner_total: createTimeNumericForProcess('', processName, 'scanner', + 'Total time for PCScan execution on concurrent threads'), + mutator_scan_stack: createTimeNumericForProcess('scan_stack', processName, 'mutator', + 'Time for scanning stack for quarantine pointers on mutator threads'), + mutator_scan: createTimeNumericForProcess('scan', processName, 'mutator', + 'Time for scanning heap for quarantine pointers on mutator threads'), + mutator_clear: createTimeNumericForProcess('clear', processName, 'mutator', + 'Time for clearing heap quarantine entries on mutator threads'), + mutator_total: createTimeNumericForProcess('', processName, 'mutator', + 'Total time for PCScan execution on mutator threads (inside safepoints)'), + survived_quarantine_size: createSizeNumericForProcess( + 'survived_quarantine_size', processName, + 'Size in bytes of survived quarantined objects after each *Scan cycle'), + survived_quarantine_percent: createPercentNumericForProcess( + 'survived_quarantine_percent', processName, + 'Percent of survived quarantined objects after a *Scan cycle relative ' + + 'to the size of quarantined objects before the cycle'), + }; + } + + function addSliceSample(hists, slice) { + if (slice.category !== 'partition_alloc') return; + if (!(slice instanceof tr.model.ThreadSlice)) return; + + if (slice.title === 'PCScan.Scanner.Scan') { + hists.scanner_scan.addSample(slice.duration); + } else if (slice.title === 'PCScan.Scanner.Sweep') { + hists.scanner_sweep.addSample(slice.duration); + } else if (slice.title === 'PCScan.Scanner.Clear') { + hists.scanner_clear.addSample(slice.duration); + } else if (slice.title === 'PCScan.Scanner') { + hists.scanner_total.addSample(slice.duration); + } else if (slice.title === 'PCScan.Mutator.ScanStack') { + hists.mutator_scan_stack.addSample(slice.duration); + } else if (slice.title === 'PCScan.Mutator.Scan') { + hists.mutator_scan.addSample(slice.duration); + } else if (slice.title === 'PCScan.Mutator.Clear') { + hists.mutator_clear.addSample(slice.duration); + } else if (slice.title === 'PCScan.Mutator') { + hists.mutator_total.addSample(slice.duration); + } + } + + function addCounterSample(hists, counter) { + if (counter.category !== 'partition_alloc') return; + if (!(counter instanceof tr.model.Counter)) return; + + for (const series of counter.series) { + for (const sample of series.samples) { + if (counter.name === 'PCScan.SurvivedQuarantineSize') { + hists.survived_quarantine_size.addSample(sample.value); + } else if (counter.name === 'PCScan.SurvivedQuarantinePercent') { + // Divide by 1000, since StatsCollector multiplies it by 1000. + hists.survived_quarantine_percent.addSample(sample.value / 1000); + } + } + } + } + + function addHistsForProcess(processHists, processHelpers) { + for (const helper of Object.values(processHelpers)) { + const processName = tr.e.chrome.chrome_processes. + canonicalizeProcessName(helper.process.name); + if (!processHists.has(processName)) { + processHists.set(processName, createHistsForProcess(processName)); + } + for (const slice of helper.process.getDescendantEvents()) { + addSliceSample(processHists.get(processName), slice); + } + for (const tid in helper.process.counters) { + addCounterSample(processHists.get(processName), helper.process.counters[tid]); + } + } + } + + const helper = + model.getOrCreateHelper(tr.model.helpers.ChromeModelHelper); + + const processHists = new Map(); + addHistsForProcess(processHists, helper.browserHelpers); + addHistsForProcess(processHists, helper.rendererHelpers); + + for (const hists of processHists.values()) { + for (const hist of Object.values(hists)) { + histograms.addHistogram(hist); + } + } + } + + tr.metrics.MetricRegistry.register(pcscanMetric); + + return { + pcscanMetric, + }; +}); + +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/metrics/partition_alloc/pcscan_metric_test.html b/chromium/third_party/catapult/tracing/tracing/metrics/partition_alloc/pcscan_metric_test.html new file mode 100644 index 00000000000..ca43e546b56 --- /dev/null +++ b/chromium/third_party/catapult/tracing/tracing/metrics/partition_alloc/pcscan_metric_test.html @@ -0,0 +1,138 @@ +<!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/core/test_utils.html"> +<link rel="import" href="/tracing/extras/chrome/chrome_processes.html"> +<link rel="import" href="/tracing/extras/chrome/chrome_test_utils.html"> +<link rel="import" href="/tracing/metrics/partition_alloc/pcscan_metric.html"> +<link rel="import" href="/tracing/value/histogram_set.html"> + +<script> +'use strict'; + +tr.b.unittest.testSuite(function() { + const CHROME_PROCESS_NAMES = + tr.e.chrome.chrome_processes.CHROME_PROCESS_NAMES; + + function makeTestModelFor(processName) { + return tr.e.chrome.ChromeTestUtils.newChromeModel(function(model) { + const process = (processName === CHROME_PROCESS_NAMES.RENDERER ? + model.rendererProcess : model.browserProcess); + const thread = process.getOrCreateThread(2); + // Create slices. + thread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({ + cat: 'partition_alloc', + title: 'PCScan.Scanner', + start: 200, + duration: 100, + cpuStart: 200, + cpuDuration: 100 + })); + thread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({ + cat: 'partition_alloc', + title: 'PCScan.Mutator', + start: 200, + duration: 50, + cpuStart: 200, + cpuDuration: 50 + })); + thread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({ + cat: 'partition_alloc', + title: 'PCScan.Scanner.Clear', + start: 200, + duration: 16, + cpuStart: 200, + cpuDuration: 16 + })); + thread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({ + cat: 'partition_alloc', + title: 'PCScan.Scanner.Scan', + start: 216, + duration: 32, + cpuStart: 216, + cpuDuration: 32 + })); + thread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({ + cat: 'partition_alloc', + title: 'PCScan.Mutator.Clear', + start: 210, + duration: 8, + cpuStart: 210, + cpuDuration: 8 + })); + thread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({ + cat: 'partition_alloc', + title: 'PCScan.Mutator.ScanStack', + start: 218, + duration: 14, + cpuStart: 218, + cpuDuration: 14 + })); + thread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({ + cat: 'partition_alloc', + title: 'PCScan.Mutator.Scan', + start: 232, + duration: 16, + cpuStart: 232, + cpuDuration: 16 + })); + thread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({ + cat: 'partition_alloc', + title: 'PCScan.Scanner.Sweep', + start: 248, + duration: 42, + cpuStart: 248, + cpuDuration: 42 + })); + // Create counters. + const quarantineSizeCounter = process.getOrCreateCounter('partition_alloc', 'PCScan.SurvivedQuarantineSize'); + const quarantineSizeSeries = new tr.model.CounterSeries('value', 0); + quarantineSizeSeries.addCounterSample(1, 200000); + quarantineSizeSeries.addCounterSample(3, 300000); + quarantineSizeCounter.addSeries(quarantineSizeSeries); + const quarantineRateCounter = process.getOrCreateCounter('partition_alloc', 'PCScan.SurvivedQuarantinePercent'); + const quarantineRateSeries = new tr.model.CounterSeries('value', 0); + quarantineRateSeries.addCounterSample(1, 0.14 * 1000); + quarantineRateSeries.addCounterSample(3, 0.21 * 1000); + quarantineRateCounter.addSeries(quarantineRateSeries); + }); + } + + function testPCScanMetrics(processName) { + const histograms = new tr.v.HistogramSet(); + tr.metrics.pa.pcscanMetric(histograms, makeTestModelFor(processName)); + assert.closeTo(100, histograms.getHistogramNamed( + 'pa:pcscan:' + processName + ':scanner').average, 1e-2); + assert.closeTo(50, histograms.getHistogramNamed( + 'pa:pcscan:' + processName + ':mutator').average, 1e-2); + assert.closeTo(16, histograms.getHistogramNamed( + 'pa:pcscan:' + processName + ':scanner:clear').average, 1e-2); + assert.closeTo(32, histograms.getHistogramNamed( + 'pa:pcscan:' + processName + ':scanner:scan').average, 1e-2); + assert.closeTo(8, histograms.getHistogramNamed( + 'pa:pcscan:' + processName + ':mutator:clear').average, 1e-2); + assert.closeTo(14, histograms.getHistogramNamed( + 'pa:pcscan:' + processName + ':mutator:scan_stack').average, 1e-2); + assert.closeTo(16, histograms.getHistogramNamed( + 'pa:pcscan:' + processName + ':mutator:scan').average, 1e-2); + assert.closeTo(42, histograms.getHistogramNamed( + 'pa:pcscan:' + processName + ':scanner:sweep').average, 1e-2); + assert.closeTo(250000, histograms.getHistogramNamed( + 'pa:pcscan:' + processName + ':survived_quarantine_size').average, 1e-2); + assert.closeTo(0.175, histograms.getHistogramNamed( + 'pa:pcscan:' + processName + ':survived_quarantine_percent').average, 1e-2); + } + + test('pcscanMetricForBrowser', function() { + testPCScanMetrics(CHROME_PROCESS_NAMES.BROWSER); + }); + + test('pcscanMetricForRenderer', function() { + testPCScanMetrics(CHROME_PROCESS_NAMES.RENDERER); + }); +}); +</script> |