summaryrefslogtreecommitdiff
path: root/chromium/third_party/catapult/tracing/tracing/ui/tracks/slice_group_track.html
blob: 78ffd07cf00e813aa027bd3859f34403abe643d5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
<!DOCTYPE html>
<!--
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.
-->

<link rel="import" href="/tracing/ui/tracks/multi_row_track.html">
<link rel="import" href="/tracing/base/sorted_array_utils.html">
<link rel="import" href="/tracing/ui/base/ui.html">

<script>
'use strict';

tr.exportTo('tr.ui.tracks', function() {
  /**
   * A track that displays a SliceGroup.
   * @constructor
   * @extends {MultiRowTrack}
   */
  var SliceGroupTrack = tr.ui.b.define(
      'slice-group-track', tr.ui.tracks.MultiRowTrack);

  SliceGroupTrack.prototype = {

    __proto__: tr.ui.tracks.MultiRowTrack.prototype,

    decorate: function(viewport) {
      tr.ui.tracks.MultiRowTrack.prototype.decorate.call(this, viewport);
      this.classList.add('slice-group-track');
      this.group_ = undefined;
      // Set the collapse threshold so we don't collapse by default, but the
      // user can explicitly collapse if they want it.
      this.defaultToCollapsedWhenSubRowCountMoreThan = 100;
    },

    addSubTrack_: function(slices) {
      var track = new tr.ui.tracks.SliceTrack(this.viewport);
      track.slices = slices;
      this.appendChild(track);
      return track;
    },

    get group() {
      return this.group_;
    },

    set group(group) {
      this.group_ = group;
      this.setItemsToGroup(this.group_.slices, this.group_);
    },

    get eventContainer() {
      return this.group;
    },

    addContainersToTrackMap: function(containerToTrackMap) {
      tr.ui.tracks.MultiRowTrack.prototype.addContainersToTrackMap.apply(
        this, arguments);
      containerToTrackMap.addContainer(this.group, this);
    },

    /**
     * Breaks up the list of slices into N rows, each of which is a list of
     * slices that are non overlapping.
     */
    buildSubRows_: function(slices) {
      var precisionUnit = this.group.model.intrinsicTimeUnit;

      // This function works by walking through slices by start time.
      //
      // The basic idea here is to insert each slice as deep into the subrow
      // list as it can go such that every subSlice is fully contained by its
      // parent slice.
      //
      // Visually, if we start with this:
      //  0:  [    a       ]
      //  1:    [  b  ]
      //  2:    [c][d]
      //
      // To place this slice:
      //               [e]
      // We first check row 2's last item, [d]. [e] wont fit into [d] (they dont
      // even intersect). So we go to row 1. That gives us [b], and [d] wont fit
      // into that either. So, we go to row 0 and its last slice, [a]. That can
      // completely contain [e], so that means we should add [e] as a subchild
      // of [a]. That puts it on row 1, yielding:
      //  0:  [    a       ]
      //  1:    [  b  ][e]
      //  2:    [c][d]
      //
      // If we then get this slice:
      //                      [f]
      // We do the same deepest-to-shallowest walk of the subrows trying to fit
      // it. This time, it doesn't fit in any open slice. So, we simply append
      // it to row 0:
      //  0:  [    a       ]  [f]
      //  1:    [  b  ][e]
      //  2:    [c][d]
      if (!slices.length)
        return [];

      var ops = [];
      for (var i = 0; i < slices.length; i++) {
        if (slices[i].subSlices)
          slices[i].subSlices.splice(0,
                                     slices[i].subSlices.length);
        ops.push(i);
      }

      ops.sort(function(ix, iy) {
        var x = slices[ix];
        var y = slices[iy];
        if (x.start != y.start)
          return x.start - y.start;

        // Elements get inserted into the slices array in order of when the
        // slices start. Because slices must be properly nested, we break
        // start-time ties by assuming that the elements appearing earlier in
        // the slices array (and thus ending earlier) start earlier.
        return ix - iy;
      });

      var subRows = [[]];
      this.badSlices_ = [];  // TODO(simonjam): Connect this again.

      for (var i = 0; i < ops.length; i++) {
        var op = ops[i];
        var slice = slices[op];

        // Try to fit the slice into the existing subrows.
        var inserted = false;
        for (var j = subRows.length - 1; j >= 0; j--) {
          if (subRows[j].length == 0)
            continue;

          var insertedSlice = subRows[j][subRows[j].length - 1];
          if (slice.start < insertedSlice.start) {
            this.badSlices_.push(slice);
            inserted = true;
          }
          if (insertedSlice.bounds(slice, precisionUnit)) {
            // Insert it into subRow j + 1.
            while (subRows.length <= j + 1)
              subRows.push([]);
            subRows[j + 1].push(slice);
            if (insertedSlice.subSlices)
              insertedSlice.subSlices.push(slice);
            inserted = true;
            break;
          }
        }
        if (inserted)
          continue;

        // Append it to subRow[0] as a root.
        subRows[0].push(slice);
      }

      return subRows;
    }
  };

  return {
    SliceGroupTrack: SliceGroupTrack
  };
});
</script>