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