• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_AP_FILE_PGO_RECORD_POOL_H
17 #define ECMASCRIPT_PGO_PROFILER_AP_FILE_PGO_RECORD_POOL_H
18 
19 #include <cstdint>
20 #include <fstream>
21 #include <unordered_map>
22 #include <memory>
23 
24 #include "ecmascript/common.h"
25 #include "ecmascript/log.h"
26 #include "ecmascript/log_wrapper.h"
27 #include "ecmascript/mem/c_string.h"
28 #include "ecmascript/pgo_profiler/ap_file/pgo_file_info.h"
29 #include "ecmascript/pgo_profiler/ap_file/pool_template.h"
30 #include "ecmascript/pgo_profiler/pgo_utils.h"
31 #include "ecmascript/pgo_profiler/types/pgo_profile_type.h"
32 #include "macros.h"
33 
34 namespace panda::ecmascript::pgo {
35 class PGOProfilerHeader;
36 
37 class PGOStringPool {
38 public:
39     class Entry : public PGOFileDataInterface {
40     public:
Entry(CString name)41         explicit Entry(CString name) : name_(std::move(name)) {}
42         Entry() = default;
GetEntryId()43         ApEntityId GetEntryId() const
44         {
45             return entryId_;
46         }
47 
SetEntryId(ApEntityId entryId)48         void SetEntryId(ApEntityId entryId)
49         {
50             entryId_ = entryId;
51         }
52 
GetData()53         const CString &GetData() const
54         {
55             return name_;
56         }
57 
ProcessToBinary(PGOContext & context,std::fstream & stream)58         uint32_t ProcessToBinary([[maybe_unused]] PGOContext &context, std::fstream &stream) override
59         {
60             stream << name_ << '\0';
61             return 1;
62         }
63 
ParseFromBinary(PGOContext & context,void ** buffer,PGOProfilerHeader const * header)64         uint32_t ParseFromBinary([[maybe_unused]] PGOContext &context, void **buffer,
65                                  [[maybe_unused]] PGOProfilerHeader const *header) override
66         {
67             name_ = base::ReadBuffer(buffer);
68             return 1;
69         }
70 
ProcessToText(std::ofstream & stream)71         bool ProcessToText(std::ofstream &stream) override
72         {
73             stream << name_;
74             return true;
75         }
76 
77     private:
78         ApEntityId entryId_ {0};
79         CString name_;
80     };
81     using PoolType = PoolTemplate<Entry, CString>;
82 
PGOStringPool(const std::string & poolName,uint32_t reservedCount)83     PGOStringPool(const std::string &poolName, uint32_t reservedCount)
84     {
85         pool_ = std::make_shared<PoolType>(poolName, reservedCount);
86     };
~PGOStringPool()87     ~PGOStringPool()
88     {
89         Clear();
90     }
91 
TryAdd(const CString & value,ApEntityId & entryId)92     bool TryAdd(const CString &value, ApEntityId &entryId)
93     {
94         return pool_->TryAdd(value, entryId);
95     }
96 
TryAddSafe(const CString & value,ApEntityId & entryId)97     bool TryAddSafe(const CString& value, ApEntityId& entryId)
98     {
99         WriteLockHolder lock(poolLock_);
100         return TryAdd(value, entryId);
101     }
102 
GetEntryId(const CString & value,ApEntityId & entryId)103     bool GetEntryId(const CString &value, ApEntityId &entryId) const
104     {
105         return pool_->GetEntryId(value, entryId);
106     }
107 
GetEntryIdSafe(const CString & value,ApEntityId & entryId)108     bool GetEntryIdSafe(const CString& value, ApEntityId& entryId)
109     {
110         ReadLockHolder lock(poolLock_);
111         return GetEntryId(value, entryId);
112     }
113 
GetPandaFileDescSafe(ApEntityId abcId,CString & desc)114     bool GetPandaFileDescSafe(ApEntityId abcId, CString& desc)
115     {
116         ReadLockHolder lock(poolLock_);
117         const auto* entry = GetEntry(abcId);
118         if (entry == nullptr) {
119             return false;
120         }
121         desc = entry->GetData();
122         return true;
123     }
124 
GetEntry(ApEntityId entryId)125     const Entry *GetEntry(ApEntityId entryId) const
126     {
127         return pool_->GetEntry(entryId);
128     }
129 
GetEntryIdByNormalizedName(const CString & value,ApEntityId & entryId)130     bool GetEntryIdByNormalizedName(const CString &value, ApEntityId &entryId) const
131     {
132         return pool_->GetEntryIdByNormalizedName(value, entryId);
133     }
134 
Clear()135     void Clear()
136     {
137         pool_->Clear();
138     }
139 
ClearSafe()140     void ClearSafe()
141     {
142         WriteLockHolder lock(poolLock_);
143         Clear();
144     }
145 
GetPool()146     std::shared_ptr<PoolType> &GetPool()
147     {
148         return pool_;
149     }
150 
151 protected:
152     NO_COPY_SEMANTIC(PGOStringPool);
153     NO_MOVE_SEMANTIC(PGOStringPool);
154     std::shared_ptr<PoolType> pool_;
155     RWLock poolLock_;
156 };
157 
158 class PGORecordPool : public PGOFileSectionInterface {
159 public:
160     PGORecordPool() = default;
Support(PGOProfilerHeader const * header)161     bool Support(PGOProfilerHeader const *header) const override
162     {
163         return header->SupportRecordPool();
164     }
165 
GetSection(PGOProfilerHeader const * header)166     SectionInfo *GetSection(PGOProfilerHeader const *header) const override
167     {
168         return header->GetRecordPoolSection();
169     }
170 
ProcessToBinary(PGOContext & context,std::fstream & stream)171     uint32_t ProcessToBinary(PGOContext &context, std::fstream &stream) override
172     {
173         LOG_ECMA(DEBUG) << "[PGORecordPool] ProcessToBinary, count: " << pool_.size();
174         SectionInfo secInfo;
175         secInfo.number_ = pool_.size();
176         secInfo.offset_ = sizeof(SectionInfo);
177         auto secInfoPos = stream.tellp();
178         stream.seekp(secInfo.offset_, std::ofstream::cur);
179         for (auto &entry : pool_) {
180             ProfileTypeRef profileTypeRef(context, entry.first);
181             stream.write(reinterpret_cast<const char *>(&(profileTypeRef)), sizeof(ApEntityId));
182             stream.write(entry.second.c_str(), entry.second.length() + 1);
183         }
184         secInfo.size_ = static_cast<uint32_t>(stream.tellp()) - static_cast<uint32_t>(secInfoPos);
185         auto tail = stream.tellp();
186         stream.seekp(secInfoPos, std::ofstream::beg);
187         stream.write(reinterpret_cast<const char *>(&(secInfo)), sizeof(SectionInfo));
188         stream.seekp(tail, std::ofstream::beg);
189         return 1;
190     }
191 
ParseFromBinary(PGOContext & context,void ** buffer,PGOProfilerHeader const * header)192     uint32_t ParseFromBinary(PGOContext &context, void **buffer,
193                              [[maybe_unused]] PGOProfilerHeader const *header) override
194     {
195         auto secInfo = base::ReadBuffer<SectionInfo>(buffer);
196         for (uint32_t i = 0; i < secInfo.number_; i++) {
197             ProfileTypeRef profileTypeRef(base::ReadBuffer<ApEntityId>(buffer, sizeof(ApEntityId)));
198             ProfileType profileType(context, profileTypeRef);
199             pool_.try_emplace(profileType, base::ReadBuffer(buffer));
200         }
201         return 1;
202     }
203 
ProcessToText(std::ofstream & stream)204     bool ProcessToText(std::ofstream &stream) override
205     {
206         bool isFirst = true;
207         for (auto &entry : pool_) {
208             if (isFirst) {
209                 stream << DumpUtils::NEW_LINE;
210                 stream << "RecordPool";
211                 stream << DumpUtils::BLOCK_START;
212                 isFirst = false;
213             }
214             stream << DumpUtils::NEW_LINE;
215             stream << entry.first.GetTypeString();
216             stream << DumpUtils::SPACE;
217             stream << DumpUtils::ARRAY_START;
218             stream << entry.second;
219             stream << DumpUtils::ARRAY_END;
220         }
221         if (!isFirst) {
222             stream << (DumpUtils::SPACE + DumpUtils::NEW_LINE);
223         }
224         return true;
225     }
226 
Merge(const PGORecordPool & recordPool)227     void Merge(const PGORecordPool &recordPool)
228     {
229         for (const auto &entry : recordPool.pool_) {
230             Add(ProfileType(entry.first), entry.second);
231         }
232     }
233 
Add(ProfileType profileType,const CString & recordName)234     void Add(ProfileType profileType, const CString &recordName)
235     {
236         ASSERT(profileType.GetKind() == ProfileType::Kind::RecordClassId);
237         auto result = pool_.try_emplace(profileType, recordName);
238         if (result.second) {
239             LOG_ECMA(DEBUG) << "Add Record. profile: " << profileType.GetTypeString() << ", recordName: " << recordName;
240         }
241     }
242 
GetName(ProfileType profileType)243     const char *GetName(ProfileType profileType) const
244     {
245         auto iter = pool_.find(profileType);
246         if (iter == pool_.end()) {
247             return "";
248         }
249         return iter->second.c_str();
250     }
251 
Clear()252     void Clear()
253     {
254         pool_.clear();
255     }
256 
257 private:
258     std::unordered_map<ProfileType, CString, HashProfileType> pool_;
259 };
260 
261 class PGOAbcFilePool : public PGOStringPool {
262 public:
263     enum class ReservedType : uint8_t { EMPTY_ABC_FILE_ID = 0, END };
264     static constexpr uint32_t RESERVED_COUNT = 64;
265     static_assert(static_cast<uint32_t>(ReservedType::END) < RESERVED_COUNT);
266 
IsReserved(const CString & value)267     static bool IsReserved(const CString &value)
268     {
269         return value.empty();
270     }
271 
GetReservedId(const CString & value)272     static ApEntityId GetReservedId([[maybe_unused]] const CString &value)
273     {
274         ASSERT(value.empty());
275         return ApEntityId(static_cast<uint32_t>(ReservedType::EMPTY_ABC_FILE_ID));
276     }
277 
Support(PGOProfilerHeader const * header)278     static bool Support(PGOProfilerHeader const *header)
279     {
280         return header->SupportProfileTypeWithAbcId();
281     }
282 
GetSection(PGOProfilerHeader const * header)283     static SectionInfo *GetSection(PGOProfilerHeader const *header)
284     {
285         return header->GetAbcFilePoolSection();
286     }
287 
PGOAbcFilePool()288     PGOAbcFilePool() : PGOStringPool("AbcFilePool", RESERVED_COUNT)
289     {
290         pool_->SetIsReservedCb(IsReserved);
291         pool_->SetGetReservedIdCb(GetReservedId);
292         pool_->SetGetSectionCb(GetSection);
293         pool_->SetSupportCb(Support);
294     }
295 
Merge(const PGOContext & context,PGOAbcFilePool & pool)296     void Merge(const PGOContext &context, PGOAbcFilePool &pool)
297     {
298         if (pool.GetPool() == nullptr) {
299             return;
300         }
301         pool_->Merge(*pool.GetPool(), [&](ApEntityId oldEntryId, ApEntityId newEntryId) {
302             context.AddAbcIdRemap(oldEntryId, newEntryId);
303         });
304     }
305 
Copy(const std::shared_ptr<PGOAbcFilePool> & pool)306     void Copy(const std::shared_ptr<PGOAbcFilePool> &pool)
307     {
308         for (auto &entry : pool->GetPool()->GetPool()) {
309             auto emplacedEntry = GetPool()->GetPool().try_emplace(entry.first, entry.second.GetData());
310             emplacedEntry.first->second.SetEntryId(entry.first);
311             GetPool()->GetValueToId().try_emplace(entry.second.GetData(), entry.first);
312         }
313     }
314 
CopySafe(const std::shared_ptr<PGOAbcFilePool> & pool)315     void CopySafe(const std::shared_ptr<PGOAbcFilePool>& pool)
316     {
317         WriteLockHolder lock(poolLock_);
318         Copy(pool);
319     }
320 };
321 }  // namespace panda::ecmascript::pgo
322 #endif // ECMASCRIPT_PGO_PROFILER_AP_FILE_PGO_RECORD_POOL_H
323