11cb0ef41Sopenharmony_ci<!DOCTYPE html>
21cb0ef41Sopenharmony_ci<html>
31cb0ef41Sopenharmony_ci<!--
41cb0ef41Sopenharmony_ciCopyright 2016 the V8 project authors. All rights reserved.  Use of this source
51cb0ef41Sopenharmony_cicode is governed by a BSD-style license that can be found in the LICENSE file.
61cb0ef41Sopenharmony_ci-->
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_ci<head>
91cb0ef41Sopenharmony_ci<meta charset="utf-8">
101cb0ef41Sopenharmony_ci<title>V8 Parse Processor</title>
111cb0ef41Sopenharmony_ci<style>
121cb0ef41Sopenharmony_ci  html {
131cb0ef41Sopenharmony_ci    font-family: monospace;
141cb0ef41Sopenharmony_ci  }
151cb0ef41Sopenharmony_ci
161cb0ef41Sopenharmony_ci  .parse {
171cb0ef41Sopenharmony_ci    background-color: red;
181cb0ef41Sopenharmony_ci    border: 1px red solid;
191cb0ef41Sopenharmony_ci  }
201cb0ef41Sopenharmony_ci
211cb0ef41Sopenharmony_ci  .preparse {
221cb0ef41Sopenharmony_ci    background-color: orange;
231cb0ef41Sopenharmony_ci    border: 1px orange solid;
241cb0ef41Sopenharmony_ci  }
251cb0ef41Sopenharmony_ci
261cb0ef41Sopenharmony_ci  .resolution {
271cb0ef41Sopenharmony_ci    background-color: green;
281cb0ef41Sopenharmony_ci    border: 1px green solid;
291cb0ef41Sopenharmony_ci  }
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_ci  .execution {
321cb0ef41Sopenharmony_ci    background-color: black;
331cb0ef41Sopenharmony_ci    border-left: 2px black solid;
341cb0ef41Sopenharmony_ci    z-index: -1;
351cb0ef41Sopenharmony_ci  }
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_ci  .script {
381cb0ef41Sopenharmony_ci    margin-top: 1em;
391cb0ef41Sopenharmony_ci    overflow: visible;
401cb0ef41Sopenharmony_ci    clear: both;
411cb0ef41Sopenharmony_ci      border-top: 2px black dotted;
421cb0ef41Sopenharmony_ci  }
431cb0ef41Sopenharmony_ci  .script h3 {
441cb0ef41Sopenharmony_ci    height: 20px;
451cb0ef41Sopenharmony_ci    margin-bottom: 0.5em;
461cb0ef41Sopenharmony_ci    white-space: nowrap;
471cb0ef41Sopenharmony_ci  }
481cb0ef41Sopenharmony_ci
491cb0ef41Sopenharmony_ci  .script-details {
501cb0ef41Sopenharmony_ci    float: left;
511cb0ef41Sopenharmony_ci  }
521cb0ef41Sopenharmony_ci
531cb0ef41Sopenharmony_ci  .chart {
541cb0ef41Sopenharmony_ci    float: left;
551cb0ef41Sopenharmony_ci    margin-right: 2em;
561cb0ef41Sopenharmony_ci  }
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_ci  .funktion-list {
591cb0ef41Sopenharmony_ci    float: left;
601cb0ef41Sopenharmony_ci    height: 400px;
611cb0ef41Sopenharmony_ci  }
621cb0ef41Sopenharmony_ci
631cb0ef41Sopenharmony_ci  .funktion-list > ul {
641cb0ef41Sopenharmony_ci    height: 80%;
651cb0ef41Sopenharmony_ci    overflow-y: scroll;
661cb0ef41Sopenharmony_ci  }
671cb0ef41Sopenharmony_ci
681cb0ef41Sopenharmony_ci  .funktion {
691cb0ef41Sopenharmony_ci  }
701cb0ef41Sopenharmony_ci
711cb0ef41Sopenharmony_ci  .script-size {
721cb0ef41Sopenharmony_ci    display: inline-flex;
731cb0ef41Sopenharmony_ci    background-color: #505050;
741cb0ef41Sopenharmony_ci    border-radius: 3px;
751cb0ef41Sopenharmony_ci    padding: 3px;
761cb0ef41Sopenharmony_ci    margin: 2px;
771cb0ef41Sopenharmony_ci    white-space: nowrap;
781cb0ef41Sopenharmony_ci    overflow: hidden;
791cb0ef41Sopenharmony_ci    text-decoration: none;
801cb0ef41Sopenharmony_ci    color: white;
811cb0ef41Sopenharmony_ci    transition: auto ease-in-out 0.8s;
821cb0ef41Sopenharmony_ci    max-width: 500px;
831cb0ef41Sopenharmony_ci  }
841cb0ef41Sopenharmony_ci  .script-size:hover {
851cb0ef41Sopenharmony_ci    max-width: 100000px !important;
861cb0ef41Sopenharmony_ci    transition: auto ease-in-out 0.8s;
871cb0ef41Sopenharmony_ci  }
881cb0ef41Sopenharmony_ci  .script-size.eval {
891cb0ef41Sopenharmony_ci    background-color: #ee6300fc;
901cb0ef41Sopenharmony_ci  }
911cb0ef41Sopenharmony_ci  .script-size.streaming {
921cb0ef41Sopenharmony_ci    background-color: #008aff;
931cb0ef41Sopenharmony_ci  }
941cb0ef41Sopenharmony_ci  .script-size.deserialized {
951cb0ef41Sopenharmony_ci    background-color: #1fad00fc;
961cb0ef41Sopenharmony_ci  }
971cb0ef41Sopenharmony_ci
981cb0ef41Sopenharmony_ci  .script-details {
991cb0ef41Sopenharmony_ci    padding-right: 5px;
1001cb0ef41Sopenharmony_ci    margin-right: 4px;
1011cb0ef41Sopenharmony_ci  }
1021cb0ef41Sopenharmony_ci  /* all but the last need a border  */
1031cb0ef41Sopenharmony_ci  .script-details:nth-last-child(n+2) {
1041cb0ef41Sopenharmony_ci    border-right: 1px white solid;
1051cb0ef41Sopenharmony_ci  }
1061cb0ef41Sopenharmony_ci
1071cb0ef41Sopenharmony_ci  .script-details.id {
1081cb0ef41Sopenharmony_ci    min-width: 2em;
1091cb0ef41Sopenharmony_ci    text-align: right;
1101cb0ef41Sopenharmony_ci  }
1111cb0ef41Sopenharmony_ci</style>
1121cb0ef41Sopenharmony_ci<script src="https://www.gstatic.com/charts/loader.js"></script>
1131cb0ef41Sopenharmony_ci<script type="module">
1141cb0ef41Sopenharmony_ci
1151cb0ef41Sopenharmony_ciimport { ParseProcessor, kSecondsToMillis, BYTES, PERCENT } from "./parse-processor.mjs";
1161cb0ef41Sopenharmony_ci
1171cb0ef41Sopenharmony_cigoogle.charts.load('current', {packages: ['corechart']});
1181cb0ef41Sopenharmony_ci
1191cb0ef41Sopenharmony_cifunction $(query) {
1201cb0ef41Sopenharmony_ci  return document.querySelector(query);
1211cb0ef41Sopenharmony_ci}
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_ciwindow.addEventListener('DOMContentLoaded', (event) => {
1241cb0ef41Sopenharmony_ci  $("#uploadInput").focus();
1251cb0ef41Sopenharmony_ci});
1261cb0ef41Sopenharmony_ci
1271cb0ef41Sopenharmony_cidocument.loadFile = function() {
1281cb0ef41Sopenharmony_ci  let files = $('#uploadInput').files;
1291cb0ef41Sopenharmony_ci
1301cb0ef41Sopenharmony_ci  let file = files[0];
1311cb0ef41Sopenharmony_ci  let reader = new FileReader();
1321cb0ef41Sopenharmony_ci
1331cb0ef41Sopenharmony_ci  reader.onload = function(evt) {
1341cb0ef41Sopenharmony_ci    const kTimerName = 'parse log file';
1351cb0ef41Sopenharmony_ci    console.time(kTimerName);
1361cb0ef41Sopenharmony_ci    let parseProcessor = new ParseProcessor();
1371cb0ef41Sopenharmony_ci    parseProcessor.processString(this.result);
1381cb0ef41Sopenharmony_ci    console.timeEnd(kTimerName);
1391cb0ef41Sopenharmony_ci    renderParseResults(parseProcessor);
1401cb0ef41Sopenharmony_ci    document.parseProcessor = parseProcessor;
1411cb0ef41Sopenharmony_ci  }
1421cb0ef41Sopenharmony_ci  reader.readAsText(file);
1431cb0ef41Sopenharmony_ci}
1441cb0ef41Sopenharmony_ci
1451cb0ef41Sopenharmony_cifunction createNode(tag, classNames) {
1461cb0ef41Sopenharmony_ci  let node = document.createElement(tag);
1471cb0ef41Sopenharmony_ci  if (classNames) {
1481cb0ef41Sopenharmony_ci    if (Array.isArray(classNames)) {
1491cb0ef41Sopenharmony_ci      node.classList.add(...classNames);
1501cb0ef41Sopenharmony_ci    } else {
1511cb0ef41Sopenharmony_ci      node.className = classNames;
1521cb0ef41Sopenharmony_ci    }
1531cb0ef41Sopenharmony_ci  }
1541cb0ef41Sopenharmony_ci  return node;
1551cb0ef41Sopenharmony_ci}
1561cb0ef41Sopenharmony_ci
1571cb0ef41Sopenharmony_cifunction div(...args) {
1581cb0ef41Sopenharmony_ci  return createNode('div', ...args);
1591cb0ef41Sopenharmony_ci}
1601cb0ef41Sopenharmony_ci
1611cb0ef41Sopenharmony_cifunction h1(string) {
1621cb0ef41Sopenharmony_ci  let node = createNode('h1');
1631cb0ef41Sopenharmony_ci  node.appendChild(text(string));
1641cb0ef41Sopenharmony_ci  return node;
1651cb0ef41Sopenharmony_ci}
1661cb0ef41Sopenharmony_ci
1671cb0ef41Sopenharmony_cifunction h3(string, ...args) {
1681cb0ef41Sopenharmony_ci  let node = createNode('h3', ...args);
1691cb0ef41Sopenharmony_ci  if (string) node.appendChild(text(string));
1701cb0ef41Sopenharmony_ci  return node;
1711cb0ef41Sopenharmony_ci}
1721cb0ef41Sopenharmony_ci
1731cb0ef41Sopenharmony_cifunction a(href, string, ...args) {
1741cb0ef41Sopenharmony_ci  let link = createNode('a', ...args);
1751cb0ef41Sopenharmony_ci  if (href.length) link.href = href;
1761cb0ef41Sopenharmony_ci  if (string) link.appendChild(text(string));
1771cb0ef41Sopenharmony_ci  return link;
1781cb0ef41Sopenharmony_ci}
1791cb0ef41Sopenharmony_ci
1801cb0ef41Sopenharmony_cifunction text(string) {
1811cb0ef41Sopenharmony_ci  return document.createTextNode(string);
1821cb0ef41Sopenharmony_ci}
1831cb0ef41Sopenharmony_ci
1841cb0ef41Sopenharmony_cifunction delay(t) {
1851cb0ef41Sopenharmony_ci  return new Promise(resolve => setTimeout(resolve, t));
1861cb0ef41Sopenharmony_ci}
1871cb0ef41Sopenharmony_ci
1881cb0ef41Sopenharmony_cifunction renderParseResults(parseProcessor) {
1891cb0ef41Sopenharmony_ci  let result = $('#result');
1901cb0ef41Sopenharmony_ci  // clear out all existing result pages;
1911cb0ef41Sopenharmony_ci  result.innerHTML = '';
1921cb0ef41Sopenharmony_ci  const start = parseProcessor.firstEventTimestamp;
1931cb0ef41Sopenharmony_ci  const end = parseProcessor.lastEventTimestamp;
1941cb0ef41Sopenharmony_ci  renderScript(result, parseProcessor.totalScript, start, end);
1951cb0ef41Sopenharmony_ci  // Build up the graphs lazily to keep the page responsive.
1961cb0ef41Sopenharmony_ci  parseProcessor.scripts.forEach(
1971cb0ef41Sopenharmony_ci      script => renderScript(result, script, start, end));
1981cb0ef41Sopenharmony_ci  renderScriptSizes(parseProcessor);
1991cb0ef41Sopenharmony_ci  // Install an intersection observer to lazily load the graphs when the script
2001cb0ef41Sopenharmony_ci  // div becomes visible for the first time.
2011cb0ef41Sopenharmony_ci  var io = new IntersectionObserver((entries, observer) => {
2021cb0ef41Sopenharmony_ci    entries.forEach(entry => {
2031cb0ef41Sopenharmony_ci      if (entry.intersectionRatio == 0) return;
2041cb0ef41Sopenharmony_ci      console.assert(!entry.target.querySelector('.graph'));
2051cb0ef41Sopenharmony_ci      let target = entry.target;
2061cb0ef41Sopenharmony_ci      appendGraph(target.script, target, start, end);
2071cb0ef41Sopenharmony_ci      observer.unobserve(entry.target);
2081cb0ef41Sopenharmony_ci    });
2091cb0ef41Sopenharmony_ci  }, {rootMargin: '400px'});
2101cb0ef41Sopenharmony_ci  document.querySelectorAll('.script').forEach(div => io.observe(div));
2111cb0ef41Sopenharmony_ci}
2121cb0ef41Sopenharmony_ci
2131cb0ef41Sopenharmony_ciconst kTimeFactor = 10;
2141cb0ef41Sopenharmony_ciconst kHeight = 20;
2151cb0ef41Sopenharmony_ciconst kFunktionTopOffset = 50;
2161cb0ef41Sopenharmony_ci
2171cb0ef41Sopenharmony_cifunction renderScript(result, script, start, end) {
2181cb0ef41Sopenharmony_ci  // Filter out empty scripts.
2191cb0ef41Sopenharmony_ci  if (script.isEmpty() || script.lastParseEvent == 0) return;
2201cb0ef41Sopenharmony_ci
2211cb0ef41Sopenharmony_ci  let scriptDiv = div('script');
2221cb0ef41Sopenharmony_ci  scriptDiv.script = script;
2231cb0ef41Sopenharmony_ci
2241cb0ef41Sopenharmony_ci  let scriptTitle = h3();
2251cb0ef41Sopenharmony_ci  let anchor = a("", 'Script #' + script.id);
2261cb0ef41Sopenharmony_ci  anchor.name = "script"+script.id
2271cb0ef41Sopenharmony_ci  scriptTitle.appendChild(anchor);
2281cb0ef41Sopenharmony_ci  scriptDiv.appendChild(scriptTitle);
2291cb0ef41Sopenharmony_ci  if (script.file) scriptTitle.appendChild(a(script.file, script.file));
2301cb0ef41Sopenharmony_ci  let summary = createNode('pre', 'script-details');
2311cb0ef41Sopenharmony_ci  summary.appendChild(text(script.summary));
2321cb0ef41Sopenharmony_ci  scriptDiv.appendChild(summary);
2331cb0ef41Sopenharmony_ci  result.appendChild(scriptDiv);
2341cb0ef41Sopenharmony_ci}
2351cb0ef41Sopenharmony_ci
2361cb0ef41Sopenharmony_cifunction renderScriptSizes(parseProcessor) {
2371cb0ef41Sopenharmony_ci  let scriptsDiv = $('#scripts');
2381cb0ef41Sopenharmony_ci  parseProcessor.scripts.forEach(
2391cb0ef41Sopenharmony_ci    script => {
2401cb0ef41Sopenharmony_ci      let scriptDiv = a(`#script${script.id}`, '', 'script-size');
2411cb0ef41Sopenharmony_ci      let scriptId = div('script-details');
2421cb0ef41Sopenharmony_ci      scriptId.classList.add('id');
2431cb0ef41Sopenharmony_ci      scriptId.innerText = `id=${script.id}`;
2441cb0ef41Sopenharmony_ci      scriptDiv.appendChild(scriptId);
2451cb0ef41Sopenharmony_ci      let scriptSize = div('script-details');
2461cb0ef41Sopenharmony_ci      scriptSize.innerText = BYTES(script.bytesTotal);
2471cb0ef41Sopenharmony_ci      scriptDiv.appendChild(scriptSize);
2481cb0ef41Sopenharmony_ci      let scriptUrl = div('script-details');
2491cb0ef41Sopenharmony_ci      if (script.isEval) {
2501cb0ef41Sopenharmony_ci        scriptUrl.innerText = "eval";
2511cb0ef41Sopenharmony_ci        scriptDiv.classList.add('eval');
2521cb0ef41Sopenharmony_ci      } else {
2531cb0ef41Sopenharmony_ci        scriptUrl.innerText = script.file.split("/").pop();
2541cb0ef41Sopenharmony_ci      }
2551cb0ef41Sopenharmony_ci      if (script.isStreamingCompiled ) {
2561cb0ef41Sopenharmony_ci        scriptDiv.classList.add('streaming');
2571cb0ef41Sopenharmony_ci      } else if (script.deserializationTimestamp > 0) {
2581cb0ef41Sopenharmony_ci        scriptDiv.classList.add('deserialized');
2591cb0ef41Sopenharmony_ci      }
2601cb0ef41Sopenharmony_ci      scriptDiv.appendChild(scriptUrl);
2611cb0ef41Sopenharmony_ci      scriptDiv.style.maxWidth = `${script.bytesTotal * 0.001}px`;
2621cb0ef41Sopenharmony_ci      scriptsDiv.appendChild(scriptDiv);
2631cb0ef41Sopenharmony_ci    });
2641cb0ef41Sopenharmony_ci}
2651cb0ef41Sopenharmony_ci
2661cb0ef41Sopenharmony_ciconst kMaxTime = 120 * kSecondsToMillis;
2671cb0ef41Sopenharmony_ci// Resolution of the graphs
2681cb0ef41Sopenharmony_ciconst kTimeIncrement = 1;
2691cb0ef41Sopenharmony_ciconst kSelectionTimespan = 2;
2701cb0ef41Sopenharmony_ci// TODO(cbruni): support compilation cache hit.
2711cb0ef41Sopenharmony_ciclass Series {
2721cb0ef41Sopenharmony_ci  constructor(metricName, description, color, lineStyle, isArea=false) {
2731cb0ef41Sopenharmony_ci    this.metricName = metricName;
2741cb0ef41Sopenharmony_ci    this.description = description;
2751cb0ef41Sopenharmony_ci    this.color = color;
2761cb0ef41Sopenharmony_ci    this.lineStyle = lineStyle;
2771cb0ef41Sopenharmony_ci    this.isArea = isArea;
2781cb0ef41Sopenharmony_ci  }
2791cb0ef41Sopenharmony_ci}
2801cb0ef41Sopenharmony_ciconst series = [
2811cb0ef41Sopenharmony_ci    new Series('firstParseEvent', 'Any Parse', '#4D4D4D', undefined, true),
2821cb0ef41Sopenharmony_ci    new Series('execution', '1st Exec', '#fff700',undefined, true),
2831cb0ef41Sopenharmony_ci    new Series('firstCompileEvent', 'Any Compile', '#5DA5DA', undefined, true),
2841cb0ef41Sopenharmony_ci
2851cb0ef41Sopenharmony_ci    new Series('compile', 'Eager Compile', '#FAA43A'),
2861cb0ef41Sopenharmony_ci    new Series('lazyCompile', 'Lazy Compile','#FAA43A', 'dash'),
2871cb0ef41Sopenharmony_ci
2881cb0ef41Sopenharmony_ci    new Series('parse', 'Parsing', '#F17CB0'),
2891cb0ef41Sopenharmony_ci    new Series('preparse', 'Preparse', '#B2912F'),
2901cb0ef41Sopenharmony_ci    new Series('resolution', 'Preparse with Var. Resolution', '#B276B2'),
2911cb0ef41Sopenharmony_ci
2921cb0ef41Sopenharmony_ci    new Series('deserialization', 'Deserialization', '#DECF3F'),
2931cb0ef41Sopenharmony_ci
2941cb0ef41Sopenharmony_ci    new Series('baseline', 'Baseline', '#606611', 'dash'),
2951cb0ef41Sopenharmony_ci    new Series('optimize', 'Optimize', '#F15854'),
2961cb0ef41Sopenharmony_ci];
2971cb0ef41Sopenharmony_ciconst metricNames = series.map(each => each.metricName);
2981cb0ef41Sopenharmony_ci// Display cumulative values (useuful for bytes).
2991cb0ef41Sopenharmony_ciconst kCumulative = true;
3001cb0ef41Sopenharmony_ci// Include durations in the graphs.
3011cb0ef41Sopenharmony_ciconst kUseDuration = false;
3021cb0ef41Sopenharmony_ci
3031cb0ef41Sopenharmony_ci
3041cb0ef41Sopenharmony_cifunction appendGraph(script, parentNode, start, end) {
3051cb0ef41Sopenharmony_ci  const timerLabel = 'graph script=' + script.id;
3061cb0ef41Sopenharmony_ci  // TODO(cbruni): add support for network events
3071cb0ef41Sopenharmony_ci
3081cb0ef41Sopenharmony_ci  console.time(timerLabel);
3091cb0ef41Sopenharmony_ci  let data = new google.visualization.DataTable();
3101cb0ef41Sopenharmony_ci  data.addColumn('number', 'Duration');
3111cb0ef41Sopenharmony_ci  // The series are interleave bytes processed, time spent and thus have two
3121cb0ef41Sopenharmony_ci  // different vAxes.
3131cb0ef41Sopenharmony_ci  let seriesOptions = [];
3141cb0ef41Sopenharmony_ci  series.forEach(series => {
3151cb0ef41Sopenharmony_ci    // Add the bytes column.
3161cb0ef41Sopenharmony_ci    data.addColumn('number', series.description);
3171cb0ef41Sopenharmony_ci    let options = {targetAxisIndex: 0, color: series.color};
3181cb0ef41Sopenharmony_ci    if (series.isArea) options.type = 'area';
3191cb0ef41Sopenharmony_ci    if (series.lineStyle === 'dash') options.lineDashStyle = [4, 4];
3201cb0ef41Sopenharmony_ci    seriesOptions.push(options)
3211cb0ef41Sopenharmony_ci    // Add the time column.
3221cb0ef41Sopenharmony_ci    if (kUseDuration) {
3231cb0ef41Sopenharmony_ci      data.addColumn('number', series.description + ' Duration');
3241cb0ef41Sopenharmony_ci      seriesOptions.push(
3251cb0ef41Sopenharmony_ci          {targetAxisIndex: 1, color: series.color, lineDashStyle: [3, 2]});
3261cb0ef41Sopenharmony_ci    }
3271cb0ef41Sopenharmony_ci  });
3281cb0ef41Sopenharmony_ci
3291cb0ef41Sopenharmony_ci  const maxTime = Math.min(kMaxTime, end);
3301cb0ef41Sopenharmony_ci  console.time('metrics');
3311cb0ef41Sopenharmony_ci  let metricValues =
3321cb0ef41Sopenharmony_ci    script.getAccumulatedTimeMetrics(metricNames , 0, maxTime, kTimeIncrement,
3331cb0ef41Sopenharmony_ci        kCumulative, kUseDuration);
3341cb0ef41Sopenharmony_ci  console.timeEnd('metrics');
3351cb0ef41Sopenharmony_ci  // Make sure that the series added to the graph matches the returned values.
3361cb0ef41Sopenharmony_ci  console.assert(metricValues[0].length == seriesOptions.length + 1);
3371cb0ef41Sopenharmony_ci  data.addRows(metricValues);
3381cb0ef41Sopenharmony_ci
3391cb0ef41Sopenharmony_ci  let options = {
3401cb0ef41Sopenharmony_ci    explorer: {
3411cb0ef41Sopenharmony_ci      actions: ['dragToZoom', 'rightClickToReset'],
3421cb0ef41Sopenharmony_ci      maxZoomIn: 0.01
3431cb0ef41Sopenharmony_ci    },
3441cb0ef41Sopenharmony_ci    hAxis: {
3451cb0ef41Sopenharmony_ci      format: '#,###.##s'
3461cb0ef41Sopenharmony_ci    },
3471cb0ef41Sopenharmony_ci    vAxes: {
3481cb0ef41Sopenharmony_ci      0: {title: 'Bytes Touched', format: 'short'},
3491cb0ef41Sopenharmony_ci      1: {title: 'Duration', format: '#,###ms'}
3501cb0ef41Sopenharmony_ci    },
3511cb0ef41Sopenharmony_ci    height: 400,
3521cb0ef41Sopenharmony_ci    width: 1000,
3531cb0ef41Sopenharmony_ci    chartArea: {left: 70, top: 0, right: 160, height: "90%"},
3541cb0ef41Sopenharmony_ci    // The first series should be a area chart (total bytes touched),
3551cb0ef41Sopenharmony_ci    series: seriesOptions,
3561cb0ef41Sopenharmony_ci    // everthing else is a line.
3571cb0ef41Sopenharmony_ci    seriesType: 'line'
3581cb0ef41Sopenharmony_ci  };
3591cb0ef41Sopenharmony_ci  let graphNode = createNode('div', 'chart');
3601cb0ef41Sopenharmony_ci  let listNode = createNode('div', 'funktion-list');
3611cb0ef41Sopenharmony_ci  parentNode.appendChild(graphNode);
3621cb0ef41Sopenharmony_ci  parentNode.appendChild(listNode);
3631cb0ef41Sopenharmony_ci  let chart = new google.visualization.ComboChart(graphNode);
3641cb0ef41Sopenharmony_ci  google.visualization.events.addListener(chart, 'select',
3651cb0ef41Sopenharmony_ci      () => selectGraphPointHandler(chart, data, script, parentNode));
3661cb0ef41Sopenharmony_ci  chart.draw(data, options);
3671cb0ef41Sopenharmony_ci  // Add event listeners
3681cb0ef41Sopenharmony_ci  console.timeEnd(timerLabel);
3691cb0ef41Sopenharmony_ci}
3701cb0ef41Sopenharmony_ci
3711cb0ef41Sopenharmony_cifunction selectGraphPointHandler(chart, data, script, parentNode) {
3721cb0ef41Sopenharmony_ci  let selection = chart.getSelection();
3731cb0ef41Sopenharmony_ci  if (selection.length <= 0) return;
3741cb0ef41Sopenharmony_ci  // Display a list of funktions with events at the given time.
3751cb0ef41Sopenharmony_ci  let {row, column} = selection[0];
3761cb0ef41Sopenharmony_ci  if (row === null|| column === null) return;
3771cb0ef41Sopenharmony_ci  const kEntrySize = kUseDuration ? 2 : 1;
3781cb0ef41Sopenharmony_ci  let [metric, description] = series[((column-1)/ kEntrySize) | 0];
3791cb0ef41Sopenharmony_ci  let time = data.getValue(row, 0);
3801cb0ef41Sopenharmony_ci  let funktions = script.getFunktionsAtTime(
3811cb0ef41Sopenharmony_ci        time * kSecondsToMillis, kSelectionTimespan, metric);
3821cb0ef41Sopenharmony_ci  let oldList = parentNode.querySelector('.funktion-list');
3831cb0ef41Sopenharmony_ci  parentNode.replaceChild(
3841cb0ef41Sopenharmony_ci      createFunktionList(metric, description, time, funktions), oldList);
3851cb0ef41Sopenharmony_ci}
3861cb0ef41Sopenharmony_ci
3871cb0ef41Sopenharmony_cifunction createFunktionList(metric, description, time, funktions) {
3881cb0ef41Sopenharmony_ci  let container = createNode('div', 'funktion-list');
3891cb0ef41Sopenharmony_ci  container.appendChild(h3('Changes of "' + description + '" at ' +
3901cb0ef41Sopenharmony_ci        time + 's: ' + funktions.length));
3911cb0ef41Sopenharmony_ci  let listNode = createNode('ul');
3921cb0ef41Sopenharmony_ci  funktions.forEach(funktion => {
3931cb0ef41Sopenharmony_ci    let node = createNode('li', 'funktion');
3941cb0ef41Sopenharmony_ci    node.funktion = funktion;
3951cb0ef41Sopenharmony_ci    node.appendChild(text(funktion.toString(false) + " "));
3961cb0ef41Sopenharmony_ci    let script = funktion.script;
3971cb0ef41Sopenharmony_ci    if (script) {
3981cb0ef41Sopenharmony_ci      node.appendChild(a("#script" + script.id, "in script " + script.id));
3991cb0ef41Sopenharmony_ci    }
4001cb0ef41Sopenharmony_ci    listNode.appendChild(node);
4011cb0ef41Sopenharmony_ci  });
4021cb0ef41Sopenharmony_ci  container.appendChild(listNode);
4031cb0ef41Sopenharmony_ci  return container;
4041cb0ef41Sopenharmony_ci}
4051cb0ef41Sopenharmony_ci</script>
4061cb0ef41Sopenharmony_ci</head>
4071cb0ef41Sopenharmony_ci
4081cb0ef41Sopenharmony_ci<body>
4091cb0ef41Sopenharmony_ci  <h1>BEHOLD, THIS IS PARSEROR!</h1>
4101cb0ef41Sopenharmony_ci
4111cb0ef41Sopenharmony_ci  <h2>Usage</h2>
4121cb0ef41Sopenharmony_ci  Run your script with <code>--log-function-events</code> and upload <code>v8.log</code> on this page:<br/>
4131cb0ef41Sopenharmony_ci  <code>/path/to/d8 --log-function-events your_script.js</code>
4141cb0ef41Sopenharmony_ci
4151cb0ef41Sopenharmony_ci  <h2>Data</h2>
4161cb0ef41Sopenharmony_ci  <form name="fileForm">
4171cb0ef41Sopenharmony_ci    <p>
4181cb0ef41Sopenharmony_ci      <input id="uploadInput" type="file" name="files" onchange="loadFile();" accept=".log"> trace entries: <span id="count">0</span>
4191cb0ef41Sopenharmony_ci    </p>
4201cb0ef41Sopenharmony_ci  </form>
4211cb0ef41Sopenharmony_ci
4221cb0ef41Sopenharmony_ci
4231cb0ef41Sopenharmony_ci  <h2>Scripts</h2>
4241cb0ef41Sopenharmony_ci  <div id="scripts"></div>
4251cb0ef41Sopenharmony_ci
4261cb0ef41Sopenharmony_ci  <h2>Result</h2>
4271cb0ef41Sopenharmony_ci  <div id="result"></div>
4281cb0ef41Sopenharmony_ci</body>
4291cb0ef41Sopenharmony_ci
4301cb0ef41Sopenharmony_ci</html>
431