Home | History | Annotate | Download | only in profviz
      1 // Copyright 2013 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 var worker_scripts = [
     29   "../csvparser.js",
     30   "../splaytree.js",
     31   "../codemap.js",
     32   "../consarray.js",
     33   "../profile.js",
     34   "../profile_view.js",
     35   "../logreader.js",
     36   "../tickprocessor.js",
     37   "composer.js",
     38   "gnuplot-4.6.3-emscripten.js"
     39 ];
     40 
     41 
     42 function plotWorker() {
     43   var worker = null;
     44 
     45   function initialize() {
     46     ui.freeze();
     47     worker = new Worker("worker.js");
     48     running = false;
     49 
     50     worker.postMessage({ "call" : "load scripts",
     51                          "args" : worker_scripts });
     52 
     53     worker.addEventListener("message", function(event) {
     54       var call = delegateList[event.data["call"]];
     55       call(event.data["args"]);
     56     });
     57   }
     58 
     59   function scriptLoaded() {
     60     ui.thaw();
     61   }
     62 
     63   // Public methods.
     64   this.run = function(filename,
     65                       resx, resy,
     66                       distortion,
     67                       range_start, range_end) {
     68     var args = {
     69       'file'        : filename,
     70       'resx'        : resx,
     71       'resy'        : resy,
     72       'distortion'  : distortion,
     73       'range_start' : range_start,
     74       'range_end'   : range_end
     75     }
     76     worker.postMessage({ 'call' : 'run', 'args' : args });
     77   }
     78 
     79   this.reset = function() {
     80     if (worker) worker.terminate();
     81     initialize();
     82   }
     83 
     84   var delegateList = {
     85     "log"         : log,
     86     "error"       : logError,
     87     "displayplot" : displayplot,
     88     "displayprof" : displayprof,
     89     "range"       : setRange,
     90     "script"      : scriptLoaded,
     91     "reset"       : this.reset
     92   }
     93 }
     94 
     95 
     96 function UIWrapper() {
     97   var input_elements = ["range_start",
     98                         "range_end",
     99                         "distortion",
    100                         "start",
    101                         "file"];
    102 
    103   var other_elements = ["log",
    104                         "plot",
    105                         "prof",
    106                         "instructions",
    107                         "credits",
    108                         "toggledisplay"];
    109 
    110   for (var i in input_elements) {
    111     var id = input_elements[i];
    112     this[id] = document.getElementById(id);
    113   }
    114 
    115   for (var i in other_elements) {
    116     var id = other_elements[i];
    117     this[id] = document.getElementById(id);
    118   }
    119 
    120   this.freeze = function() {
    121     this.plot.style.webkitFilter = "grayscale(1)";
    122     this.prof.style.color = "#bbb";
    123     for (var i in input_elements) {
    124       this[input_elements[i]].disabled = true;
    125     }
    126   }
    127 
    128   this.thaw = function() {
    129     this.plot.style.webkitFilter = "";
    130     this.prof.style.color = "#000";
    131     for (var i in input_elements) {
    132       this[input_elements[i]].disabled = false;
    133     }
    134   }
    135 
    136   this.reset = function() {
    137     this.thaw();
    138     this.log.value = "";
    139     this.range_start.value = "automatic";
    140     this.range_end.value = "automatic";
    141     this.toggle("plot");
    142     this.plot.src = "";
    143     this.prof.value = "";
    144   }
    145 
    146   this.toggle = function(mode) {
    147     if (mode) this.toggledisplay.next_mode = mode;
    148     if (this.toggledisplay.next_mode == "plot") {
    149       this.toggledisplay.next_mode = "prof";
    150       this.plot.style.display = "block";
    151       this.prof.style.display = "none";
    152       this.toggledisplay.innerHTML = "Show profile";
    153     } else {
    154       this.toggledisplay.next_mode = "plot";
    155       this.plot.style.display = "none";
    156       this.prof.style.display = "block";
    157       this.toggledisplay.innerHTML = "Show plot";
    158     }
    159   }
    160 
    161   this.info = function(field) {
    162     var down_arrow = "\u25bc";
    163     var right_arrow = "\u25b6";
    164     if (field && this[field].style.display != "none") field = null;  // Toggle.
    165     this.credits.style.display = "none";
    166     this.instructions.style.display = "none";
    167     if (!field) return;
    168     this[field].style.display = "block";
    169   }
    170 }
    171 
    172 
    173 function log(text) {
    174   ui.log.value += text;
    175   ui.log.scrollTop = ui.log.scrollHeight;
    176 }
    177 
    178 
    179 function logError(text) {
    180   if (ui.log.value.length > 0 &&
    181       ui.log.value[ui.log.value.length-1] != "\n") {
    182     ui.log.value += "\n";
    183   }
    184   ui.log.value += "ERROR: " + text + "\n";
    185   ui.log.scrollTop = ui.log.scrollHeight;
    186   error_logged = true;
    187 }
    188 
    189 
    190 function displayplot(args) {
    191   if (error_logged) {
    192     log("Plot failed.\n\n");
    193   } else {
    194     log("Displaying plot. Total time: " +
    195         (Date.now() - timer) / 1000 + "ms.\n\n");
    196     var blob = new Blob([new Uint8Array(args.contents).buffer],
    197                         { "type" : "image\/svg+xml" });
    198     window.URL = window.URL || window.webkitURL;
    199     ui.plot.src = window.URL.createObjectURL(blob);
    200   }
    201 
    202   ui.thaw();
    203   ui.toggle("plot");
    204 }
    205 
    206 
    207 function displayprof(args) {
    208   if (error_logged) return;
    209   ui.prof.value = args;
    210   this.prof.style.color = "";
    211   ui.toggle("prof");
    212 }
    213 
    214 
    215 function start(event) {
    216   error_logged = false;
    217   ui.freeze();
    218 
    219   try {
    220     var file = getSelectedFile();
    221     var distortion = getDistortion();
    222     var range = getRange();
    223   } catch (e) {
    224     logError(e.message);
    225     display();
    226     return;
    227   }
    228 
    229   timer = Date.now();
    230   worker.run(file, kResX, kResY, distortion, range[0], range[1]);
    231 }
    232 
    233 
    234 function getSelectedFile() {
    235   var file = ui.file.files[0];
    236   if (!file) throw Error("No valid file selected.");
    237   return file;
    238 }
    239 
    240 
    241 function getDistortion() {
    242   var input_distortion =
    243       parseInt(ui.distortion.value, 10);
    244   if (isNaN(input_distortion)) {
    245     input_distortion = ui.distortion.value = 4500;
    246   }
    247   return input_distortion / 1000000;
    248 }
    249 
    250 
    251 function getRange() {
    252   var input_start =
    253       parseInt(ui.range_start.value, 10);
    254   if (isNaN(input_start)) input_start = undefined;
    255   var input_end =
    256       parseInt(ui.range_end.value, 10);
    257   if (isNaN(input_end)) input_end = undefined;
    258   return [input_start, input_end];
    259 }
    260 
    261 
    262 function setRange(args) {
    263   ui.range_start.value = args.start.toFixed(1);
    264   ui.range_end.value = args.end.toFixed(1);
    265 }
    266 
    267 
    268 function onload() {
    269   kResX = 1200;
    270   kResY = 600;
    271   error_logged = false;
    272   ui = new UIWrapper();
    273   ui.reset();
    274   ui.info(null);
    275   worker = new plotWorker();
    276   worker.reset();
    277 }
    278 
    279 
    280 var kResX;
    281 var kResY;
    282 var error_logged;
    283 var ui;
    284 var worker;
    285 var timer;
    286