browser/devtools/profiler/cleopatra/js/ProgressReporter.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rwxr-xr-x

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 /**
     6  * ProgressReporter
     7  *
     8  * This class is used by long-winded tasks to report progress to observers.
     9  * If a task has subtasks that want to report their own progress, these
    10  * subtasks can have their own progress reporters which are hooked up to the
    11  * parent progress reporter, resulting in a tree structure. A parent progress
    12  * reporter will calculate its progress value as a weighted sum of its
    13  * subreporters' progress values.
    14  *
    15  * A progress reporter has a state, an action, and a progress value.
    16  *
    17  *  - state is one of STATE_WAITING, STATE_DOING and STATE_FINISHED.
    18  *  - action is a string that describes the current task.
    19  *  - progress is the progress value as a number between 0 and 1, or NaN if
    20  *    indeterminate.
    21  *
    22  * A progress reporter starts out in the WAITING state. The DOING state is
    23  * entered with the begin method which also sets the action. While the task is
    24  * executing, the progress value can be updated with the setProgress method.
    25  * When a task has finished, it can call the finish method which is just a
    26  * shorthand for setProgress(1); this will set the state to FINISHED.
    27  *
    28  * Progress observers can be added with the addListener method which takes a
    29  * function callback. Whenever the progress value or state change, all
    30  * listener callbacks will be called with the progress reporter object. The
    31  * observer can get state, progress value and action by calling the getter
    32  * methods getState(), getProgress() and getAction().
    33  *
    34  * Creating child progress reporters for subtasks can be done with the
    35  * addSubreporter(s) methods. If a progress reporter has subreporters, normal
    36  * progress report functions (setProgress and finish) can no longer be called.
    37  * Instead, the parent reporter will listen to progress changes on its
    38  * subreporters and update its state automatically, and then notify its own
    39  * listeners.
    40  * When adding a subreporter, you are expected to provide an estimated
    41  * duration for the subtask. This value will be used as a weight when
    42  * calculating the progress of the parent reporter.
    43  */
    45 "use strict";
    47 const gDebugExpectedDurations = false;
    49 function ProgressReporter() {
    50   this._observers = [];
    51   this._subreporters = [];
    52   this._subreporterExpectedDurationsSum = 0;
    53   this._progress = 0;
    54   this._state = ProgressReporter.STATE_WAITING;
    55   this._action = "";
    56 }
    58 ProgressReporter.STATE_WAITING = 0;
    59 ProgressReporter.STATE_DOING = 1;
    60 ProgressReporter.STATE_FINISHED = 2;
    62 ProgressReporter.prototype = {
    63   getProgress: function () {
    64     return this._progress;
    65   },
    66   getState: function () {
    67     return this._state;
    68   },
    69   setAction: function (action) {
    70     this._action = action;
    71     this._reportProgress();
    72   },
    73   getAction: function () {
    74     switch (this._state) {
    75       case ProgressReporter.STATE_WAITING:
    76         return "Waiting for preceding tasks to finish...";
    77       case ProgressReporter.STATE_DOING:
    78         return this._action;
    79       case ProgressReporter.STATE_FINISHED:
    80         return "Finished.";
    81       default:
    82         throw "Broken state";
    83     }
    84   },
    85   addListener: function (callback) {
    86     this._observers.push(callback);
    87   },
    88   addSubreporter: function (expectedDuration) {
    89     this._subreporterExpectedDurationsSum += expectedDuration;
    90     var subreporter = new ProgressReporter();
    91     var self = this;
    92     subreporter.addListener(function (progress) {
    93       self._recalculateProgressFromSubreporters();
    94       self._recalculateStateAndActionFromSubreporters();
    95       self._reportProgress();
    96     });
    97     this._subreporters.push({ expectedDuration: expectedDuration, reporter: subreporter });
    98     return subreporter;
    99   },
   100   addSubreporters: function (expectedDurations) {
   101     var reporters = {};
   102     for (var key in expectedDurations) {
   103       reporters[key] = this.addSubreporter(expectedDurations[key]);
   104     }
   105     return reporters;
   106   },
   107   begin: function (action) {
   108     this._startTime = Date.now();
   109     this._state = ProgressReporter.STATE_DOING;
   110     this._action = action;
   111     this._reportProgress();
   112   },
   113   setProgress: function (progress) {
   114     if (this._subreporters.length > 0)
   115       throw "Can't call setProgress on a progress reporter with subreporters";
   116     if (progress != this._progress &&
   117         (progress == 1 ||
   118          (isNaN(progress) != isNaN(this._progress)) ||
   119          (progress - this._progress >= 0.01))) {
   120       this._progress = progress;
   121       if (progress == 1)
   122         this._transitionToFinished();
   123       this._reportProgress();
   124     }
   125   },
   126   finish: function () {
   127     this.setProgress(1);
   128   },
   129   _recalculateProgressFromSubreporters: function () {
   130     if (this._subreporters.length == 0)
   131       throw "Can't _recalculateProgressFromSubreporters on a progress reporter without any subreporters";
   132     this._progress = 0;
   133     for (var i = 0; i < this._subreporters.length; i++) {
   134       var expectedDuration = this._subreporters[i].expectedDuration;
   135       var reporter = this._subreporters[i].reporter;
   136       this._progress += reporter.getProgress() * expectedDuration / this._subreporterExpectedDurationsSum;
   137     }
   138   },
   139   _recalculateStateAndActionFromSubreporters: function () {
   140     if (this._subreporters.length == 0)
   141       throw "Can't _recalculateStateAndActionFromSubreporters on a progress reporter without any subreporters";
   142     var actions = [];
   143     var allWaiting = true;
   144     var allFinished = true;
   145     for (var i = 0; i < this._subreporters.length; i++) {
   146       var expectedDuration = this._subreporters[i].expectedDuration;
   147       var reporter = this._subreporters[i].reporter;
   148       var state = reporter.getState();
   149       if (state != ProgressReporter.STATE_WAITING)
   150         allWaiting = false;
   151       if (state != ProgressReporter.STATE_FINISHED)
   152         allFinished = false;
   153       if (state == ProgressReporter.STATE_DOING)
   154         actions.push(reporter.getAction());
   155     }
   156     if (allFinished) {
   157       this._transitionToFinished();
   158     } else if (!allWaiting) {
   159       this._state = ProgressReporter.STATE_DOING;
   160       if (actions.length == 0) {
   161         this._action = "About to start next task..."
   162       } else {
   163         this._action = actions.join("\n");
   164       }
   165     }
   166   },
   167   _transitionToFinished: function () {
   168     this._state = ProgressReporter.STATE_FINISHED;
   170     if (gDebugExpectedDurations) {
   171       this._realDuration = Date.now() - this._startTime;
   172       if (this._subreporters.length) {
   173         for (var i = 0; i < this._subreporters.length; i++) {
   174           var expectedDuration = this._subreporters[i].expectedDuration;
   175           var reporter = this._subreporters[i].reporter;
   176           var realDuration = reporter._realDuration;
   177           dump("For reporter with expectedDuration " + expectedDuration + ", real duration was " + realDuration + "\n");
   178         }
   179       }
   180     }
   181   },
   182   _reportProgress: function () {
   183     for (var i = 0; i < this._observers.length; i++) {
   184       this._observers[i](this);
   185     }
   186   },
   187 };

mercurial