// Copyright 2020 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. import {V8CustomElement, defineCustomElement} from './helper.mjs'; defineCustomElement('stats-panel', (templateText) => class StatsPanel extends V8CustomElement { constructor() { super(templateText); this.timeline_ = undefined; } get stats() { return this.$('#stats'); } set timeline(value){ this.timeline_ = value; } get timeline(){ return this.timeline_; } //TODO(zcankare) Depreciate timeline set transitions(value){ this.transitions_ = value; } get transitions(){ return this.transitions_; } filterUniqueTransitions(filter) { // Returns a list of Maps whose parent is not in the list. return this.timeline.filter(map => { if (filter(map) === false) return false; let parent = map.parent(); if (parent === undefined) return true; return filter(parent) === false; }); } update() { this.removeAllChildren(this.stats); this.updateGeneralStats(); this.updateNamedTransitionsStats(); } updateGeneralStats() { console.assert(this.timeline_ !== undefined, "Timeline not set yet!"); let pairs = [ ['Total', null, e => true], ['Transitions', 'primary', e => e.edge && e.edge.isTransition()], ['Fast to Slow', 'violet', e => e.edge && e.edge.isFastToSlow()], ['Slow to Fast', 'orange', e => e.edge && e.edge.isSlowToFast()], ['Initial Map', 'yellow', e => e.edge && e.edge.isInitial()], [ 'Replace Descriptors', 'red', e => e.edge && e.edge.isReplaceDescriptors() ], ['Copy as Prototype', 'red', e => e.edge && e.edge.isCopyAsPrototype()], [ 'Optimize as Prototype', null, e => e.edge && e.edge.isOptimizeAsPrototype() ], ['Deprecated', null, e => e.isDeprecated()], ['Bootstrapped', 'green', e => e.isBootstrapped()], ]; let text = ''; let tableNode = this.table('transitionType'); tableNode.innerHTML = 'ColorTypeCountPercent'; let name, filter; let total = this.timeline.size(); pairs.forEach(([name, color, filter]) => { let row = this.tr(); if (color !== null) { row.appendChild(this.td(this.div(['colorbox', color]))); } else { row.appendChild(this.td('')); } row.onclick = (e) => { // lazily compute the stats let node = e.target.parentNode; if (node.maps == undefined) { node.maps = this.filterUniqueTransitions(filter); } this.dispatchEvent(new CustomEvent( 'change', {bubbles: true, composed: true, detail: node.maps})); }; row.appendChild(this.td(name)); let count = this.timeline.count(filter); row.appendChild(this.td(count)); let percent = Math.round(count / total * 1000) / 10; row.appendChild(this.td(percent.toFixed(1) + '%')); tableNode.appendChild(row); }); this.stats.appendChild(tableNode); } updateNamedTransitionsStats() { let tableNode = this.table('transitionTable'); let nameMapPairs = Array.from(this.transitions.entries()); tableNode.innerHTML = 'Propery Name#'; nameMapPairs.sort((a, b) => b[1].length - a[1].length).forEach(([ name, maps ]) => { let row = this.tr(); row.maps = maps; row.addEventListener( 'click', e => this.dispatchEvent(new CustomEvent( 'change', {bubbles: true, composed: true, detail: e.target.parentNode.maps.map(map => map.to)}))); row.appendChild(this.td(name)); row.appendChild(this.td(maps.length)); tableNode.appendChild(row); }); this.stats.appendChild(tableNode); } });