| <!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="import" href="/tracing/base/math/range.html"> |
| <link rel="import" href="/tracing/base/math/sorted_array_utils.html"> |
| <link rel="import" href="/tracing/model/event.html"> |
| <link rel="import" href="/tracing/model/object_snapshot.html"> |
| |
| <script> |
| 'use strict'; |
| |
| /** |
| * @fileoverview Provides the ObjectSnapshot and ObjectHistory classes. |
| */ |
| tr.exportTo('tr.model', function() { |
| var ObjectSnapshot = tr.model.ObjectSnapshot; |
| |
| /** |
| * An object with a specific id, whose state has been snapshotted several |
| * times. |
| * |
| * @constructor |
| */ |
| function ObjectInstance( |
| parent, scopedId, category, name, creationTs, opt_baseTypeName) { |
| tr.model.Event.call(this); |
| this.parent = parent; |
| this.scopedId = scopedId; |
| this.category = category; |
| this.baseTypeName = opt_baseTypeName ? opt_baseTypeName : name; |
| this.name = name; |
| this.creationTs = creationTs; |
| this.creationTsWasExplicit = false; |
| this.deletionTs = Number.MAX_VALUE; |
| this.deletionTsWasExplicit = false; |
| this.colorId = 0; |
| this.bounds = new tr.b.math.Range(); |
| this.snapshots = []; |
| this.hasImplicitSnapshots = false; |
| } |
| |
| ObjectInstance.prototype = { |
| __proto__: tr.model.Event.prototype, |
| |
| get typeName() { |
| return this.name; |
| }, |
| |
| addBoundsToRange: function(range) { |
| range.addRange(this.bounds); |
| }, |
| |
| addSnapshot: function(ts, args, opt_name, opt_baseTypeName) { |
| if (ts < this.creationTs) |
| throw new Error('Snapshots must be >= instance.creationTs'); |
| if (ts >= this.deletionTs) |
| throw new Error('Snapshots cannot be added after ' + |
| 'an objects deletion timestamp.'); |
| |
| var lastSnapshot; |
| if (this.snapshots.length > 0) { |
| lastSnapshot = this.snapshots[this.snapshots.length - 1]; |
| if (lastSnapshot.ts === ts) |
| throw new Error('Snapshots already exists at this time!'); |
| if (ts < lastSnapshot.ts) { |
| throw new Error( |
| 'Snapshots must be added in increasing timestamp order'); |
| } |
| } |
| |
| // Update baseTypeName if needed. |
| if (opt_name && |
| (this.name !== opt_name)) { |
| if (!opt_baseTypeName) |
| throw new Error('Must provide base type name for name update'); |
| if (this.baseTypeName !== opt_baseTypeName) |
| throw new Error('Cannot update type name: base types dont match'); |
| this.name = opt_name; |
| } |
| |
| var snapshotConstructor = |
| tr.model.ObjectSnapshot.subTypes.getConstructor( |
| this.category, this.name); |
| var snapshot = new snapshotConstructor(this, ts, args); |
| this.snapshots.push(snapshot); |
| return snapshot; |
| }, |
| |
| wasDeleted: function(ts) { |
| var lastSnapshot; |
| if (this.snapshots.length > 0) { |
| lastSnapshot = this.snapshots[this.snapshots.length - 1]; |
| if (lastSnapshot.ts > ts) |
| throw new Error( |
| 'Instance cannot be deleted at ts=' + |
| ts + '. A snapshot exists that is older.'); |
| } |
| this.deletionTs = ts; |
| this.deletionTsWasExplicit = true; |
| }, |
| |
| /** |
| * See ObjectSnapshot constructor notes on object initialization. |
| */ |
| preInitialize: function() { |
| for (var i = 0; i < this.snapshots.length; i++) |
| this.snapshots[i].preInitialize(); |
| }, |
| |
| /** |
| * See ObjectSnapshot constructor notes on object initialization. |
| */ |
| initialize: function() { |
| for (var i = 0; i < this.snapshots.length; i++) |
| this.snapshots[i].initialize(); |
| }, |
| |
| isAliveAt: function(ts) { |
| if (ts < this.creationTs && this.creationTsWasExplicit) |
| return false; |
| if (ts > this.deletionTs) |
| return false; |
| |
| return true; |
| }, |
| |
| getSnapshotAt: function(ts) { |
| if (ts < this.creationTs) { |
| if (this.creationTsWasExplicit) |
| throw new Error('ts must be within lifetime of this instance'); |
| return this.snapshots[0]; |
| } |
| if (ts > this.deletionTs) |
| throw new Error('ts must be within lifetime of this instance'); |
| |
| var snapshots = this.snapshots; |
| var i = tr.b.math.findIndexInSortedIntervals( |
| snapshots, |
| function(snapshot) { return snapshot.ts; }, |
| function(snapshot, i) { |
| if (i === snapshots.length - 1) |
| return snapshots[i].objectInstance.deletionTs; |
| return snapshots[i + 1].ts - snapshots[i].ts; |
| }, |
| ts); |
| if (i < 0) { |
| // Note, this is a little bit sketchy: this lets early ts point at the |
| // first snapshot, even before it is taken. We do this because raster |
| // tasks usually post before their tile snapshots are dumped. This may |
| // be a good line of code to re-visit if we start seeing strange and |
| // confusing object references showing up in the traces. |
| return this.snapshots[0]; |
| } |
| if (i >= this.snapshots.length) |
| return this.snapshots[this.snapshots.length - 1]; |
| return this.snapshots[i]; |
| }, |
| |
| updateBounds: function() { |
| this.bounds.reset(); |
| this.bounds.addValue(this.creationTs); |
| if (this.deletionTs !== Number.MAX_VALUE) |
| this.bounds.addValue(this.deletionTs); |
| else if (this.snapshots.length > 0) |
| this.bounds.addValue(this.snapshots[this.snapshots.length - 1].ts); |
| }, |
| |
| shiftTimestampsForward: function(amount) { |
| this.creationTs += amount; |
| if (this.deletionTs !== Number.MAX_VALUE) |
| this.deletionTs += amount; |
| this.snapshots.forEach(function(snapshot) { |
| snapshot.ts += amount; |
| }); |
| }, |
| |
| get userFriendlyName() { |
| return this.typeName + ' object ' + this.scopedId; |
| } |
| }; |
| |
| tr.model.EventRegistry.register( |
| ObjectInstance, |
| { |
| name: 'objectInstance', |
| pluralName: 'objectInstances' |
| }); |
| |
| return { |
| ObjectInstance, |
| }; |
| }); |
| </script> |