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