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="import" href="/tracing/base/guid.html">
9<link rel="import" href="/tracing/base/range.html">
10<link rel="import" href="/tracing/model/counter.html">
11<link rel="import" href="/tracing/model/event_container.html">
12<link rel="import" href="/tracing/model/object_collection.html">
13<link rel="import" href="/tracing/model/thread.html">
14
15<script>
16'use strict';
17
18/**
19 * @fileoverview Provides the ProcessBase class.
20 */
21tr.exportTo('tr.model', function() {
22
23  var Thread = tr.model.Thread;
24  var Counter = tr.model.Counter;
25
26  /**
27   * The ProcessBase is a partial base class, upon which Kernel
28   * and Process are built.
29   *
30   * @constructor
31   * @extends {tr.model.EventContainer}
32   */
33  function ProcessBase(model) {
34    if (!model)
35      throw new Error('Must provide a model');
36    tr.model.EventContainer.call(this);
37    this.model = model;
38    this.threads = {};
39    this.counters = {};
40    this.objects = new tr.model.ObjectCollection(this);
41    this.sortIndex = 0;
42  };
43
44  ProcessBase.compare = function(x, y) {
45    return x.sortIndex - y.sortIndex;
46  };
47
48  ProcessBase.prototype = {
49    __proto__: tr.model.EventContainer.prototype,
50
51    get stableId() {
52      throw new Error('Not implemented');
53    },
54
55    iterateAllChildEventContainers: function(callback, opt_this) {
56      for (var tid in this.threads)
57        callback.call(opt_this, this.threads[tid]);
58      for (var id in this.counters)
59        callback.call(opt_this, this.counters[id]);
60      callback.call(opt_this, this.objects);
61    },
62
63    iterateAllEventsInThisContainer: function(eventTypePredicate,
64                                              callback, opt_this) {
65    },
66
67    iterateAllPersistableObjects: function(cb) {
68      cb(this);
69      for (var tid in this.threads)
70        this.threads[tid].iterateAllPersistableObjects(cb);
71    },
72
73    /**
74     * Gets the number of threads in this process.
75     */
76    get numThreads() {
77      var n = 0;
78      for (var p in this.threads) {
79        n++;
80      }
81      return n;
82    },
83
84    /**
85     * Shifts all the timestamps inside this process forward by the amount
86     * specified.
87     */
88    shiftTimestampsForward: function(amount) {
89      this.iterateAllChildEventContainers(function(child) {
90        child.shiftTimestampsForward(amount);
91      });
92    },
93
94    /**
95     * Closes any open slices.
96     */
97    autoCloseOpenSlices: function() {
98      for (var tid in this.threads) {
99        var thread = this.threads[tid];
100        thread.autoCloseOpenSlices();
101      }
102    },
103
104    autoDeleteObjects: function(maxTimestamp) {
105      this.objects.autoDeleteObjects(maxTimestamp);
106    },
107
108    /**
109     * Called by the model after finalizing imports,
110     * but before joining refs.
111     */
112    preInitializeObjects: function() {
113      this.objects.preInitializeAllObjects();
114    },
115
116    /**
117     * Called by the model after joining refs.
118     */
119    initializeObjects: function() {
120      this.objects.initializeAllObjects();
121    },
122
123    /**
124     * Merge slices from the kernel with those from userland for each thread.
125     */
126    mergeKernelWithUserland: function() {
127      for (var tid in this.threads) {
128        var thread = this.threads[tid];
129        thread.mergeKernelWithUserland();
130      }
131    },
132
133    updateBounds: function() {
134      this.bounds.reset();
135      for (var tid in this.threads) {
136        this.threads[tid].updateBounds();
137        this.bounds.addRange(this.threads[tid].bounds);
138      }
139      for (var id in this.counters) {
140        this.counters[id].updateBounds();
141        this.bounds.addRange(this.counters[id].bounds);
142      }
143      this.objects.updateBounds();
144      this.bounds.addRange(this.objects.bounds);
145    },
146
147    addCategoriesToDict: function(categoriesDict) {
148      for (var tid in this.threads)
149        this.threads[tid].addCategoriesToDict(categoriesDict);
150      for (var id in this.counters)
151        categoriesDict[this.counters[id].category] = true;
152      this.objects.addCategoriesToDict(categoriesDict);
153    },
154
155    findAllThreadsMatching: function(predicate, opt_this) {
156      var threads = [];
157      for (var tid in this.threads) {
158        var thread = this.threads[tid];
159        if (predicate.call(opt_this, thread))
160          threads.push(thread);
161      }
162      return threads;
163    },
164
165    /**
166     * @param {String} The name of the thread to find.
167     * @return {Array} An array of all the matched threads.
168     */
169    findAllThreadsNamed: function(name) {
170      var threads = this.findAllThreadsMatching(function(thread) {
171        if (!thread.name)
172          return false;
173        return thread.name === name;
174      });
175      return threads;
176    },
177
178    findAtMostOneThreadNamed: function(name) {
179      var threads = this.findAllThreadsNamed(name);
180      if (threads.length === 0)
181        return undefined;
182      if (threads.length > 1)
183        throw new Error('Expected no more than one ' + name);
184      return threads[0];
185    },
186
187    /**
188     * Removes threads from the process that are fully empty.
189     */
190    pruneEmptyContainers: function() {
191      var threadsToKeep = {};
192      for (var tid in this.threads) {
193        var thread = this.threads[tid];
194        if (!thread.isEmpty)
195          threadsToKeep[tid] = thread;
196      }
197      this.threads = threadsToKeep;
198    },
199
200    /**
201     * @return {TimelineThread} The thread identified by tid on this process,
202     * or undefined if it doesn't exist.
203     */
204    getThread: function(tid) {
205      return this.threads[tid];
206    },
207
208    /**
209     * @return {TimelineThread} The thread identified by tid on this process,
210     * creating it if it doesn't exist.
211     */
212    getOrCreateThread: function(tid) {
213      if (!this.threads[tid])
214        this.threads[tid] = new Thread(this, tid);
215      return this.threads[tid];
216    },
217
218    /**
219     * @return {Counter} The counter on this process with the given
220     * category/name combination, creating it if it doesn't exist.
221     */
222    getOrCreateCounter: function(cat, name) {
223      var id = cat + '.' + name;
224      if (!this.counters[id])
225        this.counters[id] = new Counter(this, id, cat, name);
226      return this.counters[id];
227    },
228
229    getSettingsKey: function() {
230      throw new Error('Not implemented');
231    },
232
233    createSubSlices: function() {
234      for (var tid in this.threads)
235        this.threads[tid].createSubSlices();
236    }
237  };
238
239  return {
240    ProcessBase: ProcessBase
241  };
242});
243</script>
244