blob: 40e6496bb8b73414a9ef9f3d255975fbf19d2ca0 [file] [log] [blame]
<!DOCTYPE html>
<!--
Copyright 2016 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/iteration_helpers.html">
<link rel="import" href="/tracing/metrics/metric_registry.html">
<link rel="import" href="/tracing/value/diagnostics/diagnostic_map.html">
<link rel="import" href="/tracing/value/histogram.html">
<script>
'use strict';
tr.exportTo('tr.metrics', function() {
var MEMORY_INFRA_TRACING_CATEGORY = 'disabled-by-default-memory-infra';
var TIME_BOUNDARIES = tr.v.HistogramBinBoundaries.createExponential(
1e-3, 1e5, 30);
var BYTE_BOUNDARIES = tr.v.HistogramBinBoundaries.createExponential(
1, 1e9, 30);
var COUNT_BOUNDARIES = tr.v.HistogramBinBoundaries.createExponential(
1, 1e5, 30);
function addTimeDurationValue(valueName, duration, allValues) {
var hist = new tr.v.Histogram(valueName,
tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, TIME_BOUNDARIES);
hist.addSample(duration);
allValues.addHistogram(hist);
}
// Adds values specific to memory-infra dumps.
function addMemoryInfraValues(values, model, categoryNamesToTotalEventSizes) {
var memoryDumpCount = model.globalMemoryDumps.length;
if (memoryDumpCount === 0)
return;
var totalOverhead = 0;
var nonMemoryInfraThreadOverhead = 0;
var overheadByProvider = {};
tr.b.iterItems(model.processes, function(pid, process) {
tr.b.iterItems(process.threads, function(tid, thread) {
tr.b.iterItems(thread.sliceGroup.slices, function(slice_id, slice) {
if (slice.category !== MEMORY_INFRA_TRACING_CATEGORY)
return;
totalOverhead += slice.duration;
if (thread.name !== 'MemoryInfra')
nonMemoryInfraThreadOverhead += slice.duration;
if (slice.args && slice.args['dump_provider.name']) {
var providerName = slice.args['dump_provider.name'];
var durationAndCount = overheadByProvider[providerName];
if (durationAndCount === undefined) {
overheadByProvider[providerName] = durationAndCount =
{duration: 0, count: 0};
}
durationAndCount.duration += slice.duration;
durationAndCount.count++;
}
});
});
});
addTimeDurationValue(
'Average CPU overhead on all threads per memory-infra dump',
totalOverhead / memoryDumpCount, values);
addTimeDurationValue(
'Average CPU overhead on non-memory-infra threads per memory-infra ' +
'dump',
nonMemoryInfraThreadOverhead / memoryDumpCount, values);
tr.b.iterItems(overheadByProvider, function(providerName, overhead) {
addTimeDurationValue(
'Average CPU overhead of ' + providerName + ' per OnMemoryDump call',
overhead.duration / overhead.count, values);
});
var memoryInfraEventsSize =
categoryNamesToTotalEventSizes.get(MEMORY_INFRA_TRACING_CATEGORY);
var memoryInfraTraceBytesValue = new tr.v.Histogram(
'Total trace size of memory-infra dumps in bytes',
tr.b.Unit.byName.sizeInBytes_smallerIsBetter, BYTE_BOUNDARIES);
memoryInfraTraceBytesValue.addSample(memoryInfraEventsSize);
values.addHistogram(memoryInfraTraceBytesValue);
var traceBytesPerDumpValue = new tr.v.Histogram(
'Average trace size of memory-infra dumps in bytes',
tr.b.Unit.byName.sizeInBytes_smallerIsBetter, BYTE_BOUNDARIES);
traceBytesPerDumpValue.addSample(memoryInfraEventsSize / memoryDumpCount);
values.addHistogram(traceBytesPerDumpValue);
}
function tracingMetric(values, model) {
if (!model.stats.hasEventSizesinBytes) {
throw new Error('Model stats does not have event size information. ' +
'Please enable ImportOptions.trackDetailedModelStats.');
}
var eventStats = model.stats.allTraceEventStatsInTimeIntervals;
eventStats.sort(function(a, b) {
return a.timeInterval - b.timeInterval;
});
var totalTraceBytes = eventStats.reduce((a, b) =>
(a + b.totalEventSizeinBytes), 0);
// We maintain a sliding window of records [start ... end-1] where end
// increments each time through the loop, and we move start just far enough
// to keep the window less than 1 second wide. Note that we need to compute
// the number of time intervals (i.e. units that timeInterval is given in)
// in one second to know how wide the sliding window should be.
var maxEventCountPerSec = 0;
var maxEventBytesPerSec = 0;
var INTERVALS_PER_SEC = Math.floor(
1000 / model.stats.TIME_INTERVAL_SIZE_IN_MS);
var runningEventNumPerSec = 0;
var runningEventBytesPerSec = 0;
var start = 0;
var end = 0;
while (end < eventStats.length) {
// Slide the end marker forward. Moving the end marker from N
// to N+1 adds eventStats[N] to the sliding window.
runningEventNumPerSec += eventStats[end].numEvents;
runningEventBytesPerSec += eventStats[end].totalEventSizeinBytes;
end++;
// Slide the start marker forward so that the time interval covered
// by the window is less than 1 second wide.
while ((eventStats[end - 1].timeInterval -
eventStats[start].timeInterval) >= INTERVALS_PER_SEC) {
runningEventNumPerSec -= eventStats[start].numEvents;
runningEventBytesPerSec -= eventStats[start].totalEventSizeinBytes;
start++;
}
// Update maximum values.
maxEventCountPerSec = Math.max(maxEventCountPerSec,
runningEventNumPerSec);
maxEventBytesPerSec = Math.max(maxEventBytesPerSec,
runningEventBytesPerSec);
}
var stats = model.stats.allTraceEventStats;
var categoryNamesToTotalEventSizes = (
stats.reduce((map, stat) => (
map.set(stat.category,
((map.get(stat.category) || 0) +
stat.totalEventSizeinBytes))), new Map()));
// Determine the category with the highest total event size.
var maxCatNameAndBytes = Array.from(
categoryNamesToTotalEventSizes.entries()).reduce(
(a, b) => (b[1] >= a[1]) ? b : a);
var maxEventBytesPerCategory = maxCatNameAndBytes[1];
var categoryWithMaxEventBytes = maxCatNameAndBytes[0];
var maxEventCountPerSecValue = new tr.v.Histogram(
'Max number of events per second',
tr.b.Unit.byName.count_smallerIsBetter, COUNT_BOUNDARIES);
maxEventCountPerSecValue.addSample(maxEventCountPerSec);
var maxEventBytesPerSecValue = new tr.v.Histogram(
'Max event size in bytes per second',
tr.b.Unit.byName.sizeInBytes_smallerIsBetter, BYTE_BOUNDARIES);
maxEventBytesPerSecValue.addSample(maxEventBytesPerSec);
var totalTraceBytesValue = new tr.v.Histogram('Total trace size in bytes',
tr.b.Unit.byName.sizeInBytes_smallerIsBetter, BYTE_BOUNDARIES);
totalTraceBytesValue.addSample(totalTraceBytes);
var biggestCategory = {
name: categoryWithMaxEventBytes,
size_in_bytes: maxEventBytesPerCategory
};
totalTraceBytesValue.diagnostics.set(
'category_with_max_event_size', new tr.v.d.Generic(biggestCategory));
values.addHistogram(totalTraceBytesValue);
maxEventCountPerSecValue.diagnostics.set(
'category_with_max_event_size', new tr.v.d.Generic(biggestCategory));
values.addHistogram(maxEventCountPerSecValue);
maxEventBytesPerSecValue.diagnostics.set(
'category_with_max_event_size', new tr.v.d.Generic(biggestCategory));
values.addHistogram(maxEventBytesPerSecValue);
addMemoryInfraValues(values, model, categoryNamesToTotalEventSizes);
}
tr.metrics.MetricRegistry.register(tracingMetric);
return {
tracingMetric: tracingMetric,
// For testing only:
MEMORY_INFRA_TRACING_CATEGORY: MEMORY_INFRA_TRACING_CATEGORY
};
});
</script>