• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"use strict";
2/*
3 * Copyright (c) 2022-2025 Huawei Device Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16Object.defineProperty(exports, "__esModule", { value: true });
17exports.getMainPerfProbe = exports.enterMainPerfProbe = void 0;
18const compat_1 = require("#koalaui/compat");
19/**
20 * Creates a {@link MainPerfProbe} instance with the {@link name} and enters its main probe.
21 *
22 * If a {@link MainPerfProbe} with this {@link name} already exists then it is canceled and the new one is created.
23 *
24 * Exit it with {@link MainPerfProbe.exit}.
25 */
26function enterMainPerfProbe(name) {
27    return new MainPerfProbeImpl(name);
28}
29exports.enterMainPerfProbe = enterMainPerfProbe;
30/**
31 * Returns {@link MainPerfProbe} instance with the {@link name} if it exists,
32 * otherwise a dummy instance.
33 *
34 * @see MainPerfProbe.dummy
35 */
36function getMainPerfProbe(name) {
37    const instance = MainPerfProbeImpl.mainProbes.get(name);
38    return instance ? instance : MainPerfProbeImpl.DUMMY;
39}
40exports.getMainPerfProbe = getMainPerfProbe;
41class DummyPerfProbe {
42    get name() { return "dummy"; }
43    get dummy() { return true; }
44    exit(log) { }
45    cancel() { }
46    get canceled() { return false; }
47    enterProbe(name) { return PerfProbeImpl.DUMMY; }
48    exitProbe(name) { return PerfProbeImpl.DUMMY; }
49    getProbe(name) { return PerfProbeImpl.DUMMY; }
50    //performProbe: <T>(_: string, func: () => T) => func(),
51    performProbe(name, func) { return func(); }
52    probePerformed(_) { return false; }
53    get userData() {
54        return undefined;
55    }
56    set userData(_) { }
57}
58class PerfProbeImpl {
59    constructor(name, main, parent, remainder = false) {
60        this.children = new Array();
61        this.childrenSorted = false;
62        this.index = 0;
63        this.startTime = 0.0;
64        this.totalTime = 0.0;
65        this.callCount = 0;
66        this.currentRecursionDepth = 0;
67        this.recursiveCallCount = 0;
68        this._canceled = false;
69        this._name = name;
70        this._main = main;
71        this.parent = parent;
72        this.remainder = remainder;
73    }
74    get name() {
75        return this._name;
76    }
77    get dummy() {
78        return false;
79    }
80    get main() {
81        return this._main;
82    }
83    get performing() {
84        return this.startTime > 0;
85    }
86    get userData() {
87        return this._userData;
88    }
89    set userData(value) {
90        this._userData = value;
91    }
92    exit(log) {
93        if (this.canceled)
94            return;
95        if (this.currentRecursionDepth == 0) {
96            this.totalTime += (0, compat_1.timeNow)() - this.startTime;
97            this.startTime = 0;
98        }
99        else {
100            this.currentRecursionDepth--;
101        }
102        if (!this.performing) {
103            this.main.pop(this);
104        }
105        if (log)
106            this.log();
107    }
108    cancel(cancelChildren = true) {
109        this._canceled = true;
110        if (cancelChildren)
111            this.maybeCancelChildren();
112    }
113    maybeCancelChildren() {
114        MainPerfProbeImpl.visit(this, false, (probe, depth) => {
115            if (probe.performing)
116                probe.cancel(false);
117        });
118    }
119    get canceled() {
120        return this._canceled;
121    }
122    toString() {
123        if (this.canceled) {
124            return `[${this.name}] canceled`;
125        }
126        if (this.performing) {
127            return `[${this.name}] still performing...`;
128        }
129        const mainProbe = this.main.probes.get(this.main.name);
130        const percentage = mainProbe.totalTime > 0 ? Math.round((100 / mainProbe.totalTime) * this.totalTime) : 0;
131        let result = `[${this.name}] call count: ${this.callCount}`
132            + ` | recursive call count: ${this.recursiveCallCount}`
133            + ` | time: ${this.totalTime}ms ${percentage}%`;
134        if (this.userData) {
135            result += ` | user data: ${this.userData}`;
136        }
137        return result;
138    }
139    log(prefix) {
140        console.log(prefix ? `${prefix}${this.toString()}` : this.toString());
141    }
142}
143PerfProbeImpl.DUMMY = new DummyPerfProbe();
144class MainPerfProbeImpl extends PerfProbeImpl {
145    constructor(name) {
146        super(name);
147        this.probes = new Map();
148        const prev = MainPerfProbeImpl.mainProbes.get(name);
149        if (prev)
150            prev.cancel();
151        MainPerfProbeImpl.mainProbes.set(name, this);
152        this.currentProbe = this.enterProbe(name);
153    }
154    createProbe(name) {
155        const probes = name == this.name ? this : new PerfProbeImpl(name, this);
156        this.push(probes);
157        return probes;
158    }
159    get main() {
160        return this;
161    }
162    push(probe) {
163        probe.parent = this.currentProbe;
164        probe.index = probe.parent ? probe.parent.children.length : 0;
165        if (probe.parent)
166            probe.parent.children.push(probe);
167        this.currentProbe = probe;
168    }
169    pop(probe) {
170        if (probe.parent) {
171            this.currentProbe = probe.parent;
172        }
173    }
174    performProbe(name, func) {
175        const probe = this.enterProbe(name);
176        try {
177            return func();
178        }
179        finally {
180            probe.exit();
181        }
182    }
183    enterProbe(name) {
184        let probe = this.probes.get(name);
185        if (!probe) {
186            probe = this.createProbe(name);
187            this.probes.set(name, probe);
188        }
189        probe._canceled = false;
190        if (probe.performing) {
191            probe.recursiveCallCount++;
192            probe.currentRecursionDepth++;
193        }
194        else {
195            probe.startTime = (0, compat_1.timeNow)();
196            probe.callCount++;
197        }
198        return probe;
199    }
200    exitProbe(name) {
201        const probe = this.getProbe(name);
202        probe.exit(undefined);
203        return probe;
204    }
205    getProbe(name) {
206        const probe = this.probes.get(name);
207        return probe !== undefined ? probe : PerfProbeImpl.DUMMY;
208    }
209    probePerformed(name) {
210        const probe = this.probes.get(name);
211        return probe != undefined && !probe.performing && !probe.canceled;
212    }
213    exit(log) {
214        super.exit();
215        if (log)
216            this.log();
217        this.cancel();
218    }
219    cancel() {
220        MainPerfProbeImpl.mainProbes.delete(this.name);
221    }
222    static visit(root, logging, apply) {
223        let current = root;
224        let index = 0;
225        let depth = 0;
226        let visiting = true;
227        while (true) {
228            if (visiting) {
229                current.index = 0;
230                apply(current, depth);
231            }
232            if (index >= current.children.length) {
233                if (!current.parent) {
234                    break;
235                }
236                current = current.parent;
237                index = ++current.index;
238                depth--;
239                visiting = false;
240                continue;
241            }
242            visiting = true;
243            if (logging && !current.childrenSorted) {
244                current.childrenSorted = true;
245                current.children = current.children.sort((p1, p2) => p2.totalTime - p1.totalTime);
246                if (depth == 0) {
247                    // a special probe to log the time remained
248                    current.children.push(new PerfProbeImpl("<remainder>", root.main, current, true));
249                }
250            }
251            current = current.children[index];
252            index = 0;
253            depth++;
254        }
255    }
256    log(prefix) {
257        prefix = prefix !== undefined ? `${prefix}: ` : "";
258        console.log(`${prefix}perf probes:`);
259        MainPerfProbeImpl.visit(this.main, true, (probe, depth) => {
260            let indent = "\t";
261            for (let i = 0; i < depth; i++)
262                indent += "\t";
263            if (probe.remainder) {
264                const parentTime = probe.parent.totalTime;
265                let childrenTime = 0;
266                probe.parent.children.forEach((a) => { childrenTime += a.totalTime; });
267                probe.totalTime = Math.max(0, parentTime - childrenTime);
268                const percentage = parentTime > 0 ? Math.round((100 / parentTime) * probe.totalTime) : 0;
269                console.log(`${prefix}${indent}[${probe.name}] time: ${(0, compat_1.numberToFixed)(probe.totalTime, 2)}ms ${percentage}%`);
270            }
271            else {
272                console.log(`${prefix}${indent}${probe.toString()}`);
273            }
274        });
275    }
276}
277MainPerfProbeImpl.mainProbes = new Map();
278MainPerfProbeImpl.DUMMY = new DummyPerfProbe();
279//# sourceMappingURL=PerfProbe.js.map