// Copyright (c) 2013 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.
'use strict';
base.requireStylesheet('tracing.analysis.analyze_slices');
base.require('tracing.analysis.util');
base.require('ui');
base.exportTo('tracing.analysis', function() {
function analyzeSingleSliceHit(results, sliceHit) {
var slice = sliceHit.slice;
var table = results.appendTable('analysis-slice-table', 2);
results.appendTableHeader(table, 'Selected slice:');
results.appendSummaryRow(table, 'Title', slice.title);
if (slice.category)
results.appendSummaryRow(table, 'Category', slice.category);
results.appendSummaryRowTime(table, 'Start', slice.start);
results.appendSummaryRowTime(table, 'Duration', slice.duration);
if (slice.durationInUserTime) {
results.appendSummaryRowTime(
table, 'Duration (U)', slice.durationInUserTime);
}
var n = 0;
for (var argName in slice.args) {
n += 1;
}
if (n > 0) {
results.appendSummaryRow(table, 'Args');
for (var argName in slice.args) {
var argVal = slice.args[argName];
// TODO(sleffler) use span instead?
results.appendSummaryRow(table, ' ' + argName, argVal);
}
}
}
function analyzeMultipleSliceHits(results, sliceHits) {
var tsLo = sliceHits.bounds.min;
var tsHi = sliceHits.bounds.max;
// compute total sliceHits duration
var titles = sliceHits.map(function(i) { return i.slice.title; });
var numTitles = 0;
var sliceHitsByTitle = {};
for (var i = 0; i < sliceHits.length; i++) {
var slice = sliceHits[i].slice;
if (!sliceHitsByTitle[slice.title]) {
sliceHitsByTitle[slice.title] = {
hits: []
};
numTitles++;
}
var sliceGroup = sliceHitsByTitle[slice.title];
sliceGroup.hits.push(sliceHits[i]);
}
var table;
table = results.appendTable('analysis-slices-table', 3);
results.appendTableHeader(table, 'Slices:');
var totalDuration = 0;
base.iterItems(sliceHitsByTitle,
function(sliceHitGroupTitle, sliceHitGroup) {
var duration = 0;
var avg = 0;
var startOfFirstOccurrence = Number.MAX_VALUE;
var startOfLastOccurrence = -Number.MAX_VALUE;
var frequencyDetails = undefined;
var min = Number.MAX_VALUE;
var max = -Number.MAX_VALUE;
for (var i = 0; i < sliceHitGroup.hits.length; i++) {
var slice = sliceHitGroup.hits[i].slice;
duration += slice.duration;
startOfFirstOccurrence = Math.min(slice.start,
startOfFirstOccurrence);
startOfLastOccurrence = Math.max(slice.start,
startOfLastOccurrence);
min = Math.min(slice.duration, min);
max = Math.max(slice.duration, max);
}
totalDuration += duration;
if (sliceHitGroup.hits.length == 0)
avg = 0;
avg = duration / sliceHitGroup.hits.length;
var statistics = {min: min,
max: max,
avg: avg,
avg_stddev: undefined,
frequency: undefined,
frequency_stddev: undefined};
// Compute the stddev of the slice durations.
var sumOfSquaredDistancesToMean = 0;
for (var i = 0; i < sliceHitGroup.hits.length; i++) {
var signedDistance =
statistics.avg - sliceHitGroup.hits[i].slice.duration;
sumOfSquaredDistancesToMean += signedDistance * signedDistance;
}
statistics.avg_stddev = Math.sqrt(
sumOfSquaredDistancesToMean / (sliceHitGroup.hits.length - 1));
// We require at least 3 samples to compute the stddev.
var elapsed = startOfLastOccurrence - startOfFirstOccurrence;
if (sliceHitGroup.hits.length > 2 && elapsed > 0) {
var numDistances = sliceHitGroup.hits.length - 1;
statistics.frequency = (1000 * numDistances) / elapsed;
// Compute the stddev.
sumOfSquaredDistancesToMean = 0;
for (var i = 1; i < sliceHitGroup.hits.length; i++) {
var currentFrequency = 1000 /
(sliceHitGroup.hits[i].slice.start -
sliceHitGroup.hits[i - 1].slice.start);
var signedDistance = statistics.frequency - currentFrequency;
sumOfSquaredDistancesToMean += signedDistance * signedDistance;
}
statistics.frequency_stddev = Math.sqrt(
sumOfSquaredDistancesToMean / (numDistances - 1));
}
results.appendDataRow(
table, sliceHitGroupTitle, duration, sliceHitGroup.hits.length,
statistics,
function() {
return new tracing.Selection(sliceHitGroup.hits);
});
// The whole selection is a single type so list out the information
// for each sub slice.
if (numTitles === 1) {
for (var i = 0; i < sliceHitGroup.hits.length; i++) {
analyzeSingleSliceHit(results, sliceHitGroup.hits[i]);
}
}
});
// Only one row so we already know the totals.
if (numTitles !== 1) {
results.appendDataRow(table, '*Totals', totalDuration, sliceHits.length);
results.appendSpacingRow(table);
}
results.appendSummaryRowTime(table, 'Selection start', tsLo);
results.appendSummaryRowTime(table, 'Selection extent', tsHi - tsLo);
}
return {
analyzeSingleSliceHit: analyzeSingleSliceHit,
analyzeMultipleSliceHits: analyzeMultipleSliceHits
};
});