1 /*
2  * Copyright (c) 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
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 
16 #ifndef ECMASCRIPT_PGO_PROFILER_PGO_UTILS_H
17 #define ECMASCRIPT_PGO_PROFILER_PGO_UTILS_H
18 
19 #include <list>
20 #include <string>
21 
22 #include "ecmascript/common.h"
23 #include "ecmascript/log.h"
24 #include "ecmascript/log_wrapper.h"
25 #include "ecmascript/platform/mutex.h"
26 #include "libpandafile/file.h"
27 #include "mem/mem.h"
28 
29 namespace panda::ecmascript::pgo {
30 static constexpr Alignment ALIGN_SIZE = Alignment::LOG_ALIGN_4;
31 using PGOMethodId = panda_file::File::EntityId;
32 using ApEntityId = uint32_t;
33 
34 class DumpUtils {
35 public:
36     static const std::string ELEMENT_SEPARATOR;
37     static const std::string BLOCK_SEPARATOR;
38     static const std::string TYPE_SEPARATOR;
39     static const std::string BLOCK_START;
40     static const std::string ARRAY_START;
41     static const std::string ARRAY_END;
42     static const std::string NEW_LINE;
43     static const std::string SPACE;
44     static const std::string BLOCK_AND_ARRAY_START;
45     static const std::string VERSION_HEADER;
46     static const std::string PANDA_FILE_INFO_HEADER;
47     static const uint32_t HEX_FORMAT_WIDTH_FOR_32BITS;
48 };
49 
50 class DumpJsonUtils {
51 public:
52     static inline const std::string ABC_FILE_POOL = "abcFilePool";
53     static inline const std::string ABC_FILE = "abcFile";
54     static inline const std::string RECORD_DETAIL = "recordDetail";
55     static inline const std::string MODULE_NAME = "moduleName";
56     static inline const std::string FUNCTION = "function";
57     static inline const std::string FUNCTION_NAME = "functionName";
58     static inline const std::string TYPE = "type";
59     static inline const std::string TYPE_OFFSET = "typeOffset";
60     static inline const std::string TYPE_NAME = "typeName";
61     static inline const std::string IS_ROOT = "isRoot";
62     static inline const std::string KIND = "kind";
63     static inline const std::string ABC_ID = "abcId";
64     static inline const std::string ID = "id";
65 };
66 
67 class ApNameUtils {
68 public:
69     static const std::string AP_SUFFIX;
70     static const std::string RUNTIME_AP_PREFIX;
71     static const std::string MERGED_AP_PREFIX;
72     static const std::string DEFAULT_AP_NAME;
73     static std::string PUBLIC_API GetRuntimeApName(const std::string &ohosModuleName);
74     static std::string PUBLIC_API GetMergedApName(const std::string &ohosModuleName);
75     static std::string PUBLIC_API GetOhosPkgApName(const std::string &ohosModuleName);
76 
77 private:
78     static std::string GetBriefApName(const std::string &ohosModuleName);
79 };
80 
81 class ConcurrentGuardValues {
82 public:
83     mutable std::atomic_int last_tid {0};
84     mutable std::atomic_int count {0};
85     static const int MAX_LOG_COUNT = 30;
86 
AddLog(std::string str)87     void AddLog(std::string str)
88     {
89         LockHolder lock(mutex_);
90         if (log_.size() >= MAX_LOG_COUNT) {
91             log_.pop_front();
92         }
93         log_.push_back(str + ", tid: " + std::to_string(Gettid()));
94     }
95 
AddLogWithDebugLog(std::string str)96     void AddLogWithDebugLog(std::string str)
97     {
98         AddLog(str);
99         LOG_ECMA(DEBUG) << str;
100     }
101 
ClearLog()102     void ClearLog()
103     {
104         LockHolder lock(mutex_);
105         log_.clear();
106     }
107 
PrintLog()108     void PrintLog()
109     {
110         LockHolder lock(mutex_);
111         std::ostringstream os;
112         os << "concurrent guard logs: " << std::endl;
113         for (auto& str: log_) {
114             os << str << std::endl;
115         }
116         LOG_ECMA(INFO) << os.str();
117     }
118 
Gettid()119     int Gettid()
120     {
121         return os::thread::GetCurrentThreadId();
122     }
123 
124 private:
125     std::list<std::string> log_;
126     Mutex mutex_;
127 };
128 
129 class ConcurrentGuard {
130 private:
131     std::string operation_;
132 
133 public:
ConcurrentGuard(ConcurrentGuardValues& v, std::string operation = �)134     ConcurrentGuard(ConcurrentGuardValues& v, std::string operation = ""): operation_(operation), v_(v)
135     {
136         v_.AddLogWithDebugLog("[ConcurrentGuard] " + operation_ + " start");
137         auto tid = v_.Gettid();
138         auto except = 0;
139         // Support reenter
140         if (!v_.count.compare_exchange_strong(except, 1) && v_.last_tid != tid) {
141             v_.PrintLog();
142             LOG_ECMA(FATAL) << "[ConcurrentGuard] total thead count should be 0, but get " << except
143                             << ", current tid: " << tid << ", last tid: " << v_.last_tid;
144         }
145         v_.last_tid = tid;
146     }
~ConcurrentGuard()147     ~ConcurrentGuard()
148     {
149         auto tid = v_.Gettid();
150         auto except = 1;
151         // Support reenter
152         if (!v_.count.compare_exchange_strong(except, 0) && v_.last_tid != tid) {
153             v_.PrintLog();
154             LOG_ECMA(FATAL) << "[ConcurrentGuard] total thead count should be 1, but get " << except
155                             << ", current tid: " << tid << ", last tid: " << v_.last_tid;
156         }
157         v_.AddLogWithDebugLog("[ConcurrentGuard] " + operation_ + " end");
158     };
159 
160 private:
161     ConcurrentGuardValues& v_;
162 };
163 }  // namespace panda::ecmascript::pgo
164 #endif  // ECMASCRIPT_PGO_PROFILER_PGO_UTILS_H
165