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 
51 namespace panda::ecmascript {
52 class OptCodeProfiler {
53 public:
54     using EcmaOpcode = kungfu::EcmaOpcode;
55 
56     enum Mode {
57         TYPED_PATH,
58         SLOW_PATH,
59     };
60 
61     struct Value {
Valuepanda::ecmascript::OptCodeProfiler::Value62         Value() : typedPathValue(0), slowPathValue(0) {}
63 
TypedPathCountpanda::ecmascript::OptCodeProfiler::Value64         uint64_t TypedPathCount() const
65         {
66             return typedPathValue;
67         }
68 
SlowPathCountpanda::ecmascript::OptCodeProfiler::Value69         uint64_t SlowPathCount() const
70         {
71             return slowPathValue;
72         }
73 
Countpanda::ecmascript::OptCodeProfiler::Value74         uint64_t Count() const
75         {
76             return typedPathValue + slowPathValue;
77         }
78 
ResetStatpanda::ecmascript::OptCodeProfiler::Value79         void ResetStat()
80         {
81             typedPathValue = 0;
82             slowPathValue = 0;
83         }
84 
85         uint64_t typedPathValue;
86         uint64_t slowPathValue;
87     };
88 
89     struct Key {
Keypanda::ecmascript::OptCodeProfiler::Key90         Key(uint32_t abcId, uint32_t methodId)
91         {
92             abcAndMethodId_ = (((uint64_t)abcId) << 32) + methodId; // 32: 32bit
93         }
94 
Keypanda::ecmascript::OptCodeProfiler::Key95         Key(uint64_t key) : abcAndMethodId_(key) {};
96 
GetAbcIdpanda::ecmascript::OptCodeProfiler::Key97         uint32_t GetAbcId() const
98         {
99             return (uint32_t) (abcAndMethodId_ >> 32); // 32: 32bit
100         }
101 
GetMethodIdpanda::ecmascript::OptCodeProfiler::Key102         uint32_t GetMethodId() const
103         {
104             return (uint32_t) abcAndMethodId_;
105         }
106 
Valuepanda::ecmascript::OptCodeProfiler::Key107         uint64_t Value() const
108         {
109             return abcAndMethodId_;
110         }
111 
112         uint64_t abcAndMethodId_;
113     };
114 
115     struct Name {
Namepanda::ecmascript::OptCodeProfiler::Name116         Name(std::string name) : methodName_(name), totalCount_(1) {}
117 
Countpanda::ecmascript::OptCodeProfiler::Name118         uint64_t Count() const
119         {
120             return totalCount_;
121         }
122 
Incpanda::ecmascript::OptCodeProfiler::Name123         void Inc()
124         {
125             totalCount_ = totalCount_ + 1;
126         }
127 
GetNamepanda::ecmascript::OptCodeProfiler::Name128         std::string GetName() const
129         {
130             return methodName_;
131         }
132 
133         std::string methodName_;
134         uint64_t totalCount_;
135     };
136 
137     struct Record {
Recordpanda::ecmascript::OptCodeProfiler::Record138         Record(EcmaOpcode opcode) : opcode_(opcode), fast_(0), slow_(0) {}
139 
Countpanda::ecmascript::OptCodeProfiler::Record140         uint64_t Count() const
141         {
142             return fast_ + slow_;
143         }
144 
GetFastpanda::ecmascript::OptCodeProfiler::Record145         uint64_t GetFast() const
146         {
147             return fast_;
148         }
149 
GetSlowpanda::ecmascript::OptCodeProfiler::Record150         uint64_t GetSlow() const
151         {
152             return slow_;
153         }
154 
GetOpCodepanda::ecmascript::OptCodeProfiler::Record155         EcmaOpcode GetOpCode() const
156         {
157             return opcode_;
158         }
159 
IncFastpanda::ecmascript::OptCodeProfiler::Record160         void IncFast()
161         {
162             fast_ = fast_ + 1;
163         }
164 
IncSlowpanda::ecmascript::OptCodeProfiler::Record165         void IncSlow()
166         {
167             slow_ = slow_ + 1;
168         }
169 
170         EcmaOpcode opcode_;
171         uint64_t fast_;
172         uint64_t slow_;
173     };
174 
OptCodeProfiler()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>;
193 private:
194     void FilterMethodToPrint();
195     void PrintMethodRecord(Key key, std::string methodName);
ResetMethodInfo()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 
210 class TypedOpProfiler {
211 public:
212     using OpCode = kungfu::OpCode;
213 
TypedOpProfiler()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 
Update(OpCode opcode)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 
Print(std::string opStr)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 
Clear()263     void Clear()
264     {
265         for (OpCode op : recordOp_) {
266             profMap_.at(op) = 0;
267         }
268         recordOp_.clear();
269     }
270 
271 private:
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