2
* Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3
* Licensed under the Apache License, Version 2.0 (the "License");
4
* you may not use this file except in compliance with the License.
5
* You may obtain a copy of the License at
7
* http://www.apache.org/licenses/LICENSE-2.0
9
* Unless required by applicable law or agreed to in writing, software
10
* distributed under the License is distributed on an "AS IS" BASIS,
11
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
* See the License for the specific language governing permissions and
13
* limitations under the License.
16
import { int32 } from "@koalaui/compat"
19
* Adds statistics for constructing/disposing of the TreeNode instances.
20
* It is disabled by default because collecting such data affects performance.
22
const DEBUG_WITH_NODE_STATS = false
24
export class KoalaProfiler {
25
private static readonly map = DEBUG_WITH_NODE_STATS
26
? new Map<int32, Set<Object>>()
29
static nodeCreated(nodeType: int32, node: Object) {
30
if (KoalaProfiler.map === undefined) return
31
let set = KoalaProfiler.map!.get(nodeType)
32
if (set === undefined) {
33
set = new Set<Object>()
34
KoalaProfiler.map!.set(nodeType, set)
39
static nodeDisposed(nodeType: int32, node: Object) {
40
if (KoalaProfiler.map === undefined) return
41
let set = KoalaProfiler.map!.get(nodeType)
42
if (set === undefined) throw new Error("node never existed")
43
if (!set.delete(node)) console.log("node is already disposed")
46
public static counters: KoalaProfiler | undefined = undefined
48
private invalidations = 0
53
private cachedDraws = 0
57
private lastTime = 0.0
59
private updateEnterTime = 0.0
60
private updateExitTime = 0.0
61
private updateTime = 0.0
62
private buildEnterTime = 0.0
63
private buildExitTime = 0.0
64
private buildTime = 0.0
65
private layoutEnterTime = 0.0
66
private layoutExitTime = 0.0
67
private layoutTime = 0.0
68
private drawEnterTime = 0.0
69
private drawExitTime = 0.0
70
private drawTime = 0.0
71
private updatableStates = 0
72
private mutableStates = 0
73
private computableValues = 0
76
KoalaProfiler.counters = new KoalaProfiler()
80
KoalaProfiler.counters = undefined
83
static enabled(): boolean {
84
return KoalaProfiler.counters != undefined
88
this.invalidations = 0
96
this.updateEnterTime = 0
97
this.updateExitTime = 0
98
this.updatableStates = 0
99
this.mutableStates = 0
100
this.computableValues = 0
104
console.log(this.getReport())
107
getReport(): string {
108
const updateTime = Math.round(1000 * (this.updateExitTime - this.updateEnterTime))
109
const buildTime = Math.round(1000 * (this.buildExitTime - this.buildEnterTime))
110
const layoutTime = Math.round(1000 * (this.layoutExitTime - this.layoutEnterTime))
111
const drawTime = Math.round(1000 * (this.drawExitTime - this.drawEnterTime))
112
if (this.updateTime < updateTime) this.updateTime = updateTime
113
if (this.buildTime < buildTime) this.buildTime = buildTime
114
if (this.layoutTime < layoutTime) this.layoutTime = layoutTime
115
if (this.drawTime < drawTime) this.drawTime = drawTime
117
// TODO: OHOS does not properly handle \n in template literals
118
const array = Array.of<string>(
119
`invalidations: ${this.invalidations}`,
120
`modified states: ${this.mutableStates}/${this.updatableStates} + ${this.computableValues}`,
121
`update states (mks): ${this.updateTime} / ${updateTime}`,
122
`build root node (mks): ${this.buildTime} / ${buildTime}`,
123
`layout view (mks): ${this.layoutTime} / ${layoutTime}`,
124
`draw view (mks): ${this.drawTime} / ${drawTime}`,
125
`computes: ${this.computes}`,
126
`builds: ${this.builds}`,
127
`nodes: ${this.nodes}`,
128
`realDraws: ${this.realDraws}`,
129
`cachedDraws: ${this.cachedDraws}`,
130
`measures: ${this.measures}`,
131
`layouts: ${this.layouts}`,
132
`FPS: ${this.lastFPS}`,
134
KoalaProfiler.map?.forEach((set:Set<Object>, kind:int32) => {
135
if (set.size > 0) array.push(kind + ":" + set.size)
137
return array.join("\n")
140
invalidation() { this.invalidations++ }
141
compute() { this.computes++ }
142
build() { this.builds++ }
143
node() { this.nodes++ }
144
realDraw() { this.realDraws++ }
145
cachedDraw() { this.cachedDraws++ }
146
layout() { this.layouts++ }
147
measure() { this.measures++ }
149
if (ms - this.lastTime <= 1000) {
152
this.lastFPS = Math.round(this.frames * 1000 / (ms - this.lastTime)) as int32
158
this.buildEnterTime = Date.now()
161
this.buildExitTime = Date.now()
164
this.layoutEnterTime = Date.now()
167
this.layoutExitTime = Date.now()
170
this.drawEnterTime = Date.now()
173
this.drawExitTime = Date.now()
175
updateSnapshotEnter() {
176
this.updateEnterTime = Date.now()
178
updateSnapshotExit() {
179
this.updateExitTime = Date.now()
181
updateSnapshot(modified: int32, all?: int32) {
182
if (all === undefined) {
183
this.computableValues = modified - this.mutableStates
186
this.mutableStates = modified
187
this.updatableStates = all