• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2024-2025 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
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
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.
14 */
15
16import { ArkAssignStmt, Stmt } from '../../core/base/Stmt';
17import { UnknownType } from '../../core/base/Type';
18import { CallGraphNode, CallGraphNodeKind } from '../model/CallGraph';
19import { PointerAnalysis } from '../pointerAnalysis/PointerAnalysis';
20import Logger, { LOG_MODULE_TYPE } from '../../utils/logger';
21
22const logger = Logger.getLogger(LOG_MODULE_TYPE.ARKANALYZER, 'PTA');
23
24abstract class StatTraits {
25    TotalTime: number = 0;
26    startTime: number = 0;
27    endTime: number = 0;
28
29    public getStat(): string {
30        return '';
31    }
32
33    public printStat(): void {
34        logger.trace(this.getStat());
35    }
36}
37
38export class PTAStat extends StatTraits {
39    pta: PointerAnalysis;
40    numProcessedAddr: number = 0;
41    numProcessedCopy: number = 0;
42    numProcessedLoad: number = 0;
43    numProcessedWrite: number = 0;
44    numProcessedThis: number = 0;
45    numRealWrite: number = 0;
46    numRealLoad: number = 0;
47
48    numUnhandledFun: number = 0;
49    numTotalValuesInHandedFun: number = 0;
50    numTotalHandledValue: number = 0;
51
52    // Original type is UnknownType but inferred by PTA
53    numInferedUnknownValue: number = 0;
54    // Original type is not UnknownType and inferred with different type by PTA
55    numInferedDiffTypeValue: number = 0;
56    // Total number of values in the functions visited by PTA
57    totalValuesInVisitedFunc: number = 0;
58    // Original type is UnkonwnType and not inferred by PTA as well
59    numNotInferedUnknownValue: number = 0;
60    numUnhandledFunc: number = 0;
61
62    iterTimes: number = 0;
63
64    startMemUsage: any;
65    endMemUsage: any;
66    rssUsed: number = 0;
67    heapUsed: number = 0;
68
69    constructor(pta: PointerAnalysis) {
70        super();
71        this.pta = pta;
72    }
73
74    public startStat(): void {
75        this.startTime = this.getNow();
76        this.startMemUsage = process.memoryUsage();
77    }
78
79    public endStat(): void {
80        this.endTime = this.getNow();
81        this.endMemUsage = process.memoryUsage();
82        this.TotalTime = (this.endTime - this.startTime) / 1000;
83        this.rssUsed = Number(this.endMemUsage.rss - this.startMemUsage.rss) / Number(1024 * 1024);
84        this.heapUsed = Number(this.endMemUsage.heapTotal - this.startMemUsage.heapTotal) / Number(1024 * 1024);
85        this.getInferedStat();
86        this.getUnhandledFuncStat();
87    }
88
89    public getNow(): number {
90        return new Date().getTime();
91    }
92
93    private getInferedStat(): void {
94        let stmtStat = (s: Stmt): void => {
95            if (!(s instanceof ArkAssignStmt)) {
96                return;
97            }
98
99            let lop = s.getLeftOp();
100            if (visited.has(lop)) {
101                return;
102            }
103            visited.add(lop);
104
105            if (inferred.includes(lop)) {
106                if (lop.getType() instanceof UnknownType) {
107                    this.numInferedUnknownValue++;
108                } else {
109                    this.numInferedDiffTypeValue++;
110                }
111            } else {
112                if (lop.getType() instanceof UnknownType) {
113                    this.numNotInferedUnknownValue++;
114                }
115            }
116            this.totalValuesInVisitedFunc++;
117        };
118
119        let inferred = Array.from(this.pta.getTypeDiffMap().keys());
120        let visited = new Set();
121
122        let cg = this.pta.getCallGraph();
123        this.pta.getHandledFuncs().forEach(funcID => {
124            let f = cg.getArkMethodByFuncID(funcID);
125            f
126                ?.getCfg()
127                ?.getStmts()
128                .forEach(s => stmtStat(s));
129        });
130    }
131
132    private getUnhandledFuncStat(): void {
133        let cg = this.pta.getCallGraph();
134        this.pta.getUnhandledFuncs().forEach(funcID => {
135            let cgNode = cg.getNode(funcID);
136            if ((cgNode as CallGraphNode).isSdkMethod()) {
137                return;
138            }
139
140            let f = cg.getArkMethodByFuncID(funcID);
141            if (f) {
142                this.numUnhandledFun++;
143            }
144        });
145    }
146
147    public getStat(): string {
148        // TODO: get PAG stat and CG stat
149        let output: string;
150        output = '==== Pointer analysis Statictics: ====\n';
151        output = output + `Processed address\t${this.numProcessedAddr}\n`;
152        output = output + `Processed copy\t\t${this.numProcessedCopy}\n`;
153        output = output + `Processed load\t\t${this.numProcessedLoad}\n`;
154        output = output + `Processed write\t\t${this.numProcessedWrite}\n`;
155        output = output + `Real write\t\t${this.numRealWrite}\n`;
156        output = output + `Real load\t\t${this.numRealLoad}\n`;
157        output = output + `Processed This\t\t${this.numProcessedThis}\n\n`;
158        output = output + `Unhandled function\t${this.numUnhandledFun}\n`;
159        output = output + `Total values in visited function\t${this.totalValuesInVisitedFunc}\n`;
160        output = output + `Infered Value unknown+different type\t${this.numInferedUnknownValue}+${this.numInferedDiffTypeValue}\n\n`;
161        output = output + `Total Time\t\t${this.TotalTime} S\n`;
162        output = output + `Total iterator Times\t${this.iterTimes}\n`;
163        output = output + `RSS used\t\t${this.rssUsed.toFixed(3)} Mb\n`;
164        output = output + `Heap used\t\t${this.heapUsed.toFixed(3)} Mb\n`;
165        return output;
166    }
167
168    public printStat(): void {
169        logger.trace(this.getStat());
170    }
171}
172
173export class PAGStat extends StatTraits {
174    numDynamicCall: number = 0;
175    numTotalFunction: number = 0;
176    numTotalNode: number = 0;
177
178    public getStat(): string {
179        let output: string;
180        output = '==== PAG Statictics: ====\n';
181        output = output + `Dynamic call\t\t${this.numDynamicCall}\n`;
182        output = output + `Total function handled\t${this.numTotalFunction}\n`;
183        output = output + `Total PAG Nodes\t\t${this.numTotalNode}\n`;
184        return output;
185    }
186
187    public printStat(): void {
188        logger.trace(this.getStat());
189    }
190}
191
192export class CGStat extends StatTraits {
193    //real, vitual, intrinsic, constructor
194    numTotalNode: number = 0;
195    numReal: number = 0;
196    numVirtual: number = 0;
197    numIntrinsic: number = 0;
198    numConstructor: number = 0;
199    numBlank: number = 0;
200
201    public startStat(): void {
202        this.startTime = new Date().getTime();
203    }
204
205    public endStat(): void {
206        this.endTime = new Date().getTime();
207        this.TotalTime = (this.endTime - this.startTime) / 1000;
208    }
209
210    public addNodeStat(kind: CallGraphNodeKind): void {
211        switch (kind) {
212            case CallGraphNodeKind.real:
213                this.numReal++;
214                break;
215            case CallGraphNodeKind.vitual:
216                this.numVirtual++;
217                break;
218            case CallGraphNodeKind.constructor:
219                this.numConstructor++;
220                break;
221            case CallGraphNodeKind.intrinsic:
222                this.numIntrinsic++;
223                break;
224            default:
225                this.numBlank++;
226        }
227        this.numTotalNode++;
228    }
229
230    public getStat(): string {
231        let output: string;
232        output = '==== CG Statictics: ====\n';
233        output = output + `CG construction Total Time\t\t${this.TotalTime} S\n`;
234        output = output + `Real function\t\t${this.numReal}\n`;
235        output = output + `Intrinsic function\t${this.numIntrinsic}\n`;
236        output = output + `Constructor function\t${this.numConstructor}\n`;
237        output = output + `Virtual function\t\t${this.numVirtual}\n`;
238        output = output + `Blank function\t\t${this.numBlank}\n`;
239        output = output + `Total\t\t\t${this.numTotalNode}\n`;
240        return output;
241    }
242}
243