1// Copyright 2018 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5'use strict'; 6 7const global_timeline_template = 8 document.currentScript.ownerDocument.querySelector( 9 '#global-timeline-template'); 10 11class GlobalTimeline extends HTMLElement { 12 constructor() { 13 super(); 14 const shadowRoot = this.attachShadow({mode: 'open'}); 15 shadowRoot.appendChild(global_timeline_template.content.cloneNode(true)); 16 } 17 18 $(id) { 19 return this.shadowRoot.querySelector(id); 20 } 21 22 set data(value) { 23 this._data = value; 24 this.stateChanged(); 25 } 26 27 get data() { 28 return this._data; 29 } 30 31 set selection(value) { 32 this._selection = value; 33 this.stateChanged(); 34 } 35 36 get selection() { 37 return this._selection; 38 } 39 40 isValid() { 41 return this.data && this.selection; 42 } 43 44 hide() { 45 this.$('#container').style.display = 'none'; 46 } 47 48 show() { 49 this.$('#container').style.display = 'block'; 50 } 51 52 stateChanged() { 53 if (this.isValid()) { 54 this.drawChart(); 55 } else { 56 this.hide(); 57 } 58 } 59 60 getFieldData() { 61 const labels = [ 62 {type: 'number', label: 'Time'}, 63 {type: 'number', label: 'Ptr compression benefit'}, 64 {type: 'string', role: 'tooltip'}, 65 {type: 'number', label: 'Embedder fields'}, 66 {type: 'number', label: 'Tagged fields'}, 67 {type: 'number', label: 'Other raw fields'}, 68 {type: 'number', label: 'Unboxed doubles'} 69 ]; 70 const chart_data = [labels]; 71 const isolate_data = this.data[this.selection.isolate]; 72 let sum_total = 0; 73 let sum_ptr_compr_benefit_perc = 0; 74 let count = 0; 75 Object.keys(isolate_data.gcs).forEach(gc_key => { 76 const gc_data = isolate_data.gcs[gc_key]; 77 const data_set = gc_data[this.selection.data_set].field_data; 78 const data = []; 79 data.push(gc_data.time * kMillis2Seconds); 80 const total = data_set.tagged_fields + 81 data_set.embedder_fields + 82 data_set.other_raw_fields + 83 data_set.unboxed_double_fields; 84 const ptr_compr_benefit = data_set.tagged_fields / 2; 85 const ptr_compr_benefit_perc = ptr_compr_benefit / total * 100; 86 sum_total += total; 87 sum_ptr_compr_benefit_perc += ptr_compr_benefit_perc; 88 count++; 89 const tooltip = "Ptr compression benefit: " + 90 (ptr_compr_benefit / KB).toFixed(2) + "KB " + 91 " (" + ptr_compr_benefit_perc.toFixed(2) + "%)"; 92 data.push(ptr_compr_benefit / KB); 93 data.push(tooltip); 94 data.push(data_set.embedder_fields / KB); 95 data.push(data_set.tagged_fields / KB); 96 data.push(data_set.other_raw_fields / KB); 97 data.push(data_set.unboxed_double_fields / KB); 98 chart_data.push(data); 99 }); 100 const avg_ptr_compr_benefit_perc = 101 count ? sum_ptr_compr_benefit_perc / count : 0; 102 console.log("=================================================="); 103 console.log("= Average ptr compression benefit is " + 104 avg_ptr_compr_benefit_perc.toFixed(2) + "%"); 105 console.log("= Average V8 heap size " + 106 (sum_total / count / KB).toFixed(2) + " KB"); 107 console.log("=================================================="); 108 return chart_data; 109 } 110 111 getCategoryData() { 112 const categories = Object.keys(this.selection.categories) 113 .map(k => this.selection.category_names.get(k)); 114 const labels = ['Time', ...categories]; 115 const chart_data = [labels]; 116 const isolate_data = this.data[this.selection.isolate]; 117 Object.keys(isolate_data.gcs).forEach(gc_key => { 118 const gc_data = isolate_data.gcs[gc_key]; 119 const data_set = gc_data[this.selection.data_set].instance_type_data; 120 const data = []; 121 data.push(gc_data.time * kMillis2Seconds); 122 Object.values(this.selection.categories).forEach(instance_types => { 123 data.push( 124 instance_types 125 .map(instance_type => { 126 return data_set[instance_type].overall; 127 }) 128 .reduce((accu, current) => accu + current, 0) / 129 KB); 130 }); 131 chart_data.push(data); 132 }); 133 return chart_data; 134 } 135 136 getInstanceTypeData() { 137 const instance_types = 138 Object.values(this.selection.categories) 139 .reduce((accu, current) => accu.concat(current), []); 140 const labels = ['Time', ...instance_types]; 141 const chart_data = [labels]; 142 const isolate_data = this.data[this.selection.isolate]; 143 Object.keys(isolate_data.gcs).forEach(gc_key => { 144 const gc_data = isolate_data.gcs[gc_key]; 145 const data_set = gc_data[this.selection.data_set].instance_type_data; 146 const data = []; 147 data.push(gc_data.time * kMillis2Seconds); 148 instance_types.forEach(instance_type => { 149 data.push(data_set[instance_type].overall / KB); 150 }); 151 chart_data.push(data); 152 }); 153 return chart_data; 154 } 155 156 getChartData() { 157 switch (this.selection.data_view) { 158 case VIEW_BY_FIELD_TYPE: 159 return this.getFieldData(); 160 case VIEW_BY_INSTANCE_CATEGORY: 161 return this.getCategoryData(); 162 case VIEW_BY_INSTANCE_TYPE: 163 default: 164 return this.getInstanceTypeData(); 165 } 166 } 167 168 getChartOptions() { 169 const options = { 170 isStacked: true, 171 hAxis: { 172 format: '###.##s', 173 title: 'Time [s]', 174 }, 175 vAxis: { 176 format: '#,###KB', 177 title: 'Memory consumption [KBytes]' 178 }, 179 chartArea: {left:100, width: '85%', height: '70%'}, 180 legend: {position: 'top', maxLines: '1'}, 181 pointsVisible: true, 182 pointSize: 5, 183 explorer: {}, 184 }; 185 switch (this.selection.data_view) { 186 case VIEW_BY_FIELD_TYPE: 187 // Overlay pointer compression benefit on top of the graph 188 return Object.assign(options, { 189 series: {0: {type: 'line', lineDashStyle: [13, 13]}}, 190 }); 191 case VIEW_BY_INSTANCE_CATEGORY: 192 case VIEW_BY_INSTANCE_TYPE: 193 default: 194 return options; 195 } 196 } 197 198 drawChart() { 199 console.assert(this.data, 'invalid data'); 200 console.assert(this.selection, 'invalid selection'); 201 202 const chart_data = this.getChartData(); 203 204 const data = google.visualization.arrayToDataTable(chart_data); 205 const options = this.getChartOptions(); 206 const chart = new google.visualization.AreaChart(this.$('#chart')); 207 this.show(); 208 chart.draw(data, google.charts.Line.convertOptions(options)); 209 } 210} 211 212customElements.define('global-timeline', GlobalTimeline); 213