blob: ee76d0ca5659f2e6d0bf6065a82c7b7bb806e052 [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/range.html">
<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/metrics/metric_registry.html">
<link rel="import" href="/tracing/metrics/v8/utils.html">
<link rel="import" href="/tracing/value/histogram.html">
<script>
'use strict';
tr.exportTo('tr.metrics.blink', function() {
// Maps the Blink GC events in timeline to telemetry friendly names.
var BLINK_GC_EVENTS = {
'BlinkGCMarking': 'blink-gc-marking',
'ThreadState::completeSweep': 'blink-gc-complete-sweep',
'ThreadState::performIdleLazySweep': 'blink-gc-idle-lazy-sweep'
};
function isBlinkGarbageCollectionEvent(event) {
return event.title in BLINK_GC_EVENTS;
}
function blinkGarbageCollectionEventName(event) {
return BLINK_GC_EVENTS[event.title];
}
function blinkGcMetric(values, model) {
addDurationOfTopEvents(values, model);
addTotalDurationOfTopEvents(values, model);
addIdleTimesOfTopEvents(values, model);
addTotalIdleTimesOfTopEvents(values, model);
}
tr.metrics.MetricRegistry.register(blinkGcMetric);
var timeDurationInMs_smallerIsBetter =
tr.b.Unit.byName.timeDurationInMs_smallerIsBetter;
var percentage_biggerIsBetter =
tr.b.Unit.byName.normalizedPercentage_biggerIsBetter;
// 0.1 steps from 0 to 20 since it is the most common range.
// Exponentially increasing steps from 20 to 200.
var CUSTOM_BOUNDARIES = tr.v.HistogramBinBoundaries.createLinear(0, 20, 200)
.addExponentialBins(200, 100);
function createNumericForTopEventTime(name) {
var n = new tr.v.Histogram(name,
timeDurationInMs_smallerIsBetter, CUSTOM_BOUNDARIES);
n.customizeSummaryOptions({
avg: true,
count: true,
max: true,
min: false,
std: true,
sum: true,
percentile: [0.90]});
return n;
}
function createNumericForIdleTime(name) {
var n = new tr.v.Histogram(name,
timeDurationInMs_smallerIsBetter, CUSTOM_BOUNDARIES);
n.customizeSummaryOptions({
avg: true,
count: false,
max: true,
min: false,
std: false,
sum: true,
percentile: []
});
return n;
}
function createPercentage(name, numerator, denominator) {
var histogram = new tr.v.Histogram(name, percentage_biggerIsBetter);
if (denominator === 0)
histogram.addSample(0);
else
histogram.addSample(numerator / denominator);
return histogram;
}
/**
* Example output:
* - blink-gc-marking.
*/
function addDurationOfTopEvents(values, model) {
tr.metrics.v8.utils.groupAndProcessEvents(model,
isBlinkGarbageCollectionEvent,
blinkGarbageCollectionEventName,
function(name, events) {
var cpuDuration = createNumericForTopEventTime(name);
events.forEach(function(event) {
cpuDuration.addSample(event.cpuDuration);
});
values.addHistogram(cpuDuration);
}
);
}
/**
* Example output:
* - blink-gc-total
*/
function addTotalDurationOfTopEvents(values, model) {
tr.metrics.v8.utils.groupAndProcessEvents(model,
isBlinkGarbageCollectionEvent,
event => 'blink-gc-total',
function(name, events) {
var cpuDuration = createNumericForTopEventTime(name);
events.forEach(function(event) {
cpuDuration.addSample(event.cpuDuration);
});
values.addHistogram(cpuDuration);
}
);
}
/**
* Example output:
* - blink-gc-marking_idle_deadline_overrun,
* - blink-gc-marking_outside_idle,
* - blink-gc-marking_percentage_idle.
*/
function addIdleTimesOfTopEvents(values, model) {
tr.metrics.v8.utils.groupAndProcessEvents(model,
isBlinkGarbageCollectionEvent,
blinkGarbageCollectionEventName,
function(name, events) {
addIdleTimes(values, model, name, events);
}
);
}
/**
* Example output:
* - blink-gc-total_idle_deadline_overrun,
* - blink-gc-total_outside_idle,
* - blink-gc-total_percentage_idle.
*/
function addTotalIdleTimesOfTopEvents(values, model) {
tr.metrics.v8.utils.groupAndProcessEvents(model,
isBlinkGarbageCollectionEvent,
event => 'blink-gc-total',
function(name, events) {
addIdleTimes(values, model, name, events);
}
);
}
function addIdleTimes(values, model, name, events) {
var cpuDuration = createNumericForIdleTime(name + '_cpu');
var insideIdle = createNumericForIdleTime(name + '_inside_idle');
var outsideIdle = createNumericForIdleTime(name + '_outside_idle');
var idleDeadlineOverrun = createNumericForIdleTime(
name + '_idle_deadline_overrun');
events.forEach(function(event) {
var idleTask = tr.metrics.v8.utils.findParent(
event, tr.metrics.v8.utils.isIdleTask);
var inside = 0;
var overrun = 0;
if (idleTask) {
var allottedTime = idleTask['args']['allotted_time_ms'];
if (event.duration > allottedTime) {
overrun = event.duration - allottedTime;
// Don't count time over the deadline as being inside idle time.
// Since the deadline should be relative to wall clock we
// compare allotted_time_ms with wall duration instead of thread
// duration, and then assume the thread duration was inside idle
// for the same percentage of time.
inside = event.cpuDuration * allottedTime / event.duration;
} else {
inside = event.cpuDuration;
}
}
cpuDuration.addSample(event.cpuDuration);
insideIdle.addSample(inside);
outsideIdle.addSample(event.cpuDuration - inside);
idleDeadlineOverrun.addSample(overrun);
});
values.addHistogram(idleDeadlineOverrun);
values.addHistogram(outsideIdle);
var percentage = createPercentage(
name + '_percentage_idle', insideIdle.sum, cpuDuration.sum);
values.addHistogram(percentage);
}
return {
blinkGcMetric: blinkGcMetric
};
});
</script>