blob: a2afb62215f4101808a22516087fb00e8add8825 [file] [log] [blame]
<!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="stylesheet" href="/ui/tracks/process_track_base.css">
<link rel="import" href="/ui/tracks/container_track.html">
<link rel="import" href="/ui/tracks/counter_track.html">
<link rel="import" href="/ui/tracks/frame_track.html">
<link rel="import" href="/ui/tracks/object_instance_group_track.html">
<link rel="import" href="/ui/tracks/process_summary_track.html">
<link rel="import" href="/ui/tracks/spacing_track.html">
<link rel="import" href="/ui/tracks/thread_track.html">
<link rel="import" href="/core/filter.html">
<link rel="import" href="/model/model_settings.html">
<link rel="import" href="/ui/base/ui.html">
<link rel="import" href="/ui/base/dom_helpers.html">
<script>
'use strict';
tr.exportTo('tr.ui.tracks', function() {
var ObjectSnapshotView = tr.ui.analysis.ObjectSnapshotView;
var ObjectInstanceView = tr.ui.analysis.ObjectInstanceView;
var SpacingTrack = tr.ui.tracks.SpacingTrack;
/**
* Visualizes a Process by building ThreadTracks and CounterTracks.
* @constructor
*/
var ProcessTrackBase =
tr.ui.b.define('process-track-base', tr.ui.tracks.ContainerTrack);
ProcessTrackBase.prototype = {
__proto__: tr.ui.tracks.ContainerTrack.prototype,
decorate: function(viewport) {
tr.ui.tracks.ContainerTrack.prototype.decorate.call(this, viewport);
this.processBase_ = undefined;
this.classList.add('process-track-base');
this.classList.add('expanded');
this.processNameEl_ = tr.ui.b.createSpan();
this.processNameEl_.classList.add('process-track-name');
this.headerEl_ = tr.ui.b.createDiv({className: 'process-track-header'});
this.headerEl_.appendChild(this.processNameEl_);
this.headerEl_.addEventListener('click', this.onHeaderClick_.bind(this));
this.appendChild(this.headerEl_);
},
get processBase() {
return this.processBase_;
},
set processBase(processBase) {
this.processBase_ = processBase;
if (this.processBase_) {
var modelSettings = new tr.model.ModelSettings(this.processBase_.model);
var defaultValue = this.processBase_.important;
this.expanded = modelSettings.getSettingFor(
this.processBase_, 'expanded', defaultValue);
}
this.updateContents_();
},
get expanded() {
return this.classList.contains('expanded');
},
set expanded(expanded) {
expanded = !!expanded;
if (this.expanded === expanded)
return;
this.classList.toggle('expanded');
// Expanding and collapsing tracks is, essentially, growing and shrinking
// the viewport. We dispatch a change event to trigger any processing
// to happen.
this.viewport_.dispatchChangeEvent();
if (!this.processBase_)
return;
var modelSettings = new tr.model.ModelSettings(this.processBase_.model);
modelSettings.setSettingFor(this.processBase_, 'expanded', expanded);
this.updateContents_();
this.viewport.rebuildEventToTrackMap();
this.viewport.rebuildContainerToTrackMap();
},
get hasVisibleContent() {
if (this.expanded)
return this.children.length > 1;
return true;
},
onHeaderClick_: function(e) {
e.stopPropagation();
e.preventDefault();
this.expanded = !this.expanded;
},
updateContents_: function() {
this.clearTracks_();
if (!this.processBase_)
return;
this.processNameEl_.textContent = this.processBase_.userFriendlyName;
this.headerEl_.title = this.processBase_.userFriendlyDetails;
// Create the object instance tracks for this process.
this.willAppendTracks_();
if (this.expanded) {
this.appendMemoryDumpTrack_();
this.appendObjectInstanceTracks_();
this.appendCounterTracks_();
this.appendFrameTrack_();
this.appendThreadTracks_();
} else {
this.appendSummaryTrack_();
}
this.didAppendTracks_();
},
addEventsToTrackMap: function(eventToTrackMap) {
this.tracks_.forEach(function(track) {
track.addEventsToTrackMap(eventToTrackMap);
});
},
willAppendTracks_: function() {
},
didAppendTracks_: function() {
},
appendMemoryDumpTrack_: function() {
},
appendSummaryTrack_: function() {
var track = new tr.ui.tracks.ProcessSummaryTrack(this.viewport);
track.process = this.process;
if (!track.hasVisibleContent)
return;
this.appendChild(track);
// no spacing track, since this track only shown in collapsed state
},
appendFrameTrack_: function() {
var frames = this.process ? this.process.frames : undefined;
if (!frames || !frames.length)
return;
var track = new tr.ui.tracks.FrameTrack(this.viewport);
track.frames = frames;
this.appendChild(track);
this.backgroundProvider = track;
},
appendObjectInstanceTracks_: function() {
var instancesByTypeName =
this.processBase_.objects.getAllInstancesByTypeName();
var instanceTypeNames = tr.b.dictionaryKeys(instancesByTypeName);
instanceTypeNames.sort();
var didAppendAtLeastOneTrack = false;
instanceTypeNames.forEach(function(typeName) {
var allInstances = instancesByTypeName[typeName];
// If a object snapshot has a view it will be shown,
// unless the view asked for it to not be shown.
var instanceViewInfo = ObjectInstanceView.getTypeInfo(
undefined, typeName);
var snapshotViewInfo = ObjectSnapshotView.getTypeInfo(
undefined, typeName);
if (instanceViewInfo && !instanceViewInfo.metadata.showInTrackView)
instanceViewInfo = undefined;
if (snapshotViewInfo && !snapshotViewInfo.metadata.showInTrackView)
snapshotViewInfo = undefined;
var hasViewInfo = instanceViewInfo || snapshotViewInfo;
// There are some instances that don't merit their own track in
// the UI. Filter them out.
var visibleInstances = [];
for (var i = 0; i < allInstances.length; i++) {
var instance = allInstances[i];
// Do not create tracks for instances that have no snapshots.
if (instance.snapshots.length === 0)
continue;
// Do not create tracks for instances that have implicit snapshots
// and don't have a view.
if (instance.hasImplicitSnapshots && !hasViewInfo)
continue;
visibleInstances.push(instance);
}
if (visibleInstances.length === 0)
return;
// Look up the constructor for this track, or use the default
// constructor if none exists.
var trackConstructor =
tr.ui.tracks.ObjectInstanceTrack.getConstructor(
undefined, typeName);
if (!trackConstructor) {
var snapshotViewInfo = ObjectSnapshotView.getTypeInfo(
undefined, typeName);
if (snapshotViewInfo && snapshotViewInfo.metadata.showInstances) {
trackConstructor = tr.ui.tracks.ObjectInstanceGroupTrack;
} else {
trackConstructor = tr.ui.tracks.ObjectInstanceTrack;
}
}
var track = new trackConstructor(this.viewport);
track.objectInstances = visibleInstances;
this.appendChild(track);
didAppendAtLeastOneTrack = true;
}, this);
if (didAppendAtLeastOneTrack)
this.appendChild(new SpacingTrack(this.viewport));
},
appendCounterTracks_: function() {
// Add counter tracks for this process.
var counters = tr.b.dictionaryValues(this.processBase.counters);
counters.sort(tr.model.Counter.compare);
// Create the counters for this process.
counters.forEach(function(counter) {
var track = new tr.ui.tracks.CounterTrack(this.viewport);
track.counter = counter;
this.appendChild(track);
this.appendChild(new SpacingTrack(this.viewport));
}.bind(this));
},
appendThreadTracks_: function() {
// Get a sorted list of threads.
var threads = tr.b.dictionaryValues(this.processBase.threads);
threads.sort(tr.model.Thread.compare);
// Create the threads.
threads.forEach(function(thread) {
var track = new tr.ui.tracks.ThreadTrack(this.viewport);
track.thread = thread;
if (!track.hasVisibleContent)
return;
this.appendChild(track);
this.appendChild(new SpacingTrack(this.viewport));
}.bind(this));
}
};
return {
ProcessTrackBase: ProcessTrackBase
};
});
</script>