Home | History | Annotate | Download | only in trace_model
      1 // Copyright (c) 2013 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 /**
      8  * @fileoverview Provides the ObjectSnapshot and ObjectHistory classes.
      9  */
     10 base.require('base.range');
     11 base.require('base.sorted_array_utils');
     12 base.require('tracing.trace_model.object_snapshot');
     13 
     14 base.exportTo('tracing.trace_model', function() {
     15   var ObjectSnapshot = tracing.trace_model.ObjectSnapshot;
     16 
     17   /**
     18    * An object with a specific id, whose state has been snapshotted several
     19    * times.
     20    *
     21    * @constructor
     22    */
     23   function ObjectInstance(parent, id, category, name, creationTs) {
     24     this.parent = parent;
     25     this.id = id;
     26     this.category = category;
     27     this.name = name;
     28     this.creationTs = creationTs;
     29     this.creationTsWasExplicit = false;
     30     this.deletionTs = Number.MAX_VALUE;
     31     this.deletionTsWasExplicit = false;
     32     this.selected = false;
     33     this.colorId = 0;
     34     this.bounds = new base.Range();
     35     this.snapshots = [];
     36     this.hasImplicitSnapshots = false;
     37   }
     38 
     39   ObjectInstance.prototype = {
     40     __proto__: Object.prototype,
     41 
     42     get typeName() {
     43       return this.name;
     44     },
     45 
     46     addSnapshot: function(ts, args) {
     47       if (ts < this.creationTs)
     48         throw new Error('Snapshots must be >= instance.creationTs');
     49       if (ts >= this.deletionTs)
     50         throw new Error('Snapshots cannot be added after ' +
     51                         'an objects deletion timestamp.');
     52 
     53       var lastSnapshot;
     54       if (this.snapshots.length > 0) {
     55         lastSnapshot = this.snapshots[this.snapshots.length - 1];
     56         if (lastSnapshot.ts == ts)
     57           throw new Error('Snapshots already exists at this time!');
     58         if (ts < lastSnapshot.ts) {
     59           throw new Error(
     60               'Snapshots must be added in increasing timestamp order');
     61         }
     62       }
     63 
     64       var snapshotConstructor =
     65           tracing.trace_model.ObjectSnapshot.getConstructor(this.name);
     66       var snapshot = new snapshotConstructor(this, ts, args);
     67       this.snapshots.push(snapshot);
     68       return snapshot;
     69     },
     70 
     71     wasDeleted: function(ts) {
     72       var lastSnapshot;
     73       if (this.snapshots.length > 0) {
     74         lastSnapshot = this.snapshots[this.snapshots.length - 1];
     75         if (lastSnapshot.ts > ts)
     76           throw new Error(
     77               'Instance cannot be deleted at ts=' +
     78               ts + '. A snapshot exists that is older.');
     79       }
     80       this.deletionTs = ts;
     81       this.deletionTsWasExplicit = true;
     82     },
     83 
     84     /**
     85      * See ObjectSnapshot constructor notes on object initialization.
     86      */
     87     preInitialize: function() {
     88       for (var i = 0; i < this.snapshots.length; i++)
     89         this.snapshots[i].preInitialize();
     90     },
     91 
     92     /**
     93      * See ObjectSnapshot constructor notes on object initialization.
     94      */
     95     initialize: function() {
     96       for (var i = 0; i < this.snapshots.length; i++)
     97         this.snapshots[i].initialize();
     98     },
     99 
    100     getSnapshotAt: function(ts) {
    101       if (ts < this.creationTs) {
    102         if (this.creationTsWasExplicit)
    103           throw new Error('ts must be within lifetime of this instance');
    104         return this.snapshots[0];
    105       }
    106       if (ts > this.deletionTs)
    107         throw new Error('ts must be within lifetime of this instance');
    108 
    109       var snapshots = this.snapshots;
    110       var i = base.findLowIndexInSortedIntervals(
    111           snapshots,
    112           function(snapshot) { return snapshot.ts; },
    113           function(snapshot, i) {
    114             if (i == snapshots.length - 1)
    115               return snapshots[i].objectInstance.deletionTs;
    116             return snapshots[i + 1].ts - snapshots[i].ts;
    117           },
    118           ts);
    119       if (i < 0) {
    120         // Note, this is a little bit sketchy: this lets early ts point at the
    121         // first snapshot, even before it is taken. We do this because raster
    122         // tasks usually post before their tile snapshots are dumped. This may
    123         // be a good line of code to re-visit if we start seeing strange and
    124         // confusing object references showing up in the traces.
    125         return this.snapshots[0];
    126       }
    127       if (i >= this.snapshots.length)
    128         return this.snapshots[this.snapshots.length - 1];
    129       return this.snapshots[i];
    130     },
    131 
    132     updateBounds: function() {
    133       this.bounds.reset();
    134       this.bounds.addValue(this.creationTs);
    135       if (this.deletionTs != Number.MAX_VALUE)
    136         this.bounds.addValue(this.deletionTs);
    137       else if (this.snapshots.length > 0)
    138         this.bounds.addValue(this.snapshots[this.snapshots.length - 1].ts);
    139     },
    140 
    141     shiftTimestampsForward: function(amount) {
    142       this.creationTs += amount;
    143       if (this.deletionTs != Number.MAX_VALUE)
    144         this.deletionTs += amount;
    145       this.snapshots.forEach(function(snapshot) {
    146         snapshot.ts += amount;
    147       });
    148     }
    149   };
    150 
    151   ObjectInstance.nameToConstructorMap_ = {};
    152   ObjectInstance.register = function(name, constructor) {
    153     if (ObjectInstance.nameToConstructorMap_[name])
    154       throw new Error('Constructor already registerd for ' + name);
    155     ObjectInstance.nameToConstructorMap_[name] = constructor;
    156   };
    157 
    158   ObjectInstance.unregister = function(name) {
    159     delete ObjectInstance.nameToConstructorMap_[name];
    160   };
    161 
    162   ObjectInstance.getConstructor = function(name) {
    163     if (ObjectInstance.nameToConstructorMap_[name])
    164       return ObjectInstance.nameToConstructorMap_[name];
    165     return ObjectInstance;
    166   };
    167 
    168   return {
    169     ObjectInstance: ObjectInstance
    170   };
    171 });
    172