@itwin/frontend-devtools
Version:
Debug menu and supporting UI widgets
144 lines • 6.28 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
* @module Widgets
*/
import { IModelApp } from "@itwin/core-frontend";
import { createButton } from "../ui/Button";
import { createCheckBox } from "../ui/CheckBox";
import { createNumericInput } from "../ui/NumericInput";
function computeProgress(vp) {
const ready = vp.numReadyTiles;
const requested = vp.numRequestedTiles;
const total = ready + requested;
const ratio = (total > 0) ? (ready / total) : 1.0;
return Math.round(ratio * 100);
}
const statEntries = [
{ getValue: (stats, vp) => stats.numActiveRequests + (IModelApp.tileAdmin.getTilesForUser(vp)?.external.requested ?? 0), label: "Active" },
{ getValue: (stats, _vp) => stats.numPendingRequests, label: "Pending" },
{ getValue: (stats, _vp) => stats.numCanceled, label: "Canceled" },
{ getValue: (stats, _vp) => stats.numActiveRequests + stats.numPendingRequests, label: "Total" },
{ getValue: (_stats, vp) => vp.numSelectedTiles, label: "Selected" },
{ getValue: (_stats, vp) => vp.numReadyTiles, label: "Ready" },
{ getValue: (_stats, vp) => computeProgress(vp), label: "Progress" },
{ getValue: (stats, _vp) => stats.totalCompletedRequests, label: "Completed" },
{ getValue: (stats, _vp) => stats.totalTimedOutRequests, label: "Timed Out" },
{ getValue: (stats, _vp) => stats.totalFailedRequests, label: "Failed" },
{ getValue: (stats, _vp) => stats.totalEmptyTiles, label: "Empty" },
{ getValue: (stats, _vp) => stats.totalUndisplayableTiles, label: "Undisplayable" },
{ getValue: (stats, _vp) => stats.totalElidedTiles, label: "Elided" },
{ getValue: (stats, _vp) => stats.totalCacheMisses, label: "Cache Misses" },
{ getValue: (stats, _vp) => stats.totalDispatchedRequests, label: "Dispatched" },
{ getValue: (stats, _vp) => stats.totalAbortedRequests, label: "Aborted" },
{ getValue: (stats) => Math.round(stats.decoding.mean), label: "Decoding mean time (ms)" },
{ getValue: (stats) => stats.decoding.max, label: "Decoding max time (ms)" },
];
const indexOfFirstGlobalStatistic = 7; // "Completed"
/** Outputs statistics related to tile requests including the current number of active, pending, selected, and ready tile requests; as well as cumulative statistics for the session including the number of failed, timed-out, empty, and elided tile requests.
* @beta
*/
export class TileStatisticsTracker {
_statElements = [];
_div;
_vp;
_curIntervalId;
constructor(parent, vp) {
this._vp = vp;
this.addMaxActive(parent);
createCheckBox({
parent,
name: "Track Tile Requests",
id: "stats_trackMemory",
handler: (_cb) => this.toggle(),
});
this._div = document.createElement("div");
this._div.style.display = "none";
this._div.style.textAlign = "right";
const table = document.createElement("table");
table.style.width = "100%";
table.setAttribute("border", "1");
this._div.appendChild(table);
const row = document.createElement("tr");
const frameColumn = document.createElement("td");
const globalColumn = document.createElement("td");
frameColumn.style.width = globalColumn.style.width = "50%";
row.appendChild(frameColumn);
row.appendChild(globalColumn);
table.appendChild(row);
for (let i = 0; i < statEntries.length; i++) {
const div = document.createElement("div");
const elem = document.createElement("text");
this._statElements[i] = elem;
div.appendChild(elem);
const column = i >= indexOfFirstGlobalStatistic ? globalColumn : frameColumn;
column.appendChild(div);
}
const resetButton = createButton({
parent: this._div,
value: "Reset",
tooltip: "Reset all cumulative statistics",
handler: () => this.reset(),
});
resetButton.div.style.textAlign = "center";
parent.appendChild(this._div);
}
[Symbol.dispose]() {
this.clearInterval();
}
addMaxActive(parent) {
const div = document.createElement("div");
const label = document.createElement("label");
label.style.display = "inline";
label.htmlFor = "maxActiveRequests";
label.innerText = "Max Active Requests: ";
div.appendChild(label);
createNumericInput({
parent: div,
id: "maxActiveRequests",
display: "inline",
min: 0,
step: 1,
value: IModelApp.tileAdmin.channels.rpcConcurrency,
handler: (value, _input) => this.updateMaxActive(value),
});
parent.appendChild(div);
}
updateMaxActive(value) {
IModelApp.tileAdmin.channels.setRpcConcurrency(value);
}
clearInterval() {
if (undefined !== this._curIntervalId) {
window.clearInterval(this._curIntervalId);
this._curIntervalId = undefined;
}
}
toggle() {
if (undefined !== this._curIntervalId) {
// Currently on - turn off.
this._div.style.display = "none";
this.clearInterval();
}
else {
// Currently off - turn on.
this._div.style.display = "block";
this.update();
this._curIntervalId = window.setInterval(() => this.update(), 500);
}
}
update() {
const stats = IModelApp.tileAdmin.statistics;
for (let i = 0; i < statEntries.length; i++) {
const stat = statEntries[i];
const label = `${stat.label}: ${stat.getValue(stats, this._vp)}`;
this._statElements[i].innerText = label;
}
}
reset() {
IModelApp.tileAdmin.resetStatistics();
this.update();
}
}
//# sourceMappingURL=TileStatisticsTracker.js.map