process_track_base.html revision cef7893435aa41160dd1255c43cb8498279738cc
1<!DOCTYPE html>
2<!--
3Copyright (c) 2013 The Chromium Authors. All rights reserved.
4Use of this source code is governed by a BSD-style license that can be
5found in the LICENSE file.
6-->
7
8<link rel="stylesheet" href="/tracing/ui/tracks/process_track_base.css">
9
10<link rel="import" href="/tracing/core/filter.html">
11<link rel="import" href="/tracing/model/model_settings.html">
12<link rel="import" href="/tracing/ui/base/dom_helpers.html">
13<link rel="import" href="/tracing/ui/base/ui.html">
14<link rel="import" href="/tracing/ui/tracks/container_track.html">
15<link rel="import" href="/tracing/ui/tracks/counter_track.html">
16<link rel="import" href="/tracing/ui/tracks/frame_track.html">
17<link rel="import" href="/tracing/ui/tracks/object_instance_group_track.html">
18<link rel="import" href="/tracing/ui/tracks/process_summary_track.html">
19<link rel="import" href="/tracing/ui/tracks/spacing_track.html">
20<link rel="import" href="/tracing/ui/tracks/thread_track.html">
21
22<script>
23'use strict';
24
25tr.exportTo('tr.ui.tracks', function() {
26
27  var ObjectSnapshotView = tr.ui.analysis.ObjectSnapshotView;
28  var ObjectInstanceView = tr.ui.analysis.ObjectInstanceView;
29  var SpacingTrack = tr.ui.tracks.SpacingTrack;
30
31  /**
32   * Visualizes a Process by building ThreadTracks and CounterTracks.
33   * @constructor
34   */
35  var ProcessTrackBase =
36      tr.ui.b.define('process-track-base', tr.ui.tracks.ContainerTrack);
37
38  ProcessTrackBase.prototype = {
39
40    __proto__: tr.ui.tracks.ContainerTrack.prototype,
41
42    decorate: function(viewport) {
43      tr.ui.tracks.ContainerTrack.prototype.decorate.call(this, viewport);
44
45      this.processBase_ = undefined;
46
47      this.classList.add('process-track-base');
48      this.classList.add('expanded');
49
50      this.processNameEl_ = tr.ui.b.createSpan();
51      this.processNameEl_.classList.add('process-track-name');
52
53      this.headerEl_ = tr.ui.b.createDiv({className: 'process-track-header'});
54      this.headerEl_.appendChild(this.processNameEl_);
55      this.headerEl_.addEventListener('click', this.onHeaderClick_.bind(this));
56
57      this.appendChild(this.headerEl_);
58    },
59
60    get processBase() {
61      return this.processBase_;
62    },
63
64    set processBase(processBase) {
65      this.processBase_ = processBase;
66
67      if (this.processBase_) {
68        var modelSettings = new tr.model.ModelSettings(this.processBase_.model);
69        var defaultValue = this.processBase_.important;
70        this.expanded = modelSettings.getSettingFor(
71            this.processBase_, 'expanded', defaultValue);
72      }
73
74      this.updateContents_();
75    },
76
77    get expanded() {
78      return this.classList.contains('expanded');
79    },
80
81    set expanded(expanded) {
82      expanded = !!expanded;
83
84      if (this.expanded === expanded)
85        return;
86
87      this.classList.toggle('expanded');
88
89      // Expanding and collapsing tracks is, essentially, growing and shrinking
90      // the viewport. We dispatch a change event to trigger any processing
91      // to happen.
92      this.viewport_.dispatchChangeEvent();
93
94      if (!this.processBase_)
95        return;
96
97      var modelSettings = new tr.model.ModelSettings(this.processBase_.model);
98      modelSettings.setSettingFor(this.processBase_, 'expanded', expanded);
99      this.updateContents_();
100      this.viewport.rebuildEventToTrackMap();
101      this.viewport.rebuildContainerToTrackMap();
102    },
103
104    get hasVisibleContent() {
105      if (this.expanded)
106        return this.children.length > 1;
107      return true;
108    },
109
110    onHeaderClick_: function(e) {
111      e.stopPropagation();
112      e.preventDefault();
113      this.expanded = !this.expanded;
114    },
115
116    updateContents_: function() {
117      this.clearTracks_();
118
119      if (!this.processBase_)
120        return;
121
122      this.processNameEl_.textContent = this.processBase_.userFriendlyName;
123      this.headerEl_.title = this.processBase_.userFriendlyDetails;
124
125      // Create the object instance tracks for this process.
126      this.willAppendTracks_();
127      if (this.expanded) {
128        this.appendMemoryDumpTrack_();
129        this.appendObjectInstanceTracks_();
130        this.appendCounterTracks_();
131        this.appendFrameTrack_();
132        this.appendThreadTracks_();
133      } else {
134        this.appendSummaryTrack_();
135      }
136      this.didAppendTracks_();
137    },
138
139    addEventsToTrackMap: function(eventToTrackMap) {
140      this.tracks_.forEach(function(track) {
141        track.addEventsToTrackMap(eventToTrackMap);
142      });
143    },
144
145    willAppendTracks_: function() {
146    },
147
148    didAppendTracks_: function() {
149    },
150
151    appendMemoryDumpTrack_: function() {
152    },
153
154    appendSummaryTrack_: function() {
155      var track = new tr.ui.tracks.ProcessSummaryTrack(this.viewport);
156      track.process = this.process;
157      if (!track.hasVisibleContent)
158        return;
159      this.appendChild(track);
160      // no spacing track, since this track only shown in collapsed state
161    },
162
163    appendFrameTrack_: function() {
164      var frames = this.process ? this.process.frames : undefined;
165      if (!frames || !frames.length)
166        return;
167
168      var track = new tr.ui.tracks.FrameTrack(this.viewport);
169      track.frames = frames;
170      this.appendChild(track);
171    },
172
173    appendObjectInstanceTracks_: function() {
174      var instancesByTypeName =
175          this.processBase_.objects.getAllInstancesByTypeName();
176      var instanceTypeNames = tr.b.dictionaryKeys(instancesByTypeName);
177      instanceTypeNames.sort();
178
179      var didAppendAtLeastOneTrack = false;
180      instanceTypeNames.forEach(function(typeName) {
181        var allInstances = instancesByTypeName[typeName];
182
183        // If a object snapshot has a view it will be shown,
184        // unless the view asked for it to not be shown.
185        var instanceViewInfo = ObjectInstanceView.getTypeInfo(
186            undefined, typeName);
187        var snapshotViewInfo = ObjectSnapshotView.getTypeInfo(
188            undefined, typeName);
189        if (instanceViewInfo && !instanceViewInfo.metadata.showInTrackView)
190          instanceViewInfo = undefined;
191        if (snapshotViewInfo && !snapshotViewInfo.metadata.showInTrackView)
192          snapshotViewInfo = undefined;
193        var hasViewInfo = instanceViewInfo || snapshotViewInfo;
194
195        // There are some instances that don't merit their own track in
196        // the UI. Filter them out.
197        var visibleInstances = [];
198        for (var i = 0; i < allInstances.length; i++) {
199          var instance = allInstances[i];
200
201          // Do not create tracks for instances that have no snapshots.
202          if (instance.snapshots.length === 0)
203            continue;
204
205          // Do not create tracks for instances that have implicit snapshots
206          // and don't have a view.
207          if (instance.hasImplicitSnapshots && !hasViewInfo)
208            continue;
209
210          visibleInstances.push(instance);
211        }
212        if (visibleInstances.length === 0)
213          return;
214
215        // Look up the constructor for this track, or use the default
216        // constructor if none exists.
217        var trackConstructor =
218            tr.ui.tracks.ObjectInstanceTrack.getConstructor(
219                undefined, typeName);
220        if (!trackConstructor) {
221          var snapshotViewInfo = ObjectSnapshotView.getTypeInfo(
222              undefined, typeName);
223          if (snapshotViewInfo && snapshotViewInfo.metadata.showInstances) {
224            trackConstructor = tr.ui.tracks.ObjectInstanceGroupTrack;
225          } else {
226            trackConstructor = tr.ui.tracks.ObjectInstanceTrack;
227          }
228        }
229        var track = new trackConstructor(this.viewport);
230        track.objectInstances = visibleInstances;
231        this.appendChild(track);
232        didAppendAtLeastOneTrack = true;
233      }, this);
234      if (didAppendAtLeastOneTrack)
235        this.appendChild(new SpacingTrack(this.viewport));
236    },
237
238    appendCounterTracks_: function() {
239      // Add counter tracks for this process.
240      var counters = tr.b.dictionaryValues(this.processBase.counters);
241      counters.sort(tr.model.Counter.compare);
242
243      // Create the counters for this process.
244      counters.forEach(function(counter) {
245        var track = new tr.ui.tracks.CounterTrack(this.viewport);
246        track.counter = counter;
247        this.appendChild(track);
248        this.appendChild(new SpacingTrack(this.viewport));
249      }.bind(this));
250    },
251
252    appendThreadTracks_: function() {
253      // Get a sorted list of threads.
254      var threads = tr.b.dictionaryValues(this.processBase.threads);
255      threads.sort(tr.model.Thread.compare);
256
257      // Create the threads.
258      threads.forEach(function(thread) {
259        var track = new tr.ui.tracks.ThreadTrack(this.viewport);
260        track.thread = thread;
261        if (!track.hasVisibleContent)
262          return;
263        this.appendChild(track);
264        this.appendChild(new SpacingTrack(this.viewport));
265      }.bind(this));
266    }
267  };
268
269  return {
270    ProcessTrackBase: ProcessTrackBase
271  };
272});
273</script>
274