summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/catapult/tracing/tracing/metrics/partition_alloc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/catapult/tracing/tracing/metrics/partition_alloc')
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/partition_alloc/OWNERS2
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/partition_alloc/pcscan_metric.html195
-rw-r--r--chromium/third_party/catapult/tracing/tracing/metrics/partition_alloc/pcscan_metric_test.html138
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>