Javascript  |  165行  |  5.64 KB

// 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
  };
});