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   var delegateList = {
     46     "log"         : log,
     47     "error"       : logError,
     48     "displayplot" : displayplot,
     49     "displayprof" : displayprof,
     50     "range"       : setRange,
     51     "script"      : scriptLoaded
     52   }
     53 
     54   function initialize() {
     55     ui.freeze();
     56     worker = new Worker("worker.js");
     57     running = false;
     58 
     59     worker.postMessage({ "call" : "load scripts",
     60                          "args" : worker_scripts });
     61 
     62     worker.addEventListener("message", function(event) {
     63       var call = delegateList[event.data["call"]];
     64       call(event.data["args"]);
     65     });
     66   }
     67 
     68   function scriptLoaded() {
     69     ui.thaw();
     70   }
     71 
     72   // Public methods.
     73   this.run = function(filename,
     74                       resx, resy,
     75                       distortion,
     76                       range_start, range_end) {
     77     var args = {
     78       'file'        : filename,
     79       'resx'        : resx,
     80       'resy'        : resy,
     81       'distortion'  : distortion,
     82       'range_start' : range_start,
     83       'range_end'   : range_end
     84     }
     85     worker.postMessage({ 'call' : 'run', 'args' : args });
     86   }
     87 
     88   this.reset = function() {
     89     if (worker) worker.terminate();
     90     initialize();
     91   }
     92 }
     93 
     94 
     95 function UIWrapper() {
     96   var input_elements = ["range_start",
     97                         "range_end",
     98                         "distortion",
     99                         "start",
    100                         "file"];
    101 
    102   var other_elements = ["log",
    103                         "plot",
    104                         "prof",
    105                         "instructions",
    106                         "credits",
    107                         "toggledisplay"];
    108 
    109   for (var i in input_elements) {
    110     var id = input_elements[i];
    111     this[id] = document.getElementById(id);
    112   }
    113 
    114   for (var i in other_elements) {
    115     var id = other_elements[i];
    116     this[id] = document.getElementById(id);
    117   }
    118 
    119   this.freeze = function() {
    120     this.plot.style.webkitFilter = "grayscale(1)";
    121     this.prof.style.color = "#bbb";
    122     for (var i in input_elements) {
    123       this[input_elements[i]].disabled = true;
    124     }
    125   }
    126 
    127   this.thaw = function() {
    128     this.plot.style.webkitFilter = "";
    129     this.prof.style.color = "#000";
    130     for (var i in input_elements) {
    131       this[input_elements[i]].disabled = false;
    132     }
    133   }
    134 
    135   this.reset = function() {
    136     this.thaw();
    137     this.log.value = "";
    138     this.range_start.value = "automatic";
    139     this.range_end.value = "automatic";
    140     this.toggle("plot");
    141     this.plot.src = "";
    142     this.prof.value = "";
    143   }
    144 
    145   this.toggle = function(mode) {
    146     if (mode) this.toggledisplay.next_mode = mode;
    147     if (this.toggledisplay.next_mode == "plot") {
    148       this.toggledisplay.next_mode = "prof";
    149       this.plot.style.display = "block";
    150       this.prof.style.display = "none";
    151       this.toggledisplay.innerHTML = "Show profile";
    152     } else {
    153       this.toggledisplay.next_mode = "plot";
    154       this.plot.style.display = "none";
    155       this.prof.style.display = "block";
    156       this.toggledisplay.innerHTML = "Show plot";
    157     }
    158   }
    159 
    160   this.info = function(field) {
    161     var down_arrow = "\u25bc";
    162     var right_arrow = "\u25b6";
    163     if (field && this[field].style.display != "none") field = null;  // Toggle.
    164     this.credits.style.display = "none";
    165     this.instructions.style.display = "none";
    166     if (!field) return;
    167     this[field].style.display = "block";
    168   }
    169 }
    170 
    171 
    172 function log(text) {
    173   ui.log.value += text;
    174   ui.log.scrollTop = ui.log.scrollHeight;
    175 }
    176 
    177 
    178 function logError(text) {
    179   if (ui.log.value.length > 0 &&
    180       ui.log.value[ui.log.value.length-1] != "\n") {
    181     ui.log.value += "\n";
    182   }
    183   ui.log.value += "ERROR: " + text + "\n";
    184   ui.log.scrollTop = ui.log.scrollHeight;
    185   error_logged = true;
    186 }
    187 
    188 
    189 function displayplot(args) {
    190   if (error_logged) {
    191     log("Plot failed.\n\n");
    192   } else {
    193     log("Displaying plot. Total time: " +
    194         (Date.now() - timer) / 1000 + "ms.\n\n");
    195     var blob = new Blob([new Uint8Array(args.contents).buffer],
    196                         { "type" : "image\/svg+xml" });
    197     window.URL = window.URL || window.webkitURL;
    198     ui.plot.src = window.URL.createObjectURL(blob);
    199   }
    200 
    201   ui.thaw();
    202   ui.toggle("plot");
    203 }
    204 
    205 
    206 function displayprof(args) {
    207   if (error_logged) return;
    208   ui.prof.value = args;
    209   this.prof.style.color = "";
    210   ui.toggle("prof");
    211 }
    212 
    213 
    214 function start(event) {
    215   error_logged = false;
    216   ui.freeze();
    217 
    218   try {
    219     var file = getSelectedFile();
    220     var distortion = getDistortion();
    221     var range = getRange();
    222   } catch (e) {
    223     logError(e.message);
    224     display();
    225     return;
    226   }
    227 
    228   timer = Date.now();
    229   worker.run(file, kResX, kResY, distortion, range[0], range[1]);
    230 }
    231 
    232 
    233 function getSelectedFile() {
    234   var file = ui.file.files[0];
    235   if (!file) throw Error("No valid file selected.");
    236   if (!file.type.toString().match(/text/)) {
    237     throw Error("'" + escape(file.name) + "' is not a text file.");
    238   }
    239   return file;
    240 }
    241 
    242 
    243 function getDistortion() {
    244   var input_distortion =
    245       parseInt(ui.distortion.value, 10);
    246   if (isNaN(input_distortion)) {
    247     input_distortion = ui.distortion.value = 4500;
    248   }
    249   return input_distortion / 1000000;
    250 }
    251 
    252 
    253 function getRange() {
    254   var input_start =
    255       parseInt(ui.range_start.value, 10);
    256   if (isNaN(input_start)) input_start = undefined;
    257   var input_end =
    258       parseInt(ui.range_end.value, 10);
    259   if (isNaN(input_end)) input_end = undefined;
    260   return [input_start, input_end];
    261 }
    262 
    263 
    264 function setRange(args) {
    265   ui.range_start.value = args.start.toFixed(1);
    266   ui.range_end.value = args.end.toFixed(1);
    267 }
    268 
    269 
    270 function onload() {
    271   kResX = 1200;
    272   kResY = 600;
    273   error_logged = false;
    274   ui = new UIWrapper();
    275   ui.reset();
    276   ui.info(null);
    277   worker = new plotWorker();
    278   worker.reset();
    279 }
    280 
    281 
    282 var kResX;
    283 var kResY;
    284 var error_logged;
    285 var ui;
    286 var worker;
    287 var timer;
    288