blob: 71fc823d6a355b008af4193be36afa06e56f6c77 [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/metrics/metric_registry.html">
<link rel="import" href="/tracing/metrics/v8/utils.html">
<link rel="import" href="/tracing/value/numeric.html">
<link rel="import" href="/tracing/value/unit.html">
<link rel="import" href="/tracing/value/value.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.v.Unit.byName.timeDurationInMs_smallerIsBetter;
var percentage_biggerIsBetter =
tr.v.Unit.byName.normalizedPercentage_biggerIsBetter;
var numericBuilder = new tr.v.NumericBuilder(
timeDurationInMs_smallerIsBetter, 0);
// 0.1 steps from 0 to 20 since it is the most common range.
numericBuilder.addLinearBins(20, 200);
// Exponentially increasing steps from 20 to 200.
numericBuilder.addExponentialBins(200, 100);
function createNumericForTopEventTime() {
var n = numericBuilder.build();
n.customizeSummaryOptions({
avg: true,
count: true,
max: true,
min: false,
std: true,
sum: true,
percentile: [0.90]});
return n;
}
function createNumericForIdleTime() {
var n = numericBuilder.build();
n.customizeSummaryOptions({
avg: true,
count: false,
max: true,
min: false,
std: false,
sum: true,
percentile: []
});
return n;
}
function createPercentage(numerator, denominator) {
var percentage = denominator === 0 ? 0 : numerator / denominator * 100;
return new tr.v.ScalarNumeric(percentage_biggerIsBetter, percentage);
}
/**
* Example output:
* - blink-gc-marking.
*/
function addDurationOfTopEvents(values, model) {
tr.metrics.v8.utils.groupAndProcessEvents(model,
isBlinkGarbageCollectionEvent,
blinkGarbageCollectionEventName,
function(name, events) {
var cpuDuration = createNumericForTopEventTime();
events.forEach(function(event) {
cpuDuration.add(event.cpuDuration);
});
values.addValue(new tr.v.NumericValue(name, 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();
events.forEach(function(event) {
cpuDuration.add(event.cpuDuration);
});
values.addValue(new tr.v.NumericValue(name, 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();
var insideIdle = createNumericForIdleTime();
var outsideIdle = createNumericForIdleTime();
var idleDeadlineOverrun = createNumericForIdleTime();
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.add(event.cpuDuration);
insideIdle.add(inside);
outsideIdle.add(event.cpuDuration - inside);
idleDeadlineOverrun.add(overrun);
});
values.addValue(new tr.v.NumericValue(
name + '_idle_deadline_overrun',
idleDeadlineOverrun));
values.addValue(new tr.v.NumericValue(
name + '_outside_idle', outsideIdle));
var percentage = createPercentage(insideIdle.sum,
cpuDuration.sum);
values.addValue(new tr.v.NumericValue(
name + '_percentage_idle', percentage));
}
return {
blinkGcMetric: blinkGcMetric
};
});
</script>