1/*
2 * Copyright (c) 2022 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#ifndef ECMASCRIPT_DFX_VMSTAT_OPT_CODE_PROFILER_H
16#define ECMASCRIPT_DFX_VMSTAT_OPT_CODE_PROFILER_H
17
18#include "ecmascript/compiler/bytecodes.h"
19#include "ecmascript/compiler/ecma_opcode_des.h"
20#include "ecmascript/compiler/share_opcodes.h"
21#include <set>
22
23// bcIndex   bytecode   count    fast    slow    typerate
24// ====================(print all)=======================
25// ........
26// ======================================================
27// total
28
29// tip: not print if count below 10000
30// ====================(top1 method: name, methodId)=====
31// .......
32// (bcIndex   bytecode   count    fast    slow    typerate)
33// .......
34// ======================================================
35
36// ====================(top2 method: name)===============
37// .......
38// ======================================================
39
40// .......
41
42// ====================(top10 method: name)==============
43// .......
44// ======================================================
45
46// methodId, abcId, bcIndex, Value1(opcode, fastcount, slowcount),Value2(methodName, totalcount)
47// key: methodId, abcId
48// std::map<key, <bcIndex, Value1>>
49// std::map<key, Value2>
50
51namespace panda::ecmascript {
52class OptCodeProfiler {
53public:
54    using EcmaOpcode = kungfu::EcmaOpcode;
55
56    enum Mode {
57        TYPED_PATH,
58        SLOW_PATH,
59    };
60
61    struct Value {
62        Value() : typedPathValue(0), slowPathValue(0) {}
63
64        uint64_t TypedPathCount() const
65        {
66            return typedPathValue;
67        }
68
69        uint64_t SlowPathCount() const
70        {
71            return slowPathValue;
72        }
73
74        uint64_t Count() const
75        {
76            return typedPathValue + slowPathValue;
77        }
78
79        void ResetStat()
80        {
81            typedPathValue = 0;
82            slowPathValue = 0;
83        }
84
85        uint64_t typedPathValue;
86        uint64_t slowPathValue;
87    };
88
89    struct Key {
90        Key(uint32_t abcId, uint32_t methodId)
91        {
92            abcAndMethodId_ = (((uint64_t)abcId) << 32) + methodId; // 32: 32bit
93        }
94
95        Key(uint64_t key) : abcAndMethodId_(key) {};
96
97        uint32_t GetAbcId() const
98        {
99            return (uint32_t) (abcAndMethodId_ >> 32); // 32: 32bit
100        }
101
102        uint32_t GetMethodId() const
103        {
104            return (uint32_t) abcAndMethodId_;
105        }
106
107        uint64_t Value() const
108        {
109            return abcAndMethodId_;
110        }
111
112        uint64_t abcAndMethodId_;
113    };
114
115    struct Name {
116        Name(std::string name) : methodName_(name), totalCount_(1) {}
117
118        uint64_t Count() const
119        {
120            return totalCount_;
121        }
122
123        void Inc()
124        {
125            totalCount_ = totalCount_ + 1;
126        }
127
128        std::string GetName() const
129        {
130            return methodName_;
131        }
132
133        std::string methodName_;
134        uint64_t totalCount_;
135    };
136
137    struct Record {
138        Record(EcmaOpcode opcode) : opcode_(opcode), fast_(0), slow_(0) {}
139
140        uint64_t Count() const
141        {
142            return fast_ + slow_;
143        }
144
145        uint64_t GetFast() const
146        {
147            return fast_;
148        }
149
150        uint64_t GetSlow() const
151        {
152            return slow_;
153        }
154
155        EcmaOpcode GetOpCode() const
156        {
157            return opcode_;
158        }
159
160        void IncFast()
161        {
162            fast_ = fast_ + 1;
163        }
164
165        void IncSlow()
166        {
167            slow_ = slow_ + 1;
168        }
169
170        EcmaOpcode opcode_;
171        uint64_t fast_;
172        uint64_t slow_;
173    };
174
175    OptCodeProfiler()
176    {
177#if ECMASCRIPT_ENABLE_OPT_CODE_PROFILER
178        profMap_ = {
179#define BYTECODE_PROF_MAP(name) { kungfu::EcmaOpcode::name, OptCodeProfiler::Value() },
180    ECMA_OPCODE_LIST(BYTECODE_PROF_MAP)
181#undef BYTECODE_PROF_MAP
182        };
183#endif
184    }
185
186    ~OptCodeProfiler();
187
188    void Update(JSHandle<JSTaggedValue> &func, int bcIndex, EcmaOpcode opcode, Mode mode);
189
190    void PrintAndReset();
191
192    using BcRecord = std::map<int, Record>;
193private:
194    void FilterMethodToPrint();
195    void PrintMethodRecord(Key key, std::string methodName);
196    void ResetMethodInfo()
197    {
198        methodIdToRecord_.clear();
199        methodIdToName_.clear();
200    }
201#if ECMASCRIPT_ENABLE_JIT_WARMUP_PROFILER == 0
202    int printMehodCount_ {10};
203#endif
204    std::map<EcmaOpcode, Value> profMap_;
205    std::map<uint64_t, BcRecord> methodIdToRecord_;
206    std::map<uint64_t, Name> methodIdToName_;
207    std::vector<CString> abcNames_;
208};
209
210class TypedOpProfiler {
211public:
212    using OpCode = kungfu::OpCode;
213
214    TypedOpProfiler()
215    {
216        strOpMap_ = {
217#define DECLARE_GATE_OPCODE(NAME, OP, R, S, D, V) \
218        { #OP, OpCode::OP },
219
220    MCR_IMMUTABLE_META_DATA_CACHE_LIST(DECLARE_GATE_OPCODE)
221    MCR_GATE_META_DATA_LIST_WITH_PC_OFFSET(DECLARE_GATE_OPCODE)
222    MCR_GATE_META_DATA_LIST_FOR_CALL(DECLARE_GATE_OPCODE)
223    MCR_GATE_META_DATA_LIST_WITH_VALUE(DECLARE_GATE_OPCODE)
224    MCR_GATE_META_DATA_LIST_WITH_BOOL(DECLARE_GATE_OPCODE)
225    MCR_GATE_META_DATA_LIST_WITH_GATE_TYPE(DECLARE_GATE_OPCODE)
226    MCR_GATE_META_DATA_LIST_WITH_VALUE_IN(DECLARE_GATE_OPCODE)
227#undef DECLARE_GATE_OPCODE
228        };
229
230        profMap_ = {
231#define DECLARE_GATE_OPCODE(NAME, OP, R, S, D, V) \
232        { OpCode::OP, 0 },
233
234    MCR_IMMUTABLE_META_DATA_CACHE_LIST(DECLARE_GATE_OPCODE)
235    MCR_GATE_META_DATA_LIST_WITH_PC_OFFSET(DECLARE_GATE_OPCODE)
236    MCR_GATE_META_DATA_LIST_FOR_CALL(DECLARE_GATE_OPCODE)
237    MCR_GATE_META_DATA_LIST_WITH_VALUE(DECLARE_GATE_OPCODE)
238    MCR_GATE_META_DATA_LIST_WITH_BOOL(DECLARE_GATE_OPCODE)
239    MCR_GATE_META_DATA_LIST_WITH_GATE_TYPE(DECLARE_GATE_OPCODE)
240    MCR_GATE_META_DATA_LIST_WITH_VALUE_IN(DECLARE_GATE_OPCODE)
241#undef DECLARE_GATE_OPCODE
242        };
243    }
244
245    void Update(OpCode opcode)
246    {
247        auto it = profMap_.find(opcode);
248        if (it != profMap_.end()) {
249            it->second++;
250            recordOp_.insert(opcode);
251        }
252    }
253
254    void Print(std::string opStr)
255    {
256        auto it = strOpMap_.find(opStr);
257        if (it != strOpMap_.end()) {
258            LOG_TRACE(INFO) << "Opcode: " << it->first << " Count:"
259                            << profMap_.at(it->second);
260        }
261    }
262
263    void Clear()
264    {
265        for (OpCode op : recordOp_) {
266            profMap_.at(op) = 0;
267        }
268        recordOp_.clear();
269    }
270
271private:
272    std::map<std::string, OpCode> strOpMap_;
273    std::map<OpCode, uint64_t> profMap_;
274    std::set<OpCode> recordOp_ {};
275};
276}  // namespace panda::ecmascript
277#endif  // ECMASCRIPT_DFX_VMSTAT_OPT_CODE_PROFILER_H
278