Commit 8057caf7 authored by Camillo Bruni's avatar Camillo Bruni Committed by V8 LUCI CQ

[tools][system-analyzer] Speed improvements

- Avoid redrawing property-link tables if the contents don't change
- Don't update timeline legends if the selection doesn't change
- Use shorter class names for the flamechart for faster parsing
- Round positions in flamechart to avoid long strings that would be
  created from raw double positions
- Don't redraw the tooltip if the content is the same

Change-Id: I925f1708400286c7c9f8db62f75c3b5fe8a16b12
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3521945Reviewed-by: 's avatarPatrick Thier <pthier@chromium.org>
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79540}
parent 0b28b6e6
......@@ -34,6 +34,7 @@ export class V8CustomElement extends HTMLElement {
}
forceUpdate() {
this._updateTimeoutId = undefined;
this._update();
}
......
......@@ -73,4 +73,25 @@ export function arrayEquals(left, right) {
return true;
}
export function entriesEquals(left, right) {
if (left == right) return true;
if (left == undefined) return right == undefined;
const leftEntries = Object.entries(left);
const rightEntries = Object.entries(right);
if (leftEntries.length !== rightEntries.length) return false;
for (let i = 0; i < leftEntries.length; i++) {
const l = leftEntries[i];
const r = rightEntries[i];
if (l[0] != r[0]) return false;
if (l[1] != r[1]) return false;
}
return true;
}
export function keysEquals(left, right) {
if (left == right) return true;
if (left == undefined) return right == undefined;
return arrayEquals(Object.keys(left), Object.keys(right));
}
export * from '../js/helper.mjs'
......@@ -47,7 +47,7 @@ found in the LICENSE file. -->
</head>
<body>
<tool-tip id="tool-tip"></tool-tip>
<tool-tip id="tool-tip" style="will-change: transform"></tool-tip>
<section id="file-reader">
<log-file-reader id="log-file-reader"></log-file-reader>
......
......@@ -3,8 +3,9 @@
// found in the LICENSE file.
import {App} from '../index.mjs'
import {FocusEvent, SelectRelatedEvent} from './events.mjs';
import {DOM, ExpandableText, V8CustomElement} from './helper.mjs';
import {DOM, entriesEquals, ExpandableText, V8CustomElement} from './helper.mjs';
DOM.defineCustomElement('view/property-link-table',
template =>
......@@ -27,7 +28,7 @@ DOM.defineCustomElement('view/property-link-table',
}
set propertyDict(propertyDict) {
if (this._propertyDict === propertyDict) return;
if (entriesEquals(this._propertyDict, propertyDict)) return;
if (typeof propertyDict !== 'object') {
throw new Error(
`Invalid property dict, expected object: ${propertyDict}`);
......
......@@ -510,6 +510,7 @@ class SelectionHandler {
class Legend {
_timeline;
_lastSelection;
_typesFilters = new Map();
_typeClickHandler = this._handleTypeClick.bind(this);
_filterPredicate = this.filter.bind(this);
......@@ -553,6 +554,8 @@ class Legend {
}
update() {
if (this._lastSelection === this.selection) return;
this._lastSelection = this.selection;
const tbody = DOM.tbody();
const missingTypes = new Set(this._typesFilters.keys());
this._checkDurationField();
......
......@@ -108,19 +108,19 @@ export class TimelineTrackStackedBase extends TimelineTrackBase {
}
_drawItem(item, i, outline = false) {
const x = this.timeToPosition(item.time);
const x = roundTo3Digits(this.timeToPosition(item.time));
const y = (item.depth + 1) * kItemHeight;
let width = item.duration * this._timeToPixel;
let width = roundTo3Digits(item.duration * this._timeToPixel);
if (outline) {
return `<rect x=${x} y=${y} width=${width} height=${
kItemHeight - 1} class=flameSelected />`;
kItemHeight - 1} class=fs />`;
}
let color = this._legend.colorForType(item.type);
if (i % 2 == 1) {
color = CSSColor.darken(color, 20);
}
return `<rect x=${x} y=${y} width=${width} height=${kItemHeight - 1} fill=${
color} class=flame />`;
color} class=f />`;
}
_drawItemText(item) {
......@@ -141,4 +141,8 @@ export class TimelineTrackStackedBase extends TimelineTrackBase {
buffer += `<text x=${x + 1} y=${y - 3} class=txt>${text}</text>`
return buffer;
}
}
\ No newline at end of file
}
function roundTo3Digits(value) {
return ((value * 1000) | 0) / 1000;
}
......@@ -184,10 +184,10 @@ found in the LICENSE file. -->
dominant-baseline: hanging;
font-size: 9px;
}
.flame {
.flame, .f {
stroke-width: 0;
}
.flameSelected {
.flameSelected, .fs {
fill: var(--on-background-color);
fill-opacity: 0.1;
stroke: var(--on-background-color);
......@@ -234,4 +234,4 @@ found in the LICENSE file. -->
<tbody></tbody>
</table>
</div>
</div>
\ No newline at end of file
</div>
......@@ -152,7 +152,7 @@ class Annotations {
const start = this._flames.find(time);
let offset = 0;
// Draw annotations gradually outwards starting form the given time.
let deadline = performance.now() + 500;
let deadline = performance.now() + 100;
for (let range = 0; range < this._flames.length; range += 10000) {
this._markFlames(start - range, start - offset);
this._markFlames(start + offset, start + range);
......@@ -165,7 +165,7 @@ class Annotations {
// Abort if we started another update asynchronously.
if (this._logEntry != logEntry) return;
deadline = performance.now() + 500;
deadline = performance.now() + 100;
}
this._drawBuffer();
}
......
......@@ -8,6 +8,15 @@ found in the LICENSE file. -->
:host {
position: absolute;
z-index: 100;
will-change: transform;
}
#body {
display: none;
position: absolute;
--tip-offset: 10px;
--tip-width: 10px;
--tip-height: 40px;
}
#content {
......@@ -36,15 +45,6 @@ found in the LICENSE file. -->
max-width: 500px;
}
#body {
display: none;
position: absolute;
z-index: 99999;
--tip-offset: 10px;
--tip-width: 10px;
--tip-height: 40px;
}
#body.top {
bottom: var(--tip-height);
}
......
......@@ -87,6 +87,9 @@ DOM.defineCustomElement(
set content(content) {
if (!content) return this.hide();
this.show();
if (this._content === content) return;
this._content = content;
if (typeof content === 'string') {
this.contentNode.innerHTML = content;
this.contentNode.className = 'textContent';
......@@ -112,12 +115,15 @@ DOM.defineCustomElement(
}
hide() {
this._content = undefined;
if (this._isHidden) return;
this._isHidden = true;
this.bodyNode.style.display = 'none';
this.targetNode = undefined;
}
show() {
if (!this._isHidden) return;
this.bodyNode.style.display = 'block';
this._isHidden = false;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment