turbo-visualizer.js 9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

document.onload = (function(d3){
  "use strict";
  var jsonObj;
  var sourceExpandClassList = document.getElementById(SOURCE_EXPAND_ID).classList;
  var sourceCollapseClassList = document.getElementById(SOURCE_COLLAPSE_ID).classList;
  var sourceExpanded = sourceCollapseClassList.contains(COLLAPSE_PANE_BUTTON_VISIBLE);
  var disassemblyExpandClassList = document.getElementById(DISASSEMBLY_EXPAND_ID).classList;
  var disassemblyCollapseClassList = document.getElementById(DISASSEMBLY_COLLAPSE_ID).classList;
  var disassemblyExpanded = disassemblyCollapseClassList.contains(COLLAPSE_PANE_BUTTON_VISIBLE);
  var svg  = null;
  var graph = null;
  var schedule = null;
  var empty = null;
  var currentPhaseView = null;
  var disassemblyView = null;
  var sourceView = null;
  var selectionBroker = null;

  function updatePanes() {
    if (sourceExpanded) {
      if (disassemblyExpanded) {
        d3.select("#" + SOURCE_PANE_ID).style(WIDTH, "30%");
        d3.select("#" + INTERMEDIATE_PANE_ID).style(WIDTH, "40%");
        d3.select("#" + GENERATED_PANE_ID).style(WIDTH, "30%");
      } else {
        d3.select("#" + SOURCE_PANE_ID).style(WIDTH, "50%");
        d3.select("#" + INTERMEDIATE_PANE_ID).style(WIDTH, "50%");
        d3.select("#" + GENERATED_PANE_ID).style(WIDTH, "0%");
      }
    } else {
      if (disassemblyExpanded) {
        d3.select("#" + SOURCE_PANE_ID).style(WIDTH, "0%");
        d3.select("#" + INTERMEDIATE_PANE_ID).style(WIDTH, "50%");
        d3.select("#" + GENERATED_PANE_ID).style(WIDTH, "50%");
      } else {
        d3.select("#" + SOURCE_PANE_ID).style(WIDTH, "0%");
        d3.select("#" + INTERMEDIATE_PANE_ID).style(WIDTH, "100%");
        d3.select("#" + GENERATED_PANE_ID).style(WIDTH, "0%");
      }
    }
  }

47 48 49 50 51 52 53 54 55 56
  function getLastExpandedState(type, default_state) {
    var state = window.sessionStorage.getItem("expandedState-"+type);
    if (state === null) return default_state;
    return state === 'true';
  }

  function setLastExpandedState(type, state) {
    window.sessionStorage.setItem("expandedState-"+type, state);
  }

57 58 59 60
  function toggleSourceExpanded() {
    setSourceExpanded(!sourceExpanded);
  }

61 62
  function setSourceExpanded(newState) {
    sourceExpanded = newState;
63
    setLastExpandedState("source", newState);
64 65 66 67 68 69 70 71 72 73 74 75 76 77
    updatePanes();
    if (newState) {
      sourceCollapseClassList.add(COLLAPSE_PANE_BUTTON_VISIBLE);
      sourceCollapseClassList.remove(COLLAPSE_PANE_BUTTON_INVISIBLE);
      sourceExpandClassList.add(COLLAPSE_PANE_BUTTON_INVISIBLE);
      sourceExpandClassList.remove(COLLAPSE_PANE_BUTTON_VISIBLE);
    } else {
      sourceCollapseClassList.add(COLLAPSE_PANE_BUTTON_INVISIBLE);
      sourceCollapseClassList.remove(COLLAPSE_PANE_BUTTON_VISIBLE);
      sourceExpandClassList.add(COLLAPSE_PANE_BUTTON_VISIBLE);
      sourceExpandClassList.remove(COLLAPSE_PANE_BUTTON_INVISIBLE);
    }
  }

78 79 80 81
  function toggleDisassemblyExpanded() {
    setDisassemblyExpanded(!disassemblyExpanded);
  }

82 83
  function setDisassemblyExpanded(newState) {
    disassemblyExpanded = newState;
84
    setLastExpandedState("disassembly", newState);
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
    updatePanes();
    if (newState) {
      disassemblyCollapseClassList.add(COLLAPSE_PANE_BUTTON_VISIBLE);
      disassemblyCollapseClassList.remove(COLLAPSE_PANE_BUTTON_INVISIBLE);
      disassemblyExpandClassList.add(COLLAPSE_PANE_BUTTON_INVISIBLE);
      disassemblyExpandClassList.remove(COLLAPSE_PANE_BUTTON_VISIBLE);
    } else {
      disassemblyCollapseClassList.add(COLLAPSE_PANE_BUTTON_INVISIBLE);
      disassemblyCollapseClassList.remove(COLLAPSE_PANE_BUTTON_VISIBLE);
      disassemblyExpandClassList.add(COLLAPSE_PANE_BUTTON_VISIBLE);
      disassemblyExpandClassList.remove(COLLAPSE_PANE_BUTTON_INVISIBLE);
    }
  }

  function hideCurrentPhase() {
    var rememberedSelection = null;
    if (currentPhaseView != null) {
      rememberedSelection = currentPhaseView.detachSelection();
      currentPhaseView.hide();
      currentPhaseView = null;
    }
    return rememberedSelection;
  }

  function displayPhaseView(view, data) {
    var rememberedSelection = hideCurrentPhase();
    view.show(data, rememberedSelection);
    d3.select("#middle").classed("scrollable", view.isScrollable());
    currentPhaseView = view;
  }

  function displayPhase(phase) {
    if (phase.type == 'graph') {
      displayPhaseView(graph, phase.data);
    } else if (phase.type == 'schedule') {
      displayPhaseView(schedule, phase.data);
    } else {
      displayPhaseView(empty, null);
    }
  }

  function fitPanesToParents() {
    d3.select("#left").classed("scrollable", false)
    d3.select("#right").classed("scrollable", false);

    graph.fitGraphViewToWindow();
    disassemblyView.resizeToParent();
    sourceView.resizeToParent();

    d3.select("#left").classed("scrollable", true);
    d3.select("#right").classed("scrollable", true);
  }

  selectionBroker = new SelectionBroker();

  function initializeHandlers(g) {
141 142
    d3.select("#source-collapse").on("click", function(){
      toggleSourceExpanded(true);
143 144
      setTimeout(function(){
        g.fitGraphViewToWindow();
145
      }, 300);
146
    });
147 148
    d3.select("#disassembly-collapse").on("click", function(){
      toggleDisassemblyExpanded();
149 150
      setTimeout(function(){
        g.fitGraphViewToWindow();
151
      }, 300);
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
    });
    window.onresize = function(){
      fitPanesToParents();
    };
    d3.select("#hidden-file-upload").on("change", function() {
      if (window.File && window.FileReader && window.FileList) {
        var uploadFile = this.files[0];
        var filereader = new window.FileReader();
        var consts = Node.consts;
        filereader.onload = function(){
          var txtRes = filereader.result;
          // If the JSON isn't properly terminated, assume compiler crashed and
          // add best-guess empty termination
          if (txtRes[txtRes.length-2] == ',') {
            txtRes += '{"name":"disassembly","type":"disassembly","data":""}]}';
          }
          try{
            jsonObj = JSON.parse(txtRes);

171 172
            hideCurrentPhase();

173 174
            selectionBroker.setNodePositionMap(jsonObj.nodePositions);

175
            sourceView.initializeCode(jsonObj.source, jsonObj.sourcePosition);
176
            disassemblyView.initializeCode(jsonObj.source);
177 178 179 180 181 182 183 184 185 186 187 188 189

            var selectMenu = document.getElementById('display-selector');
            var disassemblyPhase = null;
            selectMenu.innerHTML = '';
            for (var i = 0; i < jsonObj.phases.length; ++i) {
              var optionElement = document.createElement("option");
              optionElement.text = jsonObj.phases[i].name;
              if (optionElement.text == 'disassembly') {
                disassemblyPhase = jsonObj.phases[i];
              } else {
                selectMenu.add(optionElement, null);
              }
            }
190 191

            disassemblyView.initializePerfProfile(jsonObj.eventCounts);
192 193
            disassemblyView.show(disassemblyPhase.data, null);

194 195 196 197 198 199 200 201 202
            var initialPhaseIndex = +window.sessionStorage.getItem("lastSelectedPhase");
            if (!(initialPhaseIndex in jsonObj.phases)) {
              initialPhaseIndex = 0;
            }

            // We wish to show the remembered phase {lastSelectedPhase}, but
            // this will crash if the first view we switch to is a
            // ScheduleView. So we first switch to the first phase, which
            // should never be a ScheduleView.
203
            displayPhase(jsonObj.phases[0]);
204 205
            displayPhase(jsonObj.phases[initialPhaseIndex]);
            selectMenu.selectedIndex = initialPhaseIndex;
206 207

            selectMenu.onchange = function(item) {
208
              window.sessionStorage.setItem("lastSelectedPhase", selectMenu.selectedIndex);
209 210 211 212
              displayPhase(jsonObj.phases[selectMenu.selectedIndex]);
            }

            fitPanesToParents();
213 214 215

            d3.select("#search-input").attr("value", window.sessionStorage.getItem("lastSearch") || "");

216 217
          }
          catch(err) {
218 219 220
            window.console.log("caught exception, clearing session storage just in case");
            window.sessionStorage.clear(); // just in case
            window.console.log("showing error");
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
            window.alert("Invalid TurboFan JSON file\n" +
                         "error: " + err.message);
            return;
          }
        };
        filereader.readAsText(uploadFile);
      } else {
        alert("Can't load graph");
      }
    });
  }

  sourceView = new CodeView(SOURCE_PANE_ID, PR, "", 0, selectionBroker);
  disassemblyView = new DisassemblyView(DISASSEMBLY_PANE_ID, selectionBroker);
  graph = new GraphView(d3, GRAPH_PANE_ID, [], [], selectionBroker);
  schedule = new ScheduleView(SCHEDULE_PANE_ID, selectionBroker);
  empty = new EmptyView(EMPTY_PANE_ID, selectionBroker);

  initializeHandlers(graph);

241 242
  setSourceExpanded(getLastExpandedState("source", true));
  setDisassemblyExpanded(getLastExpandedState("disassembly", false));
243 244 245 246

  displayPhaseView(empty, null);
  fitPanesToParents();
})(window.d3);